linux/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/* Copyright (c) 2017-2019 Mellanox Technologies. All rights reserved */
   3
   4#define pr_fmt(fmt) "mlxfw: " fmt
   5
   6#include <linux/kernel.h>
   7#include <linux/module.h>
   8#include <linux/delay.h>
   9
  10#include "mlxfw.h"
  11#include "mlxfw_mfa2.h"
  12
  13#define MLXFW_FSM_STATE_WAIT_CYCLE_MS 200
  14#define MLXFW_FSM_STATE_WAIT_TIMEOUT_MS 30000
  15#define MLXFW_FSM_STATE_WAIT_ROUNDS \
  16        (MLXFW_FSM_STATE_WAIT_TIMEOUT_MS / MLXFW_FSM_STATE_WAIT_CYCLE_MS)
  17#define MLXFW_FSM_MAX_COMPONENT_SIZE (10 * (1 << 20))
  18
  19static const int mlxfw_fsm_state_errno[] = {
  20        [MLXFW_FSM_STATE_ERR_ERROR] = -EIO,
  21        [MLXFW_FSM_STATE_ERR_REJECTED_DIGEST_ERR] = -EBADMSG,
  22        [MLXFW_FSM_STATE_ERR_REJECTED_NOT_APPLICABLE] = -ENOENT,
  23        [MLXFW_FSM_STATE_ERR_REJECTED_UNKNOWN_KEY] = -ENOKEY,
  24        [MLXFW_FSM_STATE_ERR_REJECTED_AUTH_FAILED] = -EACCES,
  25        [MLXFW_FSM_STATE_ERR_REJECTED_UNSIGNED] = -EKEYREVOKED,
  26        [MLXFW_FSM_STATE_ERR_REJECTED_KEY_NOT_APPLICABLE] = -EKEYREJECTED,
  27        [MLXFW_FSM_STATE_ERR_REJECTED_BAD_FORMAT] = -ENOEXEC,
  28        [MLXFW_FSM_STATE_ERR_BLOCKED_PENDING_RESET] = -EBUSY,
  29        [MLXFW_FSM_STATE_ERR_MAX] = -EINVAL
  30};
  31
  32#define MLXFW_ERR_PRFX "Firmware flash failed: "
  33#define MLXFW_ERR_MSG(fwdev, extack, msg, err) do { \
  34        mlxfw_err(fwdev, "%s, err (%d)\n", MLXFW_ERR_PRFX msg, err); \
  35        NL_SET_ERR_MSG_MOD(extack, MLXFW_ERR_PRFX msg); \
  36} while (0)
  37
  38static int mlxfw_fsm_state_err(struct mlxfw_dev *mlxfw_dev,
  39                               struct netlink_ext_ack *extack,
  40                               enum mlxfw_fsm_state_err err)
  41{
  42        enum mlxfw_fsm_state_err fsm_state_err;
  43
  44        fsm_state_err = min_t(enum mlxfw_fsm_state_err, err,
  45                              MLXFW_FSM_STATE_ERR_MAX);
  46
  47        switch (fsm_state_err) {
  48        case MLXFW_FSM_STATE_ERR_ERROR:
  49                MLXFW_ERR_MSG(mlxfw_dev, extack, "general error", err);
  50                break;
  51        case MLXFW_FSM_STATE_ERR_REJECTED_DIGEST_ERR:
  52                MLXFW_ERR_MSG(mlxfw_dev, extack, "component hash mismatch", err);
  53                break;
  54        case MLXFW_FSM_STATE_ERR_REJECTED_NOT_APPLICABLE:
  55                MLXFW_ERR_MSG(mlxfw_dev, extack, "component not applicable", err);
  56                break;
  57        case MLXFW_FSM_STATE_ERR_REJECTED_UNKNOWN_KEY:
  58                MLXFW_ERR_MSG(mlxfw_dev, extack, "unknown key", err);
  59                break;
  60        case MLXFW_FSM_STATE_ERR_REJECTED_AUTH_FAILED:
  61                MLXFW_ERR_MSG(mlxfw_dev, extack, "authentication failed", err);
  62                break;
  63        case MLXFW_FSM_STATE_ERR_REJECTED_UNSIGNED:
  64                MLXFW_ERR_MSG(mlxfw_dev, extack, "component was not signed", err);
  65                break;
  66        case MLXFW_FSM_STATE_ERR_REJECTED_KEY_NOT_APPLICABLE:
  67                MLXFW_ERR_MSG(mlxfw_dev, extack, "key not applicable", err);
  68                break;
  69        case MLXFW_FSM_STATE_ERR_REJECTED_BAD_FORMAT:
  70                MLXFW_ERR_MSG(mlxfw_dev, extack, "bad format", err);
  71                break;
  72        case MLXFW_FSM_STATE_ERR_BLOCKED_PENDING_RESET:
  73                MLXFW_ERR_MSG(mlxfw_dev, extack, "pending reset", err);
  74                break;
  75        case MLXFW_FSM_STATE_ERR_OK:
  76        case MLXFW_FSM_STATE_ERR_MAX:
  77                MLXFW_ERR_MSG(mlxfw_dev, extack, "unknown error", err);
  78                break;
  79        }
  80
  81        return mlxfw_fsm_state_errno[fsm_state_err];
  82};
  83
  84static int mlxfw_fsm_state_wait(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
  85                                enum mlxfw_fsm_state fsm_state,
  86                                struct netlink_ext_ack *extack)
  87{
  88        enum mlxfw_fsm_state_err fsm_state_err;
  89        enum mlxfw_fsm_state curr_fsm_state;
  90        int times;
  91        int err;
  92
  93        times = MLXFW_FSM_STATE_WAIT_ROUNDS;
  94retry:
  95        err = mlxfw_dev->ops->fsm_query_state(mlxfw_dev, fwhandle,
  96                                              &curr_fsm_state, &fsm_state_err);
  97        if (err) {
  98                MLXFW_ERR_MSG(mlxfw_dev, extack, "FSM state query failed", err);
  99                return err;
 100        }
 101
 102        if (fsm_state_err != MLXFW_FSM_STATE_ERR_OK)
 103                return mlxfw_fsm_state_err(mlxfw_dev, extack, fsm_state_err);
 104
 105        if (curr_fsm_state != fsm_state) {
 106                if (--times == 0) {
 107                        MLXFW_ERR_MSG(mlxfw_dev, extack,
 108                                      "Timeout reached on FSM state change", -ETIMEDOUT);
 109                        return -ETIMEDOUT;
 110                }
 111                msleep(MLXFW_FSM_STATE_WAIT_CYCLE_MS);
 112                goto retry;
 113        }
 114        return 0;
 115}
 116
 117static int
 118mlxfw_fsm_reactivate_err(struct mlxfw_dev *mlxfw_dev,
 119                         struct netlink_ext_ack *extack, u8 err)
 120{
 121        enum mlxfw_fsm_reactivate_status status;
 122
 123#define MXFW_REACT_PRFX "Reactivate FSM: "
 124#define MLXFW_REACT_ERR(msg, err) \
 125        MLXFW_ERR_MSG(mlxfw_dev, extack, MXFW_REACT_PRFX msg, err)
 126
 127        status = min_t(enum mlxfw_fsm_reactivate_status, err,
 128                       MLXFW_FSM_REACTIVATE_STATUS_MAX);
 129
 130        switch (status) {
 131        case MLXFW_FSM_REACTIVATE_STATUS_BUSY:
 132                MLXFW_REACT_ERR("busy", err);
 133                break;
 134        case MLXFW_FSM_REACTIVATE_STATUS_PROHIBITED_FW_VER_ERR:
 135                MLXFW_REACT_ERR("prohibited fw ver", err);
 136                break;
 137        case MLXFW_FSM_REACTIVATE_STATUS_FIRST_PAGE_COPY_FAILED:
 138                MLXFW_REACT_ERR("first page copy failed", err);
 139                break;
 140        case MLXFW_FSM_REACTIVATE_STATUS_FIRST_PAGE_ERASE_FAILED:
 141                MLXFW_REACT_ERR("first page erase failed", err);
 142                break;
 143        case MLXFW_FSM_REACTIVATE_STATUS_FIRST_PAGE_RESTORE_FAILED:
 144                MLXFW_REACT_ERR("first page restore failed", err);
 145                break;
 146        case MLXFW_FSM_REACTIVATE_STATUS_CANDIDATE_FW_DEACTIVATION_FAILED:
 147                MLXFW_REACT_ERR("candidate fw deactivation failed", err);
 148                break;
 149        case MLXFW_FSM_REACTIVATE_STATUS_ERR_DEVICE_RESET_REQUIRED:
 150                MLXFW_REACT_ERR("device reset required", err);
 151                break;
 152        case MLXFW_FSM_REACTIVATE_STATUS_ERR_FW_PROGRAMMING_NEEDED:
 153                MLXFW_REACT_ERR("fw programming needed", err);
 154                break;
 155        case MLXFW_FSM_REACTIVATE_STATUS_FW_ALREADY_ACTIVATED:
 156                MLXFW_REACT_ERR("fw already activated", err);
 157                break;
 158        case MLXFW_FSM_REACTIVATE_STATUS_OK:
 159        case MLXFW_FSM_REACTIVATE_STATUS_MAX:
 160                MLXFW_REACT_ERR("unexpected error", err);
 161                break;
 162        }
 163        return -EREMOTEIO;
 164};
 165
 166static int mlxfw_fsm_reactivate(struct mlxfw_dev *mlxfw_dev,
 167                                struct netlink_ext_ack *extack,
 168                                bool *supported)
 169{
 170        u8 status;
 171        int err;
 172
 173        if (!mlxfw_dev->ops->fsm_reactivate)
 174                return 0;
 175
 176        err = mlxfw_dev->ops->fsm_reactivate(mlxfw_dev, &status);
 177        if (err == -EOPNOTSUPP) {
 178                *supported = false;
 179                return 0;
 180        }
 181
 182        if (err) {
 183                MLXFW_ERR_MSG(mlxfw_dev, extack,
 184                              "Could not reactivate firmware flash", err);
 185                return err;
 186        }
 187
 188        if (status == MLXFW_FSM_REACTIVATE_STATUS_OK ||
 189            status == MLXFW_FSM_REACTIVATE_STATUS_FW_ALREADY_ACTIVATED)
 190                return 0;
 191
 192        return mlxfw_fsm_reactivate_err(mlxfw_dev, extack, status);
 193}
 194
 195static void mlxfw_status_notify(struct mlxfw_dev *mlxfw_dev,
 196                                const char *msg, const char *comp_name,
 197                                u32 done_bytes, u32 total_bytes)
 198{
 199        devlink_flash_update_status_notify(mlxfw_dev->devlink, msg, comp_name,
 200                                           done_bytes, total_bytes);
 201}
 202
 203#define MLXFW_ALIGN_DOWN(x, align_bits) ((x) & ~((1 << (align_bits)) - 1))
 204#define MLXFW_ALIGN_UP(x, align_bits) \
 205                MLXFW_ALIGN_DOWN((x) + ((1 << (align_bits)) - 1), (align_bits))
 206
 207static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev,
 208                                 u32 fwhandle,
 209                                 struct mlxfw_mfa2_component *comp,
 210                                 bool reactivate_supp,
 211                                 struct netlink_ext_ack *extack)
 212{
 213        u16 comp_max_write_size;
 214        u8 comp_align_bits;
 215        u32 comp_max_size;
 216        char comp_name[8];
 217        u16 block_size;
 218        u8 *block_ptr;
 219        u32 offset;
 220        int err;
 221
 222        sprintf(comp_name, "%u", comp->index);
 223
 224        err = mlxfw_dev->ops->component_query(mlxfw_dev, comp->index,
 225                                              &comp_max_size, &comp_align_bits,
 226                                              &comp_max_write_size);
 227        if (err) {
 228                MLXFW_ERR_MSG(mlxfw_dev, extack, "FSM component query failed", err);
 229                return err;
 230        }
 231
 232        comp_max_size = min_t(u32, comp_max_size, MLXFW_FSM_MAX_COMPONENT_SIZE);
 233        if (comp->data_size > comp_max_size) {
 234                MLXFW_ERR_MSG(mlxfw_dev, extack,
 235                              "Component size is bigger than limit", -EINVAL);
 236                return -EINVAL;
 237        }
 238
 239        comp_max_write_size = MLXFW_ALIGN_DOWN(comp_max_write_size,
 240                                               comp_align_bits);
 241
 242        mlxfw_dbg(mlxfw_dev, "Component update\n");
 243        mlxfw_status_notify(mlxfw_dev, "Updating component", comp_name, 0, 0);
 244        err = mlxfw_dev->ops->fsm_component_update(mlxfw_dev, fwhandle,
 245                                                   comp->index,
 246                                                   comp->data_size);
 247        if (err) {
 248                if (!reactivate_supp)
 249                        MLXFW_ERR_MSG(mlxfw_dev, extack,
 250                                      "FSM component update failed, FW reactivate is not supported",
 251                                      err);
 252                else
 253                        MLXFW_ERR_MSG(mlxfw_dev, extack,
 254                                      "FSM component update failed", err);
 255                return err;
 256        }
 257
 258        err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
 259                                   MLXFW_FSM_STATE_DOWNLOAD, extack);
 260        if (err)
 261                goto err_out;
 262
 263        mlxfw_dbg(mlxfw_dev, "Component download\n");
 264        mlxfw_status_notify(mlxfw_dev, "Downloading component",
 265                            comp_name, 0, comp->data_size);
 266        for (offset = 0;
 267             offset < MLXFW_ALIGN_UP(comp->data_size, comp_align_bits);
 268             offset += comp_max_write_size) {
 269                block_ptr = comp->data + offset;
 270                block_size = (u16) min_t(u32, comp->data_size - offset,
 271                                         comp_max_write_size);
 272                err = mlxfw_dev->ops->fsm_block_download(mlxfw_dev, fwhandle,
 273                                                         block_ptr, block_size,
 274                                                         offset);
 275                if (err) {
 276                        MLXFW_ERR_MSG(mlxfw_dev, extack,
 277                                      "Component download failed", err);
 278                        goto err_out;
 279                }
 280                mlxfw_status_notify(mlxfw_dev, "Downloading component",
 281                                    comp_name, offset + block_size,
 282                                    comp->data_size);
 283        }
 284
 285        mlxfw_dbg(mlxfw_dev, "Component verify\n");
 286        mlxfw_status_notify(mlxfw_dev, "Verifying component", comp_name, 0, 0);
 287        err = mlxfw_dev->ops->fsm_component_verify(mlxfw_dev, fwhandle,
 288                                                   comp->index);
 289        if (err) {
 290                MLXFW_ERR_MSG(mlxfw_dev, extack,
 291                              "FSM component verify failed", err);
 292                goto err_out;
 293        }
 294
 295        err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
 296                                   MLXFW_FSM_STATE_LOCKED, extack);
 297        if (err)
 298                goto err_out;
 299        return 0;
 300
 301err_out:
 302        mlxfw_dev->ops->fsm_cancel(mlxfw_dev, fwhandle);
 303        return err;
 304}
 305
 306static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
 307                                  struct mlxfw_mfa2_file *mfa2_file,
 308                                  bool reactivate_supp,
 309                                  struct netlink_ext_ack *extack)
 310{
 311        u32 component_count;
 312        int err;
 313        int i;
 314
 315        err = mlxfw_mfa2_file_component_count(mfa2_file, mlxfw_dev->psid,
 316                                              mlxfw_dev->psid_size,
 317                                              &component_count);
 318        if (err) {
 319                MLXFW_ERR_MSG(mlxfw_dev, extack,
 320                              "Could not find device PSID in MFA2 file", err);
 321                return err;
 322        }
 323
 324        for (i = 0; i < component_count; i++) {
 325                struct mlxfw_mfa2_component *comp;
 326
 327                comp = mlxfw_mfa2_file_component_get(mfa2_file, mlxfw_dev->psid,
 328                                                     mlxfw_dev->psid_size, i);
 329                if (IS_ERR(comp)) {
 330                        err = PTR_ERR(comp);
 331                        MLXFW_ERR_MSG(mlxfw_dev, extack,
 332                                      "Failed to get MFA2 component", err);
 333                        return err;
 334                }
 335
 336                mlxfw_info(mlxfw_dev, "Flashing component type %d\n",
 337                           comp->index);
 338                err = mlxfw_flash_component(mlxfw_dev, fwhandle, comp,
 339                                            reactivate_supp, extack);
 340                mlxfw_mfa2_file_component_put(comp);
 341                if (err)
 342                        return err;
 343        }
 344        return 0;
 345}
 346
 347int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev,
 348                         const struct firmware *firmware,
 349                         struct netlink_ext_ack *extack)
 350{
 351        struct mlxfw_mfa2_file *mfa2_file;
 352        bool reactivate_supp = true;
 353        u32 fwhandle;
 354        int err;
 355
 356        if (!mlxfw_mfa2_check(firmware)) {
 357                MLXFW_ERR_MSG(mlxfw_dev, extack,
 358                              "Firmware file is not MFA2", -EINVAL);
 359                return -EINVAL;
 360        }
 361
 362        mfa2_file = mlxfw_mfa2_file_init(firmware);
 363        if (IS_ERR(mfa2_file)) {
 364                err = PTR_ERR(mfa2_file);
 365                MLXFW_ERR_MSG(mlxfw_dev, extack,
 366                              "Failed to initialize MFA2 firmware file", err);
 367                return err;
 368        }
 369
 370        mlxfw_info(mlxfw_dev, "Initialize firmware flash process\n");
 371        devlink_flash_update_begin_notify(mlxfw_dev->devlink);
 372        mlxfw_status_notify(mlxfw_dev, "Initializing firmware flash process",
 373                            NULL, 0, 0);
 374        err = mlxfw_dev->ops->fsm_lock(mlxfw_dev, &fwhandle);
 375        if (err) {
 376                MLXFW_ERR_MSG(mlxfw_dev, extack,
 377                              "Could not lock the firmware FSM", err);
 378                goto err_fsm_lock;
 379        }
 380
 381        err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
 382                                   MLXFW_FSM_STATE_LOCKED, extack);
 383        if (err)
 384                goto err_state_wait_idle_to_locked;
 385
 386        err = mlxfw_fsm_reactivate(mlxfw_dev, extack, &reactivate_supp);
 387        if (err)
 388                goto err_fsm_reactivate;
 389
 390        err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
 391                                   MLXFW_FSM_STATE_LOCKED, extack);
 392        if (err)
 393                goto err_state_wait_reactivate_to_locked;
 394
 395        err = mlxfw_flash_components(mlxfw_dev, fwhandle, mfa2_file,
 396                                     reactivate_supp, extack);
 397        if (err)
 398                goto err_flash_components;
 399
 400        mlxfw_dbg(mlxfw_dev, "Activate image\n");
 401        mlxfw_status_notify(mlxfw_dev, "Activating image", NULL, 0, 0);
 402        err = mlxfw_dev->ops->fsm_activate(mlxfw_dev, fwhandle);
 403        if (err) {
 404                MLXFW_ERR_MSG(mlxfw_dev, extack,
 405                              "Could not activate the downloaded image", err);
 406                goto err_fsm_activate;
 407        }
 408
 409        err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
 410                                   MLXFW_FSM_STATE_LOCKED, extack);
 411        if (err)
 412                goto err_state_wait_activate_to_locked;
 413
 414        mlxfw_dbg(mlxfw_dev, "Handle release\n");
 415        mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);
 416
 417        mlxfw_info(mlxfw_dev, "Firmware flash done\n");
 418        mlxfw_status_notify(mlxfw_dev, "Firmware flash done", NULL, 0, 0);
 419        mlxfw_mfa2_file_fini(mfa2_file);
 420        devlink_flash_update_end_notify(mlxfw_dev->devlink);
 421        return 0;
 422
 423err_state_wait_activate_to_locked:
 424err_fsm_activate:
 425err_flash_components:
 426err_state_wait_reactivate_to_locked:
 427err_fsm_reactivate:
 428err_state_wait_idle_to_locked:
 429        mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);
 430err_fsm_lock:
 431        mlxfw_mfa2_file_fini(mfa2_file);
 432        devlink_flash_update_end_notify(mlxfw_dev->devlink);
 433        return err;
 434}
 435EXPORT_SYMBOL(mlxfw_firmware_flash);
 436
 437MODULE_LICENSE("Dual BSD/GPL");
 438MODULE_AUTHOR("Yotam Gigi <yotamg@mellanox.com>");
 439MODULE_DESCRIPTION("Mellanox firmware flash lib");
 440