Merge ath-next from ath.git
authorKalle Valo <kvalo@codeaurora.org>
Sun, 19 Jun 2016 08:19:30 +0000 (11:19 +0300)
committerKalle Valo <kvalo@codeaurora.org>
Sun, 19 Jun 2016 08:19:30 +0000 (11:19 +0300)
ath.git patches for 4.8. Major changes:

ath10k

* enable btcoex support without restarting firmware
* enable ipq4019 support using AHB bus
* add QCA9887 chipset support
* retrieve calibration data from EEPROM, currently only for QCA9887

wil6210

* add pm_notify handling

30 files changed:
drivers/net/wireless/ath/ath10k/ahb.c
drivers/net/wireless/ath/ath10k/core.c
drivers/net/wireless/ath/ath10k/core.h
drivers/net/wireless/ath/ath10k/debug.c
drivers/net/wireless/ath/ath10k/hif.h
drivers/net/wireless/ath/ath10k/htt.h
drivers/net/wireless/ath/ath10k/htt_rx.c
drivers/net/wireless/ath/ath10k/hw.c
drivers/net/wireless/ath/ath10k/hw.h
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath10k/pci.c
drivers/net/wireless/ath/ath10k/pci.h
drivers/net/wireless/ath/ath10k/rx_desc.h
drivers/net/wireless/ath/ath10k/targaddrs.h
drivers/net/wireless/ath/ath10k/txrx.c
drivers/net/wireless/ath/ath10k/wmi.c
drivers/net/wireless/ath/ath10k/wmi.h
drivers/net/wireless/ath/ath5k/pcu.c
drivers/net/wireless/ath/ath6kl/core.h
drivers/net/wireless/ath/ath6kl/wmi.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/tx99.c
drivers/net/wireless/ath/wil6210/cfg80211.c
drivers/net/wireless/ath/wil6210/debug.c
drivers/net/wireless/ath/wil6210/p2p.c
drivers/net/wireless/ath/wil6210/pcie_bus.c
drivers/net/wireless/ath/wil6210/pm.c
drivers/net/wireless/ath/wil6210/txrx.c
drivers/net/wireless/ath/wil6210/wil6210.h
drivers/net/wireless/ath/wil6210/wil_platform.h

index bd62bc1..acec16b 100644 (file)
 #include "ahb.h"
 
 static const struct of_device_id ath10k_ahb_of_match[] = {
-       /* TODO: enable this entry once everything in place.
-        * { .compatible = "qcom,ipq4019-wifi",
-        *   .data = (void *)ATH10K_HW_QCA4019 },
-        */
+       { .compatible = "qcom,ipq4019-wifi",
+         .data = (void *)ATH10K_HW_QCA4019
+       },
        { }
 };
 
@@ -476,6 +475,7 @@ static irqreturn_t ath10k_ahb_interrupt_handler(int irq, void *arg)
 
 static int ath10k_ahb_request_irq_legacy(struct ath10k *ar)
 {
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
        int ret;
 
@@ -487,6 +487,7 @@ static int ath10k_ahb_request_irq_legacy(struct ath10k *ar)
                            ar_ahb->irq, ret);
                return ret;
        }
+       ar_pci->oper_irq_mode = ATH10K_PCI_IRQ_LEGACY;
 
        return 0;
 }
@@ -918,8 +919,6 @@ int ath10k_ahb_init(void)
 {
        int ret;
 
-       printk(KERN_ERR "AHB support is still work in progress\n");
-
        ret = platform_driver_register(&ath10k_ahb_driver);
        if (ret)
                printk(KERN_ERR "failed to register ath10k ahb driver: %d\n",
index 49af624..c6291c2 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/module.h>
 #include <linux/firmware.h>
 #include <linux/of.h>
+#include <asm/byteorder.h>
 
 #include "core.h"
 #include "mac.h"
@@ -55,7 +56,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .name = "qca988x hw2.0",
                .patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR,
                .uart_pin = 7,
-               .has_shifted_cc_wraparound = true,
+               .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL,
                .otp_exe_param = 0,
                .channel_counters_freq_hz = 88000,
                .max_probe_resp_desc_thres = 0,
@@ -68,6 +69,25 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                        .board_ext_size = QCA988X_BOARD_EXT_DATA_SZ,
                },
        },
+       {
+               .id = QCA9887_HW_1_0_VERSION,
+               .dev_id = QCA9887_1_0_DEVICE_ID,
+               .name = "qca9887 hw1.0",
+               .patch_load_addr = QCA9887_HW_1_0_PATCH_LOAD_ADDR,
+               .uart_pin = 7,
+               .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL,
+               .otp_exe_param = 0,
+               .channel_counters_freq_hz = 88000,
+               .max_probe_resp_desc_thres = 0,
+               .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_AFTER,
+               .cal_data_len = 2116,
+               .fw = {
+                       .dir = QCA9887_HW_1_0_FW_DIR,
+                       .board = QCA9887_HW_1_0_BOARD_DATA_FILE,
+                       .board_size = QCA9887_BOARD_DATA_SZ,
+                       .board_ext_size = QCA9887_BOARD_EXT_DATA_SZ,
+               },
+       },
        {
                .id = QCA6174_HW_2_1_VERSION,
                .dev_id = QCA6164_2_1_DEVICE_ID,
@@ -148,6 +168,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .uart_pin = 7,
                .otp_exe_param = 0x00000700,
                .continuous_frag_desc = true,
+               .cck_rate_map_rev2 = true,
                .channel_counters_freq_hz = 150000,
                .max_probe_resp_desc_thres = 24,
                .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_BEFORE,
@@ -162,6 +183,29 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                        .board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,
                },
        },
+       {
+               .id = QCA9984_HW_1_0_DEV_VERSION,
+               .dev_id = QCA9984_1_0_DEVICE_ID,
+               .name = "qca9984/qca9994 hw1.0",
+               .patch_load_addr = QCA9984_HW_1_0_PATCH_LOAD_ADDR,
+               .uart_pin = 7,
+               .otp_exe_param = 0x00000700,
+               .continuous_frag_desc = true,
+               .cck_rate_map_rev2 = true,
+               .channel_counters_freq_hz = 150000,
+               .max_probe_resp_desc_thres = 24,
+               .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_BEFORE,
+               .tx_chain_mask = 0xf,
+               .rx_chain_mask = 0xf,
+               .max_spatial_stream = 4,
+               .cal_data_len = 12064,
+               .fw = {
+                       .dir = QCA9984_HW_1_0_FW_DIR,
+                       .board = QCA9984_HW_1_0_BOARD_DATA_FILE,
+                       .board_size = QCA99X0_BOARD_DATA_SZ,
+                       .board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,
+               },
+       },
        {
                .id = QCA9377_HW_1_0_DEV_VERSION,
                .dev_id = QCA9377_1_0_DEVICE_ID,
@@ -202,9 +246,10 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .name = "qca4019 hw1.0",
                .patch_load_addr = QCA4019_HW_1_0_PATCH_LOAD_ADDR,
                .uart_pin = 7,
-               .has_shifted_cc_wraparound = true,
+               .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH,
                .otp_exe_param = 0x0010000,
                .continuous_frag_desc = true,
+               .cck_rate_map_rev2 = true,
                .channel_counters_freq_hz = 125000,
                .max_probe_resp_desc_thres = 24,
                .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_BEFORE,
@@ -236,6 +281,7 @@ static const char *const ath10k_core_fw_feature_str[] = {
        [ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA] = "adaptive-cca",
        [ATH10K_FW_FEATURE_MFP_SUPPORT] = "mfp",
        [ATH10K_FW_FEATURE_PEER_FLOW_CONTROL] = "peer-flow-ctrl",
+       [ATH10K_FW_FEATURE_BTCOEX_PARAM] = "btcoex-param",
 };
 
 static unsigned int ath10k_core_get_fw_feature_str(char *buf,
@@ -531,6 +577,35 @@ out:
        return ret;
 }
 
+static int ath10k_download_cal_eeprom(struct ath10k *ar)
+{
+       size_t data_len;
+       void *data = NULL;
+       int ret;
+
+       ret = ath10k_hif_fetch_cal_eeprom(ar, &data, &data_len);
+       if (ret) {
+               if (ret != -EOPNOTSUPP)
+                       ath10k_warn(ar, "failed to read calibration data from EEPROM: %d\n",
+                                   ret);
+               goto out_free;
+       }
+
+       ret = ath10k_download_board_data(ar, data, data_len);
+       if (ret) {
+               ath10k_warn(ar, "failed to download calibration data from EEPROM: %d\n",
+                           ret);
+               goto out_free;
+       }
+
+       ret = 0;
+
+out_free:
+       kfree(data);
+
+       return ret;
+}
+
 static int ath10k_core_get_board_id_from_otp(struct ath10k *ar)
 {
        u32 result, address;
@@ -1293,7 +1368,17 @@ static int ath10k_download_cal_data(struct ath10k *ar)
        }
 
        ath10k_dbg(ar, ATH10K_DBG_BOOT,
-                  "boot did not find DT entry, try OTP next: %d\n",
+                  "boot did not find DT entry, try target EEPROM next: %d\n",
+                  ret);
+
+       ret = ath10k_download_cal_eeprom(ar);
+       if (ret == 0) {
+               ar->cal_mode = ATH10K_CAL_MODE_EEPROM;
+               goto done;
+       }
+
+       ath10k_dbg(ar, ATH10K_DBG_BOOT,
+                  "boot did not find target EEPROM entry, try OTP next: %d\n",
                   ret);
 
        ret = ath10k_download_and_run_otp(ar);
@@ -1733,6 +1818,16 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
                if (test_bit(WMI_SERVICE_BSS_CHANNEL_INFO_64, ar->wmi.svc_map))
                        val |= WMI_10_4_BSS_CHANNEL_INFO_64;
 
+               /* 10.4 firmware supports BT-Coex without reloading firmware
+                * via pdev param. To support Bluetooth coexistence pdev param,
+                * WMI_COEX_GPIO_SUPPORT of extended resource config should be
+                * enabled always.
+                */
+               if (test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map) &&
+                   test_bit(ATH10K_FW_FEATURE_BTCOEX_PARAM,
+                            ar->running_fw->fw_file.fw_features))
+                       val |= WMI_10_4_COEX_GPIO_SUPPORT;
+
                status = ath10k_mac_ext_resource_config(ar, val);
                if (status) {
                        ath10k_err(ar,
@@ -2062,6 +2157,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
 
        switch (hw_rev) {
        case ATH10K_HW_QCA988X:
+       case ATH10K_HW_QCA9887:
                ar->regs = &qca988x_regs;
                ar->hw_values = &qca988x_values;
                break;
@@ -2071,6 +2167,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
                ar->hw_values = &qca6174_values;
                break;
        case ATH10K_HW_QCA99X0:
+       case ATH10K_HW_QCA9984:
                ar->regs = &qca99x0_regs;
                ar->hw_values = &qca99x0_values;
                break;
@@ -2159,5 +2256,5 @@ void ath10k_core_destroy(struct ath10k *ar)
 EXPORT_SYMBOL(ath10k_core_destroy);
 
 MODULE_AUTHOR("Qualcomm Atheros");
-MODULE_DESCRIPTION("Core module for QCA988X PCIe devices.");
+MODULE_DESCRIPTION("Core module for Qualcomm Atheros 802.11ac wireless LAN cards.");
 MODULE_LICENSE("Dual BSD/GPL");
index 1852e0e..3da18c9 100644 (file)
@@ -535,6 +535,13 @@ enum ath10k_fw_features {
         */
        ATH10K_FW_FEATURE_PEER_FLOW_CONTROL = 13,
 
+       /* Firmware supports BT-Coex without reloading firmware via pdev param.
+        * To support Bluetooth coexistence pdev param, WMI_COEX_GPIO_SUPPORT of
+        * extended resource config should be enabled always. This firmware IE
+        * is used to configure WMI_COEX_GPIO_SUPPORT.
+        */
+       ATH10K_FW_FEATURE_BTCOEX_PARAM = 14,
+
        /* keep last */
        ATH10K_FW_FEATURE_COUNT,
 };
@@ -571,6 +578,7 @@ enum ath10k_cal_mode {
        ATH10K_CAL_MODE_DT,
        ATH10K_PRE_CAL_MODE_FILE,
        ATH10K_PRE_CAL_MODE_DT,
+       ATH10K_CAL_MODE_EEPROM,
 };
 
 enum ath10k_crypt_mode {
@@ -593,6 +601,8 @@ static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode)
                return "pre-cal-file";
        case ATH10K_PRE_CAL_MODE_DT:
                return "pre-cal-dt";
+       case ATH10K_CAL_MODE_EEPROM:
+               return "eeprom";
        }
 
        return "unknown";
@@ -703,12 +713,10 @@ struct ath10k {
                int uart_pin;
                u32 otp_exe_param;
 
-               /* This is true if given HW chip has a quirky Cycle Counter
-                * wraparound which resets to 0x7fffffff instead of 0. All
-                * other CC related counters (e.g. Rx Clear Count) are divided
-                * by 2 so they never wraparound themselves.
+               /* Type of hw cycle counter wraparound logic, for more info
+                * refer enum ath10k_hw_cc_wraparound_type.
                 */
-               bool has_shifted_cc_wraparound;
+               enum ath10k_hw_cc_wraparound_type cc_wraparound_type;
 
                /* Some of chip expects fragment descriptor to be continuous
                 * memory for any TX operation. Set continuous_frag_desc flag
@@ -716,6 +724,12 @@ struct ath10k {
                 */
                bool continuous_frag_desc;
 
+               /* CCK hardware rate table mapping for the newer chipsets
+                * like QCA99X0, QCA4019 got revised. The CCK h/w rate values
+                * are in a proper order with respect to the rate/preamble
+                */
+               bool cck_rate_map_rev2;
+
                u32 channel_counters_freq_hz;
 
                /* Mgmt tx descriptors threshold for limiting probe response
index e251155..8fbb8f2 100644 (file)
@@ -609,25 +609,23 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file,
        char buf[32];
        int ret;
 
-       mutex_lock(&ar->conf_mutex);
-
        simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
 
        /* make sure that buf is null terminated */
        buf[sizeof(buf) - 1] = 0;
 
+       /* drop the possible '\n' from the end */
+       if (buf[count - 1] == '\n')
+               buf[count - 1] = 0;
+
+       mutex_lock(&ar->conf_mutex);
+
        if (ar->state != ATH10K_STATE_ON &&
            ar->state != ATH10K_STATE_RESTARTED) {
                ret = -ENETDOWN;
                goto exit;
        }
 
-       /* drop the possible '\n' from the end */
-       if (buf[count - 1] == '\n') {
-               buf[count - 1] = 0;
-               count--;
-       }
-
        if (!strcmp(buf, "soft")) {
                ath10k_info(ar, "simulating soft firmware crash\n");
                ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0);
@@ -2127,6 +2125,7 @@ static ssize_t ath10k_write_btcoex(struct file *file,
        size_t buf_size;
        int ret;
        bool val;
+       u32 pdev_param;
 
        buf_size = min(count, (sizeof(buf) - 1));
        if (copy_from_user(buf, ubuf, buf_size))
@@ -2150,14 +2149,25 @@ static ssize_t ath10k_write_btcoex(struct file *file,
                goto exit;
        }
 
+       pdev_param = ar->wmi.pdev_param->enable_btcoex;
+       if (test_bit(ATH10K_FW_FEATURE_BTCOEX_PARAM,
+                    ar->running_fw->fw_file.fw_features)) {
+               ret = ath10k_wmi_pdev_set_param(ar, pdev_param, val);
+               if (ret) {
+                       ath10k_warn(ar, "failed to enable btcoex: %d\n", ret);
+                       ret = count;
+                       goto exit;
+               }
+       } else {
+               ath10k_info(ar, "restarting firmware due to btcoex change");
+               queue_work(ar->workqueue, &ar->restart_work);
+       }
+
        if (val)
                set_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags);
        else
                clear_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags);
 
-       ath10k_info(ar, "restarting firmware due to btcoex change");
-
-       queue_work(ar->workqueue, &ar->restart_work);
        ret = count;
 
 exit:
index 89e7076..b2566b0 100644 (file)
@@ -87,6 +87,10 @@ struct ath10k_hif_ops {
 
        int (*suspend)(struct ath10k *ar);
        int (*resume)(struct ath10k *ar);
+
+       /* fetch calibration data from target eeprom */
+       int (*fetch_cal_eeprom)(struct ath10k *ar, void **data,
+                               size_t *data_len);
 };
 
 static inline int ath10k_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
@@ -202,4 +206,14 @@ static inline void ath10k_hif_write32(struct ath10k *ar,
        ar->hif.ops->write32(ar, address, data);
 }
 
+static inline int ath10k_hif_fetch_cal_eeprom(struct ath10k *ar,
+                                             void **data,
+                                             size_t *data_len)
+{
+       if (!ar->hif.ops->fetch_cal_eeprom)
+               return -EOPNOTSUPP;
+
+       return ar->hif.ops->fetch_cal_eeprom(ar, data, data_len);
+}
+
 #endif /* _HIF_H_ */
index 911c535..430a83e 100644 (file)
@@ -485,10 +485,10 @@ struct htt_mgmt_tx_completion {
        __le32 status;
 } __packed;
 
-#define HTT_RX_INDICATION_INFO0_EXT_TID_MASK  (0x3F)
+#define HTT_RX_INDICATION_INFO0_EXT_TID_MASK  (0x1F)
 #define HTT_RX_INDICATION_INFO0_EXT_TID_LSB   (0)
-#define HTT_RX_INDICATION_INFO0_FLUSH_VALID   (1 << 6)
-#define HTT_RX_INDICATION_INFO0_RELEASE_VALID (1 << 7)
+#define HTT_RX_INDICATION_INFO0_FLUSH_VALID   (1 << 5)
+#define HTT_RX_INDICATION_INFO0_RELEASE_VALID (1 << 6)
 
 #define HTT_RX_INDICATION_INFO1_FLUSH_START_SEQNO_MASK   0x0000003F
 #define HTT_RX_INDICATION_INFO1_FLUSH_START_SEQNO_LSB    0
index cc979a4..3b35c7a 100644 (file)
@@ -748,7 +748,7 @@ ath10k_htt_rx_h_peer_channel(struct ath10k *ar, struct htt_rx_desc *rxd)
        if (WARN_ON_ONCE(!arvif))
                return NULL;
 
-       if (WARN_ON(ath10k_mac_vif_chan(arvif->vif, &def)))
+       if (WARN_ON_ONCE(ath10k_mac_vif_chan(arvif->vif, &def)))
                return NULL;
 
        return def.chan;
@@ -939,7 +939,8 @@ static void ath10k_process_rx(struct ath10k *ar,
                   is_multicast_ether_addr(ieee80211_get_DA(hdr)) ?
                                                        "mcast" : "ucast",
                   (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4,
-                  status->flag == 0 ? "legacy" : "",
+                  (status->flag & (RX_FLAG_HT | RX_FLAG_VHT)) == 0 ?
+                                                       "legacy" : "",
                   status->flag & RX_FLAG_HT ? "ht" : "",
                   status->flag & RX_FLAG_VHT ? "vht" : "",
                   status->flag & RX_FLAG_40MHZ ? "40" : "",
@@ -2182,34 +2183,6 @@ static void ath10k_htt_rx_tx_mode_switch_ind(struct ath10k *ar,
        ath10k_mac_tx_push_pending(ar);
 }
 
-static inline enum nl80211_band phy_mode_to_band(u32 phy_mode)
-{
-       enum nl80211_band band;
-
-       switch (phy_mode) {
-       case MODE_11A:
-       case MODE_11NA_HT20:
-       case MODE_11NA_HT40:
-       case MODE_11AC_VHT20:
-       case MODE_11AC_VHT40:
-       case MODE_11AC_VHT80:
-               band = NL80211_BAND_5GHZ;
-               break;
-       case MODE_11G:
-       case MODE_11B:
-       case MODE_11GONLY:
-       case MODE_11NG_HT20:
-       case MODE_11NG_HT40:
-       case MODE_11AC_VHT20_2G:
-       case MODE_11AC_VHT40_2G:
-       case MODE_11AC_VHT80_2G:
-       default:
-               band = NL80211_BAND_2GHZ;
-       }
-
-       return band;
-}
-
 void ath10k_htt_htc_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
 {
        bool release;
@@ -2291,7 +2264,6 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
                        ath10k_htt_tx_mgmt_dec_pending(htt);
                        spin_unlock_bh(&htt->tx_lock);
                }
-               ath10k_mac_tx_push_pending(ar);
                break;
        }
        case HTT_T2H_MSG_TYPE_TX_COMPL_IND:
@@ -2442,8 +2414,6 @@ static void ath10k_htt_txrx_compl_task(unsigned long ptr)
                dev_kfree_skb_any(skb);
        }
 
-       ath10k_mac_tx_push_pending(ar);
-
        num_mpdus = atomic_read(&htt->num_mpdus_ready);
 
        while (num_mpdus) {
index f544d48..bd86e7a 100644 (file)
@@ -179,17 +179,35 @@ void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
                                u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev)
 {
        u32 cc_fix = 0;
+       u32 rcc_fix = 0;
+       enum ath10k_hw_cc_wraparound_type wraparound_type;
 
        survey->filled |= SURVEY_INFO_TIME |
                          SURVEY_INFO_TIME_BUSY;
 
-       if (ar->hw_params.has_shifted_cc_wraparound && cc < cc_prev) {
-               cc_fix = 0x7fffffff;
-               survey->filled &= ~SURVEY_INFO_TIME_BUSY;
+       wraparound_type = ar->hw_params.cc_wraparound_type;
+
+       if (cc < cc_prev || rcc < rcc_prev) {
+               switch (wraparound_type) {
+               case ATH10K_HW_CC_WRAP_SHIFTED_ALL:
+                       if (cc < cc_prev) {
+                               cc_fix = 0x7fffffff;
+                               survey->filled &= ~SURVEY_INFO_TIME_BUSY;
+                       }
+                       break;
+               case ATH10K_HW_CC_WRAP_SHIFTED_EACH:
+                       if (cc < cc_prev)
+                               cc_fix = 0x7fffffff;
+                       else
+                               rcc_fix = 0x7fffffff;
+                       break;
+               case ATH10K_HW_CC_WRAP_DISABLED:
+                       break;
+               }
        }
 
        cc -= cc_prev - cc_fix;
-       rcc -= rcc_prev;
+       rcc -= rcc_prev - rcc_fix;
 
        survey->time = CCNT_TO_MSEC(ar, cc);
        survey->time_busy = CCNT_TO_MSEC(ar, rcc);
index aedd898..f31d3ce 100644 (file)
@@ -26,7 +26,9 @@
 #define QCA6164_2_1_DEVICE_ID   (0x0041)
 #define QCA6174_2_1_DEVICE_ID   (0x003e)
 #define QCA99X0_2_0_DEVICE_ID   (0x0040)
+#define QCA9984_1_0_DEVICE_ID  (0x0046)
 #define QCA9377_1_0_DEVICE_ID   (0x0042)
+#define QCA9887_1_0_DEVICE_ID   (0x0050)
 
 /* QCA988X 1.0 definitions (unsupported) */
 #define QCA988X_HW_1_0_CHIP_ID_REV     0x0
 #define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin"
 #define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234
 
+/* QCA9887 1.0 definitions */
+#define QCA9887_HW_1_0_VERSION         0x4100016d
+#define QCA9887_HW_1_0_CHIP_ID_REV     0
+#define QCA9887_HW_1_0_FW_DIR          ATH10K_FW_DIR "/QCA9887/hw1.0"
+#define QCA9887_HW_1_0_BOARD_DATA_FILE "board.bin"
+#define QCA9887_HW_1_0_PATCH_LOAD_ADDR 0x1234
+
 /* QCA6174 target BMI version signatures */
 #define QCA6174_HW_1_0_VERSION         0x05000000
 #define QCA6174_HW_1_1_VERSION         0x05000001
@@ -91,6 +100,14 @@ enum qca9377_chip_id_rev {
 #define QCA99X0_HW_2_0_BOARD_DATA_FILE "board.bin"
 #define QCA99X0_HW_2_0_PATCH_LOAD_ADDR 0x1234
 
+/* QCA9984 1.0 defines */
+#define QCA9984_HW_1_0_DEV_VERSION     0x1000000
+#define QCA9984_HW_DEV_TYPE            0xa
+#define QCA9984_HW_1_0_CHIP_ID_REV     0x0
+#define QCA9984_HW_1_0_FW_DIR          ATH10K_FW_DIR "/QCA9984/hw1.0"
+#define QCA9984_HW_1_0_BOARD_DATA_FILE "board.bin"
+#define QCA9984_HW_1_0_PATCH_LOAD_ADDR 0x1234
+
 /* QCA9377 1.0 definitions */
 #define QCA9377_HW_1_0_FW_DIR          ATH10K_FW_DIR "/QCA9377/hw1.0"
 #define QCA9377_HW_1_0_BOARD_DATA_FILE "board.bin"
@@ -193,8 +210,10 @@ enum ath10k_hw_rev {
        ATH10K_HW_QCA988X,
        ATH10K_HW_QCA6174,
        ATH10K_HW_QCA99X0,
+       ATH10K_HW_QCA9984,
        ATH10K_HW_QCA9377,
        ATH10K_HW_QCA4019,
+       ATH10K_HW_QCA9887,
 };
 
 struct ath10k_hw_regs {
@@ -247,8 +266,10 @@ void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
                                u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev);
 
 #define QCA_REV_988X(ar) ((ar)->hw_rev == ATH10K_HW_QCA988X)
+#define QCA_REV_9887(ar) ((ar)->hw_rev == ATH10K_HW_QCA9887)
 #define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174)
 #define QCA_REV_99X0(ar) ((ar)->hw_rev == ATH10K_HW_QCA99X0)
+#define QCA_REV_9984(ar) ((ar)->hw_rev == ATH10K_HW_QCA9984)
 #define QCA_REV_9377(ar) ((ar)->hw_rev == ATH10K_HW_QCA9377)
 #define QCA_REV_40XX(ar) ((ar)->hw_rev == ATH10K_HW_QCA4019)
 
@@ -315,11 +336,41 @@ enum ath10k_hw_rate_cck {
        ATH10K_HW_RATE_CCK_SP_2M,
 };
 
+enum ath10k_hw_rate_rev2_cck {
+       ATH10K_HW_RATE_REV2_CCK_LP_1M = 1,
+       ATH10K_HW_RATE_REV2_CCK_LP_2M,
+       ATH10K_HW_RATE_REV2_CCK_LP_5_5M,
+       ATH10K_HW_RATE_REV2_CCK_LP_11M,
+       ATH10K_HW_RATE_REV2_CCK_SP_2M,
+       ATH10K_HW_RATE_REV2_CCK_SP_5_5M,
+       ATH10K_HW_RATE_REV2_CCK_SP_11M,
+};
+
 enum ath10k_hw_4addr_pad {
        ATH10K_HW_4ADDR_PAD_AFTER,
        ATH10K_HW_4ADDR_PAD_BEFORE,
 };
 
+enum ath10k_hw_cc_wraparound_type {
+       ATH10K_HW_CC_WRAP_DISABLED = 0,
+
+       /* This type is when the HW chip has a quirky Cycle Counter
+        * wraparound which resets to 0x7fffffff instead of 0. All
+        * other CC related counters (e.g. Rx Clear Count) are divided
+        * by 2 so they never wraparound themselves.
+        */
+       ATH10K_HW_CC_WRAP_SHIFTED_ALL = 1,
+
+       /* Each hw counter wrapsaround independently. When the
+        * counter overflows the repestive counter is right shifted
+        * by 1, i.e reset to 0x7fffffff, and other counters will be
+        * running unaffected. In this type of wraparound, it should
+        * be possible to report accurate Rx busy time unlike the
+        * first type.
+        */
+       ATH10K_HW_CC_WRAP_SHIFTED_EACH = 2,
+};
+
 /* Target specific defines for MAIN firmware */
 #define TARGET_NUM_VDEVS                       8
 #define TARGET_NUM_PEER_AST                    2
@@ -547,7 +598,10 @@ enum ath10k_hw_4addr_pad {
 #define WLAN_SYSTEM_SLEEP_DISABLE_MASK         0x00000001
 
 #define WLAN_GPIO_PIN0_ADDRESS                 0x00000028
+#define WLAN_GPIO_PIN0_CONFIG_LSB              11
 #define WLAN_GPIO_PIN0_CONFIG_MASK             0x00007800
+#define WLAN_GPIO_PIN0_PAD_PULL_LSB            5
+#define WLAN_GPIO_PIN0_PAD_PULL_MASK           0x00000060
 #define WLAN_GPIO_PIN1_ADDRESS                 0x0000002c
 #define WLAN_GPIO_PIN1_CONFIG_MASK             0x00007800
 #define WLAN_GPIO_PIN10_ADDRESS                        0x00000050
@@ -560,6 +614,8 @@ enum ath10k_hw_4addr_pad {
 #define CLOCK_GPIO_BT_CLK_OUT_EN_MASK          0
 
 #define SI_CONFIG_OFFSET                       0x00000000
+#define SI_CONFIG_ERR_INT_LSB                  19
+#define SI_CONFIG_ERR_INT_MASK                 0x00080000
 #define SI_CONFIG_BIDIR_OD_DATA_LSB            18
 #define SI_CONFIG_BIDIR_OD_DATA_MASK           0x00040000
 #define SI_CONFIG_I2C_LSB                      16
@@ -573,7 +629,9 @@ enum ath10k_hw_4addr_pad {
 #define SI_CONFIG_DIVIDER_LSB                  0
 #define SI_CONFIG_DIVIDER_MASK                 0x0000000f
 #define SI_CS_OFFSET                           0x00000004
+#define SI_CS_DONE_ERR_LSB                     10
 #define SI_CS_DONE_ERR_MASK                    0x00000400
+#define SI_CS_DONE_INT_LSB                     9
 #define SI_CS_DONE_INT_MASK                    0x00000200
 #define SI_CS_START_LSB                                8
 #define SI_CS_START_MASK                       0x00000100
@@ -624,7 +682,10 @@ enum ath10k_hw_4addr_pad {
 #define GPIO_BASE_ADDRESS                      WLAN_GPIO_BASE_ADDRESS
 #define GPIO_PIN0_OFFSET                       WLAN_GPIO_PIN0_ADDRESS
 #define GPIO_PIN1_OFFSET                       WLAN_GPIO_PIN1_ADDRESS
+#define GPIO_PIN0_CONFIG_LSB                   WLAN_GPIO_PIN0_CONFIG_LSB
 #define GPIO_PIN0_CONFIG_MASK                  WLAN_GPIO_PIN0_CONFIG_MASK
+#define GPIO_PIN0_PAD_PULL_LSB                 WLAN_GPIO_PIN0_PAD_PULL_LSB
+#define GPIO_PIN0_PAD_PULL_MASK                        WLAN_GPIO_PIN0_PAD_PULL_MASK
 #define GPIO_PIN1_CONFIG_MASK                  WLAN_GPIO_PIN1_CONFIG_MASK
 #define SI_BASE_ADDRESS                                WLAN_SI_BASE_ADDRESS
 #define SCRATCH_BASE_ADDRESS                   SOC_CORE_BASE_ADDRESS
@@ -679,6 +740,18 @@ enum ath10k_hw_4addr_pad {
 #define WINDOW_READ_ADDR_ADDRESS               MISSING
 #define WINDOW_WRITE_ADDR_ADDRESS              MISSING
 
+#define QCA9887_1_0_I2C_SDA_GPIO_PIN           5
+#define QCA9887_1_0_I2C_SDA_PIN_CONFIG         3
+#define QCA9887_1_0_SI_CLK_GPIO_PIN            17
+#define QCA9887_1_0_SI_CLK_PIN_CONFIG          3
+#define QCA9887_1_0_GPIO_ENABLE_W1TS_LOW_ADDRESS 0x00000010
+
+#define QCA9887_EEPROM_SELECT_READ             0xa10000a0
+#define QCA9887_EEPROM_ADDR_HI_MASK            0x0000ff00
+#define QCA9887_EEPROM_ADDR_HI_LSB             8
+#define QCA9887_EEPROM_ADDR_LO_MASK            0x00ff0000
+#define QCA9887_EEPROM_ADDR_LO_LSB             16
+
 #define RTC_STATE_V_GET(x) (((x) & RTC_STATE_V_MASK) >> RTC_STATE_V_LSB)
 
 #endif /* _HW_H_ */
index 6dd1d26..3a170b1 100644 (file)
@@ -62,6 +62,32 @@ static struct ieee80211_rate ath10k_rates[] = {
        { .bitrate = 540, .hw_value = ATH10K_HW_RATE_OFDM_54M },
 };
 
+static struct ieee80211_rate ath10k_rates_rev2[] = {
+       { .bitrate = 10,
+         .hw_value = ATH10K_HW_RATE_REV2_CCK_LP_1M },
+       { .bitrate = 20,
+         .hw_value = ATH10K_HW_RATE_REV2_CCK_LP_2M,
+         .hw_value_short = ATH10K_HW_RATE_REV2_CCK_SP_2M,
+         .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+       { .bitrate = 55,
+         .hw_value = ATH10K_HW_RATE_REV2_CCK_LP_5_5M,
+         .hw_value_short = ATH10K_HW_RATE_REV2_CCK_SP_5_5M,
+         .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+       { .bitrate = 110,
+         .hw_value = ATH10K_HW_RATE_REV2_CCK_LP_11M,
+         .hw_value_short = ATH10K_HW_RATE_REV2_CCK_SP_11M,
+         .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+
+       { .bitrate = 60, .hw_value = ATH10K_HW_RATE_OFDM_6M },
+       { .bitrate = 90, .hw_value = ATH10K_HW_RATE_OFDM_9M },
+       { .bitrate = 120, .hw_value = ATH10K_HW_RATE_OFDM_12M },
+       { .bitrate = 180, .hw_value = ATH10K_HW_RATE_OFDM_18M },
+       { .bitrate = 240, .hw_value = ATH10K_HW_RATE_OFDM_24M },
+       { .bitrate = 360, .hw_value = ATH10K_HW_RATE_OFDM_36M },
+       { .bitrate = 480, .hw_value = ATH10K_HW_RATE_OFDM_48M },
+       { .bitrate = 540, .hw_value = ATH10K_HW_RATE_OFDM_54M },
+};
+
 #define ATH10K_MAC_FIRST_OFDM_RATE_IDX 4
 
 #define ath10k_a_rates (ath10k_rates + ATH10K_MAC_FIRST_OFDM_RATE_IDX)
@@ -70,6 +96,9 @@ static struct ieee80211_rate ath10k_rates[] = {
 #define ath10k_g_rates (ath10k_rates + 0)
 #define ath10k_g_rates_size (ARRAY_SIZE(ath10k_rates))
 
+#define ath10k_g_rates_rev2 (ath10k_rates_rev2 + 0)
+#define ath10k_g_rates_rev2_size (ARRAY_SIZE(ath10k_rates_rev2))
+
 static bool ath10k_mac_bitrate_is_cck(int bitrate)
 {
        switch (bitrate) {
@@ -3781,6 +3810,9 @@ void ath10k_mac_tx_push_pending(struct ath10k *ar)
        int ret;
        int max;
 
+       if (ar->htt.num_pending_tx >= (ar->htt.max_num_pending_tx / 2))
+               return;
+
        spin_lock_bh(&ar->txqs_lock);
        rcu_read_lock();
 
@@ -4051,9 +4083,7 @@ static void ath10k_mac_op_wake_tx_queue(struct ieee80211_hw *hw,
                list_add_tail(&artxq->list, &ar->txqs);
        spin_unlock_bh(&ar->txqs_lock);
 
-       if (ath10k_mac_tx_can_push(hw, txq))
-               tasklet_schedule(&ar->htt.txrx_compl_task);
-
+       ath10k_mac_tx_push_pending(ar);
        ath10k_htt_tx_txq_update(hw, txq);
 }
 
@@ -4467,6 +4497,19 @@ static int ath10k_start(struct ieee80211_hw *hw)
                }
        }
 
+       param = ar->wmi.pdev_param->enable_btcoex;
+       if (test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map) &&
+           test_bit(ATH10K_FW_FEATURE_BTCOEX_PARAM,
+                    ar->running_fw->fw_file.fw_features)) {
+               ret = ath10k_wmi_pdev_set_param(ar, param, 0);
+               if (ret) {
+                       ath10k_warn(ar,
+                                   "failed to set btcoex param: %d\n", ret);
+                       goto err_core_stop;
+               }
+               clear_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags);
+       }
+
        ar->num_started_vdevs = 0;
        ath10k_regd_update(ar);
 
@@ -7695,8 +7738,14 @@ int ath10k_mac_register(struct ath10k *ar)
                band = &ar->mac.sbands[NL80211_BAND_2GHZ];
                band->n_channels = ARRAY_SIZE(ath10k_2ghz_channels);
                band->channels = channels;
-               band->n_bitrates = ath10k_g_rates_size;
-               band->bitrates = ath10k_g_rates;
+
+               if (ar->hw_params.cck_rate_map_rev2) {
+                       band->n_bitrates = ath10k_g_rates_rev2_size;
+                       band->bitrates = ath10k_g_rates_rev2;
+               } else {
+                       band->n_bitrates = ath10k_g_rates_size;
+                       band->bitrates = ath10k_g_rates;
+               }
 
                ar->hw->wiphy->bands[NL80211_BAND_2GHZ] = band;
        }
index 8133d7b..f06dd39 100644 (file)
@@ -56,7 +56,9 @@ static const struct pci_device_id ath10k_pci_id_table[] = {
        { PCI_VDEVICE(ATHEROS, QCA6164_2_1_DEVICE_ID) }, /* PCI-E QCA6164 V2.1 */
        { PCI_VDEVICE(ATHEROS, QCA6174_2_1_DEVICE_ID) }, /* PCI-E QCA6174 V2.1 */
        { PCI_VDEVICE(ATHEROS, QCA99X0_2_0_DEVICE_ID) }, /* PCI-E QCA99X0 V2 */
+       { PCI_VDEVICE(ATHEROS, QCA9984_1_0_DEVICE_ID) }, /* PCI-E QCA9984 V1 */
        { PCI_VDEVICE(ATHEROS, QCA9377_1_0_DEVICE_ID) }, /* PCI-E QCA9377 V1 */
+       { PCI_VDEVICE(ATHEROS, QCA9887_1_0_DEVICE_ID) }, /* PCI-E QCA9887 */
        {0}
 };
 
@@ -81,8 +83,12 @@ static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = {
 
        { QCA99X0_2_0_DEVICE_ID, QCA99X0_HW_2_0_CHIP_ID_REV },
 
+       { QCA9984_1_0_DEVICE_ID, QCA9984_HW_1_0_CHIP_ID_REV },
+
        { QCA9377_1_0_DEVICE_ID, QCA9377_HW_1_0_CHIP_ID_REV },
        { QCA9377_1_0_DEVICE_ID, QCA9377_HW_1_1_CHIP_ID_REV },
+
+       { QCA9887_1_0_DEVICE_ID, QCA9887_HW_1_0_CHIP_ID_REV },
 };
 
 static void ath10k_pci_buffer_cleanup(struct ath10k *ar);
@@ -837,6 +843,7 @@ static u32 ath10k_pci_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr)
 
        switch (ar->hw_rev) {
        case ATH10K_HW_QCA988X:
+       case ATH10K_HW_QCA9887:
        case ATH10K_HW_QCA6174:
        case ATH10K_HW_QCA9377:
                val = (ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
@@ -844,6 +851,7 @@ static u32 ath10k_pci_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr)
                       0x7ff) << 21;
                break;
        case ATH10K_HW_QCA99X0:
+       case ATH10K_HW_QCA9984:
        case ATH10K_HW_QCA4019:
                val = ath10k_pci_read32(ar, PCIE_BAR_REG_ADDRESS);
                break;
@@ -864,7 +872,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        int ret = 0;
        u32 *buf;
-       unsigned int completed_nbytes, orig_nbytes, remaining_bytes;
+       unsigned int completed_nbytes, alloc_nbytes, remaining_bytes;
        struct ath10k_ce_pipe *ce_diag;
        /* Host buffer address in CE space */
        u32 ce_data;
@@ -882,9 +890,10 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
         *   1) 4-byte alignment
         *   2) Buffer in DMA-able space
         */
-       orig_nbytes = nbytes;
+       alloc_nbytes = min_t(unsigned int, nbytes, DIAG_TRANSFER_LIMIT);
+
        data_buf = (unsigned char *)dma_alloc_coherent(ar->dev,
-                                                      orig_nbytes,
+                                                      alloc_nbytes,
                                                       &ce_data_base,
                                                       GFP_ATOMIC);
 
@@ -892,9 +901,9 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
                ret = -ENOMEM;
                goto done;
        }
-       memset(data_buf, 0, orig_nbytes);
+       memset(data_buf, 0, alloc_nbytes);
 
-       remaining_bytes = orig_nbytes;
+       remaining_bytes = nbytes;
        ce_data = ce_data_base;
        while (remaining_bytes) {
                nbytes = min_t(unsigned int, remaining_bytes,
@@ -954,19 +963,22 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
                }
 
                remaining_bytes -= nbytes;
+
+               if (ret) {
+                       ath10k_warn(ar, "failed to read diag value at 0x%x: %d\n",
+                                   address, ret);
+                       break;
+               }
+               memcpy(data, data_buf, nbytes);
+
                address += nbytes;
-               ce_data += nbytes;
+               data += nbytes;
        }
 
 done:
-       if (ret == 0)
-               memcpy(data, data_buf, orig_nbytes);
-       else
-               ath10k_warn(ar, "failed to read diag value at 0x%x: %d\n",
-                           address, ret);
 
        if (data_buf)
-               dma_free_coherent(ar->dev, orig_nbytes, data_buf,
+               dma_free_coherent(ar->dev, alloc_nbytes, data_buf,
                                  ce_data_base);
 
        spin_unlock_bh(&ar_pci->ce_lock);
@@ -1560,6 +1572,7 @@ static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar)
 
        switch (ar->hw_rev) {
        case ATH10K_HW_QCA988X:
+       case ATH10K_HW_QCA9887:
        case ATH10K_HW_QCA6174:
        case ATH10K_HW_QCA9377:
                val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
@@ -1569,6 +1582,7 @@ static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar)
                                   CORE_CTRL_ADDRESS, val);
                break;
        case ATH10K_HW_QCA99X0:
+       case ATH10K_HW_QCA9984:
        case ATH10K_HW_QCA4019:
                /* TODO: Find appropriate register configuration for QCA99X0
                 *  to mask irq/MSI.
@@ -1583,6 +1597,7 @@ static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar)
 
        switch (ar->hw_rev) {
        case ATH10K_HW_QCA988X:
+       case ATH10K_HW_QCA9887:
        case ATH10K_HW_QCA6174:
        case ATH10K_HW_QCA9377:
                val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
@@ -1592,6 +1607,7 @@ static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar)
                                   CORE_CTRL_ADDRESS, val);
                break;
        case ATH10K_HW_QCA99X0:
+       case ATH10K_HW_QCA9984:
        case ATH10K_HW_QCA4019:
                /* TODO: Find appropriate register configuration for QCA99X0
                 *  to unmask irq/MSI.
@@ -1932,6 +1948,8 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar)
        switch (ar_pci->pdev->device) {
        case QCA988X_2_0_DEVICE_ID:
        case QCA99X0_2_0_DEVICE_ID:
+       case QCA9984_1_0_DEVICE_ID:
+       case QCA9887_1_0_DEVICE_ID:
                return 1;
        case QCA6164_2_1_DEVICE_ID:
        case QCA6174_2_1_DEVICE_ID:
@@ -2293,16 +2311,20 @@ static int ath10k_pci_warm_reset(struct ath10k *ar)
        return 0;
 }
 
+static int ath10k_pci_qca99x0_soft_chip_reset(struct ath10k *ar)
+{
+       ath10k_pci_irq_disable(ar);
+       return ath10k_pci_qca99x0_chip_reset(ar);
+}
+
 static int ath10k_pci_safe_chip_reset(struct ath10k *ar)
 {
-       if (QCA_REV_988X(ar) || QCA_REV_6174(ar)) {
-               return ath10k_pci_warm_reset(ar);
-       } else if (QCA_REV_99X0(ar)) {
-               ath10k_pci_irq_disable(ar);
-               return ath10k_pci_qca99x0_chip_reset(ar);
-       } else {
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
+       if (!ar_pci->pci_soft_reset)
                return -ENOTSUPP;
-       }
+
+       return ar_pci->pci_soft_reset(ar);
 }
 
 static int ath10k_pci_qca988x_chip_reset(struct ath10k *ar)
@@ -2437,16 +2459,12 @@ static int ath10k_pci_qca99x0_chip_reset(struct ath10k *ar)
 
 static int ath10k_pci_chip_reset(struct ath10k *ar)
 {
-       if (QCA_REV_988X(ar))
-               return ath10k_pci_qca988x_chip_reset(ar);
-       else if (QCA_REV_6174(ar))
-               return ath10k_pci_qca6174_chip_reset(ar);
-       else if (QCA_REV_9377(ar))
-               return ath10k_pci_qca6174_chip_reset(ar);
-       else if (QCA_REV_99X0(ar))
-               return ath10k_pci_qca99x0_chip_reset(ar);
-       else
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
+       if (WARN_ON(!ar_pci->pci_hard_reset))
                return -ENOTSUPP;
+
+       return ar_pci->pci_hard_reset(ar);
 }
 
 static int ath10k_pci_hif_power_up(struct ath10k *ar)
@@ -2559,6 +2577,144 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
 }
 #endif
 
+static bool ath10k_pci_validate_cal(void *data, size_t size)
+{
+       __le16 *cal_words = data;
+       u16 checksum = 0;
+       size_t i;
+
+       if (size % 2 != 0)
+               return false;
+
+       for (i = 0; i < size / 2; i++)
+               checksum ^= le16_to_cpu(cal_words[i]);
+
+       return checksum == 0xffff;
+}
+
+static void ath10k_pci_enable_eeprom(struct ath10k *ar)
+{
+       /* Enable SI clock */
+       ath10k_pci_soc_write32(ar, CLOCK_CONTROL_OFFSET, 0x0);
+
+       /* Configure GPIOs for I2C operation */
+       ath10k_pci_write32(ar,
+                          GPIO_BASE_ADDRESS + GPIO_PIN0_OFFSET +
+                          4 * QCA9887_1_0_I2C_SDA_GPIO_PIN,
+                          SM(QCA9887_1_0_I2C_SDA_PIN_CONFIG,
+                             GPIO_PIN0_CONFIG) |
+                          SM(1, GPIO_PIN0_PAD_PULL));
+
+       ath10k_pci_write32(ar,
+                          GPIO_BASE_ADDRESS + GPIO_PIN0_OFFSET +
+                          4 * QCA9887_1_0_SI_CLK_GPIO_PIN,
+                          SM(QCA9887_1_0_SI_CLK_PIN_CONFIG, GPIO_PIN0_CONFIG) |
+                          SM(1, GPIO_PIN0_PAD_PULL));
+
+       ath10k_pci_write32(ar,
+                          GPIO_BASE_ADDRESS +
+                          QCA9887_1_0_GPIO_ENABLE_W1TS_LOW_ADDRESS,
+                          1u << QCA9887_1_0_SI_CLK_GPIO_PIN);
+
+       /* In Swift ASIC - EEPROM clock will be (110MHz/512) = 214KHz */
+       ath10k_pci_write32(ar,
+                          SI_BASE_ADDRESS + SI_CONFIG_OFFSET,
+                          SM(1, SI_CONFIG_ERR_INT) |
+                          SM(1, SI_CONFIG_BIDIR_OD_DATA) |
+                          SM(1, SI_CONFIG_I2C) |
+                          SM(1, SI_CONFIG_POS_SAMPLE) |
+                          SM(1, SI_CONFIG_INACTIVE_DATA) |
+                          SM(1, SI_CONFIG_INACTIVE_CLK) |
+                          SM(8, SI_CONFIG_DIVIDER));
+}
+
+static int ath10k_pci_read_eeprom(struct ath10k *ar, u16 addr, u8 *out)
+{
+       u32 reg;
+       int wait_limit;
+
+       /* set device select byte and for the read operation */
+       reg = QCA9887_EEPROM_SELECT_READ |
+             SM(addr, QCA9887_EEPROM_ADDR_LO) |
+             SM(addr >> 8, QCA9887_EEPROM_ADDR_HI);
+       ath10k_pci_write32(ar, SI_BASE_ADDRESS + SI_TX_DATA0_OFFSET, reg);
+
+       /* write transmit data, transfer length, and START bit */
+       ath10k_pci_write32(ar, SI_BASE_ADDRESS + SI_CS_OFFSET,
+                          SM(1, SI_CS_START) | SM(1, SI_CS_RX_CNT) |
+                          SM(4, SI_CS_TX_CNT));
+
+       /* wait max 1 sec */
+       wait_limit = 100000;
+
+       /* wait for SI_CS_DONE_INT */
+       do {
+               reg = ath10k_pci_read32(ar, SI_BASE_ADDRESS + SI_CS_OFFSET);
+               if (MS(reg, SI_CS_DONE_INT))
+                       break;
+
+               wait_limit--;
+               udelay(10);
+       } while (wait_limit > 0);
+
+       if (!MS(reg, SI_CS_DONE_INT)) {
+               ath10k_err(ar, "timeout while reading device EEPROM at %04x\n",
+                          addr);
+               return -ETIMEDOUT;
+       }
+
+       /* clear SI_CS_DONE_INT */
+       ath10k_pci_write32(ar, SI_BASE_ADDRESS + SI_CS_OFFSET, reg);
+
+       if (MS(reg, SI_CS_DONE_ERR)) {
+               ath10k_err(ar, "failed to read device EEPROM at %04x\n", addr);
+               return -EIO;
+       }
+
+       /* extract receive data */
+       reg = ath10k_pci_read32(ar, SI_BASE_ADDRESS + SI_RX_DATA0_OFFSET);
+       *out = reg;
+
+       return 0;
+}
+
+static int ath10k_pci_hif_fetch_cal_eeprom(struct ath10k *ar, void **data,
+                                          size_t *data_len)
+{
+       u8 *caldata = NULL;
+       size_t calsize, i;
+       int ret;
+
+       if (!QCA_REV_9887(ar))
+               return -EOPNOTSUPP;
+
+       calsize = ar->hw_params.cal_data_len;
+       caldata = kmalloc(calsize, GFP_KERNEL);
+       if (!caldata)
+               return -ENOMEM;
+
+       ath10k_pci_enable_eeprom(ar);
+
+       for (i = 0; i < calsize; i++) {
+               ret = ath10k_pci_read_eeprom(ar, i, &caldata[i]);
+               if (ret)
+                       goto err_free;
+       }
+
+       if (!ath10k_pci_validate_cal(caldata, calsize))
+               goto err_free;
+
+       *data = caldata;
+       *data_len = calsize;
+
+       return 0;
+
+err_free:
+       kfree(data);
+
+       return -EINVAL;
+}
+
 static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
        .tx_sg                  = ath10k_pci_hif_tx_sg,
        .diag_read              = ath10k_pci_hif_diag_read,
@@ -2578,6 +2734,7 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
        .suspend                = ath10k_pci_hif_suspend,
        .resume                 = ath10k_pci_hif_resume,
 #endif
+       .fetch_cal_eeprom       = ath10k_pci_hif_fetch_cal_eeprom,
 };
 
 /*
@@ -2976,24 +3133,47 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
        enum ath10k_hw_rev hw_rev;
        u32 chip_id;
        bool pci_ps;
+       int (*pci_soft_reset)(struct ath10k *ar);
+       int (*pci_hard_reset)(struct ath10k *ar);
 
        switch (pci_dev->device) {
        case QCA988X_2_0_DEVICE_ID:
                hw_rev = ATH10K_HW_QCA988X;
                pci_ps = false;
+               pci_soft_reset = ath10k_pci_warm_reset;
+               pci_hard_reset = ath10k_pci_qca988x_chip_reset;
+               break;
+       case QCA9887_1_0_DEVICE_ID:
+               dev_warn(&pdev->dev, "QCA9887 support is still experimental, there are likely bugs. You have been warned.\n");
+               hw_rev = ATH10K_HW_QCA9887;
+               pci_ps = false;
+               pci_soft_reset = ath10k_pci_warm_reset;
+               pci_hard_reset = ath10k_pci_qca988x_chip_reset;
                break;
        case QCA6164_2_1_DEVICE_ID:
        case QCA6174_2_1_DEVICE_ID:
                hw_rev = ATH10K_HW_QCA6174;
                pci_ps = true;
+               pci_soft_reset = ath10k_pci_warm_reset;
+               pci_hard_reset = ath10k_pci_qca6174_chip_reset;
                break;
        case QCA99X0_2_0_DEVICE_ID:
                hw_rev = ATH10K_HW_QCA99X0;
                pci_ps = false;
+               pci_soft_reset = ath10k_pci_qca99x0_soft_chip_reset;
+               pci_hard_reset = ath10k_pci_qca99x0_chip_reset;
+               break;
+       case QCA9984_1_0_DEVICE_ID:
+               hw_rev = ATH10K_HW_QCA9984;
+               pci_ps = false;
+               pci_soft_reset = ath10k_pci_qca99x0_soft_chip_reset;
+               pci_hard_reset = ath10k_pci_qca99x0_chip_reset;
                break;
        case QCA9377_1_0_DEVICE_ID:
                hw_rev = ATH10K_HW_QCA9377;
                pci_ps = true;
+               pci_soft_reset = NULL;
+               pci_hard_reset = ath10k_pci_qca6174_chip_reset;
                break;
        default:
                WARN_ON(1);
@@ -3018,6 +3198,8 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
        ar->dev_id = pci_dev->device;
        ar_pci->pci_ps = pci_ps;
        ar_pci->bus_ops = &ath10k_pci_bus_ops;
+       ar_pci->pci_soft_reset = pci_soft_reset;
+       ar_pci->pci_hard_reset = pci_hard_reset;
 
        ar->id.vendor = pdev->vendor;
        ar->id.device = pdev->device;
@@ -3169,7 +3351,7 @@ static void __exit ath10k_pci_exit(void)
 module_exit(ath10k_pci_exit);
 
 MODULE_AUTHOR("Qualcomm Atheros");
-MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices");
+MODULE_DESCRIPTION("Driver support for Qualcomm Atheros 802.11ac WLAN PCIe/AHB devices");
 MODULE_LICENSE("Dual BSD/GPL");
 
 /* QCA988x 2.0 firmware files */
@@ -3180,6 +3362,11 @@ MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API5_FILE);
 MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE);
 MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_BOARD_API2_FILE);
 
+/* QCA9887 1.0 firmware files */
+MODULE_FIRMWARE(QCA9887_HW_1_0_FW_DIR "/" ATH10K_FW_API5_FILE);
+MODULE_FIRMWARE(QCA9887_HW_1_0_FW_DIR "/" QCA9887_HW_1_0_BOARD_DATA_FILE);
+MODULE_FIRMWARE(QCA9887_HW_1_0_FW_DIR "/" ATH10K_BOARD_API2_FILE);
+
 /* QCA6174 2.1 firmware files */
 MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API4_FILE);
 MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API5_FILE);
index 959dc32..6eca1df 100644 (file)
@@ -234,6 +234,12 @@ struct ath10k_pci {
 
        const struct ath10k_bus_ops *bus_ops;
 
+       /* Chip specific pci reset routine used to do a safe reset */
+       int (*pci_soft_reset)(struct ath10k *ar);
+
+       /* Chip specific pci full reset function */
+       int (*pci_hard_reset)(struct ath10k *ar);
+
        /* Keep this entry in the last, memory for struct ath10k_ahb is
         * allocated (ahb support enabled case) in the continuation of
         * this struct.
index ca8d168..034e7a5 100644 (file)
@@ -656,26 +656,6 @@ struct rx_msdu_end {
  *             Reserved: HW should fill with zero.  FW should ignore.
  */
 
-#define RX_PPDU_START_SIG_RATE_SELECT_OFDM 0
-#define RX_PPDU_START_SIG_RATE_SELECT_CCK  1
-
-#define RX_PPDU_START_SIG_RATE_OFDM_48 0
-#define RX_PPDU_START_SIG_RATE_OFDM_24 1
-#define RX_PPDU_START_SIG_RATE_OFDM_12 2
-#define RX_PPDU_START_SIG_RATE_OFDM_6  3
-#define RX_PPDU_START_SIG_RATE_OFDM_54 4
-#define RX_PPDU_START_SIG_RATE_OFDM_36 5
-#define RX_PPDU_START_SIG_RATE_OFDM_18 6
-#define RX_PPDU_START_SIG_RATE_OFDM_9  7
-
-#define RX_PPDU_START_SIG_RATE_CCK_LP_11  0
-#define RX_PPDU_START_SIG_RATE_CCK_LP_5_5 1
-#define RX_PPDU_START_SIG_RATE_CCK_LP_2   2
-#define RX_PPDU_START_SIG_RATE_CCK_LP_1   3
-#define RX_PPDU_START_SIG_RATE_CCK_SP_11  4
-#define RX_PPDU_START_SIG_RATE_CCK_SP_5_5 5
-#define RX_PPDU_START_SIG_RATE_CCK_SP_2   6
-
 #define HTT_RX_PPDU_START_PREAMBLE_LEGACY        0x04
 #define HTT_RX_PPDU_START_PREAMBLE_HT            0x08
 #define HTT_RX_PPDU_START_PREAMBLE_HT_WITH_TXBF  0x09
@@ -711,25 +691,6 @@ struct rx_msdu_end {
 /* No idea what this flag means. It seems to be always set in rate. */
 #define RX_PPDU_START_RATE_FLAG BIT(3)
 
-enum rx_ppdu_start_rate {
-       RX_PPDU_START_RATE_OFDM_48M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_48M,
-       RX_PPDU_START_RATE_OFDM_24M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_24M,
-       RX_PPDU_START_RATE_OFDM_12M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_12M,
-       RX_PPDU_START_RATE_OFDM_6M  = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_6M,
-       RX_PPDU_START_RATE_OFDM_54M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_54M,
-       RX_PPDU_START_RATE_OFDM_36M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_36M,
-       RX_PPDU_START_RATE_OFDM_18M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_18M,
-       RX_PPDU_START_RATE_OFDM_9M  = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_9M,
-
-       RX_PPDU_START_RATE_CCK_LP_11M  = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_LP_11M,
-       RX_PPDU_START_RATE_CCK_LP_5_5M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_LP_5_5M,
-       RX_PPDU_START_RATE_CCK_LP_2M   = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_LP_2M,
-       RX_PPDU_START_RATE_CCK_LP_1M   = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_LP_1M,
-       RX_PPDU_START_RATE_CCK_SP_11M  = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_SP_11M,
-       RX_PPDU_START_RATE_CCK_SP_5_5M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_SP_5_5M,
-       RX_PPDU_START_RATE_CCK_SP_2M   = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_SP_2M,
-};
-
 struct rx_ppdu_start {
        struct {
                u8 pri20_mhz;
@@ -994,7 +955,41 @@ struct rx_pkt_end {
        __le32 info0; /* %RX_PKT_END_INFO0_ */
        __le32 phy_timestamp_1;
        __le32 phy_timestamp_2;
-       __le32 rx_location_info; /* %RX_LOCATION_INFO_ */
+} __packed;
+
+#define RX_LOCATION_INFO0_RTT_FAC_LEGACY_MASK          0x00003fff
+#define RX_LOCATION_INFO0_RTT_FAC_LEGACY_LSB           0
+#define RX_LOCATION_INFO0_RTT_FAC_VHT_MASK             0x1fff8000
+#define RX_LOCATION_INFO0_RTT_FAC_VHT_LSB              15
+#define RX_LOCATION_INFO0_RTT_STRONGEST_CHAIN_MASK     0xc0000000
+#define RX_LOCATION_INFO0_RTT_STRONGEST_CHAIN_LSB      30
+#define RX_LOCATION_INFO0_RTT_FAC_LEGACY_STATUS                BIT(14)
+#define RX_LOCATION_INFO0_RTT_FAC_VHT_STATUS           BIT(29)
+
+#define RX_LOCATION_INFO1_RTT_PREAMBLE_TYPE_MASK       0x0000000c
+#define RX_LOCATION_INFO1_RTT_PREAMBLE_TYPE_LSB                2
+#define RX_LOCATION_INFO1_PKT_BW_MASK                  0x00000030
+#define RX_LOCATION_INFO1_PKT_BW_LSB                   4
+#define RX_LOCATION_INFO1_SKIP_P_SKIP_BTCF_MASK                0x0000ff00
+#define RX_LOCATION_INFO1_SKIP_P_SKIP_BTCF_LSB         8
+#define RX_LOCATION_INFO1_RTT_MSC_RATE_MASK            0x000f0000
+#define RX_LOCATION_INFO1_RTT_MSC_RATE_LSB             16
+#define RX_LOCATION_INFO1_RTT_PBD_LEG_BW_MASK          0x00300000
+#define RX_LOCATION_INFO1_RTT_PBD_LEG_BW_LSB           20
+#define RX_LOCATION_INFO1_TIMING_BACKOFF_MASK          0x07c00000
+#define RX_LOCATION_INFO1_TIMING_BACKOFF_LSB           22
+#define RX_LOCATION_INFO1_RTT_TX_FRAME_PHASE_MASK      0x18000000
+#define RX_LOCATION_INFO1_RTT_TX_FRAME_PHASE_LSB       27
+#define RX_LOCATION_INFO1_RTT_CFR_STATUS               BIT(0)
+#define RX_LOCATION_INFO1_RTT_CIR_STATUS               BIT(1)
+#define RX_LOCATION_INFO1_RTT_GI_TYPE                  BIT(7)
+#define RX_LOCATION_INFO1_RTT_MAC_PHY_PHASE            BIT(29)
+#define RX_LOCATION_INFO1_RTT_TX_DATA_START_X_PHASE    BIT(30)
+#define RX_LOCATION_INFO1_RX_LOCATION_VALID            BIT(31)
+
+struct rx_location_info {
+       __le32 rx_location_info0; /* %RX_LOCATION_INFO0_ */
+       __le32 rx_location_info1; /* %RX_LOCATION_INFO1_ */
 } __packed;
 
 enum rx_phy_ppdu_end_info0 {
@@ -1067,6 +1062,17 @@ struct rx_phy_ppdu_end {
 
 struct rx_ppdu_end_qca99x0 {
        struct rx_pkt_end rx_pkt_end;
+       __le32 rx_location_info; /* %RX_LOCATION_INFO_ */
+       struct rx_phy_ppdu_end rx_phy_ppdu_end;
+       __le32 rx_timing_offset; /* %RX_PPDU_END_RX_TIMING_OFFSET_ */
+       __le32 rx_info; /* %RX_PPDU_END_RX_INFO_ */
+       __le16 bb_length;
+       __le16 info1; /* %RX_PPDU_END_INFO1_ */
+} __packed;
+
+struct rx_ppdu_end_qca9984 {
+       struct rx_pkt_end rx_pkt_end;
+       struct rx_location_info rx_location_info;
        struct rx_phy_ppdu_end rx_phy_ppdu_end;
        __le32 rx_timing_offset; /* %RX_PPDU_END_RX_TIMING_OFFSET_ */
        __le32 rx_info; /* %RX_PPDU_END_RX_INFO_ */
@@ -1080,6 +1086,7 @@ struct rx_ppdu_end {
                struct rx_ppdu_end_qca988x qca988x;
                struct rx_ppdu_end_qca6174 qca6174;
                struct rx_ppdu_end_qca99x0 qca99x0;
+               struct rx_ppdu_end_qca9984 qca9984;
        } __packed;
 } __packed;
 
index 8e24099..aaf53a8 100644 (file)
@@ -447,6 +447,9 @@ Fw Mode/SubMode Mask
 #define QCA988X_BOARD_DATA_SZ     7168
 #define QCA988X_BOARD_EXT_DATA_SZ 0
 
+#define QCA9887_BOARD_DATA_SZ     7168
+#define QCA9887_BOARD_EXT_DATA_SZ 0
+
 #define QCA6174_BOARD_DATA_SZ     8192
 #define QCA6174_BOARD_EXT_DATA_SZ 0
 
index 576e7c4..1966c78 100644 (file)
@@ -117,6 +117,9 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
 
        ieee80211_tx_status(htt->ar->hw, msdu);
        /* we do not own the msdu anymore */
+
+       ath10k_mac_tx_push_pending(ar);
+
        return 0;
 }
 
index 2c30032..6279ab4 100644 (file)
@@ -1104,6 +1104,7 @@ static struct wmi_pdev_param_map wmi_pdev_param_map = {
        .wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED,
        .arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED,
        .arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED,
+       .enable_btcoex = WMI_PDEV_PARAM_UNSUPPORTED,
 };
 
 static struct wmi_pdev_param_map wmi_10x_pdev_param_map = {
@@ -1199,6 +1200,7 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = {
        .wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED,
        .arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED,
        .arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED,
+       .enable_btcoex = WMI_PDEV_PARAM_UNSUPPORTED,
 };
 
 static struct wmi_pdev_param_map wmi_10_2_4_pdev_param_map = {
@@ -1294,6 +1296,7 @@ static struct wmi_pdev_param_map wmi_10_2_4_pdev_param_map = {
        .wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED,
        .arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED,
        .arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED,
+       .enable_btcoex = WMI_PDEV_PARAM_UNSUPPORTED,
 };
 
 /* firmware 10.2 specific mappings */
@@ -1550,6 +1553,7 @@ static struct wmi_pdev_param_map wmi_10_4_pdev_param_map = {
        .wapi_mbssid_offset = WMI_10_4_PDEV_PARAM_WAPI_MBSSID_OFFSET,
        .arp_srcaddr = WMI_10_4_PDEV_PARAM_ARP_SRCADDR,
        .arp_dstaddr = WMI_10_4_PDEV_PARAM_ARP_DSTADDR,
+       .enable_btcoex = WMI_10_4_PDEV_PARAM_ENABLE_BTCOEX,
 };
 
 static const struct wmi_peer_flags_map wmi_peer_flags_map = {
index 9fdf47e..90f594e 100644 (file)
@@ -3447,6 +3447,7 @@ struct wmi_pdev_param_map {
        u32 wapi_mbssid_offset;
        u32 arp_srcaddr;
        u32 arp_dstaddr;
+       u32 enable_btcoex;
 };
 
 #define WMI_PDEV_PARAM_UNSUPPORTED 0
@@ -3760,6 +3761,9 @@ enum wmi_10_4_pdev_param {
        WMI_10_4_PDEV_PARAM_ATF_OBSS_NOISE_SCH,
        WMI_10_4_PDEV_PARAM_ATF_OBSS_NOISE_SCALING_FACTOR,
        WMI_10_4_PDEV_PARAM_CUST_TXPOWER_SCALE,
+       WMI_10_4_PDEV_PARAM_ATF_DYNAMIC_ENABLE,
+       WMI_10_4_PDEV_PARAM_ATF_SSID_GROUP_POLICY,
+       WMI_10_4_PDEV_PARAM_ENABLE_BTCOEX,
 };
 
 struct wmi_pdev_set_param_cmd {
index fc47b70..f23c851 100644 (file)
@@ -219,8 +219,8 @@ ath5k_hw_get_default_sifs(struct ath5k_hw *ah)
                sifs = AR5K_INIT_SIFS_QUARTER_RATE;
                break;
        case AR5K_BWMODE_DEFAULT:
-               sifs = AR5K_INIT_SIFS_DEFAULT_BG;
        default:
+               sifs = AR5K_INIT_SIFS_DEFAULT_BG;
                if (channel->band == NL80211_BAND_5GHZ)
                        sifs = AR5K_INIT_SIFS_DEFAULT_A;
                break;
index 7a1970e..ac25f17 100644 (file)
@@ -148,7 +148,7 @@ enum ath6kl_fw_capability {
        /* ratetable is the 2 stream version (max MCS15) */
        ATH6KL_FW_CAPABILITY_RATETABLE_MCS15,
 
-       /* firmare doesn't support IP checksumming */
+       /* firmware doesn't support IP checksumming */
        ATH6KL_FW_CAPABILITY_NO_IP_CHECKSUM,
 
        /* this needs to be last */
index 631c3a0..b8cf04d 100644 (file)
@@ -2544,8 +2544,7 @@ int ath6kl_wmi_create_pstream_cmd(struct wmi *wmi, u8 if_idx,
        s32 nominal_phy = 0;
        int ret;
 
-       if (!((params->user_pri < 8) &&
-             (params->user_pri <= 0x7) &&
+       if (!((params->user_pri <= 0x7) &&
              (up_to_ac[params->user_pri & 0x7] == params->traffic_class) &&
              (params->traffic_direc == UPLINK_TRAFFIC ||
               params->traffic_direc == DNLINK_TRAFFIC ||
index dec1a31..d0224fc 100644 (file)
@@ -3202,8 +3202,7 @@ static int ar9300_compress_decision(struct ath_hw *ah,
                        it, length);
                break;
        case _CompressBlock:
-               if (reference == 0) {
-               } else {
+               if (reference != 0) {
                        eep = ar9003_eeprom_struct_find_by_id(reference);
                        if (eep == NULL) {
                                ath_dbg(common, EEPROM,
index ac4781f..16aca9e 100644 (file)
@@ -132,7 +132,6 @@ static int ath9k_tx99_init(struct ath_softc *sc)
        ath9k_ps_wakeup(sc);
 
        ath9k_hw_disable_interrupts(ah);
-       atomic_set(&ah->intr_ref_cnt, -1);
        ath_drain_all_txq(sc);
        ath_stoprecv(sc);
 
@@ -266,7 +265,7 @@ static const struct file_operations fops_tx99_power = {
 
 void ath9k_tx99_init_debug(struct ath_softc *sc)
 {
-       if (!AR_SREV_9300_20_OR_LATER(sc->sc_ah))
+       if (!AR_SREV_9280_20_OR_LATER(sc->sc_ah))
                return;
 
        debugfs_create_file("tx99", S_IRUSR | S_IWUSR,
index 5769811..62bf933 100644 (file)
@@ -378,6 +378,10 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
        /* social scan on P2P_DEVICE is handled as p2p search */
        if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE &&
            wil_p2p_is_social_scan(request)) {
+               if (!wil->p2p.p2p_dev_started) {
+                       wil_err(wil, "P2P search requested on stopped P2P device\n");
+                       return -EIO;
+               }
                wil->scan_request = request;
                wil->radio_wdev = wdev;
                rc = wil_p2p_search(wil, request);
@@ -1351,6 +1355,7 @@ static int wil_cfg80211_start_p2p_device(struct wiphy *wiphy,
        struct wil6210_priv *wil = wiphy_to_wil(wiphy);
 
        wil_dbg_misc(wil, "%s: entered\n", __func__);
+       wil->p2p.p2p_dev_started = 1;
        return 0;
 }
 
@@ -1358,8 +1363,19 @@ static void wil_cfg80211_stop_p2p_device(struct wiphy *wiphy,
                                         struct wireless_dev *wdev)
 {
        struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+       u8 started;
 
        wil_dbg_misc(wil, "%s: entered\n", __func__);
+       mutex_lock(&wil->mutex);
+       started = wil_p2p_stop_discovery(wil);
+       if (started && wil->scan_request) {
+               cfg80211_scan_done(wil->scan_request, 1);
+               wil->scan_request = NULL;
+               wil->radio_wdev = wil->wdev;
+       }
+       mutex_unlock(&wil->mutex);
+
+       wil->p2p.p2p_dev_started = 0;
 }
 
 static struct cfg80211_ops wil_cfg80211_ops = {
index c312a66..217a459 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013 Qualcomm Atheros, Inc.
+ * Copyright (c) 2013,2016 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 
 void __wil_err(struct wil6210_priv *wil, const char *fmt, ...)
 {
-       struct net_device *ndev = wil_to_ndev(wil);
-       struct va_format vaf = {
-               .fmt = fmt,
-       };
+       struct va_format vaf;
        va_list args;
 
        va_start(args, fmt);
+       vaf.fmt = fmt;
        vaf.va = &args;
-       netdev_err(ndev, "%pV", &vaf);
+       netdev_err(wil_to_ndev(wil), "%pV", &vaf);
        trace_wil6210_log_err(&vaf);
        va_end(args);
 }
 
 void __wil_err_ratelimited(struct wil6210_priv *wil, const char *fmt, ...)
 {
-       if (net_ratelimit()) {
-               struct net_device *ndev = wil_to_ndev(wil);
-               struct va_format vaf = {
-                       .fmt = fmt,
-               };
-               va_list args;
+       struct va_format vaf;
+       va_list args;
 
-               va_start(args, fmt);
-               vaf.va = &args;
-               netdev_err(ndev, "%pV", &vaf);
-               trace_wil6210_log_err(&vaf);
-               va_end(args);
-       }
+       if (!net_ratelimit())
+               return;
+
+       va_start(args, fmt);
+       vaf.fmt = fmt;
+       vaf.va = &args;
+       netdev_err(wil_to_ndev(wil), "%pV", &vaf);
+       trace_wil6210_log_err(&vaf);
+       va_end(args);
 }
 
 void wil_dbg_ratelimited(const struct wil6210_priv *wil, const char *fmt, ...)
@@ -67,27 +64,24 @@ void wil_dbg_ratelimited(const struct wil6210_priv *wil, const char *fmt, ...)
 
 void __wil_info(struct wil6210_priv *wil, const char *fmt, ...)
 {
-       struct net_device *ndev = wil_to_ndev(wil);
-       struct va_format vaf = {
-               .fmt = fmt,
-       };
+       struct va_format vaf;
        va_list args;
 
        va_start(args, fmt);
+       vaf.fmt = fmt;
        vaf.va = &args;
-       netdev_info(ndev, "%pV", &vaf);
+       netdev_info(wil_to_ndev(wil), "%pV", &vaf);
        trace_wil6210_log_info(&vaf);
        va_end(args);
 }
 
 void wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...)
 {
-       struct va_format vaf = {
-               .fmt = fmt,
-       };
+       struct va_format vaf;
        va_list args;
 
        va_start(args, fmt);
+       vaf.fmt = fmt;
        vaf.va = &args;
        trace_wil6210_log_dbg(&vaf);
        va_end(args);
index 1c91538..213b825 100644 (file)
@@ -114,8 +114,10 @@ int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration,
        u8 channel = P2P_DMG_SOCIAL_CHANNEL;
        int rc;
 
-       if (chan)
-               channel = chan->hw_value;
+       if (!chan)
+               return -EINVAL;
+
+       channel = chan->hw_value;
 
        wil_dbg_misc(wil, "%s: duration %d\n", __func__, duration);
 
index aeb72c4..7b5c422 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #include <linux/pci.h>
 #include <linux/moduleparam.h>
 #include <linux/interrupt.h>
-
+#include <linux/suspend.h>
 #include "wil6210.h"
 
 static bool use_msi = true;
 module_param(use_msi, bool, S_IRUGO);
 MODULE_PARM_DESC(use_msi, " Use MSI interrupt, default - true");
 
+#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
+static int wil6210_pm_notify(struct notifier_block *notify_block,
+                            unsigned long mode, void *unused);
+#endif /* CONFIG_PM_SLEEP */
+#endif /* CONFIG_PM */
+
 static
 void wil_set_capabilities(struct wil6210_priv *wil)
 {
@@ -238,6 +245,18 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto bus_disable;
        }
 
+#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
+       wil->pm_notify.notifier_call = wil6210_pm_notify;
+       rc = register_pm_notifier(&wil->pm_notify);
+       if (rc)
+               /* Do not fail the driver initialization, as suspend can
+                * be prevented in a later phase if needed
+                */
+               wil_err(wil, "register_pm_notifier failed: %d\n", rc);
+#endif /* CONFIG_PM_SLEEP */
+#endif /* CONFIG_PM */
+
        wil6210_debugfs_init(wil);
 
 
@@ -267,6 +286,12 @@ static void wil_pcie_remove(struct pci_dev *pdev)
 
        wil_dbg_misc(wil, "%s()\n", __func__);
 
+#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
+       unregister_pm_notifier(&wil->pm_notify);
+#endif /* CONFIG_PM_SLEEP */
+#endif /* CONFIG_PM */
+
        wil6210_debugfs_remove(wil);
        wil_if_remove(wil);
        wil_if_pcie_disable(wil);
@@ -335,6 +360,45 @@ static int wil6210_resume(struct device *dev, bool is_runtime)
        return rc;
 }
 
+static int wil6210_pm_notify(struct notifier_block *notify_block,
+                            unsigned long mode, void *unused)
+{
+       struct wil6210_priv *wil = container_of(
+               notify_block, struct wil6210_priv, pm_notify);
+       int rc = 0;
+       enum wil_platform_event evt;
+
+       wil_dbg_pm(wil, "%s: mode (%ld)\n", __func__, mode);
+
+       switch (mode) {
+       case PM_HIBERNATION_PREPARE:
+       case PM_SUSPEND_PREPARE:
+       case PM_RESTORE_PREPARE:
+               rc = wil_can_suspend(wil, false);
+               if (rc)
+                       break;
+               evt = WIL_PLATFORM_EVT_PRE_SUSPEND;
+               if (wil->platform_ops.notify)
+                       rc = wil->platform_ops.notify(wil->platform_handle,
+                                                     evt);
+               break;
+       case PM_POST_SUSPEND:
+       case PM_POST_HIBERNATION:
+       case PM_POST_RESTORE:
+               evt = WIL_PLATFORM_EVT_POST_SUSPEND;
+               if (wil->platform_ops.notify)
+                       rc = wil->platform_ops.notify(wil->platform_handle,
+                                                     evt);
+               break;
+       default:
+               wil_dbg_pm(wil, "unhandled notify mode %ld\n", mode);
+               break;
+       }
+
+       wil_dbg_pm(wil, "notification mode %ld: rc (%d)\n", mode, rc);
+       return rc;
+}
+
 static int wil6210_pm_suspend(struct device *dev)
 {
        return wil6210_suspend(dev, false);
index 0b7ecbc..11ee24d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2014,2016 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -24,10 +24,32 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
        wil_dbg_pm(wil, "%s(%s)\n", __func__,
                   is_runtime ? "runtime" : "system");
 
+       if (!netif_running(wil_to_ndev(wil))) {
+               /* can always sleep when down */
+               wil_dbg_pm(wil, "Interface is down\n");
+               goto out;
+       }
+       if (test_bit(wil_status_resetting, wil->status)) {
+               wil_dbg_pm(wil, "Delay suspend when resetting\n");
+               rc = -EBUSY;
+               goto out;
+       }
+       if (wil->recovery_state != fw_recovery_idle) {
+               wil_dbg_pm(wil, "Delay suspend during recovery\n");
+               rc = -EBUSY;
+               goto out;
+       }
+
+       /* interface is running */
        switch (wdev->iftype) {
        case NL80211_IFTYPE_MONITOR:
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_P2P_CLIENT:
+               if (test_bit(wil_status_fwconnecting, wil->status)) {
+                       wil_dbg_pm(wil, "Delay suspend when connecting\n");
+                       rc = -EBUSY;
+                       goto out;
+               }
                break;
        /* AP-like interface - can't suspend */
        default:
@@ -36,6 +58,7 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
                break;
        }
 
+out:
        wil_dbg_pm(wil, "%s(%s) => %s (%d)\n", __func__,
                   is_runtime ? "runtime" : "system", rc ? "No" : "Yes", rc);
 
index a4e4379..f2f6a40 100644 (file)
@@ -184,6 +184,13 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring,
                                        &vring->va[vring->swtail].tx;
 
                        ctx = &vring->ctx[vring->swtail];
+                       if (!ctx) {
+                               wil_dbg_txrx(wil,
+                                            "ctx(%d) was already completed\n",
+                                            vring->swtail);
+                               vring->swtail = wil_vring_next_tail(vring);
+                               continue;
+                       }
                        *d = *_d;
                        wil_txdesc_unmap(dev, d, ctx);
                        if (ctx->skb)
@@ -544,6 +551,12 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count)
                        break;
                }
        }
+
+       /* make sure all writes to descriptors (shared memory) are done before
+        * committing them to HW
+        */
+       wmb();
+
        wil_w(wil, v->hwtail, v->swtail);
 
        return rc;
@@ -969,6 +982,13 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
        txdata->dot1x_open = false;
        txdata->enabled = 0; /* no Tx can be in progress or start anew */
        spin_unlock_bh(&txdata->lock);
+       /* napi_synchronize waits for completion of the current NAPI but will
+        * not prevent the next NAPI run.
+        * Add a memory barrier to guarantee that txdata->enabled is zeroed
+        * before napi_synchronize so that the next scheduled NAPI will not
+        * handle this vring
+        */
+       wmb();
        /* make sure NAPI won't touch this vring */
        if (test_bit(wil_status_napi_en, wil->status))
                napi_synchronize(&wil->napi_tx);
@@ -1551,6 +1571,13 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring,
                             vring_index, used, used + descs_used);
        }
 
+       /* Make sure to advance the head only after descriptor update is done.
+        * This will prevent a race condition where the completion thread
+        * will see the DU bit set from previous run and will handle the
+        * skb before it was completed.
+        */
+       wmb();
+
        /* advance swhead */
        wil_vring_advance_head(vring, descs_used);
        wil_dbg_txrx(wil, "TSO: Tx swhead %d -> %d\n", swhead, vring->swhead);
@@ -1567,7 +1594,7 @@ mem_error:
        while (descs_used > 0) {
                struct wil_ctx *ctx;
 
-               i = (swhead + descs_used) % vring->size;
+               i = (swhead + descs_used - 1) % vring->size;
                d = (struct vring_tx_desc *)&vring->va[i].tx;
                _desc = &vring->va[i].tx;
                *d = *_desc;
@@ -1691,6 +1718,13 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
                             vring_index, used, used + nr_frags + 1);
        }
 
+       /* Make sure to advance the head only after descriptor update is done.
+        * This will prevent a race condition where the completion thread
+        * will see the DU bit set from previous run and will handle the
+        * skb before it was completed.
+        */
+       wmb();
+
        /* advance swhead */
        wil_vring_advance_head(vring, nr_frags + 1);
        wil_dbg_txrx(wil, "Tx[%2d] swhead %d -> %d\n", vring_index, swhead,
@@ -1914,6 +1948,12 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
                                wil_consume_skb(skb, d->dma.error == 0);
                        }
                        memset(ctx, 0, sizeof(*ctx));
+                       /* Make sure the ctx is zeroed before updating the tail
+                        * to prevent a case where wil_tx_vring will see
+                        * this descriptor as used and handle it before ctx zero
+                        * is completed.
+                        */
+                       wmb();
                        /* There is no need to touch HW descriptor:
                         * - ststus bit TX_DMA_STATUS_DU is set by design,
                         *   so hardware will not try to process this desc.,
index aa09cbc..ecab4af 100644 (file)
@@ -458,6 +458,7 @@ struct wil_tid_crypto_rx {
 struct wil_p2p_info {
        struct ieee80211_channel listen_chan;
        u8 discovery_started;
+       u8 p2p_dev_started;
        u64 cookie;
        struct timer_list discovery_timer; /* listen/search duration */
        struct work_struct discovery_expired_work; /* listen/search expire */
@@ -662,6 +663,11 @@ struct wil6210_priv {
        /* High Access Latency Policy voting */
        struct wil_halp halp;
 
+#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
+       struct notifier_block pm_notify;
+#endif /* CONFIG_PM_SLEEP */
+#endif /* CONFIG_PM */
 };
 
 #define wil_to_wiphy(i) (i->wdev->wiphy)
index 33d4a34..f8c4117 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2015 Qualcomm Atheros, Inc.
+ * Copyright (c) 2014-2016 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -23,6 +23,8 @@ enum wil_platform_event {
        WIL_PLATFORM_EVT_FW_CRASH = 0,
        WIL_PLATFORM_EVT_PRE_RESET = 1,
        WIL_PLATFORM_EVT_FW_RDY = 2,
+       WIL_PLATFORM_EVT_PRE_SUSPEND = 3,
+       WIL_PLATFORM_EVT_POST_SUSPEND = 4,
 };
 
 /**