Merge branch 'for-linville' of git://github.com/kvalo/ath6kl
authorJohn W. Linville <linville@tuxdriver.com>
Tue, 13 Mar 2012 18:45:40 +0000 (14:45 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 13 Mar 2012 18:45:40 +0000 (14:45 -0400)
25 files changed:
drivers/net/wireless/ath/ath6kl/Makefile
drivers/net/wireless/ath/ath6kl/bmi.c
drivers/net/wireless/ath/ath6kl/bmi.h
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath6kl/cfg80211.h
drivers/net/wireless/ath/ath6kl/common.h
drivers/net/wireless/ath/ath6kl/core.c
drivers/net/wireless/ath/ath6kl/core.h
drivers/net/wireless/ath/ath6kl/debug.c
drivers/net/wireless/ath/ath6kl/debug.h
drivers/net/wireless/ath/ath6kl/hif-ops.h
drivers/net/wireless/ath/ath6kl/hif.c
drivers/net/wireless/ath/ath6kl/hif.h
drivers/net/wireless/ath/ath6kl/htc.c
drivers/net/wireless/ath/ath6kl/htc.h
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/target.h
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/usb.c
drivers/net/wireless/ath/ath6kl/wmi.c
drivers/net/wireless/ath/ath6kl/wmi.h

index 9ba42fa..85746c3 100644 (file)
@@ -1,5 +1,6 @@
 #------------------------------------------------------------------------------
-# Copyright (c) 2004-2010 Atheros Communications Inc.
+# Copyright (c) 2004-2011 Atheros Communications Inc.
+# Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
 # All rights reserved.
 #
 #
index aef00d5..334dbd8 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -105,7 +106,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar,
        }
 
        ath6kl_dbg(ATH6KL_DBG_BMI, "target info (ver: 0x%x type: 0x%x)\n",
-               targ_info->version, targ_info->type);
+                  targ_info->version, targ_info->type);
 
        return 0;
 }
@@ -192,7 +193,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
        memset(ar->bmi.cmd_buf, 0, ar->bmi.max_data_size + header);
 
        ath6kl_dbg(ATH6KL_DBG_BMI,
-                 "bmi write memory: addr: 0x%x, len: %d\n", addr, len);
+                  "bmi write memory: addr: 0x%x, len: %d\n", addr, len);
 
        len_remain = len;
        while (len_remain) {
@@ -434,7 +435,7 @@ int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len)
                memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len));
                offset += sizeof(tx_len);
                memcpy(&(ar->bmi.cmd_buf[offset]), &buf[len - len_remain],
-                       tx_len);
+                      tx_len);
                offset += tx_len;
 
                ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
index f1ca681..18fdd69 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004-2011 Atheros Communications Inc.
+ * Copyright (c) 2011 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -222,6 +223,29 @@ struct ath6kl_bmi_target_info {
        __le32 type;         /* target type */
 } __packed;
 
+#define ath6kl_bmi_write_hi32(ar, item, val)                           \
+       ({                                                              \
+               u32 addr;                                               \
+               __le32 v;                                               \
+                                                                       \
+               addr = ath6kl_get_hi_item_addr(ar, HI_ITEM(item));      \
+               v = cpu_to_le32(val);                                   \
+               ath6kl_bmi_write(ar, addr, (u8 *) &v, sizeof(v));       \
+       })
+
+#define ath6kl_bmi_read_hi32(ar, item, val)                            \
+       ({                                                              \
+               u32 addr, *check_type = val;                            \
+               __le32 tmp;                                             \
+               int ret;                                                \
+                                                                       \
+               (void) (check_type == val);                             \
+               addr = ath6kl_get_hi_item_addr(ar, HI_ITEM(item));      \
+               ret = ath6kl_bmi_read(ar, addr, (u8 *) &tmp, 4);        \
+               *val = le32_to_cpu(tmp);                                \
+               ret;                                                    \
+       })
+
 int ath6kl_bmi_init(struct ath6kl *ar);
 void ath6kl_bmi_cleanup(struct ath6kl *ar);
 void ath6kl_bmi_reset(struct ath6kl *ar);
index 5370333..00d3895 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -68,6 +69,10 @@ static struct ieee80211_rate ath6kl_rates[] = {
 #define ath6kl_g_rates     (ath6kl_rates + 0)
 #define ath6kl_g_rates_size    12
 
+#define ath6kl_g_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
+                       IEEE80211_HT_CAP_SGI_20          | \
+                       IEEE80211_HT_CAP_SGI_40)
+
 static struct ieee80211_channel ath6kl_2ghz_channels[] = {
        CHAN2G(1, 2412, 0),
        CHAN2G(2, 2417, 0),
@@ -112,6 +117,8 @@ static struct ieee80211_supported_band ath6kl_band_2ghz = {
        .channels = ath6kl_2ghz_channels,
        .n_bitrates = ath6kl_g_rates_size,
        .bitrates = ath6kl_g_rates,
+       .ht_cap.cap = ath6kl_g_htcap,
+       .ht_cap.ht_supported = true,
 };
 
 static struct ieee80211_supported_band ath6kl_band_5ghz = {
@@ -119,6 +126,8 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = {
        .channels = ath6kl_5ghz_a_channels,
        .n_bitrates = ath6kl_a_rates_size,
        .bitrates = ath6kl_a_rates,
+       .ht_cap.cap = ath6kl_g_htcap,
+       .ht_cap.ht_supported = true,
 };
 
 #define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */
@@ -381,7 +390,7 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
                return false;
 
        if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) &&
-           ar->num_vif))
+                                  ar->num_vif))
                return false;
 
        if (type == NL80211_IFTYPE_STATION ||
@@ -407,6 +416,12 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
        return false;
 }
 
+static bool ath6kl_is_tx_pending(struct ath6kl *ar)
+{
+       return ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0;
+}
+
+
 static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
                                   struct cfg80211_connect_params *sme)
 {
@@ -414,6 +429,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
        struct ath6kl_vif *vif = netdev_priv(dev);
        int status;
        u8 nw_subtype = (ar->p2p) ? SUBTYPE_P2PDEV : SUBTYPE_NONE;
+       u16 interval;
 
        ath6kl_cfg80211_sscan_disable(vif);
 
@@ -450,8 +466,8 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
                 * sleep until the command queue drains
                 */
                wait_event_interruptible_timeout(ar->event_wq,
-                       ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0,
-                       WMI_TIMEOUT);
+                                                ath6kl_is_tx_pending(ar),
+                                                WMI_TIMEOUT);
                if (signal_pending(current)) {
                        ath6kl_err("cmd queue drain timeout\n");
                        up(&ar->sem);
@@ -546,7 +562,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
        if (!ar->usr_bss_filter) {
                clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
                if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
-                   ALL_BSS_FILTER, 0) != 0) {
+                                            ALL_BSS_FILTER, 0) != 0) {
                        ath6kl_err("couldn't set bss filtering\n");
                        up(&ar->sem);
                        return -EIO;
@@ -568,6 +584,20 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
                   vif->grp_crypto_len, vif->ch_hint);
 
        vif->reconnect_flag = 0;
+
+       if (vif->nw_type == INFRA_NETWORK) {
+               interval = max_t(u16, vif->listen_intvl_t,
+                                ATH6KL_MAX_WOW_LISTEN_INTL);
+               status = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
+                                                      interval,
+                                                      0);
+               if (status) {
+                       ath6kl_err("couldn't set listen intervel\n");
+                       up(&ar->sem);
+                       return status;
+               }
+       }
+
        status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
                                        vif->dot11_auth_mode, vif->auth_mode,
                                        vif->prwise_crypto,
@@ -590,8 +620,8 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
        }
 
        if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
-           ((vif->auth_mode == WPA_PSK_AUTH)
-            || (vif->auth_mode == WPA2_PSK_AUTH))) {
+           ((vif->auth_mode == WPA_PSK_AUTH) ||
+            (vif->auth_mode == WPA2_PSK_AUTH))) {
                mod_timer(&vif->disconnect_timer,
                          jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
        }
@@ -824,13 +854,13 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
 
        if (vif->sme_state == SME_CONNECTING) {
                cfg80211_connect_result(vif->ndev,
-                               bssid, NULL, 0,
-                               NULL, 0,
-                               WLAN_STATUS_UNSPECIFIED_FAILURE,
-                               GFP_KERNEL);
+                                       bssid, NULL, 0,
+                                       NULL, 0,
+                                       WLAN_STATUS_UNSPECIFIED_FAILURE,
+                                       GFP_KERNEL);
        } else if (vif->sme_state == SME_CONNECTED) {
                cfg80211_disconnected(vif->ndev, reason,
-                               NULL, 0, GFP_KERNEL);
+                                     NULL, 0, GFP_KERNEL);
        }
 
        vif->sme_state = SME_DISCONNECTED;
@@ -876,19 +906,14 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
                                                  request->ssids[i].ssid);
        }
 
-       /*
-        * FIXME: we should clear the IE in fw if it's not set so just
-        * remove the check altogether
-        */
-       if (request->ie) {
-               ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
-                                              WMI_FRAME_PROBE_REQ,
-                                              request->ie, request->ie_len);
-               if (ret) {
-                       ath6kl_err("failed to set Probe Request appie for "
-                                  "scan");
-                       return ret;
-               }
+       /* this also clears IE in fw if it's not set */
+       ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
+                                      WMI_FRAME_PROBE_REQ,
+                                      request->ie, request->ie_len);
+       if (ret) {
+               ath6kl_err("failed to set Probe Request appie for "
+                          "scan");
+               return ret;
        }
 
        /*
@@ -917,7 +942,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
                force_fg_scan = 1;
 
        if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
-                   ar->fw_capabilities)) {
+                    ar->fw_capabilities)) {
                /*
                 * If capable of doing P2P mgmt operations using
                 * station interface, send additional information like
@@ -926,14 +951,17 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
                 */
                ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx,
                                                WMI_LONG_SCAN, force_fg_scan,
-                                               false, 0, 0, n_channels,
-                                               channels, request->no_cck,
+                                               false, 0,
+                                               ATH6KL_FG_SCAN_INTERVAL,
+                                               n_channels, channels,
+                                               request->no_cck,
                                                request->rates);
        } else {
                ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx,
                                                WMI_LONG_SCAN, force_fg_scan,
-                                               false, 0, 0, n_channels,
-                                               channels);
+                                               false, 0,
+                                               ATH6KL_FG_SCAN_INTERVAL,
+                                               n_channels, channels);
        }
        if (ret)
                ath6kl_err("wmi_startscan_cmd failed\n");
@@ -1046,9 +1074,9 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
                return -ENOTSUPP;
        }
 
-       if (((vif->auth_mode == WPA_PSK_AUTH)
-            || (vif->auth_mode == WPA2_PSK_AUTH))
-           && (key_usage & GROUP_USAGE))
+       if (((vif->auth_mode == WPA_PSK_AUTH) ||
+            (vif->auth_mode == WPA2_PSK_AUTH)) &&
+           (key_usage & GROUP_USAGE))
                del_timer(&vif->disconnect_timer);
 
        ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
@@ -1058,7 +1086,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
 
        if (vif->nw_type == AP_NETWORK && !pairwise &&
            (key_type == TKIP_CRYPT || key_type == AES_CRYPT ||
-            key_type == WAPI_CRYPT) && params) {
+            key_type == WAPI_CRYPT)) {
                ar->ap_mode_bkey.valid = true;
                ar->ap_mode_bkey.key_index = key_index;
                ar->ap_mode_bkey.key_type = key_type;
@@ -1263,7 +1291,6 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
 {
        struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
        struct ath6kl_vif *vif;
-       u8 ath6kl_dbm;
        int dbm = MBM_TO_DBM(mbm);
 
        ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
@@ -1280,7 +1307,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
        case NL80211_TX_POWER_AUTOMATIC:
                return 0;
        case NL80211_TX_POWER_LIMITED:
-               ar->tx_pwr = ath6kl_dbm = dbm;
+               ar->tx_pwr = dbm;
                break;
        default:
                ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
@@ -1288,7 +1315,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
                return -EOPNOTSUPP;
        }
 
-       ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_dbm);
+       ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, dbm);
 
        return 0;
 }
@@ -1349,7 +1376,7 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
        }
 
        if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx,
-            mode.pwr_mode) != 0) {
+                                    mode.pwr_mode) != 0) {
                ath6kl_err("wmi_powermode_cmd failed\n");
                return -EIO;
        }
@@ -1904,7 +1931,7 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
        struct ath6kl_vif *vif;
        int ret, left;
        u32 filter = 0;
-       u16 i;
+       u16 i, bmiss_time;
        u8 index = 0;
        __be32 ips[MAX_IP_ADDRS];
 
@@ -1941,6 +1968,34 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
        if (ret)
                return ret;
 
+       netif_stop_queue(vif->ndev);
+
+       if (vif->nw_type != AP_NETWORK) {
+               ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
+                                                   ATH6KL_MAX_WOW_LISTEN_INTL,
+                                                   0);
+               if (ret)
+                       return ret;
+
+               /* Set listen interval x 15 times as bmiss time */
+               bmiss_time = ATH6KL_MAX_WOW_LISTEN_INTL * 15;
+               if (bmiss_time > ATH6KL_MAX_BMISS_TIME)
+                       bmiss_time = ATH6KL_MAX_BMISS_TIME;
+
+               ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx,
+                                              bmiss_time, 0);
+               if (ret)
+                       return ret;
+
+               ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
+                                               0xFFFF, 0, 0xFFFF, 0, 0, 0,
+                                               0, 0, 0, 0);
+               if (ret)
+                       return ret;
+       }
+
+       ar->state = ATH6KL_STATE_SUSPENDING;
+
        /* Setup own IP addr for ARP agent. */
        in_dev = __in_dev_get_rtnl(vif->ndev);
        if (!in_dev)
@@ -2019,15 +2074,46 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
        if (!vif)
                return -EIO;
 
+       ar->state = ATH6KL_STATE_RESUMING;
+
        ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
                                                 ATH6KL_HOST_MODE_AWAKE);
-       return ret;
+       if (ret) {
+               ath6kl_warn("Failed to configure host sleep mode for "
+                           "wow resume: %d\n", ret);
+               ar->state = ATH6KL_STATE_WOW;
+               return ret;
+       }
+
+       if (vif->nw_type != AP_NETWORK) {
+               ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
+                                               0, 0, 0, 0, 0, 0, 3, 0, 0, 0);
+               if (ret)
+                       return ret;
+
+               ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
+                                                   vif->listen_intvl_t, 0);
+               if (ret)
+                       return ret;
+
+               ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx,
+                                              vif->bmiss_time_t, 0);
+               if (ret)
+                       return ret;
+       }
+
+       ar->state = ATH6KL_STATE_ON;
+
+       netif_wake_queue(vif->ndev);
+
+       return 0;
 }
 
 int ath6kl_cfg80211_suspend(struct ath6kl *ar,
                            enum ath6kl_cfg_suspend_mode mode,
                            struct cfg80211_wowlan *wow)
 {
+       enum ath6kl_state prev_state;
        int ret;
 
        switch (mode) {
@@ -2038,11 +2124,14 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
                /* Flush all non control pkts in TX path */
                ath6kl_tx_data_cleanup(ar);
 
+               prev_state = ar->state;
+
                ret = ath6kl_wow_suspend(ar, wow);
                if (ret) {
-                       ath6kl_err("wow suspend failed: %d\n", ret);
+                       ar->state = prev_state;
                        return ret;
                }
+
                ar->state = ATH6KL_STATE_WOW;
                break;
 
@@ -2114,7 +2203,6 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar)
                        return ret;
                }
 
-               ar->state = ATH6KL_STATE_ON;
                break;
 
        case ATH6KL_STATE_DEEPSLEEP:
@@ -2188,6 +2276,9 @@ static int __ath6kl_cfg80211_resume(struct wiphy *wiphy)
  */
 void ath6kl_check_wow_status(struct ath6kl *ar)
 {
+       if (ar->state == ATH6KL_STATE_SUSPENDING)
+               return;
+
        if (ar->state == ATH6KL_STATE_WOW)
                ath6kl_cfg80211_resume(ar);
 }
@@ -2275,30 +2366,27 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif,
        struct ath6kl *ar = vif->ar;
        int res;
 
-       if (info->beacon_ies) {
-               res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
-                                              WMI_FRAME_BEACON,
-                                              info->beacon_ies,
-                                              info->beacon_ies_len);
-               if (res)
-                       return res;
-       }
+       /* this also clears IE in fw if it's not set */
+       res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
+                                      WMI_FRAME_BEACON,
+                                      info->beacon_ies,
+                                      info->beacon_ies_len);
+       if (res)
+               return res;
 
-       if (info->proberesp_ies) {
-               res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
-                                                  info->proberesp_ies_len);
-               if (res)
-                       return res;
-       }
+       /* this also clears IE in fw if it's not set */
+       res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
+                                          info->proberesp_ies_len);
+       if (res)
+               return res;
 
-       if (info->assocresp_ies) {
-               res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
-                                              WMI_FRAME_ASSOC_RESP,
-                                              info->assocresp_ies,
-                                              info->assocresp_ies_len);
-               if (res)
-                       return res;
-       }
+       /* this also clears IE in fw if it's not set */
+       res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
+                                      WMI_FRAME_ASSOC_RESP,
+                                      info->assocresp_ies,
+                                      info->assocresp_ies_len);
+       if (res)
+               return res;
 
        return 0;
 }
@@ -2309,6 +2397,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
        struct ath6kl *ar = ath6kl_priv(dev);
        struct ath6kl_vif *vif = netdev_priv(dev);
        struct ieee80211_mgmt *mgmt;
+       bool hidden = false;
        u8 *ies;
        int ies_len;
        struct wmi_connect_cmd p;
@@ -2345,7 +2434,11 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
        memcpy(vif->ssid, info->ssid, info->ssid_len);
        vif->ssid_len = info->ssid_len;
        if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
-               return -EOPNOTSUPP; /* TODO */
+               hidden = true;
+
+       res = ath6kl_wmi_ap_hidden_ssid(ar->wmi, vif->fw_vif_idx, hidden);
+       if (res)
+               return res;
 
        ret = ath6kl_set_auth_type(vif, info->auth_type);
        if (ret)
@@ -2584,6 +2677,76 @@ static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif,
        return ret;
 }
 
+static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif,
+                                    u32 id,
+                                    u32 freq,
+                                    u32 wait,
+                                    const u8 *buf,
+                                    size_t len,
+                                    bool *more_data,
+                                    bool no_cck)
+{
+       struct ieee80211_mgmt *mgmt;
+       struct ath6kl_sta *conn;
+       bool is_psq_empty = false;
+       struct ath6kl_mgmt_buff *mgmt_buf;
+       size_t mgmt_buf_size;
+       struct ath6kl *ar = vif->ar;
+
+       mgmt = (struct ieee80211_mgmt *) buf;
+       if (is_multicast_ether_addr(mgmt->da))
+               return false;
+
+       conn = ath6kl_find_sta(vif, mgmt->da);
+       if (!conn)
+               return false;
+
+       if (conn->sta_flags & STA_PS_SLEEP) {
+               if (!(conn->sta_flags & STA_PS_POLLED)) {
+                       /* Queue the frames if the STA is sleeping */
+                       mgmt_buf_size = len + sizeof(struct ath6kl_mgmt_buff);
+                       mgmt_buf = kmalloc(mgmt_buf_size, GFP_KERNEL);
+                       if (!mgmt_buf)
+                               return false;
+
+                       INIT_LIST_HEAD(&mgmt_buf->list);
+                       mgmt_buf->id = id;
+                       mgmt_buf->freq = freq;
+                       mgmt_buf->wait = wait;
+                       mgmt_buf->len = len;
+                       mgmt_buf->no_cck = no_cck;
+                       memcpy(mgmt_buf->buf, buf, len);
+                       spin_lock_bh(&conn->psq_lock);
+                       is_psq_empty = skb_queue_empty(&conn->psq) &&
+                                       (conn->mgmt_psq_len == 0);
+                       list_add_tail(&mgmt_buf->list, &conn->mgmt_psq);
+                       conn->mgmt_psq_len++;
+                       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;
+               }
+
+               /*
+                * 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) || (conn->mgmt_psq_len != 0))
+                       *more_data = true;
+               spin_unlock_bh(&conn->psq_lock);
+       }
+
+       return false;
+}
+
 static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
                          struct ieee80211_channel *chan, bool offchan,
                          enum nl80211_channel_type channel_type,
@@ -2595,6 +2758,7 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
        struct ath6kl_vif *vif = netdev_priv(dev);
        u32 id;
        const struct ieee80211_mgmt *mgmt;
+       bool more_data, queued;
 
        mgmt = (const struct ieee80211_mgmt *) buf;
        if (buf + len >= mgmt->u.probe_resp.variable &&
@@ -2620,22 +2784,19 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
 
        *cookie = id;
 
-       if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
-                   ar->fw_capabilities)) {
-               /*
-                * If capable of doing P2P mgmt operations using
-                * station interface, send additional information like
-                * supported rates to advertise and xmit rates for
-                * probe requests
-                */
-               return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id,
-                                               chan->center_freq, wait,
-                                               buf, len, no_cck);
-       } else {
-               return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id,
-                                                 chan->center_freq, wait,
-                                                 buf, len);
+       /* AP mode Power saving processing */
+       if (vif->nw_type == AP_NETWORK) {
+               queued = ath6kl_mgmt_powersave_ap(vif,
+                                       id, chan->center_freq,
+                                       wait, buf,
+                                       len, &more_data, no_cck);
+               if (queued)
+                       return 0;
        }
+
+       return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id,
+                                       chan->center_freq, wait,
+                                       buf, len, no_cck);
 }
 
 static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
@@ -2929,7 +3090,10 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
        vif->wdev.netdev = ndev;
        vif->wdev.iftype = type;
        vif->fw_vif_idx = fw_vif_idx;
-       vif->nw_type = vif->next_mode = nw_type;
+       vif->nw_type = nw_type;
+       vif->next_mode = nw_type;
+       vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL;
+       vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME;
 
        memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
        if (fw_vif_idx != 0)
@@ -3009,18 +3173,36 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
 
        wiphy->max_sched_scan_ssids = 10;
 
+       ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
+                           WIPHY_FLAG_HAVE_AP_SME |
+                           WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
+                           WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
+
+       if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities))
+               ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+
+       ar->wiphy->probe_resp_offload =
+               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
+               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
+               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P |
+               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U;
+
        ret = wiphy_register(wiphy);
        if (ret < 0) {
                ath6kl_err("couldn't register wiphy device\n");
                return ret;
        }
 
+       ar->wiphy_registered = true;
+
        return 0;
 }
 
 void ath6kl_cfg80211_cleanup(struct ath6kl *ar)
 {
        wiphy_unregister(ar->wiphy);
+
+       ar->wiphy_registered = false;
 }
 
 struct ath6kl *ath6kl_cfg80211_create(void)
index 3c693b7..c5def43 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index f89f1e1..a60e78c 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2010-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 722ca59..45e641f 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 
 unsigned int debug_mask;
 static unsigned int suspend_mode;
+static unsigned int wow_mode;
 static unsigned int uart_debug;
 static unsigned int ath6kl_p2p;
 static unsigned int testmode;
 
 module_param(debug_mask, uint, 0644);
 module_param(suspend_mode, uint, 0644);
+module_param(wow_mode, uint, 0644);
 module_param(uart_debug, uint, 0644);
 module_param(ath6kl_p2p, uint, 0644);
 module_param(testmode, uint, 0644);
@@ -97,48 +100,12 @@ int ath6kl_core_init(struct ath6kl *ar)
 
        ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi);
 
-       ret = ath6kl_cfg80211_init(ar);
-       if (ret)
-               goto err_node_cleanup;
-
-       ret = ath6kl_debug_init(ar);
-       if (ret) {
-               wiphy_unregister(ar->wiphy);
-               goto err_node_cleanup;
-       }
-
-       for (i = 0; i < ar->vif_max; i++)
-               ar->avail_idx_map |= BIT(i);
-
-       rtnl_lock();
-
-       /* Add an initial station interface */
-       ndev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0,
-                                   INFRA_NETWORK);
-
-       rtnl_unlock();
-
-       if (!ndev) {
-               ath6kl_err("Failed to instantiate a network device\n");
-               ret = -ENOMEM;
-               wiphy_unregister(ar->wiphy);
-               goto err_debug_init;
-       }
-
-
-       ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n",
-                       __func__, ndev->name, ndev, ar);
-
        /* setup access class priority mappings */
        ar->ac_stream_pri_map[WMM_AC_BK] = 0; /* lowest  */
        ar->ac_stream_pri_map[WMM_AC_BE] = 1;
        ar->ac_stream_pri_map[WMM_AC_VI] = 2;
        ar->ac_stream_pri_map[WMM_AC_VO] = 3; /* highest */
 
-       /* give our connected endpoints some buffers */
-       ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep);
-       ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]);
-
        /* allocate some buffers that handle larger AMSDU frames */
        ath6kl_refill_amsdu_rxbufs(ar, ATH6KL_MAX_AMSDU_RX_BUFFERS);
 
@@ -148,32 +115,25 @@ int ath6kl_core_init(struct ath6kl *ar)
                         ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST;
 
        if (suspend_mode &&
-               suspend_mode >= WLAN_POWER_STATE_CUT_PWR &&
-               suspend_mode <= WLAN_POWER_STATE_WOW)
+           suspend_mode >= WLAN_POWER_STATE_CUT_PWR &&
+           suspend_mode <= WLAN_POWER_STATE_WOW)
                ar->suspend_mode = suspend_mode;
        else
                ar->suspend_mode = 0;
 
+       if (suspend_mode == WLAN_POWER_STATE_WOW &&
+           (wow_mode == WLAN_POWER_STATE_CUT_PWR ||
+            wow_mode == WLAN_POWER_STATE_DEEP_SLEEP))
+               ar->wow_suspend_mode = wow_mode;
+       else
+               ar->wow_suspend_mode = 0;
+
        if (uart_debug)
                ar->conf_flags |= ATH6KL_CONF_UART_DEBUG;
 
-       ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
-                           WIPHY_FLAG_HAVE_AP_SME |
-                           WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
-                           WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
-
-       if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities))
-               ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
-
-       ar->wiphy->probe_resp_offload =
-               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
-               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
-               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P |
-               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U;
-
        set_bit(FIRST_BOOT, &ar->flag);
 
-       ndev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
+       ath6kl_debug_init(ar);
 
        ret = ath6kl_init_hw_start(ar);
        if (ret) {
@@ -181,24 +141,47 @@ int ath6kl_core_init(struct ath6kl *ar)
                goto err_rxbuf_cleanup;
        }
 
-       /*
-        * Set mac address which is received in ready event
-        * FIXME: Move to ath6kl_interface_add()
-        */
-       memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
+       /* give our connected endpoints some buffers */
+       ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep);
+       ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]);
+
+       ret = ath6kl_cfg80211_init(ar);
+       if (ret)
+               goto err_rxbuf_cleanup;
+
+       ret = ath6kl_debug_init_fs(ar);
+       if (ret) {
+               wiphy_unregister(ar->wiphy);
+               goto err_rxbuf_cleanup;
+       }
+
+       for (i = 0; i < ar->vif_max; i++)
+               ar->avail_idx_map |= BIT(i);
+
+       rtnl_lock();
+
+       /* Add an initial station interface */
+       ndev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0,
+                                   INFRA_NETWORK);
+
+       rtnl_unlock();
+
+       if (!ndev) {
+               ath6kl_err("Failed to instantiate a network device\n");
+               ret = -ENOMEM;
+               wiphy_unregister(ar->wiphy);
+               goto err_rxbuf_cleanup;
+       }
+
+       ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n",
+                  __func__, ndev->name, ndev, ar);
 
        return ret;
 
 err_rxbuf_cleanup:
+       ath6kl_debug_cleanup(ar);
        ath6kl_htc_flush_rx_buf(ar->htc_target);
        ath6kl_cleanup_amsdu_rxbufs(ar);
-       rtnl_lock();
-       ath6kl_cfg80211_vif_cleanup(netdev_priv(ndev));
-       rtnl_unlock();
-       wiphy_unregister(ar->wiphy);
-err_debug_init:
-       ath6kl_debug_cleanup(ar);
-err_node_cleanup:
        ath6kl_wmi_shutdown(ar->wmi);
        clear_bit(WMI_ENABLED, &ar->flag);
        ar->wmi = NULL;
@@ -245,9 +228,7 @@ struct ath6kl *ath6kl_core_create(struct device *dev)
        clear_bit(SKIP_SCAN, &ar->flag);
        clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
 
-       ar->listen_intvl_b = A_DEFAULT_LISTEN_INTERVAL;
        ar->tx_pwr = 0;
-
        ar->intra_bss = 1;
        ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
 
@@ -261,6 +242,8 @@ struct ath6kl *ath6kl_core_create(struct device *dev)
                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);
+               ar->sta_list[ctr].mgmt_psq_len = 0;
+               INIT_LIST_HEAD(&ar->sta_list[ctr].mgmt_psq);
                ar->sta_list[ctr].aggr_conn =
                        kzalloc(sizeof(struct aggr_info_conn), GFP_KERNEL);
                if (!ar->sta_list[ctr].aggr_conn) {
index c4d66e0..f1dd890 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2010-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -59,8 +60,9 @@
 #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         1      /* beacon intervals */
-#define A_MAX_WOW_LISTEN_INTERVAL         1000
+
+/* Channel dwell time in fg scan */
+#define ATH6KL_FG_SCAN_INTERVAL                50 /* in ms */
 
 /* includes also the null byte */
 #define ATH6KL_FIRMWARE_MAGIC               "QCA-ATH6KL"
@@ -183,6 +185,11 @@ struct ath6kl_fw_ie {
 
 #define MBOX_YIELD_LIMIT 99
 
+#define ATH6KL_DEFAULT_LISTEN_INTVAL   100 /* in TUs */
+#define ATH6KL_DEFAULT_BMISS_TIME      1500
+#define ATH6KL_MAX_WOW_LISTEN_INTL     300 /* in TUs */
+#define ATH6KL_MAX_BMISS_TIME          5000
+
 /* configuration lags */
 /*
  * ATH6KL_CONF_IGNORE_ERP_BARKER: Ignore the barker premable in
@@ -226,6 +233,12 @@ struct rxtid {
        u32 hold_q_sz;
        struct skb_hold_q *hold_q;
        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.
+        */
        spinlock_t lock;
 };
 
@@ -285,6 +298,16 @@ struct ath6kl_cookie {
        struct ath6kl_cookie *arc_list_next;
 };
 
+struct ath6kl_mgmt_buff {
+       struct list_head list;
+       u32 freq;
+       u32 wait;
+       u32 id;
+       bool no_cck;
+       size_t len;
+       u8 buf[0];
+};
+
 struct ath6kl_sta {
        u16 sta_flags;
        u8 mac[ETH_ALEN];
@@ -294,7 +317,12 @@ struct ath6kl_sta {
        u8 auth;
        u8 wpa_ie[ATH6KL_MAX_IE];
        struct sk_buff_head psq;
+
+       /* protects psq, mgmt_psq, apsdq, and mgmt_psq_len fields */
        spinlock_t psq_lock;
+
+       struct list_head mgmt_psq;
+       size_t mgmt_psq_len;
        u8 apsd_info;
        struct sk_buff_head apsdq;
        struct aggr_info_conn *aggr_conn;
@@ -494,6 +522,8 @@ struct ath6kl_vif {
        bool probe_req_report;
        u16 next_chan;
        u16 assoc_bss_beacon_int;
+       u16 listen_intvl_t;
+       u16 bmiss_time_t;
        u8 assoc_bss_dtim_period;
        struct net_device_stats net_stats;
        struct target_stats target_stats;
@@ -521,6 +551,8 @@ enum ath6kl_dev_state {
 enum ath6kl_state {
        ATH6KL_STATE_OFF,
        ATH6KL_STATE_ON,
+       ATH6KL_STATE_SUSPENDING,
+       ATH6KL_STATE_RESUMING,
        ATH6KL_STATE_DEEPSLEEP,
        ATH6KL_STATE_CUTPOWER,
        ATH6KL_STATE_WOW,
@@ -549,9 +581,14 @@ struct ath6kl {
        unsigned int vif_max;
        u8 max_norm_iface;
        u8 avail_idx_map;
+
+       /*
+        * Protects at least amsdu_rx_buffer_queue, ath6kl_alloc_cookie()
+        * calls, tx_pending and total_tx_data_pend.
+        */
        spinlock_t lock;
+
        struct semaphore sem;
-       u16 listen_intvl_b;
        u8 lrssi_roam_threshold;
        struct ath6kl_version version;
        u32 target_type;
@@ -577,7 +614,13 @@ struct ath6kl {
        u8 sta_list_index;
        struct ath6kl_req_key ap_mode_bkey;
        struct sk_buff_head mcastpsq;
+
+       /*
+        * FIXME: protects access to mcastpsq but is actually useless as
+        * all skbe_queue_*() functions provide serialisation themselves
+        */
        spinlock_t mcastpsq_lock;
+
        u8 intra_bss;
        struct wmi_ap_mode_stat ap_stats;
        u8 ap_country_code[3];
@@ -620,6 +663,7 @@ struct ath6kl {
 
        u16 conf_flags;
        u16 suspend_mode;
+       u16 wow_suspend_mode;
        wait_queue_head_t event_wq;
        struct ath6kl_mbox_info mbox_info;
 
@@ -650,12 +694,16 @@ struct ath6kl {
 
        bool p2p;
 
+       bool wiphy_registered;
+
 #ifdef CONFIG_ATH6KL_DEBUG
        struct {
-               struct circ_buf fwlog_buf;
-               spinlock_t fwlog_lock;
-               void *fwlog_tmp;
+               struct sk_buff_head fwlog_queue;
+               struct completion fwlog_completion;
+               bool fwlog_open;
+
                u32 fwlog_mask;
+
                unsigned int dbgfs_diag_reg;
                u32 diag_reg_addr_wr;
                u32 diag_reg_val_wr;
@@ -727,10 +775,10 @@ struct htc_packet *ath6kl_alloc_amsdu_rxbuf(struct htc_target *target,
 void aggr_module_destroy(struct aggr_info *aggr_info);
 void aggr_reset_state(struct aggr_info_conn *aggr_conn);
 
-struct ath6kl_sta *ath6kl_find_sta(struct ath6kl_vif *vif, u8 * node_addr);
+struct ath6kl_sta *ath6kl_find_sta(struct ath6kl_vif *vif, u8 *node_addr);
 struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid);
 
-void ath6kl_ready_event(void *devt, u8 * datap, u32 sw_ver, u32 abi_ver);
+void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver);
 int ath6kl_control_tx(void *devt, struct sk_buff *skb,
                      enum htc_endpoint_id eid);
 void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel,
index d832058..552adb3 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -16,7 +17,7 @@
 
 #include "core.h"
 
-#include <linux/circ_buf.h>
+#include <linux/skbuff.h>
 #include <linux/fs.h>
 #include <linux/vmalloc.h>
 #include <linux/export.h>
@@ -32,9 +33,8 @@ struct ath6kl_fwlog_slot {
        u8 payload[0];
 };
 
-#define ATH6KL_FWLOG_SIZE 32768
-#define ATH6KL_FWLOG_SLOT_SIZE (sizeof(struct ath6kl_fwlog_slot) + \
-                               ATH6KL_FWLOG_PAYLOAD_SIZE)
+#define ATH6KL_FWLOG_MAX_ENTRIES 20
+
 #define ATH6KL_FWLOG_VALID_MASK 0x1ffff
 
 int ath6kl_printk(const char *level, const char *fmt, ...)
@@ -119,29 +119,29 @@ void ath6kl_dump_registers(struct ath6kl_device *dev,
 
        if (irq_proc_reg != NULL) {
                ath6kl_dbg(ATH6KL_DBG_IRQ,
-                       "Host Int status:           0x%x\n",
-                       irq_proc_reg->host_int_status);
+                          "Host Int status:           0x%x\n",
+                          irq_proc_reg->host_int_status);
                ath6kl_dbg(ATH6KL_DBG_IRQ,
                           "CPU Int status:            0x%x\n",
-                       irq_proc_reg->cpu_int_status);
+                          irq_proc_reg->cpu_int_status);
                ath6kl_dbg(ATH6KL_DBG_IRQ,
                           "Error Int status:          0x%x\n",
-                       irq_proc_reg->error_int_status);
+                          irq_proc_reg->error_int_status);
                ath6kl_dbg(ATH6KL_DBG_IRQ,
                           "Counter Int status:        0x%x\n",
-                       irq_proc_reg->counter_int_status);
+                          irq_proc_reg->counter_int_status);
                ath6kl_dbg(ATH6KL_DBG_IRQ,
                           "Mbox Frame:                0x%x\n",
-                       irq_proc_reg->mbox_frame);
+                          irq_proc_reg->mbox_frame);
                ath6kl_dbg(ATH6KL_DBG_IRQ,
                           "Rx Lookahead Valid:        0x%x\n",
-                       irq_proc_reg->rx_lkahd_valid);
+                          irq_proc_reg->rx_lkahd_valid);
                ath6kl_dbg(ATH6KL_DBG_IRQ,
                           "Rx Lookahead 0:            0x%x\n",
-                       irq_proc_reg->rx_lkahd[0]);
+                          irq_proc_reg->rx_lkahd[0]);
                ath6kl_dbg(ATH6KL_DBG_IRQ,
                           "Rx Lookahead 1:            0x%x\n",
-                       irq_proc_reg->rx_lkahd[1]);
+                          irq_proc_reg->rx_lkahd[1]);
 
                if (dev->ar->mbox_info.gmbox_addr != 0) {
                        /*
@@ -149,27 +149,27 @@ void ath6kl_dump_registers(struct ath6kl_device *dev,
                         * additional state.
                         */
                        ath6kl_dbg(ATH6KL_DBG_IRQ,
-                               "GMBOX Host Int status 2:   0x%x\n",
-                               irq_proc_reg->host_int_status2);
+                                  "GMBOX Host Int status 2:   0x%x\n",
+                                  irq_proc_reg->host_int_status2);
                        ath6kl_dbg(ATH6KL_DBG_IRQ,
-                               "GMBOX RX Avail:            0x%x\n",
-                               irq_proc_reg->gmbox_rx_avail);
+                                  "GMBOX RX Avail:            0x%x\n",
+                                  irq_proc_reg->gmbox_rx_avail);
                        ath6kl_dbg(ATH6KL_DBG_IRQ,
-                               "GMBOX lookahead alias 0:   0x%x\n",
-                               irq_proc_reg->rx_gmbox_lkahd_alias[0]);
+                                  "GMBOX lookahead alias 0:   0x%x\n",
+                                  irq_proc_reg->rx_gmbox_lkahd_alias[0]);
                        ath6kl_dbg(ATH6KL_DBG_IRQ,
-                               "GMBOX lookahead alias 1:   0x%x\n",
-                               irq_proc_reg->rx_gmbox_lkahd_alias[1]);
+                                  "GMBOX lookahead alias 1:   0x%x\n",
+                                  irq_proc_reg->rx_gmbox_lkahd_alias[1]);
                }
 
        }
 
        if (irq_enable_reg != NULL) {
                ath6kl_dbg(ATH6KL_DBG_IRQ,
-                       "Int status Enable:         0x%x\n",
-                       irq_enable_reg->int_status_en);
+                          "Int status Enable:         0x%x\n",
+                          irq_enable_reg->int_status_en);
                ath6kl_dbg(ATH6KL_DBG_IRQ, "Counter Int status Enable: 0x%x\n",
-                       irq_enable_reg->cntr_int_status_en);
+                          irq_enable_reg->cntr_int_status_en);
        }
        ath6kl_dbg(ATH6KL_DBG_IRQ, "<------------------------------->\n");
 }
@@ -268,105 +268,103 @@ static const struct file_operations fops_war_stats = {
        .llseek = default_llseek,
 };
 
-static void ath6kl_debug_fwlog_add(struct ath6kl *ar, const void *buf,
-                                  size_t buf_len)
+void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len)
 {
-       struct circ_buf *fwlog = &ar->debug.fwlog_buf;
-       size_t space;
-       int i;
+       struct ath6kl_fwlog_slot *slot;
+       struct sk_buff *skb;
+       size_t slot_len;
 
-       /* entries must all be equal size */
-       if (WARN_ON(buf_len != ATH6KL_FWLOG_SLOT_SIZE))
+       if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE))
                return;
 
-       space = CIRC_SPACE(fwlog->head, fwlog->tail, ATH6KL_FWLOG_SIZE);
-       if (space < buf_len)
-               /* discard oldest slot */
-               fwlog->tail = (fwlog->tail + ATH6KL_FWLOG_SLOT_SIZE) &
-                       (ATH6KL_FWLOG_SIZE - 1);
+       slot_len = sizeof(*slot) + ATH6KL_FWLOG_PAYLOAD_SIZE;
 
-       for (i = 0; i < buf_len; i += space) {
-               space = CIRC_SPACE_TO_END(fwlog->head, fwlog->tail,
-                                         ATH6KL_FWLOG_SIZE);
+       skb = alloc_skb(slot_len, GFP_KERNEL);
+       if (!skb)
+               return;
 
-               if ((size_t) space > buf_len - i)
-                       space = buf_len - i;
+       slot = (struct ath6kl_fwlog_slot *) skb_put(skb, slot_len);
+       slot->timestamp = cpu_to_le32(jiffies);
+       slot->length = cpu_to_le32(len);
+       memcpy(slot->payload, buf, len);
 
-               memcpy(&fwlog->buf[fwlog->head], buf, space);
-               fwlog->head = (fwlog->head + space) & (ATH6KL_FWLOG_SIZE - 1);
-       }
+       /* Need to pad each record to fixed length ATH6KL_FWLOG_PAYLOAD_SIZE */
+       memset(slot->payload + len, 0, ATH6KL_FWLOG_PAYLOAD_SIZE - len);
 
-}
+       spin_lock(&ar->debug.fwlog_queue.lock);
 
-void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len)
-{
-       struct ath6kl_fwlog_slot *slot = ar->debug.fwlog_tmp;
-       size_t slot_len;
+       __skb_queue_tail(&ar->debug.fwlog_queue, skb);
+       complete(&ar->debug.fwlog_completion);
 
-       if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE))
-               return;
+       /* drop oldest entries */
+       while (skb_queue_len(&ar->debug.fwlog_queue) >
+              ATH6KL_FWLOG_MAX_ENTRIES) {
+               skb = __skb_dequeue(&ar->debug.fwlog_queue);
+               kfree_skb(skb);
+       }
 
-       spin_lock_bh(&ar->debug.fwlog_lock);
+       spin_unlock(&ar->debug.fwlog_queue.lock);
 
-       slot->timestamp = cpu_to_le32(jiffies);
-       slot->length = cpu_to_le32(len);
-       memcpy(slot->payload, buf, len);
+       return;
+}
 
-       slot_len = sizeof(*slot) + len;
+static int ath6kl_fwlog_open(struct inode *inode, struct file *file)
+{
+       struct ath6kl *ar = inode->i_private;
 
-       if (slot_len < ATH6KL_FWLOG_SLOT_SIZE)
-               memset(slot->payload + len, 0,
-                      ATH6KL_FWLOG_SLOT_SIZE - slot_len);
+       if (ar->debug.fwlog_open)
+               return -EBUSY;
 
-       ath6kl_debug_fwlog_add(ar, slot, ATH6KL_FWLOG_SLOT_SIZE);
+       ar->debug.fwlog_open = true;
 
-       spin_unlock_bh(&ar->debug.fwlog_lock);
+       file->private_data = inode->i_private;
+       return 0;
 }
 
-static bool ath6kl_debug_fwlog_empty(struct ath6kl *ar)
+static int ath6kl_fwlog_release(struct inode *inode, struct file *file)
 {
-       return CIRC_CNT(ar->debug.fwlog_buf.head,
-                       ar->debug.fwlog_buf.tail,
-                       ATH6KL_FWLOG_SLOT_SIZE) == 0;
+       struct ath6kl *ar = inode->i_private;
+
+       ar->debug.fwlog_open = false;
+
+       return 0;
 }
 
 static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf,
                                 size_t count, loff_t *ppos)
 {
        struct ath6kl *ar = file->private_data;
-       struct circ_buf *fwlog = &ar->debug.fwlog_buf;
-       size_t len = 0, buf_len = count;
+       struct sk_buff *skb;
        ssize_t ret_cnt;
+       size_t len = 0;
        char *buf;
-       int ccnt;
 
-       buf = vmalloc(buf_len);
+       buf = vmalloc(count);
        if (!buf)
                return -ENOMEM;
 
        /* read undelivered logs from firmware */
        ath6kl_read_fwlogs(ar);
 
-       spin_lock_bh(&ar->debug.fwlog_lock);
+       spin_lock(&ar->debug.fwlog_queue.lock);
 
-       while (len < buf_len && !ath6kl_debug_fwlog_empty(ar)) {
-               ccnt = CIRC_CNT_TO_END(fwlog->head, fwlog->tail,
-                                      ATH6KL_FWLOG_SIZE);
+       while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) {
+               if (skb->len > count - len) {
+                       /* not enough space, put skb back and leave */
+                       __skb_queue_head(&ar->debug.fwlog_queue, skb);
+                       break;
+               }
 
-               if ((size_t) ccnt > buf_len - len)
-                       ccnt = buf_len - len;
 
-               memcpy(buf + len, &fwlog->buf[fwlog->tail], ccnt);
-               len += ccnt;
+               memcpy(buf + len, skb->data, skb->len);
+               len += skb->len;
 
-               fwlog->tail = (fwlog->tail + ccnt) &
-                       (ATH6KL_FWLOG_SIZE - 1);
+               kfree_skb(skb);
        }
 
-       spin_unlock_bh(&ar->debug.fwlog_lock);
+       spin_unlock(&ar->debug.fwlog_queue.lock);
 
-       if (WARN_ON(len > buf_len))
-               len = buf_len;
+       /* FIXME: what to do if len == 0? */
 
        ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
 
@@ -376,12 +374,87 @@ static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf,
 }
 
 static const struct file_operations fops_fwlog = {
-       .open = ath6kl_debugfs_open,
+       .open = ath6kl_fwlog_open,
+       .release = ath6kl_fwlog_release,
        .read = ath6kl_fwlog_read,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
 };
 
+static ssize_t ath6kl_fwlog_block_read(struct file *file,
+                                      char __user *user_buf,
+                                      size_t count,
+                                      loff_t *ppos)
+{
+       struct ath6kl *ar = file->private_data;
+       struct sk_buff *skb;
+       ssize_t ret_cnt;
+       size_t len = 0, not_copied;
+       char *buf;
+       int ret;
+
+       buf = vmalloc(count);
+       if (!buf)
+               return -ENOMEM;
+
+       spin_lock(&ar->debug.fwlog_queue.lock);
+
+       if (skb_queue_len(&ar->debug.fwlog_queue) == 0) {
+               /* we must init under queue lock */
+               init_completion(&ar->debug.fwlog_completion);
+
+               spin_unlock(&ar->debug.fwlog_queue.lock);
+
+               ret = wait_for_completion_interruptible(
+                       &ar->debug.fwlog_completion);
+               if (ret == -ERESTARTSYS)
+                       return ret;
+
+               spin_lock(&ar->debug.fwlog_queue.lock);
+       }
+
+       while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) {
+               if (skb->len > count - len) {
+                       /* not enough space, put skb back and leave */
+                       __skb_queue_head(&ar->debug.fwlog_queue, skb);
+                       break;
+               }
+
+
+               memcpy(buf + len, skb->data, skb->len);
+               len += skb->len;
+
+               kfree_skb(skb);
+       }
+
+       spin_unlock(&ar->debug.fwlog_queue.lock);
+
+       /* FIXME: what to do if len == 0? */
+
+       not_copied = copy_to_user(user_buf, buf, len);
+       if (not_copied != 0) {
+               ret_cnt = -EFAULT;
+               goto out;
+       }
+
+       *ppos = *ppos + len;
+
+       ret_cnt = len;
+
+out:
+       vfree(buf);
+
+       return ret_cnt;
+}
+
+static const struct file_operations fops_fwlog_block = {
+       .open = ath6kl_fwlog_open,
+       .release = ath6kl_fwlog_release,
+       .read = ath6kl_fwlog_block_read,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
 static ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf,
                                      size_t count, loff_t *ppos)
 {
@@ -667,9 +740,13 @@ static ssize_t ath6kl_endpoint_stats_read(struct file *file,
                return -ENOMEM;
 
 #define EPSTAT(name)                                                   \
-       len = print_endpoint_stat(target, buf, buf_len, len,            \
-                                 offsetof(struct htc_endpoint_stats, name), \
-                                 #name)
+       do {                                                            \
+               len = print_endpoint_stat(target, buf, buf_len, len,    \
+                                         offsetof(struct htc_endpoint_stats, \
+                                                  name),               \
+                                         #name);                       \
+       } while (0)
+
        EPSTAT(cred_low_indicate);
        EPSTAT(tx_issued);
        EPSTAT(tx_pkt_bundled);
@@ -779,17 +856,9 @@ static ssize_t ath6kl_regread_write(struct file *file,
                                    size_t count, loff_t *ppos)
 {
        struct ath6kl *ar = file->private_data;
-       u8 buf[50];
-       unsigned int len;
        unsigned long reg_addr;
 
-       len = min(count, sizeof(buf) - 1);
-       if (copy_from_user(buf, user_buf, len))
-               return -EFAULT;
-
-       buf[len] = '\0';
-
-       if (strict_strtoul(buf, 0, &reg_addr))
+       if (kstrtoul_from_user(user_buf, count, 0, &reg_addr))
                return -EINVAL;
 
        if ((reg_addr % 4) != 0)
@@ -903,15 +972,8 @@ static ssize_t ath6kl_lrssi_roam_write(struct file *file,
 {
        struct ath6kl *ar = file->private_data;
        unsigned long lrssi_roam_threshold;
-       char buf[32];
-       ssize_t len;
 
-       len = min(count, sizeof(buf) - 1);
-       if (copy_from_user(buf, user_buf, len))
-               return -EFAULT;
-
-       buf[len] = '\0';
-       if (strict_strtoul(buf, 0, &lrssi_roam_threshold))
+       if (kstrtoul_from_user(user_buf, count, 0, &lrssi_roam_threshold))
                return -EINVAL;
 
        ar->lrssi_roam_threshold = lrssi_roam_threshold;
@@ -1558,12 +1620,12 @@ static ssize_t ath6kl_listen_int_write(struct file *file,
        if (kstrtou16(buf, 0, &listen_interval))
                return -EINVAL;
 
-       if ((listen_interval < 1) || (listen_interval > 50))
+       if ((listen_interval < 15) || (listen_interval > 3000))
                return -EINVAL;
 
-       ar->listen_intvl_b = listen_interval;
-       ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, 0,
-                                     ar->listen_intvl_b);
+       vif->listen_intvl_t = listen_interval;
+       ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
+                                     vif->listen_intvl_t, 0);
 
        return count;
 }
@@ -1573,10 +1635,15 @@ static ssize_t ath6kl_listen_int_read(struct file *file,
                                      size_t count, loff_t *ppos)
 {
        struct ath6kl *ar = file->private_data;
+       struct ath6kl_vif *vif;
        char buf[32];
        int len;
 
-       len = scnprintf(buf, sizeof(buf), "%u\n", ar->listen_intvl_b);
+       vif = ath6kl_vif_first(ar);
+       if (!vif)
+               return -EIO;
+
+       len = scnprintf(buf, sizeof(buf), "%u\n", vif->listen_intvl_t);
 
        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
@@ -1649,33 +1716,29 @@ static const struct file_operations fops_power_params = {
        .llseek = default_llseek,
 };
 
-int ath6kl_debug_init(struct ath6kl *ar)
+void ath6kl_debug_init(struct ath6kl *ar)
 {
-       ar->debug.fwlog_buf.buf = vmalloc(ATH6KL_FWLOG_SIZE);
-       if (ar->debug.fwlog_buf.buf == NULL)
-               return -ENOMEM;
-
-       ar->debug.fwlog_tmp = kmalloc(ATH6KL_FWLOG_SLOT_SIZE, GFP_KERNEL);
-       if (ar->debug.fwlog_tmp == NULL) {
-               vfree(ar->debug.fwlog_buf.buf);
-               return -ENOMEM;
-       }
-
-       spin_lock_init(&ar->debug.fwlog_lock);
+       skb_queue_head_init(&ar->debug.fwlog_queue);
+       init_completion(&ar->debug.fwlog_completion);
 
        /*
         * Actually we are lying here but don't know how to read the mask
         * value from the firmware.
         */
        ar->debug.fwlog_mask = 0;
+}
 
+/*
+ * Initialisation needs to happen in two stages as fwlog events can come
+ * before cfg80211 is initialised, and debugfs depends on cfg80211
+ * initialisation.
+ */
+int ath6kl_debug_init_fs(struct ath6kl *ar)
+{
        ar->debugfs_phy = debugfs_create_dir("ath6kl",
                                             ar->wiphy->debugfsdir);
-       if (!ar->debugfs_phy) {
-               vfree(ar->debug.fwlog_buf.buf);
-               kfree(ar->debug.fwlog_tmp);
+       if (!ar->debugfs_phy)
                return -ENOMEM;
-       }
 
        debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar,
                            &fops_tgt_stats);
@@ -1689,6 +1752,9 @@ int ath6kl_debug_init(struct ath6kl *ar)
        debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar,
                            &fops_fwlog);
 
+       debugfs_create_file("fwlog_block", S_IRUSR, ar->debugfs_phy, ar,
+                           &fops_fwlog_block);
+
        debugfs_create_file("fwlog_mask", S_IRUSR | S_IWUSR, ar->debugfs_phy,
                            ar, &fops_fwlog_mask);
 
@@ -1723,27 +1789,26 @@ int ath6kl_debug_init(struct ath6kl *ar)
                            ar->debugfs_phy, ar, &fops_disconnect_timeout);
 
        debugfs_create_file("create_qos", S_IWUSR, ar->debugfs_phy, ar,
-                               &fops_create_qos);
+                           &fops_create_qos);
 
        debugfs_create_file("delete_qos", S_IWUSR, ar->debugfs_phy, ar,
-                               &fops_delete_qos);
+                           &fops_delete_qos);
 
        debugfs_create_file("bgscan_interval", S_IWUSR,
-                               ar->debugfs_phy, ar, &fops_bgscan_int);
+                           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);
+                           &fops_power_params);
 
        return 0;
 }
 
 void ath6kl_debug_cleanup(struct ath6kl *ar)
 {
-       vfree(ar->debug.fwlog_buf.buf);
-       kfree(ar->debug.fwlog_tmp);
+       skb_queue_purge(&ar->debug.fwlog_queue);
        kfree(ar->debug.roam_tbl);
 }
 
index c4be6e5..1803a0b 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -77,7 +78,8 @@ int ath6kl_debug_roam_tbl_event(struct ath6kl *ar, const void *buf,
                                size_t len);
 void ath6kl_debug_set_keepalive(struct ath6kl *ar, u8 keepalive);
 void ath6kl_debug_set_disconnect_timeout(struct ath6kl *ar, u8 timeout);
-int ath6kl_debug_init(struct ath6kl *ar);
+void ath6kl_debug_init(struct ath6kl *ar);
+int ath6kl_debug_init_fs(struct ath6kl *ar);
 void ath6kl_debug_cleanup(struct ath6kl *ar);
 
 #else
@@ -127,7 +129,11 @@ static inline void ath6kl_debug_set_disconnect_timeout(struct ath6kl *ar,
 {
 }
 
-static inline int ath6kl_debug_init(struct ath6kl *ar)
+static inline void ath6kl_debug_init(struct ath6kl *ar)
+{
+}
+
+static inline int ath6kl_debug_init_fs(struct ath6kl *ar)
 {
        return 0;
 }
index 2fe1dad..fd84086 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004-2011 Atheros Communications Inc.
+ * Copyright (c) 2011 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index e911737..68ed6c2 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2007-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -89,7 +90,7 @@ static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar)
        }
 
        ath6kl_dbg(ATH6KL_DBG_IRQ, "register dump data address 0x%x\n",
-               regdump_addr);
+                  regdump_addr);
        regdump_addr = TARG_VTOP(ar->target_type, regdump_addr);
 
        /* fetch register dump data */
@@ -106,9 +107,9 @@ static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar)
 
        BUILD_BUG_ON(REG_DUMP_COUNT_AR6003 % 4);
 
-       for (i = 0; i < REG_DUMP_COUNT_AR6003 / 4; i++) {
+       for (i = 0; i < REG_DUMP_COUNT_AR6003; i += 4) {
                ath6kl_info("%d: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n",
-                           4 * i,
+                           i,
                            le32_to_cpu(regdump_val[i]),
                            le32_to_cpu(regdump_val[i + 1]),
                            le32_to_cpu(regdump_val[i + 2]),
@@ -134,6 +135,7 @@ static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev)
                ath6kl_warn("Failed to clear debug interrupt: %d\n", ret);
 
        ath6kl_hif_dump_fw_crash(dev->ar);
+       ath6kl_read_fwlogs(dev->ar);
 
        return ret;
 }
@@ -283,7 +285,7 @@ static int ath6kl_hif_proc_counter_intr(struct ath6kl_device *dev)
                             dev->irq_en_reg.cntr_int_status_en;
 
        ath6kl_dbg(ATH6KL_DBG_IRQ,
-               "valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n",
+                  "valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n",
                counter_int_status);
 
        /*
@@ -358,7 +360,7 @@ static int ath6kl_hif_proc_cpu_intr(struct ath6kl_device *dev)
        }
 
        ath6kl_dbg(ATH6KL_DBG_IRQ,
-               "valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n",
+                  "valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n",
                cpu_int_status);
 
        /* Clear the interrupt */
index 699a036..20ed6b7 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004-2011 Atheros Communications Inc.
+ * Copyright (c) 2011 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -197,6 +198,8 @@ struct hif_scatter_req {
        u8 *virt_dma_buf;
 
        struct hif_scatter_item scat_list[1];
+
+       u32 scat_q_depth;
 };
 
 struct ath6kl_irq_proc_registers {
@@ -220,6 +223,7 @@ struct ath6kl_irq_enable_reg {
 } __packed;
 
 struct ath6kl_device {
+       /* protects irq_proc_reg and irq_en_reg below */
        spinlock_t lock;
        struct ath6kl_irq_proc_registers irq_proc_reg;
        struct ath6kl_irq_enable_reg irq_en_reg;
index 2d72190..4849d99 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2007-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -22,6 +23,9 @@
 
 #define CALC_TXRX_PADDED_LEN(dev, len)  (__ALIGN_MASK((len), (dev)->block_mask))
 
+/* threshold to re-enable Tx bundling for an AC*/
+#define TX_RESUME_BUNDLE_THRESHOLD     1500
+
 /* Functions for Tx credit handling */
 static void ath6kl_credit_deposit(struct ath6kl_htc_credit_info *cred_info,
                                  struct htc_endpoint_credit_dist *ep_dist,
@@ -168,31 +172,29 @@ static void ath6kl_credit_reduce(struct ath6kl_htc_credit_info *cred_info,
 static void ath6kl_credit_update(struct ath6kl_htc_credit_info *cred_info,
                                 struct list_head *epdist_list)
 {
-       struct htc_endpoint_credit_dist *cur_dist_list;
+       struct htc_endpoint_credit_dist *cur_list;
 
-       list_for_each_entry(cur_dist_list, epdist_list, list) {
-               if (cur_dist_list->endpoint == ENDPOINT_0)
+       list_for_each_entry(cur_list, epdist_list, list) {
+               if (cur_list->endpoint == ENDPOINT_0)
                        continue;
 
-               if (cur_dist_list->cred_to_dist > 0) {
-                       cur_dist_list->credits +=
-                                       cur_dist_list->cred_to_dist;
-                       cur_dist_list->cred_to_dist = 0;
-                       if (cur_dist_list->credits >
-                           cur_dist_list->cred_assngd)
+               if (cur_list->cred_to_dist > 0) {
+                       cur_list->credits += cur_list->cred_to_dist;
+                       cur_list->cred_to_dist = 0;
+
+                       if (cur_list->credits > cur_list->cred_assngd)
                                ath6kl_credit_reduce(cred_info,
-                                               cur_dist_list,
-                                               cur_dist_list->cred_assngd);
+                                                    cur_list,
+                                                    cur_list->cred_assngd);
 
-                       if (cur_dist_list->credits >
-                           cur_dist_list->cred_norm)
-                               ath6kl_credit_reduce(cred_info, cur_dist_list,
-                                                    cur_dist_list->cred_norm);
+                       if (cur_list->credits > cur_list->cred_norm)
+                               ath6kl_credit_reduce(cred_info, cur_list,
+                                                    cur_list->cred_norm);
 
-                       if (!(cur_dist_list->dist_flags & HTC_EP_ACTIVE)) {
-                               if (cur_dist_list->txq_depth == 0)
+                       if (!(cur_list->dist_flags & HTC_EP_ACTIVE)) {
+                               if (cur_list->txq_depth == 0)
                                        ath6kl_credit_reduce(cred_info,
-                                                            cur_dist_list, 0);
+                                                            cur_list, 0);
                        }
                }
        }
@@ -460,8 +462,8 @@ static void htc_async_tx_scat_complete(struct htc_target *target,
        INIT_LIST_HEAD(&tx_compq);
 
        ath6kl_dbg(ATH6KL_DBG_HTC,
-               "htc tx scat complete len %d entries %d\n",
-               scat_req->len, scat_req->scat_entries);
+                  "htc tx scat complete len %d entries %d\n",
+                  scat_req->len, scat_req->scat_entries);
 
        if (scat_req->status)
                ath6kl_err("send scatter req failed: %d\n", scat_req->status);
@@ -599,8 +601,8 @@ static void ath6kl_htc_tx_pkts_get(struct htc_target *target,
                                          list);
 
                ath6kl_dbg(ATH6KL_DBG_HTC,
-                       "htc tx got packet 0x%p queue depth %d\n",
-                       packet, get_queue_depth(&endpoint->txq));
+                          "htc tx got packet 0x%p queue depth %d\n",
+                          packet, get_queue_depth(&endpoint->txq));
 
                len = CALC_TXRX_PADDED_LEN(target,
                                           packet->act_len + HTC_HDR_LENGTH);
@@ -670,6 +672,7 @@ static int ath6kl_htc_tx_setup_scat_list(struct htc_target *target,
        struct htc_packet *packet;
        int i, len, rem_scat, cred_pad;
        int status = 0;
+       u8 flags;
 
        rem_scat = target->max_tx_bndl_sz;
 
@@ -696,9 +699,9 @@ static int ath6kl_htc_tx_setup_scat_list(struct htc_target *target,
 
                scat_req->scat_list[i].packet = packet;
                /* prepare packet and flag message as part of a send bundle */
-               ath6kl_htc_tx_prep_pkt(packet,
-                               packet->info.tx.flags | HTC_FLAGS_SEND_BUNDLE,
-                               cred_pad, packet->info.tx.seqno);
+               flags = packet->info.tx.flags | HTC_FLAGS_SEND_BUNDLE;
+               ath6kl_htc_tx_prep_pkt(packet, flags,
+                                      cred_pad, packet->info.tx.seqno);
                /* Make sure the buffer is 4-byte aligned */
                ath6kl_htc_tx_buf_align(&packet->buf,
                                        packet->act_len + HTC_HDR_LENGTH);
@@ -744,6 +747,12 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint,
        struct hif_scatter_req *scat_req = NULL;
        int n_scat, n_sent_bundle = 0, tot_pkts_bundle = 0;
        int status;
+       u32 txb_mask;
+       u8 ac = WMM_NUM_AC;
+
+       if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) ||
+           (WMI_CONTROL_SVC != endpoint->svc_id))
+               ac = target->dev->ar->ep2ac_map[endpoint->eid];
 
        while (true) {
                status = 0;
@@ -759,10 +768,35 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint,
                if (!scat_req) {
                        /* no scatter resources  */
                        ath6kl_dbg(ATH6KL_DBG_HTC,
-                               "htc tx no more scatter resources\n");
+                                  "htc tx no more scatter resources\n");
                        break;
                }
 
+               if ((ac < WMM_NUM_AC) && (ac != WMM_AC_BK)) {
+                       if (WMM_AC_BE == ac)
+                               /*
+                                * BE, BK have priorities and bit
+                                * positions reversed
+                                */
+                               txb_mask = (1 << WMM_AC_BK);
+                       else
+                               /*
+                                * any AC with priority lower than
+                                * itself
+                                */
+                               txb_mask = ((1 << ac) - 1);
+               /*
+                * when the scatter request resources drop below a
+                * certain threshold, disable Tx bundling for all
+                * AC's with priority lower than the current requesting
+                * AC. Otherwise re-enable Tx bundling for them
+                */
+               if (scat_req->scat_q_depth < ATH6KL_SCATTER_REQS)
+                       target->tx_bndl_mask &= ~txb_mask;
+               else
+                       target->tx_bndl_mask |= txb_mask;
+               }
+
                ath6kl_dbg(ATH6KL_DBG_HTC, "htc tx pkts to scatter: %d\n",
                           n_scat);
 
@@ -806,6 +840,7 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target,
        struct htc_packet *packet;
        int bundle_sent;
        int n_pkts_bundle;
+       u8 ac = WMM_NUM_AC;
 
        spin_lock_bh(&target->tx_lock);
 
@@ -823,6 +858,10 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target,
         */
        INIT_LIST_HEAD(&txq);
 
+       if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) ||
+           (WMI_CONTROL_SVC != endpoint->svc_id))
+               ac = target->dev->ar->ep2ac_map[endpoint->eid];
+
        while (true) {
 
                if (list_empty(&endpoint->txq))
@@ -840,15 +879,18 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target,
 
                while (true) {
                        /* try to send a bundle on each pass */
-                       if ((target->tx_bndl_enable) &&
+                       if ((target->tx_bndl_mask) &&
                            (get_queue_depth(&txq) >=
                            HTC_MIN_HTC_MSGS_TO_BUNDLE)) {
                                int temp1 = 0, temp2 = 0;
 
-                               ath6kl_htc_tx_bundle(endpoint, &txq,
-                                                    &temp1, &temp2);
-                               bundle_sent += temp1;
-                               n_pkts_bundle += temp2;
+                               /* check if bundling is enabled for an AC */
+                               if (target->tx_bndl_mask & (1 << ac)) {
+                                       ath6kl_htc_tx_bundle(endpoint, &txq,
+                                                            &temp1, &temp2);
+                                       bundle_sent += temp1;
+                                       n_pkts_bundle += temp2;
+                               }
                        }
 
                        if (list_empty(&txq))
@@ -867,6 +909,26 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target,
 
                endpoint->ep_st.tx_bundles += bundle_sent;
                endpoint->ep_st.tx_pkt_bundled += n_pkts_bundle;
+
+               /*
+                * if an AC has bundling disabled and no tx bundling
+                * has occured continously for a certain number of TX,
+                * enable tx bundling for this AC
+                */
+               if (!bundle_sent) {
+                       if (!(target->tx_bndl_mask & (1 << ac)) &&
+                           (ac < WMM_NUM_AC)) {
+                               if (++target->ac_tx_count[ac] >=
+                                       TX_RESUME_BUNDLE_THRESHOLD) {
+                                       target->ac_tx_count[ac] = 0;
+                                       target->tx_bndl_mask |= (1 << ac);
+                               }
+                       }
+               } else {
+                       /* tx bundling will reset the counter */
+                       if (ac < WMM_NUM_AC)
+                               target->ac_tx_count[ac] = 0;
+               }
        }
 
        endpoint->tx_proc_cnt = 0;
@@ -979,8 +1041,8 @@ static int htc_setup_tx_complete(struct htc_target *target)
                memcpy(&setup_comp_ext->flags, &flags,
                       sizeof(setup_comp_ext->flags));
                set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp_ext,
-                                      sizeof(struct htc_setup_comp_ext_msg),
-                                      ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG);
+                                sizeof(struct htc_setup_comp_ext_msg),
+                                ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG);
 
        } else {
                struct htc_setup_comp_msg *setup_comp;
@@ -988,8 +1050,8 @@ static int htc_setup_tx_complete(struct htc_target *target)
                memset(setup_comp, 0, sizeof(struct htc_setup_comp_msg));
                setup_comp->msg_id = cpu_to_le16(HTC_MSG_SETUP_COMPLETE_ID);
                set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp,
-                                      sizeof(struct htc_setup_comp_msg),
-                                      ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG);
+                                sizeof(struct htc_setup_comp_msg),
+                                ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG);
        }
 
        /* we want synchronous operation */
@@ -1088,9 +1150,9 @@ void ath6kl_htc_flush_txep(struct htc_target *target,
                packet->status = -ECANCELED;
                list_del(&packet->list);
                ath6kl_dbg(ATH6KL_DBG_HTC,
-                       "htc tx flushing pkt 0x%p len %d  ep %d tag 0x%x\n",
-                       packet, packet->act_len,
-                       packet->endpoint, packet->info.tx.tag);
+                          "htc tx flushing pkt 0x%p len %d  ep %d tag 0x%x\n",
+                          packet, packet->act_len,
+                          packet->endpoint, packet->info.tx.tag);
 
                INIT_LIST_HEAD(&container);
                list_add_tail(&packet->list, &container);
@@ -1490,7 +1552,7 @@ static void htc_ctrl_rx(struct htc_target *context, struct htc_packet *packets)
 
        if (packets->act_len > 0) {
                ath6kl_err("htc_ctrl_rx, got message with len:%zu\n",
-                       packets->act_len + HTC_HDR_LENGTH);
+                          packets->act_len + HTC_HDR_LENGTH);
 
                ath6kl_dbg_dump(ATH6KL_DBG_HTC,
                                "htc rx unexpected endpoint 0 message", "",
@@ -1609,8 +1671,8 @@ static int htc_parse_trailer(struct htc_target *target,
                }
 
                lk_ahd = (struct htc_lookahead_report *) record_buf;
-               if ((lk_ahd->pre_valid == ((~lk_ahd->post_valid) & 0xFF))
-                   && next_lk_ahds) {
+               if ((lk_ahd->pre_valid == ((~lk_ahd->post_valid) & 0xFF)) &&
+                   next_lk_ahds) {
 
                        ath6kl_dbg(ATH6KL_DBG_HTC,
                                   "htc rx lk_ahd found pre_valid 0x%x post_valid 0x%x\n",
@@ -2038,13 +2100,13 @@ fail_rx:
        list_for_each_entry_safe(packet, tmp_pkt, rx_pktq, list) {
                list_del(&packet->list);
                htc_reclaim_rxbuf(target, packet,
-                               &target->endpoint[packet->endpoint]);
+                                 &target->endpoint[packet->endpoint]);
        }
 
        list_for_each_entry_safe(packet, tmp_pkt, &tmp_rxq, list) {
                list_del(&packet->list);
                htc_reclaim_rxbuf(target, packet,
-                               &target->endpoint[packet->endpoint]);
+                                 &target->endpoint[packet->endpoint]);
        }
 
        return status;
@@ -2176,11 +2238,11 @@ static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target)
        u32 look_ahead;
 
        if (ath6kl_hif_poll_mboxmsg_rx(target->dev, &look_ahead,
-                              HTC_TARGET_RESPONSE_TIMEOUT))
+                                      HTC_TARGET_RESPONSE_TIMEOUT))
                return NULL;
 
        ath6kl_dbg(ATH6KL_DBG_HTC,
-               "htc rx wait ctrl look_ahead 0x%X\n", look_ahead);
+                  "htc rx wait ctrl look_ahead 0x%X\n", look_ahead);
 
        htc_hdr = (struct htc_frame_hdr *)&look_ahead;
 
@@ -2245,7 +2307,7 @@ int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target,
        depth = get_queue_depth(pkt_queue);
 
        ath6kl_dbg(ATH6KL_DBG_HTC,
-               "htc rx add multiple ep id %d cnt %d len %d\n",
+                  "htc rx add multiple ep id %d cnt %d len %d\n",
                first_pkt->endpoint, depth, first_pkt->buf_len);
 
        endpoint = &target->endpoint[first_pkt->endpoint];
@@ -2271,8 +2333,8 @@ int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target,
        if (target->rx_st_flags & HTC_RECV_WAIT_BUFFERS) {
                if (target->ep_waiting == first_pkt->endpoint) {
                        ath6kl_dbg(ATH6KL_DBG_HTC,
-                               "htc rx blocked on ep %d, unblocking\n",
-                               target->ep_waiting);
+                                  "htc rx blocked on ep %d, unblocking\n",
+                                  target->ep_waiting);
                        target->rx_st_flags &= ~HTC_RECV_WAIT_BUFFERS;
                        target->ep_waiting = ENDPOINT_MAX;
                        rx_unblock = true;
@@ -2309,7 +2371,21 @@ void ath6kl_htc_flush_rx_buf(struct htc_target *target)
                                   "htc rx flush pkt 0x%p  len %d  ep %d\n",
                                   packet, packet->buf_len,
                                   packet->endpoint);
-                       dev_kfree_skb(packet->pkt_cntxt);
+                       /*
+                        * packets in rx_bufq of endpoint 0 have originally
+                        * been queued from target->free_ctrl_rxbuf where
+                        * packet and packet->buf_start are allocated
+                        * separately using kmalloc(). For other endpoint
+                        * rx_bufq, it is allocated as skb where packet is
+                        * skb->head. Take care of this difference while freeing
+                        * the memory.
+                        */
+                       if (packet->endpoint == ENDPOINT_0) {
+                               kfree(packet->buf_start);
+                               kfree(packet);
+                       } else {
+                               dev_kfree_skb(packet->pkt_cntxt);
+                       }
                        spin_lock_bh(&target->rx_lock);
                }
                spin_unlock_bh(&target->rx_lock);
@@ -2328,6 +2404,7 @@ int ath6kl_htc_conn_service(struct htc_target *target,
        enum htc_endpoint_id assigned_ep = ENDPOINT_MAX;
        unsigned int max_msg_sz = 0;
        int status = 0;
+       u16 msg_id;
 
        ath6kl_dbg(ATH6KL_DBG_HTC,
                   "htc connect service target 0x%p service id 0x%x\n",
@@ -2371,9 +2448,10 @@ int ath6kl_htc_conn_service(struct htc_target *target,
                }
 
                resp_msg = (struct htc_conn_service_resp *)rx_pkt->buf;
+               msg_id = le16_to_cpu(resp_msg->msg_id);
 
-               if ((le16_to_cpu(resp_msg->msg_id) != HTC_MSG_CONN_SVC_RESP_ID)
-                   || (rx_pkt->act_len < sizeof(*resp_msg))) {
+               if ((msg_id != HTC_MSG_CONN_SVC_RESP_ID) ||
+                   (rx_pkt->act_len < sizeof(*resp_msg))) {
                        status = -ENOMEM;
                        goto fail_tx;
                }
@@ -2420,6 +2498,15 @@ int ath6kl_htc_conn_service(struct htc_target *target,
        endpoint->cred_dist.endpoint = assigned_ep;
        endpoint->cred_dist.cred_sz = target->tgt_cred_sz;
 
+       switch (endpoint->svc_id) {
+       case WMI_DATA_BK_SVC:
+               endpoint->tx_drop_packet_threshold = MAX_DEF_COOKIE_NUM / 3;
+               break;
+       default:
+               endpoint->tx_drop_packet_threshold = MAX_HI_COOKIE_NUM;
+               break;
+       }
+
        if (conn_req->max_rxmsg_sz) {
                /*
                 * Override cred_per_msg calculation, this optimizes
@@ -2517,7 +2604,8 @@ static void htc_setup_msg_bndl(struct htc_target *target)
                   target->max_rx_bndl_sz, target->max_tx_bndl_sz);
 
        if (target->max_tx_bndl_sz)
-               target->tx_bndl_enable = true;
+               /* tx_bndl_mask is enabled per AC, each has 1 bit */
+               target->tx_bndl_mask = (1 << WMM_NUM_AC) - 1;
 
        if (target->max_rx_bndl_sz)
                target->rx_bndl_enable = true;
@@ -2532,7 +2620,7 @@ static void htc_setup_msg_bndl(struct htc_target *target)
                 * padding will spill into the next credit buffer
                 * which is fatal.
                 */
-               target->tx_bndl_enable = false;
+               target->tx_bndl_mask = 0;
        }
 }
 
@@ -2589,8 +2677,8 @@ int ath6kl_htc_wait_target(struct htc_target *target)
        }
 
        ath6kl_dbg(ATH6KL_DBG_BOOT, "htc using protocol %s (%d)\n",
-                 (target->htc_tgt_ver == HTC_VERSION_2P0) ? "2.0" : ">= 2.1",
-                 target->htc_tgt_ver);
+                  (target->htc_tgt_ver == HTC_VERSION_2P0) ? "2.0" : ">= 2.1",
+                  target->htc_tgt_ver);
 
        if (target->msg_per_bndl_max > 0)
                htc_setup_msg_bndl(target);
@@ -2784,14 +2872,14 @@ void ath6kl_htc_cleanup(struct htc_target *target)
                ath6kl_hif_cleanup_scatter(target->dev->ar);
 
        list_for_each_entry_safe(packet, tmp_packet,
-                       &target->free_ctrl_txbuf, list) {
+                                &target->free_ctrl_txbuf, list) {
                list_del(&packet->list);
                kfree(packet->buf_start);
                kfree(packet);
        }
 
        list_for_each_entry_safe(packet, tmp_packet,
-                       &target->free_ctrl_rxbuf, list) {
+                                &target->free_ctrl_rxbuf, list) {
                list_del(&packet->list);
                kfree(packet->buf_start);
                kfree(packet);
index 57672e1..5027ccc 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004-2011 Atheros Communications Inc.
+ * Copyright (c) 2011 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -87,6 +88,8 @@
 #define WMI_DATA_VO_SVC   MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 4)
 #define WMI_MAX_SERVICES  5
 
+#define WMM_NUM_AC  4
+
 /* reserved and used to flush ALL packets */
 #define HTC_TX_PACKET_TAG_ALL          0
 #define HTC_SERVICE_TX_PACKET_TAG      1
@@ -498,6 +501,7 @@ struct htc_endpoint {
        u8 seqno;
        u32 conn_flags;
        struct htc_endpoint_stats ep_st;
+       u16 tx_drop_packet_threshold;
 };
 
 struct htc_control_buffer {
@@ -519,9 +523,16 @@ struct htc_target {
        struct ath6kl_htc_credit_info *credit_info;
        int tgt_creds;
        unsigned int tgt_cred_sz;
+
+       /* protects free_ctrl_txbuf and free_ctrl_rxbuf */
        spinlock_t htc_lock;
+
+       /* FIXME: does this protext rx_bufq and endpoint structures or what? */
        spinlock_t rx_lock;
+
+       /* protects endpoint->txq */
        spinlock_t tx_lock;
+
        struct ath6kl_device *dev;
        u32 htc_flags;
        u32 rx_st_flags;
@@ -531,7 +542,7 @@ struct htc_target {
        /* max messages per bundle for HTC */
        int msg_per_bndl_max;
 
-       bool tx_bndl_enable;
+       u32 tx_bndl_mask;
        int rx_bndl_enable;
        int max_rx_bndl_sz;
        int max_tx_bndl_sz;
@@ -543,6 +554,9 @@ struct htc_target {
        int max_xfer_szper_scatreq;
 
        int chk_irq_status_cnt;
+
+       /* counts the number of Tx without bundling continously per AC */
+       u32 ac_tx_count[WMM_NUM_AC];
 };
 
 void *ath6kl_htc_create(struct ath6kl *ar);
index 0d76c37..03cae14 100644 (file)
@@ -1,6 +1,7 @@
 
 /*
  * Copyright (c) 2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -74,7 +75,7 @@ static const struct ath6kl_hw hw_list[] = {
                },
 
                .fw_board               = AR6003_HW_2_1_1_BOARD_DATA_FILE,
-               .fw_default_board       = AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE,
+               .fw_default_board = AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE,
        },
        {
                .id                             = AR6004_HW_1_0_VERSION,
@@ -351,11 +352,7 @@ static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val,
                blk_size |=  ((u32)htc_ctrl_buf) << 16;
 
        /* set the host interest area for the block size */
-       status = ath6kl_bmi_write(ar,
-                       ath6kl_get_hi_item_addr(ar,
-                       HI_ITEM(hi_mbox_io_block_sz)),
-                       (u8 *)&blk_size,
-                       4);
+       status = ath6kl_bmi_write_hi32(ar, hi_mbox_io_block_sz, blk_size);
        if (status) {
                ath6kl_err("bmi_write_memory for IO block size failed\n");
                goto out;
@@ -367,11 +364,8 @@ static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val,
 
        if (mbox_isr_yield_val) {
                /* set the host interest area for the mbox ISR yield limit */
-               status = ath6kl_bmi_write(ar,
-                               ath6kl_get_hi_item_addr(ar,
-                               HI_ITEM(hi_mbox_isr_yield_limit)),
-                               (u8 *)&mbox_isr_yield_val,
-                               4);
+               status = ath6kl_bmi_write_hi32(ar, hi_mbox_isr_yield_limit,
+                                              mbox_isr_yield_val);
                if (status) {
                        ath6kl_err("bmi_write_memory for yield limit failed\n");
                        goto out;
@@ -384,7 +378,6 @@ out:
 
 static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx)
 {
-       int status = 0;
        int ret;
 
        /*
@@ -392,43 +385,54 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx)
         * default values. Required if checksum offload is needed. Set
         * RxMetaVersion to 2.
         */
-       if (ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi, idx,
-                                              ar->rx_meta_ver, 0, 0)) {
-               ath6kl_err("unable to set the rx frame format\n");
-               status = -EIO;
+       ret = ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi, idx,
+                                                ar->rx_meta_ver, 0, 0);
+       if (ret) {
+               ath6kl_err("unable to set the rx frame format: %d\n", ret);
+               return ret;
        }
 
-       if (ar->conf_flags & ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN)
-               if ((ath6kl_wmi_pmparams_cmd(ar->wmi, idx, 0, 1, 0, 0, 1,
-                    IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN)) != 0) {
-                       ath6kl_err("unable to set power save fail event policy\n");
-                       status = -EIO;
+       if (ar->conf_flags & ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN) {
+               ret = ath6kl_wmi_pmparams_cmd(ar->wmi, idx, 0, 1, 0, 0, 1,
+                                             IGNORE_PS_FAIL_DURING_SCAN);
+               if (ret) {
+                       ath6kl_err("unable to set power save fail event policy: %d\n",
+                                  ret);
+                       return ret;
                }
+       }
 
-       if (!(ar->conf_flags & ATH6KL_CONF_IGNORE_ERP_BARKER))
-               if ((ath6kl_wmi_set_lpreamble_cmd(ar->wmi, idx, 0,
-                    WMI_DONOT_IGNORE_BARKER_IN_ERP)) != 0) {
-                       ath6kl_err("unable to set barker preamble policy\n");
-                       status = -EIO;
+       if (!(ar->conf_flags & ATH6KL_CONF_IGNORE_ERP_BARKER)) {
+               ret = ath6kl_wmi_set_lpreamble_cmd(ar->wmi, idx, 0,
+                                                  WMI_FOLLOW_BARKER_IN_ERP);
+               if (ret) {
+                       ath6kl_err("unable to set barker preamble policy: %d\n",
+                                  ret);
+                       return ret;
                }
+       }
 
-       if (ath6kl_wmi_set_keepalive_cmd(ar->wmi, idx,
-                       WLAN_CONFIG_KEEP_ALIVE_INTERVAL)) {
-               ath6kl_err("unable to set keep alive interval\n");
-               status = -EIO;
+       ret = ath6kl_wmi_set_keepalive_cmd(ar->wmi, idx,
+                                          WLAN_CONFIG_KEEP_ALIVE_INTERVAL);
+       if (ret) {
+               ath6kl_err("unable to set keep alive interval: %d\n", ret);
+               return ret;
        }
 
-       if (ath6kl_wmi_disctimeout_cmd(ar->wmi, idx,
-                       WLAN_CONFIG_DISCONNECT_TIMEOUT)) {
-               ath6kl_err("unable to set disconnect timeout\n");
-               status = -EIO;
+       ret = ath6kl_wmi_disctimeout_cmd(ar->wmi, idx,
+                                        WLAN_CONFIG_DISCONNECT_TIMEOUT);
+       if (ret) {
+               ath6kl_err("unable to set disconnect timeout: %d\n", ret);
+               return ret;
        }
 
-       if (!(ar->conf_flags & ATH6KL_CONF_ENABLE_TX_BURST))
-               if (ath6kl_wmi_set_wmm_txop(ar->wmi, idx, WMI_TXOP_DISABLED)) {
-                       ath6kl_err("unable to set txop bursting\n");
-                       status = -EIO;
+       if (!(ar->conf_flags & ATH6KL_CONF_ENABLE_TX_BURST)) {
+               ret = ath6kl_wmi_set_wmm_txop(ar->wmi, idx, WMI_TXOP_DISABLED);
+               if (ret) {
+                       ath6kl_err("unable to set txop bursting: %d\n", ret);
+                       return ret;
                }
+       }
 
        if (ar->p2p && (ar->vif_max == 1 || idx)) {
                ret = ath6kl_wmi_info_req_cmd(ar->wmi, idx,
@@ -452,7 +456,7 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx)
                }
        }
 
-       return status;
+       return ret;
 }
 
 int ath6kl_configure_target(struct ath6kl *ar)
@@ -462,8 +466,7 @@ int ath6kl_configure_target(struct ath6kl *ar)
        int i, status;
 
        param = !!(ar->conf_flags & ATH6KL_CONF_UART_DEBUG);
-       if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar,
-                            HI_ITEM(hi_serial_enable)), (u8 *)&param, 4)) {
+       if (ath6kl_bmi_write_hi32(ar, hi_serial_enable, param)) {
                ath6kl_err("bmi_write_memory for uart debug failed\n");
                return -EIO;
        }
@@ -499,11 +502,8 @@ int ath6kl_configure_target(struct ath6kl *ar)
        if (ar->p2p && ar->vif_max == 1)
                fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV;
 
-       param = HTC_PROTOCOL_VERSION;
-       if (ath6kl_bmi_write(ar,
-                            ath6kl_get_hi_item_addr(ar,
-                            HI_ITEM(hi_app_host_interest)),
-                            (u8 *)&param, 4) != 0) {
+       if (ath6kl_bmi_write_hi32(ar, hi_app_host_interest,
+                                 HTC_PROTOCOL_VERSION) != 0) {
                ath6kl_err("bmi_write_memory for htc version failed\n");
                return -EIO;
        }
@@ -511,10 +511,7 @@ int ath6kl_configure_target(struct ath6kl *ar)
        /* set the firmware mode to STA/IBSS/AP */
        param = 0;
 
-       if (ath6kl_bmi_read(ar,
-                           ath6kl_get_hi_item_addr(ar,
-                           HI_ITEM(hi_option_flag)),
-                           (u8 *)&param, 4) != 0) {
+       if (ath6kl_bmi_read_hi32(ar, hi_option_flag, &param) != 0) {
                ath6kl_err("bmi_read_memory for setting fwmode failed\n");
                return -EIO;
        }
@@ -526,11 +523,7 @@ int ath6kl_configure_target(struct ath6kl *ar)
        param |= (0 << HI_OPTION_MAC_ADDR_METHOD_SHIFT);
        param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT);
 
-       if (ath6kl_bmi_write(ar,
-                            ath6kl_get_hi_item_addr(ar,
-                            HI_ITEM(hi_option_flag)),
-                            (u8 *)&param,
-                            4) != 0) {
+       if (ath6kl_bmi_write_hi32(ar, hi_option_flag, param) != 0) {
                ath6kl_err("bmi_write_memory for setting fwmode failed\n");
                return -EIO;
        }
@@ -549,16 +542,13 @@ int ath6kl_configure_target(struct ath6kl *ar)
        param = ar->hw.board_ext_data_addr;
        ram_reserved_size = ar->hw.reserved_ram_size;
 
-       if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar,
-                                       HI_ITEM(hi_board_ext_data)),
-                            (u8 *)&param, 4) != 0) {
+       if (ath6kl_bmi_write_hi32(ar, hi_board_ext_data, param) != 0) {
                ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n");
                return -EIO;
        }
 
-       if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar,
-                                       HI_ITEM(hi_end_ram_reserve_sz)),
-                            (u8 *)&ram_reserved_size, 4) != 0) {
+       if (ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz,
+                                 ram_reserved_size) != 0) {
                ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n");
                return -EIO;
        }
@@ -569,20 +559,13 @@ int ath6kl_configure_target(struct ath6kl *ar)
                return -EIO;
 
        /* Configure GPIO AR600x UART */
-       param = ar->hw.uarttx_pin;
-       status = ath6kl_bmi_write(ar,
-                               ath6kl_get_hi_item_addr(ar,
-                               HI_ITEM(hi_dbg_uart_txpin)),
-                               (u8 *)&param, 4);
+       status = ath6kl_bmi_write_hi32(ar, hi_dbg_uart_txpin,
+                                      ar->hw.uarttx_pin);
        if (status)
                return status;
 
        /* Configure target refclk_hz */
-       param =  ar->hw.refclk_hz;
-       status = ath6kl_bmi_write(ar,
-                               ath6kl_get_hi_item_addr(ar,
-                               HI_ITEM(hi_refclk_hz)),
-                               (u8 *)&param, 4);
+       status = ath6kl_bmi_write_hi32(ar, hi_refclk_hz, ar->hw.refclk_hz);
        if (status)
                return status;
 
@@ -832,13 +815,13 @@ static int ath6kl_fetch_testscript_file(struct ath6kl *ar)
                return 0;
 
        snprintf(filename, sizeof(filename), "%s/%s",
-               ar->hw.fw.dir, ar->hw.fw.testscript);
+                ar->hw.fw.dir, ar->hw.fw.testscript);
 
        ret = ath6kl_get_fw(ar, filename, &ar->fw_testscript,
                                &ar->fw_testscript_len);
        if (ret) {
                ath6kl_err("Failed to get testscript file %s: %d\n",
-                       filename, ret);
+                          filename, ret);
                return ret;
        }
 
@@ -922,7 +905,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
                switch (ie_id) {
                case ATH6KL_FW_IE_OTP_IMAGE:
                        ath6kl_dbg(ATH6KL_DBG_BOOT, "found otp image ie (%zd B)\n",
-                               ie_len);
+                                  ie_len);
 
                        ar->fw_otp = kmemdup(data, ie_len, GFP_KERNEL);
 
@@ -935,7 +918,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
                        break;
                case ATH6KL_FW_IE_FW_IMAGE:
                        ath6kl_dbg(ATH6KL_DBG_BOOT, "found fw image ie (%zd B)\n",
-                               ie_len);
+                                  ie_len);
 
                        /* in testmode we already might have a fw file */
                        if (ar->fw != NULL)
@@ -952,7 +935,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
                        break;
                case ATH6KL_FW_IE_PATCH_IMAGE:
                        ath6kl_dbg(ATH6KL_DBG_BOOT, "found patch image ie (%zd B)\n",
-                               ie_len);
+                                  ie_len);
 
                        ar->fw_patch = kmemdup(data, ie_len, GFP_KERNEL);
 
@@ -1096,22 +1079,14 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
         */
        if (ar->hw.board_addr != 0) {
                board_address = ar->hw.board_addr;
-               ath6kl_bmi_write(ar,
-                               ath6kl_get_hi_item_addr(ar,
-                               HI_ITEM(hi_board_data)),
-                               (u8 *) &board_address, 4);
+               ath6kl_bmi_write_hi32(ar, hi_board_data,
+                                     board_address);
        } else {
-               ath6kl_bmi_read(ar,
-                               ath6kl_get_hi_item_addr(ar,
-                               HI_ITEM(hi_board_data)),
-                               (u8 *) &board_address, 4);
+               ath6kl_bmi_read_hi32(ar, hi_board_data, &board_address);
        }
 
        /* determine where in target ram to write extended board data */
-       ath6kl_bmi_read(ar,
-                       ath6kl_get_hi_item_addr(ar,
-                       HI_ITEM(hi_board_ext_data)),
-                       (u8 *) &board_ext_address, 4);
+       ath6kl_bmi_read_hi32(ar, hi_board_ext_data, &board_ext_address);
 
        if (ar->target_type == TARGET_TYPE_AR6003 &&
            board_ext_address == 0) {
@@ -1123,6 +1098,8 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
        case TARGET_TYPE_AR6003:
                board_data_size = AR6003_BOARD_DATA_SZ;
                board_ext_data_size = AR6003_BOARD_EXT_DATA_SZ;
+               if (ar->fw_board_len > (board_data_size + board_ext_data_size))
+                       board_ext_data_size = AR6003_BOARD_EXT_DATA_SZ_V2;
                break;
        case TARGET_TYPE_AR6004:
                board_data_size = AR6004_BOARD_DATA_SZ;
@@ -1154,10 +1131,7 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
                /* record that extended board data is initialized */
                param = (board_ext_data_size << 16) | 1;
 
-               ath6kl_bmi_write(ar,
-                                ath6kl_get_hi_item_addr(ar,
-                                HI_ITEM(hi_board_ext_data_config)),
-                                (unsigned char *) &param, 4);
+               ath6kl_bmi_write_hi32(ar, hi_board_ext_data_config, param);
        }
 
        if (ar->fw_board_len < board_data_size) {
@@ -1178,11 +1152,7 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
        }
 
        /* record the fact that Board Data IS initialized */
-       param = 1;
-       ath6kl_bmi_write(ar,
-                        ath6kl_get_hi_item_addr(ar,
-                        HI_ITEM(hi_board_data_initialized)),
-                        (u8 *)&param, 4);
+       ath6kl_bmi_write_hi32(ar, hi_board_data_initialized, 1);
 
        return ret;
 }
@@ -1209,10 +1179,7 @@ static int ath6kl_upload_otp(struct ath6kl *ar)
        }
 
        /* read firmware start address */
-       ret = ath6kl_bmi_read(ar,
-                             ath6kl_get_hi_item_addr(ar,
-                                                     HI_ITEM(hi_app_start)),
-                             (u8 *) &address, sizeof(address));
+       ret = ath6kl_bmi_read_hi32(ar, hi_app_start, &address);
 
        if (ret) {
                ath6kl_err("Failed to read hi_app_start: %d\n", ret);
@@ -1270,7 +1237,7 @@ static int ath6kl_upload_firmware(struct ath6kl *ar)
 
 static int ath6kl_upload_patch(struct ath6kl *ar)
 {
-       u32 address, param;
+       u32 address;
        int ret;
 
        if (ar->fw_patch == NULL)
@@ -1287,18 +1254,14 @@ static int ath6kl_upload_patch(struct ath6kl *ar)
                return ret;
        }
 
-       param = address;
-       ath6kl_bmi_write(ar,
-                        ath6kl_get_hi_item_addr(ar,
-                        HI_ITEM(hi_dset_list_head)),
-                        (unsigned char *) &param, 4);
+       ath6kl_bmi_write_hi32(ar, hi_dset_list_head, address);
 
        return 0;
 }
 
 static int ath6kl_upload_testscript(struct ath6kl *ar)
 {
-       u32 address, param;
+       u32 address;
        int ret;
 
        if (ar->testmode != 2)
@@ -1310,7 +1273,7 @@ static int ath6kl_upload_testscript(struct ath6kl *ar)
        address = ar->hw.testscript_addr;
 
        ath6kl_dbg(ATH6KL_DBG_BOOT, "writing testscript to 0x%x (%zd B)\n",
-               address, ar->fw_testscript_len);
+                  address, ar->fw_testscript_len);
 
        ret = ath6kl_bmi_write(ar, address, ar->fw_testscript,
                ar->fw_testscript_len);
@@ -1319,23 +1282,9 @@ static int ath6kl_upload_testscript(struct ath6kl *ar)
                return ret;
        }
 
-       param = address;
-       ath6kl_bmi_write(ar,
-                       ath6kl_get_hi_item_addr(ar,
-                       HI_ITEM(hi_ota_testscript)),
-                       (unsigned char *) &param, 4);
-
-       param = 4096;
-       ath6kl_bmi_write(ar,
-                       ath6kl_get_hi_item_addr(ar,
-                       HI_ITEM(hi_end_ram_reserve_sz)),
-                       (unsigned char *) &param, 4);
-
-       param = 1;
-       ath6kl_bmi_write(ar,
-                       ath6kl_get_hi_item_addr(ar,
-                       HI_ITEM(hi_test_apps_related)),
-                       (unsigned char *) &param, 4);
+       ath6kl_bmi_write_hi32(ar, hi_ota_testscript, address);
+       ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz, 4096);
+       ath6kl_bmi_write_hi32(ar, hi_test_apps_related, 1);
 
        return 0;
 }
@@ -1346,7 +1295,7 @@ static int ath6kl_init_upload(struct ath6kl *ar)
        int status = 0;
 
        if (ar->target_type != TARGET_TYPE_AR6003 &&
-               ar->target_type != TARGET_TYPE_AR6004)
+           ar->target_type != TARGET_TYPE_AR6004)
                return -EINVAL;
 
        /* temporarily disable system sleep */
@@ -1403,7 +1352,8 @@ static int ath6kl_init_upload(struct ath6kl *ar)
                return status;
 
        /* WAR to avoid SDIO CRC err */
-       if (ar->version.target_ver == AR6003_HW_2_0_VERSION) {
+       if (ar->version.target_ver == AR6003_HW_2_0_VERSION ||
+           ar->version.target_ver == AR6003_HW_2_1_1_VERSION) {
                ath6kl_err("temporary war to avoid sdio crc error\n");
 
                param = 0x20;
@@ -1726,9 +1676,11 @@ void ath6kl_stop_txrx(struct ath6kl *ar)
         * configure NOT to reset the target during a debug session.
         */
        ath6kl_dbg(ATH6KL_DBG_TRC,
-                       "attempting to reset target on instance destroy\n");
+                  "attempting to reset target on instance destroy\n");
        ath6kl_reset_device(ar, ar->target_type, true, true);
 
        clear_bit(WLAN_ENABLED, &ar->flag);
+
+       up(&ar->sem);
 }
 EXPORT_SYMBOL(ath6kl_stop_txrx);
index b96d01a..229e192 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -80,11 +81,21 @@ static void ath6kl_add_new_sta(struct ath6kl_vif *vif, u8 *mac, u16 aid,
 static void ath6kl_sta_cleanup(struct ath6kl *ar, u8 i)
 {
        struct ath6kl_sta *sta = &ar->sta_list[i];
+       struct ath6kl_mgmt_buff *entry, *tmp;
 
        /* 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);
+
+       if (sta->mgmt_psq_len != 0) {
+               list_for_each_entry_safe(entry, tmp, &sta->mgmt_psq, list) {
+                       kfree(entry);
+               }
+               INIT_LIST_HEAD(&sta->mgmt_psq);
+               sta->mgmt_psq_len = 0;
+       }
+
        spin_unlock_bh(&sta->psq_lock);
 
        memset(&ar->ap_stats.sta[sta->aid - 1], 0,
@@ -339,7 +350,7 @@ void ath6kl_reset_device(struct ath6kl *ar, u32 target_type,
        __le32 data;
 
        if (target_type != TARGET_TYPE_AR6003 &&
-               target_type != TARGET_TYPE_AR6004)
+           target_type != TARGET_TYPE_AR6004)
                return;
 
        data = cold_reset ? cpu_to_le32(RESET_CONTROL_COLD_RST) :
@@ -588,11 +599,9 @@ 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)) {
-               ar->listen_intvl_b = listen_int;
+       if ((vif->nw_type == INFRA_NETWORK))
                ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
-                                             0, ar->listen_intvl_b);
-       }
+                                             vif->listen_intvl_t, 0);
 
        netif_wake_queue(vif->ndev);
 
@@ -810,6 +819,7 @@ void ath6kl_pspoll_event(struct ath6kl_vif *vif, u8 aid)
        struct sk_buff *skb;
        bool psq_empty = false;
        struct ath6kl *ar = vif->ar;
+       struct ath6kl_mgmt_buff *mgmt_buf;
 
        conn = ath6kl_find_sta_by_aid(ar, aid);
 
@@ -820,7 +830,7 @@ void ath6kl_pspoll_event(struct ath6kl_vif *vif, u8 aid)
         * becomes empty update the PVB for this station.
         */
        spin_lock_bh(&conn->psq_lock);
-       psq_empty  = skb_queue_empty(&conn->psq);
+       psq_empty  = skb_queue_empty(&conn->psq) && (conn->mgmt_psq_len == 0);
        spin_unlock_bh(&conn->psq_lock);
 
        if (psq_empty)
@@ -828,15 +838,31 @@ void ath6kl_pspoll_event(struct ath6kl_vif *vif, u8 aid)
                return;
 
        spin_lock_bh(&conn->psq_lock);
-       skb = skb_dequeue(&conn->psq);
-       spin_unlock_bh(&conn->psq_lock);
+       if (conn->mgmt_psq_len > 0) {
+               mgmt_buf = list_first_entry(&conn->mgmt_psq,
+                                       struct ath6kl_mgmt_buff, list);
+               list_del(&mgmt_buf->list);
+               conn->mgmt_psq_len--;
+               spin_unlock_bh(&conn->psq_lock);
+
+               conn->sta_flags |= STA_PS_POLLED;
+               ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx,
+                                        mgmt_buf->id, mgmt_buf->freq,
+                                        mgmt_buf->wait, mgmt_buf->buf,
+                                        mgmt_buf->len, mgmt_buf->no_cck);
+               conn->sta_flags &= ~STA_PS_POLLED;
+               kfree(mgmt_buf);
+       } else {
+               skb = skb_dequeue(&conn->psq);
+               spin_unlock_bh(&conn->psq_lock);
 
-       conn->sta_flags |= STA_PS_POLLED;
-       ath6kl_data_tx(skb, vif->ndev);
-       conn->sta_flags &= ~STA_PS_POLLED;
+               conn->sta_flags |= STA_PS_POLLED;
+               ath6kl_data_tx(skb, vif->ndev);
+               conn->sta_flags &= ~STA_PS_POLLED;
+       }
 
        spin_lock_bh(&conn->psq_lock);
-       psq_empty  = skb_queue_empty(&conn->psq);
+       psq_empty  = skb_queue_empty(&conn->psq) && (conn->mgmt_psq_len == 0);
        spin_unlock_bh(&conn->psq_lock);
 
        if (psq_empty)
@@ -922,8 +948,8 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid,
        }
 
        ath6kl_cfg80211_disconnect_event(vif, reason, bssid,
-                                      assoc_resp_len, assoc_info,
-                                      prot_reason_status);
+                                        assoc_resp_len, assoc_info,
+                                        prot_reason_status);
 
        aggr_reset_state(vif->aggr_cntxt->aggr_conn);
 
@@ -943,9 +969,9 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid,
        } else {
                set_bit(CONNECT_PEND, &vif->flags);
                if (((reason == ASSOC_FAILED) &&
-                   (prot_reason_status == 0x11)) ||
-                   ((reason == ASSOC_FAILED) && (prot_reason_status == 0x0)
-                    && (vif->reconnect_flag == 1))) {
+                    (prot_reason_status == 0x11)) ||
+                   ((reason == ASSOC_FAILED) && (prot_reason_status == 0x0) &&
+                    (vif->reconnect_flag == 1))) {
                        set_bit(CONNECTED, &vif->flags);
                        return;
                }
@@ -1079,7 +1105,7 @@ static void ath6kl_set_multicast_list(struct net_device *ndev)
        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");
+                          mc_all_on ? "enabling" : "disabling");
                ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx,
                                                  mc_all_on);
                if (ret)
@@ -1092,7 +1118,7 @@ static void ath6kl_set_multicast_list(struct net_device *ndev)
                found = false;
                netdev_for_each_mc_addr(ha, ndev) {
                        if (memcmp(ha->addr, mc_filter->hw_addr,
-                           ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) {
+                                  ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) {
                                found = true;
                                break;
                        }
@@ -1111,7 +1137,7 @@ static void ath6kl_set_multicast_list(struct net_device *ndev)
                                        false);
                        if (ret) {
                                ath6kl_warn("Failed to remove multicast filter:%pM\n",
-                                            mc_filter->hw_addr);
+                                           mc_filter->hw_addr);
                                return;
                        }
 
@@ -1126,7 +1152,7 @@ static void ath6kl_set_multicast_list(struct net_device *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) {
+                                  ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) {
                                found = true;
                                break;
                        }
@@ -1151,7 +1177,7 @@ static void ath6kl_set_multicast_list(struct net_device *ndev)
                                        true);
                        if (ret) {
                                ath6kl_warn("Failed to add multicast filter :%pM\n",
-                                            mc_filter->hw_addr);
+                                           mc_filter->hw_addr);
                                kfree(mc_filter);
                                goto out;
                        }
@@ -1184,5 +1210,7 @@ void init_netdev(struct net_device *dev)
                                sizeof(struct wmi_data_hdr) + HTC_HDR_LENGTH
                                + WMI_MAX_TX_META_SZ + ATH6KL_HTC_ALIGN_BYTES;
 
+       dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
+
        return;
 }
index 4febee7..5352864 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -31,6 +32,7 @@
 struct ath6kl_sdio {
        struct sdio_func *func;
 
+       /* protects access to bus_req_freeq */
        spinlock_t lock;
 
        /* free list */
@@ -49,16 +51,20 @@ struct ath6kl_sdio {
        /* scatter request list head */
        struct list_head scat_req;
 
-       /* Avoids disabling irq while the interrupts being handled */
-       struct mutex mtx_irq;
+       atomic_t irq_handling;
+       wait_queue_head_t irq_wq;
 
+       /* protects access to scat_req */
        spinlock_t scat_lock;
+
        bool scatter_enabled;
 
        bool is_disabled;
        const struct sdio_device_id *id;
        struct work_struct wr_async_work;
        struct list_head wr_asyncq;
+
+       /* protects access to wr_asyncq */
        spinlock_t wr_async_lock;
 };
 
@@ -404,7 +410,10 @@ static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf,
                        return -ENOMEM;
                mutex_lock(&ar_sdio->dma_buffer_mutex);
                tbuf = ar_sdio->dma_buffer;
-               memcpy(tbuf, buf, len);
+
+               if (request & HIF_WRITE)
+                       memcpy(tbuf, buf, len);
+
                bounced = true;
        } else
                tbuf = buf;
@@ -462,7 +471,7 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func)
        ath6kl_dbg(ATH6KL_DBG_SDIO, "irq\n");
 
        ar_sdio = sdio_get_drvdata(func);
-       mutex_lock(&ar_sdio->mtx_irq);
+       atomic_set(&ar_sdio->irq_handling, 1);
        /*
         * Release the host during interrups so we can pick it back up when
         * we process commands.
@@ -471,7 +480,10 @@ 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);
-       mutex_unlock(&ar_sdio->mtx_irq);
+
+       atomic_set(&ar_sdio->irq_handling, 0);
+       wake_up(&ar_sdio->irq_wq);
+
        WARN_ON(status && status != -ECANCELED);
 }
 
@@ -572,6 +584,13 @@ static void ath6kl_sdio_irq_enable(struct ath6kl *ar)
        sdio_release_host(ar_sdio->func);
 }
 
+static bool ath6kl_sdio_is_on_irq(struct ath6kl *ar)
+{
+       struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
+
+       return !atomic_read(&ar_sdio->irq_handling);
+}
+
 static void ath6kl_sdio_irq_disable(struct ath6kl *ar)
 {
        struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
@@ -579,14 +598,21 @@ static void ath6kl_sdio_irq_disable(struct ath6kl *ar)
 
        sdio_claim_host(ar_sdio->func);
 
-       mutex_lock(&ar_sdio->mtx_irq);
+       if (atomic_read(&ar_sdio->irq_handling)) {
+               sdio_release_host(ar_sdio->func);
+
+               ret = wait_event_interruptible(ar_sdio->irq_wq,
+                                              ath6kl_sdio_is_on_irq(ar));
+               if (ret)
+                       return;
+
+               sdio_claim_host(ar_sdio->func);
+       }
 
        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);
 }
 
@@ -601,6 +627,8 @@ static struct hif_scatter_req *ath6kl_sdio_scatter_req_get(struct ath6kl *ar)
                node = list_first_entry(&ar_sdio->scat_req,
                                        struct hif_scatter_req, list);
                list_del(&node->list);
+
+               node->scat_q_depth = get_queue_depth(&ar_sdio->scat_req);
        }
 
        spin_unlock_bh(&ar_sdio->scat_lock);
@@ -633,8 +661,8 @@ static int ath6kl_sdio_async_rw_scatter(struct ath6kl *ar,
                return -EINVAL;
 
        ath6kl_dbg(ATH6KL_DBG_SCATTER,
-               "hif-scatter: total len: %d scatter entries: %d\n",
-               scat_req->len, scat_req->scat_entries);
+                  "hif-scatter: total len: %d scatter entries: %d\n",
+                  scat_req->len, scat_req->scat_entries);
 
        if (request & HIF_SYNCHRONOUS)
                status = ath6kl_sdio_scat_rw(ar_sdio, scat_req->busrequest);
@@ -813,6 +841,7 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
        struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
        struct sdio_func *func = ar_sdio->func;
        mmc_pm_flag_t flags;
+       bool try_deepsleep = false;
        int ret;
 
        if (ar->state == ATH6KL_STATE_SCHED_SCAN) {
@@ -839,14 +868,22 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
                        goto cut_pwr;
 
                ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_WOW, wow);
-               if (ret)
+               if (ret && ret != -ENOTCONN)
+                       ath6kl_err("wow suspend failed: %d\n", ret);
+
+               if (ret &&
+                   (!ar->wow_suspend_mode ||
+                    ar->wow_suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP))
+                       try_deepsleep = true;
+               else if (ret &&
+                        ar->wow_suspend_mode == WLAN_POWER_STATE_CUT_PWR)
                        goto cut_pwr;
-
-               return 0;
+               if (!ret)
+                       return 0;
        }
 
        if (ar->suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP ||
-           !ar->suspend_mode) {
+           !ar->suspend_mode || try_deepsleep) {
 
                flags = sdio_get_host_pm_caps(func);
                if (!(flags & MMC_PM_KEEP_POWER))
@@ -901,8 +938,15 @@ static int ath6kl_sdio_resume(struct ath6kl *ar)
 
        case ATH6KL_STATE_WOW:
                break;
+
        case ATH6KL_STATE_SCHED_SCAN:
                break;
+
+       case ATH6KL_STATE_SUSPENDING:
+               break;
+
+       case ATH6KL_STATE_RESUMING:
+               break;
        }
 
        ath6kl_cfg80211_resume(ar);
@@ -981,7 +1025,7 @@ static int ath6kl_sdio_diag_read32(struct ath6kl *ar, u32 address, u32 *data)
                                (u8 *)data, sizeof(u32), HIF_RD_SYNC_BYTE_INC);
        if (status) {
                ath6kl_err("%s: failed to read from window data addr\n",
-                       __func__);
+                          __func__);
                return status;
        }
 
@@ -1285,7 +1329,6 @@ 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);
@@ -1293,6 +1336,8 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
 
        INIT_WORK(&ar_sdio->wr_async_work, ath6kl_sdio_write_async_work);
 
+       init_waitqueue_head(&ar_sdio->irq_wq);
+
        for (count = 0; count < BUS_REQUEST_MAX_NUM; count++)
                ath6kl_sdio_free_bus_req(ar_sdio, &ar_sdio->bus_req[count]);
 
index 108a723..78e0ef4 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004-2010 Atheros Communications Inc.
+ * Copyright (c) 2011 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -19,6 +20,7 @@
 
 #define AR6003_BOARD_DATA_SZ           1024
 #define AR6003_BOARD_EXT_DATA_SZ       768
+#define AR6003_BOARD_EXT_DATA_SZ_V2    1024
 
 #define AR6004_BOARD_DATA_SZ     6144
 #define AR6004_BOARD_EXT_DATA_SZ 0
index f0cd61d..6675c92 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2010-2011 Atheros Communications Inc.
+ * Copyright (c) 2011 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 7fd47a6..fe651d6 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2010-2011 Atheros Communications Inc.
+ * Copyright (c) 2011 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index a3dc694..f85353f 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -158,8 +159,8 @@ static bool ath6kl_process_uapsdq(struct ath6kl_sta *conn,
         */
        if (is_apsdq_empty) {
                ath6kl_wmi_set_apsd_bfrd_traf(ar->wmi,
-                               vif->fw_vif_idx,
-                               conn->aid, 1, 0);
+                                             vif->fw_vif_idx,
+                                             conn->aid, 1, 0);
        }
        *flags |= WMI_DATA_HDR_FLAGS_UAPSD;
 
@@ -284,6 +285,9 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb,
        int status = 0;
        struct ath6kl_cookie *cookie = NULL;
 
+       if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW))
+               return -EACCES;
+
        spin_lock_bh(&ar->lock);
 
        ath6kl_dbg(ATH6KL_DBG_WLAN_TX,
@@ -359,6 +363,11 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
                return 0;
        }
 
+       if (WARN_ON_ONCE(ar->state != ATH6KL_STATE_ON)) {
+               dev_kfree_skb(skb);
+               return 0;
+       }
+
        if (!test_bit(WMI_READY, &ar->flag))
                goto fail_tx;
 
@@ -370,7 +379,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
 
        if (test_bit(WMI_ENABLED, &ar->flag)) {
                if ((dev->features & NETIF_F_IP_CSUM) &&
-                               (csum == CHECKSUM_PARTIAL)) {
+                   (csum == CHECKSUM_PARTIAL)) {
                        csum_start = skb->csum_start -
                                        (skb_network_header(skb) - skb->head) +
                                        sizeof(struct ath6kl_llc_snap_hdr);
@@ -394,7 +403,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
                }
 
                if ((dev->features & NETIF_F_IP_CSUM) &&
-                               (csum == CHECKSUM_PARTIAL)) {
+                   (csum == CHECKSUM_PARTIAL)) {
                        meta_v2.csum_start = csum_start;
                        meta_v2.csum_dest = csum_dest;
 
@@ -419,7 +428,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
                }
 
                if ((vif->nw_type == ADHOC_NETWORK) &&
-                    ar->ibss_ps_enable && test_bit(CONNECTED, &vif->flags))
+                   ar->ibss_ps_enable && test_bit(CONNECTED, &vif->flags))
                        chk_adhoc_ps_mapping = true;
                else {
                        /* get the stream mapping */
@@ -593,7 +602,8 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
         */
        if (ar->ac_stream_pri_map[ar->ep2ac_map[endpoint]] <
            ar->hiac_stream_active_pri &&
-           ar->cookie_count <= MAX_HI_COOKIE_NUM)
+           ar->cookie_count <=
+                       target->endpoint[endpoint].tx_drop_packet_threshold)
                /*
                 * Give preference to the highest priority stream by
                 * dropping the packets which overflowed.
@@ -876,7 +886,7 @@ void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint)
                if (!IS_ALIGNED((unsigned long) skb->data, 4))
                        skb->data = PTR_ALIGN(skb->data - 4, 4);
                set_htc_rxpkt_info(packet, skb, skb->data,
-                               ATH6KL_BUFFER_SIZE, endpoint);
+                                  ATH6KL_BUFFER_SIZE, endpoint);
                list_add_tail(&packet->list, &queue);
        }
 
@@ -1256,8 +1266,8 @@ static void ath6kl_uapsd_trigger_frame_rx(struct ath6kl_vif *vif,
                        flags = 0;
 
                ath6kl_wmi_set_apsd_bfrd_traf(ar->wmi,
-                               vif->fw_vif_idx,
-                               conn->aid, 0, flags);
+                                             vif->fw_vif_idx,
+                                             conn->aid, 0, flags);
        }
 
        return;
@@ -1296,7 +1306,15 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
        skb_put(skb, packet->act_len + HTC_HDR_LENGTH);
        skb_pull(skb, HTC_HDR_LENGTH);
 
+       ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "rx ",
+                       skb->data, skb->len);
+
        if (ept == ar->ctrl_ep) {
+               if (test_bit(WMI_ENABLED, &ar->flag)) {
+                       ath6kl_check_wow_status(ar);
+                       ath6kl_wmi_control_rx(ar->wmi, skb);
+                       return;
+               }
                if_idx =
                wmi_cmd_hdr_get_if_idx((struct wmi_cmd_hdr *) skb->data);
        } else {
@@ -1321,10 +1339,6 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
 
        spin_unlock_bh(&vif->if_lock);
 
-
-       ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "rx ",
-                       skb->data, skb->len);
-
        skb->dev = vif->ndev;
 
        if (!test_bit(WMI_ENABLED, &ar->flag)) {
@@ -1336,11 +1350,6 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
 
        ath6kl_check_wow_status(ar);
 
-       if (ept == ar->ctrl_ep) {
-               ath6kl_wmi_control_rx(ar->wmi, skb);
-               return;
-       }
-
        min_hdr_len = sizeof(struct ethhdr) + sizeof(struct wmi_data_hdr) +
                      sizeof(struct ath6kl_llc_snap_hdr);
 
@@ -1416,8 +1425,33 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
                        if (!(conn->sta_flags & STA_PS_SLEEP)) {
                                struct sk_buff *skbuff = NULL;
                                bool is_apsdq_empty;
+                               struct ath6kl_mgmt_buff *mgmt;
+                               u8 idx;
 
                                spin_lock_bh(&conn->psq_lock);
+                               while (conn->mgmt_psq_len > 0) {
+                                       mgmt = list_first_entry(
+                                                       &conn->mgmt_psq,
+                                                       struct ath6kl_mgmt_buff,
+                                                       list);
+                                       list_del(&mgmt->list);
+                                       conn->mgmt_psq_len--;
+                                       spin_unlock_bh(&conn->psq_lock);
+                                       idx = vif->fw_vif_idx;
+
+                                       ath6kl_wmi_send_mgmt_cmd(ar->wmi,
+                                                                idx,
+                                                                mgmt->id,
+                                                                mgmt->freq,
+                                                                mgmt->wait,
+                                                                mgmt->buf,
+                                                                mgmt->len,
+                                                                mgmt->no_cck);
+
+                                       kfree(mgmt);
+                                       spin_lock_bh(&conn->psq_lock);
+                               }
+                               conn->mgmt_psq_len = 0;
                                while ((skbuff = skb_dequeue(&conn->psq))) {
                                        spin_unlock_bh(&conn->psq_lock);
                                        ath6kl_data_tx(skbuff, vif->ndev);
@@ -1541,7 +1575,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
                        aggr_conn = vif->aggr_cntxt->aggr_conn;
 
                if (aggr_process_recv_frm(aggr_conn, tid, seq_no,
-                   is_amsdu, skb)) {
+                                         is_amsdu, skb)) {
                        /* aggregation code will handle the skb */
                        return;
                }
index c72567c..325b122 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2007-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 97abf46..2b44233 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -126,7 +127,7 @@ int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb)
 
        if (!is_ethertype(be16_to_cpu(type))) {
                ath6kl_dbg(ATH6KL_DBG_WMI,
-                       "%s: pkt is already in 802.3 format\n", __func__);
+                          "%s: pkt is already in 802.3 format\n", __func__);
                return 0;
        }
 
@@ -827,8 +828,8 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len,
                        if (pie[1] > 3 && pie[2] == 0x00 && pie[3] == 0x50 &&
                            pie[4] == 0xf2 && pie[5] == WMM_OUI_TYPE) {
                                /* WMM OUT (00:50:F2) */
-                               if (pie[1] > 5
-                                   && pie[6] == WMM_PARAM_OUI_SUBTYPE)
+                               if (pie[1] > 5 &&
+                                   pie[6] == WMM_PARAM_OUI_SUBTYPE)
                                        wmi->is_wmm_enabled = true;
                        }
                        break;
@@ -912,17 +913,17 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len)
                regpair = ath6kl_get_regpair((u16) reg_code);
                country = ath6kl_regd_find_country_by_rd((u16) reg_code);
                ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n",
-                               regpair->regDmnEnum);
+                          regpair->regDmnEnum);
        }
 
-       if (country) {
+       if (country && wmi->parent_dev->wiphy_registered) {
                alpha2[0] = country->isoName[0];
                alpha2[1] = country->isoName[1];
 
                regulatory_hint(wmi->parent_dev->wiphy, alpha2);
 
                ath6kl_dbg(ATH6KL_DBG_WMI, "Country alpha2 being used: %c%c\n",
-                               alpha2[0], alpha2[1]);
+                          alpha2[0], alpha2[1]);
        }
 }
 
@@ -1033,8 +1034,9 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
        if (len < 8 + 2 + 2)
                return -EINVAL;
 
-       if (bih->frame_type == BEACON_FTYPE && test_bit(CONNECTED, &vif->flags)
-           && memcmp(bih->bssid, vif->bssid, ETH_ALEN) == 0) {
+       if (bih->frame_type == BEACON_FTYPE &&
+           test_bit(CONNECTED, &vif->flags) &&
+           memcmp(bih->bssid, vif->bssid, ETH_ALEN) == 0) {
                const u8 *tim;
                tim = cfg80211_find_ie(WLAN_EID_TIM, buf + 8 + 2 + 2,
                                       len - 8 - 2 - 2);
@@ -1366,8 +1368,8 @@ static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap,
                /* Upper threshold breached */
                if (rssi < sq_thresh->upper_threshold[0]) {
                        ath6kl_dbg(ATH6KL_DBG_WMI,
-                               "spurious upper rssi threshold event: %d\n",
-                               rssi);
+                                  "spurious upper rssi threshold event: %d\n",
+                                  rssi);
                } else if ((rssi < sq_thresh->upper_threshold[1]) &&
                           (rssi >= sq_thresh->upper_threshold[0])) {
                        new_threshold = WMI_RSSI_THRESHOLD1_ABOVE;
@@ -1390,7 +1392,7 @@ static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap,
                /* Lower threshold breached */
                if (rssi > sq_thresh->lower_threshold[0]) {
                        ath6kl_dbg(ATH6KL_DBG_WMI,
-                               "spurious lower rssi threshold event: %d %d\n",
+                                  "spurious lower rssi threshold event: %d %d\n",
                                rssi, sq_thresh->lower_threshold[0]);
                } else if ((rssi > sq_thresh->lower_threshold[1]) &&
                           (rssi <= sq_thresh->lower_threshold[0])) {
@@ -1551,8 +1553,8 @@ static int ath6kl_wmi_snr_threshold_event_rx(struct wmi *wmi, u8 *datap,
                /* Upper threshold breached */
                if (snr < sq_thresh->upper_threshold[0]) {
                        ath6kl_dbg(ATH6KL_DBG_WMI,
-                               "spurious upper snr threshold event: %d\n",
-                               snr);
+                                  "spurious upper snr threshold event: %d\n",
+                                  snr);
                } else if ((snr < sq_thresh->upper_threshold[1]) &&
                           (snr >= sq_thresh->upper_threshold[0])) {
                        new_threshold = WMI_SNR_THRESHOLD1_ABOVE;
@@ -1569,8 +1571,8 @@ static int ath6kl_wmi_snr_threshold_event_rx(struct wmi *wmi, u8 *datap,
                /* Lower threshold breached */
                if (snr > sq_thresh->lower_threshold[0]) {
                        ath6kl_dbg(ATH6KL_DBG_WMI,
-                               "spurious lower snr threshold event: %d\n",
-                               sq_thresh->lower_threshold[0]);
+                                  "spurious lower snr threshold event: %d\n",
+                                  sq_thresh->lower_threshold[0]);
                } else if ((snr > sq_thresh->lower_threshold[1]) &&
                           (snr <= sq_thresh->lower_threshold[0])) {
                        new_threshold = WMI_SNR_THRESHOLD4_BELOW;
@@ -2028,6 +2030,26 @@ int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u8 if_idx,
        return ret;
 }
 
+int ath6kl_wmi_bmisstime_cmd(struct wmi *wmi, u8 if_idx,
+                            u16 bmiss_time, u16 num_beacons)
+{
+       struct sk_buff *skb;
+       struct wmi_bmiss_time_cmd *cmd;
+       int ret;
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_bmiss_time_cmd *) skb->data;
+       cmd->bmiss_time = cpu_to_le16(bmiss_time);
+       cmd->num_beacons = cpu_to_le16(num_beacons);
+
+       ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_BMISS_TIME_CMDID,
+                                 NO_SYNC_WMIFLAG);
+       return ret;
+}
+
 int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 if_idx, u8 pwr_mode)
 {
        struct sk_buff *skb;
@@ -2613,7 +2635,7 @@ int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx,
        int ret;
 
        if ((wow_mode != ATH6KL_WOW_MODE_ENABLE) &&
-            wow_mode != ATH6KL_WOW_MODE_DISABLE) {
+           wow_mode != ATH6KL_WOW_MODE_DISABLE) {
                ath6kl_err("invalid wow mode: %d\n", wow_mode);
                return -EINVAL;
        }
@@ -3014,6 +3036,22 @@ int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 if_idx, u8 cmd, const u8 *mac,
                                   NO_SYNC_WMIFLAG);
 }
 
+int ath6kl_wmi_ap_hidden_ssid(struct wmi *wmi, u8 if_idx, bool enable)
+{
+       struct sk_buff *skb;
+       struct wmi_ap_hidden_ssid_cmd *cmd;
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_ap_hidden_ssid_cmd *) skb->data;
+       cmd->hidden_ssid = enable ? 1 : 0;
+
+       return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_HIDDEN_SSID_CMDID,
+                                  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)
 {
@@ -3183,8 +3221,9 @@ int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx, u32 freq, u32 dur)
  * ath6kl_wmi_send_mgmt_cmd instead. The new function supports P2P
  * mgmt operations using station interface.
  */
-int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
-                              u32 wait, const u8 *data, u16 data_len)
+static int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id,
+                                     u32 freq, u32 wait, const u8 *data,
+                                     u16 data_len)
 {
        struct sk_buff *skb;
        struct wmi_send_action_cmd *p;
@@ -3220,9 +3259,9 @@ int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
                                   NO_SYNC_WMIFLAG);
 }
 
-int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
-                              u32 wait, const u8 *data, u16 data_len,
-                              u32 no_cck)
+static int __ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id,
+                                     u32 freq, u32 wait, const u8 *data,
+                                     u16 data_len, u32 no_cck)
 {
        struct sk_buff *skb;
        struct wmi_send_mgmt_cmd *p;
@@ -3259,6 +3298,32 @@ int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
                                   NO_SYNC_WMIFLAG);
 }
 
+int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
+                               u32 wait, const u8 *data, u16 data_len,
+                               u32 no_cck)
+{
+       int status;
+       struct ath6kl *ar = wmi->parent_dev;
+
+       if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
+                    ar->fw_capabilities)) {
+               /*
+                * If capable of doing P2P mgmt operations using
+                * station interface, send additional information like
+                * supported rates to advertise and xmit rates for
+                * probe requests
+                */
+               status = __ath6kl_wmi_send_mgmt_cmd(ar->wmi, if_idx, id, freq,
+                                                   wait, data, data_len,
+                                                   no_cck);
+       } else {
+               status = ath6kl_wmi_send_action_cmd(ar->wmi, if_idx, id, freq,
+                                                   wait, data, data_len);
+       }
+
+       return status;
+}
+
 int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq,
                                       const u8 *dst, const u8 *data,
                                       u16 data_len)
@@ -3370,32 +3435,101 @@ static int ath6kl_wmi_roam_tbl_event_rx(struct wmi *wmi, u8 *datap, int len)
        return ath6kl_debug_roam_tbl_event(wmi->parent_dev, datap, len);
 }
 
-/* Control Path */
-int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
+/* Process interface specific wmi events, caller would free the datap */
+static int ath6kl_wmi_proc_events_vif(struct wmi *wmi, u16 if_idx, u16 cmd_id,
+                                       u8 *datap, u32 len)
 {
-       struct wmi_cmd_hdr *cmd;
        struct ath6kl_vif *vif;
-       u32 len;
-       u16 id;
-       u8 if_idx;
-       u8 *datap;
-       int ret = 0;
 
-       if (WARN_ON(skb == NULL))
+       vif = ath6kl_get_vif_by_index(wmi->parent_dev, if_idx);
+       if (!vif) {
+               ath6kl_dbg(ATH6KL_DBG_WMI,
+                          "Wmi event for unavailable vif, vif_index:%d\n",
+                           if_idx);
                return -EINVAL;
+       }
 
-       if (skb->len < sizeof(struct wmi_cmd_hdr)) {
-               ath6kl_err("bad packet 1\n");
-               dev_kfree_skb(skb);
+       switch (cmd_id) {
+       case WMI_CONNECT_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CONNECT_EVENTID\n");
+               return ath6kl_wmi_connect_event_rx(wmi, datap, len, vif);
+       case WMI_DISCONNECT_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DISCONNECT_EVENTID\n");
+               return ath6kl_wmi_disconnect_event_rx(wmi, datap, len, vif);
+       case WMI_TKIP_MICERR_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TKIP_MICERR_EVENTID\n");
+               return ath6kl_wmi_tkip_micerr_event_rx(wmi, datap, len, vif);
+       case WMI_BSSINFO_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_BSSINFO_EVENTID\n");
+               return ath6kl_wmi_bssinfo_event_rx(wmi, datap, len, vif);
+       case WMI_NEIGHBOR_REPORT_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_NEIGHBOR_REPORT_EVENTID\n");
+               return ath6kl_wmi_neighbor_report_event_rx(wmi, datap, len,
+                                                          vif);
+       case WMI_SCAN_COMPLETE_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n");
+               return ath6kl_wmi_scan_complete_rx(wmi, datap, len, vif);
+       case WMI_REPORT_STATISTICS_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_STATISTICS_EVENTID\n");
+               return ath6kl_wmi_stats_event_rx(wmi, datap, len, vif);
+       case WMI_CAC_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CAC_EVENTID\n");
+               return ath6kl_wmi_cac_event_rx(wmi, datap, len, vif);
+       case WMI_PSPOLL_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSPOLL_EVENTID\n");
+               return ath6kl_wmi_pspoll_event_rx(wmi, datap, len, vif);
+       case WMI_DTIMEXPIRY_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DTIMEXPIRY_EVENTID\n");
+               return ath6kl_wmi_dtimexpiry_event_rx(wmi, datap, len, vif);
+       case WMI_ADDBA_REQ_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_REQ_EVENTID\n");
+               return ath6kl_wmi_addba_req_event_rx(wmi, datap, len, vif);
+       case WMI_DELBA_REQ_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DELBA_REQ_EVENTID\n");
+               return ath6kl_wmi_delba_req_event_rx(wmi, datap, len, vif);
+       case WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI,
+                          "WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID");
+               return ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx(wmi, vif);
+       case WMI_REMAIN_ON_CHNL_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n");
+               return ath6kl_wmi_remain_on_chnl_event_rx(wmi, datap, len, vif);
+       case WMI_CANCEL_REMAIN_ON_CHNL_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI,
+                          "WMI_CANCEL_REMAIN_ON_CHNL_EVENTID\n");
+               return ath6kl_wmi_cancel_remain_on_chnl_event_rx(wmi, datap,
+                                                                len, vif);
+       case WMI_TX_STATUS_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n");
+               return ath6kl_wmi_tx_status_event_rx(wmi, datap, len, vif);
+       case WMI_RX_PROBE_REQ_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n");
+               return ath6kl_wmi_rx_probe_req_event_rx(wmi, datap, len, vif);
+       case WMI_RX_ACTION_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n");
+               return ath6kl_wmi_rx_action_event_rx(wmi, datap, len, vif);
+       default:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", cmd_id);
                return -EINVAL;
        }
 
+       return 0;
+}
+
+static int ath6kl_wmi_proc_events(struct wmi *wmi, struct sk_buff *skb)
+{
+       struct wmi_cmd_hdr *cmd;
+       int ret = 0;
+       u32 len;
+       u16 id;
+       u8 if_idx;
+       u8 *datap;
+
        cmd = (struct wmi_cmd_hdr *) skb->data;
        id = le16_to_cpu(cmd->cmd_id);
        if_idx = le16_to_cpu(cmd->info1) & WMI_CMD_HDR_IF_ID_MASK;
 
        skb_pull(skb, sizeof(struct wmi_cmd_hdr));
-
        datap = skb->data;
        len = skb->len;
 
@@ -3403,15 +3537,6 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
        ath6kl_dbg_dump(ATH6KL_DBG_WMI_DUMP, NULL, "wmi rx ",
                        datap, len);
 
-       vif = ath6kl_get_vif_by_index(wmi->parent_dev, if_idx);
-       if (!vif) {
-               ath6kl_dbg(ATH6KL_DBG_WMI,
-                          "Wmi event for unavailable vif, vif_index:%d\n",
-                           if_idx);
-               dev_kfree_skb(skb);
-               return -EINVAL;
-       }
-
        switch (id) {
        case WMI_GET_BITRATE_CMDID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_BITRATE_CMDID\n");
@@ -3429,26 +3554,10 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_READY_EVENTID\n");
                ret = ath6kl_wmi_ready_event_rx(wmi, datap, len);
                break;
-       case WMI_CONNECT_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CONNECT_EVENTID\n");
-               ret = ath6kl_wmi_connect_event_rx(wmi, datap, len, vif);
-               break;
-       case WMI_DISCONNECT_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DISCONNECT_EVENTID\n");
-               ret = ath6kl_wmi_disconnect_event_rx(wmi, datap, len, vif);
-               break;
        case WMI_PEER_NODE_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PEER_NODE_EVENTID\n");
                ret = ath6kl_wmi_peer_node_event_rx(wmi, datap, len);
                break;
-       case WMI_TKIP_MICERR_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TKIP_MICERR_EVENTID\n");
-               ret = ath6kl_wmi_tkip_micerr_event_rx(wmi, datap, len, vif);
-               break;
-       case WMI_BSSINFO_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_BSSINFO_EVENTID\n");
-               ret = ath6kl_wmi_bssinfo_event_rx(wmi, datap, len, vif);
-               break;
        case WMI_REGDOMAIN_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REGDOMAIN_EVENTID\n");
                ath6kl_wmi_regdomain_event(wmi, datap, len);
@@ -3457,23 +3566,10 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSTREAM_TIMEOUT_EVENTID\n");
                ret = ath6kl_wmi_pstream_timeout_event_rx(wmi, datap, len);
                break;
-       case WMI_NEIGHBOR_REPORT_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_NEIGHBOR_REPORT_EVENTID\n");
-               ret = ath6kl_wmi_neighbor_report_event_rx(wmi, datap, len,
-                                                         vif);
-               break;
-       case WMI_SCAN_COMPLETE_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n");
-               ret = ath6kl_wmi_scan_complete_rx(wmi, datap, len, vif);
-               break;
        case WMI_CMDERROR_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CMDERROR_EVENTID\n");
                ret = ath6kl_wmi_error_event_rx(wmi, datap, len);
                break;
-       case WMI_REPORT_STATISTICS_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_STATISTICS_EVENTID\n");
-               ret = ath6kl_wmi_stats_event_rx(wmi, datap, len, vif);
-               break;
        case WMI_RSSI_THRESHOLD_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RSSI_THRESHOLD_EVENTID\n");
                ret = ath6kl_wmi_rssi_threshold_event_rx(wmi, datap, len);
@@ -3493,10 +3589,6 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_EXTENSION_EVENTID\n");
                ret = ath6kl_wmi_control_rx_xtnd(wmi, skb);
                break;
-       case WMI_CAC_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CAC_EVENTID\n");
-               ret = ath6kl_wmi_cac_event_rx(wmi, datap, len, vif);
-               break;
        case WMI_CHANNEL_CHANGE_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CHANNEL_CHANGE_EVENTID\n");
                break;
@@ -3536,28 +3628,12 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_PMKID_LIST_EVENTID\n");
                ret = ath6kl_wmi_get_pmkid_list_event_rx(wmi, datap, len);
                break;
-       case WMI_PSPOLL_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSPOLL_EVENTID\n");
-               ret = ath6kl_wmi_pspoll_event_rx(wmi, datap, len, vif);
-               break;
-       case WMI_DTIMEXPIRY_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DTIMEXPIRY_EVENTID\n");
-               ret = ath6kl_wmi_dtimexpiry_event_rx(wmi, datap, len, vif);
-               break;
        case WMI_SET_PARAMS_REPLY_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SET_PARAMS_REPLY_EVENTID\n");
                break;
-       case WMI_ADDBA_REQ_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_REQ_EVENTID\n");
-               ret = ath6kl_wmi_addba_req_event_rx(wmi, datap, len, vif);
-               break;
        case WMI_ADDBA_RESP_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_RESP_EVENTID\n");
                break;
-       case WMI_DELBA_REQ_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DELBA_REQ_EVENTID\n");
-               ret = ath6kl_wmi_delba_req_event_rx(wmi, datap, len, vif);
-               break;
        case WMI_REPORT_BTCOEX_CONFIG_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI,
                           "WMI_REPORT_BTCOEX_CONFIG_EVENTID\n");
@@ -3570,52 +3646,39 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_COMPLETE_EVENTID\n");
                ret = ath6kl_wmi_tx_complete_event_rx(datap, len);
                break;
-       case WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI,
-                          "WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID");
-               ret = ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx(wmi, vif);
-               break;
-       case WMI_REMAIN_ON_CHNL_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n");
-               ret = ath6kl_wmi_remain_on_chnl_event_rx(wmi, datap, len, vif);
-               break;
-       case WMI_CANCEL_REMAIN_ON_CHNL_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI,
-                          "WMI_CANCEL_REMAIN_ON_CHNL_EVENTID\n");
-               ret = ath6kl_wmi_cancel_remain_on_chnl_event_rx(wmi, datap,
-                                                               len, vif);
-               break;
-       case WMI_TX_STATUS_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n");
-               ret = ath6kl_wmi_tx_status_event_rx(wmi, datap, len, vif);
-               break;
-       case WMI_RX_PROBE_REQ_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n");
-               ret = ath6kl_wmi_rx_probe_req_event_rx(wmi, datap, len, vif);
-               break;
        case WMI_P2P_CAPABILITIES_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_CAPABILITIES_EVENTID\n");
                ret = ath6kl_wmi_p2p_capabilities_event_rx(datap, len);
                break;
-       case WMI_RX_ACTION_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n");
-               ret = ath6kl_wmi_rx_action_event_rx(wmi, datap, len, vif);
-               break;
        case WMI_P2P_INFO_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_INFO_EVENTID\n");
                ret = ath6kl_wmi_p2p_info_event_rx(datap, len);
                break;
        default:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", id);
-               ret = -EINVAL;
+               /* may be the event is interface specific */
+               ret = ath6kl_wmi_proc_events_vif(wmi, if_idx, id, datap, len);
                break;
        }
 
        dev_kfree_skb(skb);
-
        return ret;
 }
 
+/* Control Path */
+int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
+{
+       if (WARN_ON(skb == NULL))
+               return -EINVAL;
+
+       if (skb->len < sizeof(struct wmi_cmd_hdr)) {
+               ath6kl_err("bad packet 1\n");
+               dev_kfree_skb(skb);
+               return -EINVAL;
+       }
+
+       return ath6kl_wmi_proc_events(wmi, skb);
+}
+
 void ath6kl_wmi_reset(struct wmi *wmi)
 {
        spin_lock_bh(&wmi->lock);
index e791986..4092e3e 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2010-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -110,6 +111,8 @@ struct wmi {
        u8 fat_pipe_exist;
        struct ath6kl *parent_dev;
        u8 pwr_mode;
+
+       /* protects fat_pipe_exist and stream_exist_for_ac */
        spinlock_t lock;
        enum htc_endpoint_id ep_id;
        struct sq_threshold_params
@@ -997,6 +1000,12 @@ struct wmi_listen_int_cmd {
        __le16 num_beacons;
 } __packed;
 
+/* WMI_SET_BMISS_TIME_CMDID */
+struct wmi_bmiss_time_cmd {
+       __le16 bmiss_time;
+       __le16 num_beacons;
+};
+
 /* WMI_SET_POWER_MODE_CMDID */
 enum wmi_power_mode {
        REC_POWER = 0x01,
@@ -1014,7 +1023,7 @@ struct wmi_power_mode_cmd {
  */
 enum power_save_fail_event_policy {
        SEND_POWER_SAVE_FAIL_EVENT_ALWAYS = 1,
-       IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN = 2,
+       IGNORE_PS_FAIL_DURING_SCAN = 2,
 };
 
 struct wmi_power_params_cmd {
@@ -1212,7 +1221,7 @@ struct wmi_snr_threshold_params_cmd {
 
 enum wmi_preamble_policy {
        WMI_IGNORE_BARKER_IN_ERP = 0,
-       WMI_DONOT_IGNORE_BARKER_IN_ERP
+       WMI_FOLLOW_BARKER_IN_ERP,
 };
 
 struct wmi_set_lpreamble_cmd {
@@ -2128,6 +2137,10 @@ struct wmi_rx_frame_format_cmd {
        u8 reserved[1];
 } __packed;
 
+struct wmi_ap_hidden_ssid_cmd {
+       u8 hidden_ssid;
+} __packed;
+
 /* AP mode events */
 struct wmi_ap_set_apsd_cmd {
        u8 enable;
@@ -2413,6 +2426,8 @@ int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 if_idx, u8 index, u8 flag,
 int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u8 if_idx,
                                  u16 listen_interval,
                                  u16 listen_beacons);
+int ath6kl_wmi_bmisstime_cmd(struct wmi *wmi, u8 if_idx,
+                            u16 bmiss_time, u16 num_beacons);
 int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 if_idx, u8 pwr_mode);
 int ath6kl_wmi_pmparams_cmd(struct wmi *wmi, u8 if_idx, u16 idle_period,
                            u16 ps_poll_num, u16 dtim_policy,
@@ -2484,6 +2499,7 @@ 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_hidden_ssid(struct wmi *wmi, u8 if_idx, bool enable);
 int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, u8 if_idx,
                                 struct wmi_connect_cmd *p);
 
@@ -2505,9 +2521,6 @@ int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable);
 int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx, u32 freq,
                                  u32 dur);
 
-int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
-                              u32 wait, const u8 *data, u16 data_len);
-
 int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
                               u32 wait, const u8 *data, u16 data_len,
                               u32 no_cck);