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