|
| 1 | +From d3e0bf403d527f717a62ea328781256f999d4f95 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Stepan Blyschak < [email protected]> |
| 3 | +Date: Mon, 20 Jun 2022 19:28:04 +0300 |
| 4 | +Subject: [PATCH] mlxsw: i2c: Prevent transaction execution for special |
| 5 | + chip states |
| 6 | + |
| 7 | +Do not run transaction in cases chip is in reset or in-service update |
| 8 | +states. In such case firmware is not accessible and will reject transaction |
| 9 | +with the relevant status "RUNNING_RESET" or "FW_ISSU_ONGOING". |
| 10 | +In case transaction is failed do to one of these reasons, stop sending |
| 11 | +transactions. In such case driver is about to be removed since it |
| 12 | +cannot continue running after reset or in-service update. And |
| 13 | +re-probed again after reset or in-service update is completed. |
| 14 | + |
| 15 | +Signed-off-by: Vadim Pasternak < [email protected]> |
| 16 | +Signed-off-by: Stepan Blyschak < [email protected]> |
| 17 | +--- |
| 18 | + drivers/net/ethernet/mellanox/mlxsw/cmd.h | 4 ++++ |
| 19 | + drivers/net/ethernet/mellanox/mlxsw/i2c.c | 29 ++++++++++++++++++++--- |
| 20 | + 2 files changed, 30 insertions(+), 3 deletions(-) |
| 21 | + |
| 22 | +diff --git a/drivers/net/ethernet/mellanox/mlxsw/cmd.h b/drivers/net/ethernet/mellanox/mlxsw/cmd.h |
| 23 | +index 91f68fb0b..d8ecb8c8a 100644 |
| 24 | +--- a/drivers/net/ethernet/mellanox/mlxsw/cmd.h |
| 25 | ++++ b/drivers/net/ethernet/mellanox/mlxsw/cmd.h |
| 26 | +@@ -149,6 +149,8 @@ enum mlxsw_cmd_status { |
| 27 | + MLXSW_CMD_STATUS_BAD_NVMEM = 0x0B, |
| 28 | + /* Device is currently running reset */ |
| 29 | + MLXSW_CMD_STATUS_RUNNING_RESET = 0x26, |
| 30 | ++ /* FW ISSU ongoing. */ |
| 31 | ++ MLXSW_CMD_STATUS_FW_ISSU = 0x27, |
| 32 | + /* Bad management packet (silently discarded). */ |
| 33 | + MLXSW_CMD_STATUS_BAD_PKT = 0x30, |
| 34 | + }; |
| 35 | +@@ -180,6 +182,8 @@ static inline const char *mlxsw_cmd_status_str(u8 status) |
| 36 | + return "BAD_NVMEM"; |
| 37 | + case MLXSW_CMD_STATUS_RUNNING_RESET: |
| 38 | + return "RUNNING_RESET"; |
| 39 | ++ case MLXSW_CMD_STATUS_FW_ISSU: |
| 40 | ++ return "FW_ISSU_ONGOING"; |
| 41 | + case MLXSW_CMD_STATUS_BAD_PKT: |
| 42 | + return "BAD_PKT"; |
| 43 | + default: |
| 44 | +diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c |
| 45 | +index 939b692ff..3c9d2c7a0 100644 |
| 46 | +--- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c |
| 47 | ++++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c |
| 48 | +@@ -63,6 +63,7 @@ |
| 49 | + * @core: switch core pointer; |
| 50 | + * @bus_info: bus info block; |
| 51 | + * @block_size: maximum block size allowed to pass to under layer; |
| 52 | ++ * @status: status to indicate chip reset or in-service update; |
| 53 | + */ |
| 54 | + struct mlxsw_i2c { |
| 55 | + struct { |
| 56 | +@@ -76,6 +77,7 @@ struct mlxsw_i2c { |
| 57 | + struct mlxsw_core *core; |
| 58 | + struct mlxsw_bus_info bus_info; |
| 59 | + u16 block_size; |
| 60 | ++ u8 status; |
| 61 | + }; |
| 62 | + |
| 63 | + #define MLXSW_I2C_READ_MSG(_client, _addr_buf, _buf, _len) { \ |
| 64 | +@@ -222,6 +224,19 @@ static int mlxsw_i2c_write_cmd(struct i2c_client *client, |
| 65 | + return 0; |
| 66 | + } |
| 67 | + |
| 68 | ++static bool |
| 69 | ++mlxsw_i2c_cmd_status_verify(struct device *dev, struct mlxsw_i2c *mlxsw_i2c, |
| 70 | ++ u8 status) |
| 71 | ++{ |
| 72 | ++ if (status == MLXSW_CMD_STATUS_FW_ISSU || |
| 73 | ++ status == MLXSW_CMD_STATUS_RUNNING_RESET) { |
| 74 | ++ mlxsw_i2c->status = status; |
| 75 | ++ dev_info(dev, "FW status=%x(%s)): Access to device is not allowed in this state\n", status, mlxsw_cmd_status_str(status)); |
| 76 | ++ return true; |
| 77 | ++ } |
| 78 | ++ return false; |
| 79 | ++} |
| 80 | ++ |
| 81 | + /* Routine posts initialization command to ASIC through mail box. */ |
| 82 | + static int |
| 83 | + mlxsw_i2c_write_init_cmd(struct i2c_client *client, |
| 84 | +@@ -405,6 +420,10 @@ mlxsw_i2c_cmd(struct device *dev, u16 opcode, u32 in_mod, size_t in_mbox_size, |
| 85 | + |
| 86 | + WARN_ON(in_mbox_size % sizeof(u32) || out_mbox_size % sizeof(u32)); |
| 87 | + |
| 88 | ++ /* Do not run transaction if chip is in reset or in-service update state. */ |
| 89 | ++ if (mlxsw_i2c->status) |
| 90 | ++ return 0; |
| 91 | ++ |
| 92 | + if (in_mbox) { |
| 93 | + reg_size = mlxsw_i2c_get_reg_size(in_mbox); |
| 94 | + num = reg_size / mlxsw_i2c->block_size; |
| 95 | +@@ -479,6 +498,8 @@ mlxsw_i2c_cmd(struct device *dev, u16 opcode, u32 in_mod, size_t in_mbox_size, |
| 96 | + |
| 97 | + cmd_fail: |
| 98 | + mutex_unlock(&mlxsw_i2c->cmd.lock); |
| 99 | ++ if (mlxsw_i2c_cmd_status_verify(&client->dev, mlxsw_i2c, *status)) |
| 100 | ++ err = 0; |
| 101 | + return err; |
| 102 | + } |
| 103 | + |
| 104 | +@@ -608,14 +629,16 @@ static int mlxsw_i2c_probe(struct i2c_client *client, |
| 105 | + /* Wait until go bit is cleared. */ |
| 106 | + err = mlxsw_i2c_wait_go_bit(client, mlxsw_i2c, &status); |
| 107 | + if (err) { |
| 108 | +- dev_err(&client->dev, "HW semaphore is not released"); |
| 109 | ++ if (!mlxsw_i2c_cmd_status_verify(&client->dev, mlxsw_i2c, status)) |
| 110 | ++ dev_err(&client->dev, "HW semaphore is not released"); |
| 111 | + goto errout; |
| 112 | + } |
| 113 | + |
| 114 | + /* Validate transaction completion status. */ |
| 115 | + if (status) { |
| 116 | +- dev_err(&client->dev, "Bad transaction completion status %x\n", |
| 117 | +- status); |
| 118 | ++ if (!mlxsw_i2c_cmd_status_verify(&client->dev, mlxsw_i2c, status)) |
| 119 | ++ dev_err(&client->dev, "Bad transaction completion status %x\n", |
| 120 | ++ status); |
| 121 | + err = -EIO; |
| 122 | + goto errout; |
| 123 | + } |
| 124 | +-- |
| 125 | +2.17.1 |
| 126 | + |
0 commit comments