xref: /linux/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c (revision cdd38c5f1ce4398ec58fec95904b75824daab7b5)
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 
19 static 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 
mlxfw_fsm_state_err(struct mlxfw_dev * mlxfw_dev,struct netlink_ext_ack * extack,enum mlxfw_fsm_state_err err)38 static 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 
mlxfw_fsm_state_wait(struct mlxfw_dev * mlxfw_dev,u32 fwhandle,enum mlxfw_fsm_state fsm_state,struct netlink_ext_ack * extack)84 static 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;
94 retry:
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 
117 static int
mlxfw_fsm_reactivate_err(struct mlxfw_dev * mlxfw_dev,struct netlink_ext_ack * extack,u8 err)118 mlxfw_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 
mlxfw_fsm_reactivate(struct mlxfw_dev * mlxfw_dev,struct netlink_ext_ack * extack,bool * supported)166 static 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 
mlxfw_status_notify(struct mlxfw_dev * mlxfw_dev,const char * msg,const char * comp_name,u32 done_bytes,u32 total_bytes)195 static 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 
mlxfw_flash_component(struct mlxfw_dev * mlxfw_dev,u32 fwhandle,struct mlxfw_mfa2_component * comp,bool reactivate_supp,struct netlink_ext_ack * extack)207 static 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 
301 err_out:
302 	mlxfw_dev->ops->fsm_cancel(mlxfw_dev, fwhandle);
303 	return err;
304 }
305 
mlxfw_flash_components(struct mlxfw_dev * mlxfw_dev,u32 fwhandle,struct mlxfw_mfa2_file * mfa2_file,bool reactivate_supp,struct netlink_ext_ack * extack)306 static 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 
mlxfw_firmware_flash(struct mlxfw_dev * mlxfw_dev,const struct firmware * firmware,struct netlink_ext_ack * extack)347 int 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 
421 err_state_wait_activate_to_locked:
422 err_fsm_activate:
423 err_flash_components:
424 err_state_wait_reactivate_to_locked:
425 err_fsm_reactivate:
426 err_state_wait_idle_to_locked:
427 	mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);
428 err_fsm_lock:
429 	mlxfw_mfa2_file_fini(mfa2_file);
430 	return err;
431 }
432 EXPORT_SYMBOL(mlxfw_firmware_flash);
433 
434 MODULE_LICENSE("Dual BSD/GPL");
435 MODULE_AUTHOR("Yotam Gigi <yotamg@mellanox.com>");
436 MODULE_DESCRIPTION("Mellanox firmware flash lib");
437