aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/arm
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/arm
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/arm')
-rw-r--r--drivers/net/arm/ep93xx_eth.c72
1 files changed, 34 insertions, 38 deletions
diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c
index f6ece1d43f6e..7f016f3d5bf0 100644
--- a/drivers/net/arm/ep93xx_eth.c
+++ b/drivers/net/arm/ep93xx_eth.c
@@ -169,6 +169,9 @@ struct ep93xx_priv
169 spinlock_t tx_pending_lock; 169 spinlock_t tx_pending_lock;
170 unsigned int tx_pending; 170 unsigned int tx_pending;
171 171
172 struct net_device *dev;
173 struct napi_struct napi;
174
172 struct net_device_stats stats; 175 struct net_device_stats stats;
173 176
174 struct mii_if_info mii; 177 struct mii_if_info mii;
@@ -190,15 +193,11 @@ static struct net_device_stats *ep93xx_get_stats(struct net_device *dev)
190 return &(ep->stats); 193 return &(ep->stats);
191} 194}
192 195
193static int ep93xx_rx(struct net_device *dev, int *budget) 196static int ep93xx_rx(struct net_device *dev, int processed, int budget)
194{ 197{
195 struct ep93xx_priv *ep = netdev_priv(dev); 198 struct ep93xx_priv *ep = netdev_priv(dev);
196 int rx_done;
197 int processed;
198 199
199 rx_done = 0; 200 while (processed < budget) {
200 processed = 0;
201 while (*budget > 0) {
202 int entry; 201 int entry;
203 struct ep93xx_rstat *rstat; 202 struct ep93xx_rstat *rstat;
204 u32 rstat0; 203 u32 rstat0;
@@ -211,10 +210,8 @@ static int ep93xx_rx(struct net_device *dev, int *budget)
211 210
212 rstat0 = rstat->rstat0; 211 rstat0 = rstat->rstat0;
213 rstat1 = rstat->rstat1; 212 rstat1 = rstat->rstat1;
214 if (!(rstat0 & RSTAT0_RFP) || !(rstat1 & RSTAT1_RFP)) { 213 if (!(rstat0 & RSTAT0_RFP) || !(rstat1 & RSTAT1_RFP))
215 rx_done = 1;
216 break; 214 break;
217 }
218 215
219 rstat->rstat0 = 0; 216 rstat->rstat0 = 0;
220 rstat->rstat1 = 0; 217 rstat->rstat1 = 0;
@@ -275,8 +272,6 @@ static int ep93xx_rx(struct net_device *dev, int *budget)
275err: 272err:
276 ep->rx_pointer = (entry + 1) & (RX_QUEUE_ENTRIES - 1); 273 ep->rx_pointer = (entry + 1) & (RX_QUEUE_ENTRIES - 1);
277 processed++; 274 processed++;
278 dev->quota--;
279 (*budget)--;
280 } 275 }
281 276
282 if (processed) { 277 if (processed) {
@@ -284,7 +279,7 @@ err:
284 wrw(ep, REG_RXSTSENQ, processed); 279 wrw(ep, REG_RXSTSENQ, processed);
285 } 280 }
286 281
287 return !rx_done; 282 return processed;
288} 283}
289 284
290static int ep93xx_have_more_rx(struct ep93xx_priv *ep) 285static int ep93xx_have_more_rx(struct ep93xx_priv *ep)
@@ -293,36 +288,32 @@ static int ep93xx_have_more_rx(struct ep93xx_priv *ep)
293 return !!((rstat->rstat0 & RSTAT0_RFP) && (rstat->rstat1 & RSTAT1_RFP)); 288 return !!((rstat->rstat0 & RSTAT0_RFP) && (rstat->rstat1 & RSTAT1_RFP));
294} 289}
295 290
296static int ep93xx_poll(struct net_device *dev, int *budget) 291static int ep93xx_poll(struct napi_struct *napi, int budget)
297{ 292{
298 struct ep93xx_priv *ep = netdev_priv(dev); 293 struct ep93xx_priv *ep = container_of(napi, struct ep93xx_priv, napi);
299 294 struct net_device *dev = ep->dev;
300 /* 295 int rx = 0;
301 * @@@ Have to stop polling if device is downed while we
302 * are polling.
303 */
304 296
305poll_some_more: 297poll_some_more:
306 if (ep93xx_rx(dev, budget)) 298 rx = ep93xx_rx(dev, rx, budget);
307 return 1; 299 if (rx < budget) {
308 300 int more = 0;
309 netif_rx_complete(dev); 301
310 302 spin_lock_irq(&ep->rx_lock);
311 spin_lock_irq(&ep->rx_lock); 303 __netif_rx_complete(dev, napi);
312 wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX); 304 wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX);
313 if (ep93xx_have_more_rx(ep)) { 305 if (ep93xx_have_more_rx(ep)) {
314 wrl(ep, REG_INTEN, REG_INTEN_TX); 306 wrl(ep, REG_INTEN, REG_INTEN_TX);
315 wrl(ep, REG_INTSTSP, REG_INTSTS_RX); 307 wrl(ep, REG_INTSTSP, REG_INTSTS_RX);
308 more = 1;
309 }
316 spin_unlock_irq(&ep->rx_lock); 310 spin_unlock_irq(&ep->rx_lock);
317 311
318 if (netif_rx_reschedule(dev, 0)) 312 if (more && netif_rx_reschedule(dev, napi))
319 goto poll_some_more; 313 goto poll_some_more;
320
321 return 0;
322 } 314 }
323 spin_unlock_irq(&ep->rx_lock);
324 315
325 return 0; 316 return rx;
326} 317}
327 318
328static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev) 319static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -426,9 +417,9 @@ static irqreturn_t ep93xx_irq(int irq, void *dev_id)
426 417
427 if (status & REG_INTSTS_RX) { 418 if (status & REG_INTSTS_RX) {
428 spin_lock(&ep->rx_lock); 419 spin_lock(&ep->rx_lock);
429 if (likely(__netif_rx_schedule_prep(dev))) { 420 if (likely(__netif_rx_schedule_prep(dev, &ep->napi))) {
430 wrl(ep, REG_INTEN, REG_INTEN_TX); 421 wrl(ep, REG_INTEN, REG_INTEN_TX);
431 __netif_rx_schedule(dev); 422 __netif_rx_schedule(dev, &ep->napi);
432 } 423 }
433 spin_unlock(&ep->rx_lock); 424 spin_unlock(&ep->rx_lock);
434 } 425 }
@@ -648,7 +639,10 @@ static int ep93xx_open(struct net_device *dev)
648 dev->dev_addr[4], dev->dev_addr[5]); 639 dev->dev_addr[4], dev->dev_addr[5]);
649 } 640 }
650 641
642 napi_enable(&ep->napi);
643
651 if (ep93xx_start_hw(dev)) { 644 if (ep93xx_start_hw(dev)) {
645 napi_disable(&ep->napi);
652 ep93xx_free_buffers(ep); 646 ep93xx_free_buffers(ep);
653 return -EIO; 647 return -EIO;
654 } 648 }
@@ -662,6 +656,7 @@ static int ep93xx_open(struct net_device *dev)
662 656
663 err = request_irq(ep->irq, ep93xx_irq, IRQF_SHARED, dev->name, dev); 657 err = request_irq(ep->irq, ep93xx_irq, IRQF_SHARED, dev->name, dev);
664 if (err) { 658 if (err) {
659 napi_disable(&ep->napi);
665 ep93xx_stop_hw(dev); 660 ep93xx_stop_hw(dev);
666 ep93xx_free_buffers(ep); 661 ep93xx_free_buffers(ep);
667 return err; 662 return err;
@@ -678,6 +673,7 @@ static int ep93xx_close(struct net_device *dev)
678{ 673{
679 struct ep93xx_priv *ep = netdev_priv(dev); 674 struct ep93xx_priv *ep = netdev_priv(dev);
680 675
676 napi_disable(&ep->napi);
681 netif_stop_queue(dev); 677 netif_stop_queue(dev);
682 678
683 wrl(ep, REG_GIINTMSK, 0); 679 wrl(ep, REG_GIINTMSK, 0);
@@ -788,14 +784,12 @@ struct net_device *ep93xx_dev_alloc(struct ep93xx_eth_data *data)
788 784
789 dev->get_stats = ep93xx_get_stats; 785 dev->get_stats = ep93xx_get_stats;
790 dev->ethtool_ops = &ep93xx_ethtool_ops; 786 dev->ethtool_ops = &ep93xx_ethtool_ops;
791 dev->poll = ep93xx_poll;
792 dev->hard_start_xmit = ep93xx_xmit; 787 dev->hard_start_xmit = ep93xx_xmit;
793 dev->open = ep93xx_open; 788 dev->open = ep93xx_open;
794 dev->stop = ep93xx_close; 789 dev->stop = ep93xx_close;
795 dev->do_ioctl = ep93xx_ioctl; 790 dev->do_ioctl = ep93xx_ioctl;
796 791
797 dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; 792 dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
798 dev->weight = 64;
799 793
800 return dev; 794 return dev;
801} 795}
@@ -847,6 +841,8 @@ static int ep93xx_eth_probe(struct platform_device *pdev)
847 goto err_out; 841 goto err_out;
848 } 842 }
849 ep = netdev_priv(dev); 843 ep = netdev_priv(dev);
844 ep->dev = dev;
845 netif_napi_add(dev, &ep->napi, ep93xx_poll, 64);
850 846
851 platform_set_drvdata(pdev, dev); 847 platform_set_drvdata(pdev, dev);
852 848