From e412b1045c3bddd31e16f9e93d6843de2482be0c Mon Sep 17 00:00:00 2001 From: Petri Gynther Date: Wed, 25 Mar 2015 12:35:09 -0700 Subject: [PATCH 1/7] net: bcmgenet: remove priv->int0_mask and priv->int1_mask Remove unused priv->int0_mask and priv->int1_mask. Signed-off-by: Petri Gynther Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 2 -- drivers/net/ethernet/broadcom/genet/bcmgenet.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index c38d5429e27a..030249dd09f0 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -985,7 +985,6 @@ static inline void bcmgenet_tx_ring_int_enable(struct bcmgenet_priv *priv, { bcmgenet_intrl2_1_writel(priv, (1 << ring->index), INTRL2_CPU_MASK_CLEAR); - priv->int1_mask &= ~(1 << ring->index); } static inline void bcmgenet_tx_ring_int_disable(struct bcmgenet_priv *priv, @@ -993,7 +992,6 @@ static inline void bcmgenet_tx_ring_int_disable(struct bcmgenet_priv *priv, { bcmgenet_intrl2_1_writel(priv, (1 << ring->index), INTRL2_CPU_MASK_SET); - priv->int1_mask |= (1 << ring->index); } /* Unlocked version of the reclaim routine */ diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index 7a59879d441f..a9e16122f231 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -558,8 +558,6 @@ struct bcmgenet_priv { void __iomem *base; enum bcmgenet_version version; struct net_device *dev; - u32 int0_mask; - u32 int1_mask; /* NAPI for descriptor based rx */ struct napi_struct napi ____cacheline_aligned; From 9dbac28fc193e3972f566f120dce67d69a1df634 Mon Sep 17 00:00:00 2001 From: Petri Gynther Date: Wed, 25 Mar 2015 12:35:10 -0700 Subject: [PATCH 2/7] net: bcmgenet: modify Tx ring int_enable and int_disable vectors Remove unnecessary function parameter priv. Use ring->priv instead. Signed-off-by: Petri Gynther Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/genet/bcmgenet.c | 26 ++++++++----------- .../net/ethernet/broadcom/genet/bcmgenet.h | 6 ++--- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 030249dd09f0..550bf98d0730 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -964,33 +964,29 @@ static void bcmgenet_free_cb(struct enet_cb *cb) dma_unmap_addr_set(cb, dma_addr, 0); } -static inline void bcmgenet_tx_ring16_int_disable(struct bcmgenet_priv *priv, - struct bcmgenet_tx_ring *ring) +static inline void bcmgenet_tx_ring16_int_disable(struct bcmgenet_tx_ring *ring) { - bcmgenet_intrl2_0_writel(priv, + bcmgenet_intrl2_0_writel(ring->priv, UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE, INTRL2_CPU_MASK_SET); } -static inline void bcmgenet_tx_ring16_int_enable(struct bcmgenet_priv *priv, - struct bcmgenet_tx_ring *ring) +static inline void bcmgenet_tx_ring16_int_enable(struct bcmgenet_tx_ring *ring) { - bcmgenet_intrl2_0_writel(priv, + bcmgenet_intrl2_0_writel(ring->priv, UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE, INTRL2_CPU_MASK_CLEAR); } -static inline void bcmgenet_tx_ring_int_enable(struct bcmgenet_priv *priv, - struct bcmgenet_tx_ring *ring) +static inline void bcmgenet_tx_ring_int_enable(struct bcmgenet_tx_ring *ring) { - bcmgenet_intrl2_1_writel(priv, (1 << ring->index), + bcmgenet_intrl2_1_writel(ring->priv, 1 << ring->index, INTRL2_CPU_MASK_CLEAR); } -static inline void bcmgenet_tx_ring_int_disable(struct bcmgenet_priv *priv, - struct bcmgenet_tx_ring *ring) +static inline void bcmgenet_tx_ring_int_disable(struct bcmgenet_tx_ring *ring) { - bcmgenet_intrl2_1_writel(priv, (1 << ring->index), + bcmgenet_intrl2_1_writel(ring->priv, 1 << ring->index, INTRL2_CPU_MASK_SET); } @@ -1083,7 +1079,7 @@ static int bcmgenet_tx_poll(struct napi_struct *napi, int budget) if (work_done == 0) { napi_complete(napi); - ring->int_enable(ring->priv, ring); + ring->int_enable(ring); return 0; } @@ -2172,7 +2168,7 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) ring = &priv->tx_rings[index]; if (likely(napi_schedule_prep(&ring->napi))) { - ring->int_disable(priv, ring); + ring->int_disable(ring); __napi_schedule(&ring->napi); } } @@ -2211,7 +2207,7 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) struct bcmgenet_tx_ring *ring = &priv->tx_rings[DESC_INDEX]; if (likely(napi_schedule_prep(&ring->napi))) { - ring->int_disable(priv, ring); + ring->int_disable(ring); __napi_schedule(&ring->napi); } } diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index a9e16122f231..7b11e7a7e153 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -535,10 +535,8 @@ struct bcmgenet_tx_ring { unsigned int prod_index; /* Tx ring producer index SW copy */ unsigned int cb_ptr; /* Tx ring initial CB ptr */ unsigned int end_ptr; /* Tx ring end CB ptr */ - void (*int_enable)(struct bcmgenet_priv *priv, - struct bcmgenet_tx_ring *); - void (*int_disable)(struct bcmgenet_priv *priv, - struct bcmgenet_tx_ring *); + void (*int_enable)(struct bcmgenet_tx_ring *); + void (*int_disable)(struct bcmgenet_tx_ring *); struct bcmgenet_priv *priv; }; From ebbd96fb2861f591df011cd0eac67dd367596cca Mon Sep 17 00:00:00 2001 From: Petri Gynther Date: Wed, 25 Mar 2015 12:35:11 -0700 Subject: [PATCH 3/7] net: bcmgenet: simplify bcmgenet_init_dma() Do the two kcalloc() calls first, before proceeding into Rx/Tx DMA init. Makes the error case handling much simpler. Signed-off-by: Petri Gynther Reviewed-by: Florian Fainelli Reviewed-by: Jaedon Shin Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/genet/bcmgenet.c | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 550bf98d0730..1c9f9b418c52 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -2050,9 +2050,6 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv) netif_dbg(priv, hw, priv->dev, "%s\n", __func__); - /* Init rDma */ - bcmgenet_rdma_writel(priv, DMA_MAX_BURST_LENGTH, DMA_SCB_BURST_SIZE); - /* Initialize common Rx ring structures */ priv->rx_bds = priv->base + priv->hw_params->rdma_offset; priv->num_rx_bds = TOTAL_DESC; @@ -2066,25 +2063,13 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv) cb->bd_addr = priv->rx_bds + i * DMA_DESC_SIZE; } - /* Initialize Rx queues */ - ret = bcmgenet_init_rx_queues(priv->dev); - if (ret) { - netdev_err(priv->dev, "failed to initialize Rx queues\n"); - bcmgenet_free_rx_buffers(priv); - kfree(priv->rx_cbs); - return ret; - } - - /* Init tDma */ - bcmgenet_tdma_writel(priv, DMA_MAX_BURST_LENGTH, DMA_SCB_BURST_SIZE); - /* Initialize common TX ring structures */ priv->tx_bds = priv->base + priv->hw_params->tdma_offset; priv->num_tx_bds = TOTAL_DESC; priv->tx_cbs = kcalloc(priv->num_tx_bds, sizeof(struct enet_cb), GFP_KERNEL); if (!priv->tx_cbs) { - __bcmgenet_fini_dma(priv); + kfree(priv->rx_cbs); return -ENOMEM; } @@ -2093,6 +2078,22 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv) cb->bd_addr = priv->tx_bds + i * DMA_DESC_SIZE; } + /* Init rDma */ + bcmgenet_rdma_writel(priv, DMA_MAX_BURST_LENGTH, DMA_SCB_BURST_SIZE); + + /* Initialize Rx queues */ + ret = bcmgenet_init_rx_queues(priv->dev); + if (ret) { + netdev_err(priv->dev, "failed to initialize Rx queues\n"); + bcmgenet_free_rx_buffers(priv); + kfree(priv->rx_cbs); + kfree(priv->tx_cbs); + return ret; + } + + /* Init tDma */ + bcmgenet_tdma_writel(priv, DMA_MAX_BURST_LENGTH, DMA_SCB_BURST_SIZE); + /* Initialize Tx queues */ bcmgenet_init_tx_queues(priv->dev); From b2e97eca88f07d1a4dae691ad8d751ba1de15645 Mon Sep 17 00:00:00 2001 From: Petri Gynther Date: Wed, 25 Mar 2015 12:35:12 -0700 Subject: [PATCH 4/7] net: bcmgenet: tweak init_umac() Use more meaningful variable names int0_enable and int1_enable when enabling bcmgenet interrupts. For Rx default queue interrupts, use: UMAC_IRQ_RXDMA_BDONE | UMAC_IRQ_RXDMA_PDONE For Tx default queue interrupts, use: UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE Signed-off-by: Petri Gynther Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/genet/bcmgenet.c | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 1c9f9b418c52..68873beba760 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1652,8 +1652,10 @@ static int init_umac(struct bcmgenet_priv *priv) { struct device *kdev = &priv->pdev->dev; int ret; - u32 reg, cpu_mask_clear; - int index; + u32 reg; + u32 int0_enable = 0; + u32 int1_enable = 0; + int i; dev_dbg(&priv->pdev->dev, "bcmgenet: init_umac\n"); @@ -1680,15 +1682,17 @@ static int init_umac(struct bcmgenet_priv *priv) bcmgenet_intr_disable(priv); - cpu_mask_clear = UMAC_IRQ_RXDMA_BDONE | UMAC_IRQ_TXDMA_BDONE; + /* Enable Rx default queue 16 interrupts */ + int0_enable |= (UMAC_IRQ_RXDMA_BDONE | UMAC_IRQ_RXDMA_PDONE); - dev_dbg(kdev, "%s:Enabling RXDMA_BDONE interrupt\n", __func__); + /* Enable Tx default queue 16 interrupts */ + int0_enable |= (UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE); /* Monitor cable plug/unplugged event for internal PHY */ if (phy_is_internal(priv->phydev)) { - cpu_mask_clear |= (UMAC_IRQ_LINK_DOWN | UMAC_IRQ_LINK_UP); + int0_enable |= (UMAC_IRQ_LINK_DOWN | UMAC_IRQ_LINK_UP); } else if (priv->ext_phy) { - cpu_mask_clear |= (UMAC_IRQ_LINK_DOWN | UMAC_IRQ_LINK_UP); + int0_enable |= (UMAC_IRQ_LINK_DOWN | UMAC_IRQ_LINK_UP); } else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) { reg = bcmgenet_bp_mc_get(priv); reg |= BIT(priv->hw_params->bp_in_en_shift); @@ -1703,13 +1707,14 @@ static int init_umac(struct bcmgenet_priv *priv) /* Enable MDIO interrupts on GENET v3+ */ if (priv->hw_params->flags & GENET_HAS_MDIO_INTR) - cpu_mask_clear |= UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR; + int0_enable |= (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR); - bcmgenet_intrl2_0_writel(priv, cpu_mask_clear, INTRL2_CPU_MASK_CLEAR); + /* Enable Tx priority queue interrupts */ + for (i = 0; i < priv->hw_params->tx_queues; ++i) + int1_enable |= (1 << i); - for (index = 0; index < priv->hw_params->tx_queues; index++) - bcmgenet_intrl2_1_writel(priv, (1 << index), - INTRL2_CPU_MASK_CLEAR); + bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR); + bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR); /* Enable rx/tx engine.*/ dev_dbg(kdev, "done init umac\n"); @@ -2111,7 +2116,8 @@ static int bcmgenet_poll(struct napi_struct *napi, int budget) if (work_done < budget) { napi_complete(napi); - bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_RXDMA_BDONE, + bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_RXDMA_BDONE | + UMAC_IRQ_RXDMA_PDONE, INTRL2_CPU_MASK_CLEAR); } @@ -2198,7 +2204,8 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) * Disable interrupt, will be enabled in the poll method. */ if (likely(napi_schedule_prep(&priv->napi))) { - bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_RXDMA_BDONE, + bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_RXDMA_BDONE | + UMAC_IRQ_RXDMA_PDONE, INTRL2_CPU_MASK_SET); __napi_schedule(&priv->napi); } From e2aadb4aa9fe4619a78dd925a4756535e9bf3d74 Mon Sep 17 00:00:00 2001 From: Petri Gynther Date: Wed, 25 Mar 2015 12:35:14 -0700 Subject: [PATCH 5/7] net: bcmgenet: rework Tx NAPI code Introduce new bcmgenet functions to handle the NAPI calls to: netif_napi_add() napi_enable() napi_disable() netif_napi_del() Signed-off-by: Petri Gynther Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/genet/bcmgenet.c | 80 ++++++++++++++----- 1 file changed, 62 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 68873beba760..367006dcc70d 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1733,7 +1733,6 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv, spin_lock_init(&ring->lock); ring->priv = priv; - netif_napi_add(priv->dev, &ring->napi, bcmgenet_tx_poll, 64); ring->index = index; if (index == DESC_INDEX) { ring->queue = 0; @@ -1777,17 +1776,6 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv, TDMA_WRITE_PTR); bcmgenet_tdma_ring_writel(priv, index, end_ptr * words_per_bd - 1, DMA_END_ADDR); - - napi_enable(&ring->napi); -} - -static void bcmgenet_fini_tx_ring(struct bcmgenet_priv *priv, - unsigned int index) -{ - struct bcmgenet_tx_ring *ring = &priv->tx_rings[index]; - - napi_disable(&ring->napi); - netif_napi_del(&ring->napi); } /* Initialize a RDMA ring */ @@ -1835,6 +1823,62 @@ static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv, return ret; } +static void bcmgenet_init_tx_napi(struct bcmgenet_priv *priv) +{ + unsigned int i; + struct bcmgenet_tx_ring *ring; + + for (i = 0; i < priv->hw_params->tx_queues; ++i) { + ring = &priv->tx_rings[i]; + netif_napi_add(priv->dev, &ring->napi, bcmgenet_tx_poll, 64); + } + + ring = &priv->tx_rings[DESC_INDEX]; + netif_napi_add(priv->dev, &ring->napi, bcmgenet_tx_poll, 64); +} + +static void bcmgenet_enable_tx_napi(struct bcmgenet_priv *priv) +{ + unsigned int i; + struct bcmgenet_tx_ring *ring; + + for (i = 0; i < priv->hw_params->tx_queues; ++i) { + ring = &priv->tx_rings[i]; + napi_enable(&ring->napi); + } + + ring = &priv->tx_rings[DESC_INDEX]; + napi_enable(&ring->napi); +} + +static void bcmgenet_disable_tx_napi(struct bcmgenet_priv *priv) +{ + unsigned int i; + struct bcmgenet_tx_ring *ring; + + for (i = 0; i < priv->hw_params->tx_queues; ++i) { + ring = &priv->tx_rings[i]; + napi_disable(&ring->napi); + } + + ring = &priv->tx_rings[DESC_INDEX]; + napi_disable(&ring->napi); +} + +static void bcmgenet_fini_tx_napi(struct bcmgenet_priv *priv) +{ + unsigned int i; + struct bcmgenet_tx_ring *ring; + + for (i = 0; i < priv->hw_params->tx_queues; ++i) { + ring = &priv->tx_rings[i]; + netif_napi_del(&ring->napi); + } + + ring = &priv->tx_rings[DESC_INDEX]; + netif_napi_del(&ring->napi); +} + /* Initialize Tx queues * * Queues 0-3 are priority-based, each one has 32 descriptors, @@ -1895,6 +1939,9 @@ static void bcmgenet_init_tx_queues(struct net_device *dev) bcmgenet_tdma_writel(priv, dma_priority[1], DMA_PRIORITY_1); bcmgenet_tdma_writel(priv, dma_priority[2], DMA_PRIORITY_2); + /* Initialize Tx NAPI */ + bcmgenet_init_tx_napi(priv); + /* Enable Tx queues */ bcmgenet_tdma_writel(priv, ring_cfg, DMA_RING_CFG); @@ -2036,12 +2083,7 @@ static void __bcmgenet_fini_dma(struct bcmgenet_priv *priv) static void bcmgenet_fini_dma(struct bcmgenet_priv *priv) { - int i; - - bcmgenet_fini_tx_ring(priv, DESC_INDEX); - - for (i = 0; i < priv->hw_params->tx_queues; i++) - bcmgenet_fini_tx_ring(priv, i); + bcmgenet_fini_tx_napi(priv); __bcmgenet_fini_dma(priv); } @@ -2466,6 +2508,7 @@ static void bcmgenet_netif_start(struct net_device *dev) /* Start the network engine */ napi_enable(&priv->napi); + bcmgenet_enable_tx_napi(priv); umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, true); @@ -2574,6 +2617,7 @@ static void bcmgenet_netif_stop(struct net_device *dev) phy_stop(priv->phydev); bcmgenet_intr_disable(priv); + bcmgenet_disable_tx_napi(priv); /* Wait for pending work items to complete. Since interrupts are * disabled no new work will be scheduled. From 3ab113399b633bacb500a903d2f96f25ded2226c Mon Sep 17 00:00:00 2001 From: Petri Gynther Date: Wed, 25 Mar 2015 12:35:15 -0700 Subject: [PATCH 6/7] net: bcmgenet: rework Rx NAPI code Introduce new bcmgenet functions to handle the NAPI calls to: netif_napi_add() napi_enable() napi_disable() netif_napi_del() Signed-off-by: Petri Gynther Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/genet/bcmgenet.c | 68 ++++++++++++------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 367006dcc70d..dc3b1faf6bbd 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1544,6 +1544,25 @@ next: return rxpktprocessed; } +/* Rx NAPI polling method */ +static int bcmgenet_rx_poll(struct napi_struct *napi, int budget) +{ + struct bcmgenet_priv *priv = container_of(napi, + struct bcmgenet_priv, napi); + unsigned int work_done; + + work_done = bcmgenet_desc_rx(priv, DESC_INDEX, budget); + + if (work_done < budget) { + napi_complete(napi); + bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_RXDMA_BDONE | + UMAC_IRQ_RXDMA_PDONE, + INTRL2_CPU_MASK_CLEAR); + } + + return work_done; +} + /* Assign skb to RX DMA descriptor. */ static int bcmgenet_alloc_rx_buffers(struct bcmgenet_priv *priv, struct bcmgenet_rx_ring *ring) @@ -1951,6 +1970,26 @@ static void bcmgenet_init_tx_queues(struct net_device *dev) bcmgenet_tdma_writel(priv, dma_ctrl, DMA_CTRL); } +static void bcmgenet_init_rx_napi(struct bcmgenet_priv *priv) +{ + netif_napi_add(priv->dev, &priv->napi, bcmgenet_rx_poll, 64); +} + +static void bcmgenet_enable_rx_napi(struct bcmgenet_priv *priv) +{ + napi_enable(&priv->napi); +} + +static void bcmgenet_disable_rx_napi(struct bcmgenet_priv *priv) +{ + napi_disable(&priv->napi); +} + +static void bcmgenet_fini_rx_napi(struct bcmgenet_priv *priv) +{ + netif_napi_del(&priv->napi); +} + /* Initialize Rx queues * * Queues 0-15 are priority queues. Hardware Filtering Block (HFB) can be @@ -2000,6 +2039,9 @@ static int bcmgenet_init_rx_queues(struct net_device *dev) ring_cfg |= (1 << DESC_INDEX); dma_ctrl |= (1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT)); + /* Initialize Rx NAPI */ + bcmgenet_init_rx_napi(priv); + /* Enable rings */ bcmgenet_rdma_writel(priv, ring_cfg, DMA_RING_CFG); @@ -2083,6 +2125,7 @@ static void __bcmgenet_fini_dma(struct bcmgenet_priv *priv) static void bcmgenet_fini_dma(struct bcmgenet_priv *priv) { + bcmgenet_fini_rx_napi(priv); bcmgenet_fini_tx_napi(priv); __bcmgenet_fini_dma(priv); @@ -2147,25 +2190,6 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv) return 0; } -/* NAPI polling method*/ -static int bcmgenet_poll(struct napi_struct *napi, int budget) -{ - struct bcmgenet_priv *priv = container_of(napi, - struct bcmgenet_priv, napi); - unsigned int work_done; - - work_done = bcmgenet_desc_rx(priv, DESC_INDEX, budget); - - if (work_done < budget) { - napi_complete(napi); - bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_RXDMA_BDONE | - UMAC_IRQ_RXDMA_PDONE, - INTRL2_CPU_MASK_CLEAR); - } - - return work_done; -} - /* Interrupt bottom half */ static void bcmgenet_irq_task(struct work_struct *work) { @@ -2507,7 +2531,7 @@ static void bcmgenet_netif_start(struct net_device *dev) struct bcmgenet_priv *priv = netdev_priv(dev); /* Start the network engine */ - napi_enable(&priv->napi); + bcmgenet_enable_rx_napi(priv); bcmgenet_enable_tx_napi(priv); umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, true); @@ -2613,10 +2637,9 @@ static void bcmgenet_netif_stop(struct net_device *dev) struct bcmgenet_priv *priv = netdev_priv(dev); netif_tx_stop_all_queues(dev); - napi_disable(&priv->napi); phy_stop(priv->phydev); - bcmgenet_intr_disable(priv); + bcmgenet_disable_rx_napi(priv); bcmgenet_disable_tx_napi(priv); /* Wait for pending work items to complete. Since interrupts are @@ -3018,7 +3041,6 @@ static int bcmgenet_probe(struct platform_device *pdev) dev->watchdog_timeo = 2 * HZ; dev->ethtool_ops = &bcmgenet_ethtool_ops; dev->netdev_ops = &bcmgenet_netdev_ops; - netif_napi_add(dev, &priv->napi, bcmgenet_poll, 64); priv->msg_enable = netif_msg_init(-1, GENET_MSG_DEFAULT); From 4055eaefb3603a2a55305c81292379922a742131 Mon Sep 17 00:00:00 2001 From: Petri Gynther Date: Wed, 25 Mar 2015 12:35:16 -0700 Subject: [PATCH 7/7] net: bcmgenet: add support for multiple Rx queues Add support for multiple Rx queues: 1. Add NAPI context per Rx queue 2. Modify Rx interrupt and Rx NAPI code to handle multiple Rx queues Signed-off-by: Petri Gynther Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/genet/bcmgenet.c | 174 +++++++++++++----- .../net/ethernet/broadcom/genet/bcmgenet.h | 12 +- 2 files changed, 139 insertions(+), 47 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index dc3b1faf6bbd..31e14079e1d7 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -964,6 +964,34 @@ static void bcmgenet_free_cb(struct enet_cb *cb) dma_unmap_addr_set(cb, dma_addr, 0); } +static inline void bcmgenet_rx_ring16_int_disable(struct bcmgenet_rx_ring *ring) +{ + bcmgenet_intrl2_0_writel(ring->priv, + UMAC_IRQ_RXDMA_BDONE | UMAC_IRQ_RXDMA_PDONE, + INTRL2_CPU_MASK_SET); +} + +static inline void bcmgenet_rx_ring16_int_enable(struct bcmgenet_rx_ring *ring) +{ + bcmgenet_intrl2_0_writel(ring->priv, + UMAC_IRQ_RXDMA_BDONE | UMAC_IRQ_RXDMA_PDONE, + INTRL2_CPU_MASK_CLEAR); +} + +static inline void bcmgenet_rx_ring_int_disable(struct bcmgenet_rx_ring *ring) +{ + bcmgenet_intrl2_1_writel(ring->priv, + 1 << (UMAC_IRQ1_RX_INTR_SHIFT + ring->index), + INTRL2_CPU_MASK_SET); +} + +static inline void bcmgenet_rx_ring_int_enable(struct bcmgenet_rx_ring *ring) +{ + bcmgenet_intrl2_1_writel(ring->priv, + 1 << (UMAC_IRQ1_RX_INTR_SHIFT + ring->index), + INTRL2_CPU_MASK_CLEAR); +} + static inline void bcmgenet_tx_ring16_int_disable(struct bcmgenet_tx_ring *ring) { bcmgenet_intrl2_0_writel(ring->priv, @@ -1390,11 +1418,10 @@ static struct sk_buff *bcmgenet_rx_refill(struct bcmgenet_priv *priv, /* bcmgenet_desc_rx - descriptor based rx process. * this could be called from bottom half, or from NAPI polling method. */ -static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv, - unsigned int index, +static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, unsigned int budget) { - struct bcmgenet_rx_ring *ring = &priv->rx_rings[index]; + struct bcmgenet_priv *priv = ring->priv; struct net_device *dev = priv->dev; struct enet_cb *cb; struct sk_buff *skb; @@ -1406,7 +1433,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv, unsigned int discards; unsigned int chksum_ok = 0; - p_index = bcmgenet_rdma_ring_readl(priv, index, RDMA_PROD_INDEX); + p_index = bcmgenet_rdma_ring_readl(priv, ring->index, RDMA_PROD_INDEX); discards = (p_index >> DMA_P_INDEX_DISCARD_CNT_SHIFT) & DMA_P_INDEX_DISCARD_CNT_MASK; @@ -1419,7 +1446,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv, /* Clear HW register when we reach 75% of maximum 0xFFFF */ if (ring->old_discards >= 0xC000) { ring->old_discards = 0; - bcmgenet_rdma_ring_writel(priv, index, 0, + bcmgenet_rdma_ring_writel(priv, ring->index, 0, RDMA_PROD_INDEX); } } @@ -1527,7 +1554,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv, dev->stats.multicast++; /* Notify kernel */ - napi_gro_receive(&priv->napi, skb); + napi_gro_receive(&ring->napi, skb); netif_dbg(priv, rx_status, dev, "pushed up to kernel\n"); next: @@ -1538,7 +1565,7 @@ next: ring->read_ptr = ring->cb_ptr; ring->c_index = (ring->c_index + 1) & DMA_C_INDEX_MASK; - bcmgenet_rdma_ring_writel(priv, index, ring->c_index, RDMA_CONS_INDEX); + bcmgenet_rdma_ring_writel(priv, ring->index, ring->c_index, RDMA_CONS_INDEX); } return rxpktprocessed; @@ -1547,17 +1574,15 @@ next: /* Rx NAPI polling method */ static int bcmgenet_rx_poll(struct napi_struct *napi, int budget) { - struct bcmgenet_priv *priv = container_of(napi, - struct bcmgenet_priv, napi); + struct bcmgenet_rx_ring *ring = container_of(napi, + struct bcmgenet_rx_ring, napi); unsigned int work_done; - work_done = bcmgenet_desc_rx(priv, DESC_INDEX, budget); + work_done = bcmgenet_desc_rx(ring, budget); if (work_done < budget) { napi_complete(napi); - bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_RXDMA_BDONE | - UMAC_IRQ_RXDMA_PDONE, - INTRL2_CPU_MASK_CLEAR); + ring->int_enable(ring); } return work_done; @@ -1728,6 +1753,10 @@ static int init_umac(struct bcmgenet_priv *priv) if (priv->hw_params->flags & GENET_HAS_MDIO_INTR) int0_enable |= (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR); + /* Enable Rx priority queue interrupts */ + for (i = 0; i < priv->hw_params->rx_queues; ++i) + int1_enable |= (1 << (UMAC_IRQ1_RX_INTR_SHIFT + i)); + /* Enable Tx priority queue interrupts */ for (i = 0; i < priv->hw_params->tx_queues; ++i) int1_enable |= (1 << i); @@ -1806,7 +1835,15 @@ static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv, u32 words_per_bd = WORDS_PER_BD(priv); int ret; + ring->priv = priv; ring->index = index; + if (index == DESC_INDEX) { + ring->int_enable = bcmgenet_rx_ring16_int_enable; + ring->int_disable = bcmgenet_rx_ring16_int_disable; + } else { + ring->int_enable = bcmgenet_rx_ring_int_enable; + ring->int_disable = bcmgenet_rx_ring_int_disable; + } ring->cbs = priv->rx_cbs + start_ptr; ring->size = size; ring->c_index = 0; @@ -1972,22 +2009,58 @@ static void bcmgenet_init_tx_queues(struct net_device *dev) static void bcmgenet_init_rx_napi(struct bcmgenet_priv *priv) { - netif_napi_add(priv->dev, &priv->napi, bcmgenet_rx_poll, 64); + unsigned int i; + struct bcmgenet_rx_ring *ring; + + for (i = 0; i < priv->hw_params->rx_queues; ++i) { + ring = &priv->rx_rings[i]; + netif_napi_add(priv->dev, &ring->napi, bcmgenet_rx_poll, 64); + } + + ring = &priv->rx_rings[DESC_INDEX]; + netif_napi_add(priv->dev, &ring->napi, bcmgenet_rx_poll, 64); } static void bcmgenet_enable_rx_napi(struct bcmgenet_priv *priv) { - napi_enable(&priv->napi); + unsigned int i; + struct bcmgenet_rx_ring *ring; + + for (i = 0; i < priv->hw_params->rx_queues; ++i) { + ring = &priv->rx_rings[i]; + napi_enable(&ring->napi); + } + + ring = &priv->rx_rings[DESC_INDEX]; + napi_enable(&ring->napi); } static void bcmgenet_disable_rx_napi(struct bcmgenet_priv *priv) { - napi_disable(&priv->napi); + unsigned int i; + struct bcmgenet_rx_ring *ring; + + for (i = 0; i < priv->hw_params->rx_queues; ++i) { + ring = &priv->rx_rings[i]; + napi_disable(&ring->napi); + } + + ring = &priv->rx_rings[DESC_INDEX]; + napi_disable(&ring->napi); } static void bcmgenet_fini_rx_napi(struct bcmgenet_priv *priv) { - netif_napi_del(&priv->napi); + unsigned int i; + struct bcmgenet_rx_ring *ring; + + for (i = 0; i < priv->hw_params->rx_queues; ++i) { + ring = &priv->rx_rings[i]; + netif_napi_del(&ring->napi); + } + + ring = &priv->rx_rings[DESC_INDEX]; + netif_napi_del(&ring->napi); } /* Initialize Rx queues @@ -2214,50 +2287,66 @@ static void bcmgenet_irq_task(struct work_struct *work) } } -/* bcmgenet_isr1: interrupt handler for ring buffer. */ +/* bcmgenet_isr1: handle Rx and Tx priority queues */ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) { struct bcmgenet_priv *priv = dev_id; - struct bcmgenet_tx_ring *ring; + struct bcmgenet_rx_ring *rx_ring; + struct bcmgenet_tx_ring *tx_ring; unsigned int index; /* Save irq status for bottom-half processing. */ priv->irq1_stat = bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_STAT) & ~bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_MASK_STATUS); + /* clear interrupts */ bcmgenet_intrl2_1_writel(priv, priv->irq1_stat, INTRL2_CPU_CLEAR); netif_dbg(priv, intr, priv->dev, "%s: IRQ=0x%x\n", __func__, priv->irq1_stat); - /* Check the MBDONE interrupts. - * packet is done, reclaim descriptors - */ + /* Check Rx priority queue interrupts */ + for (index = 0; index < priv->hw_params->rx_queues; index++) { + if (!(priv->irq1_stat & BIT(UMAC_IRQ1_RX_INTR_SHIFT + index))) + continue; + + rx_ring = &priv->rx_rings[index]; + + if (likely(napi_schedule_prep(&rx_ring->napi))) { + rx_ring->int_disable(rx_ring); + __napi_schedule(&rx_ring->napi); + } + } + + /* Check Tx priority queue interrupts */ for (index = 0; index < priv->hw_params->tx_queues; index++) { if (!(priv->irq1_stat & BIT(index))) continue; - ring = &priv->tx_rings[index]; + tx_ring = &priv->tx_rings[index]; - if (likely(napi_schedule_prep(&ring->napi))) { - ring->int_disable(ring); - __napi_schedule(&ring->napi); + if (likely(napi_schedule_prep(&tx_ring->napi))) { + tx_ring->int_disable(tx_ring); + __napi_schedule(&tx_ring->napi); } } return IRQ_HANDLED; } -/* bcmgenet_isr0: Handle various interrupts. */ +/* bcmgenet_isr0: handle Rx and Tx default queues + other stuff */ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) { struct bcmgenet_priv *priv = dev_id; + struct bcmgenet_rx_ring *rx_ring; + struct bcmgenet_tx_ring *tx_ring; /* Save irq status for bottom-half processing. */ priv->irq0_stat = bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_STAT) & ~bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS); + /* clear interrupts */ bcmgenet_intrl2_0_writel(priv, priv->irq0_stat, INTRL2_CPU_CLEAR); @@ -2265,26 +2354,23 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) "IRQ=0x%x\n", priv->irq0_stat); if (priv->irq0_stat & (UMAC_IRQ_RXDMA_BDONE | UMAC_IRQ_RXDMA_PDONE)) { - /* We use NAPI(software interrupt throttling, if - * Rx Descriptor throttling is not used. - * Disable interrupt, will be enabled in the poll method. - */ - if (likely(napi_schedule_prep(&priv->napi))) { - bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_RXDMA_BDONE | - UMAC_IRQ_RXDMA_PDONE, - INTRL2_CPU_MASK_SET); - __napi_schedule(&priv->napi); - } - } - if (priv->irq0_stat & - (UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE)) { - struct bcmgenet_tx_ring *ring = &priv->tx_rings[DESC_INDEX]; + rx_ring = &priv->rx_rings[DESC_INDEX]; - if (likely(napi_schedule_prep(&ring->napi))) { - ring->int_disable(ring); - __napi_schedule(&ring->napi); + if (likely(napi_schedule_prep(&rx_ring->napi))) { + rx_ring->int_disable(rx_ring); + __napi_schedule(&rx_ring->napi); } } + + if (priv->irq0_stat & (UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE)) { + tx_ring = &priv->tx_rings[DESC_INDEX]; + + if (likely(napi_schedule_prep(&tx_ring->napi))) { + tx_ring->int_disable(tx_ring); + __napi_schedule(&tx_ring->napi); + } + } + if (priv->irq0_stat & (UMAC_IRQ_PHY_DET_R | UMAC_IRQ_PHY_DET_F | UMAC_IRQ_LINK_UP | diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index 7b11e7a7e153..a834da1dfe4c 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -310,6 +310,11 @@ struct bcmgenet_mib_counters { #define UMAC_IRQ_MDIO_DONE (1 << 23) #define UMAC_IRQ_MDIO_ERROR (1 << 24) +/* INTRL2 instance 1 definitions */ +#define UMAC_IRQ1_TX_INTR_MASK 0xFFFF +#define UMAC_IRQ1_RX_INTR_MASK 0xFFFF +#define UMAC_IRQ1_RX_INTR_SHIFT 16 + /* Register block offsets */ #define GENET_SYS_OFF 0x0000 #define GENET_GR_BRIDGE_OFF 0x0040 @@ -541,6 +546,7 @@ struct bcmgenet_tx_ring { }; struct bcmgenet_rx_ring { + struct napi_struct napi; /* Rx NAPI struct */ unsigned int index; /* Rx ring index */ struct enet_cb *cbs; /* Rx ring buffer control block */ unsigned int size; /* Rx ring size */ @@ -549,6 +555,9 @@ struct bcmgenet_rx_ring { unsigned int cb_ptr; /* Rx ring initial CB ptr */ unsigned int end_ptr; /* Rx ring end CB ptr */ unsigned int old_discards; + void (*int_enable)(struct bcmgenet_rx_ring *); + void (*int_disable)(struct bcmgenet_rx_ring *); + struct bcmgenet_priv *priv; }; /* device context */ @@ -557,9 +566,6 @@ struct bcmgenet_priv { enum bcmgenet_version version; struct net_device *dev; - /* NAPI for descriptor based rx */ - struct napi_struct napi ____cacheline_aligned; - /* transmit variables */ void __iomem *tx_bds; struct enet_cb *tx_cbs;