diff options
Diffstat (limited to 'drivers/net/ethernet/mellanox')
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/catas.c | 25 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/cmd.c | 49 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/main.c | 30 |
3 files changed, 93 insertions, 11 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/catas.c b/drivers/net/ethernet/mellanox/mlx4/catas.c index 915e947b422d..9c656fe4983d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/catas.c +++ b/drivers/net/ethernet/mellanox/mlx4/catas.c | |||
@@ -69,16 +69,21 @@ static void poll_catas(unsigned long dev_ptr) | |||
69 | struct mlx4_priv *priv = mlx4_priv(dev); | 69 | struct mlx4_priv *priv = mlx4_priv(dev); |
70 | 70 | ||
71 | if (readl(priv->catas_err.map)) { | 71 | if (readl(priv->catas_err.map)) { |
72 | dump_err_buf(dev); | 72 | /* If the device is off-line, we cannot try to recover it */ |
73 | 73 | if (pci_channel_offline(dev->pdev)) | |
74 | mlx4_dispatch_event(dev, MLX4_DEV_EVENT_CATASTROPHIC_ERROR, 0); | 74 | mod_timer(&priv->catas_err.timer, |
75 | round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL)); | ||
76 | else { | ||
77 | dump_err_buf(dev); | ||
78 | mlx4_dispatch_event(dev, MLX4_DEV_EVENT_CATASTROPHIC_ERROR, 0); | ||
75 | 79 | ||
76 | if (internal_err_reset) { | 80 | if (internal_err_reset) { |
77 | spin_lock(&catas_lock); | 81 | spin_lock(&catas_lock); |
78 | list_add(&priv->catas_err.list, &catas_list); | 82 | list_add(&priv->catas_err.list, &catas_list); |
79 | spin_unlock(&catas_lock); | 83 | spin_unlock(&catas_lock); |
80 | 84 | ||
81 | queue_work(mlx4_wq, &catas_work); | 85 | queue_work(mlx4_wq, &catas_work); |
86 | } | ||
82 | } | 87 | } |
83 | } else | 88 | } else |
84 | mod_timer(&priv->catas_err.timer, | 89 | mod_timer(&priv->catas_err.timer, |
@@ -100,6 +105,10 @@ static void catas_reset(struct work_struct *work) | |||
100 | list_for_each_entry_safe(priv, tmppriv, &tlist, catas_err.list) { | 105 | list_for_each_entry_safe(priv, tmppriv, &tlist, catas_err.list) { |
101 | struct pci_dev *pdev = priv->dev.pdev; | 106 | struct pci_dev *pdev = priv->dev.pdev; |
102 | 107 | ||
108 | /* If the device is off-line, we cannot reset it */ | ||
109 | if (pci_channel_offline(pdev)) | ||
110 | continue; | ||
111 | |||
103 | ret = mlx4_restart_one(priv->dev.pdev); | 112 | ret = mlx4_restart_one(priv->dev.pdev); |
104 | /* 'priv' now is not valid */ | 113 | /* 'priv' now is not valid */ |
105 | if (ret) | 114 | if (ret) |
diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 7e94987d030c..c8fef4353021 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c | |||
@@ -296,7 +296,12 @@ int mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param, | |||
296 | 296 | ||
297 | static int cmd_pending(struct mlx4_dev *dev) | 297 | static int cmd_pending(struct mlx4_dev *dev) |
298 | { | 298 | { |
299 | u32 status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET); | 299 | u32 status; |
300 | |||
301 | if (pci_channel_offline(dev->pdev)) | ||
302 | return -EIO; | ||
303 | |||
304 | status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET); | ||
300 | 305 | ||
301 | return (status & swab32(1 << HCR_GO_BIT)) || | 306 | return (status & swab32(1 << HCR_GO_BIT)) || |
302 | (mlx4_priv(dev)->cmd.toggle == | 307 | (mlx4_priv(dev)->cmd.toggle == |
@@ -314,11 +319,29 @@ static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param, | |||
314 | 319 | ||
315 | mutex_lock(&cmd->hcr_mutex); | 320 | mutex_lock(&cmd->hcr_mutex); |
316 | 321 | ||
322 | if (pci_channel_offline(dev->pdev)) { | ||
323 | /* | ||
324 | * Device is going through error recovery | ||
325 | * and cannot accept commands. | ||
326 | */ | ||
327 | ret = -EIO; | ||
328 | goto out; | ||
329 | } | ||
330 | |||
317 | end = jiffies; | 331 | end = jiffies; |
318 | if (event) | 332 | if (event) |
319 | end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS); | 333 | end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS); |
320 | 334 | ||
321 | while (cmd_pending(dev)) { | 335 | while (cmd_pending(dev)) { |
336 | if (pci_channel_offline(dev->pdev)) { | ||
337 | /* | ||
338 | * Device is going through error recovery | ||
339 | * and cannot accept commands. | ||
340 | */ | ||
341 | ret = -EIO; | ||
342 | goto out; | ||
343 | } | ||
344 | |||
322 | if (time_after_eq(jiffies, end)) { | 345 | if (time_after_eq(jiffies, end)) { |
323 | mlx4_err(dev, "%s:cmd_pending failed\n", __func__); | 346 | mlx4_err(dev, "%s:cmd_pending failed\n", __func__); |
324 | goto out; | 347 | goto out; |
@@ -431,14 +454,33 @@ static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, | |||
431 | 454 | ||
432 | down(&priv->cmd.poll_sem); | 455 | down(&priv->cmd.poll_sem); |
433 | 456 | ||
457 | if (pci_channel_offline(dev->pdev)) { | ||
458 | /* | ||
459 | * Device is going through error recovery | ||
460 | * and cannot accept commands. | ||
461 | */ | ||
462 | err = -EIO; | ||
463 | goto out; | ||
464 | } | ||
465 | |||
434 | err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, | 466 | err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, |
435 | in_modifier, op_modifier, op, CMD_POLL_TOKEN, 0); | 467 | in_modifier, op_modifier, op, CMD_POLL_TOKEN, 0); |
436 | if (err) | 468 | if (err) |
437 | goto out; | 469 | goto out; |
438 | 470 | ||
439 | end = msecs_to_jiffies(timeout) + jiffies; | 471 | end = msecs_to_jiffies(timeout) + jiffies; |
440 | while (cmd_pending(dev) && time_before(jiffies, end)) | 472 | while (cmd_pending(dev) && time_before(jiffies, end)) { |
473 | if (pci_channel_offline(dev->pdev)) { | ||
474 | /* | ||
475 | * Device is going through error recovery | ||
476 | * and cannot accept commands. | ||
477 | */ | ||
478 | err = -EIO; | ||
479 | goto out; | ||
480 | } | ||
481 | |||
441 | cond_resched(); | 482 | cond_resched(); |
483 | } | ||
442 | 484 | ||
443 | if (cmd_pending(dev)) { | 485 | if (cmd_pending(dev)) { |
444 | err = -ETIMEDOUT; | 486 | err = -ETIMEDOUT; |
@@ -532,6 +574,9 @@ int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, | |||
532 | int out_is_imm, u32 in_modifier, u8 op_modifier, | 574 | int out_is_imm, u32 in_modifier, u8 op_modifier, |
533 | u16 op, unsigned long timeout, int native) | 575 | u16 op, unsigned long timeout, int native) |
534 | { | 576 | { |
577 | if (pci_channel_offline(dev->pdev)) | ||
578 | return -EIO; | ||
579 | |||
535 | if (!mlx4_is_mfunc(dev) || (native && mlx4_is_master(dev))) { | 580 | if (!mlx4_is_mfunc(dev) || (native && mlx4_is_master(dev))) { |
536 | if (mlx4_priv(dev)->cmd.use_events) | 581 | if (mlx4_priv(dev)->cmd.use_events) |
537 | return mlx4_cmd_wait(dev, in_param, out_param, | 582 | return mlx4_cmd_wait(dev, in_param, out_param, |
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 42645166bae2..e717091734d0 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c | |||
@@ -1775,6 +1775,9 @@ static int mlx4_get_ownership(struct mlx4_dev *dev) | |||
1775 | void __iomem *owner; | 1775 | void __iomem *owner; |
1776 | u32 ret; | 1776 | u32 ret; |
1777 | 1777 | ||
1778 | if (pci_channel_offline(dev->pdev)) | ||
1779 | return -EIO; | ||
1780 | |||
1778 | owner = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_OWNER_BASE, | 1781 | owner = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_OWNER_BASE, |
1779 | MLX4_OWNER_SIZE); | 1782 | MLX4_OWNER_SIZE); |
1780 | if (!owner) { | 1783 | if (!owner) { |
@@ -1791,6 +1794,9 @@ static void mlx4_free_ownership(struct mlx4_dev *dev) | |||
1791 | { | 1794 | { |
1792 | void __iomem *owner; | 1795 | void __iomem *owner; |
1793 | 1796 | ||
1797 | if (pci_channel_offline(dev->pdev)) | ||
1798 | return; | ||
1799 | |||
1794 | owner = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_OWNER_BASE, | 1800 | owner = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_OWNER_BASE, |
1795 | MLX4_OWNER_SIZE); | 1801 | MLX4_OWNER_SIZE); |
1796 | if (!owner) { | 1802 | if (!owner) { |
@@ -2237,11 +2243,33 @@ static DEFINE_PCI_DEVICE_TABLE(mlx4_pci_table) = { | |||
2237 | 2243 | ||
2238 | MODULE_DEVICE_TABLE(pci, mlx4_pci_table); | 2244 | MODULE_DEVICE_TABLE(pci, mlx4_pci_table); |
2239 | 2245 | ||
2246 | static pci_ers_result_t mlx4_pci_err_detected(struct pci_dev *pdev, | ||
2247 | pci_channel_state_t state) | ||
2248 | { | ||
2249 | mlx4_remove_one(pdev); | ||
2250 | |||
2251 | return state == pci_channel_io_perm_failure ? | ||
2252 | PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET; | ||
2253 | } | ||
2254 | |||
2255 | static pci_ers_result_t mlx4_pci_slot_reset(struct pci_dev *pdev) | ||
2256 | { | ||
2257 | int ret = __mlx4_init_one(pdev, NULL); | ||
2258 | |||
2259 | return ret ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED; | ||
2260 | } | ||
2261 | |||
2262 | static struct pci_error_handlers mlx4_err_handler = { | ||
2263 | .error_detected = mlx4_pci_err_detected, | ||
2264 | .slot_reset = mlx4_pci_slot_reset, | ||
2265 | }; | ||
2266 | |||
2240 | static struct pci_driver mlx4_driver = { | 2267 | static struct pci_driver mlx4_driver = { |
2241 | .name = DRV_NAME, | 2268 | .name = DRV_NAME, |
2242 | .id_table = mlx4_pci_table, | 2269 | .id_table = mlx4_pci_table, |
2243 | .probe = mlx4_init_one, | 2270 | .probe = mlx4_init_one, |
2244 | .remove = __devexit_p(mlx4_remove_one) | 2271 | .remove = __devexit_p(mlx4_remove_one), |
2272 | .err_handler = &mlx4_err_handler, | ||
2245 | }; | 2273 | }; |
2246 | 2274 | ||
2247 | static int __init mlx4_verify_params(void) | 2275 | static int __init mlx4_verify_params(void) |