be2net: FW download for Lancer
Added implementation of FW download feature for Lancer. Signed-off-by: Shripad Nunjundarao <shripad.nunjundarao@emulex.com> Signed-off-by: Sevin Xavier <selvin.xavier@emulex.com> Signed-off-by: Padmanabh Ratnakar <padmanabh.ratnakar@emulex.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
005d569600
commit
485bf569ba
@@ -71,7 +71,8 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
|
|||||||
compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) &
|
compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) &
|
||||||
CQE_STATUS_COMPL_MASK;
|
CQE_STATUS_COMPL_MASK;
|
||||||
|
|
||||||
if ((compl->tag0 == OPCODE_COMMON_WRITE_FLASHROM) &&
|
if (((compl->tag0 == OPCODE_COMMON_WRITE_FLASHROM) ||
|
||||||
|
(compl->tag0 == OPCODE_COMMON_WRITE_OBJECT)) &&
|
||||||
(compl->tag1 == CMD_SUBSYSTEM_COMMON)) {
|
(compl->tag1 == CMD_SUBSYSTEM_COMMON)) {
|
||||||
adapter->flash_status = compl_status;
|
adapter->flash_status = compl_status;
|
||||||
complete(&adapter->flash_compl);
|
complete(&adapter->flash_compl);
|
||||||
@@ -1801,6 +1802,81 @@ err:
|
|||||||
return status;
|
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 *addn_status)
|
||||||
|
{
|
||||||
|
struct be_mcc_wrb *wrb;
|
||||||
|
struct lancer_cmd_req_write_object *req;
|
||||||
|
struct lancer_cmd_resp_write_object *resp;
|
||||||
|
void *ctxt = NULL;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
spin_lock_bh(&adapter->mcc_lock);
|
||||||
|
adapter->flash_status = 0;
|
||||||
|
|
||||||
|
wrb = wrb_from_mccq(adapter);
|
||||||
|
if (!wrb) {
|
||||||
|
status = -EBUSY;
|
||||||
|
goto err_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
req = embedded_payload(wrb);
|
||||||
|
|
||||||
|
be_wrb_hdr_prepare(wrb, sizeof(struct lancer_cmd_req_write_object),
|
||||||
|
true, 1, OPCODE_COMMON_WRITE_OBJECT);
|
||||||
|
wrb->tag1 = CMD_SUBSYSTEM_COMMON;
|
||||||
|
|
||||||
|
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
|
||||||
|
OPCODE_COMMON_WRITE_OBJECT,
|
||||||
|
sizeof(struct lancer_cmd_req_write_object));
|
||||||
|
|
||||||
|
ctxt = &req->context;
|
||||||
|
AMAP_SET_BITS(struct amap_lancer_write_obj_context,
|
||||||
|
write_length, ctxt, data_size);
|
||||||
|
|
||||||
|
if (data_size == 0)
|
||||||
|
AMAP_SET_BITS(struct amap_lancer_write_obj_context,
|
||||||
|
eof, ctxt, 1);
|
||||||
|
else
|
||||||
|
AMAP_SET_BITS(struct amap_lancer_write_obj_context,
|
||||||
|
eof, ctxt, 0);
|
||||||
|
|
||||||
|
be_dws_cpu_to_le(ctxt, sizeof(req->context));
|
||||||
|
req->write_offset = cpu_to_le32(data_offset);
|
||||||
|
strcpy(req->object_name, obj_name);
|
||||||
|
req->descriptor_count = cpu_to_le32(1);
|
||||||
|
req->buf_len = cpu_to_le32(data_size);
|
||||||
|
req->addr_low = cpu_to_le32((cmd->dma +
|
||||||
|
sizeof(struct lancer_cmd_req_write_object))
|
||||||
|
& 0xFFFFFFFF);
|
||||||
|
req->addr_high = cpu_to_le32(upper_32_bits(cmd->dma +
|
||||||
|
sizeof(struct lancer_cmd_req_write_object)));
|
||||||
|
|
||||||
|
be_mcc_notify(adapter);
|
||||||
|
spin_unlock_bh(&adapter->mcc_lock);
|
||||||
|
|
||||||
|
if (!wait_for_completion_timeout(&adapter->flash_compl,
|
||||||
|
msecs_to_jiffies(12000)))
|
||||||
|
status = -1;
|
||||||
|
else
|
||||||
|
status = adapter->flash_status;
|
||||||
|
|
||||||
|
resp = embedded_payload(wrb);
|
||||||
|
if (!status) {
|
||||||
|
*data_written = le32_to_cpu(resp->actual_write_len);
|
||||||
|
} else {
|
||||||
|
*addn_status = resp->additional_status;
|
||||||
|
status = resp->status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
|
||||||
|
err_unlock:
|
||||||
|
spin_unlock_bh(&adapter->mcc_lock);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
|
int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
|
||||||
u32 flash_type, u32 flash_opcode, u32 buf_size)
|
u32 flash_type, u32 flash_opcode, u32 buf_size)
|
||||||
{
|
{
|
||||||
|
@@ -193,6 +193,7 @@ struct be_mcc_mailbox {
|
|||||||
#define OPCODE_COMMON_GET_PHY_DETAILS 102
|
#define OPCODE_COMMON_GET_PHY_DETAILS 102
|
||||||
#define OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP 103
|
#define OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP 103
|
||||||
#define OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES 121
|
#define OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES 121
|
||||||
|
#define OPCODE_COMMON_WRITE_OBJECT 172
|
||||||
|
|
||||||
#define OPCODE_ETH_RSS_CONFIG 1
|
#define OPCODE_ETH_RSS_CONFIG 1
|
||||||
#define OPCODE_ETH_ACPI_CONFIG 2
|
#define OPCODE_ETH_ACPI_CONFIG 2
|
||||||
@@ -1131,6 +1132,36 @@ struct be_cmd_write_flashrom {
|
|||||||
struct flashrom_params params;
|
struct flashrom_params params;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**************** Lancer Firmware Flash ************/
|
||||||
|
struct amap_lancer_write_obj_context {
|
||||||
|
u8 write_length[24];
|
||||||
|
u8 reserved1[7];
|
||||||
|
u8 eof;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct lancer_cmd_req_write_object {
|
||||||
|
struct be_cmd_req_hdr hdr;
|
||||||
|
u8 context[sizeof(struct amap_lancer_write_obj_context) / 8];
|
||||||
|
u32 write_offset;
|
||||||
|
u8 object_name[104];
|
||||||
|
u32 descriptor_count;
|
||||||
|
u32 buf_len;
|
||||||
|
u32 addr_low;
|
||||||
|
u32 addr_high;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lancer_cmd_resp_write_object {
|
||||||
|
u8 opcode;
|
||||||
|
u8 subsystem;
|
||||||
|
u8 rsvd1[2];
|
||||||
|
u8 status;
|
||||||
|
u8 additional_status;
|
||||||
|
u8 rsvd2[2];
|
||||||
|
u32 resp_len;
|
||||||
|
u32 actual_resp_len;
|
||||||
|
u32 actual_write_len;
|
||||||
|
};
|
||||||
|
|
||||||
/************************ WOL *******************************/
|
/************************ WOL *******************************/
|
||||||
struct be_cmd_req_acpi_wol_magic_config{
|
struct be_cmd_req_acpi_wol_magic_config{
|
||||||
struct be_cmd_req_hdr hdr;
|
struct be_cmd_req_hdr hdr;
|
||||||
@@ -1481,6 +1512,11 @@ extern int be_cmd_get_beacon_state(struct be_adapter *adapter,
|
|||||||
extern int be_cmd_write_flashrom(struct be_adapter *adapter,
|
extern int be_cmd_write_flashrom(struct be_adapter *adapter,
|
||||||
struct be_dma_mem *cmd, u32 flash_oper,
|
struct be_dma_mem *cmd, u32 flash_oper,
|
||||||
u32 flash_opcode, u32 buf_size);
|
u32 flash_opcode, u32 buf_size);
|
||||||
|
extern 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 *addn_status);
|
||||||
int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
|
int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
|
||||||
int offset);
|
int offset);
|
||||||
extern int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac,
|
extern int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac,
|
||||||
|
@@ -2712,7 +2712,6 @@ static int be_flash_data(struct be_adapter *adapter,
|
|||||||
"cmd to write to flash rom failed.\n");
|
"cmd to write to flash rom failed.\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
yield();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -2730,32 +2729,98 @@ static int get_ufigen_type(struct flash_file_hdr_g2 *fhdr)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int be_load_fw(struct be_adapter *adapter, u8 *func)
|
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 be_dma_mem flash_cmd;
|
||||||
|
struct lancer_cmd_req_write_object *req;
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (!IS_ALIGNED(fw->size, sizeof(u32))) {
|
||||||
|
dev_err(&adapter->pdev->dev,
|
||||||
|
"FW Image not properly aligned. "
|
||||||
|
"Length must be 4 byte aligned.\n");
|
||||||
|
status = -EINVAL;
|
||||||
|
goto lancer_fw_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
flash_cmd.size = sizeof(struct lancer_cmd_req_write_object)
|
||||||
|
+ LANCER_FW_DOWNLOAD_CHUNK;
|
||||||
|
flash_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, flash_cmd.size,
|
||||||
|
&flash_cmd.dma, GFP_KERNEL);
|
||||||
|
if (!flash_cmd.va) {
|
||||||
|
status = -ENOMEM;
|
||||||
|
dev_err(&adapter->pdev->dev,
|
||||||
|
"Memory allocation failure while flashing\n");
|
||||||
|
goto lancer_fw_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
req = flash_cmd.va;
|
||||||
|
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, &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, &add_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
dma_free_coherent(&adapter->pdev->dev, flash_cmd.size, flash_cmd.va,
|
||||||
|
flash_cmd.dma);
|
||||||
|
if (status) {
|
||||||
|
dev_err(&adapter->pdev->dev,
|
||||||
|
"Firmware load error. "
|
||||||
|
"Status code: 0x%x Additional Status: 0x%x\n",
|
||||||
|
status, add_status);
|
||||||
|
goto lancer_fw_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n");
|
||||||
|
lancer_fw_exit:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int be_fw_download(struct be_adapter *adapter, const struct firmware* fw)
|
||||||
{
|
{
|
||||||
char fw_file[ETHTOOL_FLASH_MAX_FILENAME];
|
|
||||||
const struct firmware *fw;
|
|
||||||
struct flash_file_hdr_g2 *fhdr;
|
struct flash_file_hdr_g2 *fhdr;
|
||||||
struct flash_file_hdr_g3 *fhdr3;
|
struct flash_file_hdr_g3 *fhdr3;
|
||||||
struct image_hdr *img_hdr_ptr = NULL;
|
struct image_hdr *img_hdr_ptr = NULL;
|
||||||
struct be_dma_mem flash_cmd;
|
struct be_dma_mem flash_cmd;
|
||||||
int status, i = 0, num_imgs = 0;
|
|
||||||
const u8 *p;
|
const u8 *p;
|
||||||
|
int status = 0, i = 0, num_imgs = 0;
|
||||||
if (!netif_running(adapter->netdev)) {
|
|
||||||
dev_err(&adapter->pdev->dev,
|
|
||||||
"Firmware load not allowed (interface is down)\n");
|
|
||||||
return -EPERM;
|
|
||||||
}
|
|
||||||
|
|
||||||
strcpy(fw_file, func);
|
|
||||||
|
|
||||||
status = request_firmware(&fw, fw_file, &adapter->pdev->dev);
|
|
||||||
if (status)
|
|
||||||
goto fw_exit;
|
|
||||||
|
|
||||||
p = fw->data;
|
p = fw->data;
|
||||||
fhdr = (struct flash_file_hdr_g2 *) p;
|
fhdr = (struct flash_file_hdr_g2 *) p;
|
||||||
dev_info(&adapter->pdev->dev, "Flashing firmware file %s\n", fw_file);
|
|
||||||
|
|
||||||
flash_cmd.size = sizeof(struct be_cmd_write_flashrom) + 32*1024;
|
flash_cmd.size = sizeof(struct be_cmd_write_flashrom) + 32*1024;
|
||||||
flash_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, flash_cmd.size,
|
flash_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, flash_cmd.size,
|
||||||
@@ -2764,7 +2829,7 @@ int be_load_fw(struct be_adapter *adapter, u8 *func)
|
|||||||
status = -ENOMEM;
|
status = -ENOMEM;
|
||||||
dev_err(&adapter->pdev->dev,
|
dev_err(&adapter->pdev->dev,
|
||||||
"Memory allocation failure while flashing\n");
|
"Memory allocation failure while flashing\n");
|
||||||
goto fw_exit;
|
goto be_fw_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((adapter->generation == BE_GEN3) &&
|
if ((adapter->generation == BE_GEN3) &&
|
||||||
@@ -2792,11 +2857,37 @@ int be_load_fw(struct be_adapter *adapter, u8 *func)
|
|||||||
flash_cmd.dma);
|
flash_cmd.dma);
|
||||||
if (status) {
|
if (status) {
|
||||||
dev_err(&adapter->pdev->dev, "Firmware load error\n");
|
dev_err(&adapter->pdev->dev, "Firmware load error\n");
|
||||||
goto fw_exit;
|
goto be_fw_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n");
|
dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n");
|
||||||
|
|
||||||
|
be_fw_exit:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int be_load_fw(struct be_adapter *adapter, u8 *fw_file)
|
||||||
|
{
|
||||||
|
const struct firmware *fw;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
if (!netif_running(adapter->netdev)) {
|
||||||
|
dev_err(&adapter->pdev->dev,
|
||||||
|
"Firmware load not allowed (interface is down)\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = request_firmware(&fw, fw_file, &adapter->pdev->dev);
|
||||||
|
if (status)
|
||||||
|
goto fw_exit;
|
||||||
|
|
||||||
|
dev_info(&adapter->pdev->dev, "Flashing firmware file %s\n", fw_file);
|
||||||
|
|
||||||
|
if (lancer_chip(adapter))
|
||||||
|
status = lancer_fw_download(adapter, fw);
|
||||||
|
else
|
||||||
|
status = be_fw_download(adapter, fw);
|
||||||
|
|
||||||
fw_exit:
|
fw_exit:
|
||||||
release_firmware(fw);
|
release_firmware(fw);
|
||||||
return status;
|
return status;
|
||||||
|
Reference in New Issue
Block a user