diff options
author | Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> | 2013-06-19 15:30:23 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-06-19 20:01:39 -0400 |
commit | 3719109d61ca96746c733538ec776d02a6952640 (patch) | |
tree | 68a0e18a90a7f9077cd6a53647edcb3252c3237a /drivers/net/ethernet/renesas | |
parent | ea7d69e75ac06daa7bc2fca2a8317197e5e3c81c (diff) |
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>
Diffstat (limited to 'drivers/net/ethernet/renesas')
-rw-r--r-- | drivers/net/ethernet/renesas/sh_eth.c | 85 | ||||
-rw-r--r-- | drivers/net/ethernet/renesas/sh_eth.h | 1 |
2 files changed, 74 insertions, 12 deletions
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index cd5987ecee4b..5233edab2dd5 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c | |||
@@ -1244,7 +1244,7 @@ static int sh_eth_txfree(struct net_device *ndev) | |||
1244 | } | 1244 | } |
1245 | 1245 | ||
1246 | /* Packet receive function */ | 1246 | /* Packet receive function */ |
1247 | static int sh_eth_rx(struct net_device *ndev, u32 intr_status) | 1247 | static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota) |
1248 | { | 1248 | { |
1249 | struct sh_eth_private *mdp = netdev_priv(ndev); | 1249 | struct sh_eth_private *mdp = netdev_priv(ndev); |
1250 | struct sh_eth_rxdesc *rxdesc; | 1250 | struct sh_eth_rxdesc *rxdesc; |
@@ -1252,6 +1252,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status) | |||
1252 | int entry = mdp->cur_rx % mdp->num_rx_ring; | 1252 | int entry = mdp->cur_rx % mdp->num_rx_ring; |
1253 | int boguscnt = (mdp->dirty_rx + mdp->num_rx_ring) - mdp->cur_rx; | 1253 | int boguscnt = (mdp->dirty_rx + mdp->num_rx_ring) - mdp->cur_rx; |
1254 | struct sk_buff *skb; | 1254 | struct sk_buff *skb; |
1255 | int exceeded = 0; | ||
1255 | u16 pkt_len = 0; | 1256 | u16 pkt_len = 0; |
1256 | u32 desc_status; | 1257 | u32 desc_status; |
1257 | 1258 | ||
@@ -1263,6 +1264,12 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status) | |||
1263 | if (--boguscnt < 0) | 1264 | if (--boguscnt < 0) |
1264 | break; | 1265 | break; |
1265 | 1266 | ||
1267 | if (*quota <= 0) { | ||
1268 | exceeded = 1; | ||
1269 | break; | ||
1270 | } | ||
1271 | (*quota)--; | ||
1272 | |||
1266 | if (!(desc_status & RDFEND)) | 1273 | if (!(desc_status & RDFEND)) |
1267 | ndev->stats.rx_length_errors++; | 1274 | ndev->stats.rx_length_errors++; |
1268 | 1275 | ||
@@ -1350,7 +1357,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status) | |||
1350 | sh_eth_write(ndev, EDRRR_R, EDRRR); | 1357 | sh_eth_write(ndev, EDRRR_R, EDRRR); |
1351 | } | 1358 | } |
1352 | 1359 | ||
1353 | return 0; | 1360 | return exceeded; |
1354 | } | 1361 | } |
1355 | 1362 | ||
1356 | static void sh_eth_rcv_snd_disable(struct net_device *ndev) | 1363 | 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) | |||
1491 | struct sh_eth_private *mdp = netdev_priv(ndev); | 1498 | struct sh_eth_private *mdp = netdev_priv(ndev); |
1492 | struct sh_eth_cpu_data *cd = mdp->cd; | 1499 | struct sh_eth_cpu_data *cd = mdp->cd; |
1493 | irqreturn_t ret = IRQ_NONE; | 1500 | irqreturn_t ret = IRQ_NONE; |
1494 | unsigned long intr_status; | 1501 | unsigned long intr_status, intr_enable; |
1495 | 1502 | ||
1496 | spin_lock(&mdp->lock); | 1503 | spin_lock(&mdp->lock); |
1497 | 1504 | ||
@@ -1502,25 +1509,41 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev) | |||
1502 | * and we need to fully handle it in sh_eth_error() in order to quench | 1509 | * and we need to fully handle it in sh_eth_error() in order to quench |
1503 | * it as it doesn't get cleared by just writing 1 to the ECI bit... | 1510 | * it as it doesn't get cleared by just writing 1 to the ECI bit... |
1504 | */ | 1511 | */ |
1505 | intr_status &= sh_eth_read(ndev, EESIPR) | DMAC_M_ECI; | 1512 | intr_enable = sh_eth_read(ndev, EESIPR); |
1506 | /* Clear interrupt */ | 1513 | intr_status &= intr_enable | DMAC_M_ECI; |
1507 | if (intr_status & (EESR_RX_CHECK | cd->tx_check | cd->eesr_err_check)) { | 1514 | if (intr_status & (EESR_RX_CHECK | cd->tx_check | cd->eesr_err_check)) |
1508 | sh_eth_write(ndev, intr_status, EESR); | ||
1509 | ret = IRQ_HANDLED; | 1515 | ret = IRQ_HANDLED; |
1510 | } else | 1516 | else |
1511 | goto other_irq; | 1517 | goto other_irq; |
1512 | 1518 | ||
1513 | if (intr_status & EESR_RX_CHECK) | 1519 | if (intr_status & EESR_RX_CHECK) { |
1514 | sh_eth_rx(ndev, intr_status); | 1520 | if (napi_schedule_prep(&mdp->napi)) { |
1521 | /* Mask Rx interrupts */ | ||
1522 | sh_eth_write(ndev, intr_enable & ~EESR_RX_CHECK, | ||
1523 | EESIPR); | ||
1524 | __napi_schedule(&mdp->napi); | ||
1525 | } else { | ||
1526 | dev_warn(&ndev->dev, | ||
1527 | "ignoring interrupt, status 0x%08lx, mask 0x%08lx.\n", | ||
1528 | intr_status, intr_enable); | ||
1529 | } | ||
1530 | } | ||
1515 | 1531 | ||
1516 | /* Tx Check */ | 1532 | /* Tx Check */ |
1517 | if (intr_status & cd->tx_check) { | 1533 | if (intr_status & cd->tx_check) { |
1534 | /* Clear Tx interrupts */ | ||
1535 | sh_eth_write(ndev, intr_status & cd->tx_check, EESR); | ||
1536 | |||
1518 | sh_eth_txfree(ndev); | 1537 | sh_eth_txfree(ndev); |
1519 | netif_wake_queue(ndev); | 1538 | netif_wake_queue(ndev); |
1520 | } | 1539 | } |
1521 | 1540 | ||
1522 | if (intr_status & cd->eesr_err_check) | 1541 | if (intr_status & cd->eesr_err_check) { |
1542 | /* Clear error interrupts */ | ||
1543 | sh_eth_write(ndev, intr_status & cd->eesr_err_check, EESR); | ||
1544 | |||
1523 | sh_eth_error(ndev, intr_status); | 1545 | sh_eth_error(ndev, intr_status); |
1546 | } | ||
1524 | 1547 | ||
1525 | other_irq: | 1548 | other_irq: |
1526 | spin_unlock(&mdp->lock); | 1549 | spin_unlock(&mdp->lock); |
@@ -1528,6 +1551,33 @@ other_irq: | |||
1528 | return ret; | 1551 | return ret; |
1529 | } | 1552 | } |
1530 | 1553 | ||
1554 | static int sh_eth_poll(struct napi_struct *napi, int budget) | ||
1555 | { | ||
1556 | struct sh_eth_private *mdp = container_of(napi, struct sh_eth_private, | ||
1557 | napi); | ||
1558 | struct net_device *ndev = napi->dev; | ||
1559 | int quota = budget; | ||
1560 | unsigned long intr_status; | ||
1561 | |||
1562 | for (;;) { | ||
1563 | intr_status = sh_eth_read(ndev, EESR); | ||
1564 | if (!(intr_status & EESR_RX_CHECK)) | ||
1565 | break; | ||
1566 | /* Clear Rx interrupts */ | ||
1567 | sh_eth_write(ndev, intr_status & EESR_RX_CHECK, EESR); | ||
1568 | |||
1569 | if (sh_eth_rx(ndev, intr_status, "a)) | ||
1570 | goto out; | ||
1571 | } | ||
1572 | |||
1573 | napi_complete(napi); | ||
1574 | |||
1575 | /* Reenable Rx interrupts */ | ||
1576 | sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR); | ||
1577 | out: | ||
1578 | return budget - quota; | ||
1579 | } | ||
1580 | |||
1531 | /* PHY state control function */ | 1581 | /* PHY state control function */ |
1532 | static void sh_eth_adjust_link(struct net_device *ndev) | 1582 | static void sh_eth_adjust_link(struct net_device *ndev) |
1533 | { | 1583 | { |
@@ -1839,6 +1889,8 @@ static int sh_eth_open(struct net_device *ndev) | |||
1839 | if (ret) | 1889 | if (ret) |
1840 | goto out_free_irq; | 1890 | goto out_free_irq; |
1841 | 1891 | ||
1892 | napi_enable(&mdp->napi); | ||
1893 | |||
1842 | return ret; | 1894 | return ret; |
1843 | 1895 | ||
1844 | out_free_irq: | 1896 | out_free_irq: |
@@ -1934,6 +1986,8 @@ static int sh_eth_close(struct net_device *ndev) | |||
1934 | { | 1986 | { |
1935 | struct sh_eth_private *mdp = netdev_priv(ndev); | 1987 | struct sh_eth_private *mdp = netdev_priv(ndev); |
1936 | 1988 | ||
1989 | napi_disable(&mdp->napi); | ||
1990 | |||
1937 | netif_stop_queue(ndev); | 1991 | netif_stop_queue(ndev); |
1938 | 1992 | ||
1939 | /* Disable interrupts by clearing the interrupt mask. */ | 1993 | /* Disable interrupts by clearing the interrupt mask. */ |
@@ -2623,10 +2677,12 @@ static int sh_eth_drv_probe(struct platform_device *pdev) | |||
2623 | } | 2677 | } |
2624 | } | 2678 | } |
2625 | 2679 | ||
2680 | netif_napi_add(ndev, &mdp->napi, sh_eth_poll, 64); | ||
2681 | |||
2626 | /* network device register */ | 2682 | /* network device register */ |
2627 | ret = register_netdev(ndev); | 2683 | ret = register_netdev(ndev); |
2628 | if (ret) | 2684 | if (ret) |
2629 | goto out_release; | 2685 | goto out_napi_del; |
2630 | 2686 | ||
2631 | /* mdio bus init */ | 2687 | /* mdio bus init */ |
2632 | ret = sh_mdio_init(ndev, pdev->id, pd); | 2688 | ret = sh_mdio_init(ndev, pdev->id, pd); |
@@ -2644,6 +2700,9 @@ static int sh_eth_drv_probe(struct platform_device *pdev) | |||
2644 | out_unregister: | 2700 | out_unregister: |
2645 | unregister_netdev(ndev); | 2701 | unregister_netdev(ndev); |
2646 | 2702 | ||
2703 | out_napi_del: | ||
2704 | netif_napi_del(&mdp->napi); | ||
2705 | |||
2647 | out_release: | 2706 | out_release: |
2648 | /* net_dev free */ | 2707 | /* net_dev free */ |
2649 | if (ndev) | 2708 | if (ndev) |
@@ -2656,9 +2715,11 @@ out: | |||
2656 | static int sh_eth_drv_remove(struct platform_device *pdev) | 2715 | static int sh_eth_drv_remove(struct platform_device *pdev) |
2657 | { | 2716 | { |
2658 | struct net_device *ndev = platform_get_drvdata(pdev); | 2717 | struct net_device *ndev = platform_get_drvdata(pdev); |
2718 | struct sh_eth_private *mdp = netdev_priv(ndev); | ||
2659 | 2719 | ||
2660 | sh_mdio_release(ndev); | 2720 | sh_mdio_release(ndev); |
2661 | unregister_netdev(ndev); | 2721 | unregister_netdev(ndev); |
2722 | netif_napi_del(&mdp->napi); | ||
2662 | pm_runtime_disable(&pdev->dev); | 2723 | pm_runtime_disable(&pdev->dev); |
2663 | free_netdev(ndev); | 2724 | free_netdev(ndev); |
2664 | 2725 | ||
diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h index d05b60b826eb..029744f77af6 100644 --- a/drivers/net/ethernet/renesas/sh_eth.h +++ b/drivers/net/ethernet/renesas/sh_eth.h | |||
@@ -505,6 +505,7 @@ struct sh_eth_private { | |||
505 | u32 cur_tx, dirty_tx; | 505 | u32 cur_tx, dirty_tx; |
506 | u32 rx_buf_sz; /* Based on MTU+slack. */ | 506 | u32 rx_buf_sz; /* Based on MTU+slack. */ |
507 | int edmac_endian; | 507 | int edmac_endian; |
508 | struct napi_struct napi; | ||
508 | /* MII transceiver section. */ | 509 | /* MII transceiver section. */ |
509 | u32 phy_id; /* PHY ID */ | 510 | u32 phy_id; /* PHY ID */ |
510 | struct mii_bus *mii_bus; /* MDIO bus control */ | 511 | struct mii_bus *mii_bus; /* MDIO bus control */ |