diff options
author | Jack Morgenstein <jackm@dev.mellanox.co.il> | 2012-11-27 11:24:30 -0500 |
---|---|---|
committer | Roland Dreier <roland@purestorage.com> | 2012-11-29 15:14:54 -0500 |
commit | 311f813a2daefcba03f706a692fe0c67888d7622 (patch) | |
tree | ab2b5e480aa0a8cd35d7e63a1346f89b10009c0b | |
parent | ceb7decb366591e9b67d70832e07f5d240572a3d (diff) |
mlx4_core: Fix potential deadlock in mlx4_eq_int()
The slave_state_lock spinlock is used in both interrupt context and
process context, hence irq locking must be used. Found by lockdep.
Signed-off-by: Jack Morgenstein <jackm@dev.mellanox.co.il>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Roland Dreier <roland@purestorage.com>
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/cmd.c | 9 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/eq.c | 10 |
2 files changed, 11 insertions, 8 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index e791e705f7b1..fdc5f23d8e9f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c | |||
@@ -1498,6 +1498,7 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, | |||
1498 | u32 reply; | 1498 | u32 reply; |
1499 | u8 is_going_down = 0; | 1499 | u8 is_going_down = 0; |
1500 | int i; | 1500 | int i; |
1501 | unsigned long flags; | ||
1501 | 1502 | ||
1502 | slave_state[slave].comm_toggle ^= 1; | 1503 | slave_state[slave].comm_toggle ^= 1; |
1503 | reply = (u32) slave_state[slave].comm_toggle << 31; | 1504 | reply = (u32) slave_state[slave].comm_toggle << 31; |
@@ -1576,12 +1577,12 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, | |||
1576 | mlx4_warn(dev, "Bad comm cmd:%d from slave:%d\n", cmd, slave); | 1577 | mlx4_warn(dev, "Bad comm cmd:%d from slave:%d\n", cmd, slave); |
1577 | goto reset_slave; | 1578 | goto reset_slave; |
1578 | } | 1579 | } |
1579 | spin_lock(&priv->mfunc.master.slave_state_lock); | 1580 | spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); |
1580 | if (!slave_state[slave].is_slave_going_down) | 1581 | if (!slave_state[slave].is_slave_going_down) |
1581 | slave_state[slave].last_cmd = cmd; | 1582 | slave_state[slave].last_cmd = cmd; |
1582 | else | 1583 | else |
1583 | is_going_down = 1; | 1584 | is_going_down = 1; |
1584 | spin_unlock(&priv->mfunc.master.slave_state_lock); | 1585 | spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags); |
1585 | if (is_going_down) { | 1586 | if (is_going_down) { |
1586 | mlx4_warn(dev, "Slave is going down aborting command(%d)" | 1587 | mlx4_warn(dev, "Slave is going down aborting command(%d)" |
1587 | " executing from slave:%d\n", | 1588 | " executing from slave:%d\n", |
@@ -1597,10 +1598,10 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, | |||
1597 | reset_slave: | 1598 | reset_slave: |
1598 | /* cleanup any slave resources */ | 1599 | /* cleanup any slave resources */ |
1599 | mlx4_delete_all_resources_for_slave(dev, slave); | 1600 | mlx4_delete_all_resources_for_slave(dev, slave); |
1600 | spin_lock(&priv->mfunc.master.slave_state_lock); | 1601 | spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); |
1601 | if (!slave_state[slave].is_slave_going_down) | 1602 | if (!slave_state[slave].is_slave_going_down) |
1602 | slave_state[slave].last_cmd = MLX4_COMM_CMD_RESET; | 1603 | slave_state[slave].last_cmd = MLX4_COMM_CMD_RESET; |
1603 | spin_unlock(&priv->mfunc.master.slave_state_lock); | 1604 | spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags); |
1604 | /*with slave in the middle of flr, no need to clean resources again.*/ | 1605 | /*with slave in the middle of flr, no need to clean resources again.*/ |
1605 | inform_slave_state: | 1606 | inform_slave_state: |
1606 | memset(&slave_state[slave].event_eq, 0, | 1607 | memset(&slave_state[slave].event_eq, 0, |
diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index c509a86db610..3cb7727408e5 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c | |||
@@ -407,6 +407,7 @@ void mlx4_master_handle_slave_flr(struct work_struct *work) | |||
407 | struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; | 407 | struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; |
408 | int i; | 408 | int i; |
409 | int err; | 409 | int err; |
410 | unsigned long flags; | ||
410 | 411 | ||
411 | mlx4_dbg(dev, "mlx4_handle_slave_flr\n"); | 412 | mlx4_dbg(dev, "mlx4_handle_slave_flr\n"); |
412 | 413 | ||
@@ -418,10 +419,10 @@ void mlx4_master_handle_slave_flr(struct work_struct *work) | |||
418 | 419 | ||
419 | mlx4_delete_all_resources_for_slave(dev, i); | 420 | mlx4_delete_all_resources_for_slave(dev, i); |
420 | /*return the slave to running mode*/ | 421 | /*return the slave to running mode*/ |
421 | spin_lock(&priv->mfunc.master.slave_state_lock); | 422 | spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); |
422 | slave_state[i].last_cmd = MLX4_COMM_CMD_RESET; | 423 | slave_state[i].last_cmd = MLX4_COMM_CMD_RESET; |
423 | slave_state[i].is_slave_going_down = 0; | 424 | slave_state[i].is_slave_going_down = 0; |
424 | spin_unlock(&priv->mfunc.master.slave_state_lock); | 425 | spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags); |
425 | /*notify the FW:*/ | 426 | /*notify the FW:*/ |
426 | err = mlx4_cmd(dev, 0, i, 0, MLX4_CMD_INFORM_FLR_DONE, | 427 | err = mlx4_cmd(dev, 0, i, 0, MLX4_CMD_INFORM_FLR_DONE, |
427 | MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); | 428 | MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); |
@@ -446,6 +447,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) | |||
446 | u8 update_slave_state; | 447 | u8 update_slave_state; |
447 | int i; | 448 | int i; |
448 | enum slave_port_gen_event gen_event; | 449 | enum slave_port_gen_event gen_event; |
450 | unsigned long flags; | ||
449 | 451 | ||
450 | while ((eqe = next_eqe_sw(eq, dev->caps.eqe_factor))) { | 452 | while ((eqe = next_eqe_sw(eq, dev->caps.eqe_factor))) { |
451 | /* | 453 | /* |
@@ -653,13 +655,13 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) | |||
653 | } else | 655 | } else |
654 | update_slave_state = 1; | 656 | update_slave_state = 1; |
655 | 657 | ||
656 | spin_lock(&priv->mfunc.master.slave_state_lock); | 658 | spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); |
657 | if (update_slave_state) { | 659 | if (update_slave_state) { |
658 | priv->mfunc.master.slave_state[flr_slave].active = false; | 660 | priv->mfunc.master.slave_state[flr_slave].active = false; |
659 | priv->mfunc.master.slave_state[flr_slave].last_cmd = MLX4_COMM_CMD_FLR; | 661 | priv->mfunc.master.slave_state[flr_slave].last_cmd = MLX4_COMM_CMD_FLR; |
660 | priv->mfunc.master.slave_state[flr_slave].is_slave_going_down = 1; | 662 | priv->mfunc.master.slave_state[flr_slave].is_slave_going_down = 1; |
661 | } | 663 | } |
662 | spin_unlock(&priv->mfunc.master.slave_state_lock); | 664 | spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags); |
663 | queue_work(priv->mfunc.master.comm_wq, | 665 | queue_work(priv->mfunc.master.comm_wq, |
664 | &priv->mfunc.master.slave_flr_event_work); | 666 | &priv->mfunc.master.slave_flr_event_work); |
665 | break; | 667 | break; |