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
32 #define pr_fmt(fmt) "mlxfw: " fmt
33
34 #include <linux/kernel.h>
35 #include <linux/module.h>
36 #include <linux/delay.h>
37
38 #include "mlxfw.h"
39 #include "mlxfw_mfa2.h"
40
41 #define MLXFW_FSM_STATE_WAIT_CYCLE_MS 200
42 #define MLXFW_FSM_STATE_WAIT_TIMEOUT_MS 30000
43 #define MLXFW_FSM_STATE_WAIT_ROUNDS \
44 (MLXFW_FSM_STATE_WAIT_TIMEOUT_MS / MLXFW_FSM_STATE_WAIT_CYCLE_MS)
45 #define MLXFW_FSM_MAX_COMPONENT_SIZE (10 * (1 << 20))
46
47 static const char * const mlxfw_fsm_state_err_str[] = {
48 [MLXFW_FSM_STATE_ERR_ERROR] =
49 "general error",
50 [MLXFW_FSM_STATE_ERR_REJECTED_DIGEST_ERR] =
51 "component hash mismatch",
52 [MLXFW_FSM_STATE_ERR_REJECTED_NOT_APPLICABLE] =
53 "component not applicable",
54 [MLXFW_FSM_STATE_ERR_REJECTED_UNKNOWN_KEY] =
55 "unknown key",
56 [MLXFW_FSM_STATE_ERR_REJECTED_AUTH_FAILED] =
57 "authentication failed",
58 [MLXFW_FSM_STATE_ERR_REJECTED_UNSIGNED] =
59 "component was not signed",
60 [MLXFW_FSM_STATE_ERR_REJECTED_KEY_NOT_APPLICABLE] =
61 "key not applicable",
62 [MLXFW_FSM_STATE_ERR_REJECTED_BAD_FORMAT] =
63 "bad format",
64 [MLXFW_FSM_STATE_ERR_BLOCKED_PENDING_RESET] =
65 "pending reset",
66 [MLXFW_FSM_STATE_ERR_MAX] =
67 "unknown error"
68 };
69
mlxfw_fsm_state_wait(struct mlxfw_dev * mlxfw_dev,u32 fwhandle,enum mlxfw_fsm_state fsm_state)70 static int mlxfw_fsm_state_wait(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
71 enum mlxfw_fsm_state fsm_state)
72 {
73 enum mlxfw_fsm_state_err fsm_state_err;
74 enum mlxfw_fsm_state curr_fsm_state;
75 int times;
76 int err;
77
78 times = MLXFW_FSM_STATE_WAIT_ROUNDS;
79 retry:
80 err = mlxfw_dev->ops->fsm_query_state(mlxfw_dev, fwhandle,
81 &curr_fsm_state, &fsm_state_err);
82 if (err)
83 return err;
84
85 if (fsm_state_err != MLXFW_FSM_STATE_ERR_OK) {
86 pr_err("Firmware flash failed: %s\n",
87 mlxfw_fsm_state_err_str[fsm_state_err]);
88 return -EINVAL;
89 }
90 if (curr_fsm_state != fsm_state) {
91 if (--times == 0) {
92 pr_err("Timeout reached on FSM state change");
93 return -ETIMEDOUT;
94 }
95 msleep(MLXFW_FSM_STATE_WAIT_CYCLE_MS);
96 goto retry;
97 }
98 return 0;
99 }
100
101 #define MLXFW_ALIGN_DOWN(x, align_bits) ((x) & ~((1 << (align_bits)) - 1))
102 #define MLXFW_ALIGN_UP(x, align_bits) \
103 MLXFW_ALIGN_DOWN((x) + ((1 << (align_bits)) - 1), (align_bits))
104
mlxfw_flash_component(struct mlxfw_dev * mlxfw_dev,u32 fwhandle,struct mlxfw_mfa2_component * comp)105 static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev,
106 u32 fwhandle,
107 struct mlxfw_mfa2_component *comp)
108 {
109 u16 comp_max_write_size;
110 u8 comp_align_bits;
111 u32 comp_max_size;
112 u16 block_size;
113 u8 *block_ptr;
114 u32 offset;
115 int err;
116
117 err = mlxfw_dev->ops->component_query(mlxfw_dev, comp->index,
118 &comp_max_size, &comp_align_bits,
119 &comp_max_write_size);
120 if (err)
121 return err;
122
123 comp_max_size = min_t(u32, comp_max_size, MLXFW_FSM_MAX_COMPONENT_SIZE);
124 if (comp->data_size > comp_max_size) {
125 pr_err("Component %d is of size %d which is bigger than limit %d\n",
126 comp->index, comp->data_size, comp_max_size);
127 return -EINVAL;
128 }
129
130 comp_max_write_size = MLXFW_ALIGN_DOWN(comp_max_write_size,
131 comp_align_bits);
132
133 pr_debug("Component update\n");
134 err = mlxfw_dev->ops->fsm_component_update(mlxfw_dev, fwhandle,
135 comp->index,
136 comp->data_size);
137 if (err)
138 return err;
139
140 err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
141 MLXFW_FSM_STATE_DOWNLOAD);
142 if (err)
143 goto err_out;
144
145 pr_debug("Component download\n");
146 for (offset = 0;
147 offset < MLXFW_ALIGN_UP(comp->data_size, comp_align_bits);
148 offset += comp_max_write_size) {
149 block_ptr = comp->data + offset;
150 block_size = (u16) min_t(u32, comp->data_size - offset,
151 comp_max_write_size);
152 err = mlxfw_dev->ops->fsm_block_download(mlxfw_dev, fwhandle,
153 block_ptr, block_size,
154 offset);
155 if (err)
156 goto err_out;
157 }
158
159 pr_debug("Component verify\n");
160 err = mlxfw_dev->ops->fsm_component_verify(mlxfw_dev, fwhandle,
161 comp->index);
162 if (err)
163 goto err_out;
164
165 err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, MLXFW_FSM_STATE_LOCKED);
166 if (err)
167 goto err_out;
168 return 0;
169
170 err_out:
171 mlxfw_dev->ops->fsm_cancel(mlxfw_dev, fwhandle);
172 return err;
173 }
174
mlxfw_flash_components(struct mlxfw_dev * mlxfw_dev,u32 fwhandle,struct mlxfw_mfa2_file * mfa2_file)175 static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
176 struct mlxfw_mfa2_file *mfa2_file)
177 {
178 u32 component_count;
179 int err;
180 int i;
181
182 err = mlxfw_mfa2_file_component_count(mfa2_file, mlxfw_dev->psid,
183 mlxfw_dev->psid_size,
184 &component_count);
185 if (err) {
186 pr_err("Could not find device PSID in MFA2 file\n");
187 return err;
188 }
189
190 for (i = 0; i < component_count; i++) {
191 struct mlxfw_mfa2_component *comp;
192
193 comp = mlxfw_mfa2_file_component_get(mfa2_file, mlxfw_dev->psid,
194 mlxfw_dev->psid_size, i);
195 if (IS_ERR(comp))
196 return PTR_ERR(comp);
197
198 pr_info("Flashing component type %d\n", comp->index);
199 err = mlxfw_flash_component(mlxfw_dev, fwhandle, comp);
200 mlxfw_mfa2_file_component_put(comp);
201 if (err)
202 return err;
203 }
204 return 0;
205 }
206
mlxfw_firmware_flash(struct mlxfw_dev * mlxfw_dev,const struct firmware * firmware)207 int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev,
208 const struct firmware *firmware)
209 {
210 struct mlxfw_mfa2_file *mfa2_file;
211 u32 fwhandle;
212 int err;
213
214 if (!mlxfw_mfa2_check(firmware)) {
215 pr_err("Firmware file is not MFA2\n");
216 return -EINVAL;
217 }
218
219 mfa2_file = mlxfw_mfa2_file_init(firmware);
220 if (IS_ERR(mfa2_file))
221 return PTR_ERR(mfa2_file);
222
223 pr_info("Initialize firmware flash process\n");
224 err = mlxfw_dev->ops->fsm_lock(mlxfw_dev, &fwhandle);
225 if (err) {
226 pr_err("Could not lock the firmware FSM\n");
227 goto err_fsm_lock;
228 }
229
230 err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
231 MLXFW_FSM_STATE_LOCKED);
232 if (err)
233 goto err_state_wait_idle_to_locked;
234
235 err = mlxfw_flash_components(mlxfw_dev, fwhandle, mfa2_file);
236 if (err)
237 goto err_flash_components;
238
239 pr_debug("Activate image\n");
240 err = mlxfw_dev->ops->fsm_activate(mlxfw_dev, fwhandle);
241 if (err) {
242 pr_err("Could not activate the downloaded image\n");
243 goto err_fsm_activate;
244 }
245
246 err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, MLXFW_FSM_STATE_LOCKED);
247 if (err)
248 goto err_state_wait_activate_to_locked;
249
250 pr_debug("Handle release\n");
251 mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);
252
253 pr_info("Firmware flash done.\n");
254 mlxfw_mfa2_file_fini(mfa2_file);
255 return 0;
256
257 err_state_wait_activate_to_locked:
258 err_fsm_activate:
259 err_flash_components:
260 err_state_wait_idle_to_locked:
261 mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);
262 err_fsm_lock:
263 mlxfw_mfa2_file_fini(mfa2_file);
264 return err;
265 }
266 EXPORT_SYMBOL(mlxfw_firmware_flash);
267
268 MODULE_LICENSE("Dual BSD/GPL");
269 MODULE_AUTHOR("Yotam Gigi <yotamg@mellanox.com>");
270 MODULE_DESCRIPTION("Mellanox firmware flash lib");
271 MODULE_VERSION(mlxfw, 1);
272 MODULE_DEPEND(mlxfw, linuxkpi, 1, 1, 1);
273 MODULE_DEPEND(mlxfw, xz, 1, 1, 1);
274