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