Merge remote branch 'wireless-next/master' into ath6kl-next
authorKalle Valo <kvalo@qca.qualcomm.com>
Fri, 13 Jan 2012 11:57:45 +0000 (13:57 +0200)
committerKalle Valo <kvalo@qca.qualcomm.com>
Fri, 13 Jan 2012 11:57:45 +0000 (13:57 +0200)
Conflicts:
drivers/net/wireless/ath/ath6kl/usb.c

12 files changed:
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath6kl/core.h
drivers/net/wireless/ath/ath6kl/debug.c
drivers/net/wireless/ath/ath6kl/htc.c
drivers/net/wireless/ath/ath6kl/init.c
drivers/net/wireless/ath/ath6kl/main.c
drivers/net/wireless/ath/ath6kl/sdio.c
drivers/net/wireless/ath/ath6kl/testmode.c
drivers/net/wireless/ath/ath6kl/testmode.h
drivers/net/wireless/ath/ath6kl/txrx.c
drivers/net/wireless/ath/ath6kl/wmi.c
drivers/net/wireless/ath/ath6kl/wmi.h

index 6c59a21..a13ecec 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/moduleparam.h>
+#include <linux/inetdevice.h>
 
 #include "core.h"
 #include "cfg80211.h"
@@ -461,13 +462,13 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
                }
        }
 
-       if (sme->ie && (sme->ie_len > 0)) {
-               status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len);
-               if (status) {
-                       up(&ar->sem);
-                       return status;
-               }
-       } else
+       status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len);
+       if (status) {
+               up(&ar->sem);
+               return status;
+       }
+
+       if (sme->ie == NULL || sme->ie_len == 0)
                ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG;
 
        if (test_bit(CONNECTED, &vif->flags) &&
@@ -523,8 +524,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
            (vif->prwise_crypto == WEP_CRYPT)) {
                struct ath6kl_key *key = NULL;
 
-               if (sme->key_idx < WMI_MIN_KEY_INDEX ||
-                   sme->key_idx > WMI_MAX_KEY_INDEX) {
+               if (sme->key_idx > WMI_MAX_KEY_INDEX) {
                        ath6kl_err("key index %d out of bounds\n",
                                   sme->key_idx);
                        up(&ar->sem);
@@ -605,11 +605,13 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
        return 0;
 }
 
-static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
-                                   enum network_type nw_type,
-                                   const u8 *bssid,
-                                   struct ieee80211_channel *chan,
-                                   const u8 *beacon_ie, size_t beacon_ie_len)
+static struct cfg80211_bss *
+ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
+                        enum network_type nw_type,
+                        const u8 *bssid,
+                        struct ieee80211_channel *chan,
+                        const u8 *beacon_ie,
+                        size_t beacon_ie_len)
 {
        struct ath6kl *ar = vif->ar;
        struct cfg80211_bss *bss;
@@ -638,7 +640,7 @@ static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
                 */
                ie = kmalloc(2 + vif->ssid_len + beacon_ie_len, GFP_KERNEL);
                if (ie == NULL)
-                       return -ENOMEM;
+                       return NULL;
                ie[0] = WLAN_EID_SSID;
                ie[1] = vif->ssid_len;
                memcpy(ie + 2, vif->ssid, vif->ssid_len);
@@ -652,15 +654,9 @@ static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
                                   "cfg80211\n", bssid);
                kfree(ie);
        } else
-               ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss "
-                          "entry\n");
+               ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss\n");
 
-       if (bss == NULL)
-               return -ENOMEM;
-
-       cfg80211_put_bss(bss);
-
-       return 0;
+       return bss;
 }
 
 void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
@@ -672,6 +668,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
 {
        struct ieee80211_channel *chan;
        struct ath6kl *ar = vif->ar;
+       struct cfg80211_bss *bss;
 
        /* capinfo + listen interval */
        u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
@@ -712,8 +709,9 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
 
        chan = ieee80211_get_channel(ar->wiphy, (int) channel);
 
-       if (ath6kl_add_bss_if_needed(vif, nw_type, bssid, chan, assoc_info,
-                                    beacon_ie_len) < 0) {
+       bss = ath6kl_add_bss_if_needed(vif, nw_type, bssid, chan,
+                                      assoc_info, beacon_ie_len);
+       if (!bss) {
                ath6kl_err("could not add cfg80211 bss entry\n");
                return;
        }
@@ -722,6 +720,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
                ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",
                           nw_type & ADHOC_CREATOR ? "creator" : "joiner");
                cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
+               cfg80211_put_bss(bss);
                return;
        }
 
@@ -732,11 +731,11 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
                                        assoc_req_ie, assoc_req_len,
                                        assoc_resp_ie, assoc_resp_len,
                                        WLAN_STATUS_SUCCESS, GFP_KERNEL);
+               cfg80211_put_bss(bss);
        } else if (vif->sme_state == SME_CONNECTED) {
                /* inform roam event to cfg80211 */
-               cfg80211_roamed(vif->ndev, chan, bssid,
-                               assoc_req_ie, assoc_req_len,
-                               assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
+               cfg80211_roamed_bss(vif->ndev, bss, assoc_req_ie, assoc_req_len,
+                                   assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
        }
 }
 
@@ -984,6 +983,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
        struct ath6kl *ar = ath6kl_priv(ndev);
        struct ath6kl_vif *vif = netdev_priv(ndev);
        struct ath6kl_key *key = NULL;
+       int seq_len;
        u8 key_usage;
        u8 key_type;
 
@@ -997,7 +997,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
                                              params->key);
        }
 
-       if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
+       if (key_index > WMI_MAX_KEY_INDEX) {
                ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
                           "%s: key index %d out of bounds\n", __func__,
                           key_index);
@@ -1012,23 +1012,21 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
        else
                key_usage = GROUP_USAGE;
 
-       if (params) {
-               int seq_len = params->seq_len;
-               if (params->cipher == WLAN_CIPHER_SUITE_SMS4 &&
-                   seq_len > ATH6KL_KEY_SEQ_LEN) {
-                       /* Only first half of the WPI PN is configured */
-                       seq_len = ATH6KL_KEY_SEQ_LEN;
-               }
-               if (params->key_len > WLAN_MAX_KEY_LEN ||
-                   seq_len > sizeof(key->seq))
-                       return -EINVAL;
-
-               key->key_len = params->key_len;
-               memcpy(key->key, params->key, key->key_len);
-               key->seq_len = seq_len;
-               memcpy(key->seq, params->seq, key->seq_len);
-               key->cipher = params->cipher;
+       seq_len = params->seq_len;
+       if (params->cipher == WLAN_CIPHER_SUITE_SMS4 &&
+           seq_len > ATH6KL_KEY_SEQ_LEN) {
+               /* Only first half of the WPI PN is configured */
+               seq_len = ATH6KL_KEY_SEQ_LEN;
        }
+       if (params->key_len > WLAN_MAX_KEY_LEN ||
+           seq_len > sizeof(key->seq))
+               return -EINVAL;
+
+       key->key_len = params->key_len;
+       memcpy(key->key, params->key, key->key_len);
+       key->seq_len = seq_len;
+       memcpy(key->seq, params->seq, key->seq_len);
+       key->cipher = params->cipher;
 
        switch (key->cipher) {
        case WLAN_CIPHER_SUITE_WEP40:
@@ -1115,7 +1113,7 @@ static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
        if (!ath6kl_cfg80211_ready(vif))
                return -EIO;
 
-       if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
+       if (key_index > WMI_MAX_KEY_INDEX) {
                ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
                           "%s: key index %d out of bounds\n", __func__,
                           key_index);
@@ -1148,7 +1146,7 @@ static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
        if (!ath6kl_cfg80211_ready(vif))
                return -EIO;
 
-       if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
+       if (key_index > WMI_MAX_KEY_INDEX) {
                ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
                           "%s: key index %d out of bounds\n", __func__,
                           key_index);
@@ -1184,7 +1182,7 @@ static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
        if (!ath6kl_cfg80211_ready(vif))
                return -EIO;
 
-       if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
+       if (key_index > WMI_MAX_KEY_INDEX) {
                ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
                           "%s: key index %d out of bounds\n",
                           __func__, key_index);
@@ -1730,11 +1728,14 @@ static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
 
 static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
 {
+       struct in_device *in_dev;
+       struct in_ifaddr *ifa;
        struct ath6kl_vif *vif;
        int ret, pos, left;
        u32 filter = 0;
        u16 i;
-       u8 mask[WOW_MASK_SIZE];
+       u8 mask[WOW_MASK_SIZE], index = 0;
+       __be32 ips[MAX_IP_ADDRS];
 
        vif = ath6kl_vif_first(ar);
        if (!vif)
@@ -1781,6 +1782,33 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
                        return ret;
        }
 
+       /* Setup own IP addr for ARP agent. */
+       in_dev = __in_dev_get_rtnl(vif->ndev);
+       if (!in_dev)
+               goto skip_arp;
+
+       ifa = in_dev->ifa_list;
+       memset(&ips, 0, sizeof(ips));
+
+       /* Configure IP addr only if IP address count < MAX_IP_ADDRS */
+       while (index < MAX_IP_ADDRS && ifa) {
+               ips[index] = ifa->ifa_local;
+               ifa = ifa->ifa_next;
+               index++;
+       }
+
+       if (ifa) {
+               ath6kl_err("total IP addr count is exceeding fw limit\n");
+               return -EINVAL;
+       }
+
+       ret = ath6kl_wmi_set_ip_cmd(ar->wmi, vif->fw_vif_idx, ips[0], ips[1]);
+       if (ret) {
+               ath6kl_err("fail to setup ip for arp agent\n");
+               return ret;
+       }
+
+skip_arp:
        if (wow->disconnect)
                filter |= WOW_FILTER_OPTION_NWK_DISASSOC;
 
@@ -2014,7 +2042,18 @@ static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
                              struct ieee80211_channel *chan,
                              enum nl80211_channel_type channel_type)
 {
-       struct ath6kl_vif *vif = netdev_priv(dev);
+       struct ath6kl_vif *vif;
+
+       /*
+        * 'dev' could be NULL if a channel change is required for the hardware
+        * device itself, instead of a particular VIF.
+        *
+        * FIXME: To be handled properly when monitor mode is supported.
+        */
+       if (!dev)
+               return -EBUSY;
+
+       vif = netdev_priv(dev);
 
        if (!ath6kl_cfg80211_ready(vif))
                return -EIO;
@@ -2214,6 +2253,11 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
        p.dot11_auth_mode = vif->dot11_auth_mode;
        p.ch = cpu_to_le16(vif->next_chan);
 
+       /* Enable uAPSD support by default */
+       res = ath6kl_wmi_ap_set_apsd(ar->wmi, vif->fw_vif_idx, true);
+       if (res < 0)
+               return res;
+
        if (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
                p.nw_subtype = SUBTYPE_P2PGO;
        } else {
@@ -2259,6 +2303,19 @@ static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
        return 0;
 }
 
+static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+static int ath6kl_del_station(struct wiphy *wiphy, struct net_device *dev,
+                             u8 *mac)
+{
+       struct ath6kl *ar = ath6kl_priv(dev);
+       struct ath6kl_vif *vif = netdev_priv(dev);
+       const u8 *addr = mac ? mac : bcast_addr;
+
+       return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx, WMI_AP_DEAUTH,
+                                     addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+}
+
 static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
                                 u8 *mac, struct station_parameters *params)
 {
@@ -2518,6 +2575,12 @@ ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
                .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
                BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
        },
+       [NL80211_IFTYPE_AP] = {
+               .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+               BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
+               .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+               BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+       },
        [NL80211_IFTYPE_P2P_CLIENT] = {
                .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
                BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
@@ -2562,6 +2625,7 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
        .add_beacon = ath6kl_add_beacon,
        .set_beacon = ath6kl_set_beacon,
        .del_beacon = ath6kl_del_beacon,
+       .del_station = ath6kl_del_station,
        .change_station = ath6kl_change_station,
        .remain_on_channel = ath6kl_remain_on_channel,
        .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
@@ -2666,8 +2730,7 @@ struct ath6kl *ath6kl_core_alloc(struct device *dev)
        clear_bit(SKIP_SCAN, &ar->flag);
        clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
 
-       ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL;
-       ar->listen_intvl_b = 0;
+       ar->listen_intvl_b = A_DEFAULT_LISTEN_INTERVAL;
        ar->tx_pwr = 0;
 
        ar->intra_bss = 1;
@@ -2682,6 +2745,7 @@ struct ath6kl *ath6kl_core_alloc(struct device *dev)
        for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
                spin_lock_init(&ar->sta_list[ctr].psq_lock);
                skb_queue_head_init(&ar->sta_list[ctr].psq);
+               skb_queue_head_init(&ar->sta_list[ctr].apsdq);
        }
 
        skb_queue_head_init(&ar->mcastpsq);
@@ -2758,12 +2822,15 @@ static int ath6kl_init_if_data(struct ath6kl_vif *vif)
        set_bit(WMM_ENABLED, &vif->flags);
        spin_lock_init(&vif->if_lock);
 
+       INIT_LIST_HEAD(&vif->mc_filter);
+
        return 0;
 }
 
 void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
 {
        struct ath6kl *ar = vif->ar;
+       struct ath6kl_mc_filter *mc_filter, *tmp;
 
        aggr_module_destroy(vif->aggr_cntxt);
 
@@ -2772,6 +2839,11 @@ void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
        if (vif->nw_type == ADHOC_NETWORK)
                ar->ibss_if_active = false;
 
+       list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) {
+               list_del(&mc_filter->list);
+               kfree(mc_filter);
+       }
+
        unregister_netdevice(vif->ndev);
 
        ar->num_vif--;
index c863a28..ba39539 100644 (file)
 #define ATH6KL_MAX_ENDPOINTS   4
 #define MAX_NODE_NUM           15
 
+#define ATH6KL_APSD_ALL_FRAME          0xFFFF
+#define ATH6KL_APSD_NUM_OF_AC          0x4
+#define ATH6KL_APSD_FRAME_MASK         0xF
+
 /* Extra bytes for htc header alignment */
 #define ATH6KL_HTC_ALIGN_BYTES 3
 
@@ -55,7 +59,7 @@
 #define MAX_DEFAULT_SEND_QUEUE_DEPTH      (MAX_DEF_COOKIE_NUM / WMM_NUM_AC)
 
 #define DISCON_TIMER_INTVAL               10000  /* in msec */
-#define A_DEFAULT_LISTEN_INTERVAL         100
+#define A_DEFAULT_LISTEN_INTERVAL         1      /* beacon intervals */
 #define A_MAX_WOW_LISTEN_INTERVAL         1000
 
 /* includes also the null byte */
@@ -97,45 +101,47 @@ struct ath6kl_fw_ie {
        u8 data[0];
 };
 
+#define ATH6KL_FW_API2_FILE "fw-2.bin"
+#define ATH6KL_FW_API3_FILE "fw-3.bin"
+
 /* AR6003 1.0 definitions */
 #define AR6003_HW_1_0_VERSION                 0x300002ba
 
 /* AR6003 2.0 definitions */
 #define AR6003_HW_2_0_VERSION                 0x30000384
 #define AR6003_HW_2_0_PATCH_DOWNLOAD_ADDRESS  0x57e910
-#define AR6003_HW_2_0_OTP_FILE "ath6k/AR6003/hw2.0/otp.bin.z77"
-#define AR6003_HW_2_0_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athwlan.bin.z77"
-#define AR6003_HW_2_0_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athtcmd_ram.bin"
-#define AR6003_HW_2_0_PATCH_FILE "ath6k/AR6003/hw2.0/data.patch.bin"
-#define AR6003_HW_2_0_FIRMWARE_2_FILE "ath6k/AR6003/hw2.0/fw-2.bin"
+#define AR6003_HW_2_0_FW_DIR                   "ath6k/AR6003/hw2.0"
+#define AR6003_HW_2_0_OTP_FILE                 "otp.bin.z77"
+#define AR6003_HW_2_0_FIRMWARE_FILE            "athwlan.bin.z77"
+#define AR6003_HW_2_0_TCMD_FIRMWARE_FILE       "athtcmd_ram.bin"
+#define AR6003_HW_2_0_PATCH_FILE               "data.patch.bin"
 #define AR6003_HW_2_0_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin"
 #define AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE \
                        "ath6k/AR6003/hw2.0/bdata.SD31.bin"
 
 /* AR6003 3.0 definitions */
 #define AR6003_HW_2_1_1_VERSION                 0x30000582
-#define AR6003_HW_2_1_1_OTP_FILE "ath6k/AR6003/hw2.1.1/otp.bin"
-#define AR6003_HW_2_1_1_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athwlan.bin"
-#define AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE \
-                       "ath6k/AR6003/hw2.1.1/athtcmd_ram.bin"
-#define AR6003_HW_2_1_1_PATCH_FILE "ath6k/AR6003/hw2.1.1/data.patch.bin"
-#define AR6003_HW_2_1_1_FIRMWARE_2_FILE "ath6k/AR6003/hw2.1.1/fw-2.bin"
+#define AR6003_HW_2_1_1_FW_DIR                 "ath6k/AR6003/hw2.1.1"
+#define AR6003_HW_2_1_1_OTP_FILE               "otp.bin"
+#define AR6003_HW_2_1_1_FIRMWARE_FILE          "athwlan.bin"
+#define AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE     "athtcmd_ram.bin"
+#define AR6003_HW_2_1_1_PATCH_FILE             "data.patch.bin"
 #define AR6003_HW_2_1_1_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin"
 #define AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE        \
                        "ath6k/AR6003/hw2.1.1/bdata.SD31.bin"
 
 /* AR6004 1.0 definitions */
 #define AR6004_HW_1_0_VERSION                 0x30000623
-#define AR6004_HW_1_0_FIRMWARE_2_FILE         "ath6k/AR6004/hw1.0/fw-2.bin"
-#define AR6004_HW_1_0_FIRMWARE_FILE           "ath6k/AR6004/hw1.0/fw.ram.bin"
+#define AR6004_HW_1_0_FW_DIR                   "ath6k/AR6004/hw1.0"
+#define AR6004_HW_1_0_FIRMWARE_FILE            "fw.ram.bin"
 #define AR6004_HW_1_0_BOARD_DATA_FILE         "ath6k/AR6004/hw1.0/bdata.bin"
 #define AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE \
        "ath6k/AR6004/hw1.0/bdata.DB132.bin"
 
 /* AR6004 1.1 definitions */
 #define AR6004_HW_1_1_VERSION                 0x30000001
-#define AR6004_HW_1_1_FIRMWARE_2_FILE         "ath6k/AR6004/hw1.1/fw-2.bin"
-#define AR6004_HW_1_1_FIRMWARE_FILE           "ath6k/AR6004/hw1.1/fw.ram.bin"
+#define AR6004_HW_1_1_FW_DIR                   "ath6k/AR6004/hw1.1"
+#define AR6004_HW_1_1_FIRMWARE_FILE            "fw.ram.bin"
 #define AR6004_HW_1_1_BOARD_DATA_FILE         "ath6k/AR6004/hw1.1/bdata.bin"
 #define AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE \
        "ath6k/AR6004/hw1.1/bdata.DB132.bin"
@@ -144,6 +150,8 @@ struct ath6kl_fw_ie {
 #define STA_PS_AWAKE           BIT(0)
 #define        STA_PS_SLEEP            BIT(1)
 #define        STA_PS_POLLED           BIT(2)
+#define STA_PS_APSD_TRIGGER     BIT(3)
+#define STA_PS_APSD_EOSP        BIT(4)
 
 /* HTC TX packet tagging definitions */
 #define ATH6KL_CONTROL_PKT_TAG    HTC_TX_PACKET_TAG_USER_DEFINED
@@ -280,6 +288,8 @@ struct ath6kl_sta {
        u8 wpa_ie[ATH6KL_MAX_IE];
        struct sk_buff_head psq;
        spinlock_t psq_lock;
+       u8 apsd_info;
+       struct sk_buff_head apsdq;
 };
 
 struct ath6kl_version {
@@ -408,6 +418,13 @@ enum ath6kl_hif_type {
        ATH6KL_HIF_TYPE_USB,
 };
 
+/* Max number of filters that hw supports */
+#define ATH6K_MAX_MC_FILTERS_PER_LIST 7
+struct ath6kl_mc_filter {
+       struct list_head list;
+       char hw_addr[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE];
+};
+
 /*
  * Driver's maximum limit, note that some firmwares support only one vif
  * and the runtime (current) limit must be checked from ar->vif_max.
@@ -471,6 +488,8 @@ struct ath6kl_vif {
        u8 assoc_bss_dtim_period;
        struct net_device_stats net_stats;
        struct target_stats target_stats;
+
+       struct list_head mc_filter;
 };
 
 #define WOW_LIST_ID            0
@@ -523,7 +542,6 @@ struct ath6kl {
        spinlock_t lock;
        struct semaphore sem;
        u16 listen_intvl_b;
-       u16 listen_intvl_t;
        u8 lrssi_roam_threshold;
        struct ath6kl_version version;
        u32 target_type;
@@ -575,11 +593,14 @@ struct ath6kl {
                u32 refclk_hz;
                u32 uarttx_pin;
 
-               const char *fw_otp;
-               const char *fw;
-               const char *fw_tcmd;
-               const char *fw_patch;
-               const char *fw_api2;
+               struct ath6kl_hw_fw {
+                       const char *dir;
+                       const char *otp;
+                       const char *fw;
+                       const char *tcmd;
+                       const char *patch;
+               } fw;
+
                const char *fw_board;
                const char *fw_default_board;
        } hw;
@@ -603,6 +624,7 @@ struct ath6kl {
        u8 *fw_patch;
        size_t fw_patch_len;
 
+       unsigned int fw_api;
        unsigned long fw_capabilities[ATH6KL_CAPABILITY_LEN];
 
        struct workqueue_struct *ath6kl_wq;
@@ -700,7 +722,7 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel,
 void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel);
 void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr,
                                u8 keymgmt, u8 ucipher, u8 auth,
-                               u8 assoc_req_len, u8 *assoc_info);
+                               u8 assoc_req_len, u8 *assoc_info, u8 apsd_info);
 void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason,
                             u8 *bssid, u8 assoc_resp_len,
                             u8 *assoc_info, u16 prot_reason_status);
index eb808b4..fa7243b 100644 (file)
@@ -1505,57 +1505,46 @@ static const struct file_operations fops_bgscan_int = {
 };
 
 static ssize_t ath6kl_listen_int_write(struct file *file,
-                                               const char __user *user_buf,
-                                               size_t count, loff_t *ppos)
+                                      const char __user *user_buf,
+                                      size_t count, loff_t *ppos)
 {
        struct ath6kl *ar = file->private_data;
-       u16 listen_int_t, listen_int_b;
+       struct ath6kl_vif *vif;
+       u16 listen_interval;
        char buf[32];
-       char *sptr, *token;
        ssize_t len;
 
+       vif = ath6kl_vif_first(ar);
+       if (!vif)
+               return -EIO;
+
        len = min(count, sizeof(buf) - 1);
        if (copy_from_user(buf, user_buf, len))
                return -EFAULT;
 
        buf[len] = '\0';
-       sptr = buf;
-
-       token = strsep(&sptr, " ");
-       if (!token)
-               return -EINVAL;
-
-       if (kstrtou16(token, 0, &listen_int_t))
-               return -EINVAL;
-
-       if (kstrtou16(sptr, 0, &listen_int_b))
-               return -EINVAL;
-
-       if ((listen_int_t < 15) || (listen_int_t > 5000))
+       if (kstrtou16(buf, 0, &listen_interval))
                return -EINVAL;
 
-       if ((listen_int_b < 1) || (listen_int_b > 50))
+       if ((listen_interval < 1) || (listen_interval > 50))
                return -EINVAL;
 
-       ar->listen_intvl_t = listen_int_t;
-       ar->listen_intvl_b = listen_int_b;
-
-       ath6kl_wmi_listeninterval_cmd(ar->wmi, 0, ar->listen_intvl_t,
+       ar->listen_intvl_b = listen_interval;
+       ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, 0,
                                      ar->listen_intvl_b);
 
        return count;
 }
 
 static ssize_t ath6kl_listen_int_read(struct file *file,
-                                               char __user *user_buf,
-                                               size_t count, loff_t *ppos)
+                                     char __user *user_buf,
+                                     size_t count, loff_t *ppos)
 {
        struct ath6kl *ar = file->private_data;
        char buf[32];
        int len;
 
-       len = scnprintf(buf, sizeof(buf), "%u %u\n", ar->listen_intvl_t,
-                                       ar->listen_intvl_b);
+       len = scnprintf(buf, sizeof(buf), "%u\n", ar->listen_intvl_b);
 
        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
@@ -1710,6 +1699,9 @@ int ath6kl_debug_init(struct ath6kl *ar)
        debugfs_create_file("bgscan_interval", S_IWUSR,
                                ar->debugfs_phy, ar, &fops_bgscan_int);
 
+       debugfs_create_file("listen_interval", S_IRUSR | S_IWUSR,
+                           ar->debugfs_phy, ar, &fops_listen_int);
+
        debugfs_create_file("power_params", S_IWUSR, ar->debugfs_phy, ar,
                                                &fops_power_params);
 
index f3b63ca..073ddff 100644 (file)
@@ -2062,6 +2062,7 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,
        enum htc_endpoint_id id;
        int n_fetched = 0;
 
+       INIT_LIST_HEAD(&comp_pktq);
        *num_pkts = 0;
 
        /*
index 7f55be3..e5969c1 100644 (file)
 unsigned int debug_mask;
 static unsigned int testmode;
 static bool suspend_cutpower;
+static unsigned int uart_debug;
 
 module_param(debug_mask, uint, 0644);
 module_param(testmode, uint, 0644);
 module_param(suspend_cutpower, bool, 0444);
+module_param(uart_debug, uint, 0644);
 
 static const struct ath6kl_hw hw_list[] = {
        {
@@ -47,11 +49,14 @@ static const struct ath6kl_hw hw_list[] = {
                /* hw2.0 needs override address hardcoded */
                .app_start_override_addr        = 0x944C00,
 
-               .fw_otp                 = AR6003_HW_2_0_OTP_FILE,
-               .fw                     = AR6003_HW_2_0_FIRMWARE_FILE,
-               .fw_tcmd                = AR6003_HW_2_0_TCMD_FIRMWARE_FILE,
-               .fw_patch               = AR6003_HW_2_0_PATCH_FILE,
-               .fw_api2                = AR6003_HW_2_0_FIRMWARE_2_FILE,
+               .fw = {
+                       .dir            = AR6003_HW_2_0_FW_DIR,
+                       .otp            = AR6003_HW_2_0_OTP_FILE,
+                       .fw             = AR6003_HW_2_0_FIRMWARE_FILE,
+                       .tcmd           = AR6003_HW_2_0_TCMD_FIRMWARE_FILE,
+                       .patch          = AR6003_HW_2_0_PATCH_FILE,
+               },
+
                .fw_board               = AR6003_HW_2_0_BOARD_DATA_FILE,
                .fw_default_board       = AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE,
        },
@@ -65,11 +70,14 @@ static const struct ath6kl_hw hw_list[] = {
                .refclk_hz                      = 26000000,
                .uarttx_pin                     = 8,
 
-               .fw_otp                 = AR6003_HW_2_1_1_OTP_FILE,
-               .fw                     = AR6003_HW_2_1_1_FIRMWARE_FILE,
-               .fw_tcmd                = AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE,
-               .fw_patch               = AR6003_HW_2_1_1_PATCH_FILE,
-               .fw_api2                = AR6003_HW_2_1_1_FIRMWARE_2_FILE,
+               .fw = {
+                       .dir            = AR6003_HW_2_1_1_FW_DIR,
+                       .otp            = AR6003_HW_2_1_1_OTP_FILE,
+                       .fw             = AR6003_HW_2_1_1_FIRMWARE_FILE,
+                       .tcmd           = AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE,
+                       .patch          = AR6003_HW_2_1_1_PATCH_FILE,
+               },
+
                .fw_board               = AR6003_HW_2_1_1_BOARD_DATA_FILE,
                .fw_default_board       = AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE,
        },
@@ -84,8 +92,11 @@ static const struct ath6kl_hw hw_list[] = {
                .refclk_hz                      = 26000000,
                .uarttx_pin                     = 11,
 
-               .fw                     = AR6004_HW_1_0_FIRMWARE_FILE,
-               .fw_api2                = AR6004_HW_1_0_FIRMWARE_2_FILE,
+               .fw = {
+                       .dir            = AR6004_HW_1_0_FW_DIR,
+                       .fw             = AR6004_HW_1_0_FIRMWARE_FILE,
+               },
+
                .fw_board               = AR6004_HW_1_0_BOARD_DATA_FILE,
                .fw_default_board       = AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE,
        },
@@ -100,8 +111,11 @@ static const struct ath6kl_hw hw_list[] = {
                .refclk_hz                      = 40000000,
                .uarttx_pin                     = 11,
 
-               .fw                     = AR6004_HW_1_1_FIRMWARE_FILE,
-               .fw_api2                = AR6004_HW_1_1_FIRMWARE_2_FILE,
+               .fw = {
+                       .dir            = AR6004_HW_1_1_FW_DIR,
+                       .fw             = AR6004_HW_1_1_FIRMWARE_FILE,
+               },
+
                .fw_board               = AR6004_HW_1_1_BOARD_DATA_FILE,
                .fw_default_board       = AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE,
        },
@@ -452,6 +466,13 @@ int ath6kl_configure_target(struct ath6kl *ar)
        u8 fw_iftype, fw_mode = 0, fw_submode = 0;
        int i, status;
 
+       param = uart_debug;
+       if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar,
+                            HI_ITEM(hi_serial_enable)), (u8 *)&param, 4)) {
+               ath6kl_err("bmi_write_memory for uart debug failed\n");
+               return -EIO;
+       }
+
        /*
         * Note: Even though the firmware interface type is
         * chosen as BSS_STA for all three interfaces, can
@@ -626,21 +647,6 @@ static int ath6kl_get_fw(struct ath6kl *ar, const char *filename,
 }
 
 #ifdef CONFIG_OF
-static const char *get_target_ver_dir(const struct ath6kl *ar)
-{
-       switch (ar->version.target_ver) {
-       case AR6003_HW_1_0_VERSION:
-               return "ath6k/AR6003/hw1.0";
-       case AR6003_HW_2_0_VERSION:
-               return "ath6k/AR6003/hw2.0";
-       case AR6003_HW_2_1_1_VERSION:
-               return "ath6k/AR6003/hw2.1.1";
-       }
-       ath6kl_warn("%s: unsupported target version 0x%x.\n", __func__,
-                   ar->version.target_ver);
-       return NULL;
-}
-
 /*
  * Check the device tree for a board-id and use it to construct
  * the pathname to the firmware file.  Used (for now) to find a
@@ -663,7 +669,7 @@ static bool check_device_tree(struct ath6kl *ar)
                        continue;
                }
                snprintf(board_filename, sizeof(board_filename),
-                        "%s/bdata.%s.bin", get_target_ver_dir(ar), board_id);
+                        "%s/bdata.%s.bin", ar->hw.fw.dir, board_id);
 
                ret = ath6kl_get_fw(ar, board_filename, &ar->fw_board,
                                    &ar->fw_board_len);
@@ -730,19 +736,20 @@ static int ath6kl_fetch_board_file(struct ath6kl *ar)
 
 static int ath6kl_fetch_otp_file(struct ath6kl *ar)
 {
-       const char *filename;
+       char filename[100];
        int ret;
 
        if (ar->fw_otp != NULL)
                return 0;
 
-       if (ar->hw.fw_otp == NULL) {
+       if (ar->hw.fw.otp == NULL) {
                ath6kl_dbg(ATH6KL_DBG_BOOT,
                           "no OTP file configured for this hw\n");
                return 0;
        }
 
-       filename = ar->hw.fw_otp;
+       snprintf(filename, sizeof(filename), "%s/%s",
+                ar->hw.fw.dir, ar->hw.fw.otp);
 
        ret = ath6kl_get_fw(ar, filename, &ar->fw_otp,
                            &ar->fw_otp_len);
@@ -757,29 +764,32 @@ static int ath6kl_fetch_otp_file(struct ath6kl *ar)
 
 static int ath6kl_fetch_fw_file(struct ath6kl *ar)
 {
-       const char *filename;
+       char filename[100];
        int ret;
 
        if (ar->fw != NULL)
                return 0;
 
        if (testmode) {
-               if (ar->hw.fw_tcmd == NULL) {
+               if (ar->hw.fw.tcmd == NULL) {
                        ath6kl_warn("testmode not supported\n");
                        return -EOPNOTSUPP;
                }
 
-               filename = ar->hw.fw_tcmd;
+               snprintf(filename, sizeof(filename), "%s/%s",
+                        ar->hw.fw.dir, ar->hw.fw.tcmd);
 
                set_bit(TESTMODE, &ar->flag);
 
                goto get_fw;
        }
 
-       if (WARN_ON(ar->hw.fw == NULL))
+       /* FIXME: remove WARN_ON() as we won't support FW API 1 for long */
+       if (WARN_ON(ar->hw.fw.fw == NULL))
                return -EINVAL;
 
-       filename = ar->hw.fw;
+       snprintf(filename, sizeof(filename), "%s/%s",
+                ar->hw.fw.dir, ar->hw.fw.fw);
 
 get_fw:
        ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len);
@@ -794,16 +804,17 @@ get_fw:
 
 static int ath6kl_fetch_patch_file(struct ath6kl *ar)
 {
-       const char *filename;
+       char filename[100];
        int ret;
 
        if (ar->fw_patch != NULL)
                return 0;
 
-       if (ar->hw.fw_patch == NULL)
+       if (ar->hw.fw.patch == NULL)
                return 0;
 
-       filename = ar->hw.fw_patch;
+       snprintf(filename, sizeof(filename), "%s/%s",
+                ar->hw.fw.dir, ar->hw.fw.patch);
 
        ret = ath6kl_get_fw(ar, filename, &ar->fw_patch,
                            &ar->fw_patch_len);
@@ -835,20 +846,17 @@ static int ath6kl_fetch_fw_api1(struct ath6kl *ar)
        return 0;
 }
 
-static int ath6kl_fetch_fw_api2(struct ath6kl *ar)
+static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
 {
        size_t magic_len, len, ie_len;
        const struct firmware *fw;
        struct ath6kl_fw_ie *hdr;
-       const char *filename;
+       char filename[100];
        const u8 *data;
        int ret, ie_id, i, index, bit;
        __le32 *val;
 
-       if (ar->hw.fw_api2 == NULL)
-               return -EOPNOTSUPP;
-
-       filename = ar->hw.fw_api2;
+       snprintf(filename, sizeof(filename), "%s/%s", ar->hw.fw.dir, name);
 
        ret = request_firmware(&fw, filename, ar->dev);
        if (ret)
@@ -1018,17 +1026,26 @@ static int ath6kl_fetch_firmwares(struct ath6kl *ar)
        if (ret)
                return ret;
 
-       ret = ath6kl_fetch_fw_api2(ar);
+       ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API3_FILE);
        if (ret == 0) {
-               ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api 2\n");
-               return 0;
+               ar->fw_api = 3;
+               goto out;
+       }
+
+       ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API2_FILE);
+       if (ret == 0) {
+               ar->fw_api = 2;
+               goto out;
        }
 
        ret = ath6kl_fetch_fw_api1(ar);
        if (ret)
                return ret;
 
-       ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api 1\n");
+       ar->fw_api = 1;
+
+out:
+       ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api %d\n", ar->fw_api);
 
        return 0;
 }
@@ -1481,10 +1498,11 @@ int ath6kl_init_hw_start(struct ath6kl *ar)
 
 
        if (test_and_clear_bit(FIRST_BOOT, &ar->flag)) {
-               ath6kl_info("%s %s fw %s%s\n",
+               ath6kl_info("%s %s fw %s api %d%s\n",
                            ar->hw.name,
                            ath6kl_init_get_hif_name(ar->hif_type),
                            ar->wiphy->fw_version,
+                           ar->fw_api,
                            test_bit(TESTMODE, &ar->flag) ? " testmode" : "");
        }
 
@@ -1677,6 +1695,8 @@ int ath6kl_core_init(struct ath6kl *ar)
 
        set_bit(FIRST_BOOT, &ar->flag);
 
+       ndev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
+
        ret = ath6kl_init_hw_start(ar);
        if (ret) {
                ath6kl_err("Failed to start hardware: %d\n", ret);
index eea3c74..0a6d6e2 100644 (file)
@@ -53,7 +53,8 @@ struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid)
 }
 
 static void ath6kl_add_new_sta(struct ath6kl *ar, u8 *mac, u16 aid, u8 *wpaie,
-                       u8 ielen, u8 keymgmt, u8 ucipher, u8 auth)
+                              size_t ielen, u8 keymgmt, u8 ucipher, u8 auth,
+                              u8 apsd_info)
 {
        struct ath6kl_sta *sta;
        u8 free_slot;
@@ -68,6 +69,7 @@ static void ath6kl_add_new_sta(struct ath6kl *ar, u8 *mac, u16 aid, u8 *wpaie,
        sta->keymgmt = keymgmt;
        sta->ucipher = ucipher;
        sta->auth = auth;
+       sta->apsd_info = apsd_info;
 
        ar->sta_list_index = ar->sta_list_index | (1 << free_slot);
        ar->ap_stats.sta[free_slot].aid = cpu_to_le32(aid);
@@ -80,6 +82,7 @@ static void ath6kl_sta_cleanup(struct ath6kl *ar, u8 i)
        /* empty the queued pkts in the PS queue if any */
        spin_lock_bh(&sta->psq_lock);
        skb_queue_purge(&sta->psq);
+       skb_queue_purge(&sta->apsdq);
        spin_unlock_bh(&sta->psq_lock);
 
        memset(&ar->ap_stats.sta[sta->aid - 1], 0,
@@ -252,7 +255,7 @@ int ath6kl_read_fwlogs(struct ath6kl *ar)
        struct ath6kl_dbglog_hdr debug_hdr;
        struct ath6kl_dbglog_buf debug_buf;
        u32 address, length, dropped, firstbuf, debug_hdr_addr;
-       int ret = 0, loop;
+       int ret, loop;
        u8 *buf;
 
        buf = kmalloc(ATH6KL_FWLOG_PAYLOAD_SIZE, GFP_KERNEL);
@@ -347,9 +350,6 @@ void ath6kl_reset_device(struct ath6kl *ar, u32 target_type,
        case TARGET_TYPE_AR6004:
                address = AR6004_RESET_CONTROL_ADDRESS;
                break;
-       default:
-               address = AR6003_RESET_CONTROL_ADDRESS;
-               break;
        }
 
        status = ath6kl_diag_write32(ar, address, data);
@@ -363,7 +363,7 @@ static void ath6kl_install_static_wep_keys(struct ath6kl_vif *vif)
        u8 index;
        u8 keyusage;
 
-       for (index = WMI_MIN_KEY_INDEX; index <= WMI_MAX_KEY_INDEX; index++) {
+       for (index = 0; index <= WMI_MAX_KEY_INDEX; index++) {
                if (vif->wep_key_list[index].key_len) {
                        keyusage = GROUP_USAGE;
                        if (index == vif->def_txkey_index)
@@ -428,7 +428,7 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel)
 
 void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr,
                                u8 keymgmt, u8 ucipher, u8 auth,
-                               u8 assoc_req_len, u8 *assoc_info)
+                               u8 assoc_req_len, u8 *assoc_info, u8 apsd_info)
 {
        struct ath6kl *ar = vif->ar;
        u8 *ies = NULL, *wpa_ie = NULL, *pos;
@@ -486,7 +486,7 @@ void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr,
 
        ath6kl_add_new_sta(ar, mac_addr, aid, wpa_ie,
                           wpa_ie ? 2 + wpa_ie[1] : 0,
-                          keymgmt, ucipher, auth);
+                          keymgmt, ucipher, auth, apsd_info);
 
        /* send event to application */
        memset(&sinfo, 0, sizeof(sinfo));
@@ -587,10 +587,11 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid,
        memcpy(vif->bssid, bssid, sizeof(vif->bssid));
        vif->bss_ch = channel;
 
-       if ((vif->nw_type == INFRA_NETWORK))
+       if ((vif->nw_type == INFRA_NETWORK)) {
+               ar->listen_intvl_b = listen_int;
                ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
-                                             ar->listen_intvl_t,
-                                             ar->listen_intvl_b);
+                                             0, ar->listen_intvl_b);
+       }
 
        netif_wake_queue(vif->ndev);
 
@@ -1020,11 +1021,154 @@ static struct net_device_stats *ath6kl_get_stats(struct net_device *dev)
        return &vif->net_stats;
 }
 
-static struct net_device_ops ath6kl_netdev_ops = {
+static int ath6kl_set_features(struct net_device *dev, u32 features)
+{
+       struct ath6kl_vif *vif = netdev_priv(dev);
+       struct ath6kl *ar = vif->ar;
+       int err = 0;
+
+       if ((features & NETIF_F_RXCSUM) &&
+           (ar->rx_meta_ver != WMI_META_VERSION_2)) {
+               ar->rx_meta_ver = WMI_META_VERSION_2;
+               err = ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi,
+                                                        vif->fw_vif_idx,
+                                                        ar->rx_meta_ver, 0, 0);
+               if (err) {
+                       dev->features = features & ~NETIF_F_RXCSUM;
+                       return err;
+               }
+       } else if (!(features & NETIF_F_RXCSUM) &&
+                  (ar->rx_meta_ver == WMI_META_VERSION_2)) {
+               ar->rx_meta_ver = 0;
+               err = ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi,
+                                                        vif->fw_vif_idx,
+                                                        ar->rx_meta_ver, 0, 0);
+               if (err) {
+                       dev->features = features | NETIF_F_RXCSUM;
+                       return err;
+               }
+
+       }
+
+       return err;
+}
+
+static void ath6kl_set_multicast_list(struct net_device *ndev)
+{
+       struct ath6kl_vif *vif = netdev_priv(ndev);
+       bool mc_all_on = false, mc_all_off = false;
+       int mc_count = netdev_mc_count(ndev);
+       struct netdev_hw_addr *ha;
+       bool found;
+       struct ath6kl_mc_filter *mc_filter, *tmp;
+       struct list_head mc_filter_new;
+       int ret;
+
+       if (!test_bit(WMI_READY, &vif->ar->flag) ||
+           !test_bit(WLAN_ENABLED, &vif->flags))
+               return;
+
+       mc_all_on = !!(ndev->flags & IFF_PROMISC) ||
+                   !!(ndev->flags & IFF_ALLMULTI) ||
+                   !!(mc_count > ATH6K_MAX_MC_FILTERS_PER_LIST);
+
+       mc_all_off = !(ndev->flags & IFF_MULTICAST) || mc_count == 0;
+
+       if (mc_all_on || mc_all_off) {
+               /* Enable/disable all multicast */
+               ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast filter\n",
+                         mc_all_on ? "enabling" : "disabling");
+               ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx,
+                                                 mc_all_on);
+               if (ret)
+                       ath6kl_warn("Failed to %s multicast receive\n",
+                                   mc_all_on ? "enable" : "disable");
+               return;
+       }
+
+       list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) {
+               found = false;
+               netdev_for_each_mc_addr(ha, ndev) {
+                       if (memcmp(ha->addr, mc_filter->hw_addr,
+                           ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) {
+                               found = true;
+                               break;
+                       }
+               }
+
+               if (!found) {
+                       /*
+                        * Delete the filter which was previously set
+                        * but not in the new request.
+                        */
+                       ath6kl_dbg(ATH6KL_DBG_TRC,
+                                  "Removing %pM from multicast filter\n",
+                                  mc_filter->hw_addr);
+                       ret = ath6kl_wmi_add_del_mcast_filter_cmd(vif->ar->wmi,
+                                       vif->fw_vif_idx, mc_filter->hw_addr,
+                                       false);
+                       if (ret) {
+                               ath6kl_warn("Failed to remove multicast filter:%pM\n",
+                                            mc_filter->hw_addr);
+                               return;
+                       }
+
+                       list_del(&mc_filter->list);
+                       kfree(mc_filter);
+               }
+       }
+
+       INIT_LIST_HEAD(&mc_filter_new);
+
+       netdev_for_each_mc_addr(ha, ndev) {
+               found = false;
+               list_for_each_entry(mc_filter, &vif->mc_filter, list) {
+                       if (memcmp(ha->addr, mc_filter->hw_addr,
+                           ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) {
+                               found = true;
+                               break;
+                       }
+               }
+
+               if (!found) {
+                       mc_filter = kzalloc(sizeof(struct ath6kl_mc_filter),
+                                           GFP_ATOMIC);
+                       if (!mc_filter) {
+                               WARN_ON(1);
+                               goto out;
+                       }
+
+                       memcpy(mc_filter->hw_addr, ha->addr,
+                              ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE);
+                       /* Set the multicast filter */
+                       ath6kl_dbg(ATH6KL_DBG_TRC,
+                                  "Adding %pM to multicast filter list\n",
+                                  mc_filter->hw_addr);
+                       ret = ath6kl_wmi_add_del_mcast_filter_cmd(vif->ar->wmi,
+                                       vif->fw_vif_idx, mc_filter->hw_addr,
+                                       true);
+                       if (ret) {
+                               ath6kl_warn("Failed to add multicast filter :%pM\n",
+                                            mc_filter->hw_addr);
+                               kfree(mc_filter);
+                               goto out;
+                       }
+
+                       list_add_tail(&mc_filter->list, &mc_filter_new);
+               }
+       }
+
+out:
+       list_splice_tail(&mc_filter_new, &vif->mc_filter);
+}
+
+static const struct net_device_ops ath6kl_netdev_ops = {
        .ndo_open               = ath6kl_open,
        .ndo_stop               = ath6kl_close,
        .ndo_start_xmit         = ath6kl_data_tx,
        .ndo_get_stats          = ath6kl_get_stats,
+       .ndo_set_features       = ath6kl_set_features,
+       .ndo_set_rx_mode        = ath6kl_set_multicast_list,
 };
 
 void init_netdev(struct net_device *dev)
index 9475e2d..662b47d 100644 (file)
@@ -49,11 +49,13 @@ struct ath6kl_sdio {
        /* scatter request list head */
        struct list_head scat_req;
 
+       /* Avoids disabling irq while the interrupts being handled */
+       struct mutex mtx_irq;
+
        spinlock_t scat_lock;
        bool scatter_enabled;
 
        bool is_disabled;
-       atomic_t irq_handling;
        const struct sdio_device_id *id;
        struct work_struct wr_async_work;
        struct list_head wr_asyncq;
@@ -460,8 +462,7 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func)
        ath6kl_dbg(ATH6KL_DBG_SDIO, "irq\n");
 
        ar_sdio = sdio_get_drvdata(func);
-       atomic_set(&ar_sdio->irq_handling, 1);
-
+       mutex_lock(&ar_sdio->mtx_irq);
        /*
         * Release the host during interrups so we can pick it back up when
         * we process commands.
@@ -470,7 +471,7 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func)
 
        status = ath6kl_hif_intr_bh_handler(ar_sdio->ar);
        sdio_claim_host(ar_sdio->func);
-       atomic_set(&ar_sdio->irq_handling, 0);
+       mutex_unlock(&ar_sdio->mtx_irq);
        WARN_ON(status && status != -ECANCELED);
 }
 
@@ -578,17 +579,14 @@ static void ath6kl_sdio_irq_disable(struct ath6kl *ar)
 
        sdio_claim_host(ar_sdio->func);
 
-       /* Mask our function IRQ */
-       while (atomic_read(&ar_sdio->irq_handling)) {
-               sdio_release_host(ar_sdio->func);
-               schedule_timeout(HZ / 10);
-               sdio_claim_host(ar_sdio->func);
-       }
+       mutex_lock(&ar_sdio->mtx_irq);
 
        ret = sdio_release_irq(ar_sdio->func);
        if (ret)
                ath6kl_err("Failed to release sdio irq: %d\n", ret);
 
+       mutex_unlock(&ar_sdio->mtx_irq);
+
        sdio_release_host(ar_sdio->func);
 }
 
@@ -772,7 +770,6 @@ static int ath6kl_sdio_config(struct ath6kl *ar)
        if (ret) {
                ath6kl_err("Set sdio block size %d failed: %d)\n",
                           HIF_MBOX_BLOCK_SIZE, ret);
-               sdio_release_host(func);
                goto out;
        }
 
@@ -1253,6 +1250,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
        spin_lock_init(&ar_sdio->scat_lock);
        spin_lock_init(&ar_sdio->wr_async_lock);
        mutex_init(&ar_sdio->dma_buffer_mutex);
+       mutex_init(&ar_sdio->mtx_irq);
 
        INIT_LIST_HEAD(&ar_sdio->scat_req);
        INIT_LIST_HEAD(&ar_sdio->bus_req_freeq);
@@ -1362,19 +1360,19 @@ MODULE_AUTHOR("Atheros Communications, Inc.");
 MODULE_DESCRIPTION("Driver support for Atheros AR600x SDIO devices");
 MODULE_LICENSE("Dual BSD/GPL");
 
-MODULE_FIRMWARE(AR6003_HW_2_0_OTP_FILE);
-MODULE_FIRMWARE(AR6003_HW_2_0_FIRMWARE_FILE);
-MODULE_FIRMWARE(AR6003_HW_2_0_PATCH_FILE);
+MODULE_FIRMWARE(AR6003_HW_2_0_FW_DIR "/" AR6003_HW_2_0_OTP_FILE);
+MODULE_FIRMWARE(AR6003_HW_2_0_FW_DIR "/" AR6003_HW_2_0_FIRMWARE_FILE);
+MODULE_FIRMWARE(AR6003_HW_2_0_FW_DIR "/" AR6003_HW_2_0_PATCH_FILE);
 MODULE_FIRMWARE(AR6003_HW_2_0_BOARD_DATA_FILE);
 MODULE_FIRMWARE(AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE);
-MODULE_FIRMWARE(AR6003_HW_2_1_1_OTP_FILE);
-MODULE_FIRMWARE(AR6003_HW_2_1_1_FIRMWARE_FILE);
-MODULE_FIRMWARE(AR6003_HW_2_1_1_PATCH_FILE);
+MODULE_FIRMWARE(AR6003_HW_2_1_1_FW_DIR "/" AR6003_HW_2_1_1_OTP_FILE);
+MODULE_FIRMWARE(AR6003_HW_2_1_1_FW_DIR "/" AR6003_HW_2_1_1_FIRMWARE_FILE);
+MODULE_FIRMWARE(AR6003_HW_2_1_1_FW_DIR "/" AR6003_HW_2_1_1_PATCH_FILE);
 MODULE_FIRMWARE(AR6003_HW_2_1_1_BOARD_DATA_FILE);
 MODULE_FIRMWARE(AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE);
-MODULE_FIRMWARE(AR6004_HW_1_0_FIRMWARE_FILE);
+MODULE_FIRMWARE(AR6004_HW_1_0_FW_DIR "/" AR6004_HW_1_0_FIRMWARE_FILE);
 MODULE_FIRMWARE(AR6004_HW_1_0_BOARD_DATA_FILE);
 MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE);
-MODULE_FIRMWARE(AR6004_HW_1_1_FIRMWARE_FILE);
+MODULE_FIRMWARE(AR6004_HW_1_1_FW_DIR "/" AR6004_HW_1_1_FIRMWARE_FILE);
 MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE);
 MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);
index 381eb66..f0cd61d 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include "testmode.h"
+#include "debug.h"
 
 #include <net/netlink.h>
 
@@ -30,7 +31,7 @@ enum ath6kl_tm_attr {
 
 enum ath6kl_tm_cmd {
        ATH6KL_TM_CMD_TCMD              = 0,
-       ATH6KL_TM_CMD_RX_REPORT         = 1,
+       ATH6KL_TM_CMD_RX_REPORT         = 1,    /* not used anymore */
 };
 
 #define ATH6KL_TM_DATA_MAX_LEN         5000
@@ -41,84 +42,33 @@ static const struct nla_policy ath6kl_tm_policy[ATH6KL_TM_ATTR_MAX + 1] = {
                                            .len = ATH6KL_TM_DATA_MAX_LEN },
 };
 
-void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf, size_t buf_len)
+void ath6kl_tm_rx_event(struct ath6kl *ar, void *buf, size_t buf_len)
 {
-       if (down_interruptible(&ar->sem))
-               return;
-
-       kfree(ar->tm.rx_report);
-
-       ar->tm.rx_report = kmemdup(buf, buf_len, GFP_KERNEL);
-       ar->tm.rx_report_len = buf_len;
-
-       up(&ar->sem);
-
-       wake_up(&ar->event_wq);
-}
-
-static int ath6kl_tm_rx_report(struct ath6kl *ar, void *buf, size_t buf_len,
-                              struct sk_buff *skb)
-{
-       int ret = 0;
-       long left;
-
-       if (down_interruptible(&ar->sem))
-               return -ERESTARTSYS;
-
-       if (!test_bit(WMI_READY, &ar->flag)) {
-               ret = -EIO;
-               goto out;
-       }
-
-       if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
-               ret = -EBUSY;
-               goto out;
-       }
-
-       if (ath6kl_wmi_test_cmd(ar->wmi, buf, buf_len) < 0) {
-               up(&ar->sem);
-               return -EIO;
-       }
-
-       left = wait_event_interruptible_timeout(ar->event_wq,
-                                               ar->tm.rx_report != NULL,
-                                               WMI_TIMEOUT);
+       struct sk_buff *skb;
 
-       if (left == 0) {
-               ret = -ETIMEDOUT;
-               goto out;
-       } else if (left < 0) {
-               ret = left;
-               goto out;
-       }
+       if (!buf || buf_len == 0)
+               return;
 
-       if (ar->tm.rx_report == NULL || ar->tm.rx_report_len == 0) {
-               ret = -EINVAL;
-               goto out;
+       skb = cfg80211_testmode_alloc_event_skb(ar->wiphy, buf_len, GFP_KERNEL);
+       if (!skb) {
+               ath6kl_warn("failed to allocate testmode rx skb!\n");
+               return;
        }
-
-       NLA_PUT(skb, ATH6KL_TM_ATTR_DATA, ar->tm.rx_report_len,
-               ar->tm.rx_report);
-
-       kfree(ar->tm.rx_report);
-       ar->tm.rx_report = NULL;
-
-out:
-       up(&ar->sem);
-
-       return ret;
+       NLA_PUT_U32(skb, ATH6KL_TM_ATTR_CMD, ATH6KL_TM_CMD_TCMD);
+       NLA_PUT(skb, ATH6KL_TM_ATTR_DATA, buf_len, buf);
+       cfg80211_testmode_event(skb, GFP_KERNEL);
+       return;
 
 nla_put_failure:
-       ret = -ENOBUFS;
-       goto out;
+       kfree_skb(skb);
+       ath6kl_warn("nla_put failed on testmode rx skb!\n");
 }
 
 int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len)
 {
        struct ath6kl *ar = wiphy_priv(wiphy);
        struct nlattr *tb[ATH6KL_TM_ATTR_MAX + 1];
-       int err, buf_len, reply_len;
-       struct sk_buff *skb;
+       int err, buf_len;
        void *buf;
 
        err = nla_parse(tb, ATH6KL_TM_ATTR_MAX, data, len,
@@ -143,24 +93,6 @@ int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len)
 
                break;
        case ATH6KL_TM_CMD_RX_REPORT:
-               if (!tb[ATH6KL_TM_ATTR_DATA])
-                       return -EINVAL;
-
-               buf = nla_data(tb[ATH6KL_TM_ATTR_DATA]);
-               buf_len = nla_len(tb[ATH6KL_TM_ATTR_DATA]);
-
-               reply_len = nla_total_size(ATH6KL_TM_DATA_MAX_LEN);
-               skb = cfg80211_testmode_alloc_reply_skb(wiphy, reply_len);
-               if (!skb)
-                       return -ENOMEM;
-
-               err = ath6kl_tm_rx_report(ar, buf, buf_len, skb);
-               if (err < 0) {
-                       kfree_skb(skb);
-                       return err;
-               }
-
-               return cfg80211_testmode_reply(skb);
        default:
                return -EOPNOTSUPP;
        }
index 43dffcc..7fd47a6 100644 (file)
 
 #ifdef CONFIG_NL80211_TESTMODE
 
-void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf, size_t buf_len);
+void ath6kl_tm_rx_event(struct ath6kl *ar, void *buf, size_t buf_len);
 int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len);
 
 #else
 
-static inline void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf,
-                                            size_t buf_len)
+static inline void ath6kl_tm_rx_event(struct ath6kl *ar, void *buf,
+                                     size_t buf_len)
 {
 }
 
index 506a303..91bbc1f 100644 (file)
@@ -77,12 +77,120 @@ static u8 ath6kl_ibss_map_epid(struct sk_buff *skb, struct net_device *dev,
        return ar->node_map[ep_map].ep_id;
 }
 
+static bool ath6kl_process_uapsdq(struct ath6kl_sta *conn,
+                               struct ath6kl_vif *vif,
+                               struct sk_buff *skb,
+                               u32 *flags)
+{
+       struct ath6kl *ar = vif->ar;
+       bool is_apsdq_empty = false;
+       struct ethhdr *datap = (struct ethhdr *) skb->data;
+       u8 up, traffic_class, *ip_hdr;
+       u16 ether_type;
+       struct ath6kl_llc_snap_hdr *llc_hdr;
+
+       if (conn->sta_flags & STA_PS_APSD_TRIGGER) {
+               /*
+                * This tx is because of a uAPSD trigger, determine
+                * more and EOSP bit. Set EOSP if queue is empty
+                * or sufficient frames are delivered for this trigger.
+                */
+               spin_lock_bh(&conn->psq_lock);
+               if (!skb_queue_empty(&conn->apsdq))
+                       *flags |= WMI_DATA_HDR_FLAGS_MORE;
+               else if (conn->sta_flags & STA_PS_APSD_EOSP)
+                       *flags |= WMI_DATA_HDR_FLAGS_EOSP;
+               *flags |= WMI_DATA_HDR_FLAGS_UAPSD;
+               spin_unlock_bh(&conn->psq_lock);
+               return false;
+       } else if (!conn->apsd_info)
+               return false;
+
+       if (test_bit(WMM_ENABLED, &vif->flags)) {
+               ether_type = be16_to_cpu(datap->h_proto);
+               if (is_ethertype(ether_type)) {
+                       /* packet is in DIX format  */
+                       ip_hdr = (u8 *)(datap + 1);
+               } else {
+                       /* packet is in 802.3 format */
+                       llc_hdr = (struct ath6kl_llc_snap_hdr *)
+                                                       (datap + 1);
+                       ether_type = be16_to_cpu(llc_hdr->eth_type);
+                       ip_hdr = (u8 *)(llc_hdr + 1);
+               }
+
+               if (ether_type == IP_ETHERTYPE)
+                       up = ath6kl_wmi_determine_user_priority(
+                                                       ip_hdr, 0);
+       } else {
+               up = 0;
+       }
+
+       traffic_class = ath6kl_wmi_get_traffic_class(up);
+
+       if ((conn->apsd_info & (1 << traffic_class)) == 0)
+               return false;
+
+       /* Queue the frames if the STA is sleeping */
+       spin_lock_bh(&conn->psq_lock);
+       is_apsdq_empty = skb_queue_empty(&conn->apsdq);
+       skb_queue_tail(&conn->apsdq, skb);
+       spin_unlock_bh(&conn->psq_lock);
+
+       /*
+        * If this is the first pkt getting queued
+        * for this STA, update the PVB for this STA
+        */
+       if (is_apsdq_empty) {
+               ath6kl_wmi_set_apsd_bfrd_traf(ar->wmi,
+                               vif->fw_vif_idx,
+                               conn->aid, 1, 0);
+       }
+       *flags |= WMI_DATA_HDR_FLAGS_UAPSD;
+
+       return true;
+}
+
+static bool ath6kl_process_psq(struct ath6kl_sta *conn,
+                               struct ath6kl_vif *vif,
+                               struct sk_buff *skb,
+                               u32 *flags)
+{
+       bool is_psq_empty = false;
+       struct ath6kl *ar = vif->ar;
+
+       if (conn->sta_flags & STA_PS_POLLED) {
+               spin_lock_bh(&conn->psq_lock);
+               if (!skb_queue_empty(&conn->psq))
+                       *flags |= WMI_DATA_HDR_FLAGS_MORE;
+               spin_unlock_bh(&conn->psq_lock);
+               return false;
+       }
+
+       /* Queue the frames if the STA is sleeping */
+       spin_lock_bh(&conn->psq_lock);
+       is_psq_empty = skb_queue_empty(&conn->psq);
+       skb_queue_tail(&conn->psq, skb);
+       spin_unlock_bh(&conn->psq_lock);
+
+       /*
+        * If this is the first pkt getting queued
+        * for this STA, update the PVB for this
+        * STA.
+        */
+       if (is_psq_empty)
+               ath6kl_wmi_set_pvb_cmd(ar->wmi,
+                                      vif->fw_vif_idx,
+                                      conn->aid, 1);
+       return true;
+}
+
 static bool ath6kl_powersave_ap(struct ath6kl_vif *vif, struct sk_buff *skb,
-                               bool *more_data)
+                               u32 *flags)
 {
        struct ethhdr *datap = (struct ethhdr *) skb->data;
        struct ath6kl_sta *conn = NULL;
-       bool ps_queued = false, is_psq_empty = false;
+       bool ps_queued = false;
        struct ath6kl *ar = vif->ar;
 
        if (is_multicast_ether_addr(datap->h_dest)) {
@@ -128,7 +236,7 @@ static bool ath6kl_powersave_ap(struct ath6kl_vif *vif, struct sk_buff *skb,
                                 */
                                spin_lock_bh(&ar->mcastpsq_lock);
                                if (!skb_queue_empty(&ar->mcastpsq))
-                                       *more_data = true;
+                                       *flags |= WMI_DATA_HDR_FLAGS_MORE;
                                spin_unlock_bh(&ar->mcastpsq_lock);
                        }
                }
@@ -142,37 +250,13 @@ static bool ath6kl_powersave_ap(struct ath6kl_vif *vif, struct sk_buff *skb,
                }
 
                if (conn->sta_flags & STA_PS_SLEEP) {
-                       if (!(conn->sta_flags & STA_PS_POLLED)) {
-                               /* Queue the frames if the STA is sleeping */
-                               spin_lock_bh(&conn->psq_lock);
-                               is_psq_empty = skb_queue_empty(&conn->psq);
-                               skb_queue_tail(&conn->psq, skb);
-                               spin_unlock_bh(&conn->psq_lock);
-
-                               /*
-                                * If this is the first pkt getting queued
-                                * for this STA, update the PVB for this
-                                * STA.
-                                */
-                               if (is_psq_empty)
-                                       ath6kl_wmi_set_pvb_cmd(ar->wmi,
-                                                              vif->fw_vif_idx,
-                                                              conn->aid, 1);
-
-                               ps_queued = true;
-                       } else {
-                               /*
-                                * This tx is because of a PsPoll.
-                                * Determine if MoreData bit has to be set.
-                                */
-                               spin_lock_bh(&conn->psq_lock);
-                               if (!skb_queue_empty(&conn->psq))
-                                       *more_data = true;
-                               spin_unlock_bh(&conn->psq_lock);
-                       }
+                       ps_queued = ath6kl_process_uapsdq(conn,
+                                               vif, skb, flags);
+                       if (!(*flags & WMI_DATA_HDR_FLAGS_UAPSD))
+                               ps_queued = ath6kl_process_psq(conn,
+                                               vif, skb, flags);
                }
        }
-
        return ps_queued;
 }
 
@@ -242,8 +326,13 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
        u32 map_no = 0;
        u16 htc_tag = ATH6KL_DATA_PKT_TAG;
        u8 ac = 99 ; /* initialize to unmapped ac */
-       bool chk_adhoc_ps_mapping = false, more_data = false;
+       bool chk_adhoc_ps_mapping = false;
        int ret;
+       struct wmi_tx_meta_v2 meta_v2;
+       void *meta;
+       u8 csum_start = 0, csum_dest = 0, csum = skb->ip_summed;
+       u8 meta_ver = 0;
+       u32 flags = 0;
 
        ath6kl_dbg(ATH6KL_DBG_WLAN_TX,
                   "%s: skb=0x%p, data=0x%p, len=0x%x\n", __func__,
@@ -260,11 +349,19 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
 
        /* AP mode Power saving processing */
        if (vif->nw_type == AP_NETWORK) {
-               if (ath6kl_powersave_ap(vif, skb, &more_data))
+               if (ath6kl_powersave_ap(vif, skb, &flags))
                        return 0;
        }
 
        if (test_bit(WMI_ENABLED, &ar->flag)) {
+               if ((dev->features & NETIF_F_IP_CSUM) &&
+                               (csum == CHECKSUM_PARTIAL)) {
+                       csum_start = skb->csum_start -
+                                       (skb_network_header(skb) - skb->head) +
+                                       sizeof(struct ath6kl_llc_snap_hdr);
+                       csum_dest = skb->csum_offset + csum_start;
+               }
+
                if (skb_headroom(skb) < dev->needed_headroom) {
                        struct sk_buff *tmp_skb = skb;
 
@@ -281,10 +378,28 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
                        goto fail_tx;
                }
 
-               if (ath6kl_wmi_data_hdr_add(ar->wmi, skb, DATA_MSGTYPE,
-                                           more_data, 0, 0, NULL,
-                                           vif->fw_vif_idx)) {
-                       ath6kl_err("wmi_data_hdr_add failed\n");
+               if ((dev->features & NETIF_F_IP_CSUM) &&
+                               (csum == CHECKSUM_PARTIAL)) {
+                       meta_v2.csum_start = csum_start;
+                       meta_v2.csum_dest = csum_dest;
+
+                       /* instruct target to calculate checksum */
+                       meta_v2.csum_flags = WMI_META_V2_FLAG_CSUM_OFFLOAD;
+                       meta_ver = WMI_META_VERSION_2;
+                       meta = &meta_v2;
+               } else {
+                       meta_ver = 0;
+                       meta = NULL;
+               }
+
+               ret = ath6kl_wmi_data_hdr_add(ar->wmi, skb,
+                               DATA_MSGTYPE, flags, 0,
+                               meta_ver,
+                               meta, vif->fw_vif_idx);
+
+               if (ret) {
+                       ath6kl_warn("failed to add wmi data header:%d\n"
+                               , ret);
                        goto fail_tx;
                }
 
@@ -449,9 +564,7 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
                 * WMI queue with too many commands the only exception to
                 * this is during testing using endpointping.
                 */
-               spin_lock_bh(&ar->lock);
                set_bit(WMI_CTRL_EP_FULL, &ar->flag);
-               spin_unlock_bh(&ar->lock);
                ath6kl_err("wmi ctrl ep is full\n");
                return action;
        }
@@ -479,9 +592,7 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
                    action != HTC_SEND_FULL_DROP) {
                        spin_unlock_bh(&ar->list_lock);
 
-                       spin_lock_bh(&vif->if_lock);
                        set_bit(NETQ_STOPPED, &vif->flags);
-                       spin_unlock_bh(&vif->if_lock);
                        netif_stop_queue(vif->ndev);
 
                        return action;
@@ -1067,6 +1178,76 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid,
        return is_queued;
 }
 
+static void ath6kl_uapsd_trigger_frame_rx(struct ath6kl_vif *vif,
+                                                struct ath6kl_sta *conn)
+{
+       struct ath6kl *ar = vif->ar;
+       bool is_apsdq_empty, is_apsdq_empty_at_start;
+       u32 num_frames_to_deliver, flags;
+       struct sk_buff *skb = NULL;
+
+       /*
+        * If the APSD q for this STA is not empty, dequeue and
+        * send a pkt from the head of the q. Also update the
+        * More data bit in the WMI_DATA_HDR if there are
+        * more pkts for this STA in the APSD q.
+        * If there are no more pkts for this STA,
+        * update the APSD bitmap for this STA.
+        */
+
+       num_frames_to_deliver = (conn->apsd_info >> ATH6KL_APSD_NUM_OF_AC) &
+                                                   ATH6KL_APSD_FRAME_MASK;
+       /*
+        * Number of frames to send in a service period is
+        * indicated by the station
+        * in the QOS_INFO of the association request
+        * If it is zero, send all frames
+        */
+       if (!num_frames_to_deliver)
+               num_frames_to_deliver = ATH6KL_APSD_ALL_FRAME;
+
+       spin_lock_bh(&conn->psq_lock);
+       is_apsdq_empty = skb_queue_empty(&conn->apsdq);
+       spin_unlock_bh(&conn->psq_lock);
+       is_apsdq_empty_at_start = is_apsdq_empty;
+
+       while ((!is_apsdq_empty) && (num_frames_to_deliver)) {
+
+               spin_lock_bh(&conn->psq_lock);
+               skb = skb_dequeue(&conn->apsdq);
+               is_apsdq_empty = skb_queue_empty(&conn->apsdq);
+               spin_unlock_bh(&conn->psq_lock);
+
+               /*
+                * Set the STA flag to Trigger delivery,
+                * so that the frame will go out
+                */
+               conn->sta_flags |= STA_PS_APSD_TRIGGER;
+               num_frames_to_deliver--;
+
+               /* Last frame in the service period, set EOSP or queue empty */
+               if ((is_apsdq_empty) || (!num_frames_to_deliver))
+                       conn->sta_flags |= STA_PS_APSD_EOSP;
+
+               ath6kl_data_tx(skb, vif->ndev);
+               conn->sta_flags &= ~(STA_PS_APSD_TRIGGER);
+               conn->sta_flags &= ~(STA_PS_APSD_EOSP);
+       }
+
+       if (is_apsdq_empty) {
+               if (is_apsdq_empty_at_start)
+                       flags = WMI_AP_APSD_NO_DELIVERY_FRAMES;
+               else
+                       flags = 0;
+
+               ath6kl_wmi_set_apsd_bfrd_traf(ar->wmi,
+                               vif->fw_vif_idx,
+                               conn->aid, 0, flags);
+       }
+
+       return;
+}
+
 void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
 {
        struct ath6kl *ar = target->dev->ar;
@@ -1078,6 +1259,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
        int status = packet->status;
        enum htc_endpoint_id ept = packet->endpoint;
        bool is_amsdu, prev_ps, ps_state = false;
+       bool trig_state = false;
        struct ath6kl_sta *conn = NULL;
        struct sk_buff *skb1 = NULL;
        struct ethhdr *datap = NULL;
@@ -1171,6 +1353,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
                              WMI_DATA_HDR_PS_MASK);
 
                offset = sizeof(struct wmi_data_hdr);
+               trig_state = !!(le16_to_cpu(dhdr->info3) & WMI_DATA_HDR_TRIG);
 
                switch (meta_type) {
                case 0:
@@ -1209,18 +1392,36 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
                else
                        conn->sta_flags &= ~STA_PS_SLEEP;
 
+               /* Accept trigger only when the station is in sleep */
+               if ((conn->sta_flags & STA_PS_SLEEP) && trig_state)
+                       ath6kl_uapsd_trigger_frame_rx(vif, conn);
+
                if (prev_ps ^ !!(conn->sta_flags & STA_PS_SLEEP)) {
                        if (!(conn->sta_flags & STA_PS_SLEEP)) {
                                struct sk_buff *skbuff = NULL;
+                               bool is_apsdq_empty;
 
                                spin_lock_bh(&conn->psq_lock);
-                               while ((skbuff = skb_dequeue(&conn->psq))
-                                      != NULL) {
+                               while ((skbuff = skb_dequeue(&conn->psq))) {
+                                       spin_unlock_bh(&conn->psq_lock);
+                                       ath6kl_data_tx(skbuff, vif->ndev);
+                                       spin_lock_bh(&conn->psq_lock);
+                               }
+
+                               is_apsdq_empty = skb_queue_empty(&conn->apsdq);
+                               while ((skbuff = skb_dequeue(&conn->apsdq))) {
                                        spin_unlock_bh(&conn->psq_lock);
                                        ath6kl_data_tx(skbuff, vif->ndev);
                                        spin_lock_bh(&conn->psq_lock);
                                }
                                spin_unlock_bh(&conn->psq_lock);
+
+                               if (!is_apsdq_empty)
+                                       ath6kl_wmi_set_apsd_bfrd_traf(
+                                                       ar->wmi,
+                                                       vif->fw_vif_idx,
+                                                       conn->aid, 0, 0);
+
                                /* Clear the PVB for this STA */
                                ath6kl_wmi_set_pvb_cmd(ar->wmi, vif->fw_vif_idx,
                                                       conn->aid, 0);
index f6f2aa2..c2420f8 100644 (file)
@@ -180,7 +180,7 @@ static int ath6kl_wmi_meta_add(struct wmi *wmi, struct sk_buff *skb,
 }
 
 int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb,
-                           u8 msg_type, bool more_data,
+                           u8 msg_type, u32 flags,
                            enum wmi_data_hdr_data_type data_type,
                            u8 meta_ver, void *tx_meta_info, u8 if_idx)
 {
@@ -204,17 +204,19 @@ int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb,
        data_hdr->info = msg_type << WMI_DATA_HDR_MSG_TYPE_SHIFT;
        data_hdr->info |= data_type << WMI_DATA_HDR_DATA_TYPE_SHIFT;
 
-       if (more_data)
-               data_hdr->info |=
-                   WMI_DATA_HDR_MORE_MASK << WMI_DATA_HDR_MORE_SHIFT;
+       if (flags & WMI_DATA_HDR_FLAGS_MORE)
+               data_hdr->info |= WMI_DATA_HDR_MORE;
 
-       data_hdr->info2 = cpu_to_le16(meta_ver << WMI_DATA_HDR_META_SHIFT);
-       data_hdr->info3 = cpu_to_le16(if_idx & WMI_DATA_HDR_IF_IDX_MASK);
+       if (flags & WMI_DATA_HDR_FLAGS_EOSP)
+               data_hdr->info3 |= cpu_to_le16(WMI_DATA_HDR_EOSP);
+
+       data_hdr->info2 |= cpu_to_le16(meta_ver << WMI_DATA_HDR_META_SHIFT);
+       data_hdr->info3 |= cpu_to_le16(if_idx & WMI_DATA_HDR_IF_IDX_MASK);
 
        return 0;
 }
 
-static u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri)
+u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri)
 {
        struct iphdr *ip_hdr = (struct iphdr *) pkt;
        u8 ip_pri;
@@ -236,6 +238,11 @@ static u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri)
                return ip_pri;
 }
 
+u8 ath6kl_wmi_get_traffic_class(u8 user_priority)
+{
+       return  up_to_ac[user_priority & 0x7];
+}
+
 int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, u8 if_idx,
                                       struct sk_buff *skb,
                                       u32 layer2_priority, bool wmm_enabled,
@@ -786,12 +793,14 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len,
                                   ev->u.ap_sta.keymgmt,
                                   le16_to_cpu(ev->u.ap_sta.cipher),
                                   ev->u.ap_sta.apsd_info);
+
                        ath6kl_connect_ap_mode_sta(
                                vif, ev->u.ap_sta.aid, ev->u.ap_sta.mac_addr,
                                ev->u.ap_sta.keymgmt,
                                le16_to_cpu(ev->u.ap_sta.cipher),
                                ev->u.ap_sta.auth, ev->assoc_req_len,
-                               ev->assoc_info + ev->beacon_ie_len);
+                               ev->assoc_info + ev->beacon_ie_len,
+                               ev->u.ap_sta.apsd_info);
                }
                return 0;
        }
@@ -1145,9 +1154,9 @@ static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len)
        return 0;
 }
 
-static int ath6kl_wmi_tcmd_test_report_rx(struct wmi *wmi, u8 *datap, int len)
+static int ath6kl_wmi_test_rx(struct wmi *wmi, u8 *datap, int len)
 {
-       ath6kl_tm_rx_report_event(wmi->parent_dev, datap, len);
+       ath6kl_tm_rx_event(wmi->parent_dev, datap, len);
 
        return 0;
 }
@@ -2479,15 +2488,16 @@ int ath6kl_wmi_delete_pstream_cmd(struct wmi *wmi, u8 if_idx, u8 traffic_class,
        return ret;
 }
 
-int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd)
+int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, u8 if_idx,
+                         __be32 ips0, __be32 ips1)
 {
        struct sk_buff *skb;
        struct wmi_set_ip_cmd *cmd;
        int ret;
 
        /* Multicast address are not valid */
-       if ((*((u8 *) &ip_cmd->ips[0]) >= 0xE0) ||
-           (*((u8 *) &ip_cmd->ips[1]) >= 0xE0))
+       if (ipv4_is_multicast(ips0) ||
+           ipv4_is_multicast(ips1))
                return -EINVAL;
 
        skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_ip_cmd));
@@ -2495,9 +2505,10 @@ int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd)
                return -ENOMEM;
 
        cmd = (struct wmi_set_ip_cmd *) skb->data;
-       memcpy(cmd, ip_cmd, sizeof(struct wmi_set_ip_cmd));
+       cmd->ips[0] = ips0;
+       cmd->ips[1] = ips1;
 
-       ret = ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SET_IP_CMDID,
+       ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_IP_CMDID,
                                  NO_SYNC_WMIFLAG);
        return ret;
 }
@@ -2853,6 +2864,51 @@ int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len)
        return ret;
 }
 
+int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on)
+{
+       struct sk_buff *skb;
+       struct wmi_mcast_filter_cmd *cmd;
+       int ret;
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_mcast_filter_cmd *) skb->data;
+       cmd->mcast_all_enable = mc_all_on;
+
+       ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_MCAST_FILTER_CMDID,
+                                 NO_SYNC_WMIFLAG);
+       return ret;
+}
+
+int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx,
+                                       u8 *filter, bool add_filter)
+{
+       struct sk_buff *skb;
+       struct wmi_mcast_filter_add_del_cmd *cmd;
+       int ret;
+
+       if ((filter[0] != 0x33 || filter[1] != 0x33) &&
+           (filter[0] != 0x01 || filter[1] != 0x00 ||
+           filter[2] != 0x5e || filter[3] > 0x7f)) {
+               ath6kl_warn("invalid multicast filter address\n");
+               return -EINVAL;
+       }
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_mcast_filter_add_del_cmd *) skb->data;
+       memcpy(cmd->mcast_mac, filter, ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE);
+       ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+                                 add_filter ? WMI_SET_MCAST_FILTER_CMDID :
+                                 WMI_DEL_MCAST_FILTER_CMDID,
+                                 NO_SYNC_WMIFLAG);
+
+       return ret;
+}
 
 s32 ath6kl_wmi_get_rate(s8 rate_index)
 {
@@ -2946,6 +3002,43 @@ int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 if_idx, u8 cmd, const u8 *mac,
                                   NO_SYNC_WMIFLAG);
 }
 
+/* This command will be used to enable/disable AP uAPSD feature */
+int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable)
+{
+       struct wmi_ap_set_apsd_cmd *cmd;
+       struct sk_buff *skb;
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_ap_set_apsd_cmd *)skb->data;
+       cmd->enable = enable;
+
+       return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_SET_APSD_CMDID,
+                                  NO_SYNC_WMIFLAG);
+}
+
+int ath6kl_wmi_set_apsd_bfrd_traf(struct wmi *wmi, u8 if_idx,
+                                            u16 aid, u16 bitmap, u32 flags)
+{
+       struct wmi_ap_apsd_buffered_traffic_cmd *cmd;
+       struct sk_buff *skb;
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_ap_apsd_buffered_traffic_cmd *)skb->data;
+       cmd->aid = cpu_to_le16(aid);
+       cmd->bitmap = cpu_to_le16(bitmap);
+       cmd->flags = cpu_to_le32(flags);
+
+       return ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+                                  WMI_AP_APSD_BUFFERED_TRAFFIC_CMDID,
+                                  NO_SYNC_WMIFLAG);
+}
+
 static int ath6kl_wmi_pspoll_event_rx(struct wmi *wmi, u8 *datap, int len,
                                      struct ath6kl_vif *vif)
 {
@@ -3400,7 +3493,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
                break;
        case WMI_TEST_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TEST_EVENTID\n");
-               ret = ath6kl_wmi_tcmd_test_report_rx(wmi, datap, len);
+               ret = ath6kl_wmi_test_rx(wmi, datap, len);
                break;
        case WMI_GET_FIXRATES_CMDID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_FIXRATES_CMDID\n");
index 42ac311..48e9d26 100644 (file)
@@ -149,8 +149,7 @@ enum wmi_msg_type {
 #define WMI_DATA_HDR_PS_MASK        0x1
 #define WMI_DATA_HDR_PS_SHIFT       5
 
-#define WMI_DATA_HDR_MORE_MASK      0x1
-#define WMI_DATA_HDR_MORE_SHIFT     5
+#define WMI_DATA_HDR_MORE      0x20
 
 enum wmi_data_hdr_data_type {
        WMI_DATA_HDR_DATA_TYPE_802_3 = 0,
@@ -160,6 +159,13 @@ enum wmi_data_hdr_data_type {
        WMI_DATA_HDR_DATA_TYPE_ACL,
 };
 
+/* Bitmap of data header flags */
+enum wmi_data_hdr_flags {
+       WMI_DATA_HDR_FLAGS_MORE = 0x1,
+       WMI_DATA_HDR_FLAGS_EOSP = 0x2,
+       WMI_DATA_HDR_FLAGS_UAPSD = 0x4,
+};
+
 #define WMI_DATA_HDR_DATA_TYPE_MASK     0x3
 #define WMI_DATA_HDR_DATA_TYPE_SHIFT    6
 
@@ -173,8 +179,12 @@ enum wmi_data_hdr_data_type {
 #define WMI_DATA_HDR_META_MASK      0x7
 #define WMI_DATA_HDR_META_SHIFT     13
 
+/* Macros for operating on WMI_DATA_HDR (info3) field */
 #define WMI_DATA_HDR_IF_IDX_MASK    0xF
 
+#define WMI_DATA_HDR_TRIG          0x10
+#define WMI_DATA_HDR_EOSP          0x10
+
 struct wmi_data_hdr {
        s8 rssi;
 
@@ -203,7 +213,8 @@ struct wmi_data_hdr {
        /*
         * usage of info3, 16-bit:
         * b3:b0        - Interface index
-        * b15:b4       - Reserved
+        * b4           - uAPSD trigger in rx & EOSP in tx
+        * b15:b5       - Reserved
         */
        __le16 info3;
 } __packed;
@@ -257,6 +268,9 @@ static inline u8 wmi_data_hdr_get_if_idx(struct wmi_data_hdr *dhdr)
 #define WMI_META_VERSION_1     0x01
 #define WMI_META_VERSION_2     0x02
 
+/* Flag to signal to FW to calculate TCP checksum */
+#define WMI_META_V2_FLAG_CSUM_OFFLOAD 0x01
+
 struct wmi_tx_meta_v1 {
        /* packet ID to identify the tx request */
        u8 pkt_id;
@@ -646,7 +660,6 @@ enum auth_mode {
        WPA2_AUTH_CCKM = 0x40,
 };
 
-#define WMI_MIN_KEY_INDEX   0
 #define WMI_MAX_KEY_INDEX   3
 
 #define WMI_MAX_KEY_LEN     32
@@ -1237,6 +1250,15 @@ enum target_event_report_config {
        NO_DISCONN_EVT_IN_RECONN
 };
 
+struct wmi_mcast_filter_cmd {
+       u8 mcast_all_enable;
+} __packed;
+
+#define ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE 6
+struct wmi_mcast_filter_add_del_cmd {
+       u8 mcast_mac[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE];
+} __packed;
+
 /* Command Replies */
 
 /* WMI_GET_CHANNEL_LIST_CMDID reply */
@@ -1903,7 +1925,7 @@ struct wow_filter {
 
 struct wmi_set_ip_cmd {
        /* IP in network byte order */
-       __le32 ips[MAX_IP_ADDRS];
+       __be32 ips[MAX_IP_ADDRS];
 } __packed;
 
 enum ath6kl_wow_filters {
@@ -2105,6 +2127,19 @@ struct wmi_rx_frame_format_cmd {
 } __packed;
 
 /* AP mode events */
+struct wmi_ap_set_apsd_cmd {
+       u8 enable;
+} __packed;
+
+enum wmi_ap_apsd_buffered_traffic_flags {
+       WMI_AP_APSD_NO_DELIVERY_FRAMES =  0x1,
+};
+
+struct wmi_ap_apsd_buffered_traffic_cmd {
+       __le16 aid;
+       __le16 bitmap;
+       __le32 flags;
+} __packed;
 
 /* WMI_PS_POLL_EVENT */
 struct wmi_pspoll_event {
@@ -2321,7 +2356,7 @@ enum htc_endpoint_id ath6kl_wmi_get_control_ep(struct wmi *wmi);
 void ath6kl_wmi_set_control_ep(struct wmi *wmi, enum htc_endpoint_id ep_id);
 int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb);
 int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb,
-                           u8 msg_type, bool more_data,
+                           u8 msg_type, u32 flags,
                            enum wmi_data_hdr_data_type data_type,
                            u8 meta_ver, void *tx_meta_info, u8 if_idx);
 
@@ -2417,7 +2452,8 @@ int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len);
 
 s32 ath6kl_wmi_get_rate(s8 rate_index);
 
-int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd);
+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_wow_mode_cmd(struct wmi *wmi, u8 if_idx,
@@ -2431,7 +2467,19 @@ int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
 int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi);
 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);
+/* AP mode uAPSD */
+int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable);
+
+int ath6kl_wmi_set_apsd_bfrd_traf(struct wmi *wmi,
+                                               u8 if_idx, u16 aid,
+                                               u16 bitmap, u32 flags);
+
+u8 ath6kl_wmi_get_traffic_class(u8 user_priority);
 
+u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri);
 /* AP mode */
 int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, u8 if_idx,
                                 struct wmi_connect_cmd *p);