437 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/* Copyright (c) 2017-2019 Mellanox Technologies. All rights reserved */3 4#define pr_fmt(fmt) "mlxfw: " fmt5 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 20014#define MLXFW_FSM_STATE_WAIT_TIMEOUT_MS 3000015#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] = -EINVAL30};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 int118mlxfw_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 else253 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 mlxfw_status_notify(mlxfw_dev, "Initializing firmware flash process",372 NULL, 0, 0);373 err = mlxfw_dev->ops->fsm_lock(mlxfw_dev, &fwhandle);374 if (err) {375 MLXFW_ERR_MSG(mlxfw_dev, extack,376 "Could not lock the firmware FSM", err);377 goto err_fsm_lock;378 }379 380 err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,381 MLXFW_FSM_STATE_LOCKED, extack);382 if (err)383 goto err_state_wait_idle_to_locked;384 385 err = mlxfw_fsm_reactivate(mlxfw_dev, extack, &reactivate_supp);386 if (err)387 goto err_fsm_reactivate;388 389 err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,390 MLXFW_FSM_STATE_LOCKED, extack);391 if (err)392 goto err_state_wait_reactivate_to_locked;393 394 err = mlxfw_flash_components(mlxfw_dev, fwhandle, mfa2_file,395 reactivate_supp, extack);396 if (err)397 goto err_flash_components;398 399 mlxfw_dbg(mlxfw_dev, "Activate image\n");400 mlxfw_status_notify(mlxfw_dev, "Activating image", NULL, 0, 0);401 err = mlxfw_dev->ops->fsm_activate(mlxfw_dev, fwhandle);402 if (err) {403 MLXFW_ERR_MSG(mlxfw_dev, extack,404 "Could not activate the downloaded image", err);405 goto err_fsm_activate;406 }407 408 err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,409 MLXFW_FSM_STATE_LOCKED, extack);410 if (err)411 goto err_state_wait_activate_to_locked;412 413 mlxfw_dbg(mlxfw_dev, "Handle release\n");414 mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);415 416 mlxfw_info(mlxfw_dev, "Firmware flash done\n");417 mlxfw_status_notify(mlxfw_dev, "Firmware flash done", NULL, 0, 0);418 mlxfw_mfa2_file_fini(mfa2_file);419 return 0;420 421err_state_wait_activate_to_locked:422err_fsm_activate:423err_flash_components:424err_state_wait_reactivate_to_locked:425err_fsm_reactivate:426err_state_wait_idle_to_locked:427 mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);428err_fsm_lock:429 mlxfw_mfa2_file_fini(mfa2_file);430 return err;431}432EXPORT_SYMBOL(mlxfw_firmware_flash);433 434MODULE_LICENSE("Dual BSD/GPL");435MODULE_AUTHOR("Yotam Gigi <yotamg@mellanox.com>");436MODULE_DESCRIPTION("Mellanox firmware flash lib");437