]> www.infradead.org Git - users/willy/xarray.git/commitdiff
net: marvell: prestera: try to load previous fw version
authorVadym Kochan <vkochan@marvell.com>
Mon, 31 May 2021 14:32:46 +0000 (17:32 +0300)
committerDavid S. Miller <davem@davemloft.net>
Tue, 1 Jun 2021 22:11:57 +0000 (15:11 -0700)
Lets try to load previous fw version in case the latest one is missing on
existing system.

Signed-off-by: Vadym Kochan <vkochan@marvell.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/marvell/prestera/prestera_pci.c

index 5edd4d2ac67235f46d1c985768d419c014345faa..a250d394da3805066d370e85bbc60be0487c2cf3 100644 (file)
@@ -17,6 +17,9 @@
 #define PRESTERA_SUPP_FW_MAJ_VER       3
 #define PRESTERA_SUPP_FW_MIN_VER       0
 
+#define PRESTERA_PREV_FW_MAJ_VER       2
+#define PRESTERA_PREV_FW_MIN_VER       0
+
 #define PRESTERA_FW_PATH_FMT   "mrvl/prestera/mvsw_prestera_fw-v%u.%u.img"
 
 #define PRESTERA_FW_HDR_MAGIC          0x351D9D06
@@ -172,6 +175,8 @@ struct prestera_fw_evtq {
 };
 
 struct prestera_fw {
+       struct prestera_fw_rev rev_supp;
+       const struct firmware *bin;
        struct workqueue_struct *wq;
        struct prestera_device dev;
        u8 __iomem *ldr_regs;
@@ -595,25 +600,24 @@ static void prestera_fw_rev_parse(const struct prestera_fw_header *hdr,
 static int prestera_fw_rev_check(struct prestera_fw *fw)
 {
        struct prestera_fw_rev *rev = &fw->dev.fw_rev;
-       u16 maj_supp = PRESTERA_SUPP_FW_MAJ_VER;
-       u16 min_supp = PRESTERA_SUPP_FW_MIN_VER;
 
-       if (rev->maj == maj_supp && rev->min >= min_supp)
+       if (rev->maj == fw->rev_supp.maj && rev->min >= fw->rev_supp.min)
                return 0;
 
        dev_err(fw->dev.dev, "Driver supports FW version only '%u.%u.x'",
-               PRESTERA_SUPP_FW_MAJ_VER, PRESTERA_SUPP_FW_MIN_VER);
+               fw->rev_supp.maj, fw->rev_supp.min);
 
        return -EINVAL;
 }
 
-static int prestera_fw_hdr_parse(struct prestera_fw *fw,
-                                const struct firmware *img)
+static int prestera_fw_hdr_parse(struct prestera_fw *fw)
 {
-       struct prestera_fw_header *hdr = (struct prestera_fw_header *)img->data;
        struct prestera_fw_rev *rev = &fw->dev.fw_rev;
+       struct prestera_fw_header *hdr;
        u32 magic;
 
+       hdr = (struct prestera_fw_header *)fw->bin->data;
+
        magic = be32_to_cpu(hdr->magic_number);
        if (magic != PRESTERA_FW_HDR_MAGIC) {
                dev_err(fw->dev.dev, "FW img hdr magic is invalid");
@@ -628,11 +632,52 @@ static int prestera_fw_hdr_parse(struct prestera_fw *fw,
        return prestera_fw_rev_check(fw);
 }
 
+static int prestera_fw_get(struct prestera_fw *fw)
+{
+       int ver_maj = PRESTERA_SUPP_FW_MAJ_VER;
+       int ver_min = PRESTERA_SUPP_FW_MIN_VER;
+       char fw_path[128];
+       int err;
+
+pick_fw_ver:
+       snprintf(fw_path, sizeof(fw_path), PRESTERA_FW_PATH_FMT,
+                ver_maj, ver_min);
+
+       err = request_firmware_direct(&fw->bin, fw_path, fw->dev.dev);
+       if (err) {
+               if (ver_maj == PRESTERA_SUPP_FW_MAJ_VER) {
+                       ver_maj = PRESTERA_PREV_FW_MAJ_VER;
+                       ver_min = PRESTERA_PREV_FW_MIN_VER;
+
+                       dev_warn(fw->dev.dev,
+                                "missing latest %s firmware, fall-back to previous %u.%u version\n",
+                                fw_path, ver_maj, ver_min);
+
+                       goto pick_fw_ver;
+               } else {
+                       dev_err(fw->dev.dev, "failed to request previous firmware: %s\n",
+                               fw_path);
+                       return err;
+               }
+       }
+
+       dev_info(fw->dev.dev, "Loading %s ...", fw_path);
+
+       fw->rev_supp.maj = ver_maj;
+       fw->rev_supp.min = ver_min;
+       fw->rev_supp.sub = 0;
+
+       return 0;
+}
+
+static void prestera_fw_put(struct prestera_fw *fw)
+{
+       release_firmware(fw->bin);
+}
+
 static int prestera_fw_load(struct prestera_fw *fw)
 {
        size_t hlen = sizeof(struct prestera_fw_header);
-       const struct firmware *f;
-       char fw_path[128];
        int err;
 
        err = prestera_ldr_wait_reg32(fw, PRESTERA_LDR_READY_REG,
@@ -651,30 +696,24 @@ static int prestera_fw_load(struct prestera_fw *fw)
 
        fw->ldr_wr_idx = 0;
 
-       snprintf(fw_path, sizeof(fw_path), PRESTERA_FW_PATH_FMT,
-                PRESTERA_SUPP_FW_MAJ_VER, PRESTERA_SUPP_FW_MIN_VER);
-
-       err = request_firmware_direct(&f, fw_path, fw->dev.dev);
-       if (err) {
-               dev_err(fw->dev.dev, "failed to request firmware file\n");
+       err = prestera_fw_get(fw);
+       if (err)
                return err;
-       }
 
-       err = prestera_fw_hdr_parse(fw, f);
+       err = prestera_fw_hdr_parse(fw);
        if (err) {
                dev_err(fw->dev.dev, "FW image header is invalid\n");
                goto out_release;
        }
 
-       prestera_ldr_write(fw, PRESTERA_LDR_IMG_SIZE_REG, f->size - hlen);
+       prestera_ldr_write(fw, PRESTERA_LDR_IMG_SIZE_REG, fw->bin->size - hlen);
        prestera_ldr_write(fw, PRESTERA_LDR_CTL_REG, PRESTERA_LDR_CTL_DL_START);
 
-       dev_info(fw->dev.dev, "Loading %s ...", fw_path);
-
-       err = prestera_ldr_fw_send(fw, f->data + hlen, f->size - hlen);
+       err = prestera_ldr_fw_send(fw, fw->bin->data + hlen,
+                                  fw->bin->size - hlen);
 
 out_release:
-       release_firmware(f);
+       prestera_fw_put(fw);
        return err;
 }