mirror of https://gitee.com/openkylin/linux.git
liquidio: Firmware image download
This patch has firmware image related changes for: firmware release upon failure, support latest firmware version and firmware download in 4MB chunks. Signed-off-by: Derek Chickles <derek.chickles@caviumnetworks.com> Signed-off-by: Satanand Burla <satananda.burla@caviumnetworks.com> Signed-off-by: Felix Manlunas <felix.manlunas@caviumnetworks.com> Signed-off-by: Raghu Vatsavayi <raghu.vatsavayi@caviumnetworks.com> Signed-off-by: Raghu Vatsavayi <rvatsavayi@caviumnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
9a96bde4e1
commit
d3d7e6c65f
|
@ -1375,6 +1375,7 @@ static int octeon_chip_specific_setup(struct octeon_device *oct)
|
|||
{
|
||||
u32 dev_id, rev_id;
|
||||
int ret = 1;
|
||||
char *s;
|
||||
|
||||
pci_read_config_dword(oct->pci_dev, 0, &dev_id);
|
||||
pci_read_config_dword(oct->pci_dev, 8, &rev_id);
|
||||
|
@ -1384,22 +1385,27 @@ static int octeon_chip_specific_setup(struct octeon_device *oct)
|
|||
case OCTEON_CN68XX_PCIID:
|
||||
oct->chip_id = OCTEON_CN68XX;
|
||||
ret = lio_setup_cn68xx_octeon_device(oct);
|
||||
s = "CN68XX";
|
||||
break;
|
||||
|
||||
case OCTEON_CN66XX_PCIID:
|
||||
oct->chip_id = OCTEON_CN66XX;
|
||||
ret = lio_setup_cn66xx_octeon_device(oct);
|
||||
s = "CN66XX";
|
||||
break;
|
||||
|
||||
default:
|
||||
s = "?";
|
||||
dev_err(&oct->pci_dev->dev, "Unknown device found (dev_id: %x)\n",
|
||||
dev_id);
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
dev_info(&oct->pci_dev->dev, "CN68XX PASS%d.%d %s\n",
|
||||
dev_info(&oct->pci_dev->dev, "%s PASS%d.%d %s Version: %s\n", s,
|
||||
OCTEON_MAJOR_REV(oct),
|
||||
OCTEON_MINOR_REV(oct),
|
||||
octeon_get_conf(oct)->card_name);
|
||||
octeon_get_conf(oct)->card_name,
|
||||
LIQUIDIO_VERSION);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1772,6 +1778,7 @@ static int load_firmware(struct octeon_device *oct)
|
|||
if (ret) {
|
||||
dev_err(&oct->pci_dev->dev, "Request firmware failed. Could not find file %s.\n.",
|
||||
fw_name);
|
||||
release_firmware(fw);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1841,6 +1848,9 @@ static void if_cfg_callback(struct octeon_device *oct,
|
|||
CVM_CAST64(resp->status));
|
||||
ACCESS_ONCE(ctx->cond) = 1;
|
||||
|
||||
snprintf(oct->fw_info.liquidio_firmware_version, 32, "%s",
|
||||
resp->cfg_info.liquidio_firmware_version);
|
||||
|
||||
/* This barrier is required to be sure that the response has been
|
||||
* written fully before waking up the handler
|
||||
*/
|
||||
|
@ -3635,6 +3645,7 @@ static void nic_starter(struct work_struct *work)
|
|||
static int octeon_device_init(struct octeon_device *octeon_dev)
|
||||
{
|
||||
int j, ret;
|
||||
char bootcmd[] = "\n";
|
||||
struct octeon_device_priv *oct_priv =
|
||||
(struct octeon_device_priv *)octeon_dev->priv;
|
||||
atomic_set(&octeon_dev->status, OCT_DEV_BEGIN_STATE);
|
||||
|
@ -3767,6 +3778,9 @@ static int octeon_device_init(struct octeon_device *octeon_dev)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* Divert uboot to take commands from host instead. */
|
||||
ret = octeon_console_send_cmd(octeon_dev, bootcmd, 50);
|
||||
|
||||
dev_dbg(&octeon_dev->pci_dev->dev, "Initializing consoles\n");
|
||||
ret = octeon_init_consoles(octeon_dev);
|
||||
if (ret) {
|
||||
|
|
|
@ -30,11 +30,10 @@
|
|||
|
||||
#include "octeon_config.h"
|
||||
|
||||
#define LIQUIDIO_VERSION "1.1.9"
|
||||
#define LIQUIDIO_MAJOR_VERSION 1
|
||||
#define LIQUIDIO_MINOR_VERSION 1
|
||||
#define LIQUIDIO_MICRO_VERSION 9
|
||||
|
||||
#define LIQUIDIO_BASE_VERSION "1.4"
|
||||
#define LIQUIDIO_MICRO_VERSION ".1"
|
||||
#define LIQUIDIO_PACKAGE ""
|
||||
#define LIQUIDIO_VERSION "1.4.1"
|
||||
#define CONTROL_IQ 0
|
||||
/** Tag types used by Octeon cores in its work. */
|
||||
enum octeon_tag_type {
|
||||
|
@ -712,6 +711,7 @@ struct liquidio_if_cfg_info {
|
|||
u64 iqmask; /** mask for IQs enabled for the port */
|
||||
u64 oqmask; /** mask for OQs enabled for the port */
|
||||
struct oct_link_info linfo; /** initial link information */
|
||||
char liquidio_firmware_version[32];
|
||||
};
|
||||
|
||||
/** Stats for each NIC port in RX direction. */
|
||||
|
|
|
@ -549,17 +549,19 @@ static char *get_oct_app_string(u32 app_mode)
|
|||
return oct_dev_app_str[CVM_DRV_INVALID_APP - CVM_DRV_APP_START];
|
||||
}
|
||||
|
||||
u8 fbuf[4 * 1024 * 1024];
|
||||
|
||||
int octeon_download_firmware(struct octeon_device *oct, const u8 *data,
|
||||
size_t size)
|
||||
{
|
||||
int ret = 0;
|
||||
u8 *p;
|
||||
u8 *buffer;
|
||||
u8 *p = fbuf;
|
||||
u32 crc32_result;
|
||||
u64 load_addr;
|
||||
u32 image_len;
|
||||
struct octeon_firmware_file_header *h;
|
||||
u32 i;
|
||||
u32 i, rem, base_len = strlen(LIQUIDIO_BASE_VERSION);
|
||||
char *base;
|
||||
|
||||
if (size < sizeof(struct octeon_firmware_file_header)) {
|
||||
dev_err(&oct->pci_dev->dev, "Firmware file too small (%d < %d).\n",
|
||||
|
@ -575,19 +577,26 @@ int octeon_download_firmware(struct octeon_device *oct, const u8 *data,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
crc32_result =
|
||||
crc32(~0, data,
|
||||
sizeof(struct octeon_firmware_file_header) -
|
||||
sizeof(u32)) ^ ~0U;
|
||||
crc32_result = crc32((unsigned int)~0, data,
|
||||
sizeof(struct octeon_firmware_file_header) -
|
||||
sizeof(u32)) ^ ~0U;
|
||||
if (crc32_result != be32_to_cpu(h->crc32)) {
|
||||
dev_err(&oct->pci_dev->dev, "Firmware CRC mismatch (0x%08x != 0x%08x).\n",
|
||||
crc32_result, be32_to_cpu(h->crc32));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (memcmp(LIQUIDIO_VERSION, h->version, strlen(LIQUIDIO_VERSION))) {
|
||||
dev_err(&oct->pci_dev->dev, "Unmatched firmware version. Expected %s, got %s.\n",
|
||||
LIQUIDIO_VERSION, h->version);
|
||||
if (strncmp(LIQUIDIO_PACKAGE, h->version, strlen(LIQUIDIO_PACKAGE))) {
|
||||
dev_err(&oct->pci_dev->dev, "Unmatched firmware package type. Expected %s, got %s.\n",
|
||||
LIQUIDIO_PACKAGE, h->version);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
base = h->version + strlen(LIQUIDIO_PACKAGE);
|
||||
ret = memcmp(LIQUIDIO_BASE_VERSION, base, base_len);
|
||||
if (ret) {
|
||||
dev_err(&oct->pci_dev->dev, "Unmatched firmware version. Expected %s.x, got %s.\n",
|
||||
LIQUIDIO_BASE_VERSION, base);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -601,44 +610,44 @@ int octeon_download_firmware(struct octeon_device *oct, const u8 *data,
|
|||
snprintf(oct->fw_info.liquidio_firmware_version, 32, "LIQUIDIO: %s",
|
||||
h->version);
|
||||
|
||||
buffer = kmemdup(data, size, GFP_KERNEL);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
p = buffer + sizeof(struct octeon_firmware_file_header);
|
||||
data += sizeof(struct octeon_firmware_file_header);
|
||||
|
||||
dev_info(&oct->pci_dev->dev, "%s: Loading %d images\n", __func__,
|
||||
be32_to_cpu(h->num_images));
|
||||
/* load all images */
|
||||
for (i = 0; i < be32_to_cpu(h->num_images); i++) {
|
||||
load_addr = be64_to_cpu(h->desc[i].addr);
|
||||
image_len = be32_to_cpu(h->desc[i].len);
|
||||
|
||||
/* validate the image */
|
||||
crc32_result = crc32(~0, p, image_len) ^ ~0U;
|
||||
if (crc32_result != be32_to_cpu(h->desc[i].crc32)) {
|
||||
dev_err(&oct->pci_dev->dev,
|
||||
"Firmware CRC mismatch in image %d (0x%08x != 0x%08x).\n",
|
||||
i, crc32_result,
|
||||
be32_to_cpu(h->desc[i].crc32));
|
||||
ret = -EINVAL;
|
||||
goto done_downloading;
|
||||
dev_info(&oct->pci_dev->dev, "Loading firmware %d at %llx\n",
|
||||
image_len, load_addr);
|
||||
|
||||
/* Write in 4MB chunks*/
|
||||
rem = image_len;
|
||||
|
||||
while (rem) {
|
||||
if (rem < (4 * 1024 * 1024))
|
||||
size = rem;
|
||||
else
|
||||
size = 4 * 1024 * 1024;
|
||||
|
||||
memcpy(p, data, size);
|
||||
|
||||
/* download the image */
|
||||
octeon_pci_write_core_mem(oct, load_addr, p, (u32)size);
|
||||
|
||||
data += size;
|
||||
rem -= (u32)size;
|
||||
load_addr += size;
|
||||
}
|
||||
|
||||
/* download the image */
|
||||
octeon_pci_write_core_mem(oct, load_addr, p, image_len);
|
||||
|
||||
p += image_len;
|
||||
dev_dbg(&oct->pci_dev->dev,
|
||||
"Downloaded image %d (%d bytes) to address 0x%016llx\n",
|
||||
i, image_len, load_addr);
|
||||
}
|
||||
dev_info(&oct->pci_dev->dev, "Writing boot command: %s\n",
|
||||
h->bootcmd);
|
||||
|
||||
/* Invoke the bootcmd */
|
||||
ret = octeon_console_send_cmd(oct, h->bootcmd, 50);
|
||||
|
||||
done_downloading:
|
||||
kfree(buffer);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void octeon_free_device_mem(struct octeon_device *oct)
|
||||
|
|
Loading…
Reference in New Issue