diff options
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_cmds.c | 583 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_cmds.h | 15 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_main.c | 564 |
3 files changed, 578 insertions, 584 deletions
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 8083eca60808..da3b39873470 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -2291,10 +2291,11 @@ err: return status; } -int lancer_cmd_write_object(struct be_adapter *adapter, struct be_dma_mem *cmd, - u32 data_size, u32 data_offset, - const char *obj_name, u32 *data_written, - u8 *change_status, u8 *addn_status) +static int lancer_cmd_write_object(struct be_adapter *adapter, + struct be_dma_mem *cmd, u32 data_size, + u32 data_offset, const char *obj_name, + u32 *data_written, u8 *change_status, + u8 *addn_status) { struct be_mcc_wrb *wrb; struct lancer_cmd_req_write_object *req; @@ -2410,7 +2411,8 @@ int be_cmd_query_sfp_info(struct be_adapter *adapter) return status; } -int lancer_cmd_delete_object(struct be_adapter *adapter, const char *obj_name) +static int lancer_cmd_delete_object(struct be_adapter *adapter, + const char *obj_name) { struct lancer_cmd_req_delete_object *req; struct be_mcc_wrb *wrb; @@ -2485,9 +2487,9 @@ err_unlock: return status; } -int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, - u32 flash_type, u32 flash_opcode, u32 img_offset, - u32 buf_size) +static int be_cmd_write_flashrom(struct be_adapter *adapter, + struct be_dma_mem *cmd, u32 flash_type, + u32 flash_opcode, u32 img_offset, u32 buf_size) { struct be_mcc_wrb *wrb; struct be_cmd_write_flashrom *req; @@ -2533,8 +2535,8 @@ err_unlock: return status; } -int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, - u16 img_optype, u32 img_offset, u32 crc_offset) +static int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, + u16 img_optype, u32 img_offset, u32 crc_offset) { struct be_cmd_read_flash_crc *req; struct be_mcc_wrb *wrb; @@ -2571,6 +2573,567 @@ err: return status; } +static char flash_cookie[2][16] = {"*** SE FLAS", "H DIRECTORY *** "}; + +static bool phy_flashing_required(struct be_adapter *adapter) +{ + return (adapter->phy.phy_type == PHY_TYPE_TN_8022 && + adapter->phy.interface_type == PHY_TYPE_BASET_10GB); +} + +static bool is_comp_in_ufi(struct be_adapter *adapter, + struct flash_section_info *fsec, int type) +{ + int i = 0, img_type = 0; + struct flash_section_info_g2 *fsec_g2 = NULL; + + if (BE2_chip(adapter)) + fsec_g2 = (struct flash_section_info_g2 *)fsec; + + for (i = 0; i < MAX_FLASH_COMP; i++) { + if (fsec_g2) + img_type = le32_to_cpu(fsec_g2->fsec_entry[i].type); + else + img_type = le32_to_cpu(fsec->fsec_entry[i].type); + + if (img_type == type) + return true; + } + return false; +} + +static struct flash_section_info *get_fsec_info(struct be_adapter *adapter, + int header_size, + const struct firmware *fw) +{ + struct flash_section_info *fsec = NULL; + const u8 *p = fw->data; + + p += header_size; + while (p < (fw->data + fw->size)) { + fsec = (struct flash_section_info *)p; + if (!memcmp(flash_cookie, fsec->cookie, sizeof(flash_cookie))) + return fsec; + p += 32; + } + return NULL; +} + +static int be_check_flash_crc(struct be_adapter *adapter, const u8 *p, + u32 img_offset, u32 img_size, int hdr_size, + u16 img_optype, bool *crc_match) +{ + u32 crc_offset; + int status; + u8 crc[4]; + + status = be_cmd_get_flash_crc(adapter, crc, img_optype, img_offset, + img_size - 4); + if (status) + return status; + + crc_offset = hdr_size + img_offset + img_size - 4; + + /* Skip flashing, if crc of flashed region matches */ + if (!memcmp(crc, p + crc_offset, 4)) + *crc_match = true; + else + *crc_match = false; + + return status; +} + +static int be_flash(struct be_adapter *adapter, const u8 *img, + struct be_dma_mem *flash_cmd, int optype, int img_size, + u32 img_offset) +{ + u32 flash_op, num_bytes, total_bytes = img_size, bytes_sent = 0; + struct be_cmd_write_flashrom *req = flash_cmd->va; + int status; + + while (total_bytes) { + num_bytes = min_t(u32, 32 * 1024, total_bytes); + + total_bytes -= num_bytes; + + if (!total_bytes) { + if (optype == OPTYPE_PHY_FW) + flash_op = FLASHROM_OPER_PHY_FLASH; + else + flash_op = FLASHROM_OPER_FLASH; + } else { + if (optype == OPTYPE_PHY_FW) + flash_op = FLASHROM_OPER_PHY_SAVE; + else + flash_op = FLASHROM_OPER_SAVE; + } + + memcpy(req->data_buf, img, num_bytes); + img += num_bytes; + status = be_cmd_write_flashrom(adapter, flash_cmd, optype, + flash_op, img_offset + + bytes_sent, num_bytes); + if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST && + optype == OPTYPE_PHY_FW) + break; + else if (status) + return status; + + bytes_sent += num_bytes; + } + return 0; +} + +/* For BE2, BE3 and BE3-R */ +static int be_flash_BEx(struct be_adapter *adapter, + const struct firmware *fw, + struct be_dma_mem *flash_cmd, int num_of_images) +{ + int img_hdrs_size = (num_of_images * sizeof(struct image_hdr)); + struct device *dev = &adapter->pdev->dev; + struct flash_section_info *fsec = NULL; + int status, i, filehdr_size, num_comp; + const struct flash_comp *pflashcomp; + bool crc_match; + const u8 *p; + + struct flash_comp gen3_flash_types[] = { + { BE3_ISCSI_PRIMARY_IMAGE_START, OPTYPE_ISCSI_ACTIVE, + BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_ISCSI}, + { BE3_REDBOOT_START, OPTYPE_REDBOOT, + BE3_REDBOOT_COMP_MAX_SIZE, IMAGE_BOOT_CODE}, + { BE3_ISCSI_BIOS_START, OPTYPE_BIOS, + BE3_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_ISCSI}, + { BE3_PXE_BIOS_START, OPTYPE_PXE_BIOS, + BE3_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_PXE}, + { BE3_FCOE_BIOS_START, OPTYPE_FCOE_BIOS, + BE3_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_FCOE}, + { BE3_ISCSI_BACKUP_IMAGE_START, OPTYPE_ISCSI_BACKUP, + BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_ISCSI}, + { BE3_FCOE_PRIMARY_IMAGE_START, OPTYPE_FCOE_FW_ACTIVE, + BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_FCOE}, + { BE3_FCOE_BACKUP_IMAGE_START, OPTYPE_FCOE_FW_BACKUP, + BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_FCOE}, + { BE3_NCSI_START, OPTYPE_NCSI_FW, + BE3_NCSI_COMP_MAX_SIZE, IMAGE_NCSI}, + { BE3_PHY_FW_START, OPTYPE_PHY_FW, + BE3_PHY_FW_COMP_MAX_SIZE, IMAGE_FIRMWARE_PHY} + }; + + struct flash_comp gen2_flash_types[] = { + { BE2_ISCSI_PRIMARY_IMAGE_START, OPTYPE_ISCSI_ACTIVE, + BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_ISCSI}, + { BE2_REDBOOT_START, OPTYPE_REDBOOT, + BE2_REDBOOT_COMP_MAX_SIZE, IMAGE_BOOT_CODE}, + { BE2_ISCSI_BIOS_START, OPTYPE_BIOS, + BE2_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_ISCSI}, + { BE2_PXE_BIOS_START, OPTYPE_PXE_BIOS, + BE2_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_PXE}, + { BE2_FCOE_BIOS_START, OPTYPE_FCOE_BIOS, + BE2_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_FCOE}, + { BE2_ISCSI_BACKUP_IMAGE_START, OPTYPE_ISCSI_BACKUP, + BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_ISCSI}, + { BE2_FCOE_PRIMARY_IMAGE_START, OPTYPE_FCOE_FW_ACTIVE, + BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_FCOE}, + { BE2_FCOE_BACKUP_IMAGE_START, OPTYPE_FCOE_FW_BACKUP, + BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_FCOE} + }; + + if (BE3_chip(adapter)) { + pflashcomp = gen3_flash_types; + filehdr_size = sizeof(struct flash_file_hdr_g3); + num_comp = ARRAY_SIZE(gen3_flash_types); + } else { + pflashcomp = gen2_flash_types; + filehdr_size = sizeof(struct flash_file_hdr_g2); + num_comp = ARRAY_SIZE(gen2_flash_types); + img_hdrs_size = 0; + } + + /* Get flash section info*/ + fsec = get_fsec_info(adapter, filehdr_size + img_hdrs_size, fw); + if (!fsec) { + dev_err(dev, "Invalid Cookie. FW image may be corrupted\n"); + return -1; + } + for (i = 0; i < num_comp; i++) { + if (!is_comp_in_ufi(adapter, fsec, pflashcomp[i].img_type)) + continue; + + if ((pflashcomp[i].optype == OPTYPE_NCSI_FW) && + memcmp(adapter->fw_ver, "3.102.148.0", 11) < 0) + continue; + + if (pflashcomp[i].optype == OPTYPE_PHY_FW && + !phy_flashing_required(adapter)) + continue; + + if (pflashcomp[i].optype == OPTYPE_REDBOOT) { + status = be_check_flash_crc(adapter, fw->data, + pflashcomp[i].offset, + pflashcomp[i].size, + filehdr_size + + img_hdrs_size, + OPTYPE_REDBOOT, &crc_match); + if (status) { + dev_err(dev, + "Could not get CRC for 0x%x region\n", + pflashcomp[i].optype); + continue; + } + + if (crc_match) + continue; + } + + p = fw->data + filehdr_size + pflashcomp[i].offset + + img_hdrs_size; + if (p + pflashcomp[i].size > fw->data + fw->size) + return -1; + + status = be_flash(adapter, p, flash_cmd, pflashcomp[i].optype, + pflashcomp[i].size, 0); + if (status) { + dev_err(dev, "Flashing section type 0x%x failed\n", + pflashcomp[i].img_type); + return status; + } + } + return 0; +} + +static u16 be_get_img_optype(struct flash_section_entry fsec_entry) +{ + u32 img_type = le32_to_cpu(fsec_entry.type); + u16 img_optype = le16_to_cpu(fsec_entry.optype); + + if (img_optype != 0xFFFF) + return img_optype; + + switch (img_type) { + case IMAGE_FIRMWARE_ISCSI: + img_optype = OPTYPE_ISCSI_ACTIVE; + break; + case IMAGE_BOOT_CODE: + img_optype = OPTYPE_REDBOOT; + break; + case IMAGE_OPTION_ROM_ISCSI: + img_optype = OPTYPE_BIOS; + break; + case IMAGE_OPTION_ROM_PXE: + img_optype = OPTYPE_PXE_BIOS; + break; + case IMAGE_OPTION_ROM_FCOE: + img_optype = OPTYPE_FCOE_BIOS; + break; + case IMAGE_FIRMWARE_BACKUP_ISCSI: + img_optype = OPTYPE_ISCSI_BACKUP; + break; + case IMAGE_NCSI: + img_optype = OPTYPE_NCSI_FW; + break; + case IMAGE_FLASHISM_JUMPVECTOR: + img_optype = OPTYPE_FLASHISM_JUMPVECTOR; + break; + case IMAGE_FIRMWARE_PHY: + img_optype = OPTYPE_SH_PHY_FW; + break; + case IMAGE_REDBOOT_DIR: + img_optype = OPTYPE_REDBOOT_DIR; + break; + case IMAGE_REDBOOT_CONFIG: + img_optype = OPTYPE_REDBOOT_CONFIG; + break; + case IMAGE_UFI_DIR: + img_optype = OPTYPE_UFI_DIR; + break; + default: + break; + } + + return img_optype; +} + +static int be_flash_skyhawk(struct be_adapter *adapter, + const struct firmware *fw, + struct be_dma_mem *flash_cmd, int num_of_images) +{ + int img_hdrs_size = num_of_images * sizeof(struct image_hdr); + bool crc_match, old_fw_img, flash_offset_support = true; + struct device *dev = &adapter->pdev->dev; + struct flash_section_info *fsec = NULL; + u32 img_offset, img_size, img_type; + u16 img_optype, flash_optype; + int status, i, filehdr_size; + const u8 *p; + + filehdr_size = sizeof(struct flash_file_hdr_g3); + fsec = get_fsec_info(adapter, filehdr_size + img_hdrs_size, fw); + if (!fsec) { + dev_err(dev, "Invalid Cookie. FW image may be corrupted\n"); + return -EINVAL; + } + +retry_flash: + for (i = 0; i < le32_to_cpu(fsec->fsec_hdr.num_images); i++) { + img_offset = le32_to_cpu(fsec->fsec_entry[i].offset); + img_size = le32_to_cpu(fsec->fsec_entry[i].pad_size); + img_type = le32_to_cpu(fsec->fsec_entry[i].type); + img_optype = be_get_img_optype(fsec->fsec_entry[i]); + old_fw_img = fsec->fsec_entry[i].optype == 0xFFFF; + + if (img_optype == 0xFFFF) + continue; + + if (flash_offset_support) + flash_optype = OPTYPE_OFFSET_SPECIFIED; + else + flash_optype = img_optype; + + /* Don't bother verifying CRC if an old FW image is being + * flashed + */ + if (old_fw_img) + goto flash; + + status = be_check_flash_crc(adapter, fw->data, img_offset, + img_size, filehdr_size + + img_hdrs_size, flash_optype, + &crc_match); + if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST || + base_status(status) == MCC_STATUS_ILLEGAL_FIELD) { + /* The current FW image on the card does not support + * OFFSET based flashing. Retry using older mechanism + * of OPTYPE based flashing + */ + if (flash_optype == OPTYPE_OFFSET_SPECIFIED) { + flash_offset_support = false; + goto retry_flash; + } + + /* The current FW image on the card does not recognize + * the new FLASH op_type. The FW download is partially + * complete. Reboot the server now to enable FW image + * to recognize the new FLASH op_type. To complete the + * remaining process, download the same FW again after + * the reboot. + */ + dev_err(dev, "Flash incomplete. Reset the server\n"); + dev_err(dev, "Download FW image again after reset\n"); + return -EAGAIN; + } else if (status) { + dev_err(dev, "Could not get CRC for 0x%x region\n", + img_optype); + return -EFAULT; + } + + if (crc_match) + continue; + +flash: + p = fw->data + filehdr_size + img_offset + img_hdrs_size; + if (p + img_size > fw->data + fw->size) + return -1; + + status = be_flash(adapter, p, flash_cmd, flash_optype, img_size, + img_offset); + + /* The current FW image on the card does not support OFFSET + * based flashing. Retry using older mechanism of OPTYPE based + * flashing + */ + if (base_status(status) == MCC_STATUS_ILLEGAL_FIELD && + flash_optype == OPTYPE_OFFSET_SPECIFIED) { + flash_offset_support = false; + goto retry_flash; + } + + /* For old FW images ignore ILLEGAL_FIELD error or errors on + * UFI_DIR region + */ + if (old_fw_img && + (base_status(status) == MCC_STATUS_ILLEGAL_FIELD || + (img_optype == OPTYPE_UFI_DIR && + base_status(status) == MCC_STATUS_FAILED))) { + continue; + } else if (status) { + dev_err(dev, "Flashing section type 0x%x failed\n", + img_type); + return -EFAULT; + } + } + return 0; +} + +int lancer_fw_download(struct be_adapter *adapter, + const struct firmware *fw) +{ + struct device *dev = &adapter->pdev->dev; + struct be_dma_mem flash_cmd; + const u8 *data_ptr = NULL; + u8 *dest_image_ptr = NULL; + size_t image_size = 0; + u32 chunk_size = 0; + u32 data_written = 0; + u32 offset = 0; + int status = 0; + u8 add_status = 0; + u8 change_status; + + if (!IS_ALIGNED(fw->size, sizeof(u32))) { + dev_err(dev, "FW image size should be multiple of 4\n"); + return -EINVAL; + } + + flash_cmd.size = sizeof(struct lancer_cmd_req_write_object) + + LANCER_FW_DOWNLOAD_CHUNK; + flash_cmd.va = dma_zalloc_coherent(dev, flash_cmd.size, + &flash_cmd.dma, GFP_KERNEL); + if (!flash_cmd.va) + return -ENOMEM; + + dest_image_ptr = flash_cmd.va + + sizeof(struct lancer_cmd_req_write_object); + image_size = fw->size; + data_ptr = fw->data; + + while (image_size) { + chunk_size = min_t(u32, image_size, LANCER_FW_DOWNLOAD_CHUNK); + + /* Copy the image chunk content. */ + memcpy(dest_image_ptr, data_ptr, chunk_size); + + status = lancer_cmd_write_object(adapter, &flash_cmd, + chunk_size, offset, + LANCER_FW_DOWNLOAD_LOCATION, + &data_written, &change_status, + &add_status); + if (status) + break; + + offset += data_written; + data_ptr += data_written; + image_size -= data_written; + } + + if (!status) { + /* Commit the FW written */ + status = lancer_cmd_write_object(adapter, &flash_cmd, + 0, offset, + LANCER_FW_DOWNLOAD_LOCATION, + &data_written, &change_status, + &add_status); + } + + dma_free_coherent(dev, flash_cmd.size, flash_cmd.va, flash_cmd.dma); + if (status) { + dev_err(dev, "Firmware load error\n"); + return be_cmd_status(status); + } + + dev_info(dev, "Firmware flashed successfully\n"); + + if (change_status == LANCER_FW_RESET_NEEDED) { + dev_info(dev, "Resetting adapter to activate new FW\n"); + status = lancer_physdev_ctrl(adapter, + PHYSDEV_CONTROL_FW_RESET_MASK); + if (status) { + dev_err(dev, "Adapter busy, could not reset FW\n"); + dev_err(dev, "Reboot server to activate new FW\n"); + } + } else if (change_status != LANCER_NO_RESET_NEEDED) { + dev_info(dev, "Reboot server to activate new FW\n"); + } + + return 0; +} + +/* Check if the flash image file is compatible with the adapter that + * is being flashed. + */ +static bool be_check_ufi_compatibility(struct be_adapter *adapter, + struct flash_file_hdr_g3 *fhdr) +{ + if (!fhdr) { + dev_err(&adapter->pdev->dev, "Invalid FW UFI file"); + return false; + } + + /* First letter of the build version is used to identify + * which chip this image file is meant for. + */ + switch (fhdr->build[0]) { + case BLD_STR_UFI_TYPE_SH: + if (!skyhawk_chip(adapter)) + return false; + break; + case BLD_STR_UFI_TYPE_BE3: + if (!BE3_chip(adapter)) + return false; + break; + case BLD_STR_UFI_TYPE_BE2: + if (!BE2_chip(adapter)) + return false; + break; + default: + return false; + } + + /* In BE3 FW images the "asic_type_rev" field doesn't track the + * asic_rev of the chips it is compatible with. + * When asic_type_rev is 0 the image is compatible only with + * pre-BE3-R chips (asic_rev < 0x10) + */ + if (BEx_chip(adapter) && fhdr->asic_type_rev == 0) + return adapter->asic_rev < 0x10; + else + return (fhdr->asic_type_rev >= adapter->asic_rev); +} + +int be_fw_download(struct be_adapter *adapter, const struct firmware *fw) +{ + struct device *dev = &adapter->pdev->dev; + struct flash_file_hdr_g3 *fhdr3; + struct image_hdr *img_hdr_ptr; + int status = 0, i, num_imgs; + struct be_dma_mem flash_cmd; + + fhdr3 = (struct flash_file_hdr_g3 *)fw->data; + if (!be_check_ufi_compatibility(adapter, fhdr3)) { + dev_err(dev, "Flash image is not compatible with adapter\n"); + return -EINVAL; + } + + flash_cmd.size = sizeof(struct be_cmd_write_flashrom); + flash_cmd.va = dma_zalloc_coherent(dev, flash_cmd.size, &flash_cmd.dma, + GFP_KERNEL); + if (!flash_cmd.va) + return -ENOMEM; + + num_imgs = le32_to_cpu(fhdr3->num_imgs); + for (i = 0; i < num_imgs; i++) { + img_hdr_ptr = (struct image_hdr *)(fw->data + + (sizeof(struct flash_file_hdr_g3) + + i * sizeof(struct image_hdr))); + if (!BE2_chip(adapter) && + le32_to_cpu(img_hdr_ptr->imageid) != 1) + continue; + + if (skyhawk_chip(adapter)) + status = be_flash_skyhawk(adapter, fw, &flash_cmd, + num_imgs); + else + status = be_flash_BEx(adapter, fw, &flash_cmd, + num_imgs); + } + + dma_free_coherent(dev, flash_cmd.size, flash_cmd.va, flash_cmd.dma); + if (!status) + dev_info(dev, "Firmware flashed successfully\n"); + + return status; +} + int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac, struct be_dma_mem *nonemb_cmd) { diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index 8c6b606f0e90..4b0ca994d6c3 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -1411,6 +1411,9 @@ struct be_cmd_read_flash_crc { } __packed; /**************** Lancer Firmware Flash ************/ +#define LANCER_FW_DOWNLOAD_CHUNK (32 * 1024) +#define LANCER_FW_DOWNLOAD_LOCATION "/prg" + struct amap_lancer_write_obj_context { u8 write_length[24]; u8 reserved1[7]; @@ -2339,19 +2342,11 @@ int be_cmd_read_port_transceiver_data(struct be_adapter *adapter, u8 page_num, u8 *data); int be_cmd_query_cable_type(struct be_adapter *adapter); int be_cmd_query_sfp_info(struct be_adapter *adapter); -int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, - u32 flash_oper, u32 flash_opcode, u32 img_offset, - u32 buf_size); -int lancer_cmd_write_object(struct be_adapter *adapter, struct be_dma_mem *cmd, - u32 data_size, u32 data_offset, - const char *obj_name, u32 *data_written, - u8 *change_status, u8 *addn_status); int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd, u32 data_size, u32 data_offset, const char *obj_name, u32 *data_read, u32 *eof, u8 *addn_status); -int lancer_cmd_delete_object(struct be_adapter *adapter, const char *obj_name); -int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, - u16 img_optype, u32 img_offset, u32 crc_offset); +int lancer_fw_download(struct be_adapter *adapter, const struct firmware *fw); +int be_fw_download(struct be_adapter *adapter, const struct firmware *fw); int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac, struct be_dma_mem *nonemb_cmd); int be_cmd_fw_init(struct be_adapter *adapter); diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 0bb6e5a29f8d..646b02136b0e 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -4490,570 +4490,6 @@ static void be_netpoll(struct net_device *netdev) } #endif -static char flash_cookie[2][16] = {"*** SE FLAS", "H DIRECTORY *** "}; - -static bool phy_flashing_required(struct be_adapter *adapter) -{ - return (adapter->phy.phy_type == PHY_TYPE_TN_8022 && - adapter->phy.interface_type == PHY_TYPE_BASET_10GB); -} - -static bool is_comp_in_ufi(struct be_adapter *adapter, - struct flash_section_info *fsec, int type) -{ - int i = 0, img_type = 0; - struct flash_section_info_g2 *fsec_g2 = NULL; - - if (BE2_chip(adapter)) - fsec_g2 = (struct flash_section_info_g2 *)fsec; - - for (i = 0; i < MAX_FLASH_COMP; i++) { - if (fsec_g2) - img_type = le32_to_cpu(fsec_g2->fsec_entry[i].type); - else - img_type = le32_to_cpu(fsec->fsec_entry[i].type); - - if (img_type == type) - return true; - } - return false; - -} - -static struct flash_section_info *get_fsec_info(struct be_adapter *adapter, - int header_size, - const struct firmware *fw) -{ - struct flash_section_info *fsec = NULL; - const u8 *p = fw->data; - - p += header_size; - while (p < (fw->data + fw->size)) { - fsec = (struct flash_section_info *)p; - if (!memcmp(flash_cookie, fsec->cookie, sizeof(flash_cookie))) - return fsec; - p += 32; - } - return NULL; -} - -static int be_check_flash_crc(struct be_adapter *adapter, const u8 *p, - u32 img_offset, u32 img_size, int hdr_size, - u16 img_optype, bool *crc_match) -{ - u32 crc_offset; - int status; - u8 crc[4]; - - status = be_cmd_get_flash_crc(adapter, crc, img_optype, img_offset, - img_size - 4); - if (status) - return status; - - crc_offset = hdr_size + img_offset + img_size - 4; - - /* Skip flashing, if crc of flashed region matches */ - if (!memcmp(crc, p + crc_offset, 4)) - *crc_match = true; - else - *crc_match = false; - - return status; -} - -static int be_flash(struct be_adapter *adapter, const u8 *img, - struct be_dma_mem *flash_cmd, int optype, int img_size, - u32 img_offset) -{ - u32 flash_op, num_bytes, total_bytes = img_size, bytes_sent = 0; - struct be_cmd_write_flashrom *req = flash_cmd->va; - int status; - - while (total_bytes) { - num_bytes = min_t(u32, 32*1024, total_bytes); - - total_bytes -= num_bytes; - - if (!total_bytes) { - if (optype == OPTYPE_PHY_FW) - flash_op = FLASHROM_OPER_PHY_FLASH; - else - flash_op = FLASHROM_OPER_FLASH; - } else { - if (optype == OPTYPE_PHY_FW) - flash_op = FLASHROM_OPER_PHY_SAVE; - else - flash_op = FLASHROM_OPER_SAVE; - } - - memcpy(req->data_buf, img, num_bytes); - img += num_bytes; - status = be_cmd_write_flashrom(adapter, flash_cmd, optype, - flash_op, img_offset + - bytes_sent, num_bytes); - if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST && - optype == OPTYPE_PHY_FW) - break; - else if (status) - return status; - - bytes_sent += num_bytes; - } - return 0; -} - -/* For BE2, BE3 and BE3-R */ -static int be_flash_BEx(struct be_adapter *adapter, - const struct firmware *fw, - struct be_dma_mem *flash_cmd, int num_of_images) -{ - int img_hdrs_size = (num_of_images * sizeof(struct image_hdr)); - struct device *dev = &adapter->pdev->dev; - struct flash_section_info *fsec = NULL; - int status, i, filehdr_size, num_comp; - const struct flash_comp *pflashcomp; - bool crc_match; - const u8 *p; - - struct flash_comp gen3_flash_types[] = { - { BE3_ISCSI_PRIMARY_IMAGE_START, OPTYPE_ISCSI_ACTIVE, - BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_ISCSI}, - { BE3_REDBOOT_START, OPTYPE_REDBOOT, - BE3_REDBOOT_COMP_MAX_SIZE, IMAGE_BOOT_CODE}, - { BE3_ISCSI_BIOS_START, OPTYPE_BIOS, - BE3_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_ISCSI}, - { BE3_PXE_BIOS_START, OPTYPE_PXE_BIOS, - BE3_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_PXE}, - { BE3_FCOE_BIOS_START, OPTYPE_FCOE_BIOS, - BE3_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_FCOE}, - { BE3_ISCSI_BACKUP_IMAGE_START, OPTYPE_ISCSI_BACKUP, - BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_ISCSI}, - { BE3_FCOE_PRIMARY_IMAGE_START, OPTYPE_FCOE_FW_ACTIVE, - BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_FCOE}, - { BE3_FCOE_BACKUP_IMAGE_START, OPTYPE_FCOE_FW_BACKUP, - BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_FCOE}, - { BE3_NCSI_START, OPTYPE_NCSI_FW, - BE3_NCSI_COMP_MAX_SIZE, IMAGE_NCSI}, - { BE3_PHY_FW_START, OPTYPE_PHY_FW, - BE3_PHY_FW_COMP_MAX_SIZE, IMAGE_FIRMWARE_PHY} - }; - - struct flash_comp gen2_flash_types[] = { - { BE2_ISCSI_PRIMARY_IMAGE_START, OPTYPE_ISCSI_ACTIVE, - BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_ISCSI}, - { BE2_REDBOOT_START, OPTYPE_REDBOOT, - BE2_REDBOOT_COMP_MAX_SIZE, IMAGE_BOOT_CODE}, - { BE2_ISCSI_BIOS_START, OPTYPE_BIOS, - BE2_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_ISCSI}, - { BE2_PXE_BIOS_START, OPTYPE_PXE_BIOS, - BE2_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_PXE}, - { BE2_FCOE_BIOS_START, OPTYPE_FCOE_BIOS, - BE2_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_FCOE}, - { BE2_ISCSI_BACKUP_IMAGE_START, OPTYPE_ISCSI_BACKUP, - BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_ISCSI}, - { BE2_FCOE_PRIMARY_IMAGE_START, OPTYPE_FCOE_FW_ACTIVE, - BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_FCOE}, - { BE2_FCOE_BACKUP_IMAGE_START, OPTYPE_FCOE_FW_BACKUP, - BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_FCOE} - }; - - if (BE3_chip(adapter)) { - pflashcomp = gen3_flash_types; - filehdr_size = sizeof(struct flash_file_hdr_g3); - num_comp = ARRAY_SIZE(gen3_flash_types); - } else { - pflashcomp = gen2_flash_types; - filehdr_size = sizeof(struct flash_file_hdr_g2); - num_comp = ARRAY_SIZE(gen2_flash_types); - img_hdrs_size = 0; - } - - /* Get flash section info*/ - fsec = get_fsec_info(adapter, filehdr_size + img_hdrs_size, fw); - if (!fsec) { - dev_err(dev, "Invalid Cookie. FW image may be corrupted\n"); - return -1; - } - for (i = 0; i < num_comp; i++) { - if (!is_comp_in_ufi(adapter, fsec, pflashcomp[i].img_type)) - continue; - - if ((pflashcomp[i].optype == OPTYPE_NCSI_FW) && - memcmp(adapter->fw_ver, "3.102.148.0", 11) < 0) - continue; - - if (pflashcomp[i].optype == OPTYPE_PHY_FW && - !phy_flashing_required(adapter)) - continue; - - if (pflashcomp[i].optype == OPTYPE_REDBOOT) { - status = be_check_flash_crc(adapter, fw->data, - pflashcomp[i].offset, - pflashcomp[i].size, - filehdr_size + - img_hdrs_size, - OPTYPE_REDBOOT, &crc_match); - if (status) { - dev_err(dev, - "Could not get CRC for 0x%x region\n", - pflashcomp[i].optype); - continue; - } - - if (crc_match) - continue; - } - - p = fw->data + filehdr_size + pflashcomp[i].offset + - img_hdrs_size; - if (p + pflashcomp[i].size > fw->data + fw->size) - return -1; - - status = be_flash(adapter, p, flash_cmd, pflashcomp[i].optype, - pflashcomp[i].size, 0); - if (status) { - dev_err(dev, "Flashing section type 0x%x failed\n", - pflashcomp[i].img_type); - return status; - } - } - return 0; -} - -static u16 be_get_img_optype(struct flash_section_entry fsec_entry) -{ - u32 img_type = le32_to_cpu(fsec_entry.type); - u16 img_optype = le16_to_cpu(fsec_entry.optype); - - if (img_optype != 0xFFFF) - return img_optype; - - switch (img_type) { - case IMAGE_FIRMWARE_ISCSI: - img_optype = OPTYPE_ISCSI_ACTIVE; - break; - case IMAGE_BOOT_CODE: - img_optype = OPTYPE_REDBOOT; - break; - case IMAGE_OPTION_ROM_ISCSI: - img_optype = OPTYPE_BIOS; - break; - case IMAGE_OPTION_ROM_PXE: - img_optype = OPTYPE_PXE_BIOS; - break; - case IMAGE_OPTION_ROM_FCOE: - img_optype = OPTYPE_FCOE_BIOS; - break; - case IMAGE_FIRMWARE_BACKUP_ISCSI: - img_optype = OPTYPE_ISCSI_BACKUP; - break; - case IMAGE_NCSI: - img_optype = OPTYPE_NCSI_FW; - break; - case IMAGE_FLASHISM_JUMPVECTOR: - img_optype = OPTYPE_FLASHISM_JUMPVECTOR; - break; - case IMAGE_FIRMWARE_PHY: - img_optype = OPTYPE_SH_PHY_FW; - break; - case IMAGE_REDBOOT_DIR: - img_optype = OPTYPE_REDBOOT_DIR; - break; - case IMAGE_REDBOOT_CONFIG: - img_optype = OPTYPE_REDBOOT_CONFIG; - break; - case IMAGE_UFI_DIR: - img_optype = OPTYPE_UFI_DIR; - break; - default: - break; - } - - return img_optype; -} - -static int be_flash_skyhawk(struct be_adapter *adapter, - const struct firmware *fw, - struct be_dma_mem *flash_cmd, int num_of_images) -{ - int img_hdrs_size = num_of_images * sizeof(struct image_hdr); - bool crc_match, old_fw_img, flash_offset_support = true; - struct device *dev = &adapter->pdev->dev; - struct flash_section_info *fsec = NULL; - u32 img_offset, img_size, img_type; - u16 img_optype, flash_optype; - int status, i, filehdr_size; - const u8 *p; - - filehdr_size = sizeof(struct flash_file_hdr_g3); - fsec = get_fsec_info(adapter, filehdr_size + img_hdrs_size, fw); - if (!fsec) { - dev_err(dev, "Invalid Cookie. FW image may be corrupted\n"); - return -EINVAL; - } - -retry_flash: - for (i = 0; i < le32_to_cpu(fsec->fsec_hdr.num_images); i++) { - img_offset = le32_to_cpu(fsec->fsec_entry[i].offset); - img_size = le32_to_cpu(fsec->fsec_entry[i].pad_size); - img_type = le32_to_cpu(fsec->fsec_entry[i].type); - img_optype = be_get_img_optype(fsec->fsec_entry[i]); - old_fw_img = fsec->fsec_entry[i].optype == 0xFFFF; - - if (img_optype == 0xFFFF) - continue; - - if (flash_offset_support) - flash_optype = OPTYPE_OFFSET_SPECIFIED; - else - flash_optype = img_optype; - - /* Don't bother verifying CRC if an old FW image is being - * flashed - */ - if (old_fw_img) - goto flash; - - status = be_check_flash_crc(adapter, fw->data, img_offset, - img_size, filehdr_size + - img_hdrs_size, flash_optype, - &crc_match); - if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST || - base_status(status) == MCC_STATUS_ILLEGAL_FIELD) { - /* The current FW image on the card does not support - * OFFSET based flashing. Retry using older mechanism - * of OPTYPE based flashing - */ - if (flash_optype == OPTYPE_OFFSET_SPECIFIED) { - flash_offset_support = false; - goto retry_flash; - } - - /* The current FW image on the card does not recognize - * the new FLASH op_type. The FW download is partially - * complete. Reboot the server now to enable FW image - * to recognize the new FLASH op_type. To complete the - * remaining process, download the same FW again after - * the reboot. - */ - dev_err(dev, "Flash incomplete. Reset the server\n"); - dev_err(dev, "Download FW image again after reset\n"); - return -EAGAIN; - } else if (status) { - dev_err(dev, "Could not get CRC for 0x%x region\n", - img_optype); - return -EFAULT; - } - - if (crc_match) - continue; - -flash: - p = fw->data + filehdr_size + img_offset + img_hdrs_size; - if (p + img_size > fw->data + fw->size) - return -1; - - status = be_flash(adapter, p, flash_cmd, flash_optype, img_size, - img_offset); - - /* The current FW image on the card does not support OFFSET - * based flashing. Retry using older mechanism of OPTYPE based - * flashing - */ - if (base_status(status) == MCC_STATUS_ILLEGAL_FIELD && - flash_optype == OPTYPE_OFFSET_SPECIFIED) { - flash_offset_support = false; - goto retry_flash; - } - - /* For old FW images ignore ILLEGAL_FIELD error or errors on - * UFI_DIR region - */ - if (old_fw_img && - (base_status(status) == MCC_STATUS_ILLEGAL_FIELD || - (img_optype == OPTYPE_UFI_DIR && - base_status(status) == MCC_STATUS_FAILED))) { - continue; - } else if (status) { - dev_err(dev, "Flashing section type 0x%x failed\n", - img_type); - return -EFAULT; - } - } - return 0; -} - -static int lancer_fw_download(struct be_adapter *adapter, - const struct firmware *fw) -{ -#define LANCER_FW_DOWNLOAD_CHUNK (32 * 1024) -#define LANCER_FW_DOWNLOAD_LOCATION "/prg" - struct device *dev = &adapter->pdev->dev; - struct be_dma_mem flash_cmd; - const u8 *data_ptr = NULL; - u8 *dest_image_ptr = NULL; - size_t image_size = 0; - u32 chunk_size = 0; - u32 data_written = 0; - u32 offset = 0; - int status = 0; - u8 add_status = 0; - u8 change_status; - - if (!IS_ALIGNED(fw->size, sizeof(u32))) { - dev_err(dev, "FW image size should be multiple of 4\n"); - return -EINVAL; - } - - flash_cmd.size = sizeof(struct lancer_cmd_req_write_object) - + LANCER_FW_DOWNLOAD_CHUNK; - flash_cmd.va = dma_zalloc_coherent(dev, flash_cmd.size, - &flash_cmd.dma, GFP_KERNEL); - if (!flash_cmd.va) - return -ENOMEM; - - dest_image_ptr = flash_cmd.va + - sizeof(struct lancer_cmd_req_write_object); - image_size = fw->size; - data_ptr = fw->data; - - while (image_size) { - chunk_size = min_t(u32, image_size, LANCER_FW_DOWNLOAD_CHUNK); - - /* Copy the image chunk content. */ - memcpy(dest_image_ptr, data_ptr, chunk_size); - - status = lancer_cmd_write_object(adapter, &flash_cmd, - chunk_size, offset, - LANCER_FW_DOWNLOAD_LOCATION, - &data_written, &change_status, - &add_status); - if (status) - break; - - offset += data_written; - data_ptr += data_written; - image_size -= data_written; - } - - if (!status) { - /* Commit the FW written */ - status = lancer_cmd_write_object(adapter, &flash_cmd, - 0, offset, - LANCER_FW_DOWNLOAD_LOCATION, - &data_written, &change_status, - &add_status); - } - - dma_free_coherent(dev, flash_cmd.size, flash_cmd.va, flash_cmd.dma); - if (status) { - dev_err(dev, "Firmware load error\n"); - return be_cmd_status(status); - } - - dev_info(dev, "Firmware flashed successfully\n"); - - if (change_status == LANCER_FW_RESET_NEEDED) { - dev_info(dev, "Resetting adapter to activate new FW\n"); - status = lancer_physdev_ctrl(adapter, - PHYSDEV_CONTROL_FW_RESET_MASK); - if (status) { - dev_err(dev, "Adapter busy, could not reset FW\n"); - dev_err(dev, "Reboot server to activate new FW\n"); - } - } else if (change_status != LANCER_NO_RESET_NEEDED) { - dev_info(dev, "Reboot server to activate new FW\n"); - } - - return 0; -} - -/* Check if the flash image file is compatible with the adapter that - * is being flashed. - */ -static bool be_check_ufi_compatibility(struct be_adapter *adapter, - struct flash_file_hdr_g3 *fhdr) -{ - if (!fhdr) { - dev_err(&adapter->pdev->dev, "Invalid FW UFI file"); - return false; - } - - /* First letter of the build version is used to identify - * which chip this image file is meant for. - */ - switch (fhdr->build[0]) { - case BLD_STR_UFI_TYPE_SH: - if (!skyhawk_chip(adapter)) - return false; - break; - case BLD_STR_UFI_TYPE_BE3: - if (!BE3_chip(adapter)) - return false; - break; - case BLD_STR_UFI_TYPE_BE2: - if (!BE2_chip(adapter)) - return false; - break; - default: - return false; - } - - /* In BE3 FW images the "asic_type_rev" field doesn't track the - * asic_rev of the chips it is compatible with. - * When asic_type_rev is 0 the image is compatible only with - * pre-BE3-R chips (asic_rev < 0x10) - */ - if (BEx_chip(adapter) && fhdr->asic_type_rev == 0) - return adapter->asic_rev < 0x10; - else - return (fhdr->asic_type_rev >= adapter->asic_rev); -} - -static int be_fw_download(struct be_adapter *adapter, const struct firmware* fw) -{ - struct device *dev = &adapter->pdev->dev; - struct flash_file_hdr_g3 *fhdr3; - struct image_hdr *img_hdr_ptr; - int status = 0, i, num_imgs; - struct be_dma_mem flash_cmd; - - fhdr3 = (struct flash_file_hdr_g3 *)fw->data; - if (!be_check_ufi_compatibility(adapter, fhdr3)) { - dev_err(dev, "Flash image is not compatible with adapter\n"); - return -EINVAL; - } - - flash_cmd.size = sizeof(struct be_cmd_write_flashrom); - flash_cmd.va = dma_zalloc_coherent(dev, flash_cmd.size, &flash_cmd.dma, - GFP_KERNEL); - if (!flash_cmd.va) - return -ENOMEM; - - num_imgs = le32_to_cpu(fhdr3->num_imgs); - for (i = 0; i < num_imgs; i++) { - img_hdr_ptr = (struct image_hdr *)(fw->data + - (sizeof(struct flash_file_hdr_g3) + - i * sizeof(struct image_hdr))); - if (!BE2_chip(adapter) && - le32_to_cpu(img_hdr_ptr->imageid) != 1) - continue; - - if (skyhawk_chip(adapter)) - status = be_flash_skyhawk(adapter, fw, &flash_cmd, - num_imgs); - else - status = be_flash_BEx(adapter, fw, &flash_cmd, - num_imgs); - } - - dma_free_coherent(dev, flash_cmd.size, flash_cmd.va, flash_cmd.dma); - if (!status) - dev_info(dev, "Firmware flashed successfully\n"); - - return status; -} - int be_load_fw(struct be_adapter *adapter, u8 *fw_file) { const struct firmware *fw; |