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