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 char * const mlxfw_fsm_state_err_str[] = {
  20        [MLXFW_FSM_STATE_ERR_ERROR] =
  21                "general error",
  22        [MLXFW_FSM_STATE_ERR_REJECTED_DIGEST_ERR] =
  23                "component hash mismatch",
  24        [MLXFW_FSM_STATE_ERR_REJECTED_NOT_APPLICABLE] =
  25                "component not applicable",
  26        [MLXFW_FSM_STATE_ERR_REJECTED_UNKNOWN_KEY] =
  27                "unknown key",
  28        [MLXFW_FSM_STATE_ERR_REJECTED_AUTH_FAILED] =
  29                "authentication failed",
  30        [MLXFW_FSM_STATE_ERR_REJECTED_UNSIGNED] =
  31                "component was not signed",
  32        [MLXFW_FSM_STATE_ERR_REJECTED_KEY_NOT_APPLICABLE] =
  33                "key not applicable",
  34        [MLXFW_FSM_STATE_ERR_REJECTED_BAD_FORMAT] =
  35                "bad format",
  36        [MLXFW_FSM_STATE_ERR_BLOCKED_PENDING_RESET] =
  37                "pending reset",
  38        [MLXFW_FSM_STATE_ERR_MAX] =
  39                "unknown error"
  40};
  41
  42static void mlxfw_status_notify(struct mlxfw_dev *mlxfw_dev,
  43                                const char *msg, const char *comp_name,
  44                                u32 done_bytes, u32 total_bytes)
  45{
  46        if (!mlxfw_dev->ops->status_notify)
  47                return;
  48        mlxfw_dev->ops->status_notify(mlxfw_dev, msg, comp_name,
  49                                      done_bytes, total_bytes);
  50}
  51
  52static int mlxfw_fsm_state_wait(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
  53                                enum mlxfw_fsm_state fsm_state,
  54                                struct netlink_ext_ack *extack)
  55{
  56        enum mlxfw_fsm_state_err fsm_state_err;
  57        enum mlxfw_fsm_state curr_fsm_state;
  58        int times;
  59        int err;
  60
  61        times = MLXFW_FSM_STATE_WAIT_ROUNDS;
  62retry:
  63        err = mlxfw_dev->ops->fsm_query_state(mlxfw_dev, fwhandle,
  64                                              &curr_fsm_state, &fsm_state_err);
  65        if (err)
  66                return err;
  67
  68        if (fsm_state_err != MLXFW_FSM_STATE_ERR_OK) {
  69                fsm_state_err = min_t(enum mlxfw_fsm_state_err,
  70                                      fsm_state_err, MLXFW_FSM_STATE_ERR_MAX);
  71                pr_err("Firmware flash failed: %s\n",
  72                       mlxfw_fsm_state_err_str[fsm_state_err]);
  73                NL_SET_ERR_MSG_MOD(extack, "Firmware flash failed");
  74                return -EINVAL;
  75        }
  76        if (curr_fsm_state != fsm_state) {
  77                if (--times == 0) {
  78                        pr_err("Timeout reached on FSM state change");
  79                        NL_SET_ERR_MSG_MOD(extack, "Timeout reached on FSM state change");
  80                        return -ETIMEDOUT;
  81                }
  82                msleep(MLXFW_FSM_STATE_WAIT_CYCLE_MS);
  83                goto retry;
  84        }
  85        return 0;
  86}
  87
  88#define MLXFW_ALIGN_DOWN(x, align_bits) ((x) & ~((1 << (align_bits)) - 1))
  89#define MLXFW_ALIGN_UP(x, align_bits) \
  90                MLXFW_ALIGN_DOWN((x) + ((1 << (align_bits)) - 1), (align_bits))
  91
  92static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev,
  93                                 u32 fwhandle,
  94                                 struct mlxfw_mfa2_component *comp,
  95                                 struct netlink_ext_ack *extack)
  96{
  97        u16 comp_max_write_size;
  98        u8 comp_align_bits;
  99        u32 comp_max_size;
 100        char comp_name[8];
 101        u16 block_size;
 102        u8 *block_ptr;
 103        u32 offset;
 104        int err;
 105
 106        sprintf(comp_name, "%u", comp->index);
 107
 108        err = mlxfw_dev->ops->component_query(mlxfw_dev, comp->index,
 109                                              &comp_max_size, &comp_align_bits,
 110                                              &comp_max_write_size);
 111        if (err)
 112                return err;
 113
 114        comp_max_size = min_t(u32, comp_max_size, MLXFW_FSM_MAX_COMPONENT_SIZE);
 115        if (comp->data_size > comp_max_size) {
 116                pr_err("Component %d is of size %d which is bigger than limit %d\n",
 117                       comp->index, comp->data_size, comp_max_size);
 118                NL_SET_ERR_MSG_MOD(extack, "Component is bigger than limit");
 119                return -EINVAL;
 120        }
 121
 122        comp_max_write_size = MLXFW_ALIGN_DOWN(comp_max_write_size,
 123                                               comp_align_bits);
 124
 125        pr_debug("Component update\n");
 126        mlxfw_status_notify(mlxfw_dev, "Updating component", comp_name, 0, 0);
 127        err = mlxfw_dev->ops->fsm_component_update(mlxfw_dev, fwhandle,
 128                                                   comp->index,
 129                                                   comp->data_size);
 130        if (err)
 131                return err;
 132
 133        err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
 134                                   MLXFW_FSM_STATE_DOWNLOAD, extack);
 135        if (err)
 136                goto err_out;
 137
 138        pr_debug("Component download\n");
 139        mlxfw_status_notify(mlxfw_dev, "Downloading component",
 140                            comp_name, 0, comp->data_size);
 141        for (offset = 0;
 142             offset < MLXFW_ALIGN_UP(comp->data_size, comp_align_bits);
 143             offset += comp_max_write_size) {
 144                block_ptr = comp->data + offset;
 145                block_size = (u16) min_t(u32, comp->data_size - offset,
 146                                         comp_max_write_size);
 147                err = mlxfw_dev->ops->fsm_block_download(mlxfw_dev, fwhandle,
 148                                                         block_ptr, block_size,
 149                                                         offset);
 150                if (err)
 151                        goto err_out;
 152                mlxfw_status_notify(mlxfw_dev, "Downloading component",
 153                                    comp_name, offset + block_size,
 154                                    comp->data_size);
 155        }
 156
 157        pr_debug("Component verify\n");
 158        mlxfw_status_notify(mlxfw_dev, "Verifying component", comp_name, 0, 0);
 159        err = mlxfw_dev->ops->fsm_component_verify(mlxfw_dev, fwhandle,
 160                                                   comp->index);
 161        if (err)
 162                goto err_out;
 163
 164        err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
 165                                   MLXFW_FSM_STATE_LOCKED, extack);
 166        if (err)
 167                goto err_out;
 168        return 0;
 169
 170err_out:
 171        mlxfw_dev->ops->fsm_cancel(mlxfw_dev, fwhandle);
 172        return err;
 173}
 174
 175static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
 176                                  struct mlxfw_mfa2_file *mfa2_file,
 177                                  struct netlink_ext_ack *extack)
 178{
 179        u32 component_count;
 180        int err;
 181        int i;
 182
 183        err = mlxfw_mfa2_file_component_count(mfa2_file, mlxfw_dev->psid,
 184                                              mlxfw_dev->psid_size,
 185                                              &component_count);
 186        if (err) {
 187                pr_err("Could not find device PSID in MFA2 file\n");
 188                NL_SET_ERR_MSG_MOD(extack, "Could not find device PSID in MFA2 file");
 189                return err;
 190        }
 191
 192        for (i = 0; i < component_count; i++) {
 193                struct mlxfw_mfa2_component *comp;
 194
 195                comp = mlxfw_mfa2_file_component_get(mfa2_file, mlxfw_dev->psid,
 196                                                     mlxfw_dev->psid_size, i);
 197                if (IS_ERR(comp))
 198                        return PTR_ERR(comp);
 199
 200                pr_info("Flashing component type %d\n", comp->index);
 201                err = mlxfw_flash_component(mlxfw_dev, fwhandle, comp, extack);
 202                mlxfw_mfa2_file_component_put(comp);
 203                if (err)
 204                        return err;
 205        }
 206        return 0;
 207}
 208
 209int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev,
 210                         const struct firmware *firmware,
 211                         struct netlink_ext_ack *extack)
 212{
 213        struct mlxfw_mfa2_file *mfa2_file;
 214        u32 fwhandle;
 215        int err;
 216
 217        if (!mlxfw_mfa2_check(firmware)) {
 218                pr_err("Firmware file is not MFA2\n");
 219                NL_SET_ERR_MSG_MOD(extack, "Firmware file is not MFA2");
 220                return -EINVAL;
 221        }
 222
 223        mfa2_file = mlxfw_mfa2_file_init(firmware);
 224        if (IS_ERR(mfa2_file))
 225                return PTR_ERR(mfa2_file);
 226
 227        pr_info("Initialize firmware flash process\n");
 228        mlxfw_status_notify(mlxfw_dev, "Initializing firmware flash process",
 229                            NULL, 0, 0);
 230        err = mlxfw_dev->ops->fsm_lock(mlxfw_dev, &fwhandle);
 231        if (err) {
 232                pr_err("Could not lock the firmware FSM\n");
 233                NL_SET_ERR_MSG_MOD(extack, "Could not lock the firmware FSM");
 234                goto err_fsm_lock;
 235        }
 236
 237        err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
 238                                   MLXFW_FSM_STATE_LOCKED, extack);
 239        if (err)
 240                goto err_state_wait_idle_to_locked;
 241
 242        err = mlxfw_flash_components(mlxfw_dev, fwhandle, mfa2_file, extack);
 243        if (err)
 244                goto err_flash_components;
 245
 246        pr_debug("Activate image\n");
 247        mlxfw_status_notify(mlxfw_dev, "Activating image", NULL, 0, 0);
 248        err = mlxfw_dev->ops->fsm_activate(mlxfw_dev, fwhandle);
 249        if (err) {
 250                pr_err("Could not activate the downloaded image\n");
 251                NL_SET_ERR_MSG_MOD(extack, "Could not activate the downloaded image");
 252                goto err_fsm_activate;
 253        }
 254
 255        err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
 256                                   MLXFW_FSM_STATE_LOCKED, extack);
 257        if (err)
 258                goto err_state_wait_activate_to_locked;
 259
 260        pr_debug("Handle release\n");
 261        mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);
 262
 263        pr_info("Firmware flash done.\n");
 264        mlxfw_status_notify(mlxfw_dev, "Firmware flash done", NULL, 0, 0);
 265        mlxfw_mfa2_file_fini(mfa2_file);
 266        return 0;
 267
 268err_state_wait_activate_to_locked:
 269err_fsm_activate:
 270err_flash_components:
 271err_state_wait_idle_to_locked:
 272        mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);
 273err_fsm_lock:
 274        mlxfw_mfa2_file_fini(mfa2_file);
 275        return err;
 276}
 277EXPORT_SYMBOL(mlxfw_firmware_flash);
 278
 279MODULE_LICENSE("Dual BSD/GPL");
 280MODULE_AUTHOR("Yotam Gigi <yotamg@mellanox.com>");
 281MODULE_DESCRIPTION("Mellanox firmware flash lib");
 282