Merge branch 'for-linville' of git://github.com/kvalo/ath6kl

This commit is contained in:
John W. Linville 2011-12-19 14:25:17 -05:00
commit 640f5950a7
22 changed files with 1819 additions and 663 deletions

View File

@ -1,12 +1,29 @@
config ATH6KL
tristate "Atheros ath6kl support"
tristate "Atheros mobile chipsets support"
config ATH6KL_SDIO
tristate "Atheros ath6kl SDIO support"
depends on ATH6KL
depends on MMC
depends on CFG80211
---help---
This module adds support for wireless adapters based on
Atheros AR6003 chipset running over SDIO. If you choose to
build it as a module, it will be called ath6kl. Pls note
that AR6002 and AR6001 are not supported by this driver.
Atheros AR6003 and AR6004 chipsets running over SDIO. If you
choose to build it as a module, it will be called ath6kl_sdio.
Please note that AR6002 and AR6001 are not supported by this
driver.
config ATH6KL_USB
tristate "Atheros ath6kl USB support"
depends on ATH6KL
depends on USB
depends on CFG80211
depends on EXPERIMENTAL
---help---
This module adds support for wireless adapters based on
Atheros AR6004 chipset running over USB. This is still under
implementation and it isn't functional. If you choose to
build it as a module, it will be called ath6kl_usb.
config ATH6KL_DEBUG
bool "Atheros ath6kl debugging"

View File

@ -21,17 +21,30 @@
# Author(s): ="Atheros"
#------------------------------------------------------------------------------
obj-$(CONFIG_ATH6KL) := ath6kl.o
ath6kl-y += debug.o
ath6kl-y += hif.o
ath6kl-y += htc.o
ath6kl-y += bmi.o
ath6kl-y += cfg80211.o
ath6kl-y += init.o
ath6kl-y += main.o
ath6kl-y += txrx.o
ath6kl-y += wmi.o
ath6kl-y += sdio.o
ath6kl-$(CONFIG_NL80211_TESTMODE) += testmode.o
obj-$(CONFIG_ATH6KL_SDIO) := ath6kl_sdio.o
ath6kl_sdio-y += debug.o
ath6kl_sdio-y += hif.o
ath6kl_sdio-y += htc.o
ath6kl_sdio-y += bmi.o
ath6kl_sdio-y += cfg80211.o
ath6kl_sdio-y += init.o
ath6kl_sdio-y += main.o
ath6kl_sdio-y += txrx.o
ath6kl_sdio-y += wmi.o
ath6kl_sdio-y += sdio.o
ath6kl_sdio-$(CONFIG_NL80211_TESTMODE) += testmode.o
obj-$(CONFIG_ATH6KL_USB) += ath6kl_usb.o
ath6kl_usb-y += debug.o
ath6kl_usb-y += hif.o
ath6kl_usb-y += htc.o
ath6kl_usb-y += bmi.o
ath6kl_usb-y += cfg80211.o
ath6kl_usb-y += init.o
ath6kl_usb-y += main.o
ath6kl_usb-y += txrx.o
ath6kl_usb-y += wmi.o
ath6kl_usb-y += usb.o
ath6kl_usb-$(CONFIG_NL80211_TESTMODE) += testmode.o
ccflags-y += -D__CHECK_ENDIAN__

View File

@ -19,165 +19,6 @@
#include "target.h"
#include "debug.h"
static int ath6kl_get_bmi_cmd_credits(struct ath6kl *ar)
{
u32 addr;
unsigned long timeout;
int ret;
ar->bmi.cmd_credits = 0;
/* Read the counter register to get the command credits */
addr = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4;
timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
while (time_before(jiffies, timeout) && !ar->bmi.cmd_credits) {
/*
* Hit the credit counter with a 4-byte access, the first byte
* read will hit the counter and cause a decrement, while the
* remaining 3 bytes has no effect. The rationale behind this
* is to make all HIF accesses 4-byte aligned.
*/
ret = hif_read_write_sync(ar, addr,
(u8 *)&ar->bmi.cmd_credits, 4,
HIF_RD_SYNC_BYTE_INC);
if (ret) {
ath6kl_err("Unable to decrement the command credit count register: %d\n",
ret);
return ret;
}
/* The counter is only 8 bits.
* Ignore anything in the upper 3 bytes
*/
ar->bmi.cmd_credits &= 0xFF;
}
if (!ar->bmi.cmd_credits) {
ath6kl_err("bmi communication timeout\n");
return -ETIMEDOUT;
}
return 0;
}
static int ath6kl_bmi_get_rx_lkahd(struct ath6kl *ar)
{
unsigned long timeout;
u32 rx_word = 0;
int ret = 0;
timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
while (time_before(jiffies, timeout) && !rx_word) {
ret = hif_read_write_sync(ar, RX_LOOKAHEAD_VALID_ADDRESS,
(u8 *)&rx_word, sizeof(rx_word),
HIF_RD_SYNC_BYTE_INC);
if (ret) {
ath6kl_err("unable to read RX_LOOKAHEAD_VALID\n");
return ret;
}
/* all we really want is one bit */
rx_word &= (1 << ENDPOINT1);
}
if (!rx_word) {
ath6kl_err("bmi_recv_buf FIFO empty\n");
return -EINVAL;
}
return ret;
}
static int ath6kl_bmi_send_buf(struct ath6kl *ar, u8 *buf, u32 len)
{
int ret;
u32 addr;
ret = ath6kl_get_bmi_cmd_credits(ar);
if (ret)
return ret;
addr = ar->mbox_info.htc_addr;
ret = hif_read_write_sync(ar, addr, buf, len,
HIF_WR_SYNC_BYTE_INC);
if (ret)
ath6kl_err("unable to send the bmi data to the device\n");
return ret;
}
static int ath6kl_bmi_recv_buf(struct ath6kl *ar, u8 *buf, u32 len)
{
int ret;
u32 addr;
/*
* During normal bootup, small reads may be required.
* Rather than issue an HIF Read and then wait as the Target
* adds successive bytes to the FIFO, we wait here until
* we know that response data is available.
*
* This allows us to cleanly timeout on an unexpected
* Target failure rather than risk problems at the HIF level.
* In particular, this avoids SDIO timeouts and possibly garbage
* data on some host controllers. And on an interconnect
* such as Compact Flash (as well as some SDIO masters) which
* does not provide any indication on data timeout, it avoids
* a potential hang or garbage response.
*
* Synchronization is more difficult for reads larger than the
* size of the MBOX FIFO (128B), because the Target is unable
* to push the 129th byte of data until AFTER the Host posts an
* HIF Read and removes some FIFO data. So for large reads the
* Host proceeds to post an HIF Read BEFORE all the data is
* actually available to read. Fortunately, large BMI reads do
* not occur in practice -- they're supported for debug/development.
*
* So Host/Target BMI synchronization is divided into these cases:
* CASE 1: length < 4
* Should not happen
*
* CASE 2: 4 <= length <= 128
* Wait for first 4 bytes to be in FIFO
* If CONSERVATIVE_BMI_READ is enabled, also wait for
* a BMI command credit, which indicates that the ENTIRE
* response is available in the the FIFO
*
* CASE 3: length > 128
* Wait for the first 4 bytes to be in FIFO
*
* For most uses, a small timeout should be sufficient and we will
* usually see a response quickly; but there may be some unusual
* (debug) cases of BMI_EXECUTE where we want an larger timeout.
* For now, we use an unbounded busy loop while waiting for
* BMI_EXECUTE.
*
* If BMI_EXECUTE ever needs to support longer-latency execution,
* especially in production, this code needs to be enhanced to sleep
* and yield. Also note that BMI_COMMUNICATION_TIMEOUT is currently
* a function of Host processor speed.
*/
if (len >= 4) { /* NB: Currently, always true */
ret = ath6kl_bmi_get_rx_lkahd(ar);
if (ret)
return ret;
}
addr = ar->mbox_info.htc_addr;
ret = hif_read_write_sync(ar, addr, buf, len,
HIF_RD_SYNC_BYTE_INC);
if (ret) {
ath6kl_err("Unable to read the bmi data from the device: %d\n",
ret);
return ret;
}
return 0;
}
int ath6kl_bmi_done(struct ath6kl *ar)
{
int ret;
@ -190,7 +31,7 @@ int ath6kl_bmi_done(struct ath6kl *ar)
ar->bmi.done_sent = true;
ret = ath6kl_bmi_send_buf(ar, (u8 *)&cid, sizeof(cid));
ret = ath6kl_hif_bmi_write(ar, (u8 *)&cid, sizeof(cid));
if (ret) {
ath6kl_err("Unable to send bmi done: %d\n", ret);
return ret;
@ -210,14 +51,20 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar,
return -EACCES;
}
ret = ath6kl_bmi_send_buf(ar, (u8 *)&cid, sizeof(cid));
ret = ath6kl_hif_bmi_write(ar, (u8 *)&cid, sizeof(cid));
if (ret) {
ath6kl_err("Unable to send get target info: %d\n", ret);
return ret;
}
ret = ath6kl_bmi_recv_buf(ar, (u8 *)&targ_info->version,
sizeof(targ_info->version));
if (ar->hif_type == ATH6KL_HIF_TYPE_USB) {
ret = ath6kl_hif_bmi_read(ar, (u8 *)targ_info,
sizeof(*targ_info));
} else {
ret = ath6kl_hif_bmi_read(ar, (u8 *)&targ_info->version,
sizeof(targ_info->version));
}
if (ret) {
ath6kl_err("Unable to recv target info: %d\n", ret);
return ret;
@ -225,7 +72,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar,
if (le32_to_cpu(targ_info->version) == TARGET_VERSION_SENTINAL) {
/* Determine how many bytes are in the Target's targ_info */
ret = ath6kl_bmi_recv_buf(ar,
ret = ath6kl_hif_bmi_read(ar,
(u8 *)&targ_info->byte_count,
sizeof(targ_info->byte_count));
if (ret) {
@ -244,7 +91,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar,
}
/* Read the remainder of the targ_info */
ret = ath6kl_bmi_recv_buf(ar,
ret = ath6kl_hif_bmi_read(ar,
((u8 *)targ_info) +
sizeof(targ_info->byte_count),
sizeof(*targ_info) -
@ -276,8 +123,8 @@ int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
return -EACCES;
}
size = BMI_DATASZ_MAX + sizeof(cid) + sizeof(addr) + sizeof(len);
if (size > MAX_BMI_CMDBUF_SZ) {
size = ar->bmi.max_data_size + sizeof(cid) + sizeof(addr) + sizeof(len);
if (size > ar->bmi.max_cmd_size) {
WARN_ON(1);
return -EINVAL;
}
@ -290,8 +137,8 @@ int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
len_remain = len;
while (len_remain) {
rx_len = (len_remain < BMI_DATASZ_MAX) ?
len_remain : BMI_DATASZ_MAX;
rx_len = (len_remain < ar->bmi.max_data_size) ?
len_remain : ar->bmi.max_data_size;
offset = 0;
memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
offset += sizeof(cid);
@ -300,13 +147,13 @@ int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
memcpy(&(ar->bmi.cmd_buf[offset]), &rx_len, sizeof(rx_len));
offset += sizeof(len);
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
if (ret) {
ath6kl_err("Unable to write to the device: %d\n",
ret);
return ret;
}
ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, rx_len);
ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, rx_len);
if (ret) {
ath6kl_err("Unable to read from the device: %d\n",
ret);
@ -326,7 +173,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
u32 offset;
u32 len_remain, tx_len;
const u32 header = sizeof(cid) + sizeof(addr) + sizeof(len);
u8 aligned_buf[BMI_DATASZ_MAX];
u8 aligned_buf[400];
u8 *src;
if (ar->bmi.done_sent) {
@ -334,12 +181,15 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
return -EACCES;
}
if ((BMI_DATASZ_MAX + header) > MAX_BMI_CMDBUF_SZ) {
if ((ar->bmi.max_data_size + header) > ar->bmi.max_cmd_size) {
WARN_ON(1);
return -EINVAL;
}
memset(ar->bmi.cmd_buf, 0, BMI_DATASZ_MAX + header);
if (WARN_ON(ar->bmi.max_data_size > sizeof(aligned_buf)))
return -E2BIG;
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);
@ -348,7 +198,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
while (len_remain) {
src = &buf[len - len_remain];
if (len_remain < (BMI_DATASZ_MAX - header)) {
if (len_remain < (ar->bmi.max_data_size - header)) {
if (len_remain & 3) {
/* align it with 4 bytes */
len_remain = len_remain +
@ -358,7 +208,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
}
tx_len = len_remain;
} else {
tx_len = (BMI_DATASZ_MAX - header);
tx_len = (ar->bmi.max_data_size - header);
}
offset = 0;
@ -371,7 +221,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
memcpy(&(ar->bmi.cmd_buf[offset]), src, tx_len);
offset += tx_len;
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
if (ret) {
ath6kl_err("Unable to write to the device: %d\n",
ret);
@ -396,7 +246,7 @@ int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param)
}
size = sizeof(cid) + sizeof(addr) + sizeof(param);
if (size > MAX_BMI_CMDBUF_SZ) {
if (size > ar->bmi.max_cmd_size) {
WARN_ON(1);
return -EINVAL;
}
@ -413,13 +263,13 @@ int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param)
memcpy(&(ar->bmi.cmd_buf[offset]), param, sizeof(*param));
offset += sizeof(*param);
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
if (ret) {
ath6kl_err("Unable to write to the device: %d\n", ret);
return ret;
}
ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param));
ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, sizeof(*param));
if (ret) {
ath6kl_err("Unable to read from the device: %d\n", ret);
return ret;
@ -443,7 +293,7 @@ int ath6kl_bmi_set_app_start(struct ath6kl *ar, u32 addr)
}
size = sizeof(cid) + sizeof(addr);
if (size > MAX_BMI_CMDBUF_SZ) {
if (size > ar->bmi.max_cmd_size) {
WARN_ON(1);
return -EINVAL;
}
@ -457,7 +307,7 @@ int ath6kl_bmi_set_app_start(struct ath6kl *ar, u32 addr)
memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
offset += sizeof(addr);
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
if (ret) {
ath6kl_err("Unable to write to the device: %d\n", ret);
return ret;
@ -479,7 +329,7 @@ int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param)
}
size = sizeof(cid) + sizeof(addr);
if (size > MAX_BMI_CMDBUF_SZ) {
if (size > ar->bmi.max_cmd_size) {
WARN_ON(1);
return -EINVAL;
}
@ -493,13 +343,13 @@ int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param)
memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
offset += sizeof(addr);
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
if (ret) {
ath6kl_err("Unable to write to the device: %d\n", ret);
return ret;
}
ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param));
ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, sizeof(*param));
if (ret) {
ath6kl_err("Unable to read from the device: %d\n", ret);
return ret;
@ -522,7 +372,7 @@ int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param)
}
size = sizeof(cid) + sizeof(addr) + sizeof(param);
if (size > MAX_BMI_CMDBUF_SZ) {
if (size > ar->bmi.max_cmd_size) {
WARN_ON(1);
return -EINVAL;
}
@ -540,7 +390,7 @@ int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param)
memcpy(&(ar->bmi.cmd_buf[offset]), &param, sizeof(param));
offset += sizeof(param);
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
if (ret) {
ath6kl_err("Unable to write to the device: %d\n", ret);
return ret;
@ -563,8 +413,8 @@ int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len)
return -EACCES;
}
size = BMI_DATASZ_MAX + header;
if (size > MAX_BMI_CMDBUF_SZ) {
size = ar->bmi.max_data_size + header;
if (size > ar->bmi.max_cmd_size) {
WARN_ON(1);
return -EINVAL;
}
@ -575,8 +425,8 @@ int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len)
len_remain = len;
while (len_remain) {
tx_len = (len_remain < (BMI_DATASZ_MAX - header)) ?
len_remain : (BMI_DATASZ_MAX - header);
tx_len = (len_remain < (ar->bmi.max_data_size - header)) ?
len_remain : (ar->bmi.max_data_size - header);
offset = 0;
memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
@ -587,7 +437,7 @@ int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len)
tx_len);
offset += tx_len;
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
if (ret) {
ath6kl_err("Unable to write to the device: %d\n",
ret);
@ -613,7 +463,7 @@ int ath6kl_bmi_lz_stream_start(struct ath6kl *ar, u32 addr)
}
size = sizeof(cid) + sizeof(addr);
if (size > MAX_BMI_CMDBUF_SZ) {
if (size > ar->bmi.max_cmd_size) {
WARN_ON(1);
return -EINVAL;
}
@ -629,7 +479,7 @@ int ath6kl_bmi_lz_stream_start(struct ath6kl *ar, u32 addr)
memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
offset += sizeof(addr);
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
if (ret) {
ath6kl_err("Unable to start LZ stream to the device: %d\n",
ret);
@ -677,8 +527,13 @@ void ath6kl_bmi_reset(struct ath6kl *ar)
int ath6kl_bmi_init(struct ath6kl *ar)
{
ar->bmi.cmd_buf = kzalloc(MAX_BMI_CMDBUF_SZ, GFP_ATOMIC);
if (WARN_ON(ar->bmi.max_data_size == 0))
return -EINVAL;
/* cmd + addr + len + data_size */
ar->bmi.max_cmd_size = ar->bmi.max_data_size + (sizeof(u32) * 3);
ar->bmi.cmd_buf = kzalloc(ar->bmi.max_cmd_size, GFP_ATOMIC);
if (!ar->bmi.cmd_buf)
return -ENOMEM;

View File

@ -44,12 +44,6 @@
* BMI handles all required Target-side cache flushing.
*/
#define MAX_BMI_CMDBUF_SZ (BMI_DATASZ_MAX + \
(sizeof(u32) * 3 /* cmd + addr + len */))
/* Maximum data size used for BMI transfers */
#define BMI_DATASZ_MAX 256
/* BMI Commands */
#define BMI_NO_COMMAND 0

View File

@ -23,10 +23,8 @@
#include "testmode.h"
static unsigned int ath6kl_p2p;
static unsigned int multi_norm_if_support;
module_param(ath6kl_p2p, uint, 0644);
module_param(multi_norm_if_support, uint, 0644);
#define RATETAB_ENT(_rate, _rateid, _flags) { \
.bitrate = (_rate), \
@ -127,6 +125,37 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = {
#define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */
/* returns true if scheduled scan was stopped */
static bool __ath6kl_cfg80211_sscan_stop(struct ath6kl_vif *vif)
{
struct ath6kl *ar = vif->ar;
if (ar->state != ATH6KL_STATE_SCHED_SCAN)
return false;
del_timer_sync(&vif->sched_scan_timer);
ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_HOST_MODE_AWAKE);
ar->state = ATH6KL_STATE_ON;
return true;
}
static void ath6kl_cfg80211_sscan_disable(struct ath6kl_vif *vif)
{
struct ath6kl *ar = vif->ar;
bool stopped;
stopped = __ath6kl_cfg80211_sscan_stop(vif);
if (!stopped)
return;
cfg80211_sched_scan_stopped(ar->wiphy);
}
static int ath6kl_set_wpa_version(struct ath6kl_vif *vif,
enum nl80211_wpa_versions wpa_version)
{
@ -205,6 +234,10 @@ static int ath6kl_set_cipher(struct ath6kl_vif *vif, u32 cipher, bool ucast)
*ar_cipher = AES_CRYPT;
*ar_cipher_len = 0;
break;
case WLAN_CIPHER_SUITE_SMS4:
*ar_cipher = WAPI_CRYPT;
*ar_cipher_len = 0;
break;
default:
ath6kl_err("cipher 0x%x not supported\n", cipher);
return -ENOTSUPP;
@ -355,7 +388,7 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
if (type == NL80211_IFTYPE_STATION ||
type == NL80211_IFTYPE_AP || type == NL80211_IFTYPE_ADHOC) {
for (i = 0; i < MAX_NUM_VIF; i++) {
for (i = 0; i < ar->vif_max; i++) {
if ((ar->avail_idx_map >> i) & BIT(0)) {
*if_idx = i;
return true;
@ -365,7 +398,7 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
if (type == NL80211_IFTYPE_P2P_CLIENT ||
type == NL80211_IFTYPE_P2P_GO) {
for (i = ar->max_norm_iface; i < MAX_NUM_VIF; i++) {
for (i = ar->max_norm_iface; i < ar->vif_max; i++) {
if ((ar->avail_idx_map >> i) & BIT(0)) {
*if_idx = i;
return true;
@ -382,6 +415,9 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
struct ath6kl *ar = ath6kl_priv(dev);
struct ath6kl_vif *vif = netdev_priv(dev);
int status;
u8 nw_subtype = (ar->p2p) ? SUBTYPE_P2PDEV : SUBTYPE_NONE;
ath6kl_cfg80211_sscan_disable(vif);
vif->sme_state = SME_CONNECTING;
@ -427,9 +463,12 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
if (sme->ie && (sme->ie_len > 0)) {
status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len);
if (status)
if (status) {
up(&ar->sem);
return status;
}
}
} else
ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG;
if (test_bit(CONNECTED, &vif->flags) &&
vif->ssid_len == sme->ssid_len &&
@ -519,6 +558,9 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
vif->nw_type = vif->next_mode;
if (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)
nw_subtype = SUBTYPE_P2PCLIENT;
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
"%s: connect called with authmode %d dot11 auth %d"
" PW crypto %d PW crypto len %d GRP crypto %d"
@ -536,7 +578,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
vif->grp_crypto, vif->grp_crypto_len,
vif->ssid_len, vif->ssid,
vif->req_bssid, vif->ch_hint,
ar->connect_ctrl_flags);
ar->connect_ctrl_flags, nw_subtype);
up(&ar->sem);
@ -563,17 +605,28 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
return 0;
}
static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, const u8 *bssid,
static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
enum network_type nw_type,
const u8 *bssid,
struct ieee80211_channel *chan,
const u8 *beacon_ie, size_t beacon_ie_len)
{
struct ath6kl *ar = vif->ar;
struct cfg80211_bss *bss;
u16 cap_mask, cap_val;
u8 *ie;
if (nw_type & ADHOC_NETWORK) {
cap_mask = WLAN_CAPABILITY_IBSS;
cap_val = WLAN_CAPABILITY_IBSS;
} else {
cap_mask = WLAN_CAPABILITY_ESS;
cap_val = WLAN_CAPABILITY_ESS;
}
bss = cfg80211_get_bss(ar->wiphy, chan, bssid,
vif->ssid, vif->ssid_len, WLAN_CAPABILITY_ESS,
WLAN_CAPABILITY_ESS);
vif->ssid, vif->ssid_len,
cap_mask, cap_val);
if (bss == NULL) {
/*
* Since cfg80211 may not yet know about the BSS,
@ -591,13 +644,12 @@ static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, const u8 *bssid,
memcpy(ie + 2, vif->ssid, vif->ssid_len);
memcpy(ie + 2 + vif->ssid_len, beacon_ie, beacon_ie_len);
bss = cfg80211_inform_bss(ar->wiphy, chan,
bssid, 0, WLAN_CAPABILITY_ESS, 100,
bssid, 0, cap_val, 100,
ie, 2 + vif->ssid_len + beacon_ie_len,
0, GFP_KERNEL);
if (bss)
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added dummy bss for "
"%pM prior to indicating connect/roamed "
"event\n", bssid);
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added bss %pM to "
"cfg80211\n", bssid);
kfree(ie);
} else
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss "
@ -660,16 +712,16 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
chan = ieee80211_get_channel(ar->wiphy, (int) channel);
if (nw_type & ADHOC_NETWORK) {
cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
if (ath6kl_add_bss_if_needed(vif, nw_type, bssid, chan, assoc_info,
beacon_ie_len) < 0) {
ath6kl_err("could not add cfg80211 bss entry\n");
return;
}
if (ath6kl_add_bss_if_needed(vif, bssid, chan, assoc_info,
beacon_ie_len) < 0) {
ath6kl_err("could not add cfg80211 bss entry for "
"connect/roamed notification\n");
if (nw_type & ADHOC_NETWORK) {
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",
nw_type & ADHOC_CREATOR ? "creator" : "joiner");
cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
return;
}
@ -691,12 +743,14 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
struct net_device *dev, u16 reason_code)
{
struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
struct ath6kl *ar = ath6kl_priv(dev);
struct ath6kl_vif *vif = netdev_priv(dev);
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
reason_code);
ath6kl_cfg80211_sscan_disable(vif);
if (!ath6kl_cfg80211_ready(vif))
return -EIO;
@ -789,7 +843,7 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
struct cfg80211_scan_request *request)
{
struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
struct ath6kl *ar = ath6kl_priv(ndev);
struct ath6kl_vif *vif = netdev_priv(ndev);
s8 n_channels = 0;
u16 *channels = NULL;
@ -799,6 +853,8 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
if (!ath6kl_cfg80211_ready(vif))
return -EIO;
ath6kl_cfg80211_sscan_disable(vif);
if (!ar->usr_bss_filter) {
clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
ret = ath6kl_wmi_bssfilter_cmd(
@ -824,6 +880,10 @@ 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,
@ -860,9 +920,25 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
if (test_bit(CONNECTED, &vif->flags))
force_fg_scan = 1;
ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, WMI_LONG_SCAN,
force_fg_scan, false, 0, 0, n_channels,
channels);
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
*/
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,
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);
}
if (ret)
ath6kl_err("wmi_startscan_cmd failed\n");
else
@ -905,7 +981,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
const u8 *mac_addr,
struct key_params *params)
{
struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
struct ath6kl *ar = ath6kl_priv(ndev);
struct ath6kl_vif *vif = netdev_priv(ndev);
struct ath6kl_key *key = NULL;
u8 key_usage;
@ -937,13 +1013,19 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
key_usage = GROUP_USAGE;
if (params) {
int seq_len = params->seq_len;
if (params->cipher == WLAN_CIPHER_SUITE_SMS4 &&
seq_len > ATH6KL_KEY_SEQ_LEN) {
/* Only first half of the WPI PN is configured */
seq_len = ATH6KL_KEY_SEQ_LEN;
}
if (params->key_len > WLAN_MAX_KEY_LEN ||
params->seq_len > sizeof(key->seq))
seq_len > sizeof(key->seq))
return -EINVAL;
key->key_len = params->key_len;
memcpy(key->key, params->key, key->key_len);
key->seq_len = params->seq_len;
key->seq_len = seq_len;
memcpy(key->seq, params->seq, key->seq_len);
key->cipher = params->cipher;
}
@ -961,6 +1043,9 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
case WLAN_CIPHER_SUITE_CCMP:
key_type = AES_CRYPT;
break;
case WLAN_CIPHER_SUITE_SMS4:
key_type = WAPI_CRYPT;
break;
default:
return -ENOTSUPP;
@ -976,10 +1061,9 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
__func__, key_index, key->key_len, key_type,
key_usage, key->seq_len);
vif->def_txkey_index = key_index;
if (vif->nw_type == AP_NETWORK && !pairwise &&
(key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
(key_type == TKIP_CRYPT || key_type == AES_CRYPT ||
key_type == WAPI_CRYPT) && params) {
ar->ap_mode_bkey.valid = true;
ar->ap_mode_bkey.key_index = key_index;
ar->ap_mode_bkey.key_type = key_type;
@ -1012,8 +1096,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
return 0;
}
return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
vif->def_txkey_index,
return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, key_index,
key_type, key_usage, key->key_len,
key->seq, key->seq_len, key->key,
KEY_OP_INIT_VAL,
@ -1024,7 +1107,7 @@ static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
u8 key_index, bool pairwise,
const u8 *mac_addr)
{
struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
struct ath6kl *ar = ath6kl_priv(ndev);
struct ath6kl_vif *vif = netdev_priv(ndev);
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
@ -1090,7 +1173,7 @@ static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
u8 key_index, bool unicast,
bool multicast)
{
struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
struct ath6kl *ar = ath6kl_priv(ndev);
struct ath6kl_vif *vif = netdev_priv(ndev);
struct ath6kl_key *key = NULL;
u8 key_usage;
@ -1181,11 +1264,12 @@ static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
*/
static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
enum nl80211_tx_power_setting type,
int dbm)
int mbm)
{
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__,
type, dbm);
@ -1288,7 +1372,7 @@ static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
struct net_device *ndev;
u8 if_idx, nw_type;
if (ar->num_vif == MAX_NUM_VIF) {
if (ar->num_vif == ar->vif_max) {
ath6kl_err("Reached maximum number of supported vif\n");
return ERR_PTR(-EINVAL);
}
@ -1333,9 +1417,6 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
if (!ath6kl_cfg80211_ready(vif))
return -EIO;
switch (type) {
case NL80211_IFTYPE_STATION:
vif->next_mode = INFRA_NETWORK;
@ -1426,7 +1507,7 @@ static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
vif->grp_crypto, vif->grp_crypto_len,
vif->ssid_len, vif->ssid,
vif->req_bssid, vif->ch_hint,
ar->connect_ctrl_flags);
ar->connect_ctrl_flags, SUBTYPE_NONE);
set_bit(CONNECT_PEND, &vif->flags);
return 0;
@ -1453,6 +1534,7 @@ static const u32 cipher_suites[] = {
WLAN_CIPHER_SUITE_TKIP,
WLAN_CIPHER_SUITE_CCMP,
CCKM_KRK_CIPHER_SUITE,
WLAN_CIPHER_SUITE_SMS4,
};
static bool is_rate_legacy(s32 rate)
@ -1779,7 +1861,7 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
case ATH6KL_CFG_SUSPEND_DEEPSLEEP:
ath6kl_cfg80211_stop(ar);
ath6kl_cfg80211_stop_all(ar);
/* save the current power mode before enabling power save */
ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
@ -1796,7 +1878,7 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
case ATH6KL_CFG_SUSPEND_CUTPOWER:
ath6kl_cfg80211_stop(ar);
ath6kl_cfg80211_stop_all(ar);
if (ar->state == ATH6KL_STATE_OFF) {
ath6kl_dbg(ATH6KL_DBG_SUSPEND,
@ -1816,6 +1898,13 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
break;
case ATH6KL_CFG_SUSPEND_SCHED_SCAN:
/*
* Nothing needed for schedule scan, firmware is already in
* wow mode and sleeping most of the time.
*/
break;
default:
break;
}
@ -1864,6 +1953,9 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar)
}
break;
case ATH6KL_STATE_SCHED_SCAN:
break;
default:
break;
}
@ -1987,7 +2079,7 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
int ies_len;
struct wmi_connect_cmd p;
int res;
int i;
int i, ret;
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
@ -2045,7 +2137,9 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
return -EOPNOTSUPP; /* TODO */
vif->dot11_auth_mode = OPEN_AUTH;
ret = ath6kl_set_auth_type(vif, info->auth_type);
if (ret)
return ret;
memset(&p, 0, sizeof(p));
@ -2081,6 +2175,9 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
case WLAN_CIPHER_SUITE_CCMP:
p.prwise_crypto_type |= AES_CRYPT;
break;
case WLAN_CIPHER_SUITE_SMS4:
p.prwise_crypto_type |= WAPI_CRYPT;
break;
}
}
if (p.prwise_crypto_type == 0) {
@ -2100,6 +2197,9 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
case WLAN_CIPHER_SUITE_CCMP:
p.grp_crypto_type = AES_CRYPT;
break;
case WLAN_CIPHER_SUITE_SMS4:
p.grp_crypto_type = WAPI_CRYPT;
break;
default:
p.grp_crypto_type = NONE_CRYPT;
break;
@ -2114,6 +2214,16 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
p.dot11_auth_mode = vif->dot11_auth_mode;
p.ch = cpu_to_le16(vif->next_chan);
if (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
p.nw_subtype = SUBTYPE_P2PGO;
} else {
/*
* Due to firmware limitation, it is not possible to
* do P2P mgmt operations in AP mode
*/
p.nw_subtype = SUBTYPE_NONE;
}
res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
if (res < 0)
return res;
@ -2279,9 +2389,23 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
}
*cookie = id;
return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id,
chan->center_freq, wait,
buf, len);
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);
}
}
static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
@ -2302,6 +2426,90 @@ static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
}
}
static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_sched_scan_request *request)
{
struct ath6kl *ar = ath6kl_priv(dev);
struct ath6kl_vif *vif = netdev_priv(dev);
u16 interval;
int ret;
u8 i;
if (ar->state != ATH6KL_STATE_ON)
return -EIO;
if (vif->sme_state != SME_DISCONNECTED)
return -EBUSY;
for (i = 0; i < ar->wiphy->max_sched_scan_ssids; i++) {
ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
i, DISABLE_SSID_FLAG,
0, NULL);
}
/* fw uses seconds, also make sure that it's >0 */
interval = max_t(u16, 1, request->interval / 1000);
ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
interval, interval,
10, 0, 0, 0, 3, 0, 0, 0);
if (request->n_ssids && request->ssids[0].ssid_len) {
for (i = 0; i < request->n_ssids; i++) {
ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
i, SPECIFIC_SSID_FLAG,
request->ssids[i].ssid_len,
request->ssids[i].ssid);
}
}
ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_WOW_MODE_ENABLE,
WOW_FILTER_SSID,
WOW_HOST_REQ_DELAY);
if (ret) {
ath6kl_warn("Failed to enable wow with ssid filter: %d\n", ret);
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_warn("Failed to set probe request IE for scheduled scan: %d",
ret);
return ret;
}
ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_HOST_MODE_ASLEEP);
if (ret) {
ath6kl_warn("Failed to enable host sleep mode for sched scan: %d\n",
ret);
return ret;
}
ar->state = ATH6KL_STATE_SCHED_SCAN;
return ret;
}
static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy,
struct net_device *dev)
{
struct ath6kl_vif *vif = netdev_priv(dev);
bool stopped;
stopped = __ath6kl_cfg80211_sscan_stop(vif);
if (!stopped)
return -EIO;
return 0;
}
static const struct ieee80211_txrx_stypes
ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
[NL80211_IFTYPE_STATION] = {
@ -2359,13 +2567,48 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
.cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
.mgmt_tx = ath6kl_mgmt_tx,
.mgmt_frame_register = ath6kl_mgmt_frame_register,
.sched_scan_start = ath6kl_cfg80211_sscan_start,
.sched_scan_stop = ath6kl_cfg80211_sscan_stop,
};
void ath6kl_cfg80211_stop(struct ath6kl *ar)
void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
{
ath6kl_cfg80211_sscan_disable(vif);
switch (vif->sme_state) {
case SME_DISCONNECTED:
break;
case SME_CONNECTING:
cfg80211_connect_result(vif->ndev, vif->bssid, NULL, 0,
NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL);
break;
case SME_CONNECTED:
cfg80211_disconnected(vif->ndev, 0, NULL, 0, GFP_KERNEL);
break;
}
if (test_bit(CONNECTED, &vif->flags) ||
test_bit(CONNECT_PEND, &vif->flags))
ath6kl_wmi_disconnect_cmd(vif->ar->wmi, vif->fw_vif_idx);
vif->sme_state = SME_DISCONNECTED;
clear_bit(CONNECTED, &vif->flags);
clear_bit(CONNECT_PEND, &vif->flags);
/* disable scanning */
if (ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF,
0, 0, 0, 0, 0, 0, 0, 0, 0) != 0)
ath6kl_warn("failed to disable scan during stop\n");
ath6kl_cfg80211_scan_complete_event(vif, true);
}
void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
{
struct ath6kl_vif *vif;
/* FIXME: for multi vif */
vif = ath6kl_vif_first(ar);
if (!vif) {
/* save the current power mode before enabling power save */
@ -2377,39 +2620,13 @@ void ath6kl_cfg80211_stop(struct ath6kl *ar)
return;
}
switch (vif->sme_state) {
case SME_CONNECTING:
cfg80211_connect_result(vif->ndev, vif->bssid, NULL, 0,
NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL);
break;
case SME_CONNECTED:
default:
/*
* FIXME: oddly enough smeState is in DISCONNECTED during
* suspend, why? Need to send disconnected event in that
* state.
*/
cfg80211_disconnected(vif->ndev, 0, NULL, 0, GFP_KERNEL);
break;
}
if (test_bit(CONNECTED, &vif->flags) ||
test_bit(CONNECT_PEND, &vif->flags))
ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
vif->sme_state = SME_DISCONNECTED;
clear_bit(CONNECTED, &vif->flags);
clear_bit(CONNECT_PEND, &vif->flags);
/* disable scanning */
if (ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0xFFFF, 0, 0,
0, 0, 0, 0, 0, 0, 0) != 0)
printk(KERN_WARNING "ath6kl: failed to disable scan "
"during suspend\n");
ath6kl_cfg80211_scan_complete_event(vif, true);
/*
* FIXME: we should take ar->list_lock to protect changes in the
* vif_list, but that's not trivial to do as ath6kl_cfg80211_stop()
* sleeps.
*/
list_for_each_entry(vif, &ar->vif_list, list)
ath6kl_cfg80211_stop(vif);
}
struct ath6kl *ath6kl_core_alloc(struct device *dev)
@ -2427,17 +2644,12 @@ struct ath6kl *ath6kl_core_alloc(struct device *dev)
}
ar = wiphy_priv(wiphy);
if (!multi_norm_if_support)
ar->p2p = !!ath6kl_p2p;
ar->p2p = !!ath6kl_p2p;
ar->wiphy = wiphy;
ar->dev = dev;
if (multi_norm_if_support)
ar->max_norm_iface = 2;
else
ar->max_norm_iface = 1;
ar->vif_max = 1;
/* FIXME: Remove this once the multivif support is enabled */
ar->max_norm_iface = 1;
spin_lock_init(&ar->lock);
@ -2459,9 +2671,6 @@ struct ath6kl *ath6kl_core_alloc(struct device *dev)
ar->tx_pwr = 0;
ar->intra_bss = 1;
memset(&ar->sc_params, 0, sizeof(ar->sc_params));
ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT;
ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS;
ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
ar->state = ATH6KL_STATE_OFF;
@ -2522,6 +2731,8 @@ int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
wiphy->wowlan.pattern_min_len = 1;
wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
wiphy->max_sched_scan_ssids = 10;
ret = wiphy_register(wiphy);
if (ret < 0) {
ath6kl_err("couldn't register wiphy device\n");
@ -2541,6 +2752,9 @@ static int ath6kl_init_if_data(struct ath6kl_vif *vif)
setup_timer(&vif->disconnect_timer, disconnect_timer_handler,
(unsigned long) vif->ndev);
setup_timer(&vif->sched_scan_timer, ath6kl_wmi_sscan_timer,
(unsigned long) vif);
set_bit(WMM_ENABLED, &vif->flags);
spin_lock_init(&vif->if_lock);

View File

@ -20,7 +20,8 @@
enum ath6kl_cfg_suspend_mode {
ATH6KL_CFG_SUSPEND_DEEPSLEEP,
ATH6KL_CFG_SUSPEND_CUTPOWER,
ATH6KL_CFG_SUSPEND_WOW
ATH6KL_CFG_SUSPEND_WOW,
ATH6KL_CFG_SUSPEND_SCHED_SCAN,
};
struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
@ -52,6 +53,7 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
int ath6kl_cfg80211_resume(struct ath6kl *ar);
void ath6kl_cfg80211_stop(struct ath6kl *ar);
void ath6kl_cfg80211_stop(struct ath6kl_vif *vif);
void ath6kl_cfg80211_stop_all(struct ath6kl *ar);
#endif /* ATH6KL_CFG80211_H */

View File

@ -71,6 +71,7 @@ enum crypto_type {
WEP_CRYPT = 0x02,
TKIP_CRYPT = 0x04,
AES_CRYPT = 0x08,
WAPI_CRYPT = 0x10,
};
struct htc_endpoint_credit_dist;

View File

@ -70,10 +70,20 @@ enum ath6kl_fw_ie_type {
ATH6KL_FW_IE_RESERVED_RAM_SIZE = 5,
ATH6KL_FW_IE_CAPABILITIES = 6,
ATH6KL_FW_IE_PATCH_ADDR = 7,
ATH6KL_FW_IE_BOARD_ADDR = 8,
ATH6KL_FW_IE_VIF_MAX = 9,
};
enum ath6kl_fw_capability {
ATH6KL_FW_CAPABILITY_HOST_P2P = 0,
ATH6KL_FW_CAPABILITY_SCHED_SCAN = 1,
/*
* Firmware is capable of supporting P2P mgmt operations on a
* station interface. After group formation, the station
* interface will become a P2P client/GO interface as the case may be
*/
ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
/* this needs to be last */
ATH6KL_FW_CAPABILITY_MAX,
@ -88,37 +98,47 @@ struct ath6kl_fw_ie {
};
/* AR6003 1.0 definitions */
#define AR6003_REV1_VERSION 0x300002ba
#define AR6003_HW_1_0_VERSION 0x300002ba
/* AR6003 2.0 definitions */
#define AR6003_REV2_VERSION 0x30000384
#define AR6003_REV2_PATCH_DOWNLOAD_ADDRESS 0x57e910
#define AR6003_REV2_OTP_FILE "ath6k/AR6003/hw2.0/otp.bin.z77"
#define AR6003_REV2_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athwlan.bin.z77"
#define AR6003_REV2_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athtcmd_ram.bin"
#define AR6003_REV2_PATCH_FILE "ath6k/AR6003/hw2.0/data.patch.bin"
#define AR6003_REV2_FIRMWARE_2_FILE "ath6k/AR6003/hw2.0/fw-2.bin"
#define AR6003_REV2_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin"
#define AR6003_REV2_DEFAULT_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.SD31.bin"
#define AR6003_HW_2_0_VERSION 0x30000384
#define AR6003_HW_2_0_PATCH_DOWNLOAD_ADDRESS 0x57e910
#define AR6003_HW_2_0_OTP_FILE "ath6k/AR6003/hw2.0/otp.bin.z77"
#define AR6003_HW_2_0_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athwlan.bin.z77"
#define AR6003_HW_2_0_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athtcmd_ram.bin"
#define AR6003_HW_2_0_PATCH_FILE "ath6k/AR6003/hw2.0/data.patch.bin"
#define AR6003_HW_2_0_FIRMWARE_2_FILE "ath6k/AR6003/hw2.0/fw-2.bin"
#define AR6003_HW_2_0_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin"
#define AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE \
"ath6k/AR6003/hw2.0/bdata.SD31.bin"
/* AR6003 3.0 definitions */
#define AR6003_REV3_VERSION 0x30000582
#define AR6003_REV3_OTP_FILE "ath6k/AR6003/hw2.1.1/otp.bin"
#define AR6003_REV3_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athwlan.bin"
#define AR6003_REV3_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athtcmd_ram.bin"
#define AR6003_REV3_PATCH_FILE "ath6k/AR6003/hw2.1.1/data.patch.bin"
#define AR6003_REV3_FIRMWARE_2_FILE "ath6k/AR6003/hw2.1.1/fw-2.bin"
#define AR6003_REV3_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin"
#define AR6003_REV3_DEFAULT_BOARD_DATA_FILE \
"ath6k/AR6003/hw2.1.1/bdata.SD31.bin"
#define AR6003_HW_2_1_1_VERSION 0x30000582
#define AR6003_HW_2_1_1_OTP_FILE "ath6k/AR6003/hw2.1.1/otp.bin"
#define AR6003_HW_2_1_1_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athwlan.bin"
#define AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE \
"ath6k/AR6003/hw2.1.1/athtcmd_ram.bin"
#define AR6003_HW_2_1_1_PATCH_FILE "ath6k/AR6003/hw2.1.1/data.patch.bin"
#define AR6003_HW_2_1_1_FIRMWARE_2_FILE "ath6k/AR6003/hw2.1.1/fw-2.bin"
#define AR6003_HW_2_1_1_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin"
#define AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE \
"ath6k/AR6003/hw2.1.1/bdata.SD31.bin"
/* AR6004 1.0 definitions */
#define AR6004_REV1_VERSION 0x30000623
#define AR6004_REV1_FIRMWARE_FILE "ath6k/AR6004/hw6.1/fw.ram.bin"
#define AR6004_REV1_FIRMWARE_2_FILE "ath6k/AR6004/hw6.1/fw-2.bin"
#define AR6004_REV1_BOARD_DATA_FILE "ath6k/AR6004/hw6.1/bdata.bin"
#define AR6004_REV1_DEFAULT_BOARD_DATA_FILE "ath6k/AR6004/hw6.1/bdata.DB132.bin"
#define AR6004_REV1_EPPING_FIRMWARE_FILE "ath6k/AR6004/hw6.1/endpointping.bin"
#define AR6004_HW_1_0_VERSION 0x30000623
#define AR6004_HW_1_0_FIRMWARE_2_FILE "ath6k/AR6004/hw1.0/fw-2.bin"
#define AR6004_HW_1_0_FIRMWARE_FILE "ath6k/AR6004/hw1.0/fw.ram.bin"
#define AR6004_HW_1_0_BOARD_DATA_FILE "ath6k/AR6004/hw1.0/bdata.bin"
#define AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE \
"ath6k/AR6004/hw1.0/bdata.DB132.bin"
/* AR6004 1.1 definitions */
#define AR6004_HW_1_1_VERSION 0x30000001
#define AR6004_HW_1_1_FIRMWARE_2_FILE "ath6k/AR6004/hw1.1/fw-2.bin"
#define AR6004_HW_1_1_FIRMWARE_FILE "ath6k/AR6004/hw1.1/fw.ram.bin"
#define AR6004_HW_1_1_BOARD_DATA_FILE "ath6k/AR6004/hw1.1/bdata.bin"
#define AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE \
"ath6k/AR6004/hw1.1/bdata.DB132.bin"
/* Per STA data, used in AP mode */
#define STA_PS_AWAKE BIT(0)
@ -272,6 +292,8 @@ struct ath6kl_bmi {
u32 cmd_credits;
bool done_sent;
u8 *cmd_buf;
u32 max_data_size;
u32 max_cmd_size;
};
struct target_stats {
@ -381,7 +403,16 @@ struct ath6kl_req_key {
u8 key_len;
};
#define MAX_NUM_VIF 1
enum ath6kl_hif_type {
ATH6KL_HIF_TYPE_SDIO,
ATH6KL_HIF_TYPE_USB,
};
/*
* Driver's maximum limit, note that some firmwares support only one vif
* and the runtime (current) limit must be checked from ar->vif_max.
*/
#define ATH6KL_VIF_MAX 3
/* vif flags info */
enum ath6kl_vif_state {
@ -424,7 +455,10 @@ struct ath6kl_vif {
struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1];
struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1];
struct aggr_info *aggr_cntxt;
struct timer_list disconnect_timer;
struct timer_list sched_scan_timer;
struct cfg80211_scan_request *scan_req;
enum sme_state sme_state;
int reconnect_flag;
@ -442,6 +476,8 @@ struct ath6kl_vif {
#define WOW_LIST_ID 0
#define WOW_HOST_REQ_DELAY 500 /* ms */
#define ATH6KL_SCHED_SCAN_RESULT_DELAY 5000 /* ms */
/* Flag info */
enum ath6kl_dev_state {
WMI_ENABLED,
@ -460,6 +496,7 @@ enum ath6kl_state {
ATH6KL_STATE_DEEPSLEEP,
ATH6KL_STATE_CUTPOWER,
ATH6KL_STATE_WOW,
ATH6KL_STATE_SCHED_SCAN,
};
struct ath6kl {
@ -474,11 +511,13 @@ struct ath6kl {
int tx_pending[ENDPOINT_MAX];
int total_tx_data_pend;
struct htc_target *htc_target;
enum ath6kl_hif_type hif_type;
void *hif_priv;
struct list_head vif_list;
/* Lock to avoid race in vif_list entries among add/del/traverse */
spinlock_t list_lock;
u8 num_vif;
unsigned int vif_max;
u8 max_norm_iface;
u8 avail_idx_map;
spinlock_t lock;
@ -517,7 +556,6 @@ struct ath6kl {
struct list_head amsdu_rx_buffer_queue;
u8 rx_meta_ver;
enum wlan_low_pwr_state wlan_pwr_state;
struct wmi_scan_params_cmd sc_params;
u8 mac_addr[ETH_ALEN];
#define AR_MCAST_FILTER_MAC_ADDR_SIZE 4
struct {
@ -525,12 +563,25 @@ struct ath6kl {
size_t rx_report_len;
} tm;
struct {
struct ath6kl_hw {
u32 id;
const char *name;
u32 dataset_patch_addr;
u32 app_load_addr;
u32 app_start_override_addr;
u32 board_ext_data_addr;
u32 reserved_ram_size;
u32 board_addr;
u32 refclk_hz;
u32 uarttx_pin;
const char *fw_otp;
const char *fw;
const char *fw_tcmd;
const char *fw_patch;
const char *fw_api2;
const char *fw_board;
const char *fw_default_board;
} hw;
u16 conf_flags;
@ -583,7 +634,7 @@ struct ath6kl {
#endif /* CONFIG_ATH6KL_DEBUG */
};
static inline void *ath6kl_priv(struct net_device *dev)
static inline struct ath6kl *ath6kl_priv(struct net_device *dev)
{
return ((struct ath6kl_vif *) netdev_priv(dev))->ar;
}

View File

@ -1551,10 +1551,10 @@ static ssize_t ath6kl_listen_int_read(struct file *file,
size_t count, loff_t *ppos)
{
struct ath6kl *ar = file->private_data;
char buf[16];
char buf[32];
int len;
len = snprintf(buf, sizeof(buf), "%u %u\n", ar->listen_intvl_t,
len = scnprintf(buf, sizeof(buf), "%u %u\n", ar->listen_intvl_t,
ar->listen_intvl_b);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);

View File

@ -41,6 +41,7 @@ enum ATH6K_DEBUG_MASK {
ATH6KL_DBG_BOOT = BIT(18), /* driver init and fw boot */
ATH6KL_DBG_WMI_DUMP = BIT(19),
ATH6KL_DBG_SUSPEND = BIT(20),
ATH6KL_DBG_USB = BIT(21),
ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */
};

View File

@ -91,6 +91,36 @@ static inline int ath6kl_hif_suspend(struct ath6kl *ar,
return ar->hif_ops->suspend(ar, wow);
}
/*
* Read from the ATH6KL through its diagnostic window. No cooperation from
* the Target is required for this.
*/
static inline int ath6kl_hif_diag_read32(struct ath6kl *ar, u32 address,
u32 *value)
{
return ar->hif_ops->diag_read32(ar, address, value);
}
/*
* Write to the ATH6KL through its diagnostic window. No cooperation from
* the Target is required for this.
*/
static inline int ath6kl_hif_diag_write32(struct ath6kl *ar, u32 address,
__le32 value)
{
return ar->hif_ops->diag_write32(ar, address, value);
}
static inline int ath6kl_hif_bmi_read(struct ath6kl *ar, u8 *buf, u32 len)
{
return ar->hif_ops->bmi_read(ar, buf, len);
}
static inline int ath6kl_hif_bmi_write(struct ath6kl *ar, u8 *buf, u32 len)
{
return ar->hif_ops->bmi_write(ar, buf, len);
}
static inline int ath6kl_hif_resume(struct ath6kl *ar)
{
ath6kl_dbg(ATH6KL_DBG_HIF, "hif resume\n");

View File

@ -689,6 +689,11 @@ int ath6kl_hif_setup(struct ath6kl_device *dev)
ath6kl_dbg(ATH6KL_DBG_HIF, "hif block size %d mbox addr 0x%x\n",
dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr);
/* usb doesn't support enabling interrupts */
/* FIXME: remove check once USB support is implemented */
if (dev->ar->hif_type == ATH6KL_HIF_TYPE_USB)
return 0;
status = ath6kl_hif_disable_intrs(dev);
fail_setup:

View File

@ -35,6 +35,7 @@
#define MAX_SCATTER_REQ_TRANSFER_SIZE (32 * 1024)
#define MANUFACTURER_ID_AR6003_BASE 0x300
#define MANUFACTURER_ID_AR6004_BASE 0x400
/* SDIO manufacturer ID and Codes */
#define MANUFACTURER_ID_ATH6KL_BASE_MASK 0xFF00
#define MANUFACTURER_CODE 0x271 /* Atheros */
@ -244,6 +245,10 @@ struct ath6kl_hif_ops {
void (*cleanup_scatter)(struct ath6kl *ar);
int (*suspend)(struct ath6kl *ar, struct cfg80211_wowlan *wow);
int (*resume)(struct ath6kl *ar);
int (*diag_read32)(struct ath6kl *ar, u32 address, u32 *value);
int (*diag_write32)(struct ath6kl *ar, u32 address, __le32 value);
int (*bmi_read)(struct ath6kl *ar, u8 *buf, u32 len);
int (*bmi_write)(struct ath6kl *ar, u8 *buf, u32 len);
int (*power_on)(struct ath6kl *ar);
int (*power_off)(struct ath6kl *ar);
void (*stop)(struct ath6kl *ar);

View File

@ -2543,6 +2543,12 @@ int ath6kl_htc_wait_target(struct htc_target *target)
struct htc_service_connect_resp resp;
int status;
/* FIXME: remove once USB support is implemented */
if (target->dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) {
ath6kl_err("HTC doesn't support USB yet. Patience!\n");
return -EOPNOTSUPP;
}
/* we should be getting 1 control message that the target is ready */
packet = htc_wait_for_ctrl_msg(target);
@ -2772,7 +2778,9 @@ void ath6kl_htc_cleanup(struct htc_target *target)
{
struct htc_packet *packet, *tmp_packet;
ath6kl_hif_cleanup_scatter(target->dev->ar);
/* FIXME: remove check once USB support is implemented */
if (target->dev->ar->hif_type != ATH6KL_HIF_TYPE_USB)
ath6kl_hif_cleanup_scatter(target->dev->ar);
list_for_each_entry_safe(packet, tmp_packet,
&target->free_ctrl_txbuf, list) {

View File

@ -33,6 +33,80 @@ module_param(debug_mask, uint, 0644);
module_param(testmode, uint, 0644);
module_param(suspend_cutpower, bool, 0444);
static const struct ath6kl_hw hw_list[] = {
{
.id = AR6003_HW_2_0_VERSION,
.name = "ar6003 hw 2.0",
.dataset_patch_addr = 0x57e884,
.app_load_addr = 0x543180,
.board_ext_data_addr = 0x57e500,
.reserved_ram_size = 6912,
.refclk_hz = 26000000,
.uarttx_pin = 8,
/* hw2.0 needs override address hardcoded */
.app_start_override_addr = 0x944C00,
.fw_otp = AR6003_HW_2_0_OTP_FILE,
.fw = AR6003_HW_2_0_FIRMWARE_FILE,
.fw_tcmd = AR6003_HW_2_0_TCMD_FIRMWARE_FILE,
.fw_patch = AR6003_HW_2_0_PATCH_FILE,
.fw_api2 = AR6003_HW_2_0_FIRMWARE_2_FILE,
.fw_board = AR6003_HW_2_0_BOARD_DATA_FILE,
.fw_default_board = AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE,
},
{
.id = AR6003_HW_2_1_1_VERSION,
.name = "ar6003 hw 2.1.1",
.dataset_patch_addr = 0x57ff74,
.app_load_addr = 0x1234,
.board_ext_data_addr = 0x542330,
.reserved_ram_size = 512,
.refclk_hz = 26000000,
.uarttx_pin = 8,
.fw_otp = AR6003_HW_2_1_1_OTP_FILE,
.fw = AR6003_HW_2_1_1_FIRMWARE_FILE,
.fw_tcmd = AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE,
.fw_patch = AR6003_HW_2_1_1_PATCH_FILE,
.fw_api2 = AR6003_HW_2_1_1_FIRMWARE_2_FILE,
.fw_board = AR6003_HW_2_1_1_BOARD_DATA_FILE,
.fw_default_board = AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE,
},
{
.id = AR6004_HW_1_0_VERSION,
.name = "ar6004 hw 1.0",
.dataset_patch_addr = 0x57e884,
.app_load_addr = 0x1234,
.board_ext_data_addr = 0x437000,
.reserved_ram_size = 19456,
.board_addr = 0x433900,
.refclk_hz = 26000000,
.uarttx_pin = 11,
.fw = AR6004_HW_1_0_FIRMWARE_FILE,
.fw_api2 = AR6004_HW_1_0_FIRMWARE_2_FILE,
.fw_board = AR6004_HW_1_0_BOARD_DATA_FILE,
.fw_default_board = AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE,
},
{
.id = AR6004_HW_1_1_VERSION,
.name = "ar6004 hw 1.1",
.dataset_patch_addr = 0x57e884,
.app_load_addr = 0x1234,
.board_ext_data_addr = 0x437000,
.reserved_ram_size = 11264,
.board_addr = 0x43d400,
.refclk_hz = 40000000,
.uarttx_pin = 11,
.fw = AR6004_HW_1_1_FIRMWARE_FILE,
.fw_api2 = AR6004_HW_1_1_FIRMWARE_2_FILE,
.fw_board = AR6004_HW_1_1_BOARD_DATA_FILE,
.fw_default_board = AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE,
},
};
/*
* Include definitions here that can be used to tune the WLAN module
* behavior. Different customers can tune the behavior as per their needs,
@ -58,7 +132,6 @@ module_param(suspend_cutpower, bool, 0444);
*/
#define WLAN_CONFIG_DISCONNECT_TIMEOUT 10
#define CONFIG_AR600x_DEBUG_UART_TX_PIN 8
#define ATH6KL_DATA_OFFSET 64
struct sk_buff *ath6kl_buf_alloc(int size)
@ -348,11 +421,7 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx)
status = -EIO;
}
/*
* FIXME: Make sure p2p configurations are not applied to
* non-p2p capable interfaces when multivif support is enabled.
*/
if (ar->p2p) {
if (ar->p2p && (ar->vif_max == 1 || idx)) {
ret = ath6kl_wmi_info_req_cmd(ar->wmi, idx,
P2P_FLAG_CAPABILITIES_REQ |
P2P_FLAG_MACADDR_REQ |
@ -365,11 +434,7 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx)
}
}
/*
* FIXME: Make sure p2p configurations are not applied to
* non-p2p capable interfaces when multivif support is enabled.
*/
if (ar->p2p) {
if (ar->p2p && (ar->vif_max == 1 || idx)) {
/* Enable Probe Request reporting for P2P */
ret = ath6kl_wmi_probe_report_req_cmd(ar->wmi, idx, true);
if (ret) {
@ -385,7 +450,7 @@ int ath6kl_configure_target(struct ath6kl *ar)
{
u32 param, ram_reserved_size;
u8 fw_iftype, fw_mode = 0, fw_submode = 0;
int i;
int i, status;
/*
* Note: Even though the firmware interface type is
@ -397,7 +462,7 @@ int ath6kl_configure_target(struct ath6kl *ar)
*/
fw_iftype = HI_OPTION_FW_MODE_BSS_STA;
for (i = 0; i < MAX_NUM_VIF; i++)
for (i = 0; i < ar->vif_max; i++)
fw_mode |= fw_iftype << (i * HI_OPTION_FW_MODE_BITS);
/*
@ -411,15 +476,11 @@ int ath6kl_configure_target(struct ath6kl *ar)
fw_submode |= HI_OPTION_FW_SUBMODE_NONE <<
(i * HI_OPTION_FW_SUBMODE_BITS);
for (i = ar->max_norm_iface; i < MAX_NUM_VIF; i++)
for (i = ar->max_norm_iface; i < ar->vif_max; i++)
fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV <<
(i * HI_OPTION_FW_SUBMODE_BITS);
/*
* FIXME: This needs to be removed once the multivif
* support is enabled.
*/
if (ar->p2p)
if (ar->p2p && ar->vif_max == 1)
fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV;
param = HTC_PROTOCOL_VERSION;
@ -442,7 +503,7 @@ int ath6kl_configure_target(struct ath6kl *ar)
return -EIO;
}
param |= (MAX_NUM_VIF << HI_OPTION_NUM_DEV_SHIFT);
param |= (ar->vif_max << HI_OPTION_NUM_DEV_SHIFT);
param |= fw_mode << HI_OPTION_FW_MODE_SHIFT;
param |= fw_submode << HI_OPTION_FW_SUBMODE_SHIFT;
@ -491,6 +552,24 @@ int ath6kl_configure_target(struct ath6kl *ar)
/* use default number of control buffers */
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);
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);
if (status)
return status;
return 0;
}
@ -550,11 +629,11 @@ static int ath6kl_get_fw(struct ath6kl *ar, const char *filename,
static const char *get_target_ver_dir(const struct ath6kl *ar)
{
switch (ar->version.target_ver) {
case AR6003_REV1_VERSION:
case AR6003_HW_1_0_VERSION:
return "ath6k/AR6003/hw1.0";
case AR6003_REV2_VERSION:
case AR6003_HW_2_0_VERSION:
return "ath6k/AR6003/hw2.0";
case AR6003_REV3_VERSION:
case AR6003_HW_2_1_1_VERSION:
return "ath6k/AR6003/hw2.1.1";
}
ath6kl_warn("%s: unsupported target version 0x%x.\n", __func__,
@ -612,17 +691,10 @@ static int ath6kl_fetch_board_file(struct ath6kl *ar)
if (ar->fw_board != NULL)
return 0;
switch (ar->version.target_ver) {
case AR6003_REV2_VERSION:
filename = AR6003_REV2_BOARD_DATA_FILE;
break;
case AR6004_REV1_VERSION:
filename = AR6004_REV1_BOARD_DATA_FILE;
break;
default:
filename = AR6003_REV3_BOARD_DATA_FILE;
break;
}
if (WARN_ON(ar->hw.fw_board == NULL))
return -EINVAL;
filename = ar->hw.fw_board;
ret = ath6kl_get_fw(ar, filename, &ar->fw_board,
&ar->fw_board_len);
@ -640,17 +712,7 @@ static int ath6kl_fetch_board_file(struct ath6kl *ar)
ath6kl_warn("Failed to get board file %s (%d), trying to find default board file.\n",
filename, ret);
switch (ar->version.target_ver) {
case AR6003_REV2_VERSION:
filename = AR6003_REV2_DEFAULT_BOARD_DATA_FILE;
break;
case AR6004_REV1_VERSION:
filename = AR6004_REV1_DEFAULT_BOARD_DATA_FILE;
break;
default:
filename = AR6003_REV3_DEFAULT_BOARD_DATA_FILE;
break;
}
filename = ar->hw.fw_default_board;
ret = ath6kl_get_fw(ar, filename, &ar->fw_board,
&ar->fw_board_len);
@ -674,19 +736,14 @@ static int ath6kl_fetch_otp_file(struct ath6kl *ar)
if (ar->fw_otp != NULL)
return 0;
switch (ar->version.target_ver) {
case AR6003_REV2_VERSION:
filename = AR6003_REV2_OTP_FILE;
break;
case AR6004_REV1_VERSION:
ath6kl_dbg(ATH6KL_DBG_TRC, "AR6004 doesn't need OTP file\n");
if (ar->hw.fw_otp == NULL) {
ath6kl_dbg(ATH6KL_DBG_BOOT,
"no OTP file configured for this hw\n");
return 0;
break;
default:
filename = AR6003_REV3_OTP_FILE;
break;
}
filename = ar->hw.fw_otp;
ret = ath6kl_get_fw(ar, filename, &ar->fw_otp,
&ar->fw_otp_len);
if (ret) {
@ -707,38 +764,22 @@ static int ath6kl_fetch_fw_file(struct ath6kl *ar)
return 0;
if (testmode) {
switch (ar->version.target_ver) {
case AR6003_REV2_VERSION:
filename = AR6003_REV2_TCMD_FIRMWARE_FILE;
break;
case AR6003_REV3_VERSION:
filename = AR6003_REV3_TCMD_FIRMWARE_FILE;
break;
case AR6004_REV1_VERSION:
ath6kl_warn("testmode not supported with ar6004\n");
if (ar->hw.fw_tcmd == NULL) {
ath6kl_warn("testmode not supported\n");
return -EOPNOTSUPP;
default:
ath6kl_warn("unknown target version: 0x%x\n",
ar->version.target_ver);
return -EINVAL;
}
filename = ar->hw.fw_tcmd;
set_bit(TESTMODE, &ar->flag);
goto get_fw;
}
switch (ar->version.target_ver) {
case AR6003_REV2_VERSION:
filename = AR6003_REV2_FIRMWARE_FILE;
break;
case AR6004_REV1_VERSION:
filename = AR6004_REV1_FIRMWARE_FILE;
break;
default:
filename = AR6003_REV3_FIRMWARE_FILE;
break;
}
if (WARN_ON(ar->hw.fw == NULL))
return -EINVAL;
filename = ar->hw.fw;
get_fw:
ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len);
@ -756,27 +797,20 @@ static int ath6kl_fetch_patch_file(struct ath6kl *ar)
const char *filename;
int ret;
switch (ar->version.target_ver) {
case AR6003_REV2_VERSION:
filename = AR6003_REV2_PATCH_FILE;
break;
case AR6004_REV1_VERSION:
/* FIXME: implement for AR6004 */
if (ar->fw_patch != NULL)
return 0;
break;
default:
filename = AR6003_REV3_PATCH_FILE;
break;
}
if (ar->fw_patch == NULL) {
ret = ath6kl_get_fw(ar, filename, &ar->fw_patch,
&ar->fw_patch_len);
if (ret) {
ath6kl_err("Failed to get patch file %s: %d\n",
filename, ret);
return ret;
}
if (ar->hw.fw_patch == NULL)
return 0;
filename = ar->hw.fw_patch;
ret = ath6kl_get_fw(ar, filename, &ar->fw_patch,
&ar->fw_patch_len);
if (ret) {
ath6kl_err("Failed to get patch file %s: %d\n",
filename, ret);
return ret;
}
return 0;
@ -811,19 +845,10 @@ static int ath6kl_fetch_fw_api2(struct ath6kl *ar)
int ret, ie_id, i, index, bit;
__le32 *val;
switch (ar->version.target_ver) {
case AR6003_REV2_VERSION:
filename = AR6003_REV2_FIRMWARE_2_FILE;
break;
case AR6003_REV3_VERSION:
filename = AR6003_REV3_FIRMWARE_2_FILE;
break;
case AR6004_REV1_VERSION:
filename = AR6004_REV1_FIRMWARE_2_FILE;
break;
default:
if (ar->hw.fw_api2 == NULL)
return -EOPNOTSUPP;
}
filename = ar->hw.fw_api2;
ret = request_firmware(&fw, filename, ar->dev);
if (ret)
@ -913,12 +938,15 @@ static int ath6kl_fetch_fw_api2(struct ath6kl *ar)
ar->hw.reserved_ram_size);
break;
case ATH6KL_FW_IE_CAPABILITIES:
if (ie_len < DIV_ROUND_UP(ATH6KL_FW_CAPABILITY_MAX, 8))
break;
ath6kl_dbg(ATH6KL_DBG_BOOT,
"found firmware capabilities ie (%zd B)\n",
ie_len);
for (i = 0; i < ATH6KL_FW_CAPABILITY_MAX; i++) {
index = ALIGN(i, 8) / 8;
index = i / 8;
bit = i % 8;
if (data[index] & (1 << bit))
@ -937,9 +965,34 @@ static int ath6kl_fetch_fw_api2(struct ath6kl *ar)
ar->hw.dataset_patch_addr = le32_to_cpup(val);
ath6kl_dbg(ATH6KL_DBG_BOOT,
"found patch address ie 0x%d\n",
"found patch address ie 0x%x\n",
ar->hw.dataset_patch_addr);
break;
case ATH6KL_FW_IE_BOARD_ADDR:
if (ie_len != sizeof(*val))
break;
val = (__le32 *) data;
ar->hw.board_addr = le32_to_cpup(val);
ath6kl_dbg(ATH6KL_DBG_BOOT,
"found board address ie 0x%x\n",
ar->hw.board_addr);
break;
case ATH6KL_FW_IE_VIF_MAX:
if (ie_len != sizeof(*val))
break;
val = (__le32 *) data;
ar->vif_max = min_t(unsigned int, le32_to_cpup(val),
ATH6KL_VIF_MAX);
if (ar->vif_max > 1 && !ar->p2p)
ar->max_norm_iface = 2;
ath6kl_dbg(ATH6KL_DBG_BOOT,
"found vif max ie %d\n", ar->vif_max);
break;
default:
ath6kl_dbg(ATH6KL_DBG_BOOT, "Unknown fw ie: %u\n",
le32_to_cpup(&hdr->id));
@ -994,8 +1047,8 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
* For AR6004, host determine Target RAM address for
* writing board data.
*/
if (ar->target_type == TARGET_TYPE_AR6004) {
board_address = AR6004_REV1_BOARD_DATA_ADDRESS;
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)),
@ -1013,7 +1066,8 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
HI_ITEM(hi_board_ext_data)),
(u8 *) &board_ext_address, 4);
if (board_ext_address == 0) {
if (ar->target_type == TARGET_TYPE_AR6003 &&
board_ext_address == 0) {
ath6kl_err("Failed to get board file target address.\n");
return -EINVAL;
}
@ -1033,8 +1087,8 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
break;
}
if (ar->fw_board_len == (board_data_size +
board_ext_data_size)) {
if (board_ext_address &&
ar->fw_board_len == (board_data_size + board_ext_data_size)) {
/* write extended board data */
ath6kl_dbg(ATH6KL_DBG_BOOT,
@ -1092,8 +1146,8 @@ static int ath6kl_upload_otp(struct ath6kl *ar)
bool from_hw = false;
int ret;
if (WARN_ON(ar->fw_otp == NULL))
return -ENOENT;
if (ar->fw_otp == NULL)
return 0;
address = ar->hw.app_load_addr;
@ -1142,7 +1196,7 @@ static int ath6kl_upload_firmware(struct ath6kl *ar)
int ret;
if (WARN_ON(ar->fw == NULL))
return -ENOENT;
return 0;
address = ar->hw.app_load_addr;
@ -1172,8 +1226,8 @@ static int ath6kl_upload_patch(struct ath6kl *ar)
u32 address, param;
int ret;
if (WARN_ON(ar->fw_patch == NULL))
return -ENOENT;
if (ar->fw_patch == NULL)
return 0;
address = ar->hw.dataset_patch_addr;
@ -1258,7 +1312,7 @@ static int ath6kl_init_upload(struct ath6kl *ar)
return status;
/* WAR to avoid SDIO CRC err */
if (ar->version.target_ver == AR6003_REV2_VERSION) {
if (ar->version.target_ver == AR6003_HW_2_0_VERSION) {
ath6kl_err("temporary war to avoid sdio crc error\n");
param = 0x20;
@ -1315,47 +1369,29 @@ static int ath6kl_init_upload(struct ath6kl *ar)
if (status)
return status;
/* Configure GPIO AR6003 UART */
param = CONFIG_AR600x_DEBUG_UART_TX_PIN;
status = ath6kl_bmi_write(ar,
ath6kl_get_hi_item_addr(ar,
HI_ITEM(hi_dbg_uart_txpin)),
(u8 *)&param, 4);
return status;
}
static int ath6kl_init_hw_params(struct ath6kl *ar)
{
switch (ar->version.target_ver) {
case AR6003_REV2_VERSION:
ar->hw.dataset_patch_addr = AR6003_REV2_DATASET_PATCH_ADDRESS;
ar->hw.app_load_addr = AR6003_REV2_APP_LOAD_ADDRESS;
ar->hw.board_ext_data_addr = AR6003_REV2_BOARD_EXT_DATA_ADDRESS;
ar->hw.reserved_ram_size = AR6003_REV2_RAM_RESERVE_SIZE;
const struct ath6kl_hw *hw;
int i;
/* hw2.0 needs override address hardcoded */
ar->hw.app_start_override_addr = 0x944C00;
for (i = 0; i < ARRAY_SIZE(hw_list); i++) {
hw = &hw_list[i];
break;
case AR6003_REV3_VERSION:
ar->hw.dataset_patch_addr = AR6003_REV3_DATASET_PATCH_ADDRESS;
ar->hw.app_load_addr = 0x1234;
ar->hw.board_ext_data_addr = AR6003_REV3_BOARD_EXT_DATA_ADDRESS;
ar->hw.reserved_ram_size = AR6003_REV3_RAM_RESERVE_SIZE;
break;
case AR6004_REV1_VERSION:
ar->hw.dataset_patch_addr = AR6003_REV2_DATASET_PATCH_ADDRESS;
ar->hw.app_load_addr = AR6003_REV3_APP_LOAD_ADDRESS;
ar->hw.board_ext_data_addr = AR6004_REV1_BOARD_EXT_DATA_ADDRESS;
ar->hw.reserved_ram_size = AR6004_REV1_RAM_RESERVE_SIZE;
break;
default:
if (hw->id == ar->version.target_ver)
break;
}
if (i == ARRAY_SIZE(hw_list)) {
ath6kl_err("Unsupported hardware version: 0x%x\n",
ar->version.target_ver);
return -EINVAL;
}
ar->hw = *hw;
ath6kl_dbg(ATH6KL_DBG_BOOT,
"target_ver 0x%x target_type 0x%x dataset_patch 0x%x app_load_addr 0x%x\n",
ar->version.target_ver, ar->target_type,
@ -1364,10 +1400,25 @@ static int ath6kl_init_hw_params(struct ath6kl *ar)
"app_start_override_addr 0x%x board_ext_data_addr 0x%x reserved_ram_size 0x%x",
ar->hw.app_start_override_addr, ar->hw.board_ext_data_addr,
ar->hw.reserved_ram_size);
ath6kl_dbg(ATH6KL_DBG_BOOT,
"refclk_hz %d uarttx_pin %d",
ar->hw.refclk_hz, ar->hw.uarttx_pin);
return 0;
}
static const char *ath6kl_init_get_hif_name(enum ath6kl_hif_type type)
{
switch (type) {
case ATH6KL_HIF_TYPE_SDIO:
return "sdio";
case ATH6KL_HIF_TYPE_USB:
return "usb";
}
return NULL;
}
int ath6kl_init_hw_start(struct ath6kl *ar)
{
long timeleft;
@ -1428,6 +1479,15 @@ int ath6kl_init_hw_start(struct ath6kl *ar)
ath6kl_dbg(ATH6KL_DBG_BOOT, "firmware booted\n");
if (test_and_clear_bit(FIRST_BOOT, &ar->flag)) {
ath6kl_info("%s %s fw %s%s\n",
ar->hw.name,
ath6kl_init_get_hif_name(ar->hif_type),
ar->wiphy->fw_version,
test_bit(TESTMODE, &ar->flag) ? " testmode" : "");
}
if (ar->version.abi_ver != ATH6KL_ABI_VERSION) {
ath6kl_err("abi version mismatch: host(0x%x), target(0x%x)\n",
ATH6KL_ABI_VERSION, ar->version.abi_ver);
@ -1448,7 +1508,7 @@ int ath6kl_init_hw_start(struct ath6kl *ar)
if ((ath6kl_set_host_app_area(ar)) != 0)
ath6kl_err("unable to set the host app area\n");
for (i = 0; i < MAX_NUM_VIF; i++) {
for (i = 0; i < ar->vif_max; i++) {
ret = ath6kl_target_config_wlan_params(ar, i);
if (ret)
goto err_htc_stop;
@ -1558,7 +1618,7 @@ int ath6kl_core_init(struct ath6kl *ar)
goto err_node_cleanup;
}
for (i = 0; i < MAX_NUM_VIF; i++)
for (i = 0; i < ar->vif_max; i++)
ar->avail_idx_map |= BIT(i);
rtnl_lock();
@ -1603,7 +1663,17 @@ int ath6kl_core_init(struct ath6kl *ar)
ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
WIPHY_FLAG_HAVE_AP_SME |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
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);

View File

@ -175,64 +175,6 @@ void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie)
ar->cookie_count++;
}
/* set the window address register (using 4-byte register access ). */
static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr)
{
int status;
s32 i;
__le32 addr_val;
/*
* Write bytes 1,2,3 of the register to set the upper address bytes,
* the LSB is written last to initiate the access cycle
*/
for (i = 1; i <= 3; i++) {
/*
* Fill the buffer with the address byte value we want to
* hit 4 times. No need to worry about endianness as the
* same byte is copied to all four bytes of addr_val at
* any time.
*/
memset((u8 *)&addr_val, ((u8 *)&addr)[i], 4);
/*
* Hit each byte of the register address with a 4-byte
* write operation to the same address, this is a harmless
* operation.
*/
status = hif_read_write_sync(ar, reg_addr + i, (u8 *)&addr_val,
4, HIF_WR_SYNC_BYTE_FIX);
if (status)
break;
}
if (status) {
ath6kl_err("failed to write initial bytes of 0x%x to window reg: 0x%X\n",
addr, reg_addr);
return status;
}
/*
* Write the address register again, this time write the whole
* 4-byte value. The effect here is that the LSB write causes the
* cycle to start, the extra 3 byte write to bytes 1,2,3 has no
* effect since we are writing the same values again
*/
addr_val = cpu_to_le32(addr);
status = hif_read_write_sync(ar, reg_addr,
(u8 *)&(addr_val),
4, HIF_WR_SYNC_BYTE_INC);
if (status) {
ath6kl_err("failed to write 0x%x to window reg: 0x%X\n",
addr, reg_addr);
return status;
}
return 0;
}
/*
* Read from the hardware through its diagnostic window. No cooperation
* from the firmware is required for this.
@ -241,14 +183,7 @@ int ath6kl_diag_read32(struct ath6kl *ar, u32 address, u32 *value)
{
int ret;
/* set window register to start read cycle */
ret = ath6kl_set_addrwin_reg(ar, WINDOW_READ_ADDR_ADDRESS, address);
if (ret)
return ret;
/* read the data */
ret = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *) value,
sizeof(*value), HIF_RD_SYNC_BYTE_INC);
ret = ath6kl_hif_diag_read32(ar, address, value);
if (ret) {
ath6kl_warn("failed to read32 through diagnose window: %d\n",
ret);
@ -266,18 +201,15 @@ int ath6kl_diag_write32(struct ath6kl *ar, u32 address, __le32 value)
{
int ret;
/* set write data */
ret = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *) &value,
sizeof(value), HIF_WR_SYNC_BYTE_INC);
ret = ath6kl_hif_diag_write32(ar, address, value);
if (ret) {
ath6kl_err("failed to write 0x%x during diagnose window to 0x%d\n",
address, value);
return ret;
}
/* set window register, which starts the write cycle */
return ath6kl_set_addrwin_reg(ar, WINDOW_WRITE_ADDR_ADDRESS,
address);
return 0;
}
int ath6kl_diag_read(struct ath6kl *ar, u32 address, void *data, u32 length)
@ -465,7 +397,9 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel)
case NONE_AUTH:
if (vif->prwise_crypto == WEP_CRYPT)
ath6kl_install_static_wep_keys(vif);
break;
if (!ik->valid || ik->key_type != WAPI_CRYPT)
break;
/* for WAPI, we need to set the delayed group key, continue: */
case WPA_PSK_AUTH:
case WPA2_PSK_AUTH:
case (WPA_PSK_AUTH | WPA2_PSK_AUTH):
@ -534,6 +468,18 @@ void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr,
wpa_ie = pos; /* WPS IE */
break; /* overrides WPA/RSN IE */
}
} else if (pos[0] == 0x44 && wpa_ie == NULL) {
/*
* Note: WAPI Parameter Set IE re-uses Element ID that
* was officially allocated for BSS AC Access Delay. As
* such, we need to be a bit more careful on when
* parsing the frame. However, BSS AC Access Delay
* element is not supposed to be included in
* (Re)Association Request frames, so this should not
* cause problems.
*/
wpa_ie = pos; /* WAPI IE */
break;
}
pos += 2 + pos[1];
}
@ -581,20 +527,6 @@ void ath6kl_disconnect(struct ath6kl_vif *vif)
/* WMI Event handlers */
static const char *get_hw_id_string(u32 id)
{
switch (id) {
case AR6003_REV1_VERSION:
return "1.0";
case AR6003_REV2_VERSION:
return "2.0";
case AR6003_REV3_VERSION:
return "2.1.1";
default:
return "unknown";
}
}
void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver)
{
struct ath6kl *ar = devt;
@ -617,13 +549,6 @@ void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver)
/* indicate to the waiting thread that the ready event was received */
set_bit(WMI_READY, &ar->flag);
wake_up(&ar->event_wq);
if (test_and_clear_bit(FIRST_BOOT, &ar->flag)) {
ath6kl_info("hw %s fw %s%s\n",
get_hw_id_string(ar->wiphy->hw_version),
ar->wiphy->fw_version,
test_bit(TESTMODE, &ar->flag) ? " testmode" : "");
}
}
void ath6kl_scan_complete_evt(struct ath6kl_vif *vif, int status)
@ -1077,21 +1002,11 @@ static int ath6kl_open(struct net_device *dev)
static int ath6kl_close(struct net_device *dev)
{
struct ath6kl *ar = ath6kl_priv(dev);
struct ath6kl_vif *vif = netdev_priv(dev);
netif_stop_queue(dev);
ath6kl_disconnect(vif);
if (test_bit(WMI_READY, &ar->flag)) {
if (ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0xFFFF,
0, 0, 0, 0, 0, 0, 0, 0, 0))
return -EIO;
}
ath6kl_cfg80211_scan_complete_event(vif, true);
ath6kl_cfg80211_stop(vif);
clear_bit(WLAN_ENABLED, &vif->flags);

View File

@ -40,8 +40,12 @@ struct ath6kl_sdio {
struct bus_request bus_req[BUS_REQUEST_MAX_NUM];
struct ath6kl *ar;
u8 *dma_buffer;
/* protects access to dma_buffer */
struct mutex dma_buffer_mutex;
/* scatter request list head */
struct list_head scat_req;
@ -396,6 +400,7 @@ static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf,
if (buf_needs_bounce(buf)) {
if (!ar_sdio->dma_buffer)
return -ENOMEM;
mutex_lock(&ar_sdio->dma_buffer_mutex);
tbuf = ar_sdio->dma_buffer;
memcpy(tbuf, buf, len);
bounced = true;
@ -406,6 +411,9 @@ static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf,
if ((request & HIF_READ) && bounced)
memcpy(buf, tbuf, len);
if (bounced)
mutex_unlock(&ar_sdio->dma_buffer_mutex);
return ret;
}
@ -799,7 +807,28 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
return ret;
}
if ((flags & MMC_PM_WAKE_SDIO_IRQ) && wow) {
if (!(flags & MMC_PM_WAKE_SDIO_IRQ))
goto deepsleep;
/* sdio irq wakes up host */
if (ar->state == ATH6KL_STATE_SCHED_SCAN) {
ret = ath6kl_cfg80211_suspend(ar,
ATH6KL_CFG_SUSPEND_SCHED_SCAN,
NULL);
if (ret) {
ath6kl_warn("Schedule scan suspend failed: %d", ret);
return ret;
}
ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
if (ret)
ath6kl_warn("set sdio wake irq flag failed: %d\n", ret);
return ret;
}
if (wow) {
/*
* The host sdio controller is capable of keep power and
* sdio irq wake up at this point. It's fine to continue
@ -816,6 +845,7 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
return ret;
}
deepsleep:
return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP, NULL);
}
@ -839,6 +869,8 @@ static int ath6kl_sdio_resume(struct ath6kl *ar)
case ATH6KL_STATE_WOW:
break;
case ATH6KL_STATE_SCHED_SCAN:
break;
}
ath6kl_cfg80211_resume(ar);
@ -846,6 +878,264 @@ static int ath6kl_sdio_resume(struct ath6kl *ar)
return 0;
}
/* set the window address register (using 4-byte register access ). */
static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr)
{
int status;
u8 addr_val[4];
s32 i;
/*
* Write bytes 1,2,3 of the register to set the upper address bytes,
* the LSB is written last to initiate the access cycle
*/
for (i = 1; i <= 3; i++) {
/*
* Fill the buffer with the address byte value we want to
* hit 4 times.
*/
memset(addr_val, ((u8 *)&addr)[i], 4);
/*
* Hit each byte of the register address with a 4-byte
* write operation to the same address, this is a harmless
* operation.
*/
status = ath6kl_sdio_read_write_sync(ar, reg_addr + i, addr_val,
4, HIF_WR_SYNC_BYTE_FIX);
if (status)
break;
}
if (status) {
ath6kl_err("%s: failed to write initial bytes of 0x%x "
"to window reg: 0x%X\n", __func__,
addr, reg_addr);
return status;
}
/*
* Write the address register again, this time write the whole
* 4-byte value. The effect here is that the LSB write causes the
* cycle to start, the extra 3 byte write to bytes 1,2,3 has no
* effect since we are writing the same values again
*/
status = ath6kl_sdio_read_write_sync(ar, reg_addr, (u8 *)(&addr),
4, HIF_WR_SYNC_BYTE_INC);
if (status) {
ath6kl_err("%s: failed to write 0x%x to window reg: 0x%X\n",
__func__, addr, reg_addr);
return status;
}
return 0;
}
static int ath6kl_sdio_diag_read32(struct ath6kl *ar, u32 address, u32 *data)
{
int status;
/* set window register to start read cycle */
status = ath6kl_set_addrwin_reg(ar, WINDOW_READ_ADDR_ADDRESS,
address);
if (status)
return status;
/* read the data */
status = ath6kl_sdio_read_write_sync(ar, WINDOW_DATA_ADDRESS,
(u8 *)data, sizeof(u32), HIF_RD_SYNC_BYTE_INC);
if (status) {
ath6kl_err("%s: failed to read from window data addr\n",
__func__);
return status;
}
return status;
}
static int ath6kl_sdio_diag_write32(struct ath6kl *ar, u32 address,
__le32 data)
{
int status;
u32 val = (__force u32) data;
/* set write data */
status = ath6kl_sdio_read_write_sync(ar, WINDOW_DATA_ADDRESS,
(u8 *) &val, sizeof(u32), HIF_WR_SYNC_BYTE_INC);
if (status) {
ath6kl_err("%s: failed to write 0x%x to window data addr\n",
__func__, data);
return status;
}
/* set window register, which starts the write cycle */
return ath6kl_set_addrwin_reg(ar, WINDOW_WRITE_ADDR_ADDRESS,
address);
}
static int ath6kl_sdio_bmi_credits(struct ath6kl *ar)
{
u32 addr;
unsigned long timeout;
int ret;
ar->bmi.cmd_credits = 0;
/* Read the counter register to get the command credits */
addr = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4;
timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
while (time_before(jiffies, timeout) && !ar->bmi.cmd_credits) {
/*
* Hit the credit counter with a 4-byte access, the first byte
* read will hit the counter and cause a decrement, while the
* remaining 3 bytes has no effect. The rationale behind this
* is to make all HIF accesses 4-byte aligned.
*/
ret = ath6kl_sdio_read_write_sync(ar, addr,
(u8 *)&ar->bmi.cmd_credits, 4,
HIF_RD_SYNC_BYTE_INC);
if (ret) {
ath6kl_err("Unable to decrement the command credit "
"count register: %d\n", ret);
return ret;
}
/* The counter is only 8 bits.
* Ignore anything in the upper 3 bytes
*/
ar->bmi.cmd_credits &= 0xFF;
}
if (!ar->bmi.cmd_credits) {
ath6kl_err("bmi communication timeout\n");
return -ETIMEDOUT;
}
return 0;
}
static int ath6kl_bmi_get_rx_lkahd(struct ath6kl *ar)
{
unsigned long timeout;
u32 rx_word = 0;
int ret = 0;
timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
while ((time_before(jiffies, timeout)) && !rx_word) {
ret = ath6kl_sdio_read_write_sync(ar,
RX_LOOKAHEAD_VALID_ADDRESS,
(u8 *)&rx_word, sizeof(rx_word),
HIF_RD_SYNC_BYTE_INC);
if (ret) {
ath6kl_err("unable to read RX_LOOKAHEAD_VALID\n");
return ret;
}
/* all we really want is one bit */
rx_word &= (1 << ENDPOINT1);
}
if (!rx_word) {
ath6kl_err("bmi_recv_buf FIFO empty\n");
return -EINVAL;
}
return ret;
}
static int ath6kl_sdio_bmi_write(struct ath6kl *ar, u8 *buf, u32 len)
{
int ret;
u32 addr;
ret = ath6kl_sdio_bmi_credits(ar);
if (ret)
return ret;
addr = ar->mbox_info.htc_addr;
ret = ath6kl_sdio_read_write_sync(ar, addr, buf, len,
HIF_WR_SYNC_BYTE_INC);
if (ret)
ath6kl_err("unable to send the bmi data to the device\n");
return ret;
}
static int ath6kl_sdio_bmi_read(struct ath6kl *ar, u8 *buf, u32 len)
{
int ret;
u32 addr;
/*
* During normal bootup, small reads may be required.
* Rather than issue an HIF Read and then wait as the Target
* adds successive bytes to the FIFO, we wait here until
* we know that response data is available.
*
* This allows us to cleanly timeout on an unexpected
* Target failure rather than risk problems at the HIF level.
* In particular, this avoids SDIO timeouts and possibly garbage
* data on some host controllers. And on an interconnect
* such as Compact Flash (as well as some SDIO masters) which
* does not provide any indication on data timeout, it avoids
* a potential hang or garbage response.
*
* Synchronization is more difficult for reads larger than the
* size of the MBOX FIFO (128B), because the Target is unable
* to push the 129th byte of data until AFTER the Host posts an
* HIF Read and removes some FIFO data. So for large reads the
* Host proceeds to post an HIF Read BEFORE all the data is
* actually available to read. Fortunately, large BMI reads do
* not occur in practice -- they're supported for debug/development.
*
* So Host/Target BMI synchronization is divided into these cases:
* CASE 1: length < 4
* Should not happen
*
* CASE 2: 4 <= length <= 128
* Wait for first 4 bytes to be in FIFO
* If CONSERVATIVE_BMI_READ is enabled, also wait for
* a BMI command credit, which indicates that the ENTIRE
* response is available in the the FIFO
*
* CASE 3: length > 128
* Wait for the first 4 bytes to be in FIFO
*
* For most uses, a small timeout should be sufficient and we will
* usually see a response quickly; but there may be some unusual
* (debug) cases of BMI_EXECUTE where we want an larger timeout.
* For now, we use an unbounded busy loop while waiting for
* BMI_EXECUTE.
*
* If BMI_EXECUTE ever needs to support longer-latency execution,
* especially in production, this code needs to be enhanced to sleep
* and yield. Also note that BMI_COMMUNICATION_TIMEOUT is currently
* a function of Host processor speed.
*/
if (len >= 4) { /* NB: Currently, always true */
ret = ath6kl_bmi_get_rx_lkahd(ar);
if (ret)
return ret;
}
addr = ar->mbox_info.htc_addr;
ret = ath6kl_sdio_read_write_sync(ar, addr, buf, len,
HIF_RD_SYNC_BYTE_INC);
if (ret) {
ath6kl_err("Unable to read the bmi data from the device: %d\n",
ret);
return ret;
}
return 0;
}
static void ath6kl_sdio_stop(struct ath6kl *ar)
{
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
@ -890,6 +1180,10 @@ static const struct ath6kl_hif_ops ath6kl_sdio_ops = {
.cleanup_scatter = ath6kl_sdio_cleanup_scatter,
.suspend = ath6kl_sdio_suspend,
.resume = ath6kl_sdio_resume,
.diag_read32 = ath6kl_sdio_diag_read32,
.diag_write32 = ath6kl_sdio_diag_write32,
.bmi_read = ath6kl_sdio_bmi_read,
.bmi_write = ath6kl_sdio_bmi_write,
.power_on = ath6kl_sdio_power_on,
.power_off = ath6kl_sdio_power_off,
.stop = ath6kl_sdio_stop,
@ -958,6 +1252,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
spin_lock_init(&ar_sdio->lock);
spin_lock_init(&ar_sdio->scat_lock);
spin_lock_init(&ar_sdio->wr_async_lock);
mutex_init(&ar_sdio->dma_buffer_mutex);
INIT_LIST_HEAD(&ar_sdio->scat_req);
INIT_LIST_HEAD(&ar_sdio->bus_req_freeq);
@ -976,8 +1271,10 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
}
ar_sdio->ar = ar;
ar->hif_type = ATH6KL_HIF_TYPE_SDIO;
ar->hif_priv = ar_sdio;
ar->hif_ops = &ath6kl_sdio_ops;
ar->bmi.max_data_size = 256;
ath6kl_sdio_set_mbox_info(ar);
@ -1027,13 +1324,15 @@ static void ath6kl_sdio_remove(struct sdio_func *func)
static const struct sdio_device_id ath6kl_sdio_devices[] = {
{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x0))},
{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x1))},
{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x0))},
{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x1))},
{},
};
MODULE_DEVICE_TABLE(sdio, ath6kl_sdio_devices);
static struct sdio_driver ath6kl_sdio_driver = {
.name = "ath6kl",
.name = "ath6kl_sdio",
.id_table = ath6kl_sdio_devices,
.probe = ath6kl_sdio_probe,
.remove = ath6kl_sdio_remove,
@ -1063,13 +1362,19 @@ MODULE_AUTHOR("Atheros Communications, Inc.");
MODULE_DESCRIPTION("Driver support for Atheros AR600x SDIO devices");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_FIRMWARE(AR6003_REV2_OTP_FILE);
MODULE_FIRMWARE(AR6003_REV2_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6003_REV2_PATCH_FILE);
MODULE_FIRMWARE(AR6003_REV2_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6003_REV2_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6003_REV3_OTP_FILE);
MODULE_FIRMWARE(AR6003_REV3_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6003_REV3_PATCH_FILE);
MODULE_FIRMWARE(AR6003_REV3_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6003_REV3_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6003_HW_2_0_OTP_FILE);
MODULE_FIRMWARE(AR6003_HW_2_0_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6003_HW_2_0_PATCH_FILE);
MODULE_FIRMWARE(AR6003_HW_2_0_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6003_HW_2_1_1_OTP_FILE);
MODULE_FIRMWARE(AR6003_HW_2_1_1_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6003_HW_2_1_1_PATCH_FILE);
MODULE_FIRMWARE(AR6003_HW_2_1_1_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_0_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6004_HW_1_0_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);

View File

@ -20,7 +20,7 @@
#define AR6003_BOARD_DATA_SZ 1024
#define AR6003_BOARD_EXT_DATA_SZ 768
#define AR6004_BOARD_DATA_SZ 7168
#define AR6004_BOARD_DATA_SZ 6144
#define AR6004_BOARD_EXT_DATA_SZ 0
#define RESET_CONTROL_ADDRESS 0x00000000
@ -334,20 +334,6 @@ struct host_interest {
(((target_type) == TARGET_TYPE_AR6003) ? AR6003_VTOP(vaddr) : \
(((target_type) == TARGET_TYPE_AR6004) ? AR6004_VTOP(vaddr) : 0))
#define AR6003_REV2_APP_LOAD_ADDRESS 0x543180
#define AR6003_REV2_BOARD_EXT_DATA_ADDRESS 0x57E500
#define AR6003_REV2_DATASET_PATCH_ADDRESS 0x57e884
#define AR6003_REV2_RAM_RESERVE_SIZE 6912
#define AR6003_REV3_APP_LOAD_ADDRESS 0x545000
#define AR6003_REV3_BOARD_EXT_DATA_ADDRESS 0x542330
#define AR6003_REV3_DATASET_PATCH_ADDRESS 0x57FF74
#define AR6003_REV3_RAM_RESERVE_SIZE 512
#define AR6004_REV1_BOARD_DATA_ADDRESS 0x435400
#define AR6004_REV1_BOARD_EXT_DATA_ADDRESS 0x437000
#define AR6004_REV1_RAM_RESERVE_SIZE 11264
#define ATH6KL_FWLOG_PAYLOAD_SIZE 1500
struct ath6kl_dbglog_buf {

View File

@ -453,11 +453,11 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
set_bit(WMI_CTRL_EP_FULL, &ar->flag);
spin_unlock_bh(&ar->lock);
ath6kl_err("wmi ctrl ep is full\n");
goto stop_adhoc_netq;
return action;
}
if (packet->info.tx.tag == ATH6KL_CONTROL_PKT_TAG)
goto stop_adhoc_netq;
return action;
/*
* The last MAX_HI_COOKIE_NUM "batch" of cookies are reserved for
@ -465,20 +465,18 @@ 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 <= MAX_HI_COOKIE_NUM)
/*
* Give preference to the highest priority stream by
* dropping the packets which overflowed.
*/
action = HTC_SEND_FULL_DROP;
goto stop_adhoc_netq;
}
stop_adhoc_netq:
/* FIXME: Locking */
spin_lock_bh(&ar->list_lock);
list_for_each_entry(vif, &ar->vif_list, list) {
if (vif->nw_type == ADHOC_NETWORK) {
if (vif->nw_type == ADHOC_NETWORK ||
action != HTC_SEND_FULL_DROP) {
spin_unlock_bh(&ar->list_lock);
spin_lock_bh(&vif->if_lock);
@ -543,7 +541,7 @@ void ath6kl_tx_complete(void *context, struct list_head *packet_queue)
int status;
enum htc_endpoint_id eid;
bool wake_event = false;
bool flushing[MAX_NUM_VIF] = {false};
bool flushing[ATH6KL_VIF_MAX] = {false};
u8 if_idx;
struct ath6kl_vif *vif;
@ -571,8 +569,6 @@ void ath6kl_tx_complete(void *context, struct list_head *packet_queue)
if (!skb || !skb->data)
goto fatal;
packet->buf = skb->data;
__skb_queue_tail(&skb_queue, skb);
if (!status && (packet->act_len != skb->len))
@ -593,10 +589,10 @@ void ath6kl_tx_complete(void *context, struct list_head *packet_queue)
if (eid == ar->ctrl_ep) {
if_idx = wmi_cmd_hdr_get_if_idx(
(struct wmi_cmd_hdr *) skb->data);
(struct wmi_cmd_hdr *) packet->buf);
} else {
if_idx = wmi_data_hdr_get_if_idx(
(struct wmi_data_hdr *) skb->data);
(struct wmi_data_hdr *) packet->buf);
}
vif = ath6kl_get_vif_by_index(ar, if_idx);

View File

@ -0,0 +1,431 @@
/*
* Copyright (c) 2007-2011 Atheros Communications 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 notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/module.h>
#include <linux/usb.h>
#include "debug.h"
#include "core.h"
/* usb device object */
struct ath6kl_usb {
struct usb_device *udev;
struct usb_interface *interface;
u8 *diag_cmd_buffer;
u8 *diag_resp_buffer;
struct ath6kl *ar;
};
/* diagnostic command defnitions */
#define ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD 1
#define ATH6KL_USB_CONTROL_REQ_RECV_BMI_RESP 2
#define ATH6KL_USB_CONTROL_REQ_DIAG_CMD 3
#define ATH6KL_USB_CONTROL_REQ_DIAG_RESP 4
#define ATH6KL_USB_CTRL_DIAG_CC_READ 0
#define ATH6KL_USB_CTRL_DIAG_CC_WRITE 1
struct ath6kl_usb_ctrl_diag_cmd_write {
__le32 cmd;
__le32 address;
__le32 value;
__le32 _pad[1];
} __packed;
struct ath6kl_usb_ctrl_diag_cmd_read {
__le32 cmd;
__le32 address;
} __packed;
struct ath6kl_usb_ctrl_diag_resp_read {
__le32 value;
} __packed;
#define ATH6KL_USB_MAX_DIAG_CMD (sizeof(struct ath6kl_usb_ctrl_diag_cmd_write))
#define ATH6KL_USB_MAX_DIAG_RESP (sizeof(struct ath6kl_usb_ctrl_diag_resp_read))
static void ath6kl_usb_destroy(struct ath6kl_usb *ar_usb)
{
usb_set_intfdata(ar_usb->interface, NULL);
kfree(ar_usb->diag_cmd_buffer);
kfree(ar_usb->diag_resp_buffer);
kfree(ar_usb);
}
static struct ath6kl_usb *ath6kl_usb_create(struct usb_interface *interface)
{
struct ath6kl_usb *ar_usb = NULL;
struct usb_device *dev = interface_to_usbdev(interface);
int status = 0;
ar_usb = kzalloc(sizeof(struct ath6kl_usb), GFP_KERNEL);
if (ar_usb == NULL)
goto fail_ath6kl_usb_create;
memset(ar_usb, 0, sizeof(struct ath6kl_usb));
usb_set_intfdata(interface, ar_usb);
ar_usb->udev = dev;
ar_usb->interface = interface;
ar_usb->diag_cmd_buffer = kzalloc(ATH6KL_USB_MAX_DIAG_CMD, GFP_KERNEL);
if (ar_usb->diag_cmd_buffer == NULL) {
status = -ENOMEM;
goto fail_ath6kl_usb_create;
}
ar_usb->diag_resp_buffer = kzalloc(ATH6KL_USB_MAX_DIAG_RESP,
GFP_KERNEL);
if (ar_usb->diag_resp_buffer == NULL) {
status = -ENOMEM;
goto fail_ath6kl_usb_create;
}
fail_ath6kl_usb_create:
if (status != 0) {
ath6kl_usb_destroy(ar_usb);
ar_usb = NULL;
}
return ar_usb;
}
static void ath6kl_usb_device_detached(struct usb_interface *interface)
{
struct ath6kl_usb *ar_usb;
ar_usb = usb_get_intfdata(interface);
if (ar_usb == NULL)
return;
ath6kl_stop_txrx(ar_usb->ar);
ath6kl_core_cleanup(ar_usb->ar);
ath6kl_usb_destroy(ar_usb);
}
static int ath6kl_usb_submit_ctrl_out(struct ath6kl_usb *ar_usb,
u8 req, u16 value, u16 index, void *data,
u32 size)
{
u8 *buf = NULL;
int ret;
if (size > 0) {
buf = kmalloc(size, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
memcpy(buf, data, size);
}
/* note: if successful returns number of bytes transfered */
ret = usb_control_msg(ar_usb->udev,
usb_sndctrlpipe(ar_usb->udev, 0),
req,
USB_DIR_OUT | USB_TYPE_VENDOR |
USB_RECIP_DEVICE, value, index, buf,
size, 1000);
if (ret < 0) {
ath6kl_dbg(ATH6KL_DBG_USB, "%s failed,result = %d\n",
__func__, ret);
}
kfree(buf);
return 0;
}
static int ath6kl_usb_submit_ctrl_in(struct ath6kl_usb *ar_usb,
u8 req, u16 value, u16 index, void *data,
u32 size)
{
u8 *buf = NULL;
int ret;
if (size > 0) {
buf = kmalloc(size, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
}
/* note: if successful returns number of bytes transfered */
ret = usb_control_msg(ar_usb->udev,
usb_rcvctrlpipe(ar_usb->udev, 0),
req,
USB_DIR_IN | USB_TYPE_VENDOR |
USB_RECIP_DEVICE, value, index, buf,
size, 2 * HZ);
if (ret < 0) {
ath6kl_dbg(ATH6KL_DBG_USB, "%s failed,result = %d\n",
__func__, ret);
}
memcpy((u8 *) data, buf, size);
kfree(buf);
return 0;
}
static int ath6kl_usb_ctrl_msg_exchange(struct ath6kl_usb *ar_usb,
u8 req_val, u8 *req_buf, u32 req_len,
u8 resp_val, u8 *resp_buf, u32 *resp_len)
{
int ret;
/* send command */
ret = ath6kl_usb_submit_ctrl_out(ar_usb, req_val, 0, 0,
req_buf, req_len);
if (ret != 0)
return ret;
if (resp_buf == NULL) {
/* no expected response */
return ret;
}
/* get response */
ret = ath6kl_usb_submit_ctrl_in(ar_usb, resp_val, 0, 0,
resp_buf, *resp_len);
return ret;
}
static int ath6kl_usb_diag_read32(struct ath6kl *ar, u32 address, u32 *data)
{
struct ath6kl_usb *ar_usb = ar->hif_priv;
struct ath6kl_usb_ctrl_diag_resp_read *resp;
struct ath6kl_usb_ctrl_diag_cmd_read *cmd;
u32 resp_len;
int ret;
cmd = (struct ath6kl_usb_ctrl_diag_cmd_read *) ar_usb->diag_cmd_buffer;
memset(cmd, 0, sizeof(*cmd));
cmd->cmd = ATH6KL_USB_CTRL_DIAG_CC_READ;
cmd->address = cpu_to_le32(address);
resp_len = sizeof(*resp);
ret = ath6kl_usb_ctrl_msg_exchange(ar_usb,
ATH6KL_USB_CONTROL_REQ_DIAG_CMD,
(u8 *) cmd,
sizeof(struct ath6kl_usb_ctrl_diag_cmd_write),
ATH6KL_USB_CONTROL_REQ_DIAG_RESP,
ar_usb->diag_resp_buffer, &resp_len);
if (ret)
return ret;
resp = (struct ath6kl_usb_ctrl_diag_resp_read *)
ar_usb->diag_resp_buffer;
*data = le32_to_cpu(resp->value);
return ret;
}
static int ath6kl_usb_diag_write32(struct ath6kl *ar, u32 address, __le32 data)
{
struct ath6kl_usb *ar_usb = ar->hif_priv;
struct ath6kl_usb_ctrl_diag_cmd_write *cmd;
cmd = (struct ath6kl_usb_ctrl_diag_cmd_write *) ar_usb->diag_cmd_buffer;
memset(cmd, 0, sizeof(struct ath6kl_usb_ctrl_diag_cmd_write));
cmd->cmd = cpu_to_le32(ATH6KL_USB_CTRL_DIAG_CC_WRITE);
cmd->address = cpu_to_le32(address);
cmd->value = data;
return ath6kl_usb_ctrl_msg_exchange(ar_usb,
ATH6KL_USB_CONTROL_REQ_DIAG_CMD,
(u8 *) cmd,
sizeof(*cmd),
0, NULL, NULL);
}
static int ath6kl_usb_bmi_read(struct ath6kl *ar, u8 *buf, u32 len)
{
struct ath6kl_usb *ar_usb = ar->hif_priv;
int ret;
/* get response */
ret = ath6kl_usb_submit_ctrl_in(ar_usb,
ATH6KL_USB_CONTROL_REQ_RECV_BMI_RESP,
0, 0, buf, len);
if (ret != 0) {
ath6kl_err("Unable to read the bmi data from the device: %d\n",
ret);
return ret;
}
return 0;
}
static int ath6kl_usb_bmi_write(struct ath6kl *ar, u8 *buf, u32 len)
{
struct ath6kl_usb *ar_usb = ar->hif_priv;
int ret;
/* send command */
ret = ath6kl_usb_submit_ctrl_out(ar_usb,
ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD,
0, 0, buf, len);
if (ret != 0) {
ath6kl_err("unable to send the bmi data to the device: %d\n",
ret);
return ret;
}
return 0;
}
static int ath6kl_usb_power_on(struct ath6kl *ar)
{
return 0;
}
static int ath6kl_usb_power_off(struct ath6kl *ar)
{
return 0;
}
static const struct ath6kl_hif_ops ath6kl_usb_ops = {
.diag_read32 = ath6kl_usb_diag_read32,
.diag_write32 = ath6kl_usb_diag_write32,
.bmi_read = ath6kl_usb_bmi_read,
.bmi_write = ath6kl_usb_bmi_write,
.power_on = ath6kl_usb_power_on,
.power_off = ath6kl_usb_power_off,
};
/* ath6kl usb driver registered functions */
static int ath6kl_usb_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(interface);
struct ath6kl *ar;
struct ath6kl_usb *ar_usb = NULL;
int vendor_id, product_id;
int ret = 0;
usb_get_dev(dev);
vendor_id = le16_to_cpu(dev->descriptor.idVendor);
product_id = le16_to_cpu(dev->descriptor.idProduct);
ath6kl_dbg(ATH6KL_DBG_USB, "vendor_id = %04x\n", vendor_id);
ath6kl_dbg(ATH6KL_DBG_USB, "product_id = %04x\n", product_id);
if (interface->cur_altsetting)
ath6kl_dbg(ATH6KL_DBG_USB, "USB Interface %d\n",
interface->cur_altsetting->desc.bInterfaceNumber);
if (dev->speed == USB_SPEED_HIGH)
ath6kl_dbg(ATH6KL_DBG_USB, "USB 2.0 Host\n");
else
ath6kl_dbg(ATH6KL_DBG_USB, "USB 1.1 Host\n");
ar_usb = ath6kl_usb_create(interface);
if (ar_usb == NULL) {
ret = -ENOMEM;
goto err_usb_put;
}
ar = ath6kl_core_alloc(&ar_usb->udev->dev);
if (ar == NULL) {
ath6kl_err("Failed to alloc ath6kl core\n");
ret = -ENOMEM;
goto err_usb_destroy;
}
ar->hif_priv = ar_usb;
ar->hif_type = ATH6KL_HIF_TYPE_USB;
ar->hif_ops = &ath6kl_usb_ops;
ar->mbox_info.block_size = 16;
ar->bmi.max_data_size = 252;
ar_usb->ar = ar;
ret = ath6kl_core_init(ar);
if (ret) {
ath6kl_err("Failed to init ath6kl core: %d\n", ret);
goto err_core_free;
}
return ret;
err_core_free:
ath6kl_core_free(ar);
err_usb_destroy:
ath6kl_usb_destroy(ar_usb);
err_usb_put:
usb_put_dev(dev);
return ret;
}
static void ath6kl_usb_remove(struct usb_interface *interface)
{
usb_put_dev(interface_to_usbdev(interface));
ath6kl_usb_device_detached(interface);
}
/* table of devices that work with this driver */
static struct usb_device_id ath6kl_usb_ids[] = {
{USB_DEVICE(0x0cf3, 0x9374)},
{ /* Terminating entry */ },
};
MODULE_DEVICE_TABLE(usb, ath6kl_usb_ids);
static struct usb_driver ath6kl_usb_driver = {
.name = "ath6kl_usb",
.probe = ath6kl_usb_probe,
.disconnect = ath6kl_usb_remove,
.id_table = ath6kl_usb_ids,
};
static int ath6kl_usb_init(void)
{
usb_register(&ath6kl_usb_driver);
return 0;
}
static void ath6kl_usb_exit(void)
{
usb_deregister(&ath6kl_usb_driver);
}
module_init(ath6kl_usb_init);
module_exit(ath6kl_usb_exit);
MODULE_AUTHOR("Atheros Communications, Inc.");
MODULE_DESCRIPTION("Driver support for Atheros AR600x USB devices");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_FIRMWARE(AR6004_HW_1_0_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6004_HW_1_0_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);

View File

@ -85,7 +85,7 @@ struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx)
{
struct ath6kl_vif *vif, *found = NULL;
if (WARN_ON(if_idx > (MAX_NUM_VIF - 1)))
if (WARN_ON(if_idx > (ar->vif_max - 1)))
return NULL;
/* FIXME: Locking */
@ -187,7 +187,7 @@ int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb,
struct wmi_data_hdr *data_hdr;
int ret;
if (WARN_ON(skb == NULL || (if_idx > MAX_NUM_VIF - 1)))
if (WARN_ON(skb == NULL || (if_idx > wmi->parent_dev->vif_max - 1)))
return -EINVAL;
if (tx_meta_info) {
@ -977,6 +977,13 @@ static int ath6kl_wmi_tkip_micerr_event_rx(struct wmi *wmi, u8 *datap, int len,
return 0;
}
void ath6kl_wmi_sscan_timer(unsigned long ptr)
{
struct ath6kl_vif *vif = (struct ath6kl_vif *) ptr;
cfg80211_sched_scan_results(vif->ar->wiphy);
}
static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
struct ath6kl_vif *vif)
{
@ -1066,6 +1073,21 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
return -ENOMEM;
cfg80211_put_bss(bss);
/*
* Firmware doesn't return any event when scheduled scan has
* finished, so we need to use a timer to find out when there are
* no more results.
*
* The timer is started from the first bss info received, otherwise
* the timer would not ever fire if the scan interval is short
* enough.
*/
if (ar->state == ATH6KL_STATE_SCHED_SCAN &&
!timer_pending(&vif->sched_scan_timer)) {
mod_timer(&vif->sched_scan_timer, jiffies +
msecs_to_jiffies(ATH6KL_SCHED_SCAN_RESULT_DELAY));
}
return 0;
}
@ -1620,7 +1642,7 @@ int ath6kl_wmi_cmd_send(struct wmi *wmi, u8 if_idx, struct sk_buff *skb,
int ret;
u16 info1;
if (WARN_ON(skb == NULL || (if_idx > (MAX_NUM_VIF - 1))))
if (WARN_ON(skb == NULL || (if_idx > (wmi->parent_dev->vif_max - 1))))
return -EINVAL;
ath6kl_dbg(ATH6KL_DBG_WMI, "wmi tx id %d len %d flag %d\n",
@ -1682,7 +1704,8 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, u8 if_idx,
u8 pairwise_crypto_len,
enum crypto_type group_crypto,
u8 group_crypto_len, int ssid_len, u8 *ssid,
u8 *bssid, u16 channel, u32 ctrl_flags)
u8 *bssid, u16 channel, u32 ctrl_flags,
u8 nw_subtype)
{
struct sk_buff *skb;
struct wmi_connect_cmd *cc;
@ -1722,6 +1745,7 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, u8 if_idx,
cc->grp_crypto_len = group_crypto_len;
cc->ch = cpu_to_le16(channel);
cc->ctrl_flags = cpu_to_le32(ctrl_flags);
cc->nw_subtype = nw_subtype;
if (bssid != NULL)
memcpy(cc->bssid, bssid, ETH_ALEN);
@ -1774,6 +1798,72 @@ int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx)
return ret;
}
int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
enum wmi_scan_type scan_type,
u32 force_fgscan, u32 is_legacy,
u32 home_dwell_time, u32 force_scan_interval,
s8 num_chan, u16 *ch_list, u32 no_cck, u32 *rates)
{
struct sk_buff *skb;
struct wmi_begin_scan_cmd *sc;
s8 size;
int i, band, ret;
struct ath6kl *ar = wmi->parent_dev;
int num_rates;
size = sizeof(struct wmi_begin_scan_cmd);
if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN))
return -EINVAL;
if (num_chan > WMI_MAX_CHANNELS)
return -EINVAL;
if (num_chan)
size += sizeof(u16) * (num_chan - 1);
skb = ath6kl_wmi_get_new_buf(size);
if (!skb)
return -ENOMEM;
sc = (struct wmi_begin_scan_cmd *) skb->data;
sc->scan_type = scan_type;
sc->force_fg_scan = cpu_to_le32(force_fgscan);
sc->is_legacy = cpu_to_le32(is_legacy);
sc->home_dwell_time = cpu_to_le32(home_dwell_time);
sc->force_scan_intvl = cpu_to_le32(force_scan_interval);
sc->no_cck = cpu_to_le32(no_cck);
sc->num_ch = num_chan;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
struct ieee80211_supported_band *sband =
ar->wiphy->bands[band];
u32 ratemask = rates[band];
u8 *supp_rates = sc->supp_rates[band].rates;
num_rates = 0;
for (i = 0; i < sband->n_bitrates; i++) {
if ((BIT(i) & ratemask) == 0)
continue; /* skip rate */
supp_rates[num_rates++] =
(u8) (sband->bitrates[i].bitrate / 5);
}
sc->supp_rates[band].nrates = num_rates;
}
for (i = 0; i < num_chan; i++)
sc->ch_list[i] = cpu_to_le16(ch_list[i]);
ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_BEGIN_SCAN_CMDID,
NO_SYNC_WMIFLAG);
return ret;
}
/* ath6kl_wmi_start_scan_cmd is to be deprecated. Use
* ath6kl_wmi_begin_scan_cmd instead. The new function supports P2P
* mgmt operations using station interface.
*/
int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx,
enum wmi_scan_type scan_type,
u32 force_fgscan, u32 is_legacy,
@ -2940,7 +3030,10 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
p = (struct wmi_set_appie_cmd *) skb->data;
p->mgmt_frm_type = mgmt_frm_type;
p->ie_len = ie_len;
memcpy(p->ie_info, ie, ie_len);
if (ie != NULL && ie_len > 0)
memcpy(p->ie_info, ie, ie_len);
return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_APPIE_CMDID,
NO_SYNC_WMIFLAG);
}
@ -2981,6 +3074,10 @@ int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx, u32 freq, u32 dur)
NO_SYNC_WMIFLAG);
}
/* ath6kl_wmi_send_action_cmd is to be deprecated. Use
* 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)
{
@ -3018,14 +3115,57 @@ 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)
{
struct sk_buff *skb;
struct wmi_send_mgmt_cmd *p;
u8 *buf;
if (wait)
return -EINVAL; /* Offload for wait not supported */
buf = kmalloc(data_len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len);
if (!skb) {
kfree(buf);
return -ENOMEM;
}
kfree(wmi->last_mgmt_tx_frame);
memcpy(buf, data, data_len);
wmi->last_mgmt_tx_frame = buf;
wmi->last_mgmt_tx_frame_len = data_len;
ath6kl_dbg(ATH6KL_DBG_WMI, "send_action_cmd: id=%u freq=%u wait=%u "
"len=%u\n", id, freq, wait, data_len);
p = (struct wmi_send_mgmt_cmd *) skb->data;
p->id = cpu_to_le32(id);
p->freq = cpu_to_le32(freq);
p->wait = cpu_to_le32(wait);
p->no_cck = cpu_to_le32(no_cck);
p->len = cpu_to_le16(data_len);
memcpy(p->data, data, data_len);
return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SEND_MGMT_CMDID,
NO_SYNC_WMIFLAG);
}
int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq,
const u8 *dst, const u8 *data,
u16 data_len)
{
struct sk_buff *skb;
struct wmi_p2p_probe_response_cmd *p;
size_t cmd_len = sizeof(*p) + data_len;
skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len);
if (data_len == 0)
cmd_len++; /* work around target minimum length requirement */
skb = ath6kl_wmi_get_new_buf(cmd_len);
if (!skb)
return -ENOMEM;

View File

@ -329,6 +329,10 @@ enum wmi_cmd_id {
WMI_SYNCHRONIZE_CMDID,
WMI_CREATE_PSTREAM_CMDID,
WMI_DELETE_PSTREAM_CMDID,
/* WMI_START_SCAN_CMDID is to be deprecated. Use
* WMI_BEGIN_SCAN_CMDID instead. The new cmd supports P2P mgmt
* operations using station interface.
*/
WMI_START_SCAN_CMDID,
WMI_SET_SCAN_PARAMS_CMDID,
WMI_SET_BSS_FILTER_CMDID,
@ -542,12 +546,61 @@ enum wmi_cmd_id {
WMI_GTK_OFFLOAD_OP_CMDID,
WMI_REMAIN_ON_CHNL_CMDID,
WMI_CANCEL_REMAIN_ON_CHNL_CMDID,
/* WMI_SEND_ACTION_CMDID is to be deprecated. Use
* WMI_SEND_MGMT_CMDID instead. The new cmd supports P2P mgmt
* operations using station interface.
*/
WMI_SEND_ACTION_CMDID,
WMI_PROBE_REQ_REPORT_CMDID,
WMI_DISABLE_11B_RATES_CMDID,
WMI_SEND_PROBE_RESPONSE_CMDID,
WMI_GET_P2P_INFO_CMDID,
WMI_AP_JOIN_BSS_CMDID,
WMI_SMPS_ENABLE_CMDID,
WMI_SMPS_CONFIG_CMDID,
WMI_SET_RATECTRL_PARM_CMDID,
/* LPL specific commands*/
WMI_LPL_FORCE_ENABLE_CMDID,
WMI_LPL_SET_POLICY_CMDID,
WMI_LPL_GET_POLICY_CMDID,
WMI_LPL_GET_HWSTATE_CMDID,
WMI_LPL_SET_PARAMS_CMDID,
WMI_LPL_GET_PARAMS_CMDID,
WMI_SET_BUNDLE_PARAM_CMDID,
/*GreenTx specific commands*/
WMI_GREENTX_PARAMS_CMDID,
WMI_RTT_MEASREQ_CMDID,
WMI_RTT_CAPREQ_CMDID,
WMI_RTT_STATUSREQ_CMDID,
/* WPS Commands */
WMI_WPS_START_CMDID,
WMI_GET_WPS_STATUS_CMDID,
/* More P2P commands */
WMI_SET_NOA_CMDID,
WMI_GET_NOA_CMDID,
WMI_SET_OPPPS_CMDID,
WMI_GET_OPPPS_CMDID,
WMI_ADD_PORT_CMDID,
WMI_DEL_PORT_CMDID,
/* 802.11w cmd */
WMI_SET_RSN_CAP_CMDID,
WMI_GET_RSN_CAP_CMDID,
WMI_SET_IGTK_CMDID,
WMI_RX_FILTER_COALESCE_FILTER_OP_CMDID,
WMI_RX_FILTER_SET_FRAME_TEST_LIST_CMDID,
WMI_SEND_MGMT_CMDID,
WMI_BEGIN_SCAN_CMDID,
};
enum wmi_mgmt_frame_type {
@ -567,6 +620,14 @@ enum network_type {
AP_NETWORK = 0x10,
};
enum network_subtype {
SUBTYPE_NONE,
SUBTYPE_BT,
SUBTYPE_P2PDEV,
SUBTYPE_P2PCLIENT,
SUBTYPE_P2PGO,
};
enum dot11_auth_mode {
OPEN_AUTH = 0x01,
SHARED_AUTH = 0x02,
@ -639,6 +700,7 @@ struct wmi_connect_cmd {
__le16 ch;
u8 bssid[ETH_ALEN];
__le32 ctrl_flags;
u8 nw_subtype;
} __packed;
/* WMI_RECONNECT_CMDID */
@ -726,6 +788,43 @@ enum wmi_scan_type {
WMI_SHORT_SCAN = 1,
};
struct wmi_supp_rates {
u8 nrates;
u8 rates[ATH6KL_RATE_MAXSIZE];
};
struct wmi_begin_scan_cmd {
__le32 force_fg_scan;
/* for legacy cisco AP compatibility */
__le32 is_legacy;
/* max duration in the home channel(msec) */
__le32 home_dwell_time;
/* time interval between scans (msec) */
__le32 force_scan_intvl;
/* no CCK rates */
__le32 no_cck;
/* enum wmi_scan_type */
u8 scan_type;
/* Supported rates to advertise in the probe request frames */
struct wmi_supp_rates supp_rates[IEEE80211_NUM_BANDS];
/* how many channels follow */
u8 num_ch;
/* channels in Mhz */
__le16 ch_list[1];
} __packed;
/* wmi_start_scan_cmd is to be deprecated. Use
* wmi_begin_scan_cmd instead. The new structure supports P2P mgmt
* operations using station interface.
*/
struct wmi_start_scan_cmd {
__le32 force_fg_scan;
@ -748,9 +847,6 @@ struct wmi_start_scan_cmd {
__le16 ch_list[1];
} __packed;
/* WMI_SET_SCAN_PARAMS_CMDID */
#define WMI_SHORTSCANRATIO_DEFAULT 3
/*
* Warning: scan control flag value of 0xFF is used to disable
* all flags in WMI_SCAN_PARAMS_CMD. Do not add any more
@ -783,13 +879,6 @@ enum wmi_scan_ctrl_flags_bits {
ENABLE_SCAN_ABORT_EVENT = 0x40
};
#define DEFAULT_SCAN_CTRL_FLAGS \
(CONNECT_SCAN_CTRL_FLAGS | \
SCAN_CONNECTED_CTRL_FLAGS | \
ACTIVE_SCAN_CTRL_FLAGS | \
ROAM_SCAN_CTRL_FLAGS | \
ENABLE_AUTO_CTRL_FLAGS)
struct wmi_scan_params_cmd {
/* sec */
__le16 fg_start_period;
@ -1818,7 +1907,7 @@ struct wmi_set_ip_cmd {
} __packed;
enum ath6kl_wow_filters {
WOW_FILTER_SSID = BIT(0),
WOW_FILTER_SSID = BIT(1),
WOW_FILTER_OPTION_MAGIC_PACKET = BIT(2),
WOW_FILTER_OPTION_EAP_REQ = BIT(3),
WOW_FILTER_OPTION_PATTERNS = BIT(4),
@ -1963,7 +2052,7 @@ struct wmi_tx_complete_event {
* !!! Warning !!!
* -Changing the following values needs compilation of both driver and firmware
*/
#define AP_MAX_NUM_STA 8
#define AP_MAX_NUM_STA 10
/* Spl. AID used to set DTIM flag in the beacons */
#define MCAST_AID 0xFF
@ -2046,6 +2135,10 @@ struct wmi_remain_on_chnl_cmd {
__le32 duration;
} __packed;
/* wmi_send_action_cmd is to be deprecated. Use
* wmi_send_mgmt_cmd instead. The new structure supports P2P mgmt
* operations using station interface.
*/
struct wmi_send_action_cmd {
__le32 id;
__le32 freq;
@ -2054,6 +2147,15 @@ struct wmi_send_action_cmd {
u8 data[0];
} __packed;
struct wmi_send_mgmt_cmd {
__le32 id;
__le32 freq;
__le32 wait;
__le32 no_cck;
__le16 len;
u8 data[0];
} __packed;
struct wmi_tx_status_event {
__le32 id;
u8 ack_status;
@ -2242,7 +2344,8 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, u8 if_idx,
u8 pairwise_crypto_len,
enum crypto_type group_crypto,
u8 group_crypto_len, int ssid_len, u8 *ssid,
u8 *bssid, u16 channel, u32 ctrl_flags);
u8 *bssid, u16 channel, u32 ctrl_flags,
u8 nw_subtype);
int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 if_idx, u8 *bssid,
u16 channel);
@ -2252,6 +2355,14 @@ int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx,
u32 force_fgscan, u32 is_legacy,
u32 home_dwell_time, u32 force_scan_interval,
s8 num_chan, u16 *ch_list);
int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
enum wmi_scan_type scan_type,
u32 force_fgscan, u32 is_legacy,
u32 home_dwell_time, u32 force_scan_interval,
s8 num_chan, u16 *ch_list, u32 no_cck,
u32 *rates);
int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u8 if_idx, u16 fg_start_sec,
u16 fg_end_sec, u16 bg_sec,
u16 minact_chdw_msec, u16 maxact_chdw_msec,
@ -2346,6 +2457,10 @@ int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx, u32 freq,
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);
int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq,
const u8 *dst, const u8 *data,
u16 data_len);
@ -2359,6 +2474,8 @@ int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx);
int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
const u8 *ie, u8 ie_len);
void ath6kl_wmi_sscan_timer(unsigned long ptr);
struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx);
void *ath6kl_wmi_init(struct ath6kl *devt);
void ath6kl_wmi_shutdown(struct wmi *wmi);