]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/mlxfw/mlxfw_fsm.c
MFV: r362513
[FreeBSD/FreeBSD.git] / sys / dev / mlxfw / mlxfw_fsm.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 2017-2019 Mellanox Technologies.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of Mellanox nor the names of contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * $FreeBSD$
32  */
33
34 #define pr_fmt(fmt) "mlxfw: " fmt
35
36 #include <linux/kernel.h>
37 #include <linux/module.h>
38 #include <linux/delay.h>
39
40 #include "mlxfw.h"
41 #include "mlxfw_mfa2.h"
42
43 #define MLXFW_FSM_STATE_WAIT_CYCLE_MS 200
44 #define MLXFW_FSM_STATE_WAIT_TIMEOUT_MS 30000
45 #define MLXFW_FSM_STATE_WAIT_ROUNDS \
46         (MLXFW_FSM_STATE_WAIT_TIMEOUT_MS / MLXFW_FSM_STATE_WAIT_CYCLE_MS)
47 #define MLXFW_FSM_MAX_COMPONENT_SIZE (10 * (1 << 20))
48
49 static const char * const mlxfw_fsm_state_err_str[] = {
50         [MLXFW_FSM_STATE_ERR_ERROR] =
51                 "general error",
52         [MLXFW_FSM_STATE_ERR_REJECTED_DIGEST_ERR] =
53                 "component hash mismatch",
54         [MLXFW_FSM_STATE_ERR_REJECTED_NOT_APPLICABLE] =
55                 "component not applicable",
56         [MLXFW_FSM_STATE_ERR_REJECTED_UNKNOWN_KEY] =
57                 "unknown key",
58         [MLXFW_FSM_STATE_ERR_REJECTED_AUTH_FAILED] =
59                 "authentication failed",
60         [MLXFW_FSM_STATE_ERR_REJECTED_UNSIGNED] =
61                 "component was not signed",
62         [MLXFW_FSM_STATE_ERR_REJECTED_KEY_NOT_APPLICABLE] =
63                 "key not applicable",
64         [MLXFW_FSM_STATE_ERR_REJECTED_BAD_FORMAT] =
65                 "bad format",
66         [MLXFW_FSM_STATE_ERR_BLOCKED_PENDING_RESET] =
67                 "pending reset",
68         [MLXFW_FSM_STATE_ERR_MAX] =
69                 "unknown error"
70 };
71
72 static int mlxfw_fsm_state_wait(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
73                                 enum mlxfw_fsm_state fsm_state)
74 {
75         enum mlxfw_fsm_state_err fsm_state_err;
76         enum mlxfw_fsm_state curr_fsm_state;
77         int times;
78         int err;
79
80         times = MLXFW_FSM_STATE_WAIT_ROUNDS;
81 retry:
82         err = mlxfw_dev->ops->fsm_query_state(mlxfw_dev, fwhandle,
83                                               &curr_fsm_state, &fsm_state_err);
84         if (err)
85                 return err;
86
87         if (fsm_state_err != MLXFW_FSM_STATE_ERR_OK) {
88                 pr_err("Firmware flash failed: %s\n",
89                        mlxfw_fsm_state_err_str[fsm_state_err]);
90                 return -EINVAL;
91         }
92         if (curr_fsm_state != fsm_state) {
93                 if (--times == 0) {
94                         pr_err("Timeout reached on FSM state change");
95                         return -ETIMEDOUT;
96                 }
97                 msleep(MLXFW_FSM_STATE_WAIT_CYCLE_MS);
98                 goto retry;
99         }
100         return 0;
101 }
102
103 #define MLXFW_ALIGN_DOWN(x, align_bits) ((x) & ~((1 << (align_bits)) - 1))
104 #define MLXFW_ALIGN_UP(x, align_bits) \
105                 MLXFW_ALIGN_DOWN((x) + ((1 << (align_bits)) - 1), (align_bits))
106
107 static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev,
108                                  u32 fwhandle,
109                                  struct mlxfw_mfa2_component *comp)
110 {
111         u16 comp_max_write_size;
112         u8 comp_align_bits;
113         u32 comp_max_size;
114         u16 block_size;
115         u8 *block_ptr;
116         u32 offset;
117         int err;
118
119         err = mlxfw_dev->ops->component_query(mlxfw_dev, comp->index,
120                                               &comp_max_size, &comp_align_bits,
121                                               &comp_max_write_size);
122         if (err)
123                 return err;
124
125         comp_max_size = min_t(u32, comp_max_size, MLXFW_FSM_MAX_COMPONENT_SIZE);
126         if (comp->data_size > comp_max_size) {
127                 pr_err("Component %d is of size %d which is bigger than limit %d\n",
128                        comp->index, comp->data_size, comp_max_size);
129                 return -EINVAL;
130         }
131
132         comp_max_write_size = MLXFW_ALIGN_DOWN(comp_max_write_size,
133                                                comp_align_bits);
134
135         pr_debug("Component update\n");
136         err = mlxfw_dev->ops->fsm_component_update(mlxfw_dev, fwhandle,
137                                                    comp->index,
138                                                    comp->data_size);
139         if (err)
140                 return err;
141
142         err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
143                                    MLXFW_FSM_STATE_DOWNLOAD);
144         if (err)
145                 goto err_out;
146
147         pr_debug("Component download\n");
148         for (offset = 0;
149              offset < MLXFW_ALIGN_UP(comp->data_size, comp_align_bits);
150              offset += comp_max_write_size) {
151                 block_ptr = comp->data + offset;
152                 block_size = (u16) min_t(u32, comp->data_size - offset,
153                                          comp_max_write_size);
154                 err = mlxfw_dev->ops->fsm_block_download(mlxfw_dev, fwhandle,
155                                                          block_ptr, block_size,
156                                                          offset);
157                 if (err)
158                         goto err_out;
159         }
160
161         pr_debug("Component verify\n");
162         err = mlxfw_dev->ops->fsm_component_verify(mlxfw_dev, fwhandle,
163                                                    comp->index);
164         if (err)
165                 goto err_out;
166
167         err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, MLXFW_FSM_STATE_LOCKED);
168         if (err)
169                 goto err_out;
170         return 0;
171
172 err_out:
173         mlxfw_dev->ops->fsm_cancel(mlxfw_dev, fwhandle);
174         return err;
175 }
176
177 static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
178                                   struct mlxfw_mfa2_file *mfa2_file)
179 {
180         u32 component_count;
181         int err;
182         int i;
183
184         err = mlxfw_mfa2_file_component_count(mfa2_file, mlxfw_dev->psid,
185                                               mlxfw_dev->psid_size,
186                                               &component_count);
187         if (err) {
188                 pr_err("Could not find device PSID in MFA2 file\n");
189                 return err;
190         }
191
192         for (i = 0; i < component_count; i++) {
193                 struct mlxfw_mfa2_component *comp;
194
195                 comp = mlxfw_mfa2_file_component_get(mfa2_file, mlxfw_dev->psid,
196                                                      mlxfw_dev->psid_size, i);
197                 if (IS_ERR(comp))
198                         return PTR_ERR(comp);
199
200                 pr_info("Flashing component type %d\n", comp->index);
201                 err = mlxfw_flash_component(mlxfw_dev, fwhandle, comp);
202                 mlxfw_mfa2_file_component_put(comp);
203                 if (err)
204                         return err;
205         }
206         return 0;
207 }
208
209 int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev,
210                          const struct firmware *firmware)
211 {
212         struct mlxfw_mfa2_file *mfa2_file;
213         u32 fwhandle;
214         int err;
215
216         if (!mlxfw_mfa2_check(firmware)) {
217                 pr_err("Firmware file is not MFA2\n");
218                 return -EINVAL;
219         }
220
221         mfa2_file = mlxfw_mfa2_file_init(firmware);
222         if (IS_ERR(mfa2_file))
223                 return PTR_ERR(mfa2_file);
224
225         pr_info("Initialize firmware flash process\n");
226         err = mlxfw_dev->ops->fsm_lock(mlxfw_dev, &fwhandle);
227         if (err) {
228                 pr_err("Could not lock the firmware FSM\n");
229                 goto err_fsm_lock;
230         }
231
232         err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
233                                    MLXFW_FSM_STATE_LOCKED);
234         if (err)
235                 goto err_state_wait_idle_to_locked;
236
237         err = mlxfw_flash_components(mlxfw_dev, fwhandle, mfa2_file);
238         if (err)
239                 goto err_flash_components;
240
241         pr_debug("Activate image\n");
242         err = mlxfw_dev->ops->fsm_activate(mlxfw_dev, fwhandle);
243         if (err) {
244                 pr_err("Could not activate the downloaded image\n");
245                 goto err_fsm_activate;
246         }
247
248         err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, MLXFW_FSM_STATE_LOCKED);
249         if (err)
250                 goto err_state_wait_activate_to_locked;
251
252         pr_debug("Handle release\n");
253         mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);
254
255         pr_info("Firmware flash done.\n");
256         mlxfw_mfa2_file_fini(mfa2_file);
257         return 0;
258
259 err_state_wait_activate_to_locked:
260 err_fsm_activate:
261 err_flash_components:
262 err_state_wait_idle_to_locked:
263         mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);
264 err_fsm_lock:
265         mlxfw_mfa2_file_fini(mfa2_file);
266         return err;
267 }
268 EXPORT_SYMBOL(mlxfw_firmware_flash);
269
270 MODULE_LICENSE("Dual BSD/GPL");
271 MODULE_AUTHOR("Yotam Gigi <yotamg@mellanox.com>");
272 MODULE_DESCRIPTION("Mellanox firmware flash lib");
273 MODULE_VERSION(mlxfw, 1);
274 MODULE_DEPEND(mlxfw, linuxkpi, 1, 1, 1);
275 MODULE_DEPEND(mlxfw, xz, 1, 1, 1);