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