aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/fs_enet
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/fs_enet
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/fs_enet')
-rw-r--r--drivers/net/fs_enet/fs_enet-main.c55
-rw-r--r--drivers/net/fs_enet/fs_enet.h1
2 files changed, 25 insertions, 31 deletions
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index a4a2a0ea43d3..c509cb13222d 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -70,18 +70,16 @@ static void fs_set_multicast_list(struct net_device *dev)
70} 70}
71 71
72/* NAPI receive function */ 72/* NAPI receive function */
73static int fs_enet_rx_napi(struct net_device *dev, int *budget) 73static int fs_enet_rx_napi(struct napi_struct *napi, int budget)
74{ 74{
75 struct fs_enet_private *fep = netdev_priv(dev); 75 struct fs_enet_private *fep = container_of(napi, struct fs_enet_private, napi);
76 struct net_device *dev = to_net_dev(fep->dev);
76 const struct fs_platform_info *fpi = fep->fpi; 77 const struct fs_platform_info *fpi = fep->fpi;
77 cbd_t *bdp; 78 cbd_t *bdp;
78 struct sk_buff *skb, *skbn, *skbt; 79 struct sk_buff *skb, *skbn, *skbt;
79 int received = 0; 80 int received = 0;
80 u16 pkt_len, sc; 81 u16 pkt_len, sc;
81 int curidx; 82 int curidx;
82 int rx_work_limit = 0; /* pacify gcc */
83
84 rx_work_limit = min(dev->quota, *budget);
85 83
86 if (!netif_running(dev)) 84 if (!netif_running(dev))
87 return 0; 85 return 0;
@@ -96,7 +94,6 @@ static int fs_enet_rx_napi(struct net_device *dev, int *budget)
96 (*fep->ops->napi_clear_rx_event)(dev); 94 (*fep->ops->napi_clear_rx_event)(dev);
97 95
98 while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { 96 while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) {
99
100 curidx = bdp - fep->rx_bd_base; 97 curidx = bdp - fep->rx_bd_base;
101 98
102 /* 99 /*
@@ -136,11 +133,6 @@ static int fs_enet_rx_napi(struct net_device *dev, int *budget)
136 skbn = skb; 133 skbn = skb;
137 134
138 } else { 135 } else {
139
140 /* napi, got packet but no quota */
141 if (--rx_work_limit < 0)
142 break;
143
144 skb = fep->rx_skbuff[curidx]; 136 skb = fep->rx_skbuff[curidx];
145 137
146 dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), 138 dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp),
@@ -199,22 +191,19 @@ static int fs_enet_rx_napi(struct net_device *dev, int *budget)
199 bdp = fep->rx_bd_base; 191 bdp = fep->rx_bd_base;
200 192
201 (*fep->ops->rx_bd_done)(dev); 193 (*fep->ops->rx_bd_done)(dev);
194
195 if (received >= budget)
196 break;
202 } 197 }
203 198
204 fep->cur_rx = bdp; 199 fep->cur_rx = bdp;
205 200
206 dev->quota -= received; 201 if (received >= budget) {
207 *budget -= received; 202 /* done */
208 203 netif_rx_complete(dev, napi);
209 if (rx_work_limit < 0) 204 (*fep->ops->napi_enable_rx)(dev);
210 return 1; /* not done */ 205 }
211 206 return received;
212 /* done */
213 netif_rx_complete(dev);
214
215 (*fep->ops->napi_enable_rx)(dev);
216
217 return 0;
218} 207}
219 208
220/* non NAPI receive function */ 209/* non NAPI receive function */
@@ -470,7 +459,7 @@ fs_enet_interrupt(int irq, void *dev_id)
470 if (!fpi->use_napi) 459 if (!fpi->use_napi)
471 fs_enet_rx_non_napi(dev); 460 fs_enet_rx_non_napi(dev);
472 else { 461 else {
473 napi_ok = netif_rx_schedule_prep(dev); 462 napi_ok = napi_schedule_prep(&fep->napi);
474 463
475 (*fep->ops->napi_disable_rx)(dev); 464 (*fep->ops->napi_disable_rx)(dev);
476 (*fep->ops->clear_int_events)(dev, fep->ev_napi_rx); 465 (*fep->ops->clear_int_events)(dev, fep->ev_napi_rx);
@@ -478,7 +467,7 @@ fs_enet_interrupt(int irq, void *dev_id)
478 /* NOTE: it is possible for FCCs in NAPI mode */ 467 /* NOTE: it is possible for FCCs in NAPI mode */
479 /* to submit a spurious interrupt while in poll */ 468 /* to submit a spurious interrupt while in poll */
480 if (napi_ok) 469 if (napi_ok)
481 __netif_rx_schedule(dev); 470 __netif_rx_schedule(dev, &fep->napi);
482 } 471 }
483 } 472 }
484 473
@@ -799,18 +788,22 @@ static int fs_enet_open(struct net_device *dev)
799 int r; 788 int r;
800 int err; 789 int err;
801 790
791 napi_enable(&fep->napi);
792
802 /* Install our interrupt handler. */ 793 /* Install our interrupt handler. */
803 r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt); 794 r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt);
804 if (r != 0) { 795 if (r != 0) {
805 printk(KERN_ERR DRV_MODULE_NAME 796 printk(KERN_ERR DRV_MODULE_NAME
806 ": %s Could not allocate FS_ENET IRQ!", dev->name); 797 ": %s Could not allocate FS_ENET IRQ!", dev->name);
798 napi_disable(&fep->napi);
807 return -EINVAL; 799 return -EINVAL;
808 } 800 }
809 801
810 err = fs_init_phy(dev); 802 err = fs_init_phy(dev);
811 if(err) 803 if(err) {
804 napi_disable(&fep->napi);
812 return err; 805 return err;
813 806 }
814 phy_start(fep->phydev); 807 phy_start(fep->phydev);
815 808
816 return 0; 809 return 0;
@@ -823,6 +816,7 @@ static int fs_enet_close(struct net_device *dev)
823 816
824 netif_stop_queue(dev); 817 netif_stop_queue(dev);
825 netif_carrier_off(dev); 818 netif_carrier_off(dev);
819 napi_disable(&fep->napi);
826 phy_stop(fep->phydev); 820 phy_stop(fep->phydev);
827 821
828 spin_lock_irqsave(&fep->lock, flags); 822 spin_lock_irqsave(&fep->lock, flags);
@@ -1047,10 +1041,9 @@ static struct net_device *fs_init_instance(struct device *dev,
1047 ndev->stop = fs_enet_close; 1041 ndev->stop = fs_enet_close;
1048 ndev->get_stats = fs_enet_get_stats; 1042 ndev->get_stats = fs_enet_get_stats;
1049 ndev->set_multicast_list = fs_set_multicast_list; 1043 ndev->set_multicast_list = fs_set_multicast_list;
1050 if (fpi->use_napi) { 1044 netif_napi_add(ndev, &fep->napi,
1051 ndev->poll = fs_enet_rx_napi; 1045 fs_enet_rx_napi, fpi->napi_weight);
1052 ndev->weight = fpi->napi_weight; 1046
1053 }
1054 ndev->ethtool_ops = &fs_ethtool_ops; 1047 ndev->ethtool_ops = &fs_ethtool_ops;
1055 ndev->do_ioctl = fs_ioctl; 1048 ndev->do_ioctl = fs_ioctl;
1056 1049
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h
index 569be225cd05..46d0606b1439 100644
--- a/drivers/net/fs_enet/fs_enet.h
+++ b/drivers/net/fs_enet/fs_enet.h
@@ -121,6 +121,7 @@ struct fs_enet_mii_bus {
121}; 121};
122 122
123struct fs_enet_private { 123struct fs_enet_private {
124 struct napi_struct napi;
124 struct device *dev; /* pointer back to the device (must be initialized first) */ 125 struct device *dev; /* pointer back to the device (must be initialized first) */
125 spinlock_t lock; /* during all ops except TX pckt processing */ 126 spinlock_t lock; /* during all ops except TX pckt processing */
126 spinlock_t tx_lock; /* during fs_start_xmit and fs_tx */ 127 spinlock_t tx_lock; /* during fs_start_xmit and fs_tx */