851 lines · c
1/*2 * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved.3 *4 * This software is available to you under a choice of one of two5 * licenses. You may choose to be licensed under the terms of the GNU6 * General Public License (GPL) Version 2, available from the file7 * COPYING in the main directory of this source tree, or the8 * OpenIB.org BSD license below:9 *10 * Redistribution and use in source and binary forms, with or11 * without modification, are permitted provided that the following12 * conditions are met:13 *14 * - Redistributions of source code must retain the above15 * copyright notice, this list of conditions and the following16 * disclaimer.17 *18 * - Redistributions in binary form must reproduce the above19 * copyright notice, this list of conditions and the following20 * disclaimer in the documentation and/or other materials21 * provided with the distribution.22 *23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE30 * SOFTWARE.31 */32 33#include <linux/mlx5/driver.h>34#include <linux/mlx5/eswitch.h>35#include "mlx5_core.h"36#include "../../mlxfw/mlxfw.h"37#include "lib/tout.h"38 39enum {40 MCQS_IDENTIFIER_BOOT_IMG = 0x1,41 MCQS_IDENTIFIER_OEM_NVCONFIG = 0x4,42 MCQS_IDENTIFIER_MLNX_NVCONFIG = 0x5,43 MCQS_IDENTIFIER_CS_TOKEN = 0x6,44 MCQS_IDENTIFIER_DBG_TOKEN = 0x7,45 MCQS_IDENTIFIER_GEARBOX = 0xA,46};47 48enum {49 MCQS_UPDATE_STATE_IDLE,50 MCQS_UPDATE_STATE_IN_PROGRESS,51 MCQS_UPDATE_STATE_APPLIED,52 MCQS_UPDATE_STATE_ACTIVE,53 MCQS_UPDATE_STATE_ACTIVE_PENDING_RESET,54 MCQS_UPDATE_STATE_FAILED,55 MCQS_UPDATE_STATE_CANCELED,56 MCQS_UPDATE_STATE_BUSY,57};58 59enum {60 MCQI_INFO_TYPE_CAPABILITIES = 0x0,61 MCQI_INFO_TYPE_VERSION = 0x1,62 MCQI_INFO_TYPE_ACTIVATION_METHOD = 0x5,63};64 65enum {66 MCQI_FW_RUNNING_VERSION = 0,67 MCQI_FW_STORED_VERSION = 1,68};69 70int mlx5_query_board_id(struct mlx5_core_dev *dev)71{72 u32 *out;73 int outlen = MLX5_ST_SZ_BYTES(query_adapter_out);74 u32 in[MLX5_ST_SZ_DW(query_adapter_in)] = {};75 int err;76 77 out = kzalloc(outlen, GFP_KERNEL);78 if (!out)79 return -ENOMEM;80 81 MLX5_SET(query_adapter_in, in, opcode, MLX5_CMD_OP_QUERY_ADAPTER);82 err = mlx5_cmd_exec_inout(dev, query_adapter, in, out);83 if (err)84 goto out;85 86 memcpy(dev->board_id,87 MLX5_ADDR_OF(query_adapter_out, out,88 query_adapter_struct.vsd_contd_psid),89 MLX5_FLD_SZ_BYTES(query_adapter_out,90 query_adapter_struct.vsd_contd_psid));91 92out:93 kfree(out);94 return err;95}96 97int mlx5_core_query_vendor_id(struct mlx5_core_dev *mdev, u32 *vendor_id)98{99 u32 *out;100 int outlen = MLX5_ST_SZ_BYTES(query_adapter_out);101 u32 in[MLX5_ST_SZ_DW(query_adapter_in)] = {};102 int err;103 104 out = kzalloc(outlen, GFP_KERNEL);105 if (!out)106 return -ENOMEM;107 108 MLX5_SET(query_adapter_in, in, opcode, MLX5_CMD_OP_QUERY_ADAPTER);109 err = mlx5_cmd_exec_inout(mdev, query_adapter, in, out);110 if (err)111 goto out;112 113 *vendor_id = MLX5_GET(query_adapter_out, out,114 query_adapter_struct.ieee_vendor_id);115out:116 kfree(out);117 return err;118}119EXPORT_SYMBOL(mlx5_core_query_vendor_id);120 121static int mlx5_get_pcam_reg(struct mlx5_core_dev *dev)122{123 return mlx5_query_pcam_reg(dev, dev->caps.pcam,124 MLX5_PCAM_FEATURE_ENHANCED_FEATURES,125 MLX5_PCAM_REGS_5000_TO_507F);126}127 128static int mlx5_get_mcam_access_reg_group(struct mlx5_core_dev *dev,129 enum mlx5_mcam_reg_groups group)130{131 return mlx5_query_mcam_reg(dev, dev->caps.mcam[group],132 MLX5_MCAM_FEATURE_ENHANCED_FEATURES, group);133}134 135static int mlx5_get_qcam_reg(struct mlx5_core_dev *dev)136{137 return mlx5_query_qcam_reg(dev, dev->caps.qcam,138 MLX5_QCAM_FEATURE_ENHANCED_FEATURES,139 MLX5_QCAM_REGS_FIRST_128);140}141 142int mlx5_query_hca_caps(struct mlx5_core_dev *dev)143{144 int err;145 146 err = mlx5_core_get_caps_mode(dev, MLX5_CAP_GENERAL, HCA_CAP_OPMOD_GET_CUR);147 if (err)148 return err;149 150 if (MLX5_CAP_GEN(dev, port_selection_cap)) {151 err = mlx5_core_get_caps_mode(dev, MLX5_CAP_PORT_SELECTION, HCA_CAP_OPMOD_GET_CUR);152 if (err)153 return err;154 }155 156 if (MLX5_CAP_GEN(dev, hca_cap_2)) {157 err = mlx5_core_get_caps_mode(dev, MLX5_CAP_GENERAL_2, HCA_CAP_OPMOD_GET_CUR);158 if (err)159 return err;160 }161 162 if (MLX5_CAP_GEN(dev, eth_net_offloads)) {163 err = mlx5_core_get_caps_mode(dev, MLX5_CAP_ETHERNET_OFFLOADS,164 HCA_CAP_OPMOD_GET_CUR);165 if (err)166 return err;167 }168 169 if (MLX5_CAP_GEN(dev, ipoib_enhanced_offloads)) {170 err = mlx5_core_get_caps_mode(dev, MLX5_CAP_IPOIB_ENHANCED_OFFLOADS,171 HCA_CAP_OPMOD_GET_CUR);172 if (err)173 return err;174 }175 176 if (MLX5_CAP_GEN(dev, pg)) {177 err = mlx5_core_get_caps_mode(dev, MLX5_CAP_ODP, HCA_CAP_OPMOD_GET_CUR);178 if (err)179 return err;180 }181 182 if (MLX5_CAP_GEN(dev, atomic)) {183 err = mlx5_core_get_caps_mode(dev, MLX5_CAP_ATOMIC, HCA_CAP_OPMOD_GET_CUR);184 if (err)185 return err;186 }187 188 if (MLX5_CAP_GEN(dev, roce)) {189 err = mlx5_core_get_caps_mode(dev, MLX5_CAP_ROCE, HCA_CAP_OPMOD_GET_CUR);190 if (err)191 return err;192 }193 194 if (MLX5_CAP_GEN(dev, nic_flow_table) ||195 MLX5_CAP_GEN(dev, ipoib_enhanced_offloads)) {196 err = mlx5_core_get_caps_mode(dev, MLX5_CAP_FLOW_TABLE, HCA_CAP_OPMOD_GET_CUR);197 if (err)198 return err;199 }200 201 if (MLX5_ESWITCH_MANAGER(dev)) {202 err = mlx5_core_get_caps_mode(dev, MLX5_CAP_ESWITCH_FLOW_TABLE,203 HCA_CAP_OPMOD_GET_CUR);204 if (err)205 return err;206 207 err = mlx5_core_get_caps_mode(dev, MLX5_CAP_ESWITCH, HCA_CAP_OPMOD_GET_CUR);208 if (err)209 return err;210 }211 212 if (MLX5_CAP_GEN(dev, qos)) {213 err = mlx5_core_get_caps_mode(dev, MLX5_CAP_QOS, HCA_CAP_OPMOD_GET_CUR);214 if (err)215 return err;216 }217 218 if (MLX5_CAP_GEN(dev, debug))219 mlx5_core_get_caps_mode(dev, MLX5_CAP_DEBUG, HCA_CAP_OPMOD_GET_CUR);220 221 if (MLX5_CAP_GEN(dev, pcam_reg))222 mlx5_get_pcam_reg(dev);223 224 if (MLX5_CAP_GEN(dev, mcam_reg)) {225 mlx5_get_mcam_access_reg_group(dev, MLX5_MCAM_REGS_FIRST_128);226 mlx5_get_mcam_access_reg_group(dev, MLX5_MCAM_REGS_0x9100_0x917F);227 mlx5_get_mcam_access_reg_group(dev, MLX5_MCAM_REGS_0x9180_0x91FF);228 }229 230 if (MLX5_CAP_GEN(dev, qcam_reg))231 mlx5_get_qcam_reg(dev);232 233 if (MLX5_CAP_GEN(dev, device_memory)) {234 err = mlx5_core_get_caps_mode(dev, MLX5_CAP_DEV_MEM, HCA_CAP_OPMOD_GET_CUR);235 if (err)236 return err;237 }238 239 if (MLX5_CAP_GEN(dev, event_cap)) {240 err = mlx5_core_get_caps_mode(dev, MLX5_CAP_DEV_EVENT, HCA_CAP_OPMOD_GET_CUR);241 if (err)242 return err;243 }244 245 if (MLX5_CAP_GEN(dev, tls_tx) || MLX5_CAP_GEN(dev, tls_rx)) {246 err = mlx5_core_get_caps_mode(dev, MLX5_CAP_TLS, HCA_CAP_OPMOD_GET_CUR);247 if (err)248 return err;249 }250 251 if (MLX5_CAP_GEN_64(dev, general_obj_types) &252 MLX5_GENERAL_OBJ_TYPES_CAP_VIRTIO_NET_Q) {253 err = mlx5_core_get_caps_mode(dev, MLX5_CAP_VDPA_EMULATION, HCA_CAP_OPMOD_GET_CUR);254 if (err)255 return err;256 }257 258 if (MLX5_CAP_GEN(dev, ipsec_offload)) {259 err = mlx5_core_get_caps_mode(dev, MLX5_CAP_IPSEC, HCA_CAP_OPMOD_GET_CUR);260 if (err)261 return err;262 }263 264 if (MLX5_CAP_GEN(dev, crypto)) {265 err = mlx5_core_get_caps_mode(dev, MLX5_CAP_CRYPTO, HCA_CAP_OPMOD_GET_CUR);266 if (err)267 return err;268 }269 270 if (MLX5_CAP_GEN_64(dev, general_obj_types) &271 MLX5_GENERAL_OBJ_TYPES_CAP_MACSEC_OFFLOAD) {272 err = mlx5_core_get_caps_mode(dev, MLX5_CAP_MACSEC, HCA_CAP_OPMOD_GET_CUR);273 if (err)274 return err;275 }276 277 if (MLX5_CAP_GEN(dev, adv_virtualization)) {278 err = mlx5_core_get_caps_mode(dev, MLX5_CAP_ADV_VIRTUALIZATION,279 HCA_CAP_OPMOD_GET_CUR);280 if (err)281 return err;282 }283 284 return 0;285}286 287int mlx5_cmd_init_hca(struct mlx5_core_dev *dev, u32 *sw_owner_id)288{289 u32 in[MLX5_ST_SZ_DW(init_hca_in)] = {};290 int i;291 292 MLX5_SET(init_hca_in, in, opcode, MLX5_CMD_OP_INIT_HCA);293 294 if (MLX5_CAP_GEN(dev, sw_owner_id)) {295 for (i = 0; i < 4; i++)296 MLX5_ARRAY_SET(init_hca_in, in, sw_owner_id, i,297 sw_owner_id[i]);298 }299 300 if (MLX5_CAP_GEN_2_MAX(dev, sw_vhca_id_valid) &&301 dev->priv.sw_vhca_id > 0)302 MLX5_SET(init_hca_in, in, sw_vhca_id, dev->priv.sw_vhca_id);303 304 return mlx5_cmd_exec_in(dev, init_hca, in);305}306 307int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev)308{309 u32 in[MLX5_ST_SZ_DW(teardown_hca_in)] = {};310 311 MLX5_SET(teardown_hca_in, in, opcode, MLX5_CMD_OP_TEARDOWN_HCA);312 return mlx5_cmd_exec_in(dev, teardown_hca, in);313}314 315int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev)316{317 u32 out[MLX5_ST_SZ_DW(teardown_hca_out)] = {0};318 u32 in[MLX5_ST_SZ_DW(teardown_hca_in)] = {0};319 int force_state;320 int ret;321 322 if (!MLX5_CAP_GEN(dev, force_teardown)) {323 mlx5_core_dbg(dev, "force teardown is not supported in the firmware\n");324 return -EOPNOTSUPP;325 }326 327 MLX5_SET(teardown_hca_in, in, opcode, MLX5_CMD_OP_TEARDOWN_HCA);328 MLX5_SET(teardown_hca_in, in, profile, MLX5_TEARDOWN_HCA_IN_PROFILE_FORCE_CLOSE);329 330 ret = mlx5_cmd_exec_polling(dev, in, sizeof(in), out, sizeof(out));331 if (ret)332 return ret;333 334 force_state = MLX5_GET(teardown_hca_out, out, state);335 if (force_state == MLX5_TEARDOWN_HCA_OUT_FORCE_STATE_FAIL) {336 mlx5_core_warn(dev, "teardown with force mode failed, doing normal teardown\n");337 return -EIO;338 }339 340 return 0;341}342 343int mlx5_cmd_fast_teardown_hca(struct mlx5_core_dev *dev)344{345 unsigned long end, delay_ms = mlx5_tout_ms(dev, TEARDOWN);346 u32 out[MLX5_ST_SZ_DW(teardown_hca_out)] = {};347 u32 in[MLX5_ST_SZ_DW(teardown_hca_in)] = {};348 int state;349 int ret;350 351 if (!MLX5_CAP_GEN(dev, fast_teardown)) {352 mlx5_core_dbg(dev, "fast teardown is not supported in the firmware\n");353 return -EOPNOTSUPP;354 }355 356 MLX5_SET(teardown_hca_in, in, opcode, MLX5_CMD_OP_TEARDOWN_HCA);357 MLX5_SET(teardown_hca_in, in, profile,358 MLX5_TEARDOWN_HCA_IN_PROFILE_PREPARE_FAST_TEARDOWN);359 360 ret = mlx5_cmd_exec_inout(dev, teardown_hca, in, out);361 if (ret)362 return ret;363 364 state = MLX5_GET(teardown_hca_out, out, state);365 if (state == MLX5_TEARDOWN_HCA_OUT_FORCE_STATE_FAIL) {366 mlx5_core_warn(dev, "teardown with fast mode failed\n");367 return -EIO;368 }369 370 mlx5_set_nic_state(dev, MLX5_INITIAL_SEG_NIC_INTERFACE_DISABLED);371 372 /* Loop until device state turns to disable */373 end = jiffies + msecs_to_jiffies(delay_ms);374 do {375 if (mlx5_get_nic_state(dev) == MLX5_INITIAL_SEG_NIC_INTERFACE_DISABLED)376 break;377 if (pci_channel_offline(dev->pdev)) {378 mlx5_core_err(dev, "PCI channel offline, stop waiting for NIC IFC\n");379 return -EACCES;380 }381 382 cond_resched();383 } while (!time_after(jiffies, end));384 385 if (mlx5_get_nic_state(dev) != MLX5_INITIAL_SEG_NIC_INTERFACE_DISABLED) {386 dev_err(&dev->pdev->dev, "NIC IFC still %d after %lums.\n",387 mlx5_get_nic_state(dev), delay_ms);388 return -EIO;389 }390 391 return 0;392}393 394enum mlxsw_reg_mcc_instruction {395 MLX5_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE = 0x01,396 MLX5_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE = 0x02,397 MLX5_REG_MCC_INSTRUCTION_UPDATE_COMPONENT = 0x03,398 MLX5_REG_MCC_INSTRUCTION_VERIFY_COMPONENT = 0x04,399 MLX5_REG_MCC_INSTRUCTION_ACTIVATE = 0x06,400 MLX5_REG_MCC_INSTRUCTION_CANCEL = 0x08,401};402 403static int mlx5_reg_mcc_set(struct mlx5_core_dev *dev,404 enum mlxsw_reg_mcc_instruction instr,405 u16 component_index, u32 update_handle,406 u32 component_size)407{408 u32 out[MLX5_ST_SZ_DW(mcc_reg)];409 u32 in[MLX5_ST_SZ_DW(mcc_reg)];410 411 memset(in, 0, sizeof(in));412 413 MLX5_SET(mcc_reg, in, instruction, instr);414 MLX5_SET(mcc_reg, in, component_index, component_index);415 MLX5_SET(mcc_reg, in, update_handle, update_handle);416 MLX5_SET(mcc_reg, in, component_size, component_size);417 418 return mlx5_core_access_reg(dev, in, sizeof(in), out,419 sizeof(out), MLX5_REG_MCC, 0, 1);420}421 422static int mlx5_reg_mcc_query(struct mlx5_core_dev *dev,423 u32 *update_handle, u8 *error_code,424 u8 *control_state)425{426 u32 out[MLX5_ST_SZ_DW(mcc_reg)];427 u32 in[MLX5_ST_SZ_DW(mcc_reg)];428 int err;429 430 memset(in, 0, sizeof(in));431 memset(out, 0, sizeof(out));432 MLX5_SET(mcc_reg, in, update_handle, *update_handle);433 434 err = mlx5_core_access_reg(dev, in, sizeof(in), out,435 sizeof(out), MLX5_REG_MCC, 0, 0);436 if (err)437 goto out;438 439 *update_handle = MLX5_GET(mcc_reg, out, update_handle);440 *error_code = MLX5_GET(mcc_reg, out, error_code);441 *control_state = MLX5_GET(mcc_reg, out, control_state);442 443out:444 return err;445}446 447static int mlx5_reg_mcda_set(struct mlx5_core_dev *dev,448 u32 update_handle,449 u32 offset, u16 size,450 u8 *data)451{452 int err, in_size = MLX5_ST_SZ_BYTES(mcda_reg) + size;453 u32 out[MLX5_ST_SZ_DW(mcda_reg)];454 int i, j, dw_size = size >> 2;455 __be32 data_element;456 u32 *in;457 458 in = kzalloc(in_size, GFP_KERNEL);459 if (!in)460 return -ENOMEM;461 462 MLX5_SET(mcda_reg, in, update_handle, update_handle);463 MLX5_SET(mcda_reg, in, offset, offset);464 MLX5_SET(mcda_reg, in, size, size);465 466 for (i = 0; i < dw_size; i++) {467 j = i * 4;468 data_element = htonl(*(u32 *)&data[j]);469 memcpy(MLX5_ADDR_OF(mcda_reg, in, data) + j, &data_element, 4);470 }471 472 err = mlx5_core_access_reg(dev, in, in_size, out,473 sizeof(out), MLX5_REG_MCDA, 0, 1);474 kfree(in);475 return err;476}477 478static int mlx5_reg_mcqi_query(struct mlx5_core_dev *dev,479 u16 component_index, bool read_pending,480 u8 info_type, u16 data_size, void *mcqi_data)481{482 u32 out[MLX5_ST_SZ_DW(mcqi_reg) + MLX5_UN_SZ_DW(mcqi_reg_data)] = {};483 u32 in[MLX5_ST_SZ_DW(mcqi_reg)] = {};484 void *data;485 int err;486 487 MLX5_SET(mcqi_reg, in, component_index, component_index);488 MLX5_SET(mcqi_reg, in, read_pending_component, read_pending);489 MLX5_SET(mcqi_reg, in, info_type, info_type);490 MLX5_SET(mcqi_reg, in, data_size, data_size);491 492 err = mlx5_core_access_reg(dev, in, sizeof(in), out,493 MLX5_ST_SZ_BYTES(mcqi_reg) + data_size,494 MLX5_REG_MCQI, 0, 0);495 if (err)496 return err;497 498 data = MLX5_ADDR_OF(mcqi_reg, out, data);499 memcpy(mcqi_data, data, data_size);500 501 return 0;502}503 504static int mlx5_reg_mcqi_caps_query(struct mlx5_core_dev *dev, u16 component_index,505 u32 *max_component_size, u8 *log_mcda_word_size,506 u16 *mcda_max_write_size)507{508 u32 mcqi_reg[MLX5_ST_SZ_DW(mcqi_cap)] = {};509 int err;510 511 err = mlx5_reg_mcqi_query(dev, component_index, 0,512 MCQI_INFO_TYPE_CAPABILITIES,513 MLX5_ST_SZ_BYTES(mcqi_cap), mcqi_reg);514 if (err)515 return err;516 517 *max_component_size = MLX5_GET(mcqi_cap, mcqi_reg, max_component_size);518 *log_mcda_word_size = MLX5_GET(mcqi_cap, mcqi_reg, log_mcda_word_size);519 *mcda_max_write_size = MLX5_GET(mcqi_cap, mcqi_reg, mcda_max_write_size);520 521 return 0;522}523 524struct mlx5_mlxfw_dev {525 struct mlxfw_dev mlxfw_dev;526 struct mlx5_core_dev *mlx5_core_dev;527};528 529static int mlx5_component_query(struct mlxfw_dev *mlxfw_dev,530 u16 component_index, u32 *p_max_size,531 u8 *p_align_bits, u16 *p_max_write_size)532{533 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =534 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);535 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;536 537 if (!MLX5_CAP_GEN(dev, mcam_reg) || !MLX5_CAP_MCAM_REG(dev, mcqi)) {538 mlx5_core_warn(dev, "caps query isn't supported by running FW\n");539 return -EOPNOTSUPP;540 }541 542 return mlx5_reg_mcqi_caps_query(dev, component_index, p_max_size,543 p_align_bits, p_max_write_size);544}545 546static int mlx5_fsm_lock(struct mlxfw_dev *mlxfw_dev, u32 *fwhandle)547{548 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =549 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);550 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;551 u8 control_state, error_code;552 int err;553 554 *fwhandle = 0;555 err = mlx5_reg_mcc_query(dev, fwhandle, &error_code, &control_state);556 if (err)557 return err;558 559 if (control_state != MLXFW_FSM_STATE_IDLE)560 return -EBUSY;561 562 return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE,563 0, *fwhandle, 0);564}565 566static int mlx5_fsm_component_update(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,567 u16 component_index, u32 component_size)568{569 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =570 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);571 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;572 573 return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_UPDATE_COMPONENT,574 component_index, fwhandle, component_size);575}576 577static int mlx5_fsm_block_download(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,578 u8 *data, u16 size, u32 offset)579{580 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =581 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);582 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;583 584 return mlx5_reg_mcda_set(dev, fwhandle, offset, size, data);585}586 587static int mlx5_fsm_component_verify(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,588 u16 component_index)589{590 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =591 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);592 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;593 594 return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_VERIFY_COMPONENT,595 component_index, fwhandle, 0);596}597 598static int mlx5_fsm_activate(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)599{600 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =601 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);602 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;603 604 return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_ACTIVATE, 0,605 fwhandle, 0);606}607 608static int mlx5_fsm_query_state(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,609 enum mlxfw_fsm_state *fsm_state,610 enum mlxfw_fsm_state_err *fsm_state_err)611{612 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =613 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);614 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;615 u8 control_state, error_code;616 int err;617 618 err = mlx5_reg_mcc_query(dev, &fwhandle, &error_code, &control_state);619 if (err)620 return err;621 622 *fsm_state = control_state;623 *fsm_state_err = min_t(enum mlxfw_fsm_state_err, error_code,624 MLXFW_FSM_STATE_ERR_MAX);625 return 0;626}627 628static void mlx5_fsm_cancel(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)629{630 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =631 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);632 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;633 634 mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_CANCEL, 0, fwhandle, 0);635}636 637static void mlx5_fsm_release(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)638{639 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =640 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);641 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;642 643 mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE, 0,644 fwhandle, 0);645}646 647static int mlx5_fsm_reactivate(struct mlxfw_dev *mlxfw_dev, u8 *status)648{649 struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =650 container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);651 struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;652 u32 out[MLX5_ST_SZ_DW(mirc_reg)];653 u32 in[MLX5_ST_SZ_DW(mirc_reg)];654 unsigned long exp_time;655 int err;656 657 exp_time = jiffies + msecs_to_jiffies(mlx5_tout_ms(dev, FSM_REACTIVATE));658 659 if (!MLX5_CAP_MCAM_REG2(dev, mirc))660 return -EOPNOTSUPP;661 662 memset(in, 0, sizeof(in));663 664 err = mlx5_core_access_reg(dev, in, sizeof(in), out,665 sizeof(out), MLX5_REG_MIRC, 0, 1);666 if (err)667 return err;668 669 do {670 memset(out, 0, sizeof(out));671 err = mlx5_core_access_reg(dev, in, sizeof(in), out,672 sizeof(out), MLX5_REG_MIRC, 0, 0);673 if (err)674 return err;675 676 *status = MLX5_GET(mirc_reg, out, status_code);677 if (*status != MLXFW_FSM_REACTIVATE_STATUS_BUSY)678 return 0;679 680 msleep(20);681 } while (time_before(jiffies, exp_time));682 683 return 0;684}685 686static const struct mlxfw_dev_ops mlx5_mlxfw_dev_ops = {687 .component_query = mlx5_component_query,688 .fsm_lock = mlx5_fsm_lock,689 .fsm_component_update = mlx5_fsm_component_update,690 .fsm_block_download = mlx5_fsm_block_download,691 .fsm_component_verify = mlx5_fsm_component_verify,692 .fsm_activate = mlx5_fsm_activate,693 .fsm_reactivate = mlx5_fsm_reactivate,694 .fsm_query_state = mlx5_fsm_query_state,695 .fsm_cancel = mlx5_fsm_cancel,696 .fsm_release = mlx5_fsm_release697};698 699int mlx5_firmware_flash(struct mlx5_core_dev *dev,700 const struct firmware *firmware,701 struct netlink_ext_ack *extack)702{703 struct mlx5_mlxfw_dev mlx5_mlxfw_dev = {704 .mlxfw_dev = {705 .ops = &mlx5_mlxfw_dev_ops,706 .psid = dev->board_id,707 .psid_size = strlen(dev->board_id),708 .devlink = priv_to_devlink(dev),709 },710 .mlx5_core_dev = dev711 };712 713 if (!MLX5_CAP_GEN(dev, mcam_reg) ||714 !MLX5_CAP_MCAM_REG(dev, mcqi) ||715 !MLX5_CAP_MCAM_REG(dev, mcc) ||716 !MLX5_CAP_MCAM_REG(dev, mcda)) {717 pr_info("%s flashing isn't supported by the running FW\n", __func__);718 return -EOPNOTSUPP;719 }720 721 return mlxfw_firmware_flash(&mlx5_mlxfw_dev.mlxfw_dev,722 firmware, extack);723}724 725static int mlx5_reg_mcqi_version_query(struct mlx5_core_dev *dev,726 u16 component_index, bool read_pending,727 u32 *mcqi_version_out)728{729 return mlx5_reg_mcqi_query(dev, component_index, read_pending,730 MCQI_INFO_TYPE_VERSION,731 MLX5_ST_SZ_BYTES(mcqi_version),732 mcqi_version_out);733}734 735static int mlx5_reg_mcqs_query(struct mlx5_core_dev *dev, u32 *out,736 u16 component_index)737{738 u8 out_sz = MLX5_ST_SZ_BYTES(mcqs_reg);739 u32 in[MLX5_ST_SZ_DW(mcqs_reg)] = {};740 int err;741 742 memset(out, 0, out_sz);743 744 MLX5_SET(mcqs_reg, in, component_index, component_index);745 746 err = mlx5_core_access_reg(dev, in, sizeof(in), out,747 out_sz, MLX5_REG_MCQS, 0, 0);748 return err;749}750 751/* scans component index sequentially, to find the boot img index */752static int mlx5_get_boot_img_component_index(struct mlx5_core_dev *dev)753{754 u32 out[MLX5_ST_SZ_DW(mcqs_reg)] = {};755 u16 identifier, component_idx = 0;756 bool quit;757 int err;758 759 do {760 err = mlx5_reg_mcqs_query(dev, out, component_idx);761 if (err)762 return err;763 764 identifier = MLX5_GET(mcqs_reg, out, identifier);765 quit = !!MLX5_GET(mcqs_reg, out, last_index_flag);766 quit |= identifier == MCQS_IDENTIFIER_BOOT_IMG;767 } while (!quit && ++component_idx);768 769 if (identifier != MCQS_IDENTIFIER_BOOT_IMG) {770 mlx5_core_warn(dev, "mcqs: can't find boot_img component ix, last scanned idx %d\n",771 component_idx);772 return -EOPNOTSUPP;773 }774 775 return component_idx;776}777 778static int779mlx5_fw_image_pending(struct mlx5_core_dev *dev,780 int component_index,781 bool *pending_version_exists)782{783 u32 out[MLX5_ST_SZ_DW(mcqs_reg)];784 u8 component_update_state;785 int err;786 787 err = mlx5_reg_mcqs_query(dev, out, component_index);788 if (err)789 return err;790 791 component_update_state = MLX5_GET(mcqs_reg, out, component_update_state);792 793 if (component_update_state == MCQS_UPDATE_STATE_IDLE) {794 *pending_version_exists = false;795 } else if (component_update_state == MCQS_UPDATE_STATE_ACTIVE_PENDING_RESET) {796 *pending_version_exists = true;797 } else {798 mlx5_core_warn(dev,799 "mcqs: can't read pending fw version while fw state is %d\n",800 component_update_state);801 return -ENODATA;802 }803 return 0;804}805 806int mlx5_fw_version_query(struct mlx5_core_dev *dev,807 u32 *running_ver, u32 *pending_ver)808{809 u32 reg_mcqi_version[MLX5_ST_SZ_DW(mcqi_version)] = {};810 bool pending_version_exists;811 int component_index;812 int err;813 814 if (!MLX5_CAP_GEN(dev, mcam_reg) || !MLX5_CAP_MCAM_REG(dev, mcqi) ||815 !MLX5_CAP_MCAM_REG(dev, mcqs)) {816 mlx5_core_warn(dev, "fw query isn't supported by the FW\n");817 return -EOPNOTSUPP;818 }819 820 component_index = mlx5_get_boot_img_component_index(dev);821 if (component_index < 0)822 return component_index;823 824 err = mlx5_reg_mcqi_version_query(dev, component_index,825 MCQI_FW_RUNNING_VERSION,826 reg_mcqi_version);827 if (err)828 return err;829 830 *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);831 832 err = mlx5_fw_image_pending(dev, component_index, &pending_version_exists);833 if (err)834 return err;835 836 if (!pending_version_exists) {837 *pending_ver = 0;838 return 0;839 }840 841 err = mlx5_reg_mcqi_version_query(dev, component_index,842 MCQI_FW_STORED_VERSION,843 reg_mcqi_version);844 if (err)845 return err;846 847 *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);848 849 return 0;850}851