File Index
Files and directories
Sign in
FILE

mlxfw_fsm.c

File preview with syntax highlighting.

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