Merge tag 'samsung-soc-5.10' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk...
[linux-2.6-microblaze.git] / drivers / net / ethernet / mellanox / mlxfw / mlxfw_fsm.c
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
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
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
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
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
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
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
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
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         devlink_flash_update_begin_notify(mlxfw_dev->devlink);
372         mlxfw_status_notify(mlxfw_dev, "Initializing firmware flash process",
373                             NULL, 0, 0);
374         err = mlxfw_dev->ops->fsm_lock(mlxfw_dev, &fwhandle);
375         if (err) {
376                 MLXFW_ERR_MSG(mlxfw_dev, extack,
377                               "Could not lock the firmware FSM", err);
378                 goto err_fsm_lock;
379         }
380
381         err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
382                                    MLXFW_FSM_STATE_LOCKED, extack);
383         if (err)
384                 goto err_state_wait_idle_to_locked;
385
386         err = mlxfw_fsm_reactivate(mlxfw_dev, extack, &reactivate_supp);
387         if (err)
388                 goto err_fsm_reactivate;
389
390         err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
391                                    MLXFW_FSM_STATE_LOCKED, extack);
392         if (err)
393                 goto err_state_wait_reactivate_to_locked;
394
395         err = mlxfw_flash_components(mlxfw_dev, fwhandle, mfa2_file,
396                                      reactivate_supp, extack);
397         if (err)
398                 goto err_flash_components;
399
400         mlxfw_dbg(mlxfw_dev, "Activate image\n");
401         mlxfw_status_notify(mlxfw_dev, "Activating image", NULL, 0, 0);
402         err = mlxfw_dev->ops->fsm_activate(mlxfw_dev, fwhandle);
403         if (err) {
404                 MLXFW_ERR_MSG(mlxfw_dev, extack,
405                               "Could not activate the downloaded image", err);
406                 goto err_fsm_activate;
407         }
408
409         err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
410                                    MLXFW_FSM_STATE_LOCKED, extack);
411         if (err)
412                 goto err_state_wait_activate_to_locked;
413
414         mlxfw_dbg(mlxfw_dev, "Handle release\n");
415         mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);
416
417         mlxfw_info(mlxfw_dev, "Firmware flash done\n");
418         mlxfw_status_notify(mlxfw_dev, "Firmware flash done", NULL, 0, 0);
419         mlxfw_mfa2_file_fini(mfa2_file);
420         devlink_flash_update_end_notify(mlxfw_dev->devlink);
421         return 0;
422
423 err_state_wait_activate_to_locked:
424 err_fsm_activate:
425 err_flash_components:
426 err_state_wait_reactivate_to_locked:
427 err_fsm_reactivate:
428 err_state_wait_idle_to_locked:
429         mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);
430 err_fsm_lock:
431         mlxfw_mfa2_file_fini(mfa2_file);
432         devlink_flash_update_end_notify(mlxfw_dev->devlink);
433         return err;
434 }
435 EXPORT_SYMBOL(mlxfw_firmware_flash);
436
437 MODULE_LICENSE("Dual BSD/GPL");
438 MODULE_AUTHOR("Yotam Gigi <yotamg@mellanox.com>");
439 MODULE_DESCRIPTION("Mellanox firmware flash lib");