diff options
Diffstat (limited to 'net/ethtool/cmis_fw_update.c')
-rw-r--r-- | net/ethtool/cmis_fw_update.c | 108 |
1 files changed, 92 insertions, 16 deletions
diff --git a/net/ethtool/cmis_fw_update.c b/net/ethtool/cmis_fw_update.c index 655ff5224ffa..48aef6220f00 100644 --- a/net/ethtool/cmis_fw_update.c +++ b/net/ethtool/cmis_fw_update.c @@ -9,6 +9,7 @@ struct cmis_fw_update_fw_mng_features { u8 start_cmd_payload_size; + u8 write_mechanism; u16 max_duration_start; u16 max_duration_write; u16 max_duration_complete; @@ -36,7 +37,9 @@ struct cmis_cdb_fw_mng_features_rpl { }; enum cmis_cdb_fw_write_mechanism { + CMIS_CDB_FW_WRITE_MECHANISM_NONE = 0x00, CMIS_CDB_FW_WRITE_MECHANISM_LPL = 0x01, + CMIS_CDB_FW_WRITE_MECHANISM_EPL = 0x10, CMIS_CDB_FW_WRITE_MECHANISM_BOTH = 0x11, }; @@ -54,7 +57,8 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb, ethtool_cmis_cdb_check_completion_flag(cdb->cmis_rev, &flags); ethtool_cmis_cdb_compose_args(&args, ETHTOOL_CMIS_CDB_CMD_FW_MANAGMENT_FEATURES, - NULL, 0, cdb->max_completion_time, + NULL, 0, NULL, 0, + cdb->max_completion_time, cdb->read_write_len_ext, 1000, sizeof(*rpl), flags); @@ -67,10 +71,9 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb, } rpl = (struct cmis_cdb_fw_mng_features_rpl *)args.req.payload; - if (!(rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL || - rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_BOTH)) { + if (rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_NONE) { ethnl_module_fw_flash_ntf_err(dev, ntf_params, - "Write LPL is not supported", + "CDB write mechanism is not supported", NULL); return -EOPNOTSUPP; } @@ -82,6 +85,10 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb, */ cdb->read_write_len_ext = rpl->read_write_len_ext; fw_mng->start_cmd_payload_size = rpl->start_cmd_payload_size; + fw_mng->write_mechanism = + rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL ? + CMIS_CDB_FW_WRITE_MECHANISM_LPL : + CMIS_CDB_FW_WRITE_MECHANISM_EPL; fw_mng->max_duration_start = be16_to_cpu(rpl->max_duration_start); fw_mng->max_duration_write = be16_to_cpu(rpl->max_duration_write); fw_mng->max_duration_complete = be16_to_cpu(rpl->max_duration_complete); @@ -122,7 +129,7 @@ cmis_fw_update_start_download(struct ethtool_cmis_cdb *cdb, ethtool_cmis_cdb_compose_args(&args, ETHTOOL_CMIS_CDB_CMD_START_FW_DOWNLOAD, - (u8 *)&pl, lpl_len, + (u8 *)&pl, lpl_len, NULL, 0, fw_mng->max_duration_start, cdb->read_write_len_ext, 1000, 0, CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID); @@ -148,9 +155,9 @@ struct cmis_cdb_write_fw_block_lpl_pl { }; 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) +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) { u8 start = fw_mng->start_cmd_payload_size; u32 offset, max_block_size, max_lpl_len; @@ -158,7 +165,7 @@ cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb, int err; max_lpl_len = min_t(u32, - ethtool_cmis_get_max_payload_size(cdb->read_write_len_ext), + ethtool_cmis_get_max_lpl_size(cdb->read_write_len_ext), ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH); max_block_size = max_lpl_len - sizeof_field(struct cmis_cdb_write_fw_block_lpl_pl, @@ -183,7 +190,7 @@ cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb, ethtool_cmis_cdb_compose_args(&args, ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_LPL, - (u8 *)&pl, lpl_len, + (u8 *)&pl, lpl_len, NULL, 0, fw_mng->max_duration_write, cdb->read_write_len_ext, 1, 0, CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID); @@ -201,6 +208,67 @@ cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb, return 0; } +struct cmis_cdb_write_fw_block_epl_pl { + u8 fw_block[ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH]; +}; + +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) +{ + u8 start = fw_mng->start_cmd_payload_size; + u32 image_size = fw_update->fw->size; + u32 offset, lpl_len; + int err; + + lpl_len = sizeof_field(struct cmis_cdb_write_fw_block_lpl_pl, + block_address); + + for (offset = start; offset < image_size; + offset += ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH) { + struct cmis_cdb_write_fw_block_lpl_pl lpl = { + .block_address = cpu_to_be32(offset - start), + }; + struct cmis_cdb_write_fw_block_epl_pl *epl; + struct ethtool_cmis_cdb_cmd_args args = {}; + u32 epl_len; + + ethnl_module_fw_flash_ntf_in_progress(fw_update->dev, + &fw_update->ntf_params, + offset - start, + image_size); + + epl_len = min_t(u32, ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH, + image_size - offset); + epl = kmalloc_array(epl_len, sizeof(u8), GFP_KERNEL); + if (!epl) + return -ENOMEM; + + memcpy(epl->fw_block, &fw_update->fw->data[offset], epl_len); + + ethtool_cmis_cdb_compose_args(&args, + ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_EPL, + (u8 *)&lpl, lpl_len, (u8 *)epl, + epl_len, + fw_mng->max_duration_write, + cdb->read_write_len_ext, 1, 0, + CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID); + + err = ethtool_cmis_cdb_execute_cmd(fw_update->dev, &args); + kfree(epl); + if (err < 0) { + ethnl_module_fw_flash_ntf_err(fw_update->dev, + &fw_update->ntf_params, + "Write FW block EPL command failed", + args.err_msg); + return err; + } + } + + return 0; +} + static int cmis_fw_update_complete_download(struct ethtool_cmis_cdb *cdb, struct net_device *dev, @@ -212,7 +280,8 @@ cmis_fw_update_complete_download(struct ethtool_cmis_cdb *cdb, ethtool_cmis_cdb_compose_args(&args, ETHTOOL_CMIS_CDB_CMD_COMPLETE_FW_DOWNLOAD, - NULL, 0, fw_mng->max_duration_complete, + NULL, 0, NULL, 0, + fw_mng->max_duration_complete, cdb->read_write_len_ext, 1000, 0, CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID); @@ -236,9 +305,15 @@ cmis_fw_update_download_image(struct ethtool_cmis_cdb *cdb, if (err < 0) return err; - err = cmis_fw_update_write_image(cdb, fw_update, fw_mng); - if (err < 0) - return err; + if (fw_mng->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL) { + err = cmis_fw_update_write_image_lpl(cdb, fw_update, fw_mng); + if (err < 0) + return err; + } else { + err = cmis_fw_update_write_image_epl(cdb, fw_update, fw_mng); + if (err < 0) + return err; + } err = cmis_fw_update_complete_download(cdb, fw_update->dev, fw_mng, &fw_update->ntf_params); @@ -294,7 +369,7 @@ cmis_fw_update_run_image(struct ethtool_cmis_cdb *cdb, struct net_device *dev, int err; ethtool_cmis_cdb_compose_args(&args, ETHTOOL_CMIS_CDB_CMD_RUN_FW_IMAGE, - (u8 *)&pl, sizeof(pl), + (u8 *)&pl, sizeof(pl), NULL, 0, cdb->max_completion_time, cdb->read_write_len_ext, 1000, 0, CDB_F_MODULE_STATE_VALID); @@ -326,7 +401,8 @@ cmis_fw_update_commit_image(struct ethtool_cmis_cdb *cdb, ethtool_cmis_cdb_compose_args(&args, ETHTOOL_CMIS_CDB_CMD_COMMIT_FW_IMAGE, - NULL, 0, cdb->max_completion_time, + NULL, 0, NULL, 0, + cdb->max_completion_time, cdb->read_write_len_ext, 1000, 0, CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID); |