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 int mlxfw_fsm_state_wait(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
  43                                enum mlxfw_fsm_state fsm_state)
  44{
  45        enum mlxfw_fsm_state_err fsm_state_err;
  46        enum mlxfw_fsm_state curr_fsm_state;
  47        int times;
  48        int err;
  49
  50        times = MLXFW_FSM_STATE_WAIT_ROUNDS;
  51retry:
  52        err = mlxfw_dev->ops->fsm_query_state(mlxfw_dev, fwhandle,
  53                                              &curr_fsm_state, &fsm_state_err);
  54        if (err)
  55                return err;
  56
  57        if (fsm_state_err != MLXFW_FSM_STATE_ERR_OK) {
  58                pr_err("Firmware flash failed: %s\n",
  59                       mlxfw_fsm_state_err_str[fsm_state_err]);
  60                return -EINVAL;
  61        }
  62        if (curr_fsm_state != fsm_state) {
  63                if (--times == 0) {
  64                        pr_err("Timeout reached on FSM state change");
  65                        return -ETIMEDOUT;
  66                }
  67                msleep(MLXFW_FSM_STATE_WAIT_CYCLE_MS);
  68                goto retry;
  69        }
  70        return 0;
  71}
  72
  73#define MLXFW_ALIGN_DOWN(x, align_bits) ((x) & ~((1 << (align_bits)) - 1))
  74#define MLXFW_ALIGN_UP(x, align_bits) \
  75                MLXFW_ALIGN_DOWN((x) + ((1 << (align_bits)) - 1), (align_bits))
  76
  77static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev,
  78                                 u32 fwhandle,
  79                                 struct mlxfw_mfa2_component *comp)
  80{
  81        u16 comp_max_write_size;
  82        u8 comp_align_bits;
  83        u32 comp_max_size;
  84        u16 block_size;
  85        u8 *block_ptr;
  86        u32 offset;
  87        int err;
  88
  89        err = mlxfw_dev->ops->component_query(mlxfw_dev, comp->index,
  90                                              &comp_max_size, &comp_align_bits,
  91                                              &comp_max_write_size);
  92        if (err)
  93                return err;
  94
  95        comp_max_size = min_t(u32, comp_max_size, MLXFW_FSM_MAX_COMPONENT_SIZE);
  96        if (comp->data_size > comp_max_size) {
  97                pr_err("Component %d is of size %d which is bigger than limit %d\n",
  98                       comp->index, comp->data_size, comp_max_size);
  99                return -EINVAL;
 100        }
 101
 102        comp_max_write_size = MLXFW_ALIGN_DOWN(comp_max_write_size,
 103                                               comp_align_bits);
 104
 105        pr_debug("Component update\n");
 106        err = mlxfw_dev->ops->fsm_component_update(mlxfw_dev, fwhandle,
 107                                                   comp->index,
 108                                                   comp->data_size);
 109        if (err)
 110                return err;
 111
 112        err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
 113                                   MLXFW_FSM_STATE_DOWNLOAD);
 114        if (err)
 115                goto err_out;
 116
 117        pr_debug("Component download\n");
 118        for (offset = 0;
 119             offset < MLXFW_ALIGN_UP(comp->data_size, comp_align_bits);
 120             offset += comp_max_write_size) {
 121                block_ptr = comp->data + offset;
 122                block_size = (u16) min_t(u32, comp->data_size - offset,
 123                                         comp_max_write_size);
 124                err = mlxfw_dev->ops->fsm_block_download(mlxfw_dev, fwhandle,
 125                                                         block_ptr, block_size,
 126                                                         offset);
 127                if (err)
 128                        goto err_out;
 129        }
 130
 131        pr_debug("Component verify\n");
 132        err = mlxfw_dev->ops->fsm_component_verify(mlxfw_dev, fwhandle,
 133                                                   comp->index);
 134        if (err)
 135                goto err_out;
 136
 137        err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, MLXFW_FSM_STATE_LOCKED);
 138        if (err)
 139                goto err_out;
 140        return 0;
 141
 142err_out:
 143        mlxfw_dev->ops->fsm_cancel(mlxfw_dev, fwhandle);
 144        return err;
 145}
 146
 147static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
 148                                  struct mlxfw_mfa2_file *mfa2_file)
 149{
 150        u32 component_count;
 151        int err;
 152        int i;
 153
 154        err = mlxfw_mfa2_file_component_count(mfa2_file, mlxfw_dev->psid,
 155                                              mlxfw_dev->psid_size,
 156                                              &component_count);
 157        if (err) {
 158                pr_err("Could not find device PSID in MFA2 file\n");
 159                return err;
 160        }
 161
 162        for (i = 0; i < component_count; i++) {
 163                struct mlxfw_mfa2_component *comp;
 164
 165                comp = mlxfw_mfa2_file_component_get(mfa2_file, mlxfw_dev->psid,
 166                                                     mlxfw_dev->psid_size, i);
 167                if (IS_ERR(comp))
 168                        return PTR_ERR(comp);
 169
 170                pr_info("Flashing component type %d\n", comp->index);
 171                err = mlxfw_flash_component(mlxfw_dev, fwhandle, comp);
 172                mlxfw_mfa2_file_component_put(comp);
 173                if (err)
 174                        return err;
 175        }
 176        return 0;
 177}
 178
 179int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev,
 180                         const struct firmware *firmware)
 181{
 182        struct mlxfw_mfa2_file *mfa2_file;
 183        u32 fwhandle;
 184        int err;
 185
 186        if (!mlxfw_mfa2_check(firmware)) {
 187                pr_err("Firmware file is not MFA2\n");
 188                return -EINVAL;
 189        }
 190
 191        mfa2_file = mlxfw_mfa2_file_init(firmware);
 192        if (IS_ERR(mfa2_file))
 193                return PTR_ERR(mfa2_file);
 194
 195        pr_info("Initialize firmware flash process\n");
 196        err = mlxfw_dev->ops->fsm_lock(mlxfw_dev, &fwhandle);
 197        if (err) {
 198                pr_err("Could not lock the firmware FSM\n");
 199                goto err_fsm_lock;
 200        }
 201
 202        err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
 203                                   MLXFW_FSM_STATE_LOCKED);
 204        if (err)
 205                goto err_state_wait_idle_to_locked;
 206
 207        err = mlxfw_flash_components(mlxfw_dev, fwhandle, mfa2_file);
 208        if (err)
 209                goto err_flash_components;
 210
 211        pr_debug("Activate image\n");
 212        err = mlxfw_dev->ops->fsm_activate(mlxfw_dev, fwhandle);
 213        if (err) {
 214                pr_err("Could not activate the downloaded image\n");
 215                goto err_fsm_activate;
 216        }
 217
 218        err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, MLXFW_FSM_STATE_LOCKED);
 219        if (err)
 220                goto err_state_wait_activate_to_locked;
 221
 222        pr_debug("Handle release\n");
 223        mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);
 224
 225        pr_info("Firmware flash done.\n");
 226        mlxfw_mfa2_file_fini(mfa2_file);
 227        return 0;
 228
 229err_state_wait_activate_to_locked:
 230err_fsm_activate:
 231err_flash_components:
 232err_state_wait_idle_to_locked:
 233        mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);
 234err_fsm_lock:
 235        mlxfw_mfa2_file_fini(mfa2_file);
 236        return err;
 237}
 238EXPORT_SYMBOL(mlxfw_firmware_flash);
 239
 240MODULE_LICENSE("Dual BSD/GPL");
 241MODULE_AUTHOR("Yotam Gigi <yotamg@mellanox.com>");
 242MODULE_DESCRIPTION("Mellanox firmware flash lib");
 243