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
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)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
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)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
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)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
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)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
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)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
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)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
module_is_ready(u8 data)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
cmis_fw_update_wait_for_module_state(struct net_device * dev,u8 flags)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
cmis_fw_update_run_image(struct ethtool_cmis_cdb * cdb,struct net_device * dev,struct ethnl_module_fw_flash_ntf_params * ntf_params)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
cmis_fw_update_commit_image(struct ethtool_cmis_cdb * cdb,struct net_device * dev,struct ethnl_module_fw_flash_ntf_params * ntf_params)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
cmis_fw_update_reset(struct net_device * dev)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
ethtool_cmis_fw_update(struct ethtool_cmis_fw_update_params * fw_update)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