aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/bnx2.c
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@linux-foundation.org>2007-10-03 19:41:36 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:47:45 -0400
commitbea3348eef27e6044b6161fd04c3152215f96411 (patch)
treef0990b263e5ce42505d290a4c346fe990bcd4c33 /drivers/net/bnx2.c
parentdde4e47e8fe333a5649a3fa0e7db1fa7c08d6158 (diff)
[NET]: Make NAPI polling independent of struct net_device objects.
Several devices have multiple independant RX queues per net device, and some have a single interrupt doorbell for several queues. In either case, it's easier to support layouts like that if the structure representing the poll is independant from the net device itself. The signature of the ->poll() call back goes from: int foo_poll(struct net_device *dev, int *budget) to int foo_poll(struct napi_struct *napi, int budget) The caller is returned the number of RX packets processed (or the number of "NAPI credits" consumed if you want to get abstract). The callee no longer messes around bumping dev->quota, *budget, etc. because that is all handled in the caller upon return. The napi_struct is to be embedded in the device driver private data structures. Furthermore, it is the driver's responsibility to disable all NAPI instances in it's ->stop() device close handler. Since the napi_struct is privatized into the driver's private data structures, only the driver knows how to get at all of the napi_struct instances it may have per-device. With lots of help and suggestions from Rusty Russell, Roland Dreier, Michael Chan, Jeff Garzik, and Jamal Hadi Salim. Bug fixes from Thomas Graf, Roland Dreier, Peter Zijlstra, Joseph Fannin, Scott Wood, Hans J. Koch, and Michael Chan. [ Ported to current tree and all drivers converted. Integrated Stephen's follow-on kerneldoc additions, and restored poll_list handling to the old style to fix mutual exclusion issues. -DaveM ] Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/bnx2.c')
-rw-r--r--drivers/net/bnx2.c47
1 files changed, 22 insertions, 25 deletions
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 66eed22cbd21..ab028ad04235 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -428,7 +428,7 @@ bnx2_netif_stop(struct bnx2 *bp)
428{ 428{
429 bnx2_disable_int_sync(bp); 429 bnx2_disable_int_sync(bp);
430 if (netif_running(bp->dev)) { 430 if (netif_running(bp->dev)) {
431 netif_poll_disable(bp->dev); 431 napi_disable(&bp->napi);
432 netif_tx_disable(bp->dev); 432 netif_tx_disable(bp->dev);
433 bp->dev->trans_start = jiffies; /* prevent tx timeout */ 433 bp->dev->trans_start = jiffies; /* prevent tx timeout */
434 } 434 }
@@ -440,7 +440,7 @@ bnx2_netif_start(struct bnx2 *bp)
440 if (atomic_dec_and_test(&bp->intr_sem)) { 440 if (atomic_dec_and_test(&bp->intr_sem)) {
441 if (netif_running(bp->dev)) { 441 if (netif_running(bp->dev)) {
442 netif_wake_queue(bp->dev); 442 netif_wake_queue(bp->dev);
443 netif_poll_enable(bp->dev); 443 napi_enable(&bp->napi);
444 bnx2_enable_int(bp); 444 bnx2_enable_int(bp);
445 } 445 }
446 } 446 }
@@ -2551,7 +2551,7 @@ bnx2_msi(int irq, void *dev_instance)
2551 if (unlikely(atomic_read(&bp->intr_sem) != 0)) 2551 if (unlikely(atomic_read(&bp->intr_sem) != 0))
2552 return IRQ_HANDLED; 2552 return IRQ_HANDLED;
2553 2553
2554 netif_rx_schedule(dev); 2554 netif_rx_schedule(dev, &bp->napi);
2555 2555
2556 return IRQ_HANDLED; 2556 return IRQ_HANDLED;
2557} 2557}
@@ -2568,7 +2568,7 @@ bnx2_msi_1shot(int irq, void *dev_instance)
2568 if (unlikely(atomic_read(&bp->intr_sem) != 0)) 2568 if (unlikely(atomic_read(&bp->intr_sem) != 0))
2569 return IRQ_HANDLED; 2569 return IRQ_HANDLED;
2570 2570
2571 netif_rx_schedule(dev); 2571 netif_rx_schedule(dev, &bp->napi);
2572 2572
2573 return IRQ_HANDLED; 2573 return IRQ_HANDLED;
2574} 2574}
@@ -2604,9 +2604,9 @@ bnx2_interrupt(int irq, void *dev_instance)
2604 if (unlikely(atomic_read(&bp->intr_sem) != 0)) 2604 if (unlikely(atomic_read(&bp->intr_sem) != 0))
2605 return IRQ_HANDLED; 2605 return IRQ_HANDLED;
2606 2606
2607 if (netif_rx_schedule_prep(dev)) { 2607 if (netif_rx_schedule_prep(dev, &bp->napi)) {
2608 bp->last_status_idx = sblk->status_idx; 2608 bp->last_status_idx = sblk->status_idx;
2609 __netif_rx_schedule(dev); 2609 __netif_rx_schedule(dev, &bp->napi);
2610 } 2610 }
2611 2611
2612 return IRQ_HANDLED; 2612 return IRQ_HANDLED;
@@ -2632,12 +2632,14 @@ bnx2_has_work(struct bnx2 *bp)
2632} 2632}
2633 2633
2634static int 2634static int
2635bnx2_poll(struct net_device *dev, int *budget) 2635bnx2_poll(struct napi_struct *napi, int budget)
2636{ 2636{
2637 struct bnx2 *bp = netdev_priv(dev); 2637 struct bnx2 *bp = container_of(napi, struct bnx2, napi);
2638 struct net_device *dev = bp->dev;
2638 struct status_block *sblk = bp->status_blk; 2639 struct status_block *sblk = bp->status_blk;
2639 u32 status_attn_bits = sblk->status_attn_bits; 2640 u32 status_attn_bits = sblk->status_attn_bits;
2640 u32 status_attn_bits_ack = sblk->status_attn_bits_ack; 2641 u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
2642 int work_done = 0;
2641 2643
2642 if ((status_attn_bits & STATUS_ATTN_EVENTS) != 2644 if ((status_attn_bits & STATUS_ATTN_EVENTS) !=
2643 (status_attn_bits_ack & STATUS_ATTN_EVENTS)) { 2645 (status_attn_bits_ack & STATUS_ATTN_EVENTS)) {
@@ -2655,23 +2657,14 @@ bnx2_poll(struct net_device *dev, int *budget)
2655 if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons) 2657 if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)
2656 bnx2_tx_int(bp); 2658 bnx2_tx_int(bp);
2657 2659
2658 if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) { 2660 if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons)
2659 int orig_budget = *budget; 2661 work_done = bnx2_rx_int(bp, budget);
2660 int work_done;
2661
2662 if (orig_budget > dev->quota)
2663 orig_budget = dev->quota;
2664
2665 work_done = bnx2_rx_int(bp, orig_budget);
2666 *budget -= work_done;
2667 dev->quota -= work_done;
2668 }
2669 2662
2670 bp->last_status_idx = bp->status_blk->status_idx; 2663 bp->last_status_idx = bp->status_blk->status_idx;
2671 rmb(); 2664 rmb();
2672 2665
2673 if (!bnx2_has_work(bp)) { 2666 if (!bnx2_has_work(bp)) {
2674 netif_rx_complete(dev); 2667 netif_rx_complete(dev, napi);
2675 if (likely(bp->flags & USING_MSI_FLAG)) { 2668 if (likely(bp->flags & USING_MSI_FLAG)) {
2676 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, 2669 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
2677 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | 2670 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
@@ -2686,10 +2679,9 @@ bnx2_poll(struct net_device *dev, int *budget)
2686 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, 2679 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
2687 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | 2680 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
2688 bp->last_status_idx); 2681 bp->last_status_idx);
2689 return 0;
2690 } 2682 }
2691 2683
2692 return 1; 2684 return work_done;
2693} 2685}
2694 2686
2695/* Called with rtnl_lock from vlan functions and also netif_tx_lock 2687/* Called with rtnl_lock from vlan functions and also netif_tx_lock
@@ -5039,6 +5031,8 @@ bnx2_open(struct net_device *dev)
5039 if (rc) 5031 if (rc)
5040 return rc; 5032 return rc;
5041 5033
5034 napi_enable(&bp->napi);
5035
5042 if ((bp->flags & MSI_CAP_FLAG) && !disable_msi) { 5036 if ((bp->flags & MSI_CAP_FLAG) && !disable_msi) {
5043 if (pci_enable_msi(bp->pdev) == 0) { 5037 if (pci_enable_msi(bp->pdev) == 0) {
5044 bp->flags |= USING_MSI_FLAG; 5038 bp->flags |= USING_MSI_FLAG;
@@ -5049,6 +5043,7 @@ bnx2_open(struct net_device *dev)
5049 rc = bnx2_request_irq(bp); 5043 rc = bnx2_request_irq(bp);
5050 5044
5051 if (rc) { 5045 if (rc) {
5046 napi_disable(&bp->napi);
5052 bnx2_free_mem(bp); 5047 bnx2_free_mem(bp);
5053 return rc; 5048 return rc;
5054 } 5049 }
@@ -5056,6 +5051,7 @@ bnx2_open(struct net_device *dev)
5056 rc = bnx2_init_nic(bp); 5051 rc = bnx2_init_nic(bp);
5057 5052
5058 if (rc) { 5053 if (rc) {
5054 napi_disable(&bp->napi);
5059 bnx2_free_irq(bp); 5055 bnx2_free_irq(bp);
5060 bnx2_free_skbs(bp); 5056 bnx2_free_skbs(bp);
5061 bnx2_free_mem(bp); 5057 bnx2_free_mem(bp);
@@ -5088,6 +5084,7 @@ bnx2_open(struct net_device *dev)
5088 rc = bnx2_request_irq(bp); 5084 rc = bnx2_request_irq(bp);
5089 5085
5090 if (rc) { 5086 if (rc) {
5087 napi_disable(&bp->napi);
5091 bnx2_free_skbs(bp); 5088 bnx2_free_skbs(bp);
5092 bnx2_free_mem(bp); 5089 bnx2_free_mem(bp);
5093 del_timer_sync(&bp->timer); 5090 del_timer_sync(&bp->timer);
@@ -5301,7 +5298,8 @@ bnx2_close(struct net_device *dev)
5301 while (bp->in_reset_task) 5298 while (bp->in_reset_task)
5302 msleep(1); 5299 msleep(1);
5303 5300
5304 bnx2_netif_stop(bp); 5301 bnx2_disable_int_sync(bp);
5302 napi_disable(&bp->napi);
5305 del_timer_sync(&bp->timer); 5303 del_timer_sync(&bp->timer);
5306 if (bp->flags & NO_WOL_FLAG) 5304 if (bp->flags & NO_WOL_FLAG)
5307 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN; 5305 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
@@ -6858,11 +6856,10 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
6858#ifdef BCM_VLAN 6856#ifdef BCM_VLAN
6859 dev->vlan_rx_register = bnx2_vlan_rx_register; 6857 dev->vlan_rx_register = bnx2_vlan_rx_register;
6860#endif 6858#endif
6861 dev->poll = bnx2_poll;
6862 dev->ethtool_ops = &bnx2_ethtool_ops; 6859 dev->ethtool_ops = &bnx2_ethtool_ops;
6863 dev->weight = 64;
6864 6860
6865 bp = netdev_priv(dev); 6861 bp = netdev_priv(dev);
6862 netif_napi_add(dev, &bp->napi, bnx2_poll, 64);
6866 6863
6867#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) 6864#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
6868 dev->poll_controller = poll_bnx2; 6865 dev->poll_controller = poll_bnx2;