aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorxiong <xiong@qca.qualcomm.com>2013-02-27 13:10:11 +0800
committerAdrian Chadd <adrian@freebsd.org>2013-03-01 15:25:17 -0800
commit35d67ef499ff231a81a8bfdc68d49f70b42dc8aa (patch)
treeaf70b3686befbc677d419a4b7a9bcdea4fdb34b6
parent43a76d94377e30e9bfc60bb697a28d0235744ccb (diff)
downloadalx-35d67ef499ff231a81a8bfdc68d49f70b42dc8aa.tar.gz
alx: fix dead loop for hardware fatal error
when reset in alx_task/alx_reinit, alx_halt function calls cancel_work_sync(task), which makes a dead loop. This patch fixes it by adding parameter of in_task for alx_halt & alx_reinit. Signed-off-by: xiong <xiong@qca.qualcomm.com>
-rw-r--r--src/alx.h2
-rw-r--r--src/alx_ethtool.c2
-rw-r--r--src/alx_main.c19
3 files changed, 12 insertions, 11 deletions
diff --git a/src/alx.h b/src/alx.h
index 78bbe5d..bbf147f 100644
--- a/src/alx.h
+++ b/src/alx.h
@@ -205,7 +205,7 @@ extern int alx_alloc_rxring_buf(struct alx_adapter *adpt,
struct alx_rx_queue *rxq);
extern void alx_init_intr(struct alx_adapter *adpt);
extern void alx_disable_advanced_intr(struct alx_adapter *adpt);
-extern void alx_reinit(struct alx_adapter *adpt);
+extern void alx_reinit(struct alx_adapter *adpt, bool in_task);
extern void alx_set_ethtool_ops(struct net_device *dev);
extern char alx_drv_name[];
extern char alx_drv_version[];
diff --git a/src/alx_ethtool.c b/src/alx_ethtool.c
index 998fe87..074c640 100644
--- a/src/alx_ethtool.c
+++ b/src/alx_ethtool.c
@@ -328,7 +328,7 @@ static int alx_nway_reset(struct net_device *netdev)
struct alx_adapter *adpt = netdev_priv(netdev);
if (netif_running(netdev))
- alx_reinit(adpt);
+ alx_reinit(adpt, false);
return 0;
}
diff --git a/src/alx_main.c b/src/alx_main.c
index 7686aec..02abef4 100644
--- a/src/alx_main.c
+++ b/src/alx_main.c
@@ -35,7 +35,7 @@
#define DRV_MAJ 1
#define DRV_MIN 2
-#define DRV_PATCH 2
+#define DRV_PATCH 3
#define DRV_MODULE_VER \
__stringify(DRV_MAJ) "." __stringify(DRV_MIN) "." \
__stringify(DRV_PATCH)
@@ -1197,7 +1197,7 @@ static int alx_change_mtu(struct net_device *netdev, int new_mtu)
ALIGN(max_frame, 8) : ALX_DEF_RXBUF_SIZE;
netdev_update_features(netdev);
if (netif_running(netdev))
- alx_reinit(adpt);
+ alx_reinit(adpt, false);
}
return 0;
@@ -1360,12 +1360,13 @@ err_out:
return err;
}
-static void alx_halt(struct alx_adapter *adpt)
+static void alx_halt(struct alx_adapter *adpt, bool in_task)
{
struct alx_hw *hw = &adpt->hw;
ALX_FLAG_SET(adpt, HALT);
- alx_cancel_work(adpt);
+ if (!in_task)
+ alx_cancel_work(adpt);
alx_netif_stop(adpt);
hw->link_up = false;
@@ -1397,7 +1398,7 @@ static void alx_activate(struct alx_adapter *adpt)
static void __alx_stop(struct alx_adapter *adpt)
{
- alx_halt(adpt);
+ alx_halt(adpt, false);
alx_free_irq(adpt);
@@ -1802,7 +1803,7 @@ static void alx_update_stats(struct alx_adapter *adpt)
spin_unlock(&adpt->smb_lock);
}
-void alx_reinit(struct alx_adapter *adpt)
+void alx_reinit(struct alx_adapter *adpt, bool in_task)
{
WARN_ON(in_interrupt());
@@ -1812,7 +1813,7 @@ void alx_reinit(struct alx_adapter *adpt)
if (ALX_FLAG(adpt, HALT))
return;
- alx_halt(adpt);
+ alx_halt(adpt, in_task);
alx_activate(adpt);
ALX_FLAG_CLEAR(adpt, RESETING);
@@ -1833,7 +1834,7 @@ static void alx_task(struct work_struct *work)
if (test_and_clear_bit(ALX_FLAG_TASK_RESET, &adpt->flags)) {
netif_info(adpt, hw, adpt->netdev,
"task:alx_reinit\n");
- alx_reinit(adpt);
+ alx_reinit(adpt, true);
}
if (test_and_clear_bit(ALX_FLAG_TASK_UPDATE_SMB, &adpt->flags))
@@ -2720,7 +2721,7 @@ static pci_ers_result_t alx_pci_error_detected(struct pci_dev *pdev,
if (netif_running(netdev)) {
netif_device_detach(netdev);
- alx_halt(adpt);
+ alx_halt(adpt, false);
}
if (state == pci_channel_io_perm_failure)
rc = PCI_ERS_RESULT_DISCONNECT;