qlge: Add watchdog timer.
Add periodic heartbeat register read to trigger the eeh
recovery process.
We see cases where an eeh error was injected and the slot was
suspended. An asic access attempt is required to flush the recovery process,
but without interrupts the process can stall.
Adding this periodic register read causes the recovery process to begin.
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index 780a387..ebfd177 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -2145,6 +2145,7 @@
struct completion ide_completion;
struct nic_operations *nic_ops;
u16 device_id;
+ struct timer_list timer;
atomic_t lb_count;
};
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 7e00029..87a40d1 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -4574,6 +4574,21 @@
.ndo_vlan_rx_kill_vid = qlge_vlan_rx_kill_vid,
};
+static void ql_timer(unsigned long data)
+{
+ struct ql_adapter *qdev = (struct ql_adapter *)data;
+ u32 var = 0;
+
+ var = ql_read32(qdev, STS);
+ if (pci_channel_offline(qdev->pdev)) {
+ QPRINTK(qdev, IFUP, ERR, "EEH STS = 0x%.08x.\n", var);
+ return;
+ }
+
+ qdev->timer.expires = jiffies + (5*HZ);
+ add_timer(&qdev->timer);
+}
+
static int __devinit qlge_probe(struct pci_dev *pdev,
const struct pci_device_id *pci_entry)
{
@@ -4625,6 +4640,14 @@
pci_disable_device(pdev);
return err;
}
+ /* Start up the timer to trigger EEH if
+ * the bus goes dead
+ */
+ init_timer_deferrable(&qdev->timer);
+ qdev->timer.data = (unsigned long)qdev;
+ qdev->timer.function = ql_timer;
+ qdev->timer.expires = jiffies + (5*HZ);
+ add_timer(&qdev->timer);
ql_link_off(qdev);
ql_display_dev_info(ndev);
atomic_set(&qdev->lb_count, 0);
@@ -4645,6 +4668,8 @@
static void __devexit qlge_remove(struct pci_dev *pdev)
{
struct net_device *ndev = pci_get_drvdata(pdev);
+ struct ql_adapter *qdev = netdev_priv(ndev);
+ del_timer_sync(&qdev->timer);
unregister_netdev(ndev);
ql_release_all(pdev);
pci_disable_device(pdev);
@@ -4757,6 +4782,8 @@
QPRINTK(qdev, IFUP, ERR,
"Device was not running prior to EEH.\n");
}
+ qdev->timer.expires = jiffies + (5*HZ);
+ add_timer(&qdev->timer);
netif_device_attach(ndev);
}
@@ -4773,6 +4800,7 @@
int err;
netif_device_detach(ndev);
+ del_timer_sync(&qdev->timer);
if (netif_running(ndev)) {
err = ql_adapter_down(qdev);
@@ -4817,6 +4845,8 @@
return err;
}
+ qdev->timer.expires = jiffies + (5*HZ);
+ add_timer(&qdev->timer);
netif_device_attach(ndev);
return 0;