wlcore/wl12xx/wl18xx: check min FW version
authorArik Nemtsov <arik@wizery.com>
Mon, 25 Jun 2012 14:46:40 +0000 (17:46 +0300)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 10 Jul 2012 16:10:12 +0000 (12:10 -0400)
Refuse to boot if the FW version is too old. The minimum version is set
per chip, with the option of setting it per PG in the future.

When boot fails because of an old FW, display a helpful message.

Signed-off-by: Arik Nemtsov <arik@wizery.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
drivers/net/wireless/ti/wl12xx/main.c
drivers/net/wireless/ti/wl12xx/wl12xx.h
drivers/net/wireless/ti/wl18xx/main.c
drivers/net/wireless/ti/wl18xx/wl18xx.h
drivers/net/wireless/ti/wlcore/boot.c
drivers/net/wireless/ti/wlcore/wlcore.h

index 47ba2e0017f48ec7c6771508108e43319335a305..1c56d1db0712b948a4b47096557e53bbdb4dba94 100644 (file)
@@ -646,6 +646,9 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
                /* read data preparation is only needed by wl127x */
                wl->ops->prepare_read = wl127x_prepare_read;
 
+               wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, WL127X_IFTYPE_VER,
+                                     WL127X_MAJOR_VER, WL127X_SUBTYPE_VER,
+                                     WL127X_MINOR_VER);
                break;
 
        case CHIP_ID_1271_PG20:
@@ -663,6 +666,9 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
                /* read data preparation is only needed by wl127x */
                wl->ops->prepare_read = wl127x_prepare_read;
 
+               wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, WL127X_IFTYPE_VER,
+                                     WL127X_MAJOR_VER, WL127X_SUBTYPE_VER,
+                                     WL127X_MINOR_VER);
                break;
 
        case CHIP_ID_1283_PG20:
@@ -676,6 +682,9 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
                wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN |
                              WLCORE_QUIRK_TKIP_HEADER_SPACE;
 
+               wlcore_set_min_fw_ver(wl, WL128X_CHIP_VER, WL128X_IFTYPE_VER,
+                                     WL128X_MAJOR_VER, WL128X_SUBTYPE_VER,
+                                     WL128X_MINOR_VER);
                break;
        case CHIP_ID_1283_PG10:
        default:
index de1132410876b976aa31e72b4412ac3a9b166465..26990fb4edeade102151fe8e818c215bc51b25d0 100644 (file)
 
 #include "conf.h"
 
+/* minimum FW required for driver for wl127x */
+#define WL127X_CHIP_VER                6
+#define WL127X_IFTYPE_VER      3
+#define WL127X_MAJOR_VER       10
+#define WL127X_SUBTYPE_VER     2
+#define WL127X_MINOR_VER       115
+
+/* minimum FW required for driver for wl128x */
+#define WL128X_CHIP_VER                7
+#define WL128X_IFTYPE_VER      3
+#define WL128X_MAJOR_VER       10
+#define WL128X_SUBTYPE_VER     2
+#define WL128X_MINOR_VER       115
+
 struct wl127x_rx_mem_pool_addr {
        u32 addr;
        u32 addr_extra;
index 16847eccfe807343b45057fb738d1d43eac52a46..341e878a974b54457bbf88dbd332351e3dffd37b 100644 (file)
@@ -611,6 +611,10 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
                              WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN |
                              WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN |
                              WLCORE_QUIRK_TX_PAD_LAST_FRAME;
+
+               wlcore_set_min_fw_ver(wl, WL18XX_CHIP_VER, WL18XX_IFTYPE_VER,
+                                     WL18XX_MAJOR_VER, WL18XX_SUBTYPE_VER,
+                                     WL18XX_MINOR_VER);
                break;
        case CHIP_ID_185x_PG10:
                wl1271_warning("chip id 0x%x (185x PG10) is deprecated",
index bc67a4750615271f45b68d664a04a5aab3324251..6452396fa1d411d4e37b9c82e37046589dc26044 100644 (file)
 
 #include "conf.h"
 
+/* minimum FW required for driver */
+#define WL18XX_CHIP_VER                8
+#define WL18XX_IFTYPE_VER      2
+#define WL18XX_MAJOR_VER       0
+#define WL18XX_SUBTYPE_VER     0
+#define WL18XX_MINOR_VER       100
+
 #define WL18XX_CMD_MAX_SIZE          740
 
 struct wl18xx_priv {
index 8965960b841a2b35c0be34c823a9a6a08aee7082..61113291a89034cd94a1b62db2333dc7fe3a2be8 100644 (file)
@@ -81,6 +81,53 @@ out:
        return ret;
 }
 
+static int wlcore_validate_fw_ver(struct wl1271 *wl)
+{
+       unsigned int *fw_ver = wl->chip.fw_ver;
+       unsigned int *min_ver = wl->min_fw_ver;
+
+       /* the chip must be exactly equal */
+       if (min_ver[FW_VER_CHIP] != fw_ver[FW_VER_CHIP])
+               goto fail;
+
+       /* always check the next digit if all previous ones are equal */
+
+       if (min_ver[FW_VER_IF_TYPE] < fw_ver[FW_VER_IF_TYPE])
+               goto out;
+       else if (min_ver[FW_VER_IF_TYPE] > fw_ver[FW_VER_IF_TYPE])
+               goto fail;
+
+       if (min_ver[FW_VER_MAJOR] < fw_ver[FW_VER_MAJOR])
+               goto out;
+       else if (min_ver[FW_VER_MAJOR] > fw_ver[FW_VER_MAJOR])
+               goto fail;
+
+       if (min_ver[FW_VER_SUBTYPE] < fw_ver[FW_VER_SUBTYPE])
+               goto out;
+       else if (min_ver[FW_VER_SUBTYPE] > fw_ver[FW_VER_SUBTYPE])
+               goto fail;
+
+       if (min_ver[FW_VER_MINOR] < fw_ver[FW_VER_MINOR])
+               goto out;
+       else if (min_ver[FW_VER_MINOR] > fw_ver[FW_VER_MINOR])
+               goto fail;
+
+out:
+       return 0;
+
+fail:
+       wl1271_error("Your WiFi FW version (%u.%u.%u.%u.%u) is outdated.\n"
+                    "Please use at least FW %u.%u.%u.%u.%u.\n"
+                    "You can get more information at:\n"
+                    "http://wireless.kernel.org/en/users/Drivers/wl12xx",
+                    fw_ver[FW_VER_CHIP], fw_ver[FW_VER_IF_TYPE],
+                    fw_ver[FW_VER_MAJOR], fw_ver[FW_VER_SUBTYPE],
+                    fw_ver[FW_VER_MINOR], min_ver[FW_VER_CHIP],
+                    min_ver[FW_VER_IF_TYPE], min_ver[FW_VER_MAJOR],
+                    min_ver[FW_VER_SUBTYPE], min_ver[FW_VER_MINOR]);
+       return -EINVAL;
+}
+
 static int wlcore_boot_static_data(struct wl1271 *wl)
 {
        struct wl1271_static_data *static_data;
@@ -101,6 +148,10 @@ static int wlcore_boot_static_data(struct wl1271 *wl)
        if (ret < 0)
                goto out_free;
 
+       ret = wlcore_validate_fw_ver(wl);
+       if (ret < 0)
+               goto out_free;
+
        ret = wlcore_handle_static_data(wl, static_data);
        if (ret < 0)
                goto out_free;
index 216bdb0f2756ea4d7899a9df60eb1d1687fd4f53..942cef13d8f4a53ca04f839e0ca78fd887def19d 100644 (file)
@@ -390,6 +390,9 @@ struct wl1271 {
 
        /* sleep auth value currently configured to FW */
        int sleep_auth;
+
+       /* the minimum FW version required for the driver to work */
+       unsigned int min_fw_ver[NUM_FW_VER];
 };
 
 int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev);
@@ -408,6 +411,18 @@ wlcore_set_ht_cap(struct wl1271 *wl, enum ieee80211_band band,
        memcpy(&wl->ht_cap[band], ht_cap, sizeof(*ht_cap));
 }
 
+static inline void
+wlcore_set_min_fw_ver(struct wl1271 *wl, unsigned int chip,
+                     unsigned int iftype, unsigned int major,
+                     unsigned int subtype, unsigned int minor)
+{
+       wl->min_fw_ver[FW_VER_CHIP] = chip;
+       wl->min_fw_ver[FW_VER_IF_TYPE] = iftype;
+       wl->min_fw_ver[FW_VER_MAJOR] = major;
+       wl->min_fw_ver[FW_VER_SUBTYPE] = subtype;
+       wl->min_fw_ver[FW_VER_MINOR] = minor;
+}
+
 /* Firmware image load chunk size */
 #define CHUNK_SIZE     16384