|
@@ -119,6 +119,8 @@ struct ks8842_adapter {
|
|
int irq;
|
|
int irq;
|
|
struct tasklet_struct tasklet;
|
|
struct tasklet_struct tasklet;
|
|
spinlock_t lock; /* spinlock to be interrupt safe */
|
|
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)
|
|
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__);
|
|
netdev_dbg(netdev, "%s - entry\n", __func__);
|
|
|
|
|
|
|
|
+ cancel_work_sync(&adapter->timeout_work);
|
|
|
|
+
|
|
/* free the irq */
|
|
/* free the irq */
|
|
free_irq(adapter->irq, netdev);
|
|
free_irq(adapter->irq, netdev);
|
|
|
|
|
|
@@ -595,9 +599,11 @@ static int ks8842_set_mac(struct net_device *netdev, void *p)
|
|
return 0;
|
|
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;
|
|
unsigned long flags;
|
|
|
|
|
|
netdev_dbg(netdev, "%s: entry\n", __func__);
|
|
netdev_dbg(netdev, "%s: entry\n", __func__);
|
|
@@ -606,6 +612,9 @@ static void ks8842_tx_timeout(struct net_device *netdev)
|
|
/* disable interrupts */
|
|
/* disable interrupts */
|
|
ks8842_write16(adapter, 18, 0, REG_IER);
|
|
ks8842_write16(adapter, 18, 0, REG_IER);
|
|
ks8842_write16(adapter, 18, 0xFFFF, REG_ISR);
|
|
ks8842_write16(adapter, 18, 0xFFFF, REG_ISR);
|
|
|
|
+
|
|
|
|
+ netif_stop_queue(netdev);
|
|
|
|
+
|
|
spin_unlock_irqrestore(&adapter->lock, flags);
|
|
spin_unlock_irqrestore(&adapter->lock, flags);
|
|
|
|
|
|
ks8842_reset_hw(adapter);
|
|
ks8842_reset_hw(adapter);
|
|
@@ -615,6 +624,15 @@ static void ks8842_tx_timeout(struct net_device *netdev)
|
|
ks8842_update_link_status(netdev, adapter);
|
|
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 = {
|
|
static const struct net_device_ops ks8842_netdev_ops = {
|
|
.ndo_open = ks8842_open,
|
|
.ndo_open = ks8842_open,
|
|
.ndo_stop = ks8842_close,
|
|
.ndo_stop = ks8842_close,
|
|
@@ -649,6 +667,8 @@ static int __devinit ks8842_probe(struct platform_device *pdev)
|
|
SET_NETDEV_DEV(netdev, &pdev->dev);
|
|
SET_NETDEV_DEV(netdev, &pdev->dev);
|
|
|
|
|
|
adapter = netdev_priv(netdev);
|
|
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));
|
|
adapter->hw_addr = ioremap(iomem->start, resource_size(iomem));
|
|
if (!adapter->hw_addr)
|
|
if (!adapter->hw_addr)
|
|
goto err_ioremap;
|
|
goto err_ioremap;
|