Commit d3d7e6c6 authored by Raghu Vatsavayi's avatar Raghu Vatsavayi Committed by David S. Miller

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