.. | .. |
---|
387 | 387 | struct arcnet_local *lp = from_timer(lp, t, timer); |
---|
388 | 388 | struct net_device *dev = lp->dev; |
---|
389 | 389 | |
---|
390 | | - if (!netif_carrier_ok(dev)) { |
---|
| 390 | + spin_lock_irq(&lp->lock); |
---|
| 391 | + |
---|
| 392 | + if (!lp->reset_in_progress && !netif_carrier_ok(dev)) { |
---|
391 | 393 | netif_carrier_on(dev); |
---|
392 | 394 | netdev_info(dev, "link up\n"); |
---|
393 | 395 | } |
---|
| 396 | + |
---|
| 397 | + spin_unlock_irq(&lp->lock); |
---|
| 398 | +} |
---|
| 399 | + |
---|
| 400 | +static void reset_device_work(struct work_struct *work) |
---|
| 401 | +{ |
---|
| 402 | + struct arcnet_local *lp; |
---|
| 403 | + struct net_device *dev; |
---|
| 404 | + |
---|
| 405 | + lp = container_of(work, struct arcnet_local, reset_work); |
---|
| 406 | + dev = lp->dev; |
---|
| 407 | + |
---|
| 408 | + /* Do not bring the network interface back up if an ifdown |
---|
| 409 | + * was already done. |
---|
| 410 | + */ |
---|
| 411 | + if (!netif_running(dev) || !lp->reset_in_progress) |
---|
| 412 | + return; |
---|
| 413 | + |
---|
| 414 | + rtnl_lock(); |
---|
| 415 | + |
---|
| 416 | + /* Do another check, in case of an ifdown that was triggered in |
---|
| 417 | + * the small race window between the exit condition above and |
---|
| 418 | + * acquiring RTNL. |
---|
| 419 | + */ |
---|
| 420 | + if (!netif_running(dev) || !lp->reset_in_progress) |
---|
| 421 | + goto out; |
---|
| 422 | + |
---|
| 423 | + dev_close(dev); |
---|
| 424 | + dev_open(dev, NULL); |
---|
| 425 | + |
---|
| 426 | +out: |
---|
| 427 | + rtnl_unlock(); |
---|
394 | 428 | } |
---|
395 | 429 | |
---|
396 | 430 | static void arcnet_reply_tasklet(unsigned long data) |
---|
.. | .. |
---|
434 | 468 | |
---|
435 | 469 | ret = sock_queue_err_skb(sk, ackskb); |
---|
436 | 470 | if (ret) |
---|
437 | | - kfree_skb(ackskb); |
---|
| 471 | + dev_kfree_skb_irq(ackskb); |
---|
438 | 472 | |
---|
439 | 473 | local_irq_enable(); |
---|
440 | 474 | }; |
---|
.. | .. |
---|
452 | 486 | lp->dev = dev; |
---|
453 | 487 | spin_lock_init(&lp->lock); |
---|
454 | 488 | timer_setup(&lp->timer, arcnet_timer, 0); |
---|
| 489 | + INIT_WORK(&lp->reset_work, reset_device_work); |
---|
455 | 490 | } |
---|
456 | 491 | |
---|
457 | 492 | return dev; |
---|
458 | 493 | } |
---|
459 | 494 | EXPORT_SYMBOL(alloc_arcdev); |
---|
| 495 | + |
---|
| 496 | +void free_arcdev(struct net_device *dev) |
---|
| 497 | +{ |
---|
| 498 | + struct arcnet_local *lp = netdev_priv(dev); |
---|
| 499 | + |
---|
| 500 | + /* Do not cancel this at ->ndo_close(), as the workqueue itself |
---|
| 501 | + * indirectly calls the ifdown path through dev_close(). |
---|
| 502 | + */ |
---|
| 503 | + cancel_work_sync(&lp->reset_work); |
---|
| 504 | + free_netdev(dev); |
---|
| 505 | +} |
---|
| 506 | +EXPORT_SYMBOL(free_arcdev); |
---|
460 | 507 | |
---|
461 | 508 | /* Open/initialize the board. This is called sometime after booting when |
---|
462 | 509 | * the 'ifconfig' program is run. |
---|
.. | .. |
---|
587 | 634 | |
---|
588 | 635 | /* shut down the card */ |
---|
589 | 636 | lp->hw.close(dev); |
---|
| 637 | + |
---|
| 638 | + /* reset counters */ |
---|
| 639 | + lp->reset_in_progress = 0; |
---|
| 640 | + |
---|
590 | 641 | module_put(lp->hw.owner); |
---|
591 | 642 | return 0; |
---|
592 | 643 | } |
---|
.. | .. |
---|
763 | 814 | } |
---|
764 | 815 | |
---|
765 | 816 | /* Called by the kernel when transmit times out */ |
---|
766 | | -void arcnet_timeout(struct net_device *dev) |
---|
| 817 | +void arcnet_timeout(struct net_device *dev, unsigned int txqueue) |
---|
767 | 818 | { |
---|
768 | 819 | unsigned long flags; |
---|
769 | 820 | struct arcnet_local *lp = netdev_priv(dev); |
---|
.. | .. |
---|
820 | 871 | |
---|
821 | 872 | spin_lock_irqsave(&lp->lock, flags); |
---|
822 | 873 | |
---|
| 874 | + if (lp->reset_in_progress) |
---|
| 875 | + goto out; |
---|
| 876 | + |
---|
823 | 877 | /* RESET flag was enabled - if device is not running, we must |
---|
824 | 878 | * clear it right away (but nothing else). |
---|
825 | 879 | */ |
---|
.. | .. |
---|
852 | 906 | if (status & RESETflag) { |
---|
853 | 907 | arc_printk(D_NORMAL, dev, "spurious reset (status=%Xh)\n", |
---|
854 | 908 | status); |
---|
855 | | - arcnet_close(dev); |
---|
856 | | - arcnet_open(dev); |
---|
| 909 | + |
---|
| 910 | + lp->reset_in_progress = 1; |
---|
| 911 | + netif_stop_queue(dev); |
---|
| 912 | + netif_carrier_off(dev); |
---|
| 913 | + schedule_work(&lp->reset_work); |
---|
857 | 914 | |
---|
858 | 915 | /* get out of the interrupt handler! */ |
---|
859 | | - break; |
---|
| 916 | + goto out; |
---|
860 | 917 | } |
---|
861 | 918 | /* RX is inhibited - we must have received something. |
---|
862 | 919 | * Prepare to receive into the next buffer. |
---|
.. | .. |
---|
1052 | 1109 | udelay(1); |
---|
1053 | 1110 | lp->hw.intmask(dev, lp->intmask); |
---|
1054 | 1111 | |
---|
| 1112 | +out: |
---|
1055 | 1113 | spin_unlock_irqrestore(&lp->lock, flags); |
---|
1056 | 1114 | return retval; |
---|
1057 | 1115 | } |
---|