aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ixp2000
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/ixp2000
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/ixp2000')
-rw-r--r--drivers/net/ixp2000/ixpdev.c39
-rw-r--r--drivers/net/ixp2000/ixpdev.h2
2 files changed, 27 insertions, 14 deletions
diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c
index d9ce1aef148a..6c0dd49149d0 100644
--- a/drivers/net/ixp2000/ixpdev.c
+++ b/drivers/net/ixp2000/ixpdev.c
@@ -74,9 +74,9 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev)
74} 74}
75 75
76 76
77static int ixpdev_rx(struct net_device *dev, int *budget) 77static int ixpdev_rx(struct net_device *dev, int processed, int budget)
78{ 78{
79 while (*budget > 0) { 79 while (processed < budget) {
80 struct ixpdev_rx_desc *desc; 80 struct ixpdev_rx_desc *desc;
81 struct sk_buff *skb; 81 struct sk_buff *skb;
82 void *buf; 82 void *buf;
@@ -122,29 +122,34 @@ static int ixpdev_rx(struct net_device *dev, int *budget)
122 122
123err: 123err:
124 ixp2000_reg_write(RING_RX_PENDING, _desc); 124 ixp2000_reg_write(RING_RX_PENDING, _desc);
125 dev->quota--; 125 processed++;
126 (*budget)--;
127 } 126 }
128 127
129 return 1; 128 return processed;
130} 129}
131 130
132/* dev always points to nds[0]. */ 131/* dev always points to nds[0]. */
133static int ixpdev_poll(struct net_device *dev, int *budget) 132static int ixpdev_poll(struct napi_struct *napi, int budget)
134{ 133{
134 struct ixpdev_priv *ip = container_of(napi, struct ixpdev_priv, napi);
135 struct net_device *dev = ip->dev;
136 int rx;
137
135 /* @@@ Have to stop polling when nds[0] is administratively 138 /* @@@ Have to stop polling when nds[0] is administratively
136 * downed while we are polling. */ 139 * downed while we are polling. */
140 rx = 0;
137 do { 141 do {
138 ixp2000_reg_write(IXP2000_IRQ_THD_RAW_STATUS_A_0, 0x00ff); 142 ixp2000_reg_write(IXP2000_IRQ_THD_RAW_STATUS_A_0, 0x00ff);
139 143
140 if (ixpdev_rx(dev, budget)) 144 rx = ixpdev_rx(dev, rx, budget);
141 return 1; 145 if (rx >= budget)
146 break;
142 } while (ixp2000_reg_read(IXP2000_IRQ_THD_RAW_STATUS_A_0) & 0x00ff); 147 } while (ixp2000_reg_read(IXP2000_IRQ_THD_RAW_STATUS_A_0) & 0x00ff);
143 148
144 netif_rx_complete(dev); 149 netif_rx_complete(dev, napi);
145 ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_SET_A_0, 0x00ff); 150 ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_SET_A_0, 0x00ff);
146 151
147 return 0; 152 return rx;
148} 153}
149 154
150static void ixpdev_tx_complete(void) 155static void ixpdev_tx_complete(void)
@@ -199,9 +204,12 @@ static irqreturn_t ixpdev_interrupt(int irq, void *dev_id)
199 * Any of the eight receive units signaled RX? 204 * Any of the eight receive units signaled RX?
200 */ 205 */
201 if (status & 0x00ff) { 206 if (status & 0x00ff) {
207 struct net_device *dev = nds[0];
208 struct ixpdev_priv *ip = netdev_priv(dev);
209
202 ixp2000_reg_wrb(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0x00ff); 210 ixp2000_reg_wrb(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0x00ff);
203 if (likely(__netif_rx_schedule_prep(nds[0]))) { 211 if (likely(napi_schedule_prep(&ip->napi))) {
204 __netif_rx_schedule(nds[0]); 212 __netif_rx_schedule(dev, &ip->napi);
205 } else { 213 } else {
206 printk(KERN_CRIT "ixp2000: irq while polling!!\n"); 214 printk(KERN_CRIT "ixp2000: irq while polling!!\n");
207 } 215 }
@@ -232,11 +240,13 @@ static int ixpdev_open(struct net_device *dev)
232 struct ixpdev_priv *ip = netdev_priv(dev); 240 struct ixpdev_priv *ip = netdev_priv(dev);
233 int err; 241 int err;
234 242
243 napi_enable(&ip->napi);
235 if (!nds_open++) { 244 if (!nds_open++) {
236 err = request_irq(IRQ_IXP2000_THDA0, ixpdev_interrupt, 245 err = request_irq(IRQ_IXP2000_THDA0, ixpdev_interrupt,
237 IRQF_SHARED, "ixp2000_eth", nds); 246 IRQF_SHARED, "ixp2000_eth", nds);
238 if (err) { 247 if (err) {
239 nds_open--; 248 nds_open--;
249 napi_disable(&ip->napi);
240 return err; 250 return err;
241 } 251 }
242 252
@@ -254,6 +264,7 @@ static int ixpdev_close(struct net_device *dev)
254 struct ixpdev_priv *ip = netdev_priv(dev); 264 struct ixpdev_priv *ip = netdev_priv(dev);
255 265
256 netif_stop_queue(dev); 266 netif_stop_queue(dev);
267 napi_disable(&ip->napi);
257 set_port_admin_status(ip->channel, 0); 268 set_port_admin_status(ip->channel, 0);
258 269
259 if (!--nds_open) { 270 if (!--nds_open) {
@@ -274,7 +285,6 @@ struct net_device *ixpdev_alloc(int channel, int sizeof_priv)
274 return NULL; 285 return NULL;
275 286
276 dev->hard_start_xmit = ixpdev_xmit; 287 dev->hard_start_xmit = ixpdev_xmit;
277 dev->poll = ixpdev_poll;
278 dev->open = ixpdev_open; 288 dev->open = ixpdev_open;
279 dev->stop = ixpdev_close; 289 dev->stop = ixpdev_close;
280#ifdef CONFIG_NET_POLL_CONTROLLER 290#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -282,9 +292,10 @@ struct net_device *ixpdev_alloc(int channel, int sizeof_priv)
282#endif 292#endif
283 293
284 dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; 294 dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
285 dev->weight = 64;
286 295
287 ip = netdev_priv(dev); 296 ip = netdev_priv(dev);
297 ip->dev = dev;
298 netif_napi_add(dev, &ip->napi, ixpdev_poll, 64);
288 ip->channel = channel; 299 ip->channel = channel;
289 ip->tx_queue_entries = 0; 300 ip->tx_queue_entries = 0;
290 301
diff --git a/drivers/net/ixp2000/ixpdev.h b/drivers/net/ixp2000/ixpdev.h
index bd686cb63058..391ece623243 100644
--- a/drivers/net/ixp2000/ixpdev.h
+++ b/drivers/net/ixp2000/ixpdev.h
@@ -14,6 +14,8 @@
14 14
15struct ixpdev_priv 15struct ixpdev_priv
16{ 16{
17 struct net_device *dev;
18 struct napi_struct napi;
17 int channel; 19 int channel;
18 int tx_queue_entries; 20 int tx_queue_entries;
19}; 21};