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