xref: /freebsd/sys/dev/mlxfw/mlxfw_fsm.c (revision 2e3507c25e42292b45a5482e116d278f5515d04d)
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 
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 
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 
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 
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