diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/sky2.c | 65 | ||||
-rw-r--r-- | drivers/net/sky2.h | 1 |
2 files changed, 50 insertions, 16 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 2c9118125b5e..fafa4021bb8a 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c | |||
@@ -1866,16 +1866,13 @@ out: | |||
1866 | spin_unlock(&sky2->phy_lock); | 1866 | spin_unlock(&sky2->phy_lock); |
1867 | } | 1867 | } |
1868 | 1868 | ||
1869 | |||
1870 | /* Transmit timeout is only called if we are running, carrier is up | 1869 | /* Transmit timeout is only called if we are running, carrier is up |
1871 | * and tx queue is full (stopped). | 1870 | * and tx queue is full (stopped). |
1872 | * Called with netif_tx_lock held. | ||
1873 | */ | 1871 | */ |
1874 | static void sky2_tx_timeout(struct net_device *dev) | 1872 | static void sky2_tx_timeout(struct net_device *dev) |
1875 | { | 1873 | { |
1876 | struct sky2_port *sky2 = netdev_priv(dev); | 1874 | struct sky2_port *sky2 = netdev_priv(dev); |
1877 | struct sky2_hw *hw = sky2->hw; | 1875 | struct sky2_hw *hw = sky2->hw; |
1878 | u32 imask; | ||
1879 | 1876 | ||
1880 | if (netif_msg_timer(sky2)) | 1877 | if (netif_msg_timer(sky2)) |
1881 | printk(KERN_ERR PFX "%s: tx timeout\n", dev->name); | 1878 | printk(KERN_ERR PFX "%s: tx timeout\n", dev->name); |
@@ -1885,19 +1882,8 @@ static void sky2_tx_timeout(struct net_device *dev) | |||
1885 | sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX), | 1882 | sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX), |
1886 | sky2_read16(hw, Q_ADDR(txqaddr[sky2->port], Q_DONE))); | 1883 | sky2_read16(hw, Q_ADDR(txqaddr[sky2->port], Q_DONE))); |
1887 | 1884 | ||
1888 | imask = sky2_read32(hw, B0_IMSK); /* block IRQ in hw */ | 1885 | /* can't restart safely under softirq */ |
1889 | sky2_write32(hw, B0_IMSK, 0); | 1886 | schedule_work(&hw->restart_work); |
1890 | sky2_read32(hw, B0_IMSK); | ||
1891 | |||
1892 | netif_poll_disable(hw->dev[0]); /* stop NAPI poll */ | ||
1893 | synchronize_irq(hw->pdev->irq); | ||
1894 | |||
1895 | netif_start_queue(dev); /* don't wakeup during flush */ | ||
1896 | sky2_tx_complete(sky2, sky2->tx_prod); /* Flush transmit queue */ | ||
1897 | |||
1898 | sky2_write32(hw, B0_IMSK, imask); | ||
1899 | |||
1900 | sky2_phy_reinit(sky2); /* this clears flow control etc */ | ||
1901 | } | 1887 | } |
1902 | 1888 | ||
1903 | static int sky2_change_mtu(struct net_device *dev, int new_mtu) | 1889 | static int sky2_change_mtu(struct net_device *dev, int new_mtu) |
@@ -2651,6 +2637,49 @@ static void sky2_reset(struct sky2_hw *hw) | |||
2651 | sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_START); | 2637 | sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_START); |
2652 | } | 2638 | } |
2653 | 2639 | ||
2640 | static void sky2_restart(struct work_struct *work) | ||
2641 | { | ||
2642 | struct sky2_hw *hw = container_of(work, struct sky2_hw, restart_work); | ||
2643 | struct net_device *dev; | ||
2644 | int i, err; | ||
2645 | |||
2646 | dev_dbg(&hw->pdev->dev, "restarting\n"); | ||
2647 | |||
2648 | del_timer_sync(&hw->idle_timer); | ||
2649 | |||
2650 | rtnl_lock(); | ||
2651 | sky2_write32(hw, B0_IMSK, 0); | ||
2652 | sky2_read32(hw, B0_IMSK); | ||
2653 | |||
2654 | netif_poll_disable(hw->dev[0]); | ||
2655 | |||
2656 | for (i = 0; i < hw->ports; i++) { | ||
2657 | dev = hw->dev[i]; | ||
2658 | if (netif_running(dev)) | ||
2659 | sky2_down(dev); | ||
2660 | } | ||
2661 | |||
2662 | sky2_reset(hw); | ||
2663 | sky2_write32(hw, B0_IMSK, Y2_IS_BASE); | ||
2664 | netif_poll_enable(hw->dev[0]); | ||
2665 | |||
2666 | for (i = 0; i < hw->ports; i++) { | ||
2667 | dev = hw->dev[i]; | ||
2668 | if (netif_running(dev)) { | ||
2669 | err = sky2_up(dev); | ||
2670 | if (err) { | ||
2671 | printk(KERN_INFO PFX "%s: could not restart %d\n", | ||
2672 | dev->name, err); | ||
2673 | dev_close(dev); | ||
2674 | } | ||
2675 | } | ||
2676 | } | ||
2677 | |||
2678 | sky2_idle_start(hw); | ||
2679 | |||
2680 | rtnl_unlock(); | ||
2681 | } | ||
2682 | |||
2654 | static inline u8 sky2_wol_supported(const struct sky2_hw *hw) | 2683 | static inline u8 sky2_wol_supported(const struct sky2_hw *hw) |
2655 | { | 2684 | { |
2656 | return sky2_is_copper(hw) ? (WAKE_PHY | WAKE_MAGIC) : 0; | 2685 | return sky2_is_copper(hw) ? (WAKE_PHY | WAKE_MAGIC) : 0; |
@@ -3613,6 +3642,8 @@ static int __devinit sky2_probe(struct pci_dev *pdev, | |||
3613 | } | 3642 | } |
3614 | 3643 | ||
3615 | setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) hw); | 3644 | setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) hw); |
3645 | INIT_WORK(&hw->restart_work, sky2_restart); | ||
3646 | |||
3616 | sky2_idle_start(hw); | 3647 | sky2_idle_start(hw); |
3617 | 3648 | ||
3618 | pci_set_drvdata(pdev, hw); | 3649 | pci_set_drvdata(pdev, hw); |
@@ -3649,6 +3680,8 @@ static void __devexit sky2_remove(struct pci_dev *pdev) | |||
3649 | 3680 | ||
3650 | del_timer_sync(&hw->idle_timer); | 3681 | del_timer_sync(&hw->idle_timer); |
3651 | 3682 | ||
3683 | flush_scheduled_work(); | ||
3684 | |||
3652 | sky2_write32(hw, B0_IMSK, 0); | 3685 | sky2_write32(hw, B0_IMSK, 0); |
3653 | synchronize_irq(hw->pdev->irq); | 3686 | synchronize_irq(hw->pdev->irq); |
3654 | 3687 | ||
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index cbca27abe105..ac24bdc42976 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h | |||
@@ -1933,6 +1933,7 @@ struct sky2_hw { | |||
1933 | dma_addr_t st_dma; | 1933 | dma_addr_t st_dma; |
1934 | 1934 | ||
1935 | struct timer_list idle_timer; | 1935 | struct timer_list idle_timer; |
1936 | struct work_struct restart_work; | ||
1936 | int msi; | 1937 | int msi; |
1937 | wait_queue_head_t msi_wait; | 1938 | wait_queue_head_t msi_wait; |
1938 | }; | 1939 | }; |