0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #include <linux/mlx5/driver.h>
0034 #include <linux/mlx5/eswitch.h>
0035 #include "mlx5_core.h"
0036 #include "../../mlxfw/mlxfw.h"
0037 #include "lib/tout.h"
0038
0039 enum {
0040 MCQS_IDENTIFIER_BOOT_IMG = 0x1,
0041 MCQS_IDENTIFIER_OEM_NVCONFIG = 0x4,
0042 MCQS_IDENTIFIER_MLNX_NVCONFIG = 0x5,
0043 MCQS_IDENTIFIER_CS_TOKEN = 0x6,
0044 MCQS_IDENTIFIER_DBG_TOKEN = 0x7,
0045 MCQS_IDENTIFIER_GEARBOX = 0xA,
0046 };
0047
0048 enum {
0049 MCQS_UPDATE_STATE_IDLE,
0050 MCQS_UPDATE_STATE_IN_PROGRESS,
0051 MCQS_UPDATE_STATE_APPLIED,
0052 MCQS_UPDATE_STATE_ACTIVE,
0053 MCQS_UPDATE_STATE_ACTIVE_PENDING_RESET,
0054 MCQS_UPDATE_STATE_FAILED,
0055 MCQS_UPDATE_STATE_CANCELED,
0056 MCQS_UPDATE_STATE_BUSY,
0057 };
0058
0059 enum {
0060 MCQI_INFO_TYPE_CAPABILITIES = 0x0,
0061 MCQI_INFO_TYPE_VERSION = 0x1,
0062 MCQI_INFO_TYPE_ACTIVATION_METHOD = 0x5,
0063 };
0064
0065 enum {
0066 MCQI_FW_RUNNING_VERSION = 0,
0067 MCQI_FW_STORED_VERSION = 1,
0068 };
0069
0070 int mlx5_query_board_id(struct mlx5_core_dev *dev)
0071 {
0072 u32 *out;
0073 int outlen = MLX5_ST_SZ_BYTES(query_adapter_out);
0074 u32 in[MLX5_ST_SZ_DW(query_adapter_in)] = {};
0075 int err;
0076
0077 out = kzalloc(outlen, GFP_KERNEL);
0078 if (!out)
0079 return -ENOMEM;
0080
0081 MLX5_SET(query_adapter_in, in, opcode, MLX5_CMD_OP_QUERY_ADAPTER);
0082 err = mlx5_cmd_exec_inout(dev, query_adapter, in, out);
0083 if (err)
0084 goto out;
0085
0086 memcpy(dev->board_id,
0087 MLX5_ADDR_OF(query_adapter_out, out,
0088 query_adapter_struct.vsd_contd_psid),
0089 MLX5_FLD_SZ_BYTES(query_adapter_out,
0090 query_adapter_struct.vsd_contd_psid));
0091
0092 out:
0093 kfree(out);
0094 return err;
0095 }
0096
0097 int mlx5_core_query_vendor_id(struct mlx5_core_dev *mdev, u32 *vendor_id)
0098 {
0099 u32 *out;
0100 int outlen = MLX5_ST_SZ_BYTES(query_adapter_out);
0101 u32 in[MLX5_ST_SZ_DW(query_adapter_in)] = {};
0102 int err;
0103
0104 out = kzalloc(outlen, GFP_KERNEL);
0105 if (!out)
0106 return -ENOMEM;
0107
0108 MLX5_SET(query_adapter_in, in, opcode, MLX5_CMD_OP_QUERY_ADAPTER);
0109 err = mlx5_cmd_exec_inout(mdev, query_adapter, in, out);
0110 if (err)
0111 goto out;
0112
0113 *vendor_id = MLX5_GET(query_adapter_out, out,
0114 query_adapter_struct.ieee_vendor_id);
0115 out:
0116 kfree(out);
0117 return err;
0118 }
0119 EXPORT_SYMBOL(mlx5_core_query_vendor_id);
0120
0121 static int mlx5_get_pcam_reg(struct mlx5_core_dev *dev)
0122 {
0123 return mlx5_query_pcam_reg(dev, dev->caps.pcam,
0124 MLX5_PCAM_FEATURE_ENHANCED_FEATURES,
0125 MLX5_PCAM_REGS_5000_TO_507F);
0126 }
0127
0128 static int mlx5_get_mcam_access_reg_group(struct mlx5_core_dev *dev,
0129 enum mlx5_mcam_reg_groups group)
0130 {
0131 return mlx5_query_mcam_reg(dev, dev->caps.mcam[group],
0132 MLX5_MCAM_FEATURE_ENHANCED_FEATURES, group);
0133 }
0134
0135 static int mlx5_get_qcam_reg(struct mlx5_core_dev *dev)
0136 {
0137 return mlx5_query_qcam_reg(dev, dev->caps.qcam,
0138 MLX5_QCAM_FEATURE_ENHANCED_FEATURES,
0139 MLX5_QCAM_REGS_FIRST_128);
0140 }
0141
0142 int mlx5_query_hca_caps(struct mlx5_core_dev *dev)
0143 {
0144 int err;
0145
0146 err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL);
0147 if (err)
0148 return err;
0149
0150 if (MLX5_CAP_GEN(dev, port_selection_cap)) {
0151 err = mlx5_core_get_caps(dev, MLX5_CAP_PORT_SELECTION);
0152 if (err)
0153 return err;
0154 }
0155
0156 if (MLX5_CAP_GEN(dev, hca_cap_2)) {
0157 err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL_2);
0158 if (err)
0159 return err;
0160 }
0161
0162 if (MLX5_CAP_GEN(dev, eth_net_offloads)) {
0163 err = mlx5_core_get_caps(dev, MLX5_CAP_ETHERNET_OFFLOADS);
0164 if (err)
0165 return err;
0166 }
0167
0168 if (MLX5_CAP_GEN(dev, ipoib_enhanced_offloads)) {
0169 err = mlx5_core_get_caps(dev, MLX5_CAP_IPOIB_ENHANCED_OFFLOADS);
0170 if (err)
0171 return err;
0172 }
0173
0174 if (MLX5_CAP_GEN(dev, pg)) {
0175 err = mlx5_core_get_caps(dev, MLX5_CAP_ODP);
0176 if (err)
0177 return err;
0178 }
0179
0180 if (MLX5_CAP_GEN(dev, atomic)) {
0181 err = mlx5_core_get_caps(dev, MLX5_CAP_ATOMIC);
0182 if (err)
0183 return err;
0184 }
0185
0186 if (MLX5_CAP_GEN(dev, roce)) {
0187 err = mlx5_core_get_caps(dev, MLX5_CAP_ROCE);
0188 if (err)
0189 return err;
0190 }
0191
0192 if (MLX5_CAP_GEN(dev, nic_flow_table) ||
0193 MLX5_CAP_GEN(dev, ipoib_enhanced_offloads)) {
0194 err = mlx5_core_get_caps(dev, MLX5_CAP_FLOW_TABLE);
0195 if (err)
0196 return err;
0197 }
0198
0199 if (MLX5_CAP_GEN(dev, vport_group_manager) &&
0200 MLX5_ESWITCH_MANAGER(dev)) {
0201 err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH_FLOW_TABLE);
0202 if (err)
0203 return err;
0204 }
0205
0206 if (MLX5_ESWITCH_MANAGER(dev)) {
0207 err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH);
0208 if (err)
0209 return err;
0210 }
0211
0212 if (MLX5_CAP_GEN(dev, vector_calc)) {
0213 err = mlx5_core_get_caps(dev, MLX5_CAP_VECTOR_CALC);
0214 if (err)
0215 return err;
0216 }
0217
0218 if (MLX5_CAP_GEN(dev, qos)) {
0219 err = mlx5_core_get_caps(dev, MLX5_CAP_QOS);
0220 if (err)
0221 return err;
0222 }
0223
0224 if (MLX5_CAP_GEN(dev, debug))
0225 mlx5_core_get_caps(dev, MLX5_CAP_DEBUG);
0226
0227 if (MLX5_CAP_GEN(dev, pcam_reg))
0228 mlx5_get_pcam_reg(dev);
0229
0230 if (MLX5_CAP_GEN(dev, mcam_reg)) {
0231 mlx5_get_mcam_access_reg_group(dev, MLX5_MCAM_REGS_FIRST_128);
0232 mlx5_get_mcam_access_reg_group(dev, MLX5_MCAM_REGS_0x9080_0x90FF);
0233 mlx5_get_mcam_access_reg_group(dev, MLX5_MCAM_REGS_0x9100_0x917F);
0234 }
0235
0236 if (MLX5_CAP_GEN(dev, qcam_reg))
0237 mlx5_get_qcam_reg(dev);
0238
0239 if (MLX5_CAP_GEN(dev, device_memory)) {
0240 err = mlx5_core_get_caps(dev, MLX5_CAP_DEV_MEM);
0241 if (err)
0242 return err;
0243 }
0244
0245 if (MLX5_CAP_GEN(dev, event_cap)) {
0246 err = mlx5_core_get_caps(dev, MLX5_CAP_DEV_EVENT);
0247 if (err)
0248 return err;
0249 }
0250
0251 if (MLX5_CAP_GEN(dev, tls_tx) || MLX5_CAP_GEN(dev, tls_rx)) {
0252 err = mlx5_core_get_caps(dev, MLX5_CAP_TLS);
0253 if (err)
0254 return err;
0255 }
0256
0257 if (MLX5_CAP_GEN_64(dev, general_obj_types) &
0258 MLX5_GENERAL_OBJ_TYPES_CAP_VIRTIO_NET_Q) {
0259 err = mlx5_core_get_caps(dev, MLX5_CAP_VDPA_EMULATION);
0260 if (err)
0261 return err;
0262 }
0263
0264 if (MLX5_CAP_GEN(dev, ipsec_offload)) {
0265 err = mlx5_core_get_caps(dev, MLX5_CAP_IPSEC);
0266 if (err)
0267 return err;
0268 }
0269
0270 if (MLX5_CAP_GEN(dev, shampo)) {
0271 err = mlx5_core_get_caps(dev, MLX5_CAP_DEV_SHAMPO);
0272 if (err)
0273 return err;
0274 }
0275
0276 return 0;
0277 }
0278
0279 int mlx5_cmd_init_hca(struct mlx5_core_dev *dev, uint32_t *sw_owner_id)
0280 {
0281 u32 in[MLX5_ST_SZ_DW(init_hca_in)] = {};
0282 int i;
0283
0284 MLX5_SET(init_hca_in, in, opcode, MLX5_CMD_OP_INIT_HCA);
0285
0286 if (MLX5_CAP_GEN(dev, sw_owner_id)) {
0287 for (i = 0; i < 4; i++)
0288 MLX5_ARRAY_SET(init_hca_in, in, sw_owner_id, i,
0289 sw_owner_id[i]);
0290 }
0291
0292 if (MLX5_CAP_GEN_2_MAX(dev, sw_vhca_id_valid) &&
0293 dev->priv.sw_vhca_id > 0)
0294 MLX5_SET(init_hca_in, in, sw_vhca_id, dev->priv.sw_vhca_id);
0295
0296 return mlx5_cmd_exec_in(dev, init_hca, in);
0297 }
0298
0299 int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev)
0300 {
0301 u32 in[MLX5_ST_SZ_DW(teardown_hca_in)] = {};
0302
0303 MLX5_SET(teardown_hca_in, in, opcode, MLX5_CMD_OP_TEARDOWN_HCA);
0304 return mlx5_cmd_exec_in(dev, teardown_hca, in);
0305 }
0306
0307 int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev)
0308 {
0309 u32 out[MLX5_ST_SZ_DW(teardown_hca_out)] = {0};
0310 u32 in[MLX5_ST_SZ_DW(teardown_hca_in)] = {0};
0311 int force_state;
0312 int ret;
0313
0314 if (!MLX5_CAP_GEN(dev, force_teardown)) {
0315 mlx5_core_dbg(dev, "force teardown is not supported in the firmware\n");
0316 return -EOPNOTSUPP;
0317 }
0318
0319 MLX5_SET(teardown_hca_in, in, opcode, MLX5_CMD_OP_TEARDOWN_HCA);
0320 MLX5_SET(teardown_hca_in, in, profile, MLX5_TEARDOWN_HCA_IN_PROFILE_FORCE_CLOSE);
0321
0322 ret = mlx5_cmd_exec_polling(dev, in, sizeof(in), out, sizeof(out));
0323 if (ret)
0324 return ret;
0325
0326 force_state = MLX5_GET(teardown_hca_out, out, state);
0327 if (force_state == MLX5_TEARDOWN_HCA_OUT_FORCE_STATE_FAIL) {
0328 mlx5_core_warn(dev, "teardown with force mode failed, doing normal teardown\n");
0329 return -EIO;
0330 }
0331
0332 return 0;
0333 }
0334
0335 int mlx5_cmd_fast_teardown_hca(struct mlx5_core_dev *dev)
0336 {
0337 unsigned long end, delay_ms = mlx5_tout_ms(dev, TEARDOWN);
0338 u32 out[MLX5_ST_SZ_DW(teardown_hca_out)] = {};
0339 u32 in[MLX5_ST_SZ_DW(teardown_hca_in)] = {};
0340 int state;
0341 int ret;
0342
0343 if (!MLX5_CAP_GEN(dev, fast_teardown)) {
0344 mlx5_core_dbg(dev, "fast teardown is not supported in the firmware\n");
0345 return -EOPNOTSUPP;
0346 }
0347
0348 MLX5_SET(teardown_hca_in, in, opcode, MLX5_CMD_OP_TEARDOWN_HCA);
0349 MLX5_SET(teardown_hca_in, in, profile,
0350 MLX5_TEARDOWN_HCA_IN_PROFILE_PREPARE_FAST_TEARDOWN);
0351
0352 ret = mlx5_cmd_exec_inout(dev, teardown_hca, in, out);
0353 if (ret)
0354 return ret;
0355
0356 state = MLX5_GET(teardown_hca_out, out, state);
0357 if (state == MLX5_TEARDOWN_HCA_OUT_FORCE_STATE_FAIL) {
0358 mlx5_core_warn(dev, "teardown with fast mode failed\n");
0359 return -EIO;
0360 }
0361
0362 mlx5_set_nic_state(dev, MLX5_NIC_IFC_DISABLED);
0363
0364
0365 end = jiffies + msecs_to_jiffies(delay_ms);
0366 do {
0367 if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_DISABLED)
0368 break;
0369
0370 cond_resched();
0371 } while (!time_after(jiffies, end));
0372
0373 if (mlx5_get_nic_state(dev) != MLX5_NIC_IFC_DISABLED) {
0374 dev_err(&dev->pdev->dev, "NIC IFC still %d after %lums.\n",
0375 mlx5_get_nic_state(dev), delay_ms);
0376 return -EIO;
0377 }
0378
0379 return 0;
0380 }
0381
0382 enum mlxsw_reg_mcc_instruction {
0383 MLX5_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE = 0x01,
0384 MLX5_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE = 0x02,
0385 MLX5_REG_MCC_INSTRUCTION_UPDATE_COMPONENT = 0x03,
0386 MLX5_REG_MCC_INSTRUCTION_VERIFY_COMPONENT = 0x04,
0387 MLX5_REG_MCC_INSTRUCTION_ACTIVATE = 0x06,
0388 MLX5_REG_MCC_INSTRUCTION_CANCEL = 0x08,
0389 };
0390
0391 static int mlx5_reg_mcc_set(struct mlx5_core_dev *dev,
0392 enum mlxsw_reg_mcc_instruction instr,
0393 u16 component_index, u32 update_handle,
0394 u32 component_size)
0395 {
0396 u32 out[MLX5_ST_SZ_DW(mcc_reg)];
0397 u32 in[MLX5_ST_SZ_DW(mcc_reg)];
0398
0399 memset(in, 0, sizeof(in));
0400
0401 MLX5_SET(mcc_reg, in, instruction, instr);
0402 MLX5_SET(mcc_reg, in, component_index, component_index);
0403 MLX5_SET(mcc_reg, in, update_handle, update_handle);
0404 MLX5_SET(mcc_reg, in, component_size, component_size);
0405
0406 return mlx5_core_access_reg(dev, in, sizeof(in), out,
0407 sizeof(out), MLX5_REG_MCC, 0, 1);
0408 }
0409
0410 static int mlx5_reg_mcc_query(struct mlx5_core_dev *dev,
0411 u32 *update_handle, u8 *error_code,
0412 u8 *control_state)
0413 {
0414 u32 out[MLX5_ST_SZ_DW(mcc_reg)];
0415 u32 in[MLX5_ST_SZ_DW(mcc_reg)];
0416 int err;
0417
0418 memset(in, 0, sizeof(in));
0419 memset(out, 0, sizeof(out));
0420 MLX5_SET(mcc_reg, in, update_handle, *update_handle);
0421
0422 err = mlx5_core_access_reg(dev, in, sizeof(in), out,
0423 sizeof(out), MLX5_REG_MCC, 0, 0);
0424 if (err)
0425 goto out;
0426
0427 *update_handle = MLX5_GET(mcc_reg, out, update_handle);
0428 *error_code = MLX5_GET(mcc_reg, out, error_code);
0429 *control_state = MLX5_GET(mcc_reg, out, control_state);
0430
0431 out:
0432 return err;
0433 }
0434
0435 static int mlx5_reg_mcda_set(struct mlx5_core_dev *dev,
0436 u32 update_handle,
0437 u32 offset, u16 size,
0438 u8 *data)
0439 {
0440 int err, in_size = MLX5_ST_SZ_BYTES(mcda_reg) + size;
0441 u32 out[MLX5_ST_SZ_DW(mcda_reg)];
0442 int i, j, dw_size = size >> 2;
0443 __be32 data_element;
0444 u32 *in;
0445
0446 in = kzalloc(in_size, GFP_KERNEL);
0447 if (!in)
0448 return -ENOMEM;
0449
0450 MLX5_SET(mcda_reg, in, update_handle, update_handle);
0451 MLX5_SET(mcda_reg, in, offset, offset);
0452 MLX5_SET(mcda_reg, in, size, size);
0453
0454 for (i = 0; i < dw_size; i++) {
0455 j = i * 4;
0456 data_element = htonl(*(u32 *)&data[j]);
0457 memcpy(MLX5_ADDR_OF(mcda_reg, in, data) + j, &data_element, 4);
0458 }
0459
0460 err = mlx5_core_access_reg(dev, in, in_size, out,
0461 sizeof(out), MLX5_REG_MCDA, 0, 1);
0462 kfree(in);
0463 return err;
0464 }
0465
0466 static int mlx5_reg_mcqi_query(struct mlx5_core_dev *dev,
0467 u16 component_index, bool read_pending,
0468 u8 info_type, u16 data_size, void *mcqi_data)
0469 {
0470 u32 out[MLX5_ST_SZ_DW(mcqi_reg) + MLX5_UN_SZ_DW(mcqi_reg_data)] = {};
0471 u32 in[MLX5_ST_SZ_DW(mcqi_reg)] = {};
0472 void *data;
0473 int err;
0474
0475 MLX5_SET(mcqi_reg, in, component_index, component_index);
0476 MLX5_SET(mcqi_reg, in, read_pending_component, read_pending);
0477 MLX5_SET(mcqi_reg, in, info_type, info_type);
0478 MLX5_SET(mcqi_reg, in, data_size, data_size);
0479
0480 err = mlx5_core_access_reg(dev, in, sizeof(in), out,
0481 MLX5_ST_SZ_BYTES(mcqi_reg) + data_size,
0482 MLX5_REG_MCQI, 0, 0);
0483 if (err)
0484 return err;
0485
0486 data = MLX5_ADDR_OF(mcqi_reg, out, data);
0487 memcpy(mcqi_data, data, data_size);
0488
0489 return 0;
0490 }
0491
0492 static int mlx5_reg_mcqi_caps_query(struct mlx5_core_dev *dev, u16 component_index,
0493 u32 *max_component_size, u8 *log_mcda_word_size,
0494 u16 *mcda_max_write_size)
0495 {
0496 u32 mcqi_reg[MLX5_ST_SZ_DW(mcqi_cap)] = {};
0497 int err;
0498
0499 err = mlx5_reg_mcqi_query(dev, component_index, 0,
0500 MCQI_INFO_TYPE_CAPABILITIES,
0501 MLX5_ST_SZ_BYTES(mcqi_cap), mcqi_reg);
0502 if (err)
0503 return err;
0504
0505 *max_component_size = MLX5_GET(mcqi_cap, mcqi_reg, max_component_size);
0506 *log_mcda_word_size = MLX5_GET(mcqi_cap, mcqi_reg, log_mcda_word_size);
0507 *mcda_max_write_size = MLX5_GET(mcqi_cap, mcqi_reg, mcda_max_write_size);
0508
0509 return 0;
0510 }
0511
0512 struct mlx5_mlxfw_dev {
0513 struct mlxfw_dev mlxfw_dev;
0514 struct mlx5_core_dev *mlx5_core_dev;
0515 };
0516
0517 static int mlx5_component_query(struct mlxfw_dev *mlxfw_dev,
0518 u16 component_index, u32 *p_max_size,
0519 u8 *p_align_bits, u16 *p_max_write_size)
0520 {
0521 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
0522 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
0523 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
0524
0525 if (!MLX5_CAP_GEN(dev, mcam_reg) || !MLX5_CAP_MCAM_REG(dev, mcqi)) {
0526 mlx5_core_warn(dev, "caps query isn't supported by running FW\n");
0527 return -EOPNOTSUPP;
0528 }
0529
0530 return mlx5_reg_mcqi_caps_query(dev, component_index, p_max_size,
0531 p_align_bits, p_max_write_size);
0532 }
0533
0534 static int mlx5_fsm_lock(struct mlxfw_dev *mlxfw_dev, u32 *fwhandle)
0535 {
0536 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
0537 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
0538 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
0539 u8 control_state, error_code;
0540 int err;
0541
0542 *fwhandle = 0;
0543 err = mlx5_reg_mcc_query(dev, fwhandle, &error_code, &control_state);
0544 if (err)
0545 return err;
0546
0547 if (control_state != MLXFW_FSM_STATE_IDLE)
0548 return -EBUSY;
0549
0550 return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE,
0551 0, *fwhandle, 0);
0552 }
0553
0554 static int mlx5_fsm_component_update(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
0555 u16 component_index, u32 component_size)
0556 {
0557 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
0558 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
0559 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
0560
0561 return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_UPDATE_COMPONENT,
0562 component_index, fwhandle, component_size);
0563 }
0564
0565 static int mlx5_fsm_block_download(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
0566 u8 *data, u16 size, u32 offset)
0567 {
0568 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
0569 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
0570 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
0571
0572 return mlx5_reg_mcda_set(dev, fwhandle, offset, size, data);
0573 }
0574
0575 static int mlx5_fsm_component_verify(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
0576 u16 component_index)
0577 {
0578 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
0579 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
0580 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
0581
0582 return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_VERIFY_COMPONENT,
0583 component_index, fwhandle, 0);
0584 }
0585
0586 static int mlx5_fsm_activate(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)
0587 {
0588 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
0589 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
0590 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
0591
0592 return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_ACTIVATE, 0,
0593 fwhandle, 0);
0594 }
0595
0596 static int mlx5_fsm_query_state(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
0597 enum mlxfw_fsm_state *fsm_state,
0598 enum mlxfw_fsm_state_err *fsm_state_err)
0599 {
0600 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
0601 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
0602 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
0603 u8 control_state, error_code;
0604 int err;
0605
0606 err = mlx5_reg_mcc_query(dev, &fwhandle, &error_code, &control_state);
0607 if (err)
0608 return err;
0609
0610 *fsm_state = control_state;
0611 *fsm_state_err = min_t(enum mlxfw_fsm_state_err, error_code,
0612 MLXFW_FSM_STATE_ERR_MAX);
0613 return 0;
0614 }
0615
0616 static void mlx5_fsm_cancel(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)
0617 {
0618 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
0619 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
0620 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
0621
0622 mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_CANCEL, 0, fwhandle, 0);
0623 }
0624
0625 static void mlx5_fsm_release(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)
0626 {
0627 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
0628 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
0629 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
0630
0631 mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE, 0,
0632 fwhandle, 0);
0633 }
0634
0635 static int mlx5_fsm_reactivate(struct mlxfw_dev *mlxfw_dev, u8 *status)
0636 {
0637 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
0638 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
0639 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
0640 u32 out[MLX5_ST_SZ_DW(mirc_reg)];
0641 u32 in[MLX5_ST_SZ_DW(mirc_reg)];
0642 unsigned long exp_time;
0643 int err;
0644
0645 exp_time = jiffies + msecs_to_jiffies(mlx5_tout_ms(dev, FSM_REACTIVATE));
0646
0647 if (!MLX5_CAP_MCAM_REG2(dev, mirc))
0648 return -EOPNOTSUPP;
0649
0650 memset(in, 0, sizeof(in));
0651
0652 err = mlx5_core_access_reg(dev, in, sizeof(in), out,
0653 sizeof(out), MLX5_REG_MIRC, 0, 1);
0654 if (err)
0655 return err;
0656
0657 do {
0658 memset(out, 0, sizeof(out));
0659 err = mlx5_core_access_reg(dev, in, sizeof(in), out,
0660 sizeof(out), MLX5_REG_MIRC, 0, 0);
0661 if (err)
0662 return err;
0663
0664 *status = MLX5_GET(mirc_reg, out, status_code);
0665 if (*status != MLXFW_FSM_REACTIVATE_STATUS_BUSY)
0666 return 0;
0667
0668 msleep(20);
0669 } while (time_before(jiffies, exp_time));
0670
0671 return 0;
0672 }
0673
0674 static const struct mlxfw_dev_ops mlx5_mlxfw_dev_ops = {
0675 .component_query = mlx5_component_query,
0676 .fsm_lock = mlx5_fsm_lock,
0677 .fsm_component_update = mlx5_fsm_component_update,
0678 .fsm_block_download = mlx5_fsm_block_download,
0679 .fsm_component_verify = mlx5_fsm_component_verify,
0680 .fsm_activate = mlx5_fsm_activate,
0681 .fsm_reactivate = mlx5_fsm_reactivate,
0682 .fsm_query_state = mlx5_fsm_query_state,
0683 .fsm_cancel = mlx5_fsm_cancel,
0684 .fsm_release = mlx5_fsm_release
0685 };
0686
0687 int mlx5_firmware_flash(struct mlx5_core_dev *dev,
0688 const struct firmware *firmware,
0689 struct netlink_ext_ack *extack)
0690 {
0691 struct mlx5_mlxfw_dev mlx5_mlxfw_dev = {
0692 .mlxfw_dev = {
0693 .ops = &mlx5_mlxfw_dev_ops,
0694 .psid = dev->board_id,
0695 .psid_size = strlen(dev->board_id),
0696 .devlink = priv_to_devlink(dev),
0697 },
0698 .mlx5_core_dev = dev
0699 };
0700
0701 if (!MLX5_CAP_GEN(dev, mcam_reg) ||
0702 !MLX5_CAP_MCAM_REG(dev, mcqi) ||
0703 !MLX5_CAP_MCAM_REG(dev, mcc) ||
0704 !MLX5_CAP_MCAM_REG(dev, mcda)) {
0705 pr_info("%s flashing isn't supported by the running FW\n", __func__);
0706 return -EOPNOTSUPP;
0707 }
0708
0709 return mlxfw_firmware_flash(&mlx5_mlxfw_dev.mlxfw_dev,
0710 firmware, extack);
0711 }
0712
0713 static int mlx5_reg_mcqi_version_query(struct mlx5_core_dev *dev,
0714 u16 component_index, bool read_pending,
0715 u32 *mcqi_version_out)
0716 {
0717 return mlx5_reg_mcqi_query(dev, component_index, read_pending,
0718 MCQI_INFO_TYPE_VERSION,
0719 MLX5_ST_SZ_BYTES(mcqi_version),
0720 mcqi_version_out);
0721 }
0722
0723 static int mlx5_reg_mcqs_query(struct mlx5_core_dev *dev, u32 *out,
0724 u16 component_index)
0725 {
0726 u8 out_sz = MLX5_ST_SZ_BYTES(mcqs_reg);
0727 u32 in[MLX5_ST_SZ_DW(mcqs_reg)] = {};
0728 int err;
0729
0730 memset(out, 0, out_sz);
0731
0732 MLX5_SET(mcqs_reg, in, component_index, component_index);
0733
0734 err = mlx5_core_access_reg(dev, in, sizeof(in), out,
0735 out_sz, MLX5_REG_MCQS, 0, 0);
0736 return err;
0737 }
0738
0739
0740 static int mlx5_get_boot_img_component_index(struct mlx5_core_dev *dev)
0741 {
0742 u32 out[MLX5_ST_SZ_DW(mcqs_reg)] = {};
0743 u16 identifier, component_idx = 0;
0744 bool quit;
0745 int err;
0746
0747 do {
0748 err = mlx5_reg_mcqs_query(dev, out, component_idx);
0749 if (err)
0750 return err;
0751
0752 identifier = MLX5_GET(mcqs_reg, out, identifier);
0753 quit = !!MLX5_GET(mcqs_reg, out, last_index_flag);
0754 quit |= identifier == MCQS_IDENTIFIER_BOOT_IMG;
0755 } while (!quit && ++component_idx);
0756
0757 if (identifier != MCQS_IDENTIFIER_BOOT_IMG) {
0758 mlx5_core_warn(dev, "mcqs: can't find boot_img component ix, last scanned idx %d\n",
0759 component_idx);
0760 return -EOPNOTSUPP;
0761 }
0762
0763 return component_idx;
0764 }
0765
0766 static int
0767 mlx5_fw_image_pending(struct mlx5_core_dev *dev,
0768 int component_index,
0769 bool *pending_version_exists)
0770 {
0771 u32 out[MLX5_ST_SZ_DW(mcqs_reg)];
0772 u8 component_update_state;
0773 int err;
0774
0775 err = mlx5_reg_mcqs_query(dev, out, component_index);
0776 if (err)
0777 return err;
0778
0779 component_update_state = MLX5_GET(mcqs_reg, out, component_update_state);
0780
0781 if (component_update_state == MCQS_UPDATE_STATE_IDLE) {
0782 *pending_version_exists = false;
0783 } else if (component_update_state == MCQS_UPDATE_STATE_ACTIVE_PENDING_RESET) {
0784 *pending_version_exists = true;
0785 } else {
0786 mlx5_core_warn(dev,
0787 "mcqs: can't read pending fw version while fw state is %d\n",
0788 component_update_state);
0789 return -ENODATA;
0790 }
0791 return 0;
0792 }
0793
0794 int mlx5_fw_version_query(struct mlx5_core_dev *dev,
0795 u32 *running_ver, u32 *pending_ver)
0796 {
0797 u32 reg_mcqi_version[MLX5_ST_SZ_DW(mcqi_version)] = {};
0798 bool pending_version_exists;
0799 int component_index;
0800 int err;
0801
0802 if (!MLX5_CAP_GEN(dev, mcam_reg) || !MLX5_CAP_MCAM_REG(dev, mcqi) ||
0803 !MLX5_CAP_MCAM_REG(dev, mcqs)) {
0804 mlx5_core_warn(dev, "fw query isn't supported by the FW\n");
0805 return -EOPNOTSUPP;
0806 }
0807
0808 component_index = mlx5_get_boot_img_component_index(dev);
0809 if (component_index < 0)
0810 return component_index;
0811
0812 err = mlx5_reg_mcqi_version_query(dev, component_index,
0813 MCQI_FW_RUNNING_VERSION,
0814 reg_mcqi_version);
0815 if (err)
0816 return err;
0817
0818 *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
0819
0820 err = mlx5_fw_image_pending(dev, component_index, &pending_version_exists);
0821 if (err)
0822 return err;
0823
0824 if (!pending_version_exists) {
0825 *pending_ver = 0;
0826 return 0;
0827 }
0828
0829 err = mlx5_reg_mcqi_version_query(dev, component_index,
0830 MCQI_FW_STORED_VERSION,
0831 reg_mcqi_version);
0832 if (err)
0833 return err;
0834
0835 *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
0836
0837 return 0;
0838 }