ath10k: check chip id from the soc register during probe
authorKalle Valo <kvalo@qca.qualcomm.com>
Sun, 1 Sep 2013 08:22:14 +0000 (11:22 +0300)
committerKalle Valo <kvalo@qca.qualcomm.com>
Tue, 3 Sep 2013 06:54:16 +0000 (09:54 +0300)
ath10k doesn't support qca988x hw1.0 boards anymore. Unfortunately
the PCI id is the same in hw1.0 and hw2.0 so ath10k tries to use
hw1.0 boards anyway. But without hw1.0 workarounds in place
ath10k just crashes horribly.

To avoid using hw1.0 boards at all add a chip id detection
and fail the probe if hw1.0 is detected:

[ 5265.786408] ath10k: ERROR: qca988x hw1.0 is not supported
[ 5265.786497] ath10k: Unsupported chip id 0x043200ff
[ 5265.786574] ath10k: could not register driver core (-95)
[ 5265.793191] ath10k_pci: probe of 0000:02:00.0 failed with error -95

Also add a warning if there's an unknown chip id but continue
the boot process normally anyway.

Reported-by: Zaki Bakar <zaki.bm@gmail.com>
Tested-by: Christian Lamparter <chunkeey@googlemail.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
drivers/net/wireless/ath/ath10k/core.c
drivers/net/wireless/ath/ath10k/core.h
drivers/net/wireless/ath/ath10k/hw.h
drivers/net/wireless/ath/ath10k/pci.c

index 04c132e9f21962324c09ad705351d7a477ffca04..2dd39a82ae99e3f071b9edf4818727ae77a63fa8 100644 (file)
@@ -706,10 +706,43 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
        return 0;
 }
 
-int ath10k_core_register(struct ath10k *ar)
+static int ath10k_core_check_chip_id(struct ath10k *ar)
+{
+       u32 hw_revision = MS(ar->chip_id, SOC_CHIP_ID_REV);
+
+       /* Check that we are not using hw1.0 (some of them have same pci id
+        * as hw2.0) before doing anything else as ath10k crashes horribly
+        * due to missing hw1.0 workarounds. */
+       switch (hw_revision) {
+       case QCA988X_HW_1_0_CHIP_ID_REV:
+               ath10k_err("ERROR: qca988x hw1.0 is not supported\n");
+               return -EOPNOTSUPP;
+
+       case QCA988X_HW_2_0_CHIP_ID_REV:
+               /* known hardware revision, continue normally */
+               return 0;
+
+       default:
+               ath10k_warn("Warning: hardware revision unknown (0x%x), expect problems\n",
+                           ar->chip_id);
+               return 0;
+       }
+
+       return 0;
+}
+
+int ath10k_core_register(struct ath10k *ar, u32 chip_id)
 {
        int status;
 
+       ar->chip_id = chip_id;
+
+       status = ath10k_core_check_chip_id(ar);
+       if (status) {
+               ath10k_err("Unsupported chip id 0x%08x\n", ar->chip_id);
+               return status;
+       }
+
        status = ath10k_core_probe_fw(ar);
        if (status) {
                ath10k_err("could not probe fw (%d)\n", status);
index ab05c4c1b0fa4e2ec5767b4f1f53c2105afbddd1..174c4b40422341e685de0bbe860c3005a711e65f 100644 (file)
@@ -284,6 +284,7 @@ struct ath10k {
        struct device *dev;
        u8 mac_addr[ETH_ALEN];
 
+       u32 chip_id;
        u32 target_version;
        u8 fw_version_major;
        u32 fw_version_minor;
@@ -403,7 +404,7 @@ void ath10k_core_destroy(struct ath10k *ar);
 
 int ath10k_core_start(struct ath10k *ar);
 void ath10k_core_stop(struct ath10k *ar);
-int ath10k_core_register(struct ath10k *ar);
+int ath10k_core_register(struct ath10k *ar, u32 chip_id);
 void ath10k_core_unregister(struct ath10k *ar);
 
 #endif /* _CORE_H_ */
index 5708888486eb8ab957276e9d428826a4beeed759..643f0c9f052bde9dbc934e6da6a1e244805eb121 100644 (file)
 #define SUPPORTED_FW_RELEASE   0
 #define SUPPORTED_FW_BUILD     636
 
+/* QCA988X 1.0 definitions (unsupported) */
+#define QCA988X_HW_1_0_CHIP_ID_REV     0x0
+
 /* QCA988X 2.0 definitions */
 #define QCA988X_HW_2_0_VERSION         0x4100016c
+#define QCA988X_HW_2_0_CHIP_ID_REV     0x2
 #define QCA988X_HW_2_0_FW_DIR          "ath10k/QCA988X/hw2.0"
 #define QCA988X_HW_2_0_FW_FILE         "firmware.bin"
 #define QCA988X_HW_2_0_OTP_FILE                "otp.bin"
@@ -164,6 +168,10 @@ enum ath10k_mcast2ucast_mode {
 #define SOC_LPO_CAL_ENABLE_LSB                 20
 #define SOC_LPO_CAL_ENABLE_MASK                        0x00100000
 
+#define SOC_CHIP_ID_ADDRESS                    0x000000ec
+#define SOC_CHIP_ID_REV_LSB                    8
+#define SOC_CHIP_ID_REV_MASK                   0x00000f00
+
 #define WLAN_RESET_CONTROL_COLD_RST_MASK       0x00000008
 #define WLAN_RESET_CONTROL_WARM_RST_MASK       0x00000004
 #define WLAN_SYSTEM_SLEEP_DISABLE_LSB          0
index 29ccd0479825e0bed05d16fae4180c496d4a8108..622901d5237fbbb4de17ab0f7cda99cab2cae894 100644 (file)
@@ -2390,7 +2390,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
        int ret = 0;
        struct ath10k *ar;
        struct ath10k_pci *ar_pci;
-       u32 lcr_val;
+       u32 lcr_val, chip_id;
 
        ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__);
 
@@ -2492,7 +2492,18 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
 
        spin_lock_init(&ar_pci->ce_lock);
 
-       ret = ath10k_core_register(ar);
+       ret = ath10k_do_pci_wake(ar);
+       if (ret) {
+               ath10k_err("Failed to get chip id: %d\n", ret);
+               return ret;
+       }
+
+       chip_id = ath10k_pci_read32(ar,
+                                   RTC_SOC_BASE_ADDRESS + SOC_CHIP_ID_ADDRESS);
+
+       ath10k_do_pci_sleep(ar);
+
+       ret = ath10k_core_register(ar, chip_id);
        if (ret) {
                ath10k_err("could not register driver core (%d)\n", ret);
                goto err_iomap;