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/cmd.h>
  35#include <linux/module.h>
  36#include "mlx5_core.h"
  37#include "../../mlxfw/mlxfw.h"
  38
  39static int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev, u32 *out,
  40                                  int outlen)
  41{
  42        u32 in[MLX5_ST_SZ_DW(query_adapter_in)] = {0};
  43
  44        MLX5_SET(query_adapter_in, in, opcode, MLX5_CMD_OP_QUERY_ADAPTER);
  45        return mlx5_cmd_exec(dev, in, sizeof(in), out, outlen);
  46}
  47
  48int mlx5_query_board_id(struct mlx5_core_dev *dev)
  49{
  50        u32 *out;
  51        int outlen = MLX5_ST_SZ_BYTES(query_adapter_out);
  52        int err;
  53
  54        out = kzalloc(outlen, GFP_KERNEL);
  55        if (!out)
  56                return -ENOMEM;
  57
  58        err = mlx5_cmd_query_adapter(dev, out, outlen);
  59        if (err)
  60                goto out;
  61
  62        memcpy(dev->board_id,
  63               MLX5_ADDR_OF(query_adapter_out, out,
  64                            query_adapter_struct.vsd_contd_psid),
  65               MLX5_FLD_SZ_BYTES(query_adapter_out,
  66                                 query_adapter_struct.vsd_contd_psid));
  67
  68out:
  69        kfree(out);
  70        return err;
  71}
  72
  73int mlx5_core_query_vendor_id(struct mlx5_core_dev *mdev, u32 *vendor_id)
  74{
  75        u32 *out;
  76        int outlen = MLX5_ST_SZ_BYTES(query_adapter_out);
  77        int err;
  78
  79        out = kzalloc(outlen, GFP_KERNEL);
  80        if (!out)
  81                return -ENOMEM;
  82
  83        err = mlx5_cmd_query_adapter(mdev, out, outlen);
  84        if (err)
  85                goto out;
  86
  87        *vendor_id = MLX5_GET(query_adapter_out, out,
  88                              query_adapter_struct.ieee_vendor_id);
  89out:
  90        kfree(out);
  91        return err;
  92}
  93EXPORT_SYMBOL(mlx5_core_query_vendor_id);
  94
  95static int mlx5_get_pcam_reg(struct mlx5_core_dev *dev)
  96{
  97        return mlx5_query_pcam_reg(dev, dev->caps.pcam,
  98                                   MLX5_PCAM_FEATURE_ENHANCED_FEATURES,
  99                                   MLX5_PCAM_REGS_5000_TO_507F);
 100}
 101
 102static int mlx5_get_mcam_reg(struct mlx5_core_dev *dev)
 103{
 104        return mlx5_query_mcam_reg(dev, dev->caps.mcam,
 105                                   MLX5_MCAM_FEATURE_ENHANCED_FEATURES,
 106                                   MLX5_MCAM_REGS_FIRST_128);
 107}
 108
 109int mlx5_query_hca_caps(struct mlx5_core_dev *dev)
 110{
 111        int err;
 112
 113        err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL);
 114        if (err)
 115                return err;
 116
 117        if (MLX5_CAP_GEN(dev, eth_net_offloads)) {
 118                err = mlx5_core_get_caps(dev, MLX5_CAP_ETHERNET_OFFLOADS);
 119                if (err)
 120                        return err;
 121        }
 122
 123        if (MLX5_CAP_GEN(dev, pg)) {
 124                err = mlx5_core_get_caps(dev, MLX5_CAP_ODP);
 125                if (err)
 126                        return err;
 127        }
 128
 129        if (MLX5_CAP_GEN(dev, atomic)) {
 130                err = mlx5_core_get_caps(dev, MLX5_CAP_ATOMIC);
 131                if (err)
 132                        return err;
 133        }
 134
 135        if (MLX5_CAP_GEN(dev, roce)) {
 136                err = mlx5_core_get_caps(dev, MLX5_CAP_ROCE);
 137                if (err)
 138                        return err;
 139        }
 140
 141        if (MLX5_CAP_GEN(dev, nic_flow_table) ||
 142            MLX5_CAP_GEN(dev, ipoib_enhanced_offloads)) {
 143                err = mlx5_core_get_caps(dev, MLX5_CAP_FLOW_TABLE);
 144                if (err)
 145                        return err;
 146        }
 147
 148        if (MLX5_CAP_GEN(dev, vport_group_manager) &&
 149            MLX5_CAP_GEN(dev, eswitch_flow_table)) {
 150                err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH_FLOW_TABLE);
 151                if (err)
 152                        return err;
 153        }
 154
 155        if (MLX5_CAP_GEN(dev, eswitch_flow_table)) {
 156                err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH);
 157                if (err)
 158                        return err;
 159        }
 160
 161        if (MLX5_CAP_GEN(dev, vector_calc)) {
 162                err = mlx5_core_get_caps(dev, MLX5_CAP_VECTOR_CALC);
 163                if (err)
 164                        return err;
 165        }
 166
 167        if (MLX5_CAP_GEN(dev, qos)) {
 168                err = mlx5_core_get_caps(dev, MLX5_CAP_QOS);
 169                if (err)
 170                        return err;
 171        }
 172
 173        if (MLX5_CAP_GEN(dev, pcam_reg))
 174                mlx5_get_pcam_reg(dev);
 175
 176        if (MLX5_CAP_GEN(dev, mcam_reg))
 177                mlx5_get_mcam_reg(dev);
 178
 179        return 0;
 180}
 181
 182int mlx5_cmd_init_hca(struct mlx5_core_dev *dev)
 183{
 184        u32 out[MLX5_ST_SZ_DW(init_hca_out)] = {0};
 185        u32 in[MLX5_ST_SZ_DW(init_hca_in)]   = {0};
 186
 187        MLX5_SET(init_hca_in, in, opcode, MLX5_CMD_OP_INIT_HCA);
 188        return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
 189}
 190
 191int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev)
 192{
 193        u32 out[MLX5_ST_SZ_DW(teardown_hca_out)] = {0};
 194        u32 in[MLX5_ST_SZ_DW(teardown_hca_in)]   = {0};
 195
 196        MLX5_SET(teardown_hca_in, in, opcode, MLX5_CMD_OP_TEARDOWN_HCA);
 197        return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
 198}
 199
 200int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev)
 201{
 202        u32 out[MLX5_ST_SZ_DW(teardown_hca_out)] = {0};
 203        u32 in[MLX5_ST_SZ_DW(teardown_hca_in)] = {0};
 204        int force_state;
 205        int ret;
 206
 207        if (!MLX5_CAP_GEN(dev, force_teardown)) {
 208                mlx5_core_dbg(dev, "force teardown is not supported in the firmware\n");
 209                return -EOPNOTSUPP;
 210        }
 211
 212        MLX5_SET(teardown_hca_in, in, opcode, MLX5_CMD_OP_TEARDOWN_HCA);
 213        MLX5_SET(teardown_hca_in, in, profile, MLX5_TEARDOWN_HCA_IN_PROFILE_FORCE_CLOSE);
 214
 215        ret = mlx5_cmd_exec_polling(dev, in, sizeof(in), out, sizeof(out));
 216        if (ret)
 217                return ret;
 218
 219        force_state = MLX5_GET(teardown_hca_out, out, force_state);
 220        if (force_state == MLX5_TEARDOWN_HCA_OUT_FORCE_STATE_FAIL) {
 221                mlx5_core_err(dev, "teardown with force mode failed\n");
 222                return -EIO;
 223        }
 224
 225        return 0;
 226}
 227
 228enum mlxsw_reg_mcc_instruction {
 229        MLX5_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE = 0x01,
 230        MLX5_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE = 0x02,
 231        MLX5_REG_MCC_INSTRUCTION_UPDATE_COMPONENT = 0x03,
 232        MLX5_REG_MCC_INSTRUCTION_VERIFY_COMPONENT = 0x04,
 233        MLX5_REG_MCC_INSTRUCTION_ACTIVATE = 0x06,
 234        MLX5_REG_MCC_INSTRUCTION_CANCEL = 0x08,
 235};
 236
 237static int mlx5_reg_mcc_set(struct mlx5_core_dev *dev,
 238                            enum mlxsw_reg_mcc_instruction instr,
 239                            u16 component_index, u32 update_handle,
 240                            u32 component_size)
 241{
 242        u32 out[MLX5_ST_SZ_DW(mcc_reg)];
 243        u32 in[MLX5_ST_SZ_DW(mcc_reg)];
 244
 245        memset(in, 0, sizeof(in));
 246
 247        MLX5_SET(mcc_reg, in, instruction, instr);
 248        MLX5_SET(mcc_reg, in, component_index, component_index);
 249        MLX5_SET(mcc_reg, in, update_handle, update_handle);
 250        MLX5_SET(mcc_reg, in, component_size, component_size);
 251
 252        return mlx5_core_access_reg(dev, in, sizeof(in), out,
 253                                    sizeof(out), MLX5_REG_MCC, 0, 1);
 254}
 255
 256static int mlx5_reg_mcc_query(struct mlx5_core_dev *dev,
 257                              u32 *update_handle, u8 *error_code,
 258                              u8 *control_state)
 259{
 260        u32 out[MLX5_ST_SZ_DW(mcc_reg)];
 261        u32 in[MLX5_ST_SZ_DW(mcc_reg)];
 262        int err;
 263
 264        memset(in, 0, sizeof(in));
 265        memset(out, 0, sizeof(out));
 266        MLX5_SET(mcc_reg, in, update_handle, *update_handle);
 267
 268        err = mlx5_core_access_reg(dev, in, sizeof(in), out,
 269                                   sizeof(out), MLX5_REG_MCC, 0, 0);
 270        if (err)
 271                goto out;
 272
 273        *update_handle = MLX5_GET(mcc_reg, out, update_handle);
 274        *error_code = MLX5_GET(mcc_reg, out, error_code);
 275        *control_state = MLX5_GET(mcc_reg, out, control_state);
 276
 277out:
 278        return err;
 279}
 280
 281static int mlx5_reg_mcda_set(struct mlx5_core_dev *dev,
 282                             u32 update_handle,
 283                             u32 offset, u16 size,
 284                             u8 *data)
 285{
 286        int err, in_size = MLX5_ST_SZ_BYTES(mcda_reg) + size;
 287        u32 out[MLX5_ST_SZ_DW(mcda_reg)];
 288        int i, j, dw_size = size >> 2;
 289        __be32 data_element;
 290        u32 *in;
 291
 292        in = kzalloc(in_size, GFP_KERNEL);
 293        if (!in)
 294                return -ENOMEM;
 295
 296        MLX5_SET(mcda_reg, in, update_handle, update_handle);
 297        MLX5_SET(mcda_reg, in, offset, offset);
 298        MLX5_SET(mcda_reg, in, size, size);
 299
 300        for (i = 0; i < dw_size; i++) {
 301                j = i * 4;
 302                data_element = htonl(*(u32 *)&data[j]);
 303                memcpy(MLX5_ADDR_OF(mcda_reg, in, data) + j, &data_element, 4);
 304        }
 305
 306        err = mlx5_core_access_reg(dev, in, in_size, out,
 307                                   sizeof(out), MLX5_REG_MCDA, 0, 1);
 308        kfree(in);
 309        return err;
 310}
 311
 312static int mlx5_reg_mcqi_query(struct mlx5_core_dev *dev,
 313                               u16 component_index,
 314                               u32 *max_component_size,
 315                               u8 *log_mcda_word_size,
 316                               u16 *mcda_max_write_size)
 317{
 318        u32 out[MLX5_ST_SZ_DW(mcqi_reg) + MLX5_ST_SZ_DW(mcqi_cap)];
 319        int offset = MLX5_ST_SZ_DW(mcqi_reg);
 320        u32 in[MLX5_ST_SZ_DW(mcqi_reg)];
 321        int err;
 322
 323        memset(in, 0, sizeof(in));
 324        memset(out, 0, sizeof(out));
 325
 326        MLX5_SET(mcqi_reg, in, component_index, component_index);
 327        MLX5_SET(mcqi_reg, in, data_size, MLX5_ST_SZ_BYTES(mcqi_cap));
 328
 329        err = mlx5_core_access_reg(dev, in, sizeof(in), out,
 330                                   sizeof(out), MLX5_REG_MCQI, 0, 0);
 331        if (err)
 332                goto out;
 333
 334        *max_component_size = MLX5_GET(mcqi_cap, out + offset, max_component_size);
 335        *log_mcda_word_size = MLX5_GET(mcqi_cap, out + offset, log_mcda_word_size);
 336        *mcda_max_write_size = MLX5_GET(mcqi_cap, out + offset, mcda_max_write_size);
 337
 338out:
 339        return err;
 340}
 341
 342struct mlx5_mlxfw_dev {
 343        struct mlxfw_dev mlxfw_dev;
 344        struct mlx5_core_dev *mlx5_core_dev;
 345};
 346
 347static int mlx5_component_query(struct mlxfw_dev *mlxfw_dev,
 348                                u16 component_index, u32 *p_max_size,
 349                                u8 *p_align_bits, u16 *p_max_write_size)
 350{
 351        struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
 352                container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
 353        struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
 354
 355        return mlx5_reg_mcqi_query(dev, component_index, p_max_size,
 356                                   p_align_bits, p_max_write_size);
 357}
 358
 359static int mlx5_fsm_lock(struct mlxfw_dev *mlxfw_dev, u32 *fwhandle)
 360{
 361        struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
 362                container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
 363        struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
 364        u8 control_state, error_code;
 365        int err;
 366
 367        *fwhandle = 0;
 368        err = mlx5_reg_mcc_query(dev, fwhandle, &error_code, &control_state);
 369        if (err)
 370                return err;
 371
 372        if (control_state != MLXFW_FSM_STATE_IDLE)
 373                return -EBUSY;
 374
 375        return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE,
 376                                0, *fwhandle, 0);
 377}
 378
 379static int mlx5_fsm_component_update(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
 380                                     u16 component_index, u32 component_size)
 381{
 382        struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
 383                container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
 384        struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
 385
 386        return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_UPDATE_COMPONENT,
 387                                component_index, fwhandle, component_size);
 388}
 389
 390static int mlx5_fsm_block_download(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
 391                                   u8 *data, u16 size, u32 offset)
 392{
 393        struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
 394                container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
 395        struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
 396
 397        return mlx5_reg_mcda_set(dev, fwhandle, offset, size, data);
 398}
 399
 400static int mlx5_fsm_component_verify(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
 401                                     u16 component_index)
 402{
 403        struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
 404                container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
 405        struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
 406
 407        return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_VERIFY_COMPONENT,
 408                                component_index, fwhandle, 0);
 409}
 410
 411static int mlx5_fsm_activate(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)
 412{
 413        struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
 414                container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
 415        struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
 416
 417        return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_ACTIVATE, 0,
 418                                fwhandle, 0);
 419}
 420
 421static int mlx5_fsm_query_state(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
 422                                enum mlxfw_fsm_state *fsm_state,
 423                                enum mlxfw_fsm_state_err *fsm_state_err)
 424{
 425        struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
 426                container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
 427        struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
 428        u8 control_state, error_code;
 429        int err;
 430
 431        err = mlx5_reg_mcc_query(dev, &fwhandle, &error_code, &control_state);
 432        if (err)
 433                return err;
 434
 435        *fsm_state = control_state;
 436        *fsm_state_err = min_t(enum mlxfw_fsm_state_err, error_code,
 437                               MLXFW_FSM_STATE_ERR_MAX);
 438        return 0;
 439}
 440
 441static void mlx5_fsm_cancel(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)
 442{
 443        struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
 444                container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
 445        struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
 446
 447        mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_CANCEL, 0, fwhandle, 0);
 448}
 449
 450static void mlx5_fsm_release(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)
 451{
 452        struct mlx5_mlxfw_dev *mlx5_mlxfw_dev =
 453                container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
 454        struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
 455
 456        mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE, 0,
 457                         fwhandle, 0);
 458}
 459
 460static const struct mlxfw_dev_ops mlx5_mlxfw_dev_ops = {
 461        .component_query        = mlx5_component_query,
 462        .fsm_lock               = mlx5_fsm_lock,
 463        .fsm_component_update   = mlx5_fsm_component_update,
 464        .fsm_block_download     = mlx5_fsm_block_download,
 465        .fsm_component_verify   = mlx5_fsm_component_verify,
 466        .fsm_activate           = mlx5_fsm_activate,
 467        .fsm_query_state        = mlx5_fsm_query_state,
 468        .fsm_cancel             = mlx5_fsm_cancel,
 469        .fsm_release            = mlx5_fsm_release
 470};
 471
 472int mlx5_firmware_flash(struct mlx5_core_dev *dev,
 473                        const struct firmware *firmware)
 474{
 475        struct mlx5_mlxfw_dev mlx5_mlxfw_dev = {
 476                .mlxfw_dev = {
 477                        .ops = &mlx5_mlxfw_dev_ops,
 478                        .psid = dev->board_id,
 479                        .psid_size = strlen(dev->board_id),
 480                },
 481                .mlx5_core_dev = dev
 482        };
 483
 484        if (!MLX5_CAP_GEN(dev, mcam_reg)  ||
 485            !MLX5_CAP_MCAM_REG(dev, mcqi) ||
 486            !MLX5_CAP_MCAM_REG(dev, mcc)  ||
 487            !MLX5_CAP_MCAM_REG(dev, mcda)) {
 488                pr_info("%s flashing isn't supported by the running FW\n", __func__);
 489                return -EOPNOTSUPP;
 490        }
 491
 492        return mlxfw_firmware_flash(&mlx5_mlxfw_dev.mlxfw_dev, firmware);
 493}
 494