ath9k_htc: introduce support for different fw versions
authorOleksij Rempel <linux@rempel-privat.de>
Sun, 6 Sep 2015 11:09:01 +0000 (13:09 +0200)
committerKalle Valo <kvalo@codeaurora.org>
Fri, 18 Sep 2015 07:40:14 +0000 (10:40 +0300)
Current kernel support only one fw name with theoretically only one
fw version located in “firmware/htc_[9271|7010].fw”. Which is ok so far we
have only one fw version (1.3). After we realised new fw 1.4, we faced
compatibility problem which was decided to solve by firmware name and
location:
- new firmware is located now in
firmware/ath9k_htc/htc_[9271|7010]-1.4.0.fw
- old version 1.3 should be on old place, so old kernel have no issues
with it.
- new kernels including this patch should be able to try different
supported (min..max) fw version.
- new kernel should be able to support old fw location too. At least for
now.

At same time this patch will add new module option which should allow user
to play with development  fw version without replacing stable one. If user
will set “ath9k_htc use_dev_fw=1” module will try to find
firmware/ath9k_htc/htc_[9271|7010]-1.dev.0.fw first and if it fails, use
stable version: for example...1.4.0.fw.

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/ath/ath9k/hif_usb.c
drivers/net/wireless/ath/ath9k/hif_usb.h
drivers/net/wireless/ath/ath9k/htc_drv_init.c

index 10c02f5cbc5eb8ec45abbbbab4c11ad973aabbc1..165dd202c3654412db8dc79745d12fd48b78d29a 100644 (file)
 #include <asm/unaligned.h>
 #include "htc.h"
 
-/* identify firmware images */
-#define FIRMWARE_AR7010_1_1     "htc_7010.fw"
-#define FIRMWARE_AR9271         "htc_9271.fw"
-
-MODULE_FIRMWARE(FIRMWARE_AR7010_1_1);
-MODULE_FIRMWARE(FIRMWARE_AR9271);
+MODULE_FIRMWARE(HTC_7010_MODULE_FW);
+MODULE_FIRMWARE(HTC_9271_MODULE_FW);
 
 static struct usb_device_id ath9k_hif_usb_ids[] = {
        { USB_DEVICE(0x0cf3, 0x9271) }, /* Atheros */
@@ -1080,12 +1076,88 @@ static void ath9k_hif_usb_firmware_fail(struct hif_device_usb *hif_dev)
                device_unlock(parent);
 }
 
+static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context);
+
+/* taken from iwlwifi */
+static int ath9k_hif_request_firmware(struct hif_device_usb *hif_dev,
+                                     bool first)
+{
+       char index[8], *chip;
+       int ret;
+
+       if (first) {
+               if (htc_use_dev_fw) {
+                       hif_dev->fw_minor_index = FIRMWARE_MINOR_IDX_MAX + 1;
+                       sprintf(index, "%s", "dev");
+               } else {
+                       hif_dev->fw_minor_index = FIRMWARE_MINOR_IDX_MAX;
+                       sprintf(index, "%d", hif_dev->fw_minor_index);
+               }
+       } else {
+               hif_dev->fw_minor_index--;
+               sprintf(index, "%d", hif_dev->fw_minor_index);
+       }
+
+       /* test for FW 1.3 */
+       if (MAJOR_VERSION_REQ == 1 && hif_dev->fw_minor_index == 3) {
+               const char *filename;
+
+               if (IS_AR7010_DEVICE(hif_dev->usb_device_id->driver_info))
+                       filename = FIRMWARE_AR7010_1_1;
+               else
+                       filename = FIRMWARE_AR9271;
+
+               /* expected fw locations:
+                * - htc_9271.fw   (stable version 1.3, depricated)
+                */
+               snprintf(hif_dev->fw_name, sizeof(hif_dev->fw_name),
+                        "%s", filename);
+
+       } else if (hif_dev->fw_minor_index < FIRMWARE_MINOR_IDX_MIN) {
+               dev_err(&hif_dev->udev->dev, "no suitable firmware found!\n");
+
+               return -ENOENT;
+       } else {
+               if (IS_AR7010_DEVICE(hif_dev->usb_device_id->driver_info))
+                       chip = "7010";
+               else
+                       chip = "9271";
+
+               /* expected fw locations:
+                * - ath9k_htc/htc_9271-1.dev.0.fw (development version)
+                * - ath9k_htc/htc_9271-1.4.0.fw   (stable version)
+                */
+               snprintf(hif_dev->fw_name, sizeof(hif_dev->fw_name),
+                        "%s/htc_%s-%d.%s.0.fw", HTC_FW_PATH,
+                        chip, MAJOR_VERSION_REQ, index);
+       }
+
+       ret = request_firmware_nowait(THIS_MODULE, true, hif_dev->fw_name,
+                                     &hif_dev->udev->dev, GFP_KERNEL,
+                                     hif_dev, ath9k_hif_usb_firmware_cb);
+       if (ret) {
+               dev_err(&hif_dev->udev->dev,
+                       "ath9k_htc: Async request for firmware %s failed\n",
+                       hif_dev->fw_name);
+               return ret;
+       }
+
+       dev_info(&hif_dev->udev->dev, "ath9k_htc: Firmware %s requested\n",
+                hif_dev->fw_name);
+
+       return ret;
+}
+
 static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context)
 {
        struct hif_device_usb *hif_dev = context;
        int ret;
 
        if (!fw) {
+               ret = ath9k_hif_request_firmware(hif_dev, false);
+               if (!ret)
+                       return;
+
                dev_err(&hif_dev->udev->dev,
                        "ath9k_htc: Failed to get firmware %s\n",
                        hif_dev->fw_name);
@@ -1215,27 +1287,11 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
 
        init_completion(&hif_dev->fw_done);
 
-       /* Find out which firmware to load */
-
-       if (IS_AR7010_DEVICE(id->driver_info))
-               hif_dev->fw_name = FIRMWARE_AR7010_1_1;
-       else
-               hif_dev->fw_name = FIRMWARE_AR9271;
-
-       ret = request_firmware_nowait(THIS_MODULE, true, hif_dev->fw_name,
-                                     &hif_dev->udev->dev, GFP_KERNEL,
-                                     hif_dev, ath9k_hif_usb_firmware_cb);
-       if (ret) {
-               dev_err(&hif_dev->udev->dev,
-                       "ath9k_htc: Async request for firmware %s failed\n",
-                       hif_dev->fw_name);
+       ret = ath9k_hif_request_firmware(hif_dev, true);
+       if (ret)
                goto err_fw_req;
-       }
 
-       dev_info(&hif_dev->udev->dev, "ath9k_htc: Firmware %s requested\n",
-                hif_dev->fw_name);
-
-       return 0;
+       return ret;
 
 err_fw_req:
        usb_set_intfdata(interface, NULL);
index 51496e74b83eaf3521230421f3a07350c385e3d4..7c2ef7ecd98b4986f7818d862c772d70c219faa6 100644 (file)
 #ifndef HTC_USB_H
 #define HTC_USB_H
 
+/* old firmware images */
+#define FIRMWARE_AR7010_1_1     "htc_7010.fw"
+#define FIRMWARE_AR9271         "htc_9271.fw"
+
+/* supported Major FW version */
 #define MAJOR_VERSION_REQ 1
 #define MINOR_VERSION_REQ 3
+/* minimal and maximal supported Minor FW version. */
+#define FIRMWARE_MINOR_IDX_MAX  4
+#define FIRMWARE_MINOR_IDX_MIN  3
+#define HTC_FW_PATH    "ath9k_htc"
+
+#define HTC_9271_MODULE_FW  HTC_FW_PATH "/htc_9271-" \
+                       __stringify(MAJOR_VERSION_REQ) \
+                       "." __stringify(FIRMWARE_MINOR_IDX_MAX) ".0.fw"
+#define HTC_7010_MODULE_FW  HTC_FW_PATH "/htc_7010-" \
+                       __stringify(MAJOR_VERSION_REQ) \
+                       "." __stringify(FIRMWARE_MINOR_IDX_MAX) ".0.fw"
+
+extern int htc_use_dev_fw;
 
 #define IS_AR7010_DEVICE(_v) (((_v) == AR9280_USB) || ((_v) == AR9287_USB))
 
@@ -101,7 +119,8 @@ struct hif_device_usb {
        struct usb_anchor reg_in_submitted;
        struct usb_anchor mgmt_submitted;
        struct sk_buff *remain_skb;
-       const char *fw_name;
+       char fw_name[32];
+       int fw_minor_index;
        int rx_remain_len;
        int rx_pkt_len;
        int rx_transfer_len;
index 1e84882f8c5b35374df2a6460aada9bfac1bfa5a..efe77db965706d4bda349a72aff5336f64d80b2f 100644 (file)
@@ -38,6 +38,10 @@ static int ath9k_ps_enable;
 module_param_named(ps_enable, ath9k_ps_enable, int, 0444);
 MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave");
 
+int htc_use_dev_fw = 0;
+module_param_named(use_dev_fw, htc_use_dev_fw, int, 0444);
+MODULE_PARM_DESC(use_dev_fw, "Use development FW version");
+
 #ifdef CONFIG_MAC80211_LEDS
 int ath9k_htc_led_blink = 1;
 module_param_named(blink, ath9k_htc_led_blink, int, 0444);