aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/tulip
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/tulip
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/tulip')
-rw-r--r--drivers/net/tulip/interrupt.c54
-rw-r--r--drivers/net/tulip/tulip.h3
-rw-r--r--drivers/net/tulip/tulip_core.c11
3 files changed, 34 insertions, 34 deletions
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
index 53efd6694e75..365331446387 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -103,28 +103,29 @@ int tulip_refill_rx(struct net_device *dev)
103void oom_timer(unsigned long data) 103void oom_timer(unsigned long data)
104{ 104{
105 struct net_device *dev = (struct net_device *)data; 105 struct net_device *dev = (struct net_device *)data;
106 netif_rx_schedule(dev); 106 struct tulip_private *tp = netdev_priv(dev);
107 netif_rx_schedule(dev, &tp->napi);
107} 108}
108 109
109int tulip_poll(struct net_device *dev, int *budget) 110int tulip_poll(struct napi_struct *napi, int budget)
110{ 111{
111 struct tulip_private *tp = netdev_priv(dev); 112 struct tulip_private *tp = container_of(napi, struct tulip_private, napi);
113 struct net_device *dev = tp->dev;
112 int entry = tp->cur_rx % RX_RING_SIZE; 114 int entry = tp->cur_rx % RX_RING_SIZE;
113 int rx_work_limit = *budget; 115 int work_done = 0;
116#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
114 int received = 0; 117 int received = 0;
118#endif
115 119
116 if (!netif_running(dev)) 120 if (!netif_running(dev))
117 goto done; 121 goto done;
118 122
119 if (rx_work_limit > dev->quota)
120 rx_work_limit = dev->quota;
121
122#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION 123#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
123 124
124/* that one buffer is needed for mit activation; or might be a 125/* that one buffer is needed for mit activation; or might be a
125 bug in the ring buffer code; check later -- JHS*/ 126 bug in the ring buffer code; check later -- JHS*/
126 127
127 if (rx_work_limit >=RX_RING_SIZE) rx_work_limit--; 128 if (budget >=RX_RING_SIZE) budget--;
128#endif 129#endif
129 130
130 if (tulip_debug > 4) 131 if (tulip_debug > 4)
@@ -144,14 +145,13 @@ int tulip_poll(struct net_device *dev, int *budget)
144 while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { 145 while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
145 s32 status = le32_to_cpu(tp->rx_ring[entry].status); 146 s32 status = le32_to_cpu(tp->rx_ring[entry].status);
146 147
147
148 if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx) 148 if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx)
149 break; 149 break;
150 150
151 if (tulip_debug > 5) 151 if (tulip_debug > 5)
152 printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n", 152 printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n",
153 dev->name, entry, status); 153 dev->name, entry, status);
154 if (--rx_work_limit < 0) 154 if (work_done++ >= budget)
155 goto not_done; 155 goto not_done;
156 156
157 if ((status & 0x38008300) != 0x0300) { 157 if ((status & 0x38008300) != 0x0300) {
@@ -238,7 +238,9 @@ int tulip_poll(struct net_device *dev, int *budget)
238 tp->stats.rx_packets++; 238 tp->stats.rx_packets++;
239 tp->stats.rx_bytes += pkt_len; 239 tp->stats.rx_bytes += pkt_len;
240 } 240 }
241 received++; 241#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
242 received++;
243#endif
242 244
243 entry = (++tp->cur_rx) % RX_RING_SIZE; 245 entry = (++tp->cur_rx) % RX_RING_SIZE;
244 if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/4) 246 if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/4)
@@ -296,17 +298,15 @@ done:
296 298
297#endif /* CONFIG_TULIP_NAPI_HW_MITIGATION */ 299#endif /* CONFIG_TULIP_NAPI_HW_MITIGATION */
298 300
299 dev->quota -= received;
300 *budget -= received;
301
302 tulip_refill_rx(dev); 301 tulip_refill_rx(dev);
303 302
304 /* If RX ring is not full we are out of memory. */ 303 /* If RX ring is not full we are out of memory. */
305 if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) goto oom; 304 if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)
305 goto oom;
306 306
307 /* Remove us from polling list and enable RX intr. */ 307 /* Remove us from polling list and enable RX intr. */
308 308
309 netif_rx_complete(dev); 309 netif_rx_complete(dev, napi);
310 iowrite32(tulip_tbl[tp->chip_id].valid_intrs, tp->base_addr+CSR7); 310 iowrite32(tulip_tbl[tp->chip_id].valid_intrs, tp->base_addr+CSR7);
311 311
312 /* The last op happens after poll completion. Which means the following: 312 /* The last op happens after poll completion. Which means the following:
@@ -320,28 +320,20 @@ done:
320 * processed irqs. But it must not result in losing events. 320 * processed irqs. But it must not result in losing events.
321 */ 321 */
322 322
323 return 0; 323 return work_done;
324 324
325 not_done: 325 not_done:
326 if (!received) {
327
328 received = dev->quota; /* Not to happen */
329 }
330 dev->quota -= received;
331 *budget -= received;
332
333 if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 || 326 if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 ||
334 tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) 327 tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)
335 tulip_refill_rx(dev); 328 tulip_refill_rx(dev);
336 329
337 if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) goto oom; 330 if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)
338 331 goto oom;
339 return 1;
340 332
333 return work_done;
341 334
342 oom: /* Executed with RX ints disabled */ 335 oom: /* Executed with RX ints disabled */
343 336
344
345 /* Start timer, stop polling, but do not enable rx interrupts. */ 337 /* Start timer, stop polling, but do not enable rx interrupts. */
346 mod_timer(&tp->oom_timer, jiffies+1); 338 mod_timer(&tp->oom_timer, jiffies+1);
347 339
@@ -350,9 +342,9 @@ done:
350 * before we did netif_rx_complete(). See? We would lose it. */ 342 * before we did netif_rx_complete(). See? We would lose it. */
351 343
352 /* remove ourselves from the polling list */ 344 /* remove ourselves from the polling list */
353 netif_rx_complete(dev); 345 netif_rx_complete(dev, napi);
354 346
355 return 0; 347 return work_done;
356} 348}
357 349
358#else /* CONFIG_TULIP_NAPI */ 350#else /* CONFIG_TULIP_NAPI */
@@ -534,7 +526,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
534 rxd++; 526 rxd++;
535 /* Mask RX intrs and add the device to poll list. */ 527 /* Mask RX intrs and add the device to poll list. */
536 iowrite32(tulip_tbl[tp->chip_id].valid_intrs&~RxPollInt, ioaddr + CSR7); 528 iowrite32(tulip_tbl[tp->chip_id].valid_intrs&~RxPollInt, ioaddr + CSR7);
537 netif_rx_schedule(dev); 529 netif_rx_schedule(dev, &tp->napi);
538 530
539 if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass))) 531 if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass)))
540 break; 532 break;
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
index 16f26a8364f0..5a4d7270973e 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -353,6 +353,7 @@ struct tulip_private {
353 int chip_id; 353 int chip_id;
354 int revision; 354 int revision;
355 int flags; 355 int flags;
356 struct napi_struct napi;
356 struct net_device_stats stats; 357 struct net_device_stats stats;
357 struct timer_list timer; /* Media selection timer. */ 358 struct timer_list timer; /* Media selection timer. */
358 struct timer_list oom_timer; /* Out of memory timer. */ 359 struct timer_list oom_timer; /* Out of memory timer. */
@@ -429,7 +430,7 @@ extern int tulip_rx_copybreak;
429irqreturn_t tulip_interrupt(int irq, void *dev_instance); 430irqreturn_t tulip_interrupt(int irq, void *dev_instance);
430int tulip_refill_rx(struct net_device *dev); 431int tulip_refill_rx(struct net_device *dev);
431#ifdef CONFIG_TULIP_NAPI 432#ifdef CONFIG_TULIP_NAPI
432int tulip_poll(struct net_device *dev, int *budget); 433int tulip_poll(struct napi_struct *napi, int budget);
433#endif 434#endif
434 435
435 436
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index eca984f89bbf..7040a59fa3c9 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -294,6 +294,10 @@ static void tulip_up(struct net_device *dev)
294 int next_tick = 3*HZ; 294 int next_tick = 3*HZ;
295 int i; 295 int i;
296 296
297#ifdef CONFIG_TULIP_NAPI
298 napi_enable(&tp->napi);
299#endif
300
297 /* Wake the chip from sleep/snooze mode. */ 301 /* Wake the chip from sleep/snooze mode. */
298 tulip_set_power_state (tp, 0, 0); 302 tulip_set_power_state (tp, 0, 0);
299 303
@@ -728,6 +732,10 @@ static void tulip_down (struct net_device *dev)
728 732
729 flush_scheduled_work(); 733 flush_scheduled_work();
730 734
735#ifdef CONFIG_TULIP_NAPI
736 napi_disable(&tp->napi);
737#endif
738
731 del_timer_sync (&tp->timer); 739 del_timer_sync (&tp->timer);
732#ifdef CONFIG_TULIP_NAPI 740#ifdef CONFIG_TULIP_NAPI
733 del_timer_sync (&tp->oom_timer); 741 del_timer_sync (&tp->oom_timer);
@@ -1606,8 +1614,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
1606 dev->tx_timeout = tulip_tx_timeout; 1614 dev->tx_timeout = tulip_tx_timeout;
1607 dev->watchdog_timeo = TX_TIMEOUT; 1615 dev->watchdog_timeo = TX_TIMEOUT;
1608#ifdef CONFIG_TULIP_NAPI 1616#ifdef CONFIG_TULIP_NAPI
1609 dev->poll = tulip_poll; 1617 netif_napi_add(dev, &tp->napi, tulip_poll, 16);
1610 dev->weight = 16;
1611#endif 1618#endif
1612 dev->stop = tulip_close; 1619 dev->stop = tulip_close;
1613 dev->get_stats = tulip_get_stats; 1620 dev->get_stats = tulip_get_stats;