Merge remote-tracking branch 'sound-asoc/for-next'
[deliverable/linux.git] / drivers / net / ethernet / cavium / liquidio / octeon_console.c
index bbb50ea66f165066b5f09c59806087d0fe3b0228..01a50f3b0c8e28a342cd03828be7bf60906d41df 100644 (file)
  */
 #include <linux/pci.h>
 #include <linux/netdevice.h>
+#include <linux/crc32.h>
 #include "liquidio_common.h"
 #include "octeon_droq.h"
 #include "octeon_iq.h"
 #include "response_manager.h"
 #include "octeon_device.h"
-#include "octeon_main.h"
+#include "liquidio_image.h"
 #include "octeon_mem_ops.h"
 
 static void octeon_remote_lock(void);
@@ -40,6 +41,10 @@ static u64 cvmx_bootmem_phy_named_block_find(struct octeon_device *oct,
                                             u32 flags);
 static int octeon_console_read(struct octeon_device *oct, u32 console_num,
                               char *buffer, u32 buf_size);
+static u32 console_bitmask;
+module_param(console_bitmask, int, 0644);
+MODULE_PARM_DESC(console_bitmask,
+                "Bitmask indicating which consoles have debug output redirected to syslog.");
 
 #define MIN(a, b) min((a), (b))
 #define CAST_ULL(v) ((u64)(v))
@@ -177,6 +182,15 @@ struct octeon_pci_console_desc {
        __cvmx_bootmem_desc_get(oct, addr,                               \
                offsetof(struct cvmx_bootmem_named_block_desc, field),   \
                SIZEOF_FIELD(struct cvmx_bootmem_named_block_desc, field))
+/**
+ * \brief determines if a given console has debug enabled.
+ * @param console console to check
+ * @returns  1 = enabled. 0 otherwise
+ */
+static int octeon_console_debug_enabled(u32 console)
+{
+       return (console_bitmask >> (console)) & 0x1;
+}
 
 /**
  * This function is the implementation of the get macros defined
@@ -709,3 +723,104 @@ static int octeon_console_read(struct octeon_device *oct, u32 console_num,
 
        return bytes_to_read;
 }
+
+#define FBUF_SIZE      (4 * 1024 * 1024)
+u8 fbuf[FBUF_SIZE];
+
+int octeon_download_firmware(struct octeon_device *oct, const u8 *data,
+                            size_t size)
+{
+       int ret = 0;
+       u8 *p = fbuf;
+       u32 crc32_result;
+       u64 load_addr;
+       u32 image_len;
+       struct octeon_firmware_file_header *h;
+       u32 i, rem;
+
+       if (size < sizeof(struct octeon_firmware_file_header)) {
+               dev_err(&oct->pci_dev->dev, "Firmware file too small (%d < %d).\n",
+                       (u32)size,
+                       (u32)sizeof(struct octeon_firmware_file_header));
+               return -EINVAL;
+       }
+
+       h = (struct octeon_firmware_file_header *)data;
+
+       if (be32_to_cpu(h->magic) != LIO_NIC_MAGIC) {
+               dev_err(&oct->pci_dev->dev, "Unrecognized firmware file.\n");
+               return -EINVAL;
+       }
+
+       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 (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;
+       }
+
+       if (memcmp(LIQUIDIO_BASE_VERSION, h->version + strlen(LIQUIDIO_PACKAGE),
+                  strlen(LIQUIDIO_BASE_VERSION))) {
+               dev_err(&oct->pci_dev->dev, "Unmatched firmware version. Expected %s.x, got %s.\n",
+                       LIQUIDIO_BASE_VERSION,
+                       h->version + strlen(LIQUIDIO_PACKAGE));
+               return -EINVAL;
+       }
+
+       if (be32_to_cpu(h->num_images) > LIO_MAX_IMAGES) {
+               dev_err(&oct->pci_dev->dev, "Too many images in firmware file (%d).\n",
+                       be32_to_cpu(h->num_images));
+               return -EINVAL;
+       }
+
+       dev_info(&oct->pci_dev->dev, "Firmware version: %s\n", h->version);
+       snprintf(oct->fw_info.liquidio_firmware_version, 32, "LIQUIDIO: %s",
+                h->version);
+
+       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);
+
+               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 < FBUF_SIZE)
+                               size = rem;
+                       else
+                               size = FBUF_SIZE;
+
+                       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 */
+       ret = octeon_console_send_cmd(oct, h->bootcmd, 50);
+
+       return 0;
+}
This page took 0.026021 seconds and 5 git commands to generate.