Commit 3719109d authored by Sergei Shtylyov's avatar Sergei Shtylyov Committed by David S. Miller
Browse files

sh_eth: add NAPI support



The driver hasn't used NAPI so far; implement its support at last...

The patch was tested on Renesas R8A77781 BOCK-W board.

Signed-off-by: default avatarSergei Shtylyov <sergei.shtylyov@cogentembedded.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ea7d69e7
Loading
Loading
Loading
Loading
+73 −12
Original line number Diff line number Diff line
@@ -1244,7 +1244,7 @@ static int sh_eth_txfree(struct net_device *ndev)
}

/* Packet receive function */
static int sh_eth_rx(struct net_device *ndev, u32 intr_status)
static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
{
	struct sh_eth_private *mdp = netdev_priv(ndev);
	struct sh_eth_rxdesc *rxdesc;
@@ -1252,6 +1252,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status)
	int entry = mdp->cur_rx % mdp->num_rx_ring;
	int boguscnt = (mdp->dirty_rx + mdp->num_rx_ring) - mdp->cur_rx;
	struct sk_buff *skb;
	int exceeded = 0;
	u16 pkt_len = 0;
	u32 desc_status;

@@ -1263,6 +1264,12 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status)
		if (--boguscnt < 0)
			break;

		if (*quota <= 0) {
			exceeded = 1;
			break;
		}
		(*quota)--;

		if (!(desc_status & RDFEND))
			ndev->stats.rx_length_errors++;

@@ -1350,7 +1357,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status)
		sh_eth_write(ndev, EDRRR_R, EDRRR);
	}

	return 0;
	return exceeded;
}

static void sh_eth_rcv_snd_disable(struct net_device *ndev)
@@ -1491,7 +1498,7 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
	struct sh_eth_private *mdp = netdev_priv(ndev);
	struct sh_eth_cpu_data *cd = mdp->cd;
	irqreturn_t ret = IRQ_NONE;
	unsigned long intr_status;
	unsigned long intr_status, intr_enable;

	spin_lock(&mdp->lock);

@@ -1502,25 +1509,41 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
	 * and we need to fully handle it in sh_eth_error() in order to quench
	 * it as it doesn't get cleared by just writing 1 to the ECI bit...
	 */
	intr_status &= sh_eth_read(ndev, EESIPR) | DMAC_M_ECI;
	/* Clear interrupt */
	if (intr_status & (EESR_RX_CHECK | cd->tx_check | cd->eesr_err_check)) {
		sh_eth_write(ndev, intr_status, EESR);
	intr_enable = sh_eth_read(ndev, EESIPR);
	intr_status &= intr_enable | DMAC_M_ECI;
	if (intr_status & (EESR_RX_CHECK | cd->tx_check | cd->eesr_err_check))
		ret = IRQ_HANDLED;
	} else
	else
		goto other_irq;

	if (intr_status & EESR_RX_CHECK)
		sh_eth_rx(ndev, intr_status);
	if (intr_status & EESR_RX_CHECK) {
		if (napi_schedule_prep(&mdp->napi)) {
			/* Mask Rx interrupts */
			sh_eth_write(ndev, intr_enable & ~EESR_RX_CHECK,
				     EESIPR);
			__napi_schedule(&mdp->napi);
		} else {
			dev_warn(&ndev->dev,
				 "ignoring interrupt, status 0x%08lx, mask 0x%08lx.\n",
				 intr_status, intr_enable);
		}
	}

	/* Tx Check */
	if (intr_status & cd->tx_check) {
		/* Clear Tx interrupts */
		sh_eth_write(ndev, intr_status & cd->tx_check, EESR);

		sh_eth_txfree(ndev);
		netif_wake_queue(ndev);
	}

	if (intr_status & cd->eesr_err_check)
	if (intr_status & cd->eesr_err_check) {
		/* Clear error interrupts */
		sh_eth_write(ndev, intr_status & cd->eesr_err_check, EESR);

		sh_eth_error(ndev, intr_status);
	}

other_irq:
	spin_unlock(&mdp->lock);
@@ -1528,6 +1551,33 @@ other_irq:
	return ret;
}

static int sh_eth_poll(struct napi_struct *napi, int budget)
{
	struct sh_eth_private *mdp = container_of(napi, struct sh_eth_private,
						  napi);
	struct net_device *ndev = napi->dev;
	int quota = budget;
	unsigned long intr_status;

	for (;;) {
		intr_status = sh_eth_read(ndev, EESR);
		if (!(intr_status & EESR_RX_CHECK))
			break;
		/* Clear Rx interrupts */
		sh_eth_write(ndev, intr_status & EESR_RX_CHECK, EESR);

		if (sh_eth_rx(ndev, intr_status, &quota))
			goto out;
	}

	napi_complete(napi);

	/* Reenable Rx interrupts */
	sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR);
out:
	return budget - quota;
}

/* PHY state control function */
static void sh_eth_adjust_link(struct net_device *ndev)
{
@@ -1839,6 +1889,8 @@ static int sh_eth_open(struct net_device *ndev)
	if (ret)
		goto out_free_irq;

	napi_enable(&mdp->napi);

	return ret;

out_free_irq:
@@ -1934,6 +1986,8 @@ static int sh_eth_close(struct net_device *ndev)
{
	struct sh_eth_private *mdp = netdev_priv(ndev);

	napi_disable(&mdp->napi);

	netif_stop_queue(ndev);

	/* Disable interrupts by clearing the interrupt mask. */
@@ -2623,10 +2677,12 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
		}
	}

	netif_napi_add(ndev, &mdp->napi, sh_eth_poll, 64);

	/* network device register */
	ret = register_netdev(ndev);
	if (ret)
		goto out_release;
		goto out_napi_del;

	/* mdio bus init */
	ret = sh_mdio_init(ndev, pdev->id, pd);
@@ -2644,6 +2700,9 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
out_unregister:
	unregister_netdev(ndev);

out_napi_del:
	netif_napi_del(&mdp->napi);

out_release:
	/* net_dev free */
	if (ndev)
@@ -2656,9 +2715,11 @@ out:
static int sh_eth_drv_remove(struct platform_device *pdev)
{
	struct net_device *ndev = platform_get_drvdata(pdev);
	struct sh_eth_private *mdp = netdev_priv(ndev);

	sh_mdio_release(ndev);
	unregister_netdev(ndev);
	netif_napi_del(&mdp->napi);
	pm_runtime_disable(&pdev->dev);
	free_netdev(ndev);

+1 −0
Original line number Diff line number Diff line
@@ -505,6 +505,7 @@ struct sh_eth_private {
	u32 cur_tx, dirty_tx;
	u32 rx_buf_sz;		/* Based on MTU+slack. */
	int edmac_endian;
	struct napi_struct napi;
	/* MII transceiver section. */
	u32 phy_id;					/* PHY ID */
	struct mii_bus *mii_bus;	/* MDIO bus control */