|
Thomas Bogendoerfer |
62cde4 |
From: Sudarsana Reddy Kalluru <sudarsana.kalluru@cavium.com>
|
|
Thomas Bogendoerfer |
62cde4 |
Date: Wed, 28 Mar 2018 05:14:22 -0700
|
|
Thomas Bogendoerfer |
62cde4 |
Subject: qed: Adapter flash update support.
|
|
Thomas Bogendoerfer |
62cde4 |
Patch-mainline: v4.17-rc1
|
|
Thomas Bogendoerfer |
62cde4 |
Git-commit: 3a69cae80cdd1b5c8b23137cba2a80ecfec4cef5
|
|
Thomas Bogendoerfer |
62cde4 |
References: bsc#1086314 FATE#324886 bsc#1086313 FATE#324885 bsc#1086301 FATE#3248881
|
|
Thomas Bogendoerfer |
62cde4 |
|
|
Thomas Bogendoerfer |
62cde4 |
This patch adds the required driver support for updating the flash or
|
|
Thomas Bogendoerfer |
62cde4 |
non volatile memory of the adapter. At highlevel, flash upgrade comprises
|
|
Thomas Bogendoerfer |
62cde4 |
of reading the flash images from the input file, validating the images and
|
|
Thomas Bogendoerfer |
62cde4 |
writing them to the respective paritions.
|
|
Thomas Bogendoerfer |
62cde4 |
|
|
Thomas Bogendoerfer |
62cde4 |
Signed-off-by: Sudarsana Reddy Kalluru <Sudarsana.Kalluru@cavium.com>
|
|
Thomas Bogendoerfer |
62cde4 |
Signed-off-by: Ariel Elior <ariel.elior@cavium.com>
|
|
Thomas Bogendoerfer |
62cde4 |
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
Thomas Bogendoerfer |
62cde4 |
Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
|
|
Thomas Bogendoerfer |
62cde4 |
---
|
|
Thomas Bogendoerfer |
62cde4 |
drivers/net/ethernet/qlogic/qed/qed_main.c | 338 +++++++++++++++++++++++++++++
|
|
Thomas Bogendoerfer |
62cde4 |
include/linux/qed/qed_if.h | 19 +
|
|
Thomas Bogendoerfer |
62cde4 |
2 files changed, 357 insertions(+)
|
|
Thomas Bogendoerfer |
62cde4 |
|
|
Thomas Bogendoerfer |
62cde4 |
--- a/drivers/net/ethernet/qlogic/qed/qed_main.c
|
|
Thomas Bogendoerfer |
62cde4 |
+++ b/drivers/net/ethernet/qlogic/qed/qed_main.c
|
|
Thomas Bogendoerfer |
62cde4 |
@@ -45,6 +45,7 @@
|
|
Thomas Bogendoerfer |
62cde4 |
#include <linux/etherdevice.h>
|
|
Thomas Bogendoerfer |
62cde4 |
#include <linux/vmalloc.h>
|
|
Thomas Bogendoerfer |
62cde4 |
#include <linux/crash_dump.h>
|
|
Thomas Bogendoerfer |
62cde4 |
+#include <linux/crc32.h>
|
|
Thomas Bogendoerfer |
62cde4 |
#include <linux/qed/qed_if.h>
|
|
Thomas Bogendoerfer |
62cde4 |
#include <linux/qed/qed_ll2_if.h>
|
|
Thomas Bogendoerfer |
62cde4 |
|
|
Thomas Bogendoerfer |
62cde4 |
@@ -1553,6 +1554,342 @@ static int qed_drain(struct qed_dev *cde
|
|
Thomas Bogendoerfer |
62cde4 |
return 0;
|
|
Thomas Bogendoerfer |
62cde4 |
}
|
|
Thomas Bogendoerfer |
62cde4 |
|
|
Thomas Bogendoerfer |
62cde4 |
+static u32 qed_nvm_flash_image_access_crc(struct qed_dev *cdev,
|
|
Thomas Bogendoerfer |
62cde4 |
+ struct qed_nvm_image_att *nvm_image,
|
|
Thomas Bogendoerfer |
62cde4 |
+ u32 *crc)
|
|
Thomas Bogendoerfer |
62cde4 |
+{
|
|
Thomas Bogendoerfer |
62cde4 |
+ u8 *buf = NULL;
|
|
Thomas Bogendoerfer |
62cde4 |
+ int rc, j;
|
|
Thomas Bogendoerfer |
62cde4 |
+ u32 val;
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ /* Allocate a buffer for holding the nvram image */
|
|
Thomas Bogendoerfer |
62cde4 |
+ buf = kzalloc(nvm_image->length, GFP_KERNEL);
|
|
Thomas Bogendoerfer |
62cde4 |
+ if (!buf)
|
|
Thomas Bogendoerfer |
62cde4 |
+ return -ENOMEM;
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ /* Read image into buffer */
|
|
Thomas Bogendoerfer |
62cde4 |
+ rc = qed_mcp_nvm_read(cdev, nvm_image->start_addr,
|
|
Thomas Bogendoerfer |
62cde4 |
+ buf, nvm_image->length);
|
|
Thomas Bogendoerfer |
62cde4 |
+ if (rc) {
|
|
Thomas Bogendoerfer |
62cde4 |
+ DP_ERR(cdev, "Failed reading image from nvm\n");
|
|
Thomas Bogendoerfer |
62cde4 |
+ goto out;
|
|
Thomas Bogendoerfer |
62cde4 |
+ }
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ /* Convert the buffer into big-endian format (excluding the
|
|
Thomas Bogendoerfer |
62cde4 |
+ * closing 4 bytes of CRC).
|
|
Thomas Bogendoerfer |
62cde4 |
+ */
|
|
Thomas Bogendoerfer |
62cde4 |
+ for (j = 0; j < nvm_image->length - 4; j += 4) {
|
|
Thomas Bogendoerfer |
62cde4 |
+ val = cpu_to_be32(*(u32 *)&buf[j]);
|
|
Thomas Bogendoerfer |
62cde4 |
+ *(u32 *)&buf[j] = val;
|
|
Thomas Bogendoerfer |
62cde4 |
+ }
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ /* Calc CRC for the "actual" image buffer, i.e. not including
|
|
Thomas Bogendoerfer |
62cde4 |
+ * the last 4 CRC bytes.
|
|
Thomas Bogendoerfer |
62cde4 |
+ */
|
|
Thomas Bogendoerfer |
62cde4 |
+ *crc = (~cpu_to_be32(crc32(0xffffffff, buf, nvm_image->length - 4)));
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+out:
|
|
Thomas Bogendoerfer |
62cde4 |
+ kfree(buf);
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ return rc;
|
|
Thomas Bogendoerfer |
62cde4 |
+}
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+/* Binary file format -
|
|
Thomas Bogendoerfer |
62cde4 |
+ * /----------------------------------------------------------------------\
|
|
Thomas Bogendoerfer |
62cde4 |
+ * 0B | 0x4 [command index] |
|
|
Thomas Bogendoerfer |
62cde4 |
+ * 4B | image_type | Options | Number of register settings |
|
|
Thomas Bogendoerfer |
62cde4 |
+ * 8B | Value |
|
|
Thomas Bogendoerfer |
62cde4 |
+ * 12B | Mask |
|
|
Thomas Bogendoerfer |
62cde4 |
+ * 16B | Offset |
|
|
Thomas Bogendoerfer |
62cde4 |
+ * \----------------------------------------------------------------------/
|
|
Thomas Bogendoerfer |
62cde4 |
+ * There can be several Value-Mask-Offset sets as specified by 'Number of...'.
|
|
Thomas Bogendoerfer |
62cde4 |
+ * Options - 0'b - Calculate & Update CRC for image
|
|
Thomas Bogendoerfer |
62cde4 |
+ */
|
|
Thomas Bogendoerfer |
62cde4 |
+static int qed_nvm_flash_image_access(struct qed_dev *cdev, const u8 **data,
|
|
Thomas Bogendoerfer |
62cde4 |
+ bool *check_resp)
|
|
Thomas Bogendoerfer |
62cde4 |
+{
|
|
Thomas Bogendoerfer |
62cde4 |
+ struct qed_nvm_image_att nvm_image;
|
|
Thomas Bogendoerfer |
62cde4 |
+ struct qed_hwfn *p_hwfn;
|
|
Thomas Bogendoerfer |
62cde4 |
+ bool is_crc = false;
|
|
Thomas Bogendoerfer |
62cde4 |
+ u32 image_type;
|
|
Thomas Bogendoerfer |
62cde4 |
+ int rc = 0, i;
|
|
Thomas Bogendoerfer |
62cde4 |
+ u16 len;
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ *data += 4;
|
|
Thomas Bogendoerfer |
62cde4 |
+ image_type = **data;
|
|
Thomas Bogendoerfer |
62cde4 |
+ p_hwfn = QED_LEADING_HWFN(cdev);
|
|
Thomas Bogendoerfer |
62cde4 |
+ for (i = 0; i < p_hwfn->nvm_info.num_images; i++)
|
|
Thomas Bogendoerfer |
62cde4 |
+ if (image_type == p_hwfn->nvm_info.image_att[i].image_type)
|
|
Thomas Bogendoerfer |
62cde4 |
+ break;
|
|
Thomas Bogendoerfer |
62cde4 |
+ if (i == p_hwfn->nvm_info.num_images) {
|
|
Thomas Bogendoerfer |
62cde4 |
+ DP_ERR(cdev, "Failed to find nvram image of type %08x\n",
|
|
Thomas Bogendoerfer |
62cde4 |
+ image_type);
|
|
Thomas Bogendoerfer |
62cde4 |
+ return -ENOENT;
|
|
Thomas Bogendoerfer |
62cde4 |
+ }
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ nvm_image.start_addr = p_hwfn->nvm_info.image_att[i].nvm_start_addr;
|
|
Thomas Bogendoerfer |
62cde4 |
+ nvm_image.length = p_hwfn->nvm_info.image_att[i].len;
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ DP_VERBOSE(cdev, NETIF_MSG_DRV,
|
|
Thomas Bogendoerfer |
62cde4 |
+ "Read image %02x; type = %08x; NVM [%08x,...,%08x]\n",
|
|
Thomas Bogendoerfer |
62cde4 |
+ **data, image_type, nvm_image.start_addr,
|
|
Thomas Bogendoerfer |
62cde4 |
+ nvm_image.start_addr + nvm_image.length - 1);
|
|
Thomas Bogendoerfer |
62cde4 |
+ (*data)++;
|
|
Thomas Bogendoerfer |
62cde4 |
+ is_crc = !!(**data & BIT(0));
|
|
Thomas Bogendoerfer |
62cde4 |
+ (*data)++;
|
|
Thomas Bogendoerfer |
62cde4 |
+ len = *((u16 *)*data);
|
|
Thomas Bogendoerfer |
62cde4 |
+ *data += 2;
|
|
Thomas Bogendoerfer |
62cde4 |
+ if (is_crc) {
|
|
Thomas Bogendoerfer |
62cde4 |
+ u32 crc = 0;
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ rc = qed_nvm_flash_image_access_crc(cdev, &nvm_image, &crc;;
|
|
Thomas Bogendoerfer |
62cde4 |
+ if (rc) {
|
|
Thomas Bogendoerfer |
62cde4 |
+ DP_ERR(cdev, "Failed calculating CRC, rc = %d\n", rc);
|
|
Thomas Bogendoerfer |
62cde4 |
+ goto exit;
|
|
Thomas Bogendoerfer |
62cde4 |
+ }
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ rc = qed_mcp_nvm_write(cdev, QED_NVM_WRITE_NVRAM,
|
|
Thomas Bogendoerfer |
62cde4 |
+ (nvm_image.start_addr +
|
|
Thomas Bogendoerfer |
62cde4 |
+ nvm_image.length - 4), (u8 *)&crc, 4);
|
|
Thomas Bogendoerfer |
62cde4 |
+ if (rc)
|
|
Thomas Bogendoerfer |
62cde4 |
+ DP_ERR(cdev, "Failed writing to %08x, rc = %d\n",
|
|
Thomas Bogendoerfer |
62cde4 |
+ nvm_image.start_addr + nvm_image.length - 4, rc);
|
|
Thomas Bogendoerfer |
62cde4 |
+ goto exit;
|
|
Thomas Bogendoerfer |
62cde4 |
+ }
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ /* Iterate over the values for setting */
|
|
Thomas Bogendoerfer |
62cde4 |
+ while (len) {
|
|
Thomas Bogendoerfer |
62cde4 |
+ u32 offset, mask, value, cur_value;
|
|
Thomas Bogendoerfer |
62cde4 |
+ u8 buf[4];
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ value = *((u32 *)*data);
|
|
Thomas Bogendoerfer |
62cde4 |
+ *data += 4;
|
|
Thomas Bogendoerfer |
62cde4 |
+ mask = *((u32 *)*data);
|
|
Thomas Bogendoerfer |
62cde4 |
+ *data += 4;
|
|
Thomas Bogendoerfer |
62cde4 |
+ offset = *((u32 *)*data);
|
|
Thomas Bogendoerfer |
62cde4 |
+ *data += 4;
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ rc = qed_mcp_nvm_read(cdev, nvm_image.start_addr + offset, buf,
|
|
Thomas Bogendoerfer |
62cde4 |
+ 4);
|
|
Thomas Bogendoerfer |
62cde4 |
+ if (rc) {
|
|
Thomas Bogendoerfer |
62cde4 |
+ DP_ERR(cdev, "Failed reading from %08x\n",
|
|
Thomas Bogendoerfer |
62cde4 |
+ nvm_image.start_addr + offset);
|
|
Thomas Bogendoerfer |
62cde4 |
+ goto exit;
|
|
Thomas Bogendoerfer |
62cde4 |
+ }
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ cur_value = le32_to_cpu(*((__le32 *)buf));
|
|
Thomas Bogendoerfer |
62cde4 |
+ DP_VERBOSE(cdev, NETIF_MSG_DRV,
|
|
Thomas Bogendoerfer |
62cde4 |
+ "NVM %08x: %08x -> %08x [Value %08x Mask %08x]\n",
|
|
Thomas Bogendoerfer |
62cde4 |
+ nvm_image.start_addr + offset, cur_value,
|
|
Thomas Bogendoerfer |
62cde4 |
+ (cur_value & ~mask) | (value & mask), value, mask);
|
|
Thomas Bogendoerfer |
62cde4 |
+ value = (value & mask) | (cur_value & ~mask);
|
|
Thomas Bogendoerfer |
62cde4 |
+ rc = qed_mcp_nvm_write(cdev, QED_NVM_WRITE_NVRAM,
|
|
Thomas Bogendoerfer |
62cde4 |
+ nvm_image.start_addr + offset,
|
|
Thomas Bogendoerfer |
62cde4 |
+ (u8 *)&value, 4);
|
|
Thomas Bogendoerfer |
62cde4 |
+ if (rc) {
|
|
Thomas Bogendoerfer |
62cde4 |
+ DP_ERR(cdev, "Failed writing to %08x\n",
|
|
Thomas Bogendoerfer |
62cde4 |
+ nvm_image.start_addr + offset);
|
|
Thomas Bogendoerfer |
62cde4 |
+ goto exit;
|
|
Thomas Bogendoerfer |
62cde4 |
+ }
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ len--;
|
|
Thomas Bogendoerfer |
62cde4 |
+ }
|
|
Thomas Bogendoerfer |
62cde4 |
+exit:
|
|
Thomas Bogendoerfer |
62cde4 |
+ return rc;
|
|
Thomas Bogendoerfer |
62cde4 |
+}
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+/* Binary file format -
|
|
Thomas Bogendoerfer |
62cde4 |
+ * /----------------------------------------------------------------------\
|
|
Thomas Bogendoerfer |
62cde4 |
+ * 0B | 0x3 [command index] |
|
|
Thomas Bogendoerfer |
62cde4 |
+ * 4B | b'0: check_response? | b'1-31 reserved |
|
|
Thomas Bogendoerfer |
62cde4 |
+ * 8B | File-type | reserved |
|
|
Thomas Bogendoerfer |
62cde4 |
+ * \----------------------------------------------------------------------/
|
|
Thomas Bogendoerfer |
62cde4 |
+ * Start a new file of the provided type
|
|
Thomas Bogendoerfer |
62cde4 |
+ */
|
|
Thomas Bogendoerfer |
62cde4 |
+static int qed_nvm_flash_image_file_start(struct qed_dev *cdev,
|
|
Thomas Bogendoerfer |
62cde4 |
+ const u8 **data, bool *check_resp)
|
|
Thomas Bogendoerfer |
62cde4 |
+{
|
|
Thomas Bogendoerfer |
62cde4 |
+ int rc;
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ *data += 4;
|
|
Thomas Bogendoerfer |
62cde4 |
+ *check_resp = !!(**data & BIT(0));
|
|
Thomas Bogendoerfer |
62cde4 |
+ *data += 4;
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ DP_VERBOSE(cdev, NETIF_MSG_DRV,
|
|
Thomas Bogendoerfer |
62cde4 |
+ "About to start a new file of type %02x\n", **data);
|
|
Thomas Bogendoerfer |
62cde4 |
+ rc = qed_mcp_nvm_put_file_begin(cdev, **data);
|
|
Thomas Bogendoerfer |
62cde4 |
+ *data += 4;
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ return rc;
|
|
Thomas Bogendoerfer |
62cde4 |
+}
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+/* Binary file format -
|
|
Thomas Bogendoerfer |
62cde4 |
+ * /----------------------------------------------------------------------\
|
|
Thomas Bogendoerfer |
62cde4 |
+ * 0B | 0x2 [command index] |
|
|
Thomas Bogendoerfer |
62cde4 |
+ * 4B | Length in bytes |
|
|
Thomas Bogendoerfer |
62cde4 |
+ * 8B | b'0: check_response? | b'1-31 reserved |
|
|
Thomas Bogendoerfer |
62cde4 |
+ * 12B | Offset in bytes |
|
|
Thomas Bogendoerfer |
62cde4 |
+ * 16B | Data ... |
|
|
Thomas Bogendoerfer |
62cde4 |
+ * \----------------------------------------------------------------------/
|
|
Thomas Bogendoerfer |
62cde4 |
+ * Write data as part of a file that was previously started. Data should be
|
|
Thomas Bogendoerfer |
62cde4 |
+ * of length equal to that provided in the message
|
|
Thomas Bogendoerfer |
62cde4 |
+ */
|
|
Thomas Bogendoerfer |
62cde4 |
+static int qed_nvm_flash_image_file_data(struct qed_dev *cdev,
|
|
Thomas Bogendoerfer |
62cde4 |
+ const u8 **data, bool *check_resp)
|
|
Thomas Bogendoerfer |
62cde4 |
+{
|
|
Thomas Bogendoerfer |
62cde4 |
+ u32 offset, len;
|
|
Thomas Bogendoerfer |
62cde4 |
+ int rc;
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ *data += 4;
|
|
Thomas Bogendoerfer |
62cde4 |
+ len = *((u32 *)(*data));
|
|
Thomas Bogendoerfer |
62cde4 |
+ *data += 4;
|
|
Thomas Bogendoerfer |
62cde4 |
+ *check_resp = !!(**data & BIT(0));
|
|
Thomas Bogendoerfer |
62cde4 |
+ *data += 4;
|
|
Thomas Bogendoerfer |
62cde4 |
+ offset = *((u32 *)(*data));
|
|
Thomas Bogendoerfer |
62cde4 |
+ *data += 4;
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ DP_VERBOSE(cdev, NETIF_MSG_DRV,
|
|
Thomas Bogendoerfer |
62cde4 |
+ "About to write File-data: %08x bytes to offset %08x\n",
|
|
Thomas Bogendoerfer |
62cde4 |
+ len, offset);
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ rc = qed_mcp_nvm_write(cdev, QED_PUT_FILE_DATA, offset,
|
|
Thomas Bogendoerfer |
62cde4 |
+ (char *)(*data), len);
|
|
Thomas Bogendoerfer |
62cde4 |
+ *data += len;
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ return rc;
|
|
Thomas Bogendoerfer |
62cde4 |
+}
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+/* Binary file format [General header] -
|
|
Thomas Bogendoerfer |
62cde4 |
+ * /----------------------------------------------------------------------\
|
|
Thomas Bogendoerfer |
62cde4 |
+ * 0B | QED_NVM_SIGNATURE |
|
|
Thomas Bogendoerfer |
62cde4 |
+ * 4B | Length in bytes |
|
|
Thomas Bogendoerfer |
62cde4 |
+ * 8B | Highest command in this batchfile | Reserved |
|
|
Thomas Bogendoerfer |
62cde4 |
+ * \----------------------------------------------------------------------/
|
|
Thomas Bogendoerfer |
62cde4 |
+ */
|
|
Thomas Bogendoerfer |
62cde4 |
+static int qed_nvm_flash_image_validate(struct qed_dev *cdev,
|
|
Thomas Bogendoerfer |
62cde4 |
+ const struct firmware *image,
|
|
Thomas Bogendoerfer |
62cde4 |
+ const u8 **data)
|
|
Thomas Bogendoerfer |
62cde4 |
+{
|
|
Thomas Bogendoerfer |
62cde4 |
+ u32 signature, len;
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ /* Check minimum size */
|
|
Thomas Bogendoerfer |
62cde4 |
+ if (image->size < 12) {
|
|
Thomas Bogendoerfer |
62cde4 |
+ DP_ERR(cdev, "Image is too short [%08x]\n", (u32)image->size);
|
|
Thomas Bogendoerfer |
62cde4 |
+ return -EINVAL;
|
|
Thomas Bogendoerfer |
62cde4 |
+ }
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ /* Check signature */
|
|
Thomas Bogendoerfer |
62cde4 |
+ signature = *((u32 *)(*data));
|
|
Thomas Bogendoerfer |
62cde4 |
+ if (signature != QED_NVM_SIGNATURE) {
|
|
Thomas Bogendoerfer |
62cde4 |
+ DP_ERR(cdev, "Wrong signature '%08x'\n", signature);
|
|
Thomas Bogendoerfer |
62cde4 |
+ return -EINVAL;
|
|
Thomas Bogendoerfer |
62cde4 |
+ }
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ *data += 4;
|
|
Thomas Bogendoerfer |
62cde4 |
+ /* Validate internal size equals the image-size */
|
|
Thomas Bogendoerfer |
62cde4 |
+ len = *((u32 *)(*data));
|
|
Thomas Bogendoerfer |
62cde4 |
+ if (len != image->size) {
|
|
Thomas Bogendoerfer |
62cde4 |
+ DP_ERR(cdev, "Size mismatch: internal = %08x image = %08x\n",
|
|
Thomas Bogendoerfer |
62cde4 |
+ len, (u32)image->size);
|
|
Thomas Bogendoerfer |
62cde4 |
+ return -EINVAL;
|
|
Thomas Bogendoerfer |
62cde4 |
+ }
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ *data += 4;
|
|
Thomas Bogendoerfer |
62cde4 |
+ /* Make sure driver familiar with all commands necessary for this */
|
|
Thomas Bogendoerfer |
62cde4 |
+ if (*((u16 *)(*data)) >= QED_NVM_FLASH_CMD_NVM_MAX) {
|
|
Thomas Bogendoerfer |
62cde4 |
+ DP_ERR(cdev, "File contains unsupported commands [Need %04x]\n",
|
|
Thomas Bogendoerfer |
62cde4 |
+ *((u16 *)(*data)));
|
|
Thomas Bogendoerfer |
62cde4 |
+ return -EINVAL;
|
|
Thomas Bogendoerfer |
62cde4 |
+ }
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ *data += 4;
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ return 0;
|
|
Thomas Bogendoerfer |
62cde4 |
+}
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+static int qed_nvm_flash(struct qed_dev *cdev, const char *name)
|
|
Thomas Bogendoerfer |
62cde4 |
+{
|
|
Thomas Bogendoerfer |
62cde4 |
+ const struct firmware *image;
|
|
Thomas Bogendoerfer |
62cde4 |
+ const u8 *data, *data_end;
|
|
Thomas Bogendoerfer |
62cde4 |
+ u32 cmd_type;
|
|
Thomas Bogendoerfer |
62cde4 |
+ int rc;
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ rc = request_firmware(&image, name, &cdev->pdev->dev);
|
|
Thomas Bogendoerfer |
62cde4 |
+ if (rc) {
|
|
Thomas Bogendoerfer |
62cde4 |
+ DP_ERR(cdev, "Failed to find '%s'\n", name);
|
|
Thomas Bogendoerfer |
62cde4 |
+ return rc;
|
|
Thomas Bogendoerfer |
62cde4 |
+ }
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ DP_VERBOSE(cdev, NETIF_MSG_DRV,
|
|
Thomas Bogendoerfer |
62cde4 |
+ "Flashing '%s' - firmware's data at %p, size is %08x\n",
|
|
Thomas Bogendoerfer |
62cde4 |
+ name, image->data, (u32)image->size);
|
|
Thomas Bogendoerfer |
62cde4 |
+ data = image->data;
|
|
Thomas Bogendoerfer |
62cde4 |
+ data_end = data + image->size;
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ rc = qed_nvm_flash_image_validate(cdev, image, &data);
|
|
Thomas Bogendoerfer |
62cde4 |
+ if (rc)
|
|
Thomas Bogendoerfer |
62cde4 |
+ goto exit;
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ while (data < data_end) {
|
|
Thomas Bogendoerfer |
62cde4 |
+ bool check_resp = false;
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ /* Parse the actual command */
|
|
Thomas Bogendoerfer |
62cde4 |
+ cmd_type = *((u32 *)data);
|
|
Thomas Bogendoerfer |
62cde4 |
+ switch (cmd_type) {
|
|
Thomas Bogendoerfer |
62cde4 |
+ case QED_NVM_FLASH_CMD_FILE_DATA:
|
|
Thomas Bogendoerfer |
62cde4 |
+ rc = qed_nvm_flash_image_file_data(cdev, &data,
|
|
Thomas Bogendoerfer |
62cde4 |
+ &check_resp);
|
|
Thomas Bogendoerfer |
62cde4 |
+ break;
|
|
Thomas Bogendoerfer |
62cde4 |
+ case QED_NVM_FLASH_CMD_FILE_START:
|
|
Thomas Bogendoerfer |
62cde4 |
+ rc = qed_nvm_flash_image_file_start(cdev, &data,
|
|
Thomas Bogendoerfer |
62cde4 |
+ &check_resp);
|
|
Thomas Bogendoerfer |
62cde4 |
+ break;
|
|
Thomas Bogendoerfer |
62cde4 |
+ case QED_NVM_FLASH_CMD_NVM_CHANGE:
|
|
Thomas Bogendoerfer |
62cde4 |
+ rc = qed_nvm_flash_image_access(cdev, &data,
|
|
Thomas Bogendoerfer |
62cde4 |
+ &check_resp);
|
|
Thomas Bogendoerfer |
62cde4 |
+ break;
|
|
Thomas Bogendoerfer |
62cde4 |
+ default:
|
|
Thomas Bogendoerfer |
62cde4 |
+ DP_ERR(cdev, "Unknown command %08x\n", cmd_type);
|
|
Thomas Bogendoerfer |
62cde4 |
+ rc = -EINVAL;
|
|
Thomas Bogendoerfer |
62cde4 |
+ goto exit;
|
|
Thomas Bogendoerfer |
62cde4 |
+ }
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ if (rc) {
|
|
Thomas Bogendoerfer |
62cde4 |
+ DP_ERR(cdev, "Command %08x failed\n", cmd_type);
|
|
Thomas Bogendoerfer |
62cde4 |
+ goto exit;
|
|
Thomas Bogendoerfer |
62cde4 |
+ }
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ /* Check response if needed */
|
|
Thomas Bogendoerfer |
62cde4 |
+ if (check_resp) {
|
|
Thomas Bogendoerfer |
62cde4 |
+ u32 mcp_response = 0;
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ if (qed_mcp_nvm_resp(cdev, (u8 *)&mcp_response)) {
|
|
Thomas Bogendoerfer |
62cde4 |
+ DP_ERR(cdev, "Failed getting MCP response\n");
|
|
Thomas Bogendoerfer |
62cde4 |
+ rc = -EINVAL;
|
|
Thomas Bogendoerfer |
62cde4 |
+ goto exit;
|
|
Thomas Bogendoerfer |
62cde4 |
+ }
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ switch (mcp_response & FW_MSG_CODE_MASK) {
|
|
Thomas Bogendoerfer |
62cde4 |
+ case FW_MSG_CODE_OK:
|
|
Thomas Bogendoerfer |
62cde4 |
+ case FW_MSG_CODE_NVM_OK:
|
|
Thomas Bogendoerfer |
62cde4 |
+ case FW_MSG_CODE_NVM_PUT_FILE_FINISH_OK:
|
|
Thomas Bogendoerfer |
62cde4 |
+ case FW_MSG_CODE_PHY_OK:
|
|
Thomas Bogendoerfer |
62cde4 |
+ break;
|
|
Thomas Bogendoerfer |
62cde4 |
+ default:
|
|
Thomas Bogendoerfer |
62cde4 |
+ DP_ERR(cdev, "MFW returns error: %08x\n",
|
|
Thomas Bogendoerfer |
62cde4 |
+ mcp_response);
|
|
Thomas Bogendoerfer |
62cde4 |
+ rc = -EINVAL;
|
|
Thomas Bogendoerfer |
62cde4 |
+ goto exit;
|
|
Thomas Bogendoerfer |
62cde4 |
+ }
|
|
Thomas Bogendoerfer |
62cde4 |
+ }
|
|
Thomas Bogendoerfer |
62cde4 |
+ }
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+exit:
|
|
Thomas Bogendoerfer |
62cde4 |
+ release_firmware(image);
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+ return rc;
|
|
Thomas Bogendoerfer |
62cde4 |
+}
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
static int qed_nvm_get_image(struct qed_dev *cdev, enum qed_nvm_images type,
|
|
Thomas Bogendoerfer |
62cde4 |
u8 *buf, u16 len)
|
|
Thomas Bogendoerfer |
62cde4 |
{
|
|
Thomas Bogendoerfer |
62cde4 |
@@ -1719,6 +2056,7 @@ const struct qed_common_ops qed_common_o
|
|
Thomas Bogendoerfer |
62cde4 |
.dbg_all_data_size = &qed_dbg_all_data_size,
|
|
Thomas Bogendoerfer |
62cde4 |
.chain_alloc = &qed_chain_alloc,
|
|
Thomas Bogendoerfer |
62cde4 |
.chain_free = &qed_chain_free,
|
|
Thomas Bogendoerfer |
62cde4 |
+ .nvm_flash = &qed_nvm_flash,
|
|
Thomas Bogendoerfer |
62cde4 |
.nvm_get_image = &qed_nvm_get_image,
|
|
Thomas Bogendoerfer |
62cde4 |
.set_coalesce = &qed_set_coalesce,
|
|
Thomas Bogendoerfer |
62cde4 |
.set_led = &qed_set_led,
|
|
Thomas Bogendoerfer |
62cde4 |
--- a/include/linux/qed/qed_if.h
|
|
Thomas Bogendoerfer |
62cde4 |
+++ b/include/linux/qed/qed_if.h
|
|
Thomas Bogendoerfer |
62cde4 |
@@ -483,6 +483,15 @@ struct qed_int_info {
|
|
Thomas Bogendoerfer |
62cde4 |
u8 used_cnt;
|
|
Thomas Bogendoerfer |
62cde4 |
};
|
|
Thomas Bogendoerfer |
62cde4 |
|
|
Thomas Bogendoerfer |
62cde4 |
+#define QED_NVM_SIGNATURE 0x12435687
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+enum qed_nvm_flash_cmd {
|
|
Thomas Bogendoerfer |
62cde4 |
+ QED_NVM_FLASH_CMD_FILE_DATA = 0x2,
|
|
Thomas Bogendoerfer |
62cde4 |
+ QED_NVM_FLASH_CMD_FILE_START = 0x3,
|
|
Thomas Bogendoerfer |
62cde4 |
+ QED_NVM_FLASH_CMD_NVM_CHANGE = 0x4,
|
|
Thomas Bogendoerfer |
62cde4 |
+ QED_NVM_FLASH_CMD_NVM_MAX,
|
|
Thomas Bogendoerfer |
62cde4 |
+};
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
struct qed_common_cb_ops {
|
|
Thomas Bogendoerfer |
62cde4 |
void (*arfs_filter_op)(void *dev, void *fltr, u8 fw_rc);
|
|
Thomas Bogendoerfer |
62cde4 |
void (*link_update)(void *dev,
|
|
Thomas Bogendoerfer |
62cde4 |
@@ -658,6 +667,16 @@ struct qed_common_ops {
|
|
Thomas Bogendoerfer |
62cde4 |
struct qed_chain *p_chain);
|
|
Thomas Bogendoerfer |
62cde4 |
|
|
Thomas Bogendoerfer |
62cde4 |
/**
|
|
Thomas Bogendoerfer |
62cde4 |
+ * @brief nvm_flash - Flash nvm data.
|
|
Thomas Bogendoerfer |
62cde4 |
+ *
|
|
Thomas Bogendoerfer |
62cde4 |
+ * @param cdev
|
|
Thomas Bogendoerfer |
62cde4 |
+ * @param name - file containing the data
|
|
Thomas Bogendoerfer |
62cde4 |
+ *
|
|
Thomas Bogendoerfer |
62cde4 |
+ * @return 0 on success, error otherwise.
|
|
Thomas Bogendoerfer |
62cde4 |
+ */
|
|
Thomas Bogendoerfer |
62cde4 |
+ int (*nvm_flash)(struct qed_dev *cdev, const char *name);
|
|
Thomas Bogendoerfer |
62cde4 |
+
|
|
Thomas Bogendoerfer |
62cde4 |
+/**
|
|
Thomas Bogendoerfer |
62cde4 |
* @brief nvm_get_image - reads an entire image from nvram
|
|
Thomas Bogendoerfer |
62cde4 |
*
|
|
Thomas Bogendoerfer |
62cde4 |
* @param cdev
|