diff options
author | Jon Mason <jon.mason@exar.com> | 2010-12-10 09:02:59 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-12-10 19:08:23 -0500 |
commit | 2e41f6449c561e6e3f572e11d0f2240bd51104db (patch) | |
tree | ef85460cfe71e67cd76cc764c7f48ee88a8005ab /drivers/net/vxge | |
parent | dc66daa9be40369ead5a4ee33c6bcfb44cb3c8ee (diff) |
vxge: transmit timeout deadlock
Use a workqueue to handle the device reset during a transmit timeout, as
there can be a deadlock during bringup. Also, set the netif carrier off
before the watchdog reset is started to prevent the timeout from
reoccurring while still processing the first.
Signed-off-by: Jon Mason <jon.mason@exar.com>
Signed-off-by: Ram Vepa <ram.vepa@exar.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/vxge')
-rw-r--r-- | drivers/net/vxge/vxge-main.c | 19 | ||||
-rw-r--r-- | drivers/net/vxge/vxge-main.h | 1 |
2 files changed, 15 insertions, 5 deletions
diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index faebffb02d12..3ec80684cd5f 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c | |||
@@ -1606,12 +1606,16 @@ static int do_vxge_reset(struct vxgedev *vdev, int event) | |||
1606 | } | 1606 | } |
1607 | 1607 | ||
1608 | if (event == VXGE_LL_FULL_RESET) { | 1608 | if (event == VXGE_LL_FULL_RESET) { |
1609 | netif_carrier_off(vdev->ndev); | ||
1610 | |||
1609 | /* wait for all the vpath reset to complete */ | 1611 | /* wait for all the vpath reset to complete */ |
1610 | for (vp_id = 0; vp_id < vdev->no_of_vpath; vp_id++) { | 1612 | for (vp_id = 0; vp_id < vdev->no_of_vpath; vp_id++) { |
1611 | while (test_bit(vp_id, &vdev->vp_reset)) | 1613 | while (test_bit(vp_id, &vdev->vp_reset)) |
1612 | msleep(50); | 1614 | msleep(50); |
1613 | } | 1615 | } |
1614 | 1616 | ||
1617 | netif_carrier_on(vdev->ndev); | ||
1618 | |||
1615 | /* if execution mode is set to debug, don't reset the adapter */ | 1619 | /* if execution mode is set to debug, don't reset the adapter */ |
1616 | if (unlikely(vdev->exec_mode)) { | 1620 | if (unlikely(vdev->exec_mode)) { |
1617 | vxge_debug_init(VXGE_ERR, | 1621 | vxge_debug_init(VXGE_ERR, |
@@ -1765,9 +1769,14 @@ out: | |||
1765 | * | 1769 | * |
1766 | * driver may reset the chip on events of serr, eccerr, etc | 1770 | * driver may reset the chip on events of serr, eccerr, etc |
1767 | */ | 1771 | */ |
1768 | static int vxge_reset(struct vxgedev *vdev) | 1772 | static void vxge_reset(struct work_struct *work) |
1769 | { | 1773 | { |
1770 | return do_vxge_reset(vdev, VXGE_LL_FULL_RESET); | 1774 | struct vxgedev *vdev = container_of(work, struct vxgedev, reset_task); |
1775 | |||
1776 | if (!netif_running(vdev->ndev)) | ||
1777 | return; | ||
1778 | |||
1779 | do_vxge_reset(vdev, VXGE_LL_FULL_RESET); | ||
1771 | } | 1780 | } |
1772 | 1781 | ||
1773 | /** | 1782 | /** |
@@ -3111,8 +3120,7 @@ static int vxge_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | |||
3111 | * This function is triggered if the Tx Queue is stopped | 3120 | * This function is triggered if the Tx Queue is stopped |
3112 | * for a pre-defined amount of time when the Interface is still up. | 3121 | * for a pre-defined amount of time when the Interface is still up. |
3113 | */ | 3122 | */ |
3114 | static void | 3123 | static void vxge_tx_watchdog(struct net_device *dev) |
3115 | vxge_tx_watchdog(struct net_device *dev) | ||
3116 | { | 3124 | { |
3117 | struct vxgedev *vdev; | 3125 | struct vxgedev *vdev; |
3118 | 3126 | ||
@@ -3122,7 +3130,7 @@ vxge_tx_watchdog(struct net_device *dev) | |||
3122 | 3130 | ||
3123 | vdev->cric_err_event = VXGE_HW_EVENT_RESET_START; | 3131 | vdev->cric_err_event = VXGE_HW_EVENT_RESET_START; |
3124 | 3132 | ||
3125 | vxge_reset(vdev); | 3133 | schedule_work(&vdev->reset_task); |
3126 | vxge_debug_entryexit(VXGE_TRACE, | 3134 | vxge_debug_entryexit(VXGE_TRACE, |
3127 | "%s:%d Exiting...", __func__, __LINE__); | 3135 | "%s:%d Exiting...", __func__, __LINE__); |
3128 | } | 3136 | } |
@@ -3324,6 +3332,7 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev, | |||
3324 | ndev->netdev_ops = &vxge_netdev_ops; | 3332 | ndev->netdev_ops = &vxge_netdev_ops; |
3325 | 3333 | ||
3326 | ndev->watchdog_timeo = VXGE_LL_WATCH_DOG_TIMEOUT; | 3334 | ndev->watchdog_timeo = VXGE_LL_WATCH_DOG_TIMEOUT; |
3335 | INIT_WORK(&vdev->reset_task, vxge_reset); | ||
3327 | 3336 | ||
3328 | vxge_initialize_ethtool_ops(ndev); | 3337 | vxge_initialize_ethtool_ops(ndev); |
3329 | 3338 | ||
diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h index 256d5b406a67..5746fedc356f 100644 --- a/drivers/net/vxge/vxge-main.h +++ b/drivers/net/vxge/vxge-main.h | |||
@@ -395,6 +395,7 @@ struct vxgedev { | |||
395 | u32 level_err; | 395 | u32 level_err; |
396 | u32 level_trace; | 396 | u32 level_trace; |
397 | char fw_version[VXGE_HW_FW_STRLEN]; | 397 | char fw_version[VXGE_HW_FW_STRLEN]; |
398 | struct work_struct reset_task; | ||
398 | }; | 399 | }; |
399 | 400 | ||
400 | struct vxge_rx_priv { | 401 | struct vxge_rx_priv { |