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