diff options
Diffstat (limited to 'drivers/net/arm')
-rw-r--r-- | drivers/net/arm/ep93xx_eth.c | 72 |
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 | ||
193 | static int ep93xx_rx(struct net_device *dev, int *budget) | 196 | static 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) | |||
275 | err: | 272 | err: |
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 | ||
290 | static int ep93xx_have_more_rx(struct ep93xx_priv *ep) | 285 | static 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 | ||
296 | static int ep93xx_poll(struct net_device *dev, int *budget) | 291 | static 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 | ||
305 | poll_some_more: | 297 | poll_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 | ||
328 | static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev) | 319 | static 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 | ||