Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7145074b authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'bcmgenet-next'



Petri Gynther says:

====================
net: bcmgenet: multiple Rx queues support

Final patch set to add support for multiple Rx queues:
1. remove priv->int0_mask and priv->int1_mask
2. modify Tx ring int_enable and int_disable vectors
3. simplify bcmgenet_init_dma()
4. tweak init_umac()
5. rework Tx NAPI code
6. rework Rx NAPI code
7. add support for multiple Rx queues
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 19cc2dec 4055eaef
Loading
Loading
Loading
Loading
+267 −113
Original line number Diff line number Diff line
@@ -964,36 +964,58 @@ 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_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(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);
	priv->int1_mask &= ~(1 << ring->index);
}

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);
	priv->int1_mask |= (1 << ring->index);
}

/* Unlocked version of the reclaim routine */
@@ -1085,7 +1107,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;
	}
@@ -1396,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;
@@ -1412,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;
@@ -1425,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);
		}
	}
@@ -1533,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:
@@ -1544,12 +1565,29 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
			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;
}

/* Rx NAPI polling method */
static int bcmgenet_rx_poll(struct napi_struct *napi, int budget)
{
	struct bcmgenet_rx_ring *ring = container_of(napi,
			struct bcmgenet_rx_ring, napi);
	unsigned int work_done;

	work_done = bcmgenet_desc_rx(ring, budget);

	if (work_done < budget) {
		napi_complete(napi);
		ring->int_enable(ring);
	}

	return work_done;
}

/* Assign skb to RX DMA descriptor. */
static int bcmgenet_alloc_rx_buffers(struct bcmgenet_priv *priv,
				     struct bcmgenet_rx_ring *ring)
@@ -1658,8 +1696,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");

@@ -1686,15 +1726,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);
@@ -1709,13 +1751,18 @@ 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 Rx priority queue interrupts */
	for (i = 0; i < priv->hw_params->rx_queues; ++i)
		int1_enable |= (1 << (UMAC_IRQ1_RX_INTR_SHIFT + i));

	for (index = 0; index < priv->hw_params->tx_queues; index++)
		bcmgenet_intrl2_1_writel(priv, (1 << index),
					 INTRL2_CPU_MASK_CLEAR);
	/* Enable Tx priority queue interrupts */
	for (i = 0; i < priv->hw_params->tx_queues; ++i)
		int1_enable |= (1 << i);

	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");
@@ -1734,7 +1781,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;
@@ -1778,17 +1824,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 */
@@ -1800,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;
@@ -1836,6 +1879,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,
@@ -1896,6 +1995,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);

@@ -1905,6 +2007,62 @@ 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)
{
	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)
{
	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)
{
	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)
{
	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
 *
 * Queues 0-15 are priority queues. Hardware Filtering Block (HFB) can be
@@ -1954,6 +2112,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);

@@ -2037,12 +2198,8 @@ 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_rx_napi(priv);
	bcmgenet_fini_tx_napi(priv);

	__bcmgenet_fini_dma(priv);
}
@@ -2056,9 +2213,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;
@@ -2072,25 +2226,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;
	}

@@ -2099,28 +2241,26 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv)
		cb->bd_addr = priv->tx_bds + i * DMA_DESC_SIZE;
	}

	/* Initialize Tx queues */
	bcmgenet_init_tx_queues(priv->dev);
	/* Init rDma */
	bcmgenet_rdma_writel(priv, DMA_MAX_BURST_LENGTH, DMA_SCB_BURST_SIZE);

	return 0;
	/* 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;
	}

/* 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);
	/* Init tDma */
	bcmgenet_tdma_writel(priv, DMA_MAX_BURST_LENGTH, DMA_SCB_BURST_SIZE);

	if (work_done < budget) {
		napi_complete(napi);
		bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_RXDMA_BDONE,
					 INTRL2_CPU_MASK_CLEAR);
	}
	/* Initialize Tx queues */
	bcmgenet_init_tx_queues(priv->dev);

	return work_done;
	return 0;
}

/* Interrupt bottom half */
@@ -2147,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(priv, 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);

@@ -2198,25 +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,
						 INTRL2_CPU_MASK_SET);
			__napi_schedule(&priv->napi);
		rx_ring = &priv->rx_rings[DESC_INDEX];

		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)) {
		struct bcmgenet_tx_ring *ring = &priv->tx_rings[DESC_INDEX];

		if (likely(napi_schedule_prep(&ring->napi))) {
			ring->int_disable(priv, ring);
			__napi_schedule(&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 |
@@ -2463,7 +2617,8 @@ 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);

@@ -2568,10 +2723,10 @@ 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
	 * disabled no new work will be scheduled.
@@ -2972,7 +3127,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);

+11 −9
Original line number Diff line number Diff line
@@ -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
@@ -535,14 +540,13 @@ 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;
};

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 */
@@ -551,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 */
@@ -558,11 +565,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;

	/* transmit variables */
	void __iomem *tx_bds;