Commit fcd29ad1 authored by Feras Daoud's avatar Feras Daoud Committed by Saeed Mahameed

net/mlx5: Add Fast teardown support

Today mlx5 devices support two teardown modes:
1- Regular teardown
2- Force teardown

This change introduces the enhanced version of the "Force teardown" that
allows SW to perform teardown in a faster way without the need to reclaim
all the pages.

Fast teardown provides the following advantages:
1- Fix a FW race condition that could cause command timeout
2- Avoid moving to polling mode
3- Close the vport to prevent PCI ACK to be sent without been scatter
to memory
Signed-off-by: default avatarFeras Daoud <ferasda@mellanox.com>
Reviewed-by: default avatarMajd Dibbiny <majd@mellanox.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@mellanox.com>
parent 94563847
...@@ -250,7 +250,7 @@ int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev) ...@@ -250,7 +250,7 @@ int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev)
if (ret) if (ret)
return ret; return ret;
force_state = MLX5_GET(teardown_hca_out, out, force_state); force_state = MLX5_GET(teardown_hca_out, out, state);
if (force_state == MLX5_TEARDOWN_HCA_OUT_FORCE_STATE_FAIL) { if (force_state == MLX5_TEARDOWN_HCA_OUT_FORCE_STATE_FAIL) {
mlx5_core_warn(dev, "teardown with force mode failed, doing normal teardown\n"); mlx5_core_warn(dev, "teardown with force mode failed, doing normal teardown\n");
return -EIO; return -EIO;
...@@ -259,6 +259,54 @@ int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev) ...@@ -259,6 +259,54 @@ int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev)
return 0; return 0;
} }
#define MLX5_FAST_TEARDOWN_WAIT_MS 3000
int mlx5_cmd_fast_teardown_hca(struct mlx5_core_dev *dev)
{
unsigned long end, delay_ms = MLX5_FAST_TEARDOWN_WAIT_MS;
u32 out[MLX5_ST_SZ_DW(teardown_hca_out)] = {0};
u32 in[MLX5_ST_SZ_DW(teardown_hca_in)] = {0};
int state;
int ret;
if (!MLX5_CAP_GEN(dev, fast_teardown)) {
mlx5_core_dbg(dev, "fast teardown is not supported in the firmware\n");
return -EOPNOTSUPP;
}
MLX5_SET(teardown_hca_in, in, opcode, MLX5_CMD_OP_TEARDOWN_HCA);
MLX5_SET(teardown_hca_in, in, profile,
MLX5_TEARDOWN_HCA_IN_PROFILE_PREPARE_FAST_TEARDOWN);
ret = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
if (ret)
return ret;
state = MLX5_GET(teardown_hca_out, out, state);
if (state == MLX5_TEARDOWN_HCA_OUT_FORCE_STATE_FAIL) {
mlx5_core_warn(dev, "teardown with fast mode failed\n");
return -EIO;
}
mlx5_set_nic_state(dev, MLX5_NIC_IFC_DISABLED);
/* Loop until device state turns to disable */
end = jiffies + msecs_to_jiffies(delay_ms);
do {
if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_DISABLED)
break;
cond_resched();
} while (!time_after(jiffies, end));
if (mlx5_get_nic_state(dev) != MLX5_NIC_IFC_DISABLED) {
dev_err(&dev->pdev->dev, "NIC IFC still %d after %lums.\n",
mlx5_get_nic_state(dev), delay_ms);
return -EIO;
}
return 0;
}
enum mlxsw_reg_mcc_instruction { enum mlxsw_reg_mcc_instruction {
MLX5_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE = 0x01, MLX5_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE = 0x01,
MLX5_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE = 0x02, MLX5_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE = 0x02,
......
...@@ -58,23 +58,26 @@ enum { ...@@ -58,23 +58,26 @@ enum {
MLX5_HEALTH_SYNDR_HIGH_TEMP = 0x10 MLX5_HEALTH_SYNDR_HIGH_TEMP = 0x10
}; };
enum {
MLX5_NIC_IFC_FULL = 0,
MLX5_NIC_IFC_DISABLED = 1,
MLX5_NIC_IFC_NO_DRAM_NIC = 2,
MLX5_NIC_IFC_INVALID = 3
};
enum { enum {
MLX5_DROP_NEW_HEALTH_WORK, MLX5_DROP_NEW_HEALTH_WORK,
MLX5_DROP_NEW_RECOVERY_WORK, MLX5_DROP_NEW_RECOVERY_WORK,
}; };
static u8 get_nic_state(struct mlx5_core_dev *dev) u8 mlx5_get_nic_state(struct mlx5_core_dev *dev)
{ {
return (ioread32be(&dev->iseg->cmdq_addr_l_sz) >> 8) & 3; return (ioread32be(&dev->iseg->cmdq_addr_l_sz) >> 8) & 3;
} }
void mlx5_set_nic_state(struct mlx5_core_dev *dev, u8 state)
{
u32 cur_cmdq_addr_l_sz;
cur_cmdq_addr_l_sz = ioread32be(&dev->iseg->cmdq_addr_l_sz);
iowrite32be((cur_cmdq_addr_l_sz & 0xFFFFF000) |
state << MLX5_NIC_IFC_OFFSET,
&dev->iseg->cmdq_addr_l_sz);
}
static void trigger_cmd_completions(struct mlx5_core_dev *dev) static void trigger_cmd_completions(struct mlx5_core_dev *dev)
{ {
unsigned long flags; unsigned long flags;
...@@ -103,7 +106,7 @@ static int in_fatal(struct mlx5_core_dev *dev) ...@@ -103,7 +106,7 @@ static int in_fatal(struct mlx5_core_dev *dev)
struct mlx5_core_health *health = &dev->priv.health; struct mlx5_core_health *health = &dev->priv.health;
struct health_buffer __iomem *h = health->health; struct health_buffer __iomem *h = health->health;
if (get_nic_state(dev) == MLX5_NIC_IFC_DISABLED) if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_DISABLED)
return 1; return 1;
if (ioread32be(&h->fw_ver) == 0xffffffff) if (ioread32be(&h->fw_ver) == 0xffffffff)
...@@ -133,7 +136,7 @@ void mlx5_enter_error_state(struct mlx5_core_dev *dev, bool force) ...@@ -133,7 +136,7 @@ void mlx5_enter_error_state(struct mlx5_core_dev *dev, bool force)
static void mlx5_handle_bad_state(struct mlx5_core_dev *dev) static void mlx5_handle_bad_state(struct mlx5_core_dev *dev)
{ {
u8 nic_interface = get_nic_state(dev); u8 nic_interface = mlx5_get_nic_state(dev);
switch (nic_interface) { switch (nic_interface) {
case MLX5_NIC_IFC_FULL: case MLX5_NIC_IFC_FULL:
...@@ -168,7 +171,7 @@ static void health_recover(struct work_struct *work) ...@@ -168,7 +171,7 @@ static void health_recover(struct work_struct *work)
priv = container_of(health, struct mlx5_priv, health); priv = container_of(health, struct mlx5_priv, health);
dev = container_of(priv, struct mlx5_core_dev, priv); dev = container_of(priv, struct mlx5_core_dev, priv);
nic_state = get_nic_state(dev); nic_state = mlx5_get_nic_state(dev);
if (nic_state == MLX5_NIC_IFC_INVALID) { if (nic_state == MLX5_NIC_IFC_INVALID) {
dev_err(&dev->pdev->dev, "health recovery flow aborted since the nic state is invalid\n"); dev_err(&dev->pdev->dev, "health recovery flow aborted since the nic state is invalid\n");
return; return;
......
...@@ -1594,12 +1594,17 @@ static const struct pci_error_handlers mlx5_err_handler = { ...@@ -1594,12 +1594,17 @@ static const struct pci_error_handlers mlx5_err_handler = {
static int mlx5_try_fast_unload(struct mlx5_core_dev *dev) static int mlx5_try_fast_unload(struct mlx5_core_dev *dev)
{ {
int ret; bool fast_teardown = false, force_teardown = false;
int ret = 1;
fast_teardown = MLX5_CAP_GEN(dev, fast_teardown);
force_teardown = MLX5_CAP_GEN(dev, force_teardown);
mlx5_core_dbg(dev, "force teardown firmware support=%d\n", force_teardown);
mlx5_core_dbg(dev, "fast teardown firmware support=%d\n", fast_teardown);
if (!MLX5_CAP_GEN(dev, force_teardown)) { if (!fast_teardown && !force_teardown)
mlx5_core_dbg(dev, "force teardown is not supported in the firmware\n");
return -EOPNOTSUPP; return -EOPNOTSUPP;
}
if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) { if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
mlx5_core_dbg(dev, "Device in internal error state, giving up\n"); mlx5_core_dbg(dev, "Device in internal error state, giving up\n");
...@@ -1612,13 +1617,19 @@ static int mlx5_try_fast_unload(struct mlx5_core_dev *dev) ...@@ -1612,13 +1617,19 @@ static int mlx5_try_fast_unload(struct mlx5_core_dev *dev)
mlx5_drain_health_wq(dev); mlx5_drain_health_wq(dev);
mlx5_stop_health_poll(dev, false); mlx5_stop_health_poll(dev, false);
ret = mlx5_cmd_fast_teardown_hca(dev);
if (!ret)
goto succeed;
ret = mlx5_cmd_force_teardown_hca(dev); ret = mlx5_cmd_force_teardown_hca(dev);
if (ret) { if (!ret)
mlx5_core_dbg(dev, "Firmware couldn't do fast unload error: %d\n", ret); goto succeed;
mlx5_start_health_poll(dev);
return ret; mlx5_core_dbg(dev, "Firmware couldn't do fast unload error: %d\n", ret);
} mlx5_start_health_poll(dev);
return ret;
succeed:
mlx5_enter_error_state(dev, true); mlx5_enter_error_state(dev, true);
/* Some platforms requiring freeing the IRQ's in the shutdown /* Some platforms requiring freeing the IRQ's in the shutdown
......
...@@ -95,6 +95,8 @@ int mlx5_query_board_id(struct mlx5_core_dev *dev); ...@@ -95,6 +95,8 @@ int mlx5_query_board_id(struct mlx5_core_dev *dev);
int mlx5_cmd_init_hca(struct mlx5_core_dev *dev, uint32_t *sw_owner_id); int mlx5_cmd_init_hca(struct mlx5_core_dev *dev, uint32_t *sw_owner_id);
int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev); int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev);
int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev); int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev);
int mlx5_cmd_fast_teardown_hca(struct mlx5_core_dev *dev);
void mlx5_core_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event, void mlx5_core_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event,
unsigned long param); unsigned long param);
void mlx5_core_page_fault(struct mlx5_core_dev *dev, void mlx5_core_page_fault(struct mlx5_core_dev *dev,
...@@ -214,4 +216,14 @@ int mlx5_lag_allow(struct mlx5_core_dev *dev); ...@@ -214,4 +216,14 @@ int mlx5_lag_allow(struct mlx5_core_dev *dev);
int mlx5_lag_forbid(struct mlx5_core_dev *dev); int mlx5_lag_forbid(struct mlx5_core_dev *dev);
void mlx5_reload_interface(struct mlx5_core_dev *mdev, int protocol); void mlx5_reload_interface(struct mlx5_core_dev *mdev, int protocol);
enum {
MLX5_NIC_IFC_FULL = 0,
MLX5_NIC_IFC_DISABLED = 1,
MLX5_NIC_IFC_NO_DRAM_NIC = 2,
MLX5_NIC_IFC_INVALID = 3
};
u8 mlx5_get_nic_state(struct mlx5_core_dev *dev);
void mlx5_set_nic_state(struct mlx5_core_dev *dev, u8 state);
#endif /* __MLX5_CORE_H__ */ #endif /* __MLX5_CORE_H__ */
...@@ -504,6 +504,10 @@ struct health_buffer { ...@@ -504,6 +504,10 @@ struct health_buffer {
__be16 ext_synd; __be16 ext_synd;
}; };
enum mlx5_cmd_addr_l_sz_offset {
MLX5_NIC_IFC_OFFSET = 8,
};
struct mlx5_init_seg { struct mlx5_init_seg {
__be32 fw_rev; __be32 fw_rev;
__be32 cmdif_rev_fw_sub; __be32 cmdif_rev_fw_sub;
......
...@@ -896,7 +896,8 @@ struct mlx5_ifc_cmd_hca_cap_bits { ...@@ -896,7 +896,8 @@ struct mlx5_ifc_cmd_hca_cap_bits {
u8 log_max_mkey[0x6]; u8 log_max_mkey[0x6];
u8 reserved_at_f0[0x8]; u8 reserved_at_f0[0x8];
u8 dump_fill_mkey[0x1]; u8 dump_fill_mkey[0x1];
u8 reserved_at_f9[0x3]; u8 reserved_at_f9[0x2];
u8 fast_teardown[0x1];
u8 log_max_eq[0x4]; u8 log_max_eq[0x4];
u8 max_indirection[0x8]; u8 max_indirection[0x8];
...@@ -3352,12 +3353,13 @@ struct mlx5_ifc_teardown_hca_out_bits { ...@@ -3352,12 +3353,13 @@ struct mlx5_ifc_teardown_hca_out_bits {
u8 reserved_at_40[0x3f]; u8 reserved_at_40[0x3f];
u8 force_state[0x1]; u8 state[0x1];
}; };
enum { enum {
MLX5_TEARDOWN_HCA_IN_PROFILE_GRACEFUL_CLOSE = 0x0, MLX5_TEARDOWN_HCA_IN_PROFILE_GRACEFUL_CLOSE = 0x0,
MLX5_TEARDOWN_HCA_IN_PROFILE_FORCE_CLOSE = 0x1, MLX5_TEARDOWN_HCA_IN_PROFILE_FORCE_CLOSE = 0x1,
MLX5_TEARDOWN_HCA_IN_PROFILE_PREPARE_FAST_TEARDOWN = 0x2,
}; };
struct mlx5_ifc_teardown_hca_in_bits { struct mlx5_ifc_teardown_hca_in_bits {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment