xref: /openbmc/linux/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c (revision 060f35a317ef09101b128f399dce7ed13d019461)
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 
18 static 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 
mlxfw_fsm_state_err(struct mlxfw_dev * mlxfw_dev,struct netlink_ext_ack * extack,enum mlxfw_fsm_state_err err)37 static 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 
mlxfw_fsm_state_wait(struct mlxfw_dev * mlxfw_dev,u32 fwhandle,enum mlxfw_fsm_state fsm_state,struct netlink_ext_ack * extack)83 static 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;
93 retry:
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 
116 static int
mlxfw_fsm_reactivate_err(struct mlxfw_dev * mlxfw_dev,struct netlink_ext_ack * extack,u8 err)117 mlxfw_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 
mlxfw_fsm_reactivate(struct mlxfw_dev * mlxfw_dev,struct netlink_ext_ack * extack,bool * supported)165 static 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 
mlxfw_status_notify(struct mlxfw_dev * mlxfw_dev,const char * msg,const char * comp_name,u32 done_bytes,u32 total_bytes)194 static 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 
mlxfw_flash_component(struct mlxfw_dev * mlxfw_dev,u32 fwhandle,struct mlxfw_mfa2_component * comp,bool reactivate_supp,struct netlink_ext_ack * extack)206 static 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 
299 err_out:
300 	mlxfw_dev->ops->fsm_cancel(mlxfw_dev, fwhandle);
301 	return err;
302 }
303 
mlxfw_flash_components(struct mlxfw_dev * mlxfw_dev,u32 fwhandle,struct mlxfw_mfa2_file * mfa2_file,bool reactivate_supp,struct netlink_ext_ack * extack)304 static 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 
mlxfw_firmware_flash(struct mlxfw_dev * mlxfw_dev,const struct firmware * firmware,struct netlink_ext_ack * extack)345 int 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 
419 err_state_wait_activate_to_locked:
420 err_fsm_activate:
421 err_flash_components:
422 err_state_wait_reactivate_to_locked:
423 err_fsm_reactivate:
424 err_state_wait_idle_to_locked:
425 	mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);
426 err_fsm_lock:
427 	mlxfw_mfa2_file_fini(mfa2_file);
428 	return err;
429 }
430 EXPORT_SYMBOL(mlxfw_firmware_flash);
431 
432 MODULE_LICENSE("Dual BSD/GPL");
433 MODULE_AUTHOR("Yotam Gigi <yotamg@mellanox.com>");
434 MODULE_DESCRIPTION("Mellanox firmware flash lib");
435