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