Merge remote branch 'wireless-next/master' into ath6kl-next
authorKalle Valo <kvalo@qca.qualcomm.com>
Thu, 14 Jun 2012 11:20:18 +0000 (14:20 +0300)
committerKalle Valo <kvalo@qca.qualcomm.com>
Thu, 14 Jun 2012 11:44:49 +0000 (14:44 +0300)
Conflicts:
drivers/net/wireless/ath/ath6kl/cfg80211.c

drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath6kl/cfg80211.h
drivers/net/wireless/ath/ath6kl/core.h
drivers/net/wireless/ath/ath6kl/htc_mbox.c
drivers/net/wireless/ath/ath6kl/init.c
drivers/net/wireless/ath/ath6kl/main.c
drivers/net/wireless/ath/ath6kl/target.h
drivers/net/wireless/ath/ath6kl/txrx.c
drivers/net/wireless/ath/ath6kl/wmi.c
drivers/net/wireless/ath/ath6kl/wmi.h

index f27e973..fd7dbd4 100644 (file)
 
 #define DEFAULT_BG_SCAN_PERIOD 60
 
+struct ath6kl_cfg80211_match_probe_ssid {
+       struct cfg80211_ssid ssid;
+       u8 flag;
+};
+
 static struct ieee80211_rate ath6kl_rates[] = {
        RATETAB_ENT(10, 0x1, 0),
        RATETAB_ENT(20, 0x2, 0),
@@ -576,6 +581,9 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
 
        vif->nw_type = vif->next_mode;
 
+       /* enable enhanced bmiss detection if applicable */
+       ath6kl_cfg80211_sta_bmiss_enhance(vif, true);
+
        if (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)
                nw_subtype = SUBTYPE_P2PCLIENT;
 
@@ -852,20 +860,6 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
                }
        }
 
-       /*
-        * Send a disconnect command to target when a disconnect event is
-        * received with reason code other than 3 (DISCONNECT_CMD - disconnect
-        * request from host) to make the firmware stop trying to connect even
-        * after giving disconnect event. There will be one more disconnect
-        * event for this disconnect command with reason code DISCONNECT_CMD
-        * which will be notified to cfg80211.
-        */
-
-       if (reason != DISCONNECT_CMD) {
-               ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
-               return;
-       }
-
        clear_bit(CONNECT_PEND, &vif->flags);
 
        if (vif->sme_state == SME_CONNECTING) {
@@ -875,32 +869,96 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
                                        WLAN_STATUS_UNSPECIFIED_FAILURE,
                                        GFP_KERNEL);
        } else if (vif->sme_state == SME_CONNECTED) {
-               cfg80211_disconnected(vif->ndev, reason,
+               cfg80211_disconnected(vif->ndev, proto_reason,
                                      NULL, 0, GFP_KERNEL);
        }
 
        vif->sme_state = SME_DISCONNECTED;
+
+       /*
+        * Send a disconnect command to target when a disconnect event is
+        * received with reason code other than 3 (DISCONNECT_CMD - disconnect
+        * request from host) to make the firmware stop trying to connect even
+        * after giving disconnect event. There will be one more disconnect
+        * event for this disconnect command with reason code DISCONNECT_CMD
+        * which won't be notified to cfg80211.
+        */
+       if (reason != DISCONNECT_CMD)
+               ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
 }
 
 static int ath6kl_set_probed_ssids(struct ath6kl *ar,
                                   struct ath6kl_vif *vif,
-                                  struct cfg80211_ssid *ssids, int n_ssids)
+                                  struct cfg80211_ssid *ssids, int n_ssids,
+                                  struct cfg80211_match_set *match_set,
+                                  int n_match_ssid)
 {
-       u8 i;
+       u8 i, j, index_to_add, ssid_found = false;
+       struct ath6kl_cfg80211_match_probe_ssid ssid_list[MAX_PROBED_SSIDS];
+
+       memset(ssid_list, 0, sizeof(ssid_list));
 
-       if (n_ssids > MAX_PROBED_SSID_INDEX)
+       if (n_ssids > MAX_PROBED_SSIDS ||
+           n_match_ssid > MAX_PROBED_SSIDS)
                return -EINVAL;
 
        for (i = 0; i < n_ssids; i++) {
+               memcpy(ssid_list[i].ssid.ssid,
+                      ssids[i].ssid,
+                      ssids[i].ssid_len);
+               ssid_list[i].ssid.ssid_len = ssids[i].ssid_len;
+
+               if (ssids[i].ssid_len)
+                       ssid_list[i].flag = SPECIFIC_SSID_FLAG;
+               else
+                       ssid_list[i].flag = ANY_SSID_FLAG;
+
+               if (n_match_ssid == 0)
+                       ssid_list[i].flag |= MATCH_SSID_FLAG;
+       }
+
+       index_to_add = i;
+
+       for (i = 0; i < n_match_ssid; i++) {
+               ssid_found = false;
+
+               for (j = 0; j < n_ssids; j++) {
+                       if ((match_set[i].ssid.ssid_len ==
+                            ssid_list[j].ssid.ssid_len) &&
+                           (!memcmp(ssid_list[j].ssid.ssid,
+                                    match_set[i].ssid.ssid,
+                                    match_set[i].ssid.ssid_len))) {
+                               ssid_list[j].flag |= MATCH_SSID_FLAG;
+                               ssid_found = true;
+                               break;
+                       }
+               }
+
+               if (ssid_found)
+                       continue;
+
+               if (index_to_add >= MAX_PROBED_SSIDS)
+                       continue;
+
+               ssid_list[index_to_add].ssid.ssid_len =
+                       match_set[i].ssid.ssid_len;
+               memcpy(ssid_list[index_to_add].ssid.ssid,
+                      match_set[i].ssid.ssid,
+                      match_set[i].ssid.ssid_len);
+               ssid_list[index_to_add].flag |= MATCH_SSID_FLAG;
+               index_to_add++;
+       }
+
+       for (i = 0; i < index_to_add; i++) {
                ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i,
-                                         ssids[i].ssid_len ?
-                                         SPECIFIC_SSID_FLAG : ANY_SSID_FLAG,
-                                         ssids[i].ssid_len,
-                                         ssids[i].ssid);
+                                         ssid_list[i].flag,
+                                         ssid_list[i].ssid.ssid_len,
+                                         ssid_list[i].ssid.ssid);
+
        }
 
        /* Make sure no old entries are left behind */
-       for (i = n_ssids; i < MAX_PROBED_SSID_INDEX; i++) {
+       for (i = index_to_add; i < MAX_PROBED_SSIDS; i++) {
                ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i,
                                          DISABLE_SSID_FLAG, 0, NULL);
        }
@@ -934,7 +992,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
        }
 
        ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
-                                     request->n_ssids);
+                                     request->n_ssids, NULL, 0);
        if (ret < 0)
                return ret;
 
@@ -943,7 +1001,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
                                       WMI_FRAME_PROBE_REQ,
                                       request->ie, request->ie_len);
        if (ret) {
-               ath6kl_err("failed to set Probe Request appie for scan");
+               ath6kl_err("failed to set Probe Request appie for scan\n");
                return ret;
        }
 
@@ -1512,6 +1570,9 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
                }
        }
 
+       /* need to clean up enhanced bmiss detection fw state */
+       ath6kl_cfg80211_sta_bmiss_enhance(vif, false);
+
 set_iface_type:
        switch (type) {
        case NL80211_IFTYPE_STATION:
@@ -2074,7 +2135,9 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
        if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST))
                return -EINVAL;
 
-       if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags)) {
+       if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags) &&
+           test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
+                    ar->fw_capabilities)) {
                ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi,
                                                vif->fw_vif_idx, false);
                if (ret)
@@ -2209,7 +2272,9 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
 
        ar->state = ATH6KL_STATE_ON;
 
-       if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags)) {
+       if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags) &&
+           test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
+                    ar->fw_capabilities)) {
                ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi,
                                        vif->fw_vif_idx, true);
                if (ret)
@@ -2475,7 +2540,7 @@ void ath6kl_check_wow_status(struct ath6kl *ar)
 static int ath6kl_set_htcap(struct ath6kl_vif *vif, enum ieee80211_band band,
                            bool ht_enable)
 {
-       struct ath6kl_htcap *htcap = &vif->htcap;
+       struct ath6kl_htcap *htcap = &vif->htcap[band];
 
        if (htcap->ht_enable == ht_enable)
                return 0;
@@ -2585,6 +2650,30 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif,
        return 0;
 }
 
+void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, bool enable)
+{
+       int err;
+
+       if (WARN_ON(!test_bit(WMI_READY, &vif->ar->flag)))
+               return;
+
+       if (vif->nw_type != INFRA_NETWORK)
+               return;
+
+       if (!test_bit(ATH6KL_FW_CAPABILITY_BMISS_ENHANCE,
+                     vif->ar->fw_capabilities))
+               return;
+
+       ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s fw bmiss enhance\n",
+                  enable ? "enable" : "disable");
+
+       err = ath6kl_wmi_sta_bmiss_enhance_cmd(vif->ar->wmi,
+                                              vif->fw_vif_idx, enable);
+       if (err)
+               ath6kl_err("failed to %s enhanced bmiss detection: %d\n",
+                          enable ? "enable" : "disable", err);
+}
+
 static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon,
                                u8 *rsn_capab)
 {
@@ -2665,9 +2754,15 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
 
        /* TODO:
         * info->interval
-        * info->dtim_period
         */
 
+       ret = ath6kl_wmi_ap_set_dtim_cmd(ar->wmi, vif->fw_vif_idx,
+                                        info->dtim_period);
+
+       /* ignore error, just print a warning and continue normally */
+       if (ret)
+               ath6kl_warn("Failed to set dtim_period in beacon: %d\n", ret);
+
        if (info->beacon.head == NULL)
                return -EINVAL;
        mgmt = (struct ieee80211_mgmt *) info->beacon.head;
@@ -3131,10 +3226,24 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
        ath6kl_cfg80211_scan_complete_event(vif, true);
 
        ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
-                                     request->n_ssids);
+                                     request->n_ssids,
+                                     request->match_sets,
+                                     request->n_match_sets);
        if (ret < 0)
                return ret;
 
+       if (!request->n_match_sets) {
+               ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
+                                              ALL_BSS_FILTER, 0);
+               if (ret < 0)
+                       return ret;
+       } else {
+                ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
+                                               MATCHED_SSID_FILTER, 0);
+               if (ret < 0)
+                       return ret;
+       }
+
        /* fw uses seconds, also make sure that it's >0 */
        interval = max_t(u16, 1, request->interval / 1000);
 
@@ -3156,7 +3265,7 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
                                       WMI_FRAME_PROBE_REQ,
                                       request->ie, request->ie_len);
        if (ret) {
-               ath6kl_warn("Failed to set probe request IE for scheduled scan: %d",
+               ath6kl_warn("Failed to set probe request IE for scheduled scan: %d\n",
                            ret);
                return ret;
        }
@@ -3188,6 +3297,18 @@ static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy,
        return 0;
 }
 
+static int ath6kl_cfg80211_set_bitrate(struct wiphy *wiphy,
+                                      struct net_device *dev,
+                                      const u8 *addr,
+                                      const struct cfg80211_bitrate_mask *mask)
+{
+       struct ath6kl *ar = ath6kl_priv(dev);
+       struct ath6kl_vif *vif = netdev_priv(dev);
+
+       return ath6kl_wmi_set_bitrate_mask(ar->wmi, vif->fw_vif_idx,
+                                          mask);
+}
+
 static const struct ieee80211_txrx_stypes
 ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
        [NL80211_IFTYPE_STATION] = {
@@ -3253,6 +3374,7 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
        .mgmt_frame_register = ath6kl_mgmt_frame_register,
        .sched_scan_start = ath6kl_cfg80211_sscan_start,
        .sched_scan_stop = ath6kl_cfg80211_sscan_stop,
+       .set_bitrate_mask = ath6kl_cfg80211_set_bitrate,
 };
 
 void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
@@ -3380,7 +3502,8 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
        vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL;
        vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME;
        vif->bg_scan_period = 0;
-       vif->htcap.ht_enable = true;
+       vif->htcap[IEEE80211_BAND_2GHZ].ht_enable = true;
+       vif->htcap[IEEE80211_BAND_5GHZ].ht_enable = true;
 
        memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
        if (fw_vif_idx != 0)
@@ -3440,7 +3563,13 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
        }
 
        /* max num of ssids that can be probed during scanning */
-       wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
+       wiphy->max_scan_ssids = MAX_PROBED_SSIDS;
+
+       /* max num of ssids that can be matched after scan */
+       if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST,
+                    ar->fw_capabilities))
+               wiphy->max_match_sets = MAX_PROBED_SSIDS;
+
        wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
        switch (ar->hw.cap) {
        case WMI_11AN_CAP:
@@ -3477,6 +3606,17 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
                ath6kl_band_5ghz.ht_cap.cap = 0;
                ath6kl_band_5ghz.ht_cap.ht_supported = false;
        }
+
+       if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES) {
+               ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;
+               ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
+               ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff;
+               ath6kl_band_5ghz.ht_cap.mcs.rx_mask[1] = 0xff;
+       } else {
+               ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;
+               ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
+       }
+
        if (band_2gig)
                wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
        if (band_5gig)
@@ -3497,7 +3637,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
        wiphy->wowlan.pattern_min_len = 1;
        wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
 
-       wiphy->max_sched_scan_ssids = MAX_PROBED_SSID_INDEX;
+       wiphy->max_sched_scan_ssids = MAX_PROBED_SSIDS;
 
        ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
                            WIPHY_FLAG_HAVE_AP_SME |
index 5ea8cbb..b992046 100644 (file)
@@ -62,5 +62,7 @@ void ath6kl_cfg80211_cleanup(struct ath6kl *ar);
 
 struct ath6kl *ath6kl_cfg80211_create(void);
 void ath6kl_cfg80211_destroy(struct ath6kl *ar);
+/* TODO: remove this once ath6kl_vif_cleanup() is moved to cfg80211.c */
+void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, bool enable);
 
 #endif /* ATH6KL_CFG80211_H */
index 8443b2a..d38a31d 100644 (file)
@@ -100,6 +100,21 @@ enum ath6kl_fw_capability {
        /* Firmware has support to override rsn cap of rsn ie */
        ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
 
+       /*
+        * Multicast support in WOW and host awake mode.
+        * Allow all multicast in host awake mode.
+        * Apply multicast filter in WOW mode.
+        */
+       ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
+
+       /* Firmware supports enhanced bmiss detection */
+       ATH6KL_FW_CAPABILITY_BMISS_ENHANCE,
+
+       /*
+        * FW supports matching of ssid in schedule scan
+        */
+       ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST,
+
        /* this needs to be last */
        ATH6KL_FW_CAPABILITY_MAX,
 };
@@ -112,6 +127,10 @@ struct ath6kl_fw_ie {
        u8 data[0];
 };
 
+enum ath6kl_hw_flags {
+       ATH6KL_HW_FLAG_64BIT_RATES      = BIT(0),
+};
+
 #define ATH6KL_FW_API2_FILE "fw-2.bin"
 #define ATH6KL_FW_API3_FILE "fw-3.bin"
 
@@ -196,7 +215,7 @@ struct ath6kl_fw_ie {
 
 #define AGGR_NUM_OF_FREE_NETBUFS    16
 
-#define AGGR_RX_TIMEOUT     400        /* in ms */
+#define AGGR_RX_TIMEOUT     100        /* in ms */
 
 #define WMI_TIMEOUT (2 * HZ)
 
@@ -245,7 +264,6 @@ struct skb_hold_q {
 
 struct rxtid {
        bool aggr;
-       bool progress;
        bool timer_mon;
        u16 win_sz;
        u16 seq_next;
@@ -254,9 +272,15 @@ struct rxtid {
        struct sk_buff_head q;
 
        /*
-        * FIXME: No clue what this should protect. Apparently it should
-        * protect some of the fields above but they are also accessed
-        * without taking the lock.
+        * lock mainly protects seq_next and hold_q. Movement of seq_next
+        * needs to be protected between aggr_timeout() and
+        * aggr_process_recv_frm(). hold_q will be holding the pending
+        * reorder frames and it's access should also be protected.
+        * Some of the other fields like hold_q_sz, win_sz and aggr are
+        * initialized/reset when receiving addba/delba req, also while
+        * deleting aggr state all the pending buffers are flushed before
+        * resetting these fields, so there should not be any race in accessing
+        * these fields.
         */
        spinlock_t lock;
 };
@@ -541,7 +565,7 @@ struct ath6kl_vif {
        struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1];
        struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1];
        struct aggr_info *aggr_cntxt;
-       struct ath6kl_htcap htcap;
+       struct ath6kl_htcap htcap[IEEE80211_NUM_BANDS];
 
        struct timer_list disconnect_timer;
        struct timer_list sched_scan_timer;
@@ -684,6 +708,8 @@ struct ath6kl {
                u32 testscript_addr;
                enum wmi_phy_cap cap;
 
+               u32 flags;
+
                struct ath6kl_hw_fw {
                        const char *dir;
                        const char *otp;
index 2798624..cd0e1ba 100644 (file)
@@ -1309,7 +1309,7 @@ static int ath6kl_htc_rx_packet(struct htc_target *target,
        }
 
        ath6kl_dbg(ATH6KL_DBG_HTC,
-                  "htc rx 0x%p hdr x%x len %d mbox 0x%x\n",
+                  "htc rx 0x%p hdr 0x%x len %d mbox 0x%x\n",
                   packet, packet->info.rx.exp_hdr,
                   padded_len, dev->ar->mbox_info.htc_addr);
 
index 7eb0515..f90b5db 100644 (file)
@@ -42,6 +42,7 @@ static const struct ath6kl_hw hw_list[] = {
                .reserved_ram_size              = 6912,
                .refclk_hz                      = 26000000,
                .uarttx_pin                     = 8,
+               .flags                          = 0,
 
                /* hw2.0 needs override address hardcoded */
                .app_start_override_addr        = 0x944C00,
@@ -67,6 +68,7 @@ static const struct ath6kl_hw hw_list[] = {
                .refclk_hz                      = 26000000,
                .uarttx_pin                     = 8,
                .testscript_addr                = 0x57ef74,
+               .flags                          = 0,
 
                .fw = {
                        .dir            = AR6003_HW_2_1_1_FW_DIR,
@@ -91,6 +93,7 @@ static const struct ath6kl_hw hw_list[] = {
                .board_addr                     = 0x433900,
                .refclk_hz                      = 26000000,
                .uarttx_pin                     = 11,
+               .flags                          = ATH6KL_HW_FLAG_64BIT_RATES,
 
                .fw = {
                        .dir            = AR6004_HW_1_0_FW_DIR,
@@ -110,6 +113,7 @@ static const struct ath6kl_hw hw_list[] = {
                .board_addr                     = 0x43d400,
                .refclk_hz                      = 40000000,
                .uarttx_pin                     = 11,
+               .flags                          = ATH6KL_HW_FLAG_64BIT_RATES,
 
                .fw = {
                        .dir            = AR6004_HW_1_1_FW_DIR,
@@ -129,6 +133,7 @@ static const struct ath6kl_hw hw_list[] = {
                .board_addr                     = 0x435c00,
                .refclk_hz                      = 40000000,
                .uarttx_pin                     = 11,
+               .flags                          = ATH6KL_HW_FLAG_64BIT_RATES,
 
                .fw = {
                        .dir            = AR6004_HW_1_2_FW_DIR,
@@ -938,6 +943,14 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
                }
 
                switch (ie_id) {
+               case ATH6KL_FW_IE_FW_VERSION:
+                       strlcpy(ar->wiphy->fw_version, data,
+                               sizeof(ar->wiphy->fw_version));
+
+                       ath6kl_dbg(ATH6KL_DBG_BOOT,
+                                  "found fw version %s\n",
+                                   ar->wiphy->fw_version);
+                       break;
                case ATH6KL_FW_IE_OTP_IMAGE:
                        ath6kl_dbg(ATH6KL_DBG_BOOT, "found otp image ie (%zd B)\n",
                                   ie_len);
@@ -991,9 +1004,6 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
                                   ar->hw.reserved_ram_size);
                        break;
                case ATH6KL_FW_IE_CAPABILITIES:
-                       if (ie_len < DIV_ROUND_UP(ATH6KL_FW_CAPABILITY_MAX, 8))
-                               break;
-
                        ath6kl_dbg(ATH6KL_DBG_BOOT,
                                   "found firmware capabilities ie (%zd B)\n",
                                   ie_len);
@@ -1002,6 +1012,9 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
                                index = i / 8;
                                bit = i % 8;
 
+                               if (index == ie_len)
+                                       break;
+
                                if (data[index] & (1 << bit))
                                        __set_bit(i, ar->fw_capabilities);
                        }
@@ -1392,6 +1405,12 @@ static int ath6kl_init_upload(struct ath6kl *ar)
            ar->version.target_ver == AR6003_HW_2_1_1_VERSION) {
                ath6kl_err("temporary war to avoid sdio crc error\n");
 
+               param = 0x28;
+               address = GPIO_BASE_ADDRESS + GPIO_PIN9_ADDRESS;
+               status = ath6kl_bmi_reg_write(ar, address, param);
+               if (status)
+                       return status;
+
                param = 0x20;
 
                address = GPIO_BASE_ADDRESS + GPIO_PIN10_ADDRESS;
@@ -1659,6 +1678,9 @@ void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready)
                cfg80211_scan_done(vif->scan_req, true);
                vif->scan_req = NULL;
        }
+
+       /* need to clean up enhanced bmiss detection fw state */
+       ath6kl_cfg80211_sta_bmiss_enhance(vif, false);
 }
 
 void ath6kl_stop_txrx(struct ath6kl *ar)
index b836f27..c189e28 100644 (file)
@@ -554,20 +554,24 @@ void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver,
        struct ath6kl *ar = devt;
 
        memcpy(ar->mac_addr, datap, ETH_ALEN);
-       ath6kl_dbg(ATH6KL_DBG_TRC, "%s: mac addr = %pM\n",
-                  __func__, ar->mac_addr);
+
+       ath6kl_dbg(ATH6KL_DBG_BOOT,
+                  "ready event mac addr %pM sw_ver 0x%x abi_ver 0x%x cap 0x%x\n",
+                  ar->mac_addr, sw_ver, abi_ver, cap);
 
        ar->version.wlan_ver = sw_ver;
        ar->version.abi_ver = abi_ver;
        ar->hw.cap = cap;
 
-       snprintf(ar->wiphy->fw_version,
-                sizeof(ar->wiphy->fw_version),
-                "%u.%u.%u.%u",
-                (ar->version.wlan_ver & 0xf0000000) >> 28,
-                (ar->version.wlan_ver & 0x0f000000) >> 24,
-                (ar->version.wlan_ver & 0x00ff0000) >> 16,
-                (ar->version.wlan_ver & 0x0000ffff));
+       if (strlen(ar->wiphy->fw_version) == 0) {
+               snprintf(ar->wiphy->fw_version,
+                        sizeof(ar->wiphy->fw_version),
+                        "%u.%u.%u.%u",
+                        (ar->version.wlan_ver & 0xf0000000) >> 28,
+                        (ar->version.wlan_ver & 0x0f000000) >> 24,
+                        (ar->version.wlan_ver & 0x00ff0000) >> 16,
+                        (ar->version.wlan_ver & 0x0000ffff));
+       }
 
        /* indicate to the waiting thread that the ready event was received */
        set_bit(WMI_READY, &ar->flag);
@@ -1166,7 +1170,10 @@ static void ath6kl_set_multicast_list(struct net_device *ndev)
        else
                clear_bit(NETDEV_MCAST_ALL_ON, &vif->flags);
 
-       mc_all_on = mc_all_on || (vif->ar->state == ATH6KL_STATE_ON);
+       if (test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
+                    vif->ar->fw_capabilities)) {
+               mc_all_on = mc_all_on || (vif->ar->state == ATH6KL_STATE_ON);
+       }
 
        if (!(ndev->flags & IFF_MULTICAST)) {
                mc_all_on = false;
index 78e0ef4..a98c12b 100644 (file)
@@ -45,6 +45,7 @@
 #define LPO_CAL_ENABLE_S               20
 #define LPO_CAL_ENABLE                 0x00100000
 
+#define GPIO_PIN9_ADDRESS              0x0000004c
 #define GPIO_PIN10_ADDRESS             0x00000050
 #define GPIO_PIN11_ADDRESS             0x00000054
 #define GPIO_PIN12_ADDRESS             0x00000058
index 67206ae..7dfa0fd 100644 (file)
@@ -1036,6 +1036,7 @@ static void aggr_deque_frms(struct aggr_info_conn *agg_conn, u8 tid,
        rxtid = &agg_conn->rx_tid[tid];
        stats = &agg_conn->stat[tid];
 
+       spin_lock_bh(&rxtid->lock);
        idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz);
 
        /*
@@ -1054,8 +1055,6 @@ static void aggr_deque_frms(struct aggr_info_conn *agg_conn, u8 tid,
        seq_end = seq_no ? seq_no : rxtid->seq_next;
        idx_end = AGGR_WIN_IDX(seq_end, rxtid->hold_q_sz);
 
-       spin_lock_bh(&rxtid->lock);
-
        do {
                node = &rxtid->hold_q[idx];
                if ((order == 1) && (!node->skb))
@@ -1127,11 +1126,13 @@ static bool aggr_process_recv_frm(struct aggr_info_conn *agg_conn, u8 tid,
                    ((end > extended_end) && (cur > extended_end) &&
                     (cur < end))) {
                        aggr_deque_frms(agg_conn, tid, 0, 0);
+                       spin_lock_bh(&rxtid->lock);
                        if (cur >= rxtid->hold_q_sz - 1)
                                rxtid->seq_next = cur - (rxtid->hold_q_sz - 1);
                        else
                                rxtid->seq_next = ATH6KL_MAX_SEQ_NO -
                                                  (rxtid->hold_q_sz - 2 - cur);
+                       spin_unlock_bh(&rxtid->lock);
                } else {
                        /*
                         * Dequeue only those frames that are outside the
@@ -1185,25 +1186,25 @@ static bool aggr_process_recv_frm(struct aggr_info_conn *agg_conn, u8 tid,
        aggr_deque_frms(agg_conn, tid, 0, 1);
 
        if (agg_conn->timer_scheduled)
-               rxtid->progress = true;
-       else
-               for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) {
-                       if (rxtid->hold_q[idx].skb) {
-                               /*
-                                * There is a frame in the queue and no
-                                * timer so start a timer to ensure that
-                                * the frame doesn't remain stuck
-                                * forever.
-                                */
-                               agg_conn->timer_scheduled = true;
-                               mod_timer(&agg_conn->timer,
-                                         (jiffies +
-                                          HZ * (AGGR_RX_TIMEOUT) / 1000));
-                               rxtid->progress = false;
-                               rxtid->timer_mon = true;
-                               break;
-                       }
+               return is_queued;
+
+       spin_lock_bh(&rxtid->lock);
+       for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) {
+               if (rxtid->hold_q[idx].skb) {
+                       /*
+                        * There is a frame in the queue and no
+                        * timer so start a timer to ensure that
+                        * the frame doesn't remain stuck
+                        * forever.
+                        */
+                       agg_conn->timer_scheduled = true;
+                       mod_timer(&agg_conn->timer,
+                                 (jiffies + (HZ * AGGR_RX_TIMEOUT) / 1000));
+                       rxtid->timer_mon = true;
+                       break;
                }
+       }
+       spin_unlock_bh(&rxtid->lock);
 
        return is_queued;
 }
@@ -1608,7 +1609,7 @@ static void aggr_timeout(unsigned long arg)
                rxtid = &aggr_conn->rx_tid[i];
                stats = &aggr_conn->stat[i];
 
-               if (!rxtid->aggr || !rxtid->timer_mon || rxtid->progress)
+               if (!rxtid->aggr || !rxtid->timer_mon)
                        continue;
 
                stats->num_timeouts++;
@@ -1626,14 +1627,15 @@ static void aggr_timeout(unsigned long arg)
                rxtid = &aggr_conn->rx_tid[i];
 
                if (rxtid->aggr && rxtid->hold_q) {
+                       spin_lock_bh(&rxtid->lock);
                        for (j = 0; j < rxtid->hold_q_sz; j++) {
                                if (rxtid->hold_q[j].skb) {
                                        aggr_conn->timer_scheduled = true;
                                        rxtid->timer_mon = true;
-                                       rxtid->progress = false;
                                        break;
                                }
                        }
+                       spin_unlock_bh(&rxtid->lock);
 
                        if (j >= rxtid->hold_q_sz)
                                rxtid->timer_mon = false;
@@ -1660,7 +1662,6 @@ static void aggr_delete_tid_state(struct aggr_info_conn *aggr_conn, u8 tid)
                aggr_deque_frms(aggr_conn, tid, 0, 0);
 
        rxtid->aggr = false;
-       rxtid->progress = false;
        rxtid->timer_mon = false;
        rxtid->win_sz = 0;
        rxtid->seq_next = 0;
@@ -1739,7 +1740,6 @@ void aggr_conn_init(struct ath6kl_vif *vif, struct aggr_info *aggr_info,
        for (i = 0; i < NUM_OF_TIDS; i++) {
                rxtid = &aggr_conn->rx_tid[i];
                rxtid->aggr = false;
-               rxtid->progress = false;
                rxtid->timer_mon = false;
                skb_queue_head_init(&rxtid->q);
                spin_lock_init(&rxtid->lock);
index ee8ec23..a6caa67 100644 (file)
@@ -743,7 +743,6 @@ int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid)
                return -ENOMEM;
 
        cmd = (struct roam_ctrl_cmd *) skb->data;
-       memset(cmd, 0, sizeof(*cmd));
 
        memcpy(cmd->info.bssid, bssid, ETH_ALEN);
        cmd->roam_ctrl = WMI_FORCE_ROAM;
@@ -753,6 +752,22 @@ int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid)
                                   NO_SYNC_WMIFLAG);
 }
 
+int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period)
+{
+       struct sk_buff *skb;
+       struct set_dtim_cmd *cmd;
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct set_dtim_cmd *) skb->data;
+
+       cmd->dtim_period = cpu_to_le32(dtim_period);
+       return ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+                                  WMI_AP_SET_DTIM_CMDID, NO_SYNC_WMIFLAG);
+}
+
 int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode)
 {
        struct sk_buff *skb;
@@ -763,7 +778,6 @@ int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode)
                return -ENOMEM;
 
        cmd = (struct roam_ctrl_cmd *) skb->data;
-       memset(cmd, 0, sizeof(*cmd));
 
        cmd->info.roam_mode = mode;
        cmd->roam_ctrl = WMI_SET_ROAM_MODE;
@@ -1995,7 +2009,7 @@ int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 if_idx, u8 index, u8 flag,
        struct wmi_probed_ssid_cmd *cmd;
        int ret;
 
-       if (index > MAX_PROBED_SSID_INDEX)
+       if (index >= MAX_PROBED_SSIDS)
                return -EINVAL;
 
        if (ssid_len > sizeof(cmd->ssid))
@@ -2599,6 +2613,115 @@ static void ath6kl_wmi_relinquish_implicit_pstream_credits(struct wmi *wmi)
        spin_unlock_bh(&wmi->lock);
 }
 
+static int ath6kl_set_bitrate_mask64(struct wmi *wmi, u8 if_idx,
+                                    const struct cfg80211_bitrate_mask *mask)
+{
+       struct sk_buff *skb;
+       int ret, mode, band;
+       u64 mcsrate, ratemask[IEEE80211_NUM_BANDS];
+       struct wmi_set_tx_select_rates64_cmd *cmd;
+
+       memset(&ratemask, 0, sizeof(ratemask));
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+               /* copy legacy rate mask */
+               ratemask[band] = mask->control[band].legacy;
+               if (band == IEEE80211_BAND_5GHZ)
+                       ratemask[band] =
+                               mask->control[band].legacy << 4;
+
+               /* copy mcs rate mask */
+               mcsrate = mask->control[band].mcs[1];
+               mcsrate <<= 8;
+               mcsrate |= mask->control[band].mcs[0];
+               ratemask[band] |= mcsrate << 12;
+               ratemask[band] |= mcsrate << 28;
+       }
+
+       ath6kl_dbg(ATH6KL_DBG_WMI,
+                  "Ratemask 64 bit: 2.4:%llx 5:%llx\n",
+                  ratemask[0], ratemask[1]);
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd) * WMI_RATES_MODE_MAX);
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_set_tx_select_rates64_cmd *) skb->data;
+       for (mode = 0; mode < WMI_RATES_MODE_MAX; mode++) {
+               /* A mode operate in 5GHZ band */
+               if (mode == WMI_RATES_MODE_11A ||
+                   mode == WMI_RATES_MODE_11A_HT20 ||
+                   mode == WMI_RATES_MODE_11A_HT40)
+                       band = IEEE80211_BAND_5GHZ;
+               else
+                       band = IEEE80211_BAND_2GHZ;
+               cmd->ratemask[mode] = cpu_to_le64(ratemask[band]);
+       }
+
+       ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+                                 WMI_SET_TX_SELECT_RATES_CMDID,
+                                 NO_SYNC_WMIFLAG);
+       return ret;
+}
+
+static int ath6kl_set_bitrate_mask32(struct wmi *wmi, u8 if_idx,
+                                    const struct cfg80211_bitrate_mask *mask)
+{
+       struct sk_buff *skb;
+       int ret, mode, band;
+       u32 mcsrate, ratemask[IEEE80211_NUM_BANDS];
+       struct wmi_set_tx_select_rates32_cmd *cmd;
+
+       memset(&ratemask, 0, sizeof(ratemask));
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+               /* copy legacy rate mask */
+               ratemask[band] = mask->control[band].legacy;
+               if (band == IEEE80211_BAND_5GHZ)
+                       ratemask[band] =
+                               mask->control[band].legacy << 4;
+
+               /* copy mcs rate mask */
+               mcsrate = mask->control[band].mcs[0];
+               ratemask[band] |= mcsrate << 12;
+               ratemask[band] |= mcsrate << 20;
+       }
+
+       ath6kl_dbg(ATH6KL_DBG_WMI,
+                  "Ratemask 32 bit: 2.4:%x 5:%x\n",
+                  ratemask[0], ratemask[1]);
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd) * WMI_RATES_MODE_MAX);
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_set_tx_select_rates32_cmd *) skb->data;
+       for (mode = 0; mode < WMI_RATES_MODE_MAX; mode++) {
+               /* A mode operate in 5GHZ band */
+               if (mode == WMI_RATES_MODE_11A ||
+                   mode == WMI_RATES_MODE_11A_HT20 ||
+                   mode == WMI_RATES_MODE_11A_HT40)
+                       band = IEEE80211_BAND_5GHZ;
+               else
+                       band = IEEE80211_BAND_2GHZ;
+               cmd->ratemask[mode] = cpu_to_le32(ratemask[band]);
+       }
+
+       ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+                                 WMI_SET_TX_SELECT_RATES_CMDID,
+                                 NO_SYNC_WMIFLAG);
+       return ret;
+}
+
+int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx,
+                               const struct cfg80211_bitrate_mask *mask)
+{
+       struct ath6kl *ar = wmi->parent_dev;
+
+       if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES)
+               return ath6kl_set_bitrate_mask64(wmi, if_idx, mask);
+       else
+               return ath6kl_set_bitrate_mask32(wmi, if_idx, mask);
+}
+
 int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx,
                                       enum ath6kl_host_mode host_mode)
 {
@@ -2997,6 +3120,25 @@ int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx,
        return ret;
 }
 
+int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enhance)
+{
+       struct sk_buff *skb;
+       struct wmi_sta_bmiss_enhance_cmd *cmd;
+       int ret;
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_sta_bmiss_enhance_cmd *) skb->data;
+       cmd->enable = enhance ? 1 : 0;
+
+       ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+                                 WMI_STA_BMISS_ENHANCE_CMDID,
+                                 NO_SYNC_WMIFLAG);
+       return ret;
+}
+
 s32 ath6kl_wmi_get_rate(s8 rate_index)
 {
        if (rate_index == RATE_AUTO)
index 9076bec..43339ac 100644 (file)
@@ -624,6 +624,10 @@ enum wmi_cmd_id {
        WMI_SEND_MGMT_CMDID,
        WMI_BEGIN_SCAN_CMDID,
 
+       WMI_SET_BLACK_LIST,
+       WMI_SET_MCASTRATE,
+
+       WMI_STA_BMISS_ENHANCE_CMDID,
 };
 
 enum wmi_mgmt_frame_type {
@@ -960,6 +964,9 @@ enum wmi_bss_filter {
        /* beacons matching probed ssid */
        PROBED_SSID_FILTER,
 
+       /* beacons matching matched ssid */
+       MATCHED_SSID_FILTER,
+
        /* marker only */
        LAST_BSS_FILTER,
 };
@@ -978,7 +985,7 @@ struct wmi_bss_filter_cmd {
 } __packed;
 
 /* WMI_SET_PROBED_SSID_CMDID */
-#define MAX_PROBED_SSID_INDEX   9
+#define MAX_PROBED_SSIDS   16
 
 enum wmi_ssid_flag {
        /* disables entry */
@@ -989,10 +996,13 @@ enum wmi_ssid_flag {
 
        /* probes for any ssid */
        ANY_SSID_FLAG = 0x02,
+
+       /* match for ssid */
+       MATCH_SSID_FLAG = 0x08,
 };
 
 struct wmi_probed_ssid_cmd {
-       /* 0 to MAX_PROBED_SSID_INDEX */
+       /* 0 to MAX_PROBED_SSIDS - 1 */
        u8 entry_index;
 
        /* see, enum wmi_ssid_flg */
@@ -1017,6 +1027,11 @@ struct wmi_bmiss_time_cmd {
        __le16 num_beacons;
 };
 
+/* WMI_STA_ENHANCE_BMISS_CMDID */
+struct wmi_sta_bmiss_enhance_cmd {
+       u8 enable;
+} __packed;
+
 /* WMI_SET_POWER_MODE_CMDID */
 enum wmi_power_mode {
        REC_POWER = 0x01,
@@ -1048,6 +1063,36 @@ struct wmi_power_params_cmd {
        __le16 ps_fail_event_policy;
 } __packed;
 
+/*
+ * Ratemask for below modes should be passed
+ * to WMI_SET_TX_SELECT_RATES_CMDID.
+ * AR6003 has 32 bit mask for each modes.
+ * First 12 bits for legacy rates, 13 to 20
+ * bits for HT 20 rates and 21 to 28 bits for
+ * HT 40 rates
+ */
+enum wmi_mode_phy {
+       WMI_RATES_MODE_11A = 0,
+       WMI_RATES_MODE_11G,
+       WMI_RATES_MODE_11B,
+       WMI_RATES_MODE_11GONLY,
+       WMI_RATES_MODE_11A_HT20,
+       WMI_RATES_MODE_11G_HT20,
+       WMI_RATES_MODE_11A_HT40,
+       WMI_RATES_MODE_11G_HT40,
+       WMI_RATES_MODE_MAX
+};
+
+/* WMI_SET_TX_SELECT_RATES_CMDID */
+struct wmi_set_tx_select_rates32_cmd {
+       __le32 ratemask[WMI_RATES_MODE_MAX];
+} __packed;
+
+/* WMI_SET_TX_SELECT_RATES_CMDID */
+struct wmi_set_tx_select_rates64_cmd {
+       __le64 ratemask[WMI_RATES_MODE_MAX];
+} __packed;
+
 /* WMI_SET_DISC_TIMEOUT_CMDID */
 struct wmi_disc_timeout_cmd {
        /* seconds */
@@ -1572,6 +1617,10 @@ struct roam_ctrl_cmd {
        u8 roam_ctrl;
 } __packed;
 
+struct set_dtim_cmd {
+       __le32 dtim_period;
+} __packed;
+
 /* BSS INFO HDR version 2.0 */
 struct wmi_bss_info_hdr2 {
        __le16 ch; /* frequency in MHz */
@@ -2532,6 +2581,8 @@ int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, u8 if_idx,
                          __be32 ips0, __be32 ips1);
 int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx,
                                       enum ath6kl_host_mode host_mode);
+int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx,
+                               const struct cfg80211_bitrate_mask *mask);
 int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx,
                                enum ath6kl_wow_mode wow_mode,
                                u32 filter, u16 host_req_delay);
@@ -2542,11 +2593,14 @@ int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
 int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
                                   u16 list_id, u16 filter_id);
 int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi);
+int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period);
 int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid);
 int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode);
 int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on);
 int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx,
                                        u8 *filter, bool add_filter);
+int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enable);
+
 /* AP mode uAPSD */
 int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable);