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: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
ea7d69e75a
commit
3719109d61
|
@ -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, "a))
|
||||
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);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue