Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved.
0003  *
0004  * This software is available to you under a choice of one of two
0005  * licenses.  You may choose to be licensed under the terms of the GNU
0006  * General Public License (GPL) Version 2, available from the file
0007  * COPYING in the main directory of this source tree, or the
0008  * OpenIB.org BSD license below:
0009  *
0010  *     Redistribution and use in source and binary forms, with or
0011  *     without modification, are permitted provided that the following
0012  *     conditions are met:
0013  *
0014  *      - Redistributions of source code must retain the above
0015  *        copyright notice, this list of conditions and the following
0016  *        disclaimer.
0017  *
0018  *      - Redistributions in binary form must reproduce the above
0019  *        copyright notice, this list of conditions and the following
0020  *        disclaimer in the documentation and/or other materials
0021  *        provided with the distribution.
0022  *
0023  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0024  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0025  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0026  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
0027  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
0028  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
0029  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0030  * SOFTWARE.
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     /* Loop until device state turns to disable */
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 /* scans component index sequentially, to find the boot img index */
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 }