mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-24 13:13:57 +08:00
be2net: move FW flash cmd code to be_cmds.c
All code relating to FW cmds is in be_cmds.[ch] excepting FW flash cmd related code. This patch moves these routines from be_main.c to be_cmds.c Signed-off-by: Suresh Reddy <suresh.reddy@avagotech.com> Signed-off-by: Sathya Perla <sathya.perla@avagotech.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
8836ff48b9
commit
a23113b5f6
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user