xref: /linux/net/ethtool/cmis_fw_update.c (revision 7f71507851fc7764b36a3221839607d3a45c2025)
1 // SPDX-License-Identifier: GPL-2.0-only
2 
3 #include <linux/ethtool.h>
4 #include <linux/firmware.h>
5 
6 #include "common.h"
7 #include "module_fw.h"
8 #include "cmis.h"
9 
10 struct cmis_fw_update_fw_mng_features {
11 	u8	start_cmd_payload_size;
12 	u8	write_mechanism;
13 	u16	max_duration_start;
14 	u16	max_duration_write;
15 	u16	max_duration_complete;
16 };
17 
18 /* See section 9.4.2 "CMD 0041h: Firmware Management Features" in CMIS standard
19  * revision 5.2.
20  * struct cmis_cdb_fw_mng_features_rpl is a structured layout of the flat
21  * array, ethtool_cmis_cdb_rpl::payload.
22  */
23 struct cmis_cdb_fw_mng_features_rpl {
24 	u8	resv1;
25 	u8	resv2;
26 	u8	start_cmd_payload_size;
27 	u8	resv3;
28 	u8	read_write_len_ext;
29 	u8	write_mechanism;
30 	u8	resv4;
31 	u8	resv5;
32 	__be16	max_duration_start;
33 	__be16	resv6;
34 	__be16	max_duration_write;
35 	__be16	max_duration_complete;
36 	__be16	resv7;
37 };
38 
39 enum cmis_cdb_fw_write_mechanism {
40 	CMIS_CDB_FW_WRITE_MECHANISM_NONE	= 0x00,
41 	CMIS_CDB_FW_WRITE_MECHANISM_LPL		= 0x01,
42 	CMIS_CDB_FW_WRITE_MECHANISM_EPL		= 0x10,
43 	CMIS_CDB_FW_WRITE_MECHANISM_BOTH	= 0x11,
44 };
45 
46 static int
47 cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb,
48 				   struct net_device *dev,
49 				   struct cmis_fw_update_fw_mng_features *fw_mng,
50 				   struct ethnl_module_fw_flash_ntf_params *ntf_params)
51 {
52 	struct ethtool_cmis_cdb_cmd_args args = {};
53 	struct cmis_cdb_fw_mng_features_rpl *rpl;
54 	u8 flags = CDB_F_STATUS_VALID;
55 	int err;
56 
57 	ethtool_cmis_cdb_check_completion_flag(cdb->cmis_rev, &flags);
58 	ethtool_cmis_cdb_compose_args(&args,
59 				      ETHTOOL_CMIS_CDB_CMD_FW_MANAGMENT_FEATURES,
60 				      NULL, 0, NULL, 0,
61 				      cdb->max_completion_time,
62 				      cdb->read_write_len_ext, 1000,
63 				      sizeof(*rpl), flags);
64 
65 	err = ethtool_cmis_cdb_execute_cmd(dev, &args);
66 	if (err < 0) {
67 		ethnl_module_fw_flash_ntf_err(dev, ntf_params,
68 					      "FW Management Features command failed",
69 					      args.err_msg);
70 		return err;
71 	}
72 
73 	rpl = (struct cmis_cdb_fw_mng_features_rpl *)args.req.payload;
74 	if (rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_NONE) {
75 		ethnl_module_fw_flash_ntf_err(dev, ntf_params,
76 					      "CDB write mechanism is not supported",
77 					      NULL);
78 		return  -EOPNOTSUPP;
79 	}
80 
81 	/* Above, we used read_write_len_ext that we got from CDB
82 	 * advertisement. Update it with the value that we got from module
83 	 * features query, which is specific for Firmware Management Commands
84 	 * (IDs 0100h-01FFh).
85 	 */
86 	cdb->read_write_len_ext = rpl->read_write_len_ext;
87 	fw_mng->start_cmd_payload_size = rpl->start_cmd_payload_size;
88 	fw_mng->write_mechanism =
89 		rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL ?
90 		CMIS_CDB_FW_WRITE_MECHANISM_LPL :
91 		CMIS_CDB_FW_WRITE_MECHANISM_EPL;
92 	fw_mng->max_duration_start = be16_to_cpu(rpl->max_duration_start);
93 	fw_mng->max_duration_write = be16_to_cpu(rpl->max_duration_write);
94 	fw_mng->max_duration_complete = be16_to_cpu(rpl->max_duration_complete);
95 
96 	return 0;
97 }
98 
99 /* See section 9.7.2 "CMD 0101h: Start Firmware Download" in CMIS standard
100  * revision 5.2.
101  * struct cmis_cdb_start_fw_download_pl is a structured layout of the
102  * flat array, ethtool_cmis_cdb_request::payload.
103  */
104 struct cmis_cdb_start_fw_download_pl {
105 	__struct_group(cmis_cdb_start_fw_download_pl_h, head, /* no attrs */,
106 			__be32	image_size;
107 			__be32	resv1;
108 	);
109 	u8 vendor_data[ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH -
110 		sizeof(struct cmis_cdb_start_fw_download_pl_h)];
111 };
112 
113 static int
114 cmis_fw_update_start_download(struct ethtool_cmis_cdb *cdb,
115 			      struct ethtool_cmis_fw_update_params *fw_update,
116 			      struct cmis_fw_update_fw_mng_features *fw_mng)
117 {
118 	u8 vendor_data_size = fw_mng->start_cmd_payload_size;
119 	struct cmis_cdb_start_fw_download_pl pl = {};
120 	struct ethtool_cmis_cdb_cmd_args args = {};
121 	u8 lpl_len;
122 	int err;
123 
124 	pl.image_size = cpu_to_be32(fw_update->fw->size);
125 	memcpy(pl.vendor_data, fw_update->fw->data, vendor_data_size);
126 
127 	lpl_len = offsetof(struct cmis_cdb_start_fw_download_pl,
128 			   vendor_data[vendor_data_size]);
129 
130 	ethtool_cmis_cdb_compose_args(&args,
131 				      ETHTOOL_CMIS_CDB_CMD_START_FW_DOWNLOAD,
132 				      (u8 *)&pl, lpl_len, NULL, 0,
133 				      fw_mng->max_duration_start,
134 				      cdb->read_write_len_ext, 1000, 0,
135 				      CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);
136 
137 	err = ethtool_cmis_cdb_execute_cmd(fw_update->dev, &args);
138 	if (err < 0)
139 		ethnl_module_fw_flash_ntf_err(fw_update->dev,
140 					      &fw_update->ntf_params,
141 					      "Start FW download command failed",
142 					      args.err_msg);
143 
144 	return err;
145 }
146 
147 /* See section 9.7.4 "CMD 0103h: Write Firmware Block LPL" in CMIS standard
148  * revision 5.2.
149  * struct cmis_cdb_write_fw_block_lpl_pl is a structured layout of the
150  * flat array, ethtool_cmis_cdb_request::payload.
151  */
152 struct cmis_cdb_write_fw_block_lpl_pl {
153 	__be32	block_address;
154 	u8 fw_block[ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH - sizeof(__be32)];
155 };
156 
157 static int
158 cmis_fw_update_write_image_lpl(struct ethtool_cmis_cdb *cdb,
159 			       struct ethtool_cmis_fw_update_params *fw_update,
160 			       struct cmis_fw_update_fw_mng_features *fw_mng)
161 {
162 	u8 start = fw_mng->start_cmd_payload_size;
163 	u32 offset, max_block_size, max_lpl_len;
164 	u32 image_size = fw_update->fw->size;
165 	int err;
166 
167 	max_lpl_len = min_t(u32,
168 			    ethtool_cmis_get_max_lpl_size(cdb->read_write_len_ext),
169 			    ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH);
170 	max_block_size =
171 		max_lpl_len - sizeof_field(struct cmis_cdb_write_fw_block_lpl_pl,
172 					   block_address);
173 
174 	for (offset = start; offset < image_size; offset += max_block_size) {
175 		struct cmis_cdb_write_fw_block_lpl_pl pl = {
176 			.block_address = cpu_to_be32(offset - start),
177 		};
178 		struct ethtool_cmis_cdb_cmd_args args = {};
179 		u32 block_size, lpl_len;
180 
181 		ethnl_module_fw_flash_ntf_in_progress(fw_update->dev,
182 						      &fw_update->ntf_params,
183 						      offset - start,
184 						      image_size);
185 		block_size = min_t(u32, max_block_size, image_size - offset);
186 		memcpy(pl.fw_block, &fw_update->fw->data[offset], block_size);
187 		lpl_len = block_size +
188 			sizeof_field(struct cmis_cdb_write_fw_block_lpl_pl,
189 				     block_address);
190 
191 		ethtool_cmis_cdb_compose_args(&args,
192 					      ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_LPL,
193 					      (u8 *)&pl, lpl_len, NULL, 0,
194 					      fw_mng->max_duration_write,
195 					      cdb->read_write_len_ext, 1, 0,
196 					      CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);
197 
198 		err = ethtool_cmis_cdb_execute_cmd(fw_update->dev, &args);
199 		if (err < 0) {
200 			ethnl_module_fw_flash_ntf_err(fw_update->dev,
201 						      &fw_update->ntf_params,
202 						      "Write FW block LPL command failed",
203 						      args.err_msg);
204 			return err;
205 		}
206 	}
207 
208 	return 0;
209 }
210 
211 struct cmis_cdb_write_fw_block_epl_pl {
212 	u8 fw_block[ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH];
213 };
214 
215 static int
216 cmis_fw_update_write_image_epl(struct ethtool_cmis_cdb *cdb,
217 			       struct ethtool_cmis_fw_update_params *fw_update,
218 			       struct cmis_fw_update_fw_mng_features *fw_mng)
219 {
220 	u8 start = fw_mng->start_cmd_payload_size;
221 	u32 image_size = fw_update->fw->size;
222 	u32 offset, lpl_len;
223 	int err;
224 
225 	lpl_len = sizeof_field(struct cmis_cdb_write_fw_block_lpl_pl,
226 			       block_address);
227 
228 	for (offset = start; offset < image_size;
229 	     offset += ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH) {
230 		struct cmis_cdb_write_fw_block_lpl_pl lpl = {
231 			.block_address = cpu_to_be32(offset - start),
232 		};
233 		struct cmis_cdb_write_fw_block_epl_pl *epl;
234 		struct ethtool_cmis_cdb_cmd_args args = {};
235 		u32 epl_len;
236 
237 		ethnl_module_fw_flash_ntf_in_progress(fw_update->dev,
238 						      &fw_update->ntf_params,
239 						      offset - start,
240 						      image_size);
241 
242 		epl_len = min_t(u32, ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH,
243 				image_size - offset);
244 		epl = kmalloc_array(epl_len, sizeof(u8), GFP_KERNEL);
245 		if (!epl)
246 			return -ENOMEM;
247 
248 		memcpy(epl->fw_block, &fw_update->fw->data[offset], epl_len);
249 
250 		ethtool_cmis_cdb_compose_args(&args,
251 					      ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_EPL,
252 					      (u8 *)&lpl, lpl_len, (u8 *)epl,
253 					      epl_len,
254 					      fw_mng->max_duration_write,
255 					      cdb->read_write_len_ext, 1, 0,
256 					      CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);
257 
258 		err = ethtool_cmis_cdb_execute_cmd(fw_update->dev, &args);
259 		kfree(epl);
260 		if (err < 0) {
261 			ethnl_module_fw_flash_ntf_err(fw_update->dev,
262 						      &fw_update->ntf_params,
263 						      "Write FW block EPL command failed",
264 						      args.err_msg);
265 			return err;
266 		}
267 	}
268 
269 	return 0;
270 }
271 
272 static int
273 cmis_fw_update_complete_download(struct ethtool_cmis_cdb *cdb,
274 				 struct net_device *dev,
275 				 struct cmis_fw_update_fw_mng_features *fw_mng,
276 				 struct ethnl_module_fw_flash_ntf_params *ntf_params)
277 {
278 	struct ethtool_cmis_cdb_cmd_args args = {};
279 	int err;
280 
281 	ethtool_cmis_cdb_compose_args(&args,
282 				      ETHTOOL_CMIS_CDB_CMD_COMPLETE_FW_DOWNLOAD,
283 				      NULL, 0, NULL, 0,
284 				      fw_mng->max_duration_complete,
285 				      cdb->read_write_len_ext, 1000, 0,
286 				      CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);
287 
288 	err = ethtool_cmis_cdb_execute_cmd(dev, &args);
289 	if (err < 0)
290 		ethnl_module_fw_flash_ntf_err(dev, ntf_params,
291 					      "Complete FW download command failed",
292 					      args.err_msg);
293 
294 	return err;
295 }
296 
297 static int
298 cmis_fw_update_download_image(struct ethtool_cmis_cdb *cdb,
299 			      struct ethtool_cmis_fw_update_params *fw_update,
300 			      struct cmis_fw_update_fw_mng_features *fw_mng)
301 {
302 	int err;
303 
304 	err = cmis_fw_update_start_download(cdb, fw_update, fw_mng);
305 	if (err < 0)
306 		return err;
307 
308 	if (fw_mng->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL) {
309 		err = cmis_fw_update_write_image_lpl(cdb, fw_update, fw_mng);
310 		if (err < 0)
311 			return err;
312 	} else {
313 		err = cmis_fw_update_write_image_epl(cdb, fw_update, fw_mng);
314 		if (err < 0)
315 			return err;
316 	}
317 
318 	err = cmis_fw_update_complete_download(cdb, fw_update->dev, fw_mng,
319 					       &fw_update->ntf_params);
320 	if (err < 0)
321 		return err;
322 
323 	return 0;
324 }
325 
326 enum {
327 	CMIS_MODULE_LOW_PWR	= 1,
328 	CMIS_MODULE_READY	= 3,
329 };
330 
331 static bool module_is_ready(u8 data)
332 {
333 	u8 state = (data >> 1) & 7;
334 
335 	return state == CMIS_MODULE_READY || state == CMIS_MODULE_LOW_PWR;
336 }
337 
338 #define CMIS_MODULE_READY_MAX_DURATION_MSEC	1000
339 #define CMIS_MODULE_STATE_OFFSET		3
340 
341 static int
342 cmis_fw_update_wait_for_module_state(struct net_device *dev, u8 flags)
343 {
344 	u8 state;
345 
346 	return ethtool_cmis_wait_for_cond(dev, flags, CDB_F_MODULE_STATE_VALID,
347 					  CMIS_MODULE_READY_MAX_DURATION_MSEC,
348 					  CMIS_MODULE_STATE_OFFSET,
349 					  module_is_ready, NULL, &state);
350 }
351 
352 /* See section 9.7.10 "CMD 0109h: Run Firmware Image" in CMIS standard
353  * revision 5.2.
354  * struct cmis_cdb_run_fw_image_pl is a structured layout of the flat
355  * array, ethtool_cmis_cdb_request::payload.
356  */
357 struct cmis_cdb_run_fw_image_pl {
358 	u8 resv1;
359 	u8 image_to_run;
360 	u16 delay_to_reset;
361 };
362 
363 static int
364 cmis_fw_update_run_image(struct ethtool_cmis_cdb *cdb, struct net_device *dev,
365 			 struct ethnl_module_fw_flash_ntf_params *ntf_params)
366 {
367 	struct ethtool_cmis_cdb_cmd_args args = {};
368 	struct cmis_cdb_run_fw_image_pl pl = {0};
369 	int err;
370 
371 	ethtool_cmis_cdb_compose_args(&args, ETHTOOL_CMIS_CDB_CMD_RUN_FW_IMAGE,
372 				      (u8 *)&pl, sizeof(pl), NULL, 0,
373 				      cdb->max_completion_time,
374 				      cdb->read_write_len_ext, 1000, 0,
375 				      CDB_F_MODULE_STATE_VALID);
376 
377 	err = ethtool_cmis_cdb_execute_cmd(dev, &args);
378 	if (err < 0) {
379 		ethnl_module_fw_flash_ntf_err(dev, ntf_params,
380 					      "Run image command failed",
381 					      args.err_msg);
382 		return err;
383 	}
384 
385 	err = cmis_fw_update_wait_for_module_state(dev, args.flags);
386 	if (err < 0)
387 		ethnl_module_fw_flash_ntf_err(dev, ntf_params,
388 					      "Module is not ready on time after reset",
389 					      NULL);
390 
391 	return err;
392 }
393 
394 static int
395 cmis_fw_update_commit_image(struct ethtool_cmis_cdb *cdb,
396 			    struct net_device *dev,
397 			    struct ethnl_module_fw_flash_ntf_params *ntf_params)
398 {
399 	struct ethtool_cmis_cdb_cmd_args args = {};
400 	int err;
401 
402 	ethtool_cmis_cdb_compose_args(&args,
403 				      ETHTOOL_CMIS_CDB_CMD_COMMIT_FW_IMAGE,
404 				      NULL, 0, NULL, 0,
405 				      cdb->max_completion_time,
406 				      cdb->read_write_len_ext, 1000, 0,
407 				      CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);
408 
409 	err = ethtool_cmis_cdb_execute_cmd(dev, &args);
410 	if (err < 0)
411 		ethnl_module_fw_flash_ntf_err(dev, ntf_params,
412 					      "Commit image command failed",
413 					      args.err_msg);
414 
415 	return err;
416 }
417 
418 static int cmis_fw_update_reset(struct net_device *dev)
419 {
420 	__u32 reset_data = ETH_RESET_PHY;
421 
422 	return dev->ethtool_ops->reset(dev, &reset_data);
423 }
424 
425 void
426 ethtool_cmis_fw_update(struct ethtool_cmis_fw_update_params *fw_update)
427 {
428 	struct ethnl_module_fw_flash_ntf_params *ntf_params =
429 						&fw_update->ntf_params;
430 	struct cmis_fw_update_fw_mng_features fw_mng = {0};
431 	struct net_device *dev = fw_update->dev;
432 	struct ethtool_cmis_cdb *cdb;
433 	int err;
434 
435 	cdb = ethtool_cmis_cdb_init(dev, &fw_update->params, ntf_params);
436 	if (IS_ERR(cdb))
437 		goto err_send_ntf;
438 
439 	ethnl_module_fw_flash_ntf_start(dev, ntf_params);
440 
441 	err = cmis_fw_update_fw_mng_features_get(cdb, dev, &fw_mng, ntf_params);
442 	if (err < 0)
443 		goto err_cdb_fini;
444 
445 	err = cmis_fw_update_download_image(cdb, fw_update, &fw_mng);
446 	if (err < 0)
447 		goto err_cdb_fini;
448 
449 	err = cmis_fw_update_run_image(cdb, dev, ntf_params);
450 	if (err < 0)
451 		goto err_cdb_fini;
452 
453 	/* The CDB command "Run Firmware Image" resets the firmware, so the new
454 	 * one might have different settings.
455 	 * Free the old CDB instance, and init a new one.
456 	 */
457 	ethtool_cmis_cdb_fini(cdb);
458 
459 	cdb = ethtool_cmis_cdb_init(dev, &fw_update->params, ntf_params);
460 	if (IS_ERR(cdb))
461 		goto err_send_ntf;
462 
463 	err = cmis_fw_update_commit_image(cdb, dev, ntf_params);
464 	if (err < 0)
465 		goto err_cdb_fini;
466 
467 	err = cmis_fw_update_reset(dev);
468 	if (err < 0)
469 		goto err_cdb_fini;
470 
471 	ethnl_module_fw_flash_ntf_complete(dev, ntf_params);
472 	ethtool_cmis_cdb_fini(cdb);
473 	return;
474 
475 err_cdb_fini:
476 	ethtool_cmis_cdb_fini(cdb);
477 err_send_ntf:
478 	ethnl_module_fw_flash_ntf_err(dev, ntf_params, NULL, NULL);
479 }
480