summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ks8842.c24
1 files changed, 22 insertions, 2 deletions
diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c
index d47bba9202e..5191af2c1fa 100644
--- a/drivers/net/ks8842.c
+++ b/drivers/net/ks8842.c
@@ -119,6 +119,8 @@ struct ks8842_adapter {
int irq;
struct tasklet_struct tasklet;
spinlock_t lock; /* spinlock to be interrupt safe */
+ struct work_struct timeout_work;
+ struct net_device *netdev;
};
static inline void ks8842_select_bank(struct ks8842_adapter *adapter, u16 bank)
@@ -553,6 +555,8 @@ static int ks8842_close(struct net_device *netdev)
netdev_dbg(netdev, "%s - entry\n", __func__);
+ cancel_work_sync(&adapter->timeout_work);
+
/* free the irq */
free_irq(adapter->irq, netdev);
@@ -595,9 +599,11 @@ static int ks8842_set_mac(struct net_device *netdev, void *p)
return 0;
}
-static void ks8842_tx_timeout(struct net_device *netdev)
+static void ks8842_tx_timeout_work(struct work_struct *work)
{
- struct ks8842_adapter *adapter = netdev_priv(netdev);
+ struct ks8842_adapter *adapter =
+ container_of(work, struct ks8842_adapter, timeout_work);
+ struct net_device *netdev = adapter->netdev;
unsigned long flags;
netdev_dbg(netdev, "%s: entry\n", __func__);
@@ -606,6 +612,9 @@ static void ks8842_tx_timeout(struct net_device *netdev)
/* disable interrupts */
ks8842_write16(adapter, 18, 0, REG_IER);
ks8842_write16(adapter, 18, 0xFFFF, REG_ISR);
+
+ netif_stop_queue(netdev);
+
spin_unlock_irqrestore(&adapter->lock, flags);
ks8842_reset_hw(adapter);
@@ -615,6 +624,15 @@ static void ks8842_tx_timeout(struct net_device *netdev)
ks8842_update_link_status(netdev, adapter);
}
+static void ks8842_tx_timeout(struct net_device *netdev)
+{
+ struct ks8842_adapter *adapter = netdev_priv(netdev);
+
+ netdev_dbg(netdev, "%s: entry\n", __func__);
+
+ schedule_work(&adapter->timeout_work);
+}
+
static const struct net_device_ops ks8842_netdev_ops = {
.ndo_open = ks8842_open,
.ndo_stop = ks8842_close,
@@ -649,6 +667,8 @@ static int __devinit ks8842_probe(struct platform_device *pdev)
SET_NETDEV_DEV(netdev, &pdev->dev);
adapter = netdev_priv(netdev);
+ adapter->netdev = netdev;
+ INIT_WORK(&adapter->timeout_work, ks8842_tx_timeout_work);
adapter->hw_addr = ioremap(iomem->start, resource_size(iomem));
if (!adapter->hw_addr)
goto err_ioremap;