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 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] = -EINVAL
30};
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 int
118mlxfw_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		else
253			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