diff options
Diffstat (limited to 'drivers/net/ks8842.c')
-rw-r--r-- | drivers/net/ks8842.c | 24 |
1 files changed, 22 insertions, 2 deletions
diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c index d47bba9202e1..5191af2c1fa0 100644 --- a/drivers/net/ks8842.c +++ b/drivers/net/ks8842.c | |||
@@ -119,6 +119,8 @@ struct ks8842_adapter { | |||
119 | int irq; | 119 | int irq; |
120 | struct tasklet_struct tasklet; | 120 | struct tasklet_struct tasklet; |
121 | spinlock_t lock; /* spinlock to be interrupt safe */ | 121 | spinlock_t lock; /* spinlock to be interrupt safe */ |
122 | struct work_struct timeout_work; | ||
123 | struct net_device *netdev; | ||
122 | }; | 124 | }; |
123 | 125 | ||
124 | static inline void ks8842_select_bank(struct ks8842_adapter *adapter, u16 bank) | 126 | static inline void ks8842_select_bank(struct ks8842_adapter *adapter, u16 bank) |
@@ -553,6 +555,8 @@ static int ks8842_close(struct net_device *netdev) | |||
553 | 555 | ||
554 | netdev_dbg(netdev, "%s - entry\n", __func__); | 556 | netdev_dbg(netdev, "%s - entry\n", __func__); |
555 | 557 | ||
558 | cancel_work_sync(&adapter->timeout_work); | ||
559 | |||
556 | /* free the irq */ | 560 | /* free the irq */ |
557 | free_irq(adapter->irq, netdev); | 561 | free_irq(adapter->irq, netdev); |
558 | 562 | ||
@@ -595,9 +599,11 @@ static int ks8842_set_mac(struct net_device *netdev, void *p) | |||
595 | return 0; | 599 | return 0; |
596 | } | 600 | } |
597 | 601 | ||
598 | static void ks8842_tx_timeout(struct net_device *netdev) | 602 | static void ks8842_tx_timeout_work(struct work_struct *work) |
599 | { | 603 | { |
600 | struct ks8842_adapter *adapter = netdev_priv(netdev); | 604 | struct ks8842_adapter *adapter = |
605 | container_of(work, struct ks8842_adapter, timeout_work); | ||
606 | struct net_device *netdev = adapter->netdev; | ||
601 | unsigned long flags; | 607 | unsigned long flags; |
602 | 608 | ||
603 | netdev_dbg(netdev, "%s: entry\n", __func__); | 609 | netdev_dbg(netdev, "%s: entry\n", __func__); |
@@ -606,6 +612,9 @@ static void ks8842_tx_timeout(struct net_device *netdev) | |||
606 | /* disable interrupts */ | 612 | /* disable interrupts */ |
607 | ks8842_write16(adapter, 18, 0, REG_IER); | 613 | ks8842_write16(adapter, 18, 0, REG_IER); |
608 | ks8842_write16(adapter, 18, 0xFFFF, REG_ISR); | 614 | ks8842_write16(adapter, 18, 0xFFFF, REG_ISR); |
615 | |||
616 | netif_stop_queue(netdev); | ||
617 | |||
609 | spin_unlock_irqrestore(&adapter->lock, flags); | 618 | spin_unlock_irqrestore(&adapter->lock, flags); |
610 | 619 | ||
611 | ks8842_reset_hw(adapter); | 620 | ks8842_reset_hw(adapter); |
@@ -615,6 +624,15 @@ static void ks8842_tx_timeout(struct net_device *netdev) | |||
615 | ks8842_update_link_status(netdev, adapter); | 624 | ks8842_update_link_status(netdev, adapter); |
616 | } | 625 | } |
617 | 626 | ||
627 | static void ks8842_tx_timeout(struct net_device *netdev) | ||
628 | { | ||
629 | struct ks8842_adapter *adapter = netdev_priv(netdev); | ||
630 | |||
631 | netdev_dbg(netdev, "%s: entry\n", __func__); | ||
632 | |||
633 | schedule_work(&adapter->timeout_work); | ||
634 | } | ||
635 | |||
618 | static const struct net_device_ops ks8842_netdev_ops = { | 636 | static const struct net_device_ops ks8842_netdev_ops = { |
619 | .ndo_open = ks8842_open, | 637 | .ndo_open = ks8842_open, |
620 | .ndo_stop = ks8842_close, | 638 | .ndo_stop = ks8842_close, |
@@ -649,6 +667,8 @@ static int __devinit ks8842_probe(struct platform_device *pdev) | |||
649 | SET_NETDEV_DEV(netdev, &pdev->dev); | 667 | SET_NETDEV_DEV(netdev, &pdev->dev); |
650 | 668 | ||
651 | adapter = netdev_priv(netdev); | 669 | adapter = netdev_priv(netdev); |
670 | adapter->netdev = netdev; | ||
671 | INIT_WORK(&adapter->timeout_work, ks8842_tx_timeout_work); | ||
652 | adapter->hw_addr = ioremap(iomem->start, resource_size(iomem)); | 672 | adapter->hw_addr = ioremap(iomem->start, resource_size(iomem)); |
653 | if (!adapter->hw_addr) | 673 | if (!adapter->hw_addr) |
654 | goto err_ioremap; | 674 | goto err_ioremap; |