diff options
author | xiong <xiong@qca.qualcomm.com> | 2013-02-27 13:10:11 +0800 |
---|---|---|
committer | Adrian Chadd <adrian@freebsd.org> | 2013-03-01 15:25:17 -0800 |
commit | 35d67ef499ff231a81a8bfdc68d49f70b42dc8aa (patch) | |
tree | af70b3686befbc677d419a4b7a9bcdea4fdb34b6 | |
parent | 43a76d94377e30e9bfc60bb697a28d0235744ccb (diff) | |
download | alx-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.h | 2 | ||||
-rw-r--r-- | src/alx_ethtool.c | 2 | ||||
-rw-r--r-- | src/alx_main.c | 19 |
3 files changed, 12 insertions, 11 deletions
@@ -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; |