Commit a23113b5 authored by Suresh Reddy's avatar Suresh Reddy Committed by David S. Miller

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: default avatarSuresh Reddy <suresh.reddy@avagotech.com>
Signed-off-by: default avatarSathya Perla <sathya.perla@avagotech.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8836ff48
...@@ -2291,10 +2291,11 @@ int be_cmd_read_port_transceiver_data(struct be_adapter *adapter, ...@@ -2291,10 +2291,11 @@ int be_cmd_read_port_transceiver_data(struct be_adapter *adapter,
return status; return status;
} }
int lancer_cmd_write_object(struct be_adapter *adapter, struct be_dma_mem *cmd, static int lancer_cmd_write_object(struct be_adapter *adapter,
u32 data_size, u32 data_offset, struct be_dma_mem *cmd, u32 data_size,
const char *obj_name, u32 *data_written, u32 data_offset, const char *obj_name,
u8 *change_status, u8 *addn_status) u32 *data_written, u8 *change_status,
u8 *addn_status)
{ {
struct be_mcc_wrb *wrb; struct be_mcc_wrb *wrb;
struct lancer_cmd_req_write_object *req; struct lancer_cmd_req_write_object *req;
...@@ -2410,7 +2411,8 @@ int be_cmd_query_sfp_info(struct be_adapter *adapter) ...@@ -2410,7 +2411,8 @@ int be_cmd_query_sfp_info(struct be_adapter *adapter)
return status; 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 lancer_cmd_req_delete_object *req;
struct be_mcc_wrb *wrb; struct be_mcc_wrb *wrb;
...@@ -2485,9 +2487,9 @@ int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd, ...@@ -2485,9 +2487,9 @@ int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd,
return status; return status;
} }
int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, static int be_cmd_write_flashrom(struct be_adapter *adapter,
u32 flash_type, u32 flash_opcode, u32 img_offset, struct be_dma_mem *cmd, u32 flash_type,
u32 buf_size) u32 flash_opcode, u32 img_offset, u32 buf_size)
{ {
struct be_mcc_wrb *wrb; struct be_mcc_wrb *wrb;
struct be_cmd_write_flashrom *req; struct be_cmd_write_flashrom *req;
...@@ -2533,8 +2535,8 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, ...@@ -2533,8 +2535,8 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
return status; return status;
} }
int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, static int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
u16 img_optype, u32 img_offset, u32 crc_offset) u16 img_optype, u32 img_offset, u32 crc_offset)
{ {
struct be_cmd_read_flash_crc *req; struct be_cmd_read_flash_crc *req;
struct be_mcc_wrb *wrb; struct be_mcc_wrb *wrb;
...@@ -2571,6 +2573,567 @@ int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, ...@@ -2571,6 +2573,567 @@ int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
return status; 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, int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac,
struct be_dma_mem *nonemb_cmd) struct be_dma_mem *nonemb_cmd)
{ {
......
...@@ -1411,6 +1411,9 @@ struct be_cmd_read_flash_crc { ...@@ -1411,6 +1411,9 @@ struct be_cmd_read_flash_crc {
} __packed; } __packed;
/**************** Lancer Firmware Flash ************/ /**************** Lancer Firmware Flash ************/
#define LANCER_FW_DOWNLOAD_CHUNK (32 * 1024)
#define LANCER_FW_DOWNLOAD_LOCATION "/prg"
struct amap_lancer_write_obj_context { struct amap_lancer_write_obj_context {
u8 write_length[24]; u8 write_length[24];
u8 reserved1[7]; u8 reserved1[7];
...@@ -2339,19 +2342,11 @@ int be_cmd_read_port_transceiver_data(struct be_adapter *adapter, ...@@ -2339,19 +2342,11 @@ int be_cmd_read_port_transceiver_data(struct be_adapter *adapter,
u8 page_num, u8 *data); u8 page_num, u8 *data);
int be_cmd_query_cable_type(struct be_adapter *adapter); int be_cmd_query_cable_type(struct be_adapter *adapter);
int be_cmd_query_sfp_info(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, 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_size, u32 data_offset, const char *obj_name,
u32 *data_read, u32 *eof, u8 *addn_status); u32 *data_read, u32 *eof, u8 *addn_status);
int lancer_cmd_delete_object(struct be_adapter *adapter, const char *obj_name); int lancer_fw_download(struct be_adapter *adapter, const struct firmware *fw);
int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, int be_fw_download(struct be_adapter *adapter, const struct firmware *fw);
u16 img_optype, u32 img_offset, u32 crc_offset);
int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac, int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac,
struct be_dma_mem *nonemb_cmd); struct be_dma_mem *nonemb_cmd);
int be_cmd_fw_init(struct be_adapter *adapter); int be_cmd_fw_init(struct be_adapter *adapter);
......
...@@ -4490,570 +4490,6 @@ static void be_netpoll(struct net_device *netdev) ...@@ -4490,570 +4490,6 @@ static void be_netpoll(struct net_device *netdev)
} }
#endif #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) int be_load_fw(struct be_adapter *adapter, u8 *fw_file)
{ {
const struct firmware *fw; const struct firmware *fw;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment