diff options
author | Ajit Khaparde <ajitk@serverengines.com> | 2009-09-04 07:12:16 +0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-09-07 12:56:38 +0400 |
commit | 84517482e19bc775de7b3b4e998dee2f506bc34e (patch) | |
tree | ae3491a5cf8891feef8c2896ef50758d763646f2 /drivers/net/benet/be_main.c | |
parent | 384824281caa9ac4b76664033416f1eac4a652fe (diff) | |
download | linux-84517482e19bc775de7b3b4e998dee2f506bc34e.tar.xz |
be2net: Changes to support flashing of the be2 network adapter
Changes to support flashing of the be2 network adapter using the
request_firmware() & ethtool infrastructure. The trigger to flash the device
will come from ethtool utility. The driver will invoke request_firmware()
to start the flash process. The file containing the flash image is expected
to be available in /lib/firmware/
Signed-off-by: Ajit Khaparde <ajitk@serverengines.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/benet/be_main.c')
-rw-r--r-- | drivers/net/benet/be_main.c | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index bac85f950394..d09106f2e084 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1699,6 +1699,173 @@ static int be_close(struct net_device *netdev) return 0; } +#define FW_FILE_HDR_SIGN "ServerEngines Corp. " +char flash_cookie[2][16] = {"*** SE FLAS", + "H DIRECTORY *** "}; +static int be_flash_image(struct be_adapter *adapter, + const struct firmware *fw, + struct be_dma_mem *flash_cmd, u32 flash_type) +{ + int status; + u32 flash_op, image_offset = 0, total_bytes, image_size = 0; + int num_bytes; + const u8 *p = fw->data; + struct be_cmd_write_flashrom *req = flash_cmd->va; + + switch (flash_type) { + case FLASHROM_TYPE_ISCSI_ACTIVE: + image_offset = FLASH_iSCSI_PRIMARY_IMAGE_START; + image_size = FLASH_IMAGE_MAX_SIZE; + break; + case FLASHROM_TYPE_ISCSI_BACKUP: + image_offset = FLASH_iSCSI_BACKUP_IMAGE_START; + image_size = FLASH_IMAGE_MAX_SIZE; + break; + case FLASHROM_TYPE_FCOE_FW_ACTIVE: + image_offset = FLASH_FCoE_PRIMARY_IMAGE_START; + image_size = FLASH_IMAGE_MAX_SIZE; + break; + case FLASHROM_TYPE_FCOE_FW_BACKUP: + image_offset = FLASH_FCoE_BACKUP_IMAGE_START; + image_size = FLASH_IMAGE_MAX_SIZE; + break; + case FLASHROM_TYPE_BIOS: + image_offset = FLASH_iSCSI_BIOS_START; + image_size = FLASH_BIOS_IMAGE_MAX_SIZE; + break; + case FLASHROM_TYPE_FCOE_BIOS: + image_offset = FLASH_FCoE_BIOS_START; + image_size = FLASH_BIOS_IMAGE_MAX_SIZE; + break; + case FLASHROM_TYPE_PXE_BIOS: + image_offset = FLASH_PXE_BIOS_START; + image_size = FLASH_BIOS_IMAGE_MAX_SIZE; + break; + default: + return 0; + } + + p += sizeof(struct flash_file_hdr) + image_offset; + if (p + image_size > fw->data + fw->size) + return -1; + + total_bytes = image_size; + + while (total_bytes) { + if (total_bytes > 32*1024) + num_bytes = 32*1024; + else + num_bytes = total_bytes; + total_bytes -= num_bytes; + + if (!total_bytes) + flash_op = FLASHROM_OPER_FLASH; + else + flash_op = FLASHROM_OPER_SAVE; + memcpy(req->params.data_buf, p, num_bytes); + p += num_bytes; + status = be_cmd_write_flashrom(adapter, flash_cmd, + flash_type, flash_op, num_bytes); + if (status) { + dev_err(&adapter->pdev->dev, + "cmd to write to flash rom failed. type/op %d/%d\n", + flash_type, flash_op); + return -1; + } + yield(); + } + + return 0; +} + +int be_load_fw(struct be_adapter *adapter, u8 *func) +{ + char fw_file[ETHTOOL_FLASH_MAX_FILENAME]; + const struct firmware *fw; + struct flash_file_hdr *fhdr; + struct flash_section_info *fsec = NULL; + struct be_dma_mem flash_cmd; + int status; + const u8 *p; + bool entry_found = false; + int flash_type; + char fw_ver[FW_VER_LEN]; + char fw_cfg; + + status = be_cmd_get_fw_ver(adapter, fw_ver); + if (status) + return status; + + fw_cfg = *(fw_ver + 2); + if (fw_cfg == '0') + fw_cfg = '1'; + strcpy(fw_file, func); + + status = request_firmware(&fw, fw_file, &adapter->pdev->dev); + if (status) + goto fw_exit; + + p = fw->data; + fhdr = (struct flash_file_hdr *) p; + if (memcmp(fhdr->sign, FW_FILE_HDR_SIGN, strlen(FW_FILE_HDR_SIGN))) { + dev_err(&adapter->pdev->dev, + "Firmware(%s) load error (signature did not match)\n", + fw_file); + status = -1; + goto fw_exit; + } + + dev_info(&adapter->pdev->dev, "Flashing firmware file %s\n", fw_file); + + p += sizeof(struct flash_file_hdr); + while (p < (fw->data + fw->size)) { + fsec = (struct flash_section_info *)p; + if (!memcmp(flash_cookie, fsec->cookie, sizeof(flash_cookie))) { + entry_found = true; + break; + } + p += 32; + } + + if (!entry_found) { + status = -1; + dev_err(&adapter->pdev->dev, + "Flash cookie not found in firmware image\n"); + goto fw_exit; + } + + flash_cmd.size = sizeof(struct be_cmd_write_flashrom) + 32*1024; + flash_cmd.va = pci_alloc_consistent(adapter->pdev, flash_cmd.size, + &flash_cmd.dma); + if (!flash_cmd.va) { + status = -ENOMEM; + dev_err(&adapter->pdev->dev, + "Memory allocation failure while flashing\n"); + goto fw_exit; + } + + for (flash_type = FLASHROM_TYPE_ISCSI_ACTIVE; + flash_type <= FLASHROM_TYPE_FCOE_FW_BACKUP; flash_type++) { + status = be_flash_image(adapter, fw, &flash_cmd, + flash_type); + if (status) + break; + } + + pci_free_consistent(adapter->pdev, flash_cmd.size, flash_cmd.va, + flash_cmd.dma); + if (status) { + dev_err(&adapter->pdev->dev, "Firmware load error\n"); + goto fw_exit; + } + + dev_info(&adapter->pdev->dev, "Firmware flashed succesfully\n"); + +fw_exit: + release_firmware(fw); + return status; +} + static struct net_device_ops be_netdev_ops = { .ndo_open = be_open, .ndo_stop = be_close, |