aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/ath/ath6kl/Kconfig25
-rw-r--r--drivers/net/wireless/ath/ath6kl/Makefile37
-rw-r--r--drivers/net/wireless/ath/ath6kl/bmi.c245
-rw-r--r--drivers/net/wireless/ath/ath6kl/bmi.h6
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c382
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.h6
-rw-r--r--drivers/net/wireless/ath/ath6kl/common.h1
-rw-r--r--drivers/net/wireless/ath/ath6kl/core.h109
-rw-r--r--drivers/net/wireless/ath/ath6kl/debug.c4
-rw-r--r--drivers/net/wireless/ath/ath6kl/debug.h1
-rw-r--r--drivers/net/wireless/ath/ath6kl/hif-ops.h30
-rw-r--r--drivers/net/wireless/ath/ath6kl/hif.c5
-rw-r--r--drivers/net/wireless/ath/ath6kl/hif.h5
-rw-r--r--drivers/net/wireless/ath/ath6kl/htc.c10
-rw-r--r--drivers/net/wireless/ath/ath6kl/init.c380
-rw-r--r--drivers/net/wireless/ath/ath6kl/main.c125
-rw-r--r--drivers/net/wireless/ath/ath6kl/sdio.c329
-rw-r--r--drivers/net/wireless/ath/ath6kl/target.h16
-rw-r--r--drivers/net/wireless/ath/ath6kl/txrx.c20
-rw-r--r--drivers/net/wireless/ath/ath6kl/usb.c431
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.c152
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.h143
22 files changed, 1809 insertions, 653 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/Kconfig b/drivers/net/wireless/ath/ath6kl/Kconfig
index 3d5f8be20ea..d755a5e7ed2 100644
--- a/drivers/net/wireless/ath/ath6kl/Kconfig
+++ b/drivers/net/wireless/ath/ath6kl/Kconfig
@@ -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"
diff --git a/drivers/net/wireless/ath/ath6kl/Makefile b/drivers/net/wireless/ath/ath6kl/Makefile
index 70706930355..e14cef9c3c0 100644
--- a/drivers/net/wireless/ath/ath6kl/Makefile
+++ b/drivers/net/wireless/ath/ath6kl/Makefile
@@ -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__
diff --git a/drivers/net/wireless/ath/ath6kl/bmi.c b/drivers/net/wireless/ath/ath6kl/bmi.c
index a962fe4c6b7..aef00d5a143 100644
--- a/drivers/net/wireless/ath/ath6kl/bmi.c
+++ b/drivers/net/wireless/ath/ath6kl/bmi.c
@@ -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;
diff --git a/drivers/net/wireless/ath/ath6kl/bmi.h b/drivers/net/wireless/ath/ath6kl/bmi.h
index 009e8f650ab..f1ca6812456 100644
--- a/drivers/net/wireless/ath/ath6kl/bmi.h
+++ b/drivers/net/wireless/ath/ath6kl/bmi.h
@@ -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
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 02526044acb..6c59a217b1a 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -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,25 +2567,17 @@ 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)
{
- struct ath6kl_vif *vif;
-
- /* FIXME: for multi vif */
- vif = ath6kl_vif_first(ar);
- if (!vif) {
- /* save the current power mode before enabling power save */
- ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
-
- if (ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER) != 0)
- ath6kl_warn("ath6kl_deep_sleep_enable: "
- "wmi_powermode_cmd failed\n");
- return;
- }
+ 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,
@@ -2385,33 +2585,50 @@ void ath6kl_cfg80211_stop(struct ath6kl *ar)
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);
+ 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(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");
+ 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;
+
+ vif = ath6kl_vif_first(ar);
+ if (!vif) {
+ /* save the current power mode before enabling power save */
+ ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
+
+ if (ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER) != 0)
+ ath6kl_warn("ath6kl_deep_sleep_enable: "
+ "wmi_powermode_cmd failed\n");
+ return;
+ }
+
+ /*
+ * 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)
{
struct ath6kl *ar;
@@ -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);
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h
index 59fa9d859de..81f20a57231 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.h
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h
@@ -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 */
diff --git a/drivers/net/wireless/ath/ath6kl/common.h b/drivers/net/wireless/ath/ath6kl/common.h
index 41e465f29e6..bfd6597763d 100644
--- a/drivers/net/wireless/ath/ath6kl/common.h
+++ b/drivers/net/wireless/ath/ath6kl/common.h
@@ -71,6 +71,7 @@ enum crypto_type {
WEP_CRYPT = 0x02,
TKIP_CRYPT = 0x04,
AES_CRYPT = 0x08,
+ WAPI_CRYPT = 0x10,
};
struct htc_endpoint_credit_dist;
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index e7e095e536a..c863a28f2e0 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -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;
}
diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c
index 9eff0d010bb..eb808b46f94 100644
--- a/drivers/net/wireless/ath/ath6kl/debug.c
+++ b/drivers/net/wireless/ath/ath6kl/debug.c
@@ -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);
diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h
index 9853c9c125c..e569c652e35 100644
--- a/drivers/net/wireless/ath/ath6kl/debug.h
+++ b/drivers/net/wireless/ath/ath6kl/debug.h
@@ -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 */
};
diff --git a/drivers/net/wireless/ath/ath6kl/hif-ops.h b/drivers/net/wireless/ath/ath6kl/hif-ops.h
index eed22870448..2fe1dadfc77 100644
--- a/drivers/net/wireless/ath/ath6kl/hif-ops.h
+++ b/drivers/net/wireless/ath/ath6kl/hif-ops.h
@@ -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");
diff --git a/drivers/net/wireless/ath/ath6kl/hif.c b/drivers/net/wireless/ath/ath6kl/hif.c
index e57da35e59f..0772ef65017 100644
--- a/drivers/net/wireless/ath/ath6kl/hif.c
+++ b/drivers/net/wireless/ath/ath6kl/hif.c
@@ -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:
diff --git a/drivers/net/wireless/ath/ath6kl/hif.h b/drivers/net/wireless/ath/ath6kl/hif.h
index f2dc3bcdae4..699a036f3a4 100644
--- a/drivers/net/wireless/ath/ath6kl/hif.h
+++ b/drivers/net/wireless/ath/ath6kl/hif.h
@@ -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);
diff --git a/drivers/net/wireless/ath/ath6kl/htc.c b/drivers/net/wireless/ath/ath6kl/htc.c
index f3b63ca25c7..b01702258fa 100644
--- a/drivers/net/wireless/ath/ath6kl/htc.c
+++ b/drivers/net/wireless/ath/ath6kl/htc.c
@@ -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) {
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index 30050af9d4c..368ecbd172a 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -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);
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index 5e5f4ca8f3f..eea3c747653 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -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);
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
index e69ca5ee5bb..15c3f56caf4 100644
--- a/drivers/net/wireless/ath/ath6kl/sdio.c
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -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);
diff --git a/drivers/net/wireless/ath/ath6kl/target.h b/drivers/net/wireless/ath/ath6kl/target.h
index 687e2b350e8..108a723a108 100644
--- a/drivers/net/wireless/ath/ath6kl/target.h
+++ b/drivers/net/wireless/ath/ath6kl/target.h
@@ -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 {
diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c
index d9cff2b950b..506a3031a88 100644
--- a/drivers/net/wireless/ath/ath6kl/txrx.c
+++ b/drivers/net/wireless/ath/ath6kl/txrx.c
@@ -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);
diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c
new file mode 100644
index 00000000000..e3cf397fcaf
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/usb.c
@@ -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);
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 922344d3b26..f6f2aa27fc2 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -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;
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index 76342d5a190..42ac311eda4 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -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,7 +788,12 @@ enum wmi_scan_type {
WMI_SHORT_SCAN = 1,
};
-struct wmi_start_scan_cmd {
+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 */
@@ -738,9 +805,15 @@ struct wmi_start_scan_cmd {
/* 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;
@@ -748,8 +821,31 @@ struct wmi_start_scan_cmd {
__le16 ch_list[1];
} __packed;
-/* WMI_SET_SCAN_PARAMS_CMDID */
-#define WMI_SHORTSCANRATIO_DEFAULT 3
+/* 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;
+
+ /* 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;
+
+ /* enum wmi_scan_type */
+ u8 scan_type;
+
+ /* how many channels follow */
+ u8 num_ch;
+
+ /* channels in Mhz */
+ __le16 ch_list[1];
+} __packed;
/*
* Warning: scan control flag value of 0xFF is used to disable
@@ -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);