root/drivers/net/ethernet/mellanox/mlx5/core/fw.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mlx5_cmd_query_adapter
  2. mlx5_query_board_id
  3. mlx5_core_query_vendor_id
  4. mlx5_get_pcam_reg
  5. mlx5_get_mcam_reg
  6. mlx5_get_qcam_reg
  7. mlx5_query_hca_caps
  8. mlx5_cmd_init_hca
  9. mlx5_cmd_teardown_hca
  10. mlx5_cmd_force_teardown_hca
  11. mlx5_cmd_fast_teardown_hca
  12. mlx5_reg_mcc_set
  13. mlx5_reg_mcc_query
  14. mlx5_reg_mcda_set
  15. mlx5_reg_mcqi_query
  16. mlx5_reg_mcqi_caps_query
  17. mlx5_component_query
  18. mlx5_fsm_lock
  19. mlx5_fsm_component_update
  20. mlx5_fsm_block_download
  21. mlx5_fsm_component_verify
  22. mlx5_fsm_activate
  23. mlx5_fsm_query_state
  24. mlx5_fsm_cancel
  25. mlx5_fsm_release
  26. mlx5_firmware_flash
  27. mlx5_reg_mcqi_version_query
  28. mlx5_reg_mcqs_query
  29. mlx5_get_boot_img_component_index
  30. mlx5_fw_image_pending
  31. mlx5_fw_version_query

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

/* [<][>][^][v][top][bottom][index][help] */