#------------------------------------------------------------------------------
-# Copyright (c) 2004-2010 Atheros Communications Inc.
+# Copyright (c) 2004-2011 Atheros Communications Inc.
+# Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
# All rights reserved.
#
#
/*
* 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
/*
* 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
/*
* 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
#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),
.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 = {
.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 */
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;
}
/*
*/
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");
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;
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;
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)
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,
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 &&
*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,
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)
/*
* 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
/*
* 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
/*
* 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
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);
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;
-
ret = ath6kl_init_hw_start(ar);
if (ret) {
ath6kl_err("Failed to start hardware: %d\n", ret);
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]);
- return ret;
+ ret = ath6kl_cfg80211_init(ar);
+ if (ret)
+ goto err_rxbuf_cleanup;
+
+ ret = ath6kl_debug_init(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);
-err_rxbuf_cleanup:
- ath6kl_htc_flush_rx_buf(ar->htc_target);
- ath6kl_cleanup_amsdu_rxbufs(ar);
rtnl_lock();
- ath6kl_cfg80211_vif_cleanup(netdev_priv(ndev));
+
+ /* Add an initial station interface */
+ ndev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0,
+ INFRA_NETWORK);
+
rtnl_unlock();
- wiphy_unregister(ar->wiphy);
+
+ 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);
+
+ return ret;
+
err_debug_init:
ath6kl_debug_cleanup(ar);
-err_node_cleanup:
+err_rxbuf_cleanup:
+ ath6kl_htc_flush_rx_buf(ar->htc_target);
+ ath6kl_cleanup_amsdu_rxbufs(ar);
ath6kl_wmi_shutdown(ar->wmi);
clear_bit(WMI_ENABLED, &ar->flag);
ar->wmi = NULL;
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) {
/*
* 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
#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"
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];
u8 wpa_ie[ATH6KL_MAX_IE];
struct sk_buff_head psq;
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;
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;
/*
* 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
#include "core.h"
-#include <linux/circ_buf.h>
+#include <linux/skbuff.h>
#include <linux/fs.h>
#include <linux/vmalloc.h>
#include <linux/export.h>
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, ...)
.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);
}
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)
{
int 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
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);
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);
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);
}
/*
* 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
/*
* 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
/*
* 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
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]),
ath6kl_warn("Failed to clear debug interrupt: %d\n", ret);
ath6kl_hif_dump_fw_crash(dev->ar);
+ ath6kl_read_fwlogs(dev->ar);
return ret;
}
/*
* 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
u8 *virt_dma_buf;
struct hif_scatter_item scat_list[1];
+
+ u32 scat_q_depth;
};
struct ath6kl_irq_proc_registers {
/*
* 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
#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,
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;
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);
struct htc_packet *packet;
int bundle_sent;
int n_pkts_bundle;
+ u8 ac = WMM_NUM_AC;
spin_lock_bh(&target->tx_lock);
*/
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))
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))
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;
"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);
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
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;
* padding will spill into the next credit buffer
* which is fatal.
*/
- target->tx_bndl_enable = false;
+ target->tx_bndl_mask = 0;
}
}
/*
* 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
#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
u8 seqno;
u32 conn_flags;
struct htc_endpoint_stats ep_st;
+ u16 tx_drop_packet_threshold;
};
struct htc_control_buffer {
/* 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;
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);
/*
* 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
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;
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;
ath6kl_reset_device(ar, ar->target_type, true, true);
clear_bit(WLAN_ENABLED, &ar->flag);
+
+ up(&ar->sem);
}
EXPORT_SYMBOL(ath6kl_stop_txrx);
/*
* 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
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,
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);
* 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)
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)
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;
}
/*
* 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
/* 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;
spinlock_t scat_lock;
bool scatter_enabled;
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;
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.
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);
}
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);
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);
}
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);
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);
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]);
/*
* 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
#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
/*
* 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
/*
* 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
/*
* 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
*/
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.
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 {
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)) {
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);
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);
/*
* 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
/*
* 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
regpair->regDmnEnum);
}
- if (country) {
+ if (country && wmi->parent_dev->wiphy_registered) {
alpha2[0] = country->isoName[0];
alpha2[1] = country->isoName[1];
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)
{
* 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;
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;
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)
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;
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");
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);
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);
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;
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");
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);
/*
* 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
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;
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);
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);