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