brintos

brintos / linux-shallow public Read only

0
0
Text · 12.6 KiB · 46245e0 Raw
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