OSDN Git Service

Merge remote branch 'wireless-next/master' into ath6kl-next
authorKalle Valo <kvalo@qca.qualcomm.com>
Fri, 16 Dec 2011 19:10:39 +0000 (21:10 +0200)
committerKalle Valo <kvalo@qca.qualcomm.com>
Fri, 16 Dec 2011 19:10:39 +0000 (21:10 +0200)
Conflicts:
drivers/net/wireless/ath/ath6kl/init.c

22 files changed:
drivers/net/wireless/ath/ath6kl/Kconfig
drivers/net/wireless/ath/ath6kl/Makefile
drivers/net/wireless/ath/ath6kl/bmi.c
drivers/net/wireless/ath/ath6kl/bmi.h
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath6kl/cfg80211.h
drivers/net/wireless/ath/ath6kl/common.h
drivers/net/wireless/ath/ath6kl/core.h
drivers/net/wireless/ath/ath6kl/debug.c
drivers/net/wireless/ath/ath6kl/debug.h
drivers/net/wireless/ath/ath6kl/hif-ops.h
drivers/net/wireless/ath/ath6kl/hif.c
drivers/net/wireless/ath/ath6kl/hif.h
drivers/net/wireless/ath/ath6kl/htc.c
drivers/net/wireless/ath/ath6kl/init.c
drivers/net/wireless/ath/ath6kl/main.c
drivers/net/wireless/ath/ath6kl/sdio.c
drivers/net/wireless/ath/ath6kl/target.h
drivers/net/wireless/ath/ath6kl/txrx.c
drivers/net/wireless/ath/ath6kl/usb.c [new file with mode: 0644]
drivers/net/wireless/ath/ath6kl/wmi.c
drivers/net/wireless/ath/ath6kl/wmi.h

index 3d5f8be..d755a5e 100644 (file)
@@ -1,12 +1,29 @@
 config ATH6KL
-       tristate "Atheros ath6kl support"
+       tristate "Atheros mobile chipsets support"
+
+config ATH6KL_SDIO
+       tristate "Atheros ath6kl SDIO support"
+       depends on ATH6KL
        depends on MMC
        depends on CFG80211
        ---help---
          This module adds support for wireless adapters based on
-         Atheros AR6003 chipset running over SDIO. If you choose to
-         build it as a module, it will be called ath6kl. Pls note
-         that AR6002 and AR6001 are not supported by this driver.
+         Atheros AR6003 and AR6004 chipsets running over SDIO. If you
+         choose to build it as a module, it will be called ath6kl_sdio.
+         Please note that AR6002 and AR6001 are not supported by this
+         driver.
+
+config ATH6KL_USB
+       tristate "Atheros ath6kl USB support"
+       depends on ATH6KL
+       depends on USB
+       depends on CFG80211
+       depends on EXPERIMENTAL
+       ---help---
+         This module adds support for wireless adapters based on
+         Atheros AR6004 chipset running over USB. This is still under
+         implementation and it isn't functional. If you choose to
+         build it as a module, it will be called ath6kl_usb.
 
 config ATH6KL_DEBUG
        bool "Atheros ath6kl debugging"
index 7070693..e14cef9 100644 (file)
 # 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__
index a962fe4..aef00d5 100644 (file)
 #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;
 
index 009e8f6..f1ca681 100644 (file)
  * 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
index 0252604..6c59a21 100644 (file)
 #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);
 
index 59fa9d8..81f20a5 100644 (file)
@@ -20,7 +20,8 @@
 enum ath6kl_cfg_suspend_mode {
        ATH6KL_CFG_SUSPEND_DEEPSLEEP,
        ATH6KL_CFG_SUSPEND_CUTPOWER,
-       ATH6KL_CFG_SUSPEND_WOW
+       ATH6KL_CFG_SUSPEND_WOW,
+       ATH6KL_CFG_SUSPEND_SCHED_SCAN,
 };
 
 struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
@@ -52,6 +53,7 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
 
 int ath6kl_cfg80211_resume(struct ath6kl *ar);
 
-void ath6kl_cfg80211_stop(struct ath6kl *ar);
+void ath6kl_cfg80211_stop(struct ath6kl_vif *vif);
+void ath6kl_cfg80211_stop_all(struct ath6kl *ar);
 
 #endif /* ATH6KL_CFG80211_H */
index 41e465f..bfd6597 100644 (file)
@@ -71,6 +71,7 @@ enum crypto_type {
        WEP_CRYPT           = 0x02,
        TKIP_CRYPT          = 0x04,
        AES_CRYPT           = 0x08,
+       WAPI_CRYPT          = 0x10,
 };
 
 struct htc_endpoint_credit_dist;
index e7e095e..c863a28 100644 (file)
@@ -70,10 +70,20 @@ enum ath6kl_fw_ie_type {
        ATH6KL_FW_IE_RESERVED_RAM_SIZE = 5,
        ATH6KL_FW_IE_CAPABILITIES = 6,
        ATH6KL_FW_IE_PATCH_ADDR = 7,
+       ATH6KL_FW_IE_BOARD_ADDR = 8,
+       ATH6KL_FW_IE_VIF_MAX = 9,
 };
 
 enum ath6kl_fw_capability {
        ATH6KL_FW_CAPABILITY_HOST_P2P = 0,
+       ATH6KL_FW_CAPABILITY_SCHED_SCAN = 1,
+
+       /*
+        * Firmware is capable of supporting P2P mgmt operations on a
+        * station interface. After group formation, the station
+        * interface will become a P2P client/GO interface as the case may be
+        */
+       ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
 
        /* this needs to be last */
        ATH6KL_FW_CAPABILITY_MAX,
@@ -88,37 +98,47 @@ struct ath6kl_fw_ie {
 };
 
 /* AR6003 1.0 definitions */
-#define AR6003_REV1_VERSION                 0x300002ba
+#define AR6003_HW_1_0_VERSION                 0x300002ba
 
 /* AR6003 2.0 definitions */
-#define AR6003_REV2_VERSION                 0x30000384
-#define AR6003_REV2_PATCH_DOWNLOAD_ADDRESS  0x57e910
-#define AR6003_REV2_OTP_FILE                "ath6k/AR6003/hw2.0/otp.bin.z77"
-#define AR6003_REV2_FIRMWARE_FILE           "ath6k/AR6003/hw2.0/athwlan.bin.z77"
-#define AR6003_REV2_TCMD_FIRMWARE_FILE      "ath6k/AR6003/hw2.0/athtcmd_ram.bin"
-#define AR6003_REV2_PATCH_FILE              "ath6k/AR6003/hw2.0/data.patch.bin"
-#define AR6003_REV2_FIRMWARE_2_FILE         "ath6k/AR6003/hw2.0/fw-2.bin"
-#define AR6003_REV2_BOARD_DATA_FILE         "ath6k/AR6003/hw2.0/bdata.bin"
-#define AR6003_REV2_DEFAULT_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.SD31.bin"
+#define AR6003_HW_2_0_VERSION                 0x30000384
+#define AR6003_HW_2_0_PATCH_DOWNLOAD_ADDRESS  0x57e910
+#define AR6003_HW_2_0_OTP_FILE "ath6k/AR6003/hw2.0/otp.bin.z77"
+#define AR6003_HW_2_0_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athwlan.bin.z77"
+#define AR6003_HW_2_0_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athtcmd_ram.bin"
+#define AR6003_HW_2_0_PATCH_FILE "ath6k/AR6003/hw2.0/data.patch.bin"
+#define AR6003_HW_2_0_FIRMWARE_2_FILE "ath6k/AR6003/hw2.0/fw-2.bin"
+#define AR6003_HW_2_0_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin"
+#define AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE \
+                       "ath6k/AR6003/hw2.0/bdata.SD31.bin"
 
 /* AR6003 3.0 definitions */
-#define AR6003_REV3_VERSION                 0x30000582
-#define AR6003_REV3_OTP_FILE                "ath6k/AR6003/hw2.1.1/otp.bin"
-#define AR6003_REV3_FIRMWARE_FILE           "ath6k/AR6003/hw2.1.1/athwlan.bin"
-#define AR6003_REV3_TCMD_FIRMWARE_FILE    "ath6k/AR6003/hw2.1.1/athtcmd_ram.bin"
-#define AR6003_REV3_PATCH_FILE            "ath6k/AR6003/hw2.1.1/data.patch.bin"
-#define AR6003_REV3_FIRMWARE_2_FILE           "ath6k/AR6003/hw2.1.1/fw-2.bin"
-#define AR6003_REV3_BOARD_DATA_FILE       "ath6k/AR6003/hw2.1.1/bdata.bin"
-#define AR6003_REV3_DEFAULT_BOARD_DATA_FILE    \
-       "ath6k/AR6003/hw2.1.1/bdata.SD31.bin"
+#define AR6003_HW_2_1_1_VERSION                 0x30000582
+#define AR6003_HW_2_1_1_OTP_FILE "ath6k/AR6003/hw2.1.1/otp.bin"
+#define AR6003_HW_2_1_1_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athwlan.bin"
+#define AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE \
+                       "ath6k/AR6003/hw2.1.1/athtcmd_ram.bin"
+#define AR6003_HW_2_1_1_PATCH_FILE "ath6k/AR6003/hw2.1.1/data.patch.bin"
+#define AR6003_HW_2_1_1_FIRMWARE_2_FILE "ath6k/AR6003/hw2.1.1/fw-2.bin"
+#define AR6003_HW_2_1_1_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin"
+#define AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE        \
+                       "ath6k/AR6003/hw2.1.1/bdata.SD31.bin"
 
 /* AR6004 1.0 definitions */
-#define AR6004_REV1_VERSION                 0x30000623
-#define AR6004_REV1_FIRMWARE_FILE           "ath6k/AR6004/hw6.1/fw.ram.bin"
-#define AR6004_REV1_FIRMWARE_2_FILE         "ath6k/AR6004/hw6.1/fw-2.bin"
-#define AR6004_REV1_BOARD_DATA_FILE         "ath6k/AR6004/hw6.1/bdata.bin"
-#define AR6004_REV1_DEFAULT_BOARD_DATA_FILE "ath6k/AR6004/hw6.1/bdata.DB132.bin"
-#define AR6004_REV1_EPPING_FIRMWARE_FILE "ath6k/AR6004/hw6.1/endpointping.bin"
+#define AR6004_HW_1_0_VERSION                 0x30000623
+#define AR6004_HW_1_0_FIRMWARE_2_FILE         "ath6k/AR6004/hw1.0/fw-2.bin"
+#define AR6004_HW_1_0_FIRMWARE_FILE           "ath6k/AR6004/hw1.0/fw.ram.bin"
+#define AR6004_HW_1_0_BOARD_DATA_FILE         "ath6k/AR6004/hw1.0/bdata.bin"
+#define AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE \
+       "ath6k/AR6004/hw1.0/bdata.DB132.bin"
+
+/* AR6004 1.1 definitions */
+#define AR6004_HW_1_1_VERSION                 0x30000001
+#define AR6004_HW_1_1_FIRMWARE_2_FILE         "ath6k/AR6004/hw1.1/fw-2.bin"
+#define AR6004_HW_1_1_FIRMWARE_FILE           "ath6k/AR6004/hw1.1/fw.ram.bin"
+#define AR6004_HW_1_1_BOARD_DATA_FILE         "ath6k/AR6004/hw1.1/bdata.bin"
+#define AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE \
+       "ath6k/AR6004/hw1.1/bdata.DB132.bin"
 
 /* Per STA data, used in AP mode */
 #define STA_PS_AWAKE           BIT(0)
@@ -272,6 +292,8 @@ struct ath6kl_bmi {
        u32 cmd_credits;
        bool done_sent;
        u8 *cmd_buf;
+       u32 max_data_size;
+       u32 max_cmd_size;
 };
 
 struct target_stats {
@@ -381,7 +403,16 @@ struct ath6kl_req_key {
        u8 key_len;
 };
 
-#define MAX_NUM_VIF    1
+enum ath6kl_hif_type {
+       ATH6KL_HIF_TYPE_SDIO,
+       ATH6KL_HIF_TYPE_USB,
+};
+
+/*
+ * Driver's maximum limit, note that some firmwares support only one vif
+ * and the runtime (current) limit must be checked from ar->vif_max.
+ */
+#define ATH6KL_VIF_MAX 3
 
 /* vif flags info */
 enum ath6kl_vif_state {
@@ -424,7 +455,10 @@ struct ath6kl_vif {
        struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1];
        struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1];
        struct aggr_info *aggr_cntxt;
+
        struct timer_list disconnect_timer;
+       struct timer_list sched_scan_timer;
+
        struct cfg80211_scan_request *scan_req;
        enum sme_state sme_state;
        int reconnect_flag;
@@ -442,6 +476,8 @@ struct ath6kl_vif {
 #define WOW_LIST_ID            0
 #define WOW_HOST_REQ_DELAY     500 /* ms */
 
+#define ATH6KL_SCHED_SCAN_RESULT_DELAY 5000 /* ms */
+
 /* Flag info */
 enum ath6kl_dev_state {
        WMI_ENABLED,
@@ -460,6 +496,7 @@ enum ath6kl_state {
        ATH6KL_STATE_DEEPSLEEP,
        ATH6KL_STATE_CUTPOWER,
        ATH6KL_STATE_WOW,
+       ATH6KL_STATE_SCHED_SCAN,
 };
 
 struct ath6kl {
@@ -474,11 +511,13 @@ struct ath6kl {
        int tx_pending[ENDPOINT_MAX];
        int total_tx_data_pend;
        struct htc_target *htc_target;
+       enum ath6kl_hif_type hif_type;
        void *hif_priv;
        struct list_head vif_list;
        /* Lock to avoid race in vif_list entries among add/del/traverse */
        spinlock_t list_lock;
        u8 num_vif;
+       unsigned int vif_max;
        u8 max_norm_iface;
        u8 avail_idx_map;
        spinlock_t lock;
@@ -517,7 +556,6 @@ struct ath6kl {
        struct list_head amsdu_rx_buffer_queue;
        u8 rx_meta_ver;
        enum wlan_low_pwr_state wlan_pwr_state;
-       struct wmi_scan_params_cmd sc_params;
        u8 mac_addr[ETH_ALEN];
 #define AR_MCAST_FILTER_MAC_ADDR_SIZE  4
        struct {
@@ -525,12 +563,25 @@ struct ath6kl {
                size_t rx_report_len;
        } tm;
 
-       struct {
+       struct ath6kl_hw {
+               u32 id;
+               const char *name;
                u32 dataset_patch_addr;
                u32 app_load_addr;
                u32 app_start_override_addr;
                u32 board_ext_data_addr;
                u32 reserved_ram_size;
+               u32 board_addr;
+               u32 refclk_hz;
+               u32 uarttx_pin;
+
+               const char *fw_otp;
+               const char *fw;
+               const char *fw_tcmd;
+               const char *fw_patch;
+               const char *fw_api2;
+               const char *fw_board;
+               const char *fw_default_board;
        } hw;
 
        u16 conf_flags;
@@ -583,7 +634,7 @@ struct ath6kl {
 #endif /* CONFIG_ATH6KL_DEBUG */
 };
 
-static inline void *ath6kl_priv(struct net_device *dev)
+static inline struct ath6kl *ath6kl_priv(struct net_device *dev)
 {
        return ((struct ath6kl_vif *) netdev_priv(dev))->ar;
 }
index 9eff0d0..eb808b4 100644 (file)
@@ -1551,10 +1551,10 @@ static ssize_t ath6kl_listen_int_read(struct file *file,
                                                size_t count, loff_t *ppos)
 {
        struct ath6kl *ar = file->private_data;
-       char buf[16];
+       char buf[32];
        int len;
 
-       len = snprintf(buf, sizeof(buf), "%u %u\n", ar->listen_intvl_t,
+       len = scnprintf(buf, sizeof(buf), "%u %u\n", ar->listen_intvl_t,
                                        ar->listen_intvl_b);
 
        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
index 9853c9c..e569c65 100644 (file)
@@ -41,6 +41,7 @@ enum ATH6K_DEBUG_MASK {
        ATH6KL_DBG_BOOT         = BIT(18),    /* driver init and fw boot */
        ATH6KL_DBG_WMI_DUMP     = BIT(19),
        ATH6KL_DBG_SUSPEND      = BIT(20),
+       ATH6KL_DBG_USB          = BIT(21),
        ATH6KL_DBG_ANY          = 0xffffffff  /* enable all logs */
 };
 
index eed2287..2fe1dad 100644 (file)
@@ -91,6 +91,36 @@ static inline int ath6kl_hif_suspend(struct ath6kl *ar,
        return ar->hif_ops->suspend(ar, wow);
 }
 
+/*
+ * Read from the ATH6KL through its diagnostic window. No cooperation from
+ * the Target is required for this.
+ */
+static inline int ath6kl_hif_diag_read32(struct ath6kl *ar, u32 address,
+                                        u32 *value)
+{
+       return ar->hif_ops->diag_read32(ar, address, value);
+}
+
+/*
+ * Write to the ATH6KL through its diagnostic window. No cooperation from
+ * the Target is required for this.
+ */
+static inline int ath6kl_hif_diag_write32(struct ath6kl *ar, u32 address,
+                                         __le32 value)
+{
+       return ar->hif_ops->diag_write32(ar, address, value);
+}
+
+static inline int ath6kl_hif_bmi_read(struct ath6kl *ar, u8 *buf, u32 len)
+{
+       return ar->hif_ops->bmi_read(ar, buf, len);
+}
+
+static inline int ath6kl_hif_bmi_write(struct ath6kl *ar, u8 *buf, u32 len)
+{
+       return ar->hif_ops->bmi_write(ar, buf, len);
+}
+
 static inline int ath6kl_hif_resume(struct ath6kl *ar)
 {
        ath6kl_dbg(ATH6KL_DBG_HIF, "hif resume\n");
index e57da35..0772ef6 100644 (file)
@@ -689,6 +689,11 @@ int ath6kl_hif_setup(struct ath6kl_device *dev)
        ath6kl_dbg(ATH6KL_DBG_HIF, "hif block size %d mbox addr 0x%x\n",
                   dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr);
 
+       /* usb doesn't support enabling interrupts */
+       /* FIXME: remove check once USB support is implemented */
+       if (dev->ar->hif_type == ATH6KL_HIF_TYPE_USB)
+               return 0;
+
        status = ath6kl_hif_disable_intrs(dev);
 
 fail_setup:
index f2dc3bc..699a036 100644 (file)
@@ -35,6 +35,7 @@
 #define MAX_SCATTER_REQ_TRANSFER_SIZE    (32 * 1024)
 
 #define MANUFACTURER_ID_AR6003_BASE        0x300
+#define MANUFACTURER_ID_AR6004_BASE        0x400
     /* SDIO manufacturer ID and Codes */
 #define MANUFACTURER_ID_ATH6KL_BASE_MASK     0xFF00
 #define MANUFACTURER_CODE                  0x271       /* Atheros */
@@ -244,6 +245,10 @@ struct ath6kl_hif_ops {
        void (*cleanup_scatter)(struct ath6kl *ar);
        int (*suspend)(struct ath6kl *ar, struct cfg80211_wowlan *wow);
        int (*resume)(struct ath6kl *ar);
+       int (*diag_read32)(struct ath6kl *ar, u32 address, u32 *value);
+       int (*diag_write32)(struct ath6kl *ar, u32 address, __le32 value);
+       int (*bmi_read)(struct ath6kl *ar, u8 *buf, u32 len);
+       int (*bmi_write)(struct ath6kl *ar, u8 *buf, u32 len);
        int (*power_on)(struct ath6kl *ar);
        int (*power_off)(struct ath6kl *ar);
        void (*stop)(struct ath6kl *ar);
index f3b63ca..b017022 100644 (file)
@@ -2543,6 +2543,12 @@ int ath6kl_htc_wait_target(struct htc_target *target)
        struct htc_service_connect_resp resp;
        int status;
 
+       /* FIXME: remove once USB support is implemented */
+       if (target->dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) {
+               ath6kl_err("HTC doesn't support USB yet. Patience!\n");
+               return -EOPNOTSUPP;
+       }
+
        /* we should be getting 1 control message that the target is ready */
        packet = htc_wait_for_ctrl_msg(target);
 
@@ -2772,7 +2778,9 @@ void ath6kl_htc_cleanup(struct htc_target *target)
 {
        struct htc_packet *packet, *tmp_packet;
 
-       ath6kl_hif_cleanup_scatter(target->dev->ar);
+       /* FIXME: remove check once USB support is implemented */
+       if (target->dev->ar->hif_type != ATH6KL_HIF_TYPE_USB)
+               ath6kl_hif_cleanup_scatter(target->dev->ar);
 
        list_for_each_entry_safe(packet, tmp_packet,
                        &target->free_ctrl_txbuf, list) {
index 30050af..368ecbd 100644 (file)
@@ -33,6 +33,80 @@ module_param(debug_mask, uint, 0644);
 module_param(testmode, uint, 0644);
 module_param(suspend_cutpower, bool, 0444);
 
+static const struct ath6kl_hw hw_list[] = {
+       {
+               .id                             = AR6003_HW_2_0_VERSION,
+               .name                           = "ar6003 hw 2.0",
+               .dataset_patch_addr             = 0x57e884,
+               .app_load_addr                  = 0x543180,
+               .board_ext_data_addr            = 0x57e500,
+               .reserved_ram_size              = 6912,
+               .refclk_hz                      = 26000000,
+               .uarttx_pin                     = 8,
+
+               /* hw2.0 needs override address hardcoded */
+               .app_start_override_addr        = 0x944C00,
+
+               .fw_otp                 = AR6003_HW_2_0_OTP_FILE,
+               .fw                     = AR6003_HW_2_0_FIRMWARE_FILE,
+               .fw_tcmd                = AR6003_HW_2_0_TCMD_FIRMWARE_FILE,
+               .fw_patch               = AR6003_HW_2_0_PATCH_FILE,
+               .fw_api2                = AR6003_HW_2_0_FIRMWARE_2_FILE,
+               .fw_board               = AR6003_HW_2_0_BOARD_DATA_FILE,
+               .fw_default_board       = AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE,
+       },
+       {
+               .id                             = AR6003_HW_2_1_1_VERSION,
+               .name                           = "ar6003 hw 2.1.1",
+               .dataset_patch_addr             = 0x57ff74,
+               .app_load_addr                  = 0x1234,
+               .board_ext_data_addr            = 0x542330,
+               .reserved_ram_size              = 512,
+               .refclk_hz                      = 26000000,
+               .uarttx_pin                     = 8,
+
+               .fw_otp                 = AR6003_HW_2_1_1_OTP_FILE,
+               .fw                     = AR6003_HW_2_1_1_FIRMWARE_FILE,
+               .fw_tcmd                = AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE,
+               .fw_patch               = AR6003_HW_2_1_1_PATCH_FILE,
+               .fw_api2                = AR6003_HW_2_1_1_FIRMWARE_2_FILE,
+               .fw_board               = AR6003_HW_2_1_1_BOARD_DATA_FILE,
+               .fw_default_board       = AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE,
+       },
+       {
+               .id                             = AR6004_HW_1_0_VERSION,
+               .name                           = "ar6004 hw 1.0",
+               .dataset_patch_addr             = 0x57e884,
+               .app_load_addr                  = 0x1234,
+               .board_ext_data_addr            = 0x437000,
+               .reserved_ram_size              = 19456,
+               .board_addr                     = 0x433900,
+               .refclk_hz                      = 26000000,
+               .uarttx_pin                     = 11,
+
+               .fw                     = AR6004_HW_1_0_FIRMWARE_FILE,
+               .fw_api2                = AR6004_HW_1_0_FIRMWARE_2_FILE,
+               .fw_board               = AR6004_HW_1_0_BOARD_DATA_FILE,
+               .fw_default_board       = AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE,
+       },
+       {
+               .id                             = AR6004_HW_1_1_VERSION,
+               .name                           = "ar6004 hw 1.1",
+               .dataset_patch_addr             = 0x57e884,
+               .app_load_addr                  = 0x1234,
+               .board_ext_data_addr            = 0x437000,
+               .reserved_ram_size              = 11264,
+               .board_addr                     = 0x43d400,
+               .refclk_hz                      = 40000000,
+               .uarttx_pin                     = 11,
+
+               .fw                     = AR6004_HW_1_1_FIRMWARE_FILE,
+               .fw_api2                = AR6004_HW_1_1_FIRMWARE_2_FILE,
+               .fw_board               = AR6004_HW_1_1_BOARD_DATA_FILE,
+               .fw_default_board       = AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE,
+       },
+};
+
 /*
  * Include definitions here that can be used to tune the WLAN module
  * behavior. Different customers can tune the behavior as per their needs,
@@ -58,7 +132,6 @@ module_param(suspend_cutpower, bool, 0444);
  */
 #define WLAN_CONFIG_DISCONNECT_TIMEOUT 10
 
-#define CONFIG_AR600x_DEBUG_UART_TX_PIN 8
 
 #define ATH6KL_DATA_OFFSET    64
 struct sk_buff *ath6kl_buf_alloc(int size)
@@ -348,11 +421,7 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx)
                        status = -EIO;
                }
 
-       /*
-        * FIXME: Make sure p2p configurations are not applied to
-        * non-p2p capable interfaces when multivif support is enabled.
-        */
-       if (ar->p2p) {
+       if (ar->p2p && (ar->vif_max == 1 || idx)) {
                ret = ath6kl_wmi_info_req_cmd(ar->wmi, idx,
                                              P2P_FLAG_CAPABILITIES_REQ |
                                              P2P_FLAG_MACADDR_REQ |
@@ -365,11 +434,7 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx)
                }
        }
 
-       /*
-        * FIXME: Make sure p2p configurations are not applied to
-        * non-p2p capable interfaces when multivif support is enabled.
-        */
-       if (ar->p2p) {
+       if (ar->p2p && (ar->vif_max == 1 || idx)) {
                /* Enable Probe Request reporting for P2P */
                ret = ath6kl_wmi_probe_report_req_cmd(ar->wmi, idx, true);
                if (ret) {
@@ -385,7 +450,7 @@ int ath6kl_configure_target(struct ath6kl *ar)
 {
        u32 param, ram_reserved_size;
        u8 fw_iftype, fw_mode = 0, fw_submode = 0;
-       int i;
+       int i, status;
 
        /*
         * Note: Even though the firmware interface type is
@@ -397,7 +462,7 @@ int ath6kl_configure_target(struct ath6kl *ar)
         */
        fw_iftype = HI_OPTION_FW_MODE_BSS_STA;
 
-       for (i = 0; i < MAX_NUM_VIF; i++)
+       for (i = 0; i < ar->vif_max; i++)
                fw_mode |= fw_iftype << (i * HI_OPTION_FW_MODE_BITS);
 
        /*
@@ -411,15 +476,11 @@ int ath6kl_configure_target(struct ath6kl *ar)
                fw_submode |= HI_OPTION_FW_SUBMODE_NONE <<
                              (i * HI_OPTION_FW_SUBMODE_BITS);
 
-       for (i = ar->max_norm_iface; i < MAX_NUM_VIF; i++)
+       for (i = ar->max_norm_iface; i < ar->vif_max; i++)
                fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV <<
                              (i * HI_OPTION_FW_SUBMODE_BITS);
 
-       /*
-        * FIXME: This needs to be removed once the multivif
-        * support is enabled.
-        */
-       if (ar->p2p)
+       if (ar->p2p && ar->vif_max == 1)
                fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV;
 
        param = HTC_PROTOCOL_VERSION;
@@ -442,7 +503,7 @@ int ath6kl_configure_target(struct ath6kl *ar)
                return -EIO;
        }
 
-       param |= (MAX_NUM_VIF << HI_OPTION_NUM_DEV_SHIFT);
+       param |= (ar->vif_max << HI_OPTION_NUM_DEV_SHIFT);
        param |= fw_mode << HI_OPTION_FW_MODE_SHIFT;
        param |= fw_submode << HI_OPTION_FW_SUBMODE_SHIFT;
 
@@ -491,6 +552,24 @@ int ath6kl_configure_target(struct ath6kl *ar)
                /* use default number of control buffers */
                return -EIO;
 
+       /* Configure GPIO AR600x UART */
+       param = ar->hw.uarttx_pin;
+       status = ath6kl_bmi_write(ar,
+                               ath6kl_get_hi_item_addr(ar,
+                               HI_ITEM(hi_dbg_uart_txpin)),
+                               (u8 *)&param, 4);
+       if (status)
+               return status;
+
+       /* Configure target refclk_hz */
+       param =  ar->hw.refclk_hz;
+       status = ath6kl_bmi_write(ar,
+                               ath6kl_get_hi_item_addr(ar,
+                               HI_ITEM(hi_refclk_hz)),
+                               (u8 *)&param, 4);
+       if (status)
+               return status;
+
        return 0;
 }
 
@@ -550,11 +629,11 @@ static int ath6kl_get_fw(struct ath6kl *ar, const char *filename,
 static const char *get_target_ver_dir(const struct ath6kl *ar)
 {
        switch (ar->version.target_ver) {
-       case AR6003_REV1_VERSION:
+       case AR6003_HW_1_0_VERSION:
                return "ath6k/AR6003/hw1.0";
-       case AR6003_REV2_VERSION:
+       case AR6003_HW_2_0_VERSION:
                return "ath6k/AR6003/hw2.0";
-       case AR6003_REV3_VERSION:
+       case AR6003_HW_2_1_1_VERSION:
                return "ath6k/AR6003/hw2.1.1";
        }
        ath6kl_warn("%s: unsupported target version 0x%x.\n", __func__,
@@ -612,17 +691,10 @@ static int ath6kl_fetch_board_file(struct ath6kl *ar)
        if (ar->fw_board != NULL)
                return 0;
 
-       switch (ar->version.target_ver) {
-       case AR6003_REV2_VERSION:
-               filename = AR6003_REV2_BOARD_DATA_FILE;
-               break;
-       case AR6004_REV1_VERSION:
-               filename = AR6004_REV1_BOARD_DATA_FILE;
-               break;
-       default:
-               filename = AR6003_REV3_BOARD_DATA_FILE;
-               break;
-       }
+       if (WARN_ON(ar->hw.fw_board == NULL))
+               return -EINVAL;
+
+       filename = ar->hw.fw_board;
 
        ret = ath6kl_get_fw(ar, filename, &ar->fw_board,
                            &ar->fw_board_len);
@@ -640,17 +712,7 @@ static int ath6kl_fetch_board_file(struct ath6kl *ar)
        ath6kl_warn("Failed to get board file %s (%d), trying to find default board file.\n",
                    filename, ret);
 
-       switch (ar->version.target_ver) {
-       case AR6003_REV2_VERSION:
-               filename = AR6003_REV2_DEFAULT_BOARD_DATA_FILE;
-               break;
-       case AR6004_REV1_VERSION:
-               filename = AR6004_REV1_DEFAULT_BOARD_DATA_FILE;
-               break;
-       default:
-               filename = AR6003_REV3_DEFAULT_BOARD_DATA_FILE;
-               break;
-       }
+       filename = ar->hw.fw_default_board;
 
        ret = ath6kl_get_fw(ar, filename, &ar->fw_board,
                            &ar->fw_board_len);
@@ -674,19 +736,14 @@ static int ath6kl_fetch_otp_file(struct ath6kl *ar)
        if (ar->fw_otp != NULL)
                return 0;
 
-       switch (ar->version.target_ver) {
-       case AR6003_REV2_VERSION:
-               filename = AR6003_REV2_OTP_FILE;
-               break;
-       case AR6004_REV1_VERSION:
-               ath6kl_dbg(ATH6KL_DBG_TRC, "AR6004 doesn't need OTP file\n");
+       if (ar->hw.fw_otp == NULL) {
+               ath6kl_dbg(ATH6KL_DBG_BOOT,
+                          "no OTP file configured for this hw\n");
                return 0;
-               break;
-       default:
-               filename = AR6003_REV3_OTP_FILE;
-               break;
        }
 
+       filename = ar->hw.fw_otp;
+
        ret = ath6kl_get_fw(ar, filename, &ar->fw_otp,
                            &ar->fw_otp_len);
        if (ret) {
@@ -707,38 +764,22 @@ static int ath6kl_fetch_fw_file(struct ath6kl *ar)
                return 0;
 
        if (testmode) {
-               switch (ar->version.target_ver) {
-               case AR6003_REV2_VERSION:
-                       filename = AR6003_REV2_TCMD_FIRMWARE_FILE;
-                       break;
-               case AR6003_REV3_VERSION:
-                       filename = AR6003_REV3_TCMD_FIRMWARE_FILE;
-                       break;
-               case AR6004_REV1_VERSION:
-                       ath6kl_warn("testmode not supported with ar6004\n");
+               if (ar->hw.fw_tcmd == NULL) {
+                       ath6kl_warn("testmode not supported\n");
                        return -EOPNOTSUPP;
-               default:
-                       ath6kl_warn("unknown target version: 0x%x\n",
-                                      ar->version.target_ver);
-                       return -EINVAL;
                }
 
+               filename = ar->hw.fw_tcmd;
+
                set_bit(TESTMODE, &ar->flag);
 
                goto get_fw;
        }
 
-       switch (ar->version.target_ver) {
-       case AR6003_REV2_VERSION:
-               filename = AR6003_REV2_FIRMWARE_FILE;
-               break;
-       case AR6004_REV1_VERSION:
-               filename = AR6004_REV1_FIRMWARE_FILE;
-               break;
-       default:
-               filename = AR6003_REV3_FIRMWARE_FILE;
-               break;
-       }
+       if (WARN_ON(ar->hw.fw == NULL))
+               return -EINVAL;
+
+       filename = ar->hw.fw;
 
 get_fw:
        ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len);
@@ -756,27 +797,20 @@ static int ath6kl_fetch_patch_file(struct ath6kl *ar)
        const char *filename;
        int ret;
 
-       switch (ar->version.target_ver) {
-       case AR6003_REV2_VERSION:
-               filename = AR6003_REV2_PATCH_FILE;
-               break;
-       case AR6004_REV1_VERSION:
-               /* FIXME: implement for AR6004 */
+       if (ar->fw_patch != NULL)
                return 0;
-               break;
-       default:
-               filename = AR6003_REV3_PATCH_FILE;
-               break;
-       }
 
-       if (ar->fw_patch == NULL) {
-               ret = ath6kl_get_fw(ar, filename, &ar->fw_patch,
-                                   &ar->fw_patch_len);
-               if (ret) {
-                       ath6kl_err("Failed to get patch file %s: %d\n",
-                                  filename, ret);
-                       return ret;
-               }
+       if (ar->hw.fw_patch == NULL)
+               return 0;
+
+       filename = ar->hw.fw_patch;
+
+       ret = ath6kl_get_fw(ar, filename, &ar->fw_patch,
+                           &ar->fw_patch_len);
+       if (ret) {
+               ath6kl_err("Failed to get patch file %s: %d\n",
+                          filename, ret);
+               return ret;
        }
 
        return 0;
@@ -811,19 +845,10 @@ static int ath6kl_fetch_fw_api2(struct ath6kl *ar)
        int ret, ie_id, i, index, bit;
        __le32 *val;
 
-       switch (ar->version.target_ver) {
-       case AR6003_REV2_VERSION:
-               filename = AR6003_REV2_FIRMWARE_2_FILE;
-               break;
-       case AR6003_REV3_VERSION:
-               filename = AR6003_REV3_FIRMWARE_2_FILE;
-               break;
-       case AR6004_REV1_VERSION:
-               filename = AR6004_REV1_FIRMWARE_2_FILE;
-               break;
-       default:
+       if (ar->hw.fw_api2 == NULL)
                return -EOPNOTSUPP;
-       }
+
+       filename = ar->hw.fw_api2;
 
        ret = request_firmware(&fw, filename, ar->dev);
        if (ret)
@@ -913,12 +938,15 @@ static int ath6kl_fetch_fw_api2(struct ath6kl *ar)
                                   ar->hw.reserved_ram_size);
                        break;
                case ATH6KL_FW_IE_CAPABILITIES:
+                       if (ie_len < DIV_ROUND_UP(ATH6KL_FW_CAPABILITY_MAX, 8))
+                               break;
+
                        ath6kl_dbg(ATH6KL_DBG_BOOT,
                                   "found firmware capabilities ie (%zd B)\n",
                                   ie_len);
 
                        for (i = 0; i < ATH6KL_FW_CAPABILITY_MAX; i++) {
-                               index = ALIGN(i, 8) / 8;
+                               index = i / 8;
                                bit = i % 8;
 
                                if (data[index] & (1 << bit))
@@ -937,9 +965,34 @@ static int ath6kl_fetch_fw_api2(struct ath6kl *ar)
                        ar->hw.dataset_patch_addr = le32_to_cpup(val);
 
                        ath6kl_dbg(ATH6KL_DBG_BOOT,
-                                  "found patch address ie 0x%d\n",
+                                  "found patch address ie 0x%x\n",
                                   ar->hw.dataset_patch_addr);
                        break;
+               case ATH6KL_FW_IE_BOARD_ADDR:
+                       if (ie_len != sizeof(*val))
+                               break;
+
+                       val = (__le32 *) data;
+                       ar->hw.board_addr = le32_to_cpup(val);
+
+                       ath6kl_dbg(ATH6KL_DBG_BOOT,
+                                  "found board address ie 0x%x\n",
+                                  ar->hw.board_addr);
+                       break;
+               case ATH6KL_FW_IE_VIF_MAX:
+                       if (ie_len != sizeof(*val))
+                               break;
+
+                       val = (__le32 *) data;
+                       ar->vif_max = min_t(unsigned int, le32_to_cpup(val),
+                                           ATH6KL_VIF_MAX);
+
+                       if (ar->vif_max > 1 && !ar->p2p)
+                               ar->max_norm_iface = 2;
+
+                       ath6kl_dbg(ATH6KL_DBG_BOOT,
+                                  "found vif max ie %d\n", ar->vif_max);
+                       break;
                default:
                        ath6kl_dbg(ATH6KL_DBG_BOOT, "Unknown fw ie: %u\n",
                                   le32_to_cpup(&hdr->id));
@@ -994,8 +1047,8 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
         * For AR6004, host determine Target RAM address for
         * writing board data.
         */
-       if (ar->target_type == TARGET_TYPE_AR6004) {
-               board_address = AR6004_REV1_BOARD_DATA_ADDRESS;
+       if (ar->hw.board_addr != 0) {
+               board_address = ar->hw.board_addr;
                ath6kl_bmi_write(ar,
                                ath6kl_get_hi_item_addr(ar,
                                HI_ITEM(hi_board_data)),
@@ -1013,7 +1066,8 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
                        HI_ITEM(hi_board_ext_data)),
                        (u8 *) &board_ext_address, 4);
 
-       if (board_ext_address == 0) {
+       if (ar->target_type == TARGET_TYPE_AR6003 &&
+           board_ext_address == 0) {
                ath6kl_err("Failed to get board file target address.\n");
                return -EINVAL;
        }
@@ -1033,8 +1087,8 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
                break;
        }
 
-       if (ar->fw_board_len == (board_data_size +
-                                board_ext_data_size)) {
+       if (board_ext_address &&
+           ar->fw_board_len == (board_data_size + board_ext_data_size)) {
 
                /* write extended board data */
                ath6kl_dbg(ATH6KL_DBG_BOOT,
@@ -1092,8 +1146,8 @@ static int ath6kl_upload_otp(struct ath6kl *ar)
        bool from_hw = false;
        int ret;
 
-       if (WARN_ON(ar->fw_otp == NULL))
-               return -ENOENT;
+       if (ar->fw_otp == NULL)
+               return 0;
 
        address = ar->hw.app_load_addr;
 
@@ -1142,7 +1196,7 @@ static int ath6kl_upload_firmware(struct ath6kl *ar)
        int ret;
 
        if (WARN_ON(ar->fw == NULL))
-               return -ENOENT;
+               return 0;
 
        address = ar->hw.app_load_addr;
 
@@ -1172,8 +1226,8 @@ static int ath6kl_upload_patch(struct ath6kl *ar)
        u32 address, param;
        int ret;
 
-       if (WARN_ON(ar->fw_patch == NULL))
-               return -ENOENT;
+       if (ar->fw_patch == NULL)
+               return 0;
 
        address = ar->hw.dataset_patch_addr;
 
@@ -1258,7 +1312,7 @@ static int ath6kl_init_upload(struct ath6kl *ar)
                return status;
 
        /* WAR to avoid SDIO CRC err */
-       if (ar->version.target_ver == AR6003_REV2_VERSION) {
+       if (ar->version.target_ver == AR6003_HW_2_0_VERSION) {
                ath6kl_err("temporary war to avoid sdio crc error\n");
 
                param = 0x20;
@@ -1315,47 +1369,29 @@ static int ath6kl_init_upload(struct ath6kl *ar)
        if (status)
                return status;
 
-       /* Configure GPIO AR6003 UART */
-       param = CONFIG_AR600x_DEBUG_UART_TX_PIN;
-       status = ath6kl_bmi_write(ar,
-                                 ath6kl_get_hi_item_addr(ar,
-                                 HI_ITEM(hi_dbg_uart_txpin)),
-                                 (u8 *)&param, 4);
-
        return status;
 }
 
 static int ath6kl_init_hw_params(struct ath6kl *ar)
 {
-       switch (ar->version.target_ver) {
-       case AR6003_REV2_VERSION:
-               ar->hw.dataset_patch_addr = AR6003_REV2_DATASET_PATCH_ADDRESS;
-               ar->hw.app_load_addr = AR6003_REV2_APP_LOAD_ADDRESS;
-               ar->hw.board_ext_data_addr = AR6003_REV2_BOARD_EXT_DATA_ADDRESS;
-               ar->hw.reserved_ram_size = AR6003_REV2_RAM_RESERVE_SIZE;
+       const struct ath6kl_hw *hw;
+       int i;
 
-               /* hw2.0 needs override address hardcoded */
-               ar->hw.app_start_override_addr = 0x944C00;
+       for (i = 0; i < ARRAY_SIZE(hw_list); i++) {
+               hw = &hw_list[i];
 
-               break;
-       case AR6003_REV3_VERSION:
-               ar->hw.dataset_patch_addr = AR6003_REV3_DATASET_PATCH_ADDRESS;
-               ar->hw.app_load_addr = 0x1234;
-               ar->hw.board_ext_data_addr = AR6003_REV3_BOARD_EXT_DATA_ADDRESS;
-               ar->hw.reserved_ram_size = AR6003_REV3_RAM_RESERVE_SIZE;
-               break;
-       case AR6004_REV1_VERSION:
-               ar->hw.dataset_patch_addr = AR6003_REV2_DATASET_PATCH_ADDRESS;
-               ar->hw.app_load_addr = AR6003_REV3_APP_LOAD_ADDRESS;
-               ar->hw.board_ext_data_addr = AR6004_REV1_BOARD_EXT_DATA_ADDRESS;
-               ar->hw.reserved_ram_size = AR6004_REV1_RAM_RESERVE_SIZE;
-               break;
-       default:
+               if (hw->id == ar->version.target_ver)
+                       break;
+       }
+
+       if (i == ARRAY_SIZE(hw_list)) {
                ath6kl_err("Unsupported hardware version: 0x%x\n",
                           ar->version.target_ver);
                return -EINVAL;
        }
 
+       ar->hw = *hw;
+
        ath6kl_dbg(ATH6KL_DBG_BOOT,
                   "target_ver 0x%x target_type 0x%x dataset_patch 0x%x app_load_addr 0x%x\n",
                   ar->version.target_ver, ar->target_type,
@@ -1364,10 +1400,25 @@ static int ath6kl_init_hw_params(struct ath6kl *ar)
                   "app_start_override_addr 0x%x board_ext_data_addr 0x%x reserved_ram_size 0x%x",
                   ar->hw.app_start_override_addr, ar->hw.board_ext_data_addr,
                   ar->hw.reserved_ram_size);
+       ath6kl_dbg(ATH6KL_DBG_BOOT,
+                  "refclk_hz %d uarttx_pin %d",
+                  ar->hw.refclk_hz, ar->hw.uarttx_pin);
 
        return 0;
 }
 
+static const char *ath6kl_init_get_hif_name(enum ath6kl_hif_type type)
+{
+       switch (type) {
+       case ATH6KL_HIF_TYPE_SDIO:
+               return "sdio";
+       case ATH6KL_HIF_TYPE_USB:
+               return "usb";
+       }
+
+       return NULL;
+}
+
 int ath6kl_init_hw_start(struct ath6kl *ar)
 {
        long timeleft;
@@ -1428,6 +1479,15 @@ int ath6kl_init_hw_start(struct ath6kl *ar)
 
        ath6kl_dbg(ATH6KL_DBG_BOOT, "firmware booted\n");
 
+
+       if (test_and_clear_bit(FIRST_BOOT, &ar->flag)) {
+               ath6kl_info("%s %s fw %s%s\n",
+                           ar->hw.name,
+                           ath6kl_init_get_hif_name(ar->hif_type),
+                           ar->wiphy->fw_version,
+                           test_bit(TESTMODE, &ar->flag) ? " testmode" : "");
+       }
+
        if (ar->version.abi_ver != ATH6KL_ABI_VERSION) {
                ath6kl_err("abi version mismatch: host(0x%x), target(0x%x)\n",
                           ATH6KL_ABI_VERSION, ar->version.abi_ver);
@@ -1448,7 +1508,7 @@ int ath6kl_init_hw_start(struct ath6kl *ar)
        if ((ath6kl_set_host_app_area(ar)) != 0)
                ath6kl_err("unable to set the host app area\n");
 
-       for (i = 0; i < MAX_NUM_VIF; i++) {
+       for (i = 0; i < ar->vif_max; i++) {
                ret = ath6kl_target_config_wlan_params(ar, i);
                if (ret)
                        goto err_htc_stop;
@@ -1558,7 +1618,7 @@ int ath6kl_core_init(struct ath6kl *ar)
                goto err_node_cleanup;
        }
 
-       for (i = 0; i < MAX_NUM_VIF; i++)
+       for (i = 0; i < ar->vif_max; i++)
                ar->avail_idx_map |= BIT(i);
 
        rtnl_lock();
@@ -1603,7 +1663,17 @@ int ath6kl_core_init(struct ath6kl *ar)
 
        ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
                            WIPHY_FLAG_HAVE_AP_SME |
-                           WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+                           WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
+                           WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
+
+       if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities))
+               ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+
+       ar->wiphy->probe_resp_offload =
+               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
+               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
+               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P |
+               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U;
 
        set_bit(FIRST_BOOT, &ar->flag);
 
index 5e5f4ca..eea3c74 100644 (file)
@@ -175,64 +175,6 @@ void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie)
        ar->cookie_count++;
 }
 
-/* set the window address register (using 4-byte register access ). */
-static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr)
-{
-       int status;
-       s32 i;
-       __le32 addr_val;
-
-       /*
-        * Write bytes 1,2,3 of the register to set the upper address bytes,
-        * the LSB is written last to initiate the access cycle
-        */
-
-       for (i = 1; i <= 3; i++) {
-               /*
-                * Fill the buffer with the address byte value we want to
-                * hit 4 times. No need to worry about endianness as the
-                * same byte is copied to all four bytes of addr_val at
-                * any time.
-                */
-               memset((u8 *)&addr_val, ((u8 *)&addr)[i], 4);
-
-               /*
-                * Hit each byte of the register address with a 4-byte
-                * write operation to the same address, this is a harmless
-                * operation.
-                */
-               status = hif_read_write_sync(ar, reg_addr + i, (u8 *)&addr_val,
-                                            4, HIF_WR_SYNC_BYTE_FIX);
-               if (status)
-                       break;
-       }
-
-       if (status) {
-               ath6kl_err("failed to write initial bytes of 0x%x to window reg: 0x%X\n",
-                          addr, reg_addr);
-               return status;
-       }
-
-       /*
-        * Write the address register again, this time write the whole
-        * 4-byte value. The effect here is that the LSB write causes the
-        * cycle to start, the extra 3 byte write to bytes 1,2,3 has no
-        * effect since we are writing the same values again
-        */
-       addr_val = cpu_to_le32(addr);
-       status = hif_read_write_sync(ar, reg_addr,
-                                    (u8 *)&(addr_val),
-                                    4, HIF_WR_SYNC_BYTE_INC);
-
-       if (status) {
-               ath6kl_err("failed to write 0x%x to window reg: 0x%X\n",
-                          addr, reg_addr);
-               return status;
-       }
-
-       return 0;
-}
-
 /*
  * Read from the hardware through its diagnostic window. No cooperation
  * from the firmware is required for this.
@@ -241,14 +183,7 @@ int ath6kl_diag_read32(struct ath6kl *ar, u32 address, u32 *value)
 {
        int ret;
 
-       /* set window register to start read cycle */
-       ret = ath6kl_set_addrwin_reg(ar, WINDOW_READ_ADDR_ADDRESS, address);
-       if (ret)
-               return ret;
-
-       /* read the data */
-       ret = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *) value,
-                                 sizeof(*value), HIF_RD_SYNC_BYTE_INC);
+       ret = ath6kl_hif_diag_read32(ar, address, value);
        if (ret) {
                ath6kl_warn("failed to read32 through diagnose window: %d\n",
                            ret);
@@ -266,18 +201,15 @@ int ath6kl_diag_write32(struct ath6kl *ar, u32 address, __le32 value)
 {
        int ret;
 
-       /* set write data */
-       ret = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *) &value,
-                                 sizeof(value), HIF_WR_SYNC_BYTE_INC);
+       ret = ath6kl_hif_diag_write32(ar, address, value);
+
        if (ret) {
                ath6kl_err("failed to write 0x%x during diagnose window to 0x%d\n",
                           address, value);
                return ret;
        }
 
-       /* set window register, which starts the write cycle */
-       return ath6kl_set_addrwin_reg(ar, WINDOW_WRITE_ADDR_ADDRESS,
-                                     address);
+       return 0;
 }
 
 int ath6kl_diag_read(struct ath6kl *ar, u32 address, void *data, u32 length)
@@ -465,7 +397,9 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel)
        case NONE_AUTH:
                if (vif->prwise_crypto == WEP_CRYPT)
                        ath6kl_install_static_wep_keys(vif);
-               break;
+               if (!ik->valid || ik->key_type != WAPI_CRYPT)
+                       break;
+               /* for WAPI, we need to set the delayed group key, continue: */
        case WPA_PSK_AUTH:
        case WPA2_PSK_AUTH:
        case (WPA_PSK_AUTH | WPA2_PSK_AUTH):
@@ -534,6 +468,18 @@ void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr,
                                wpa_ie = pos; /* WPS IE */
                                break; /* overrides WPA/RSN IE */
                        }
+               } else if (pos[0] == 0x44 && wpa_ie == NULL) {
+                       /*
+                        * Note: WAPI Parameter Set IE re-uses Element ID that
+                        * was officially allocated for BSS AC Access Delay. As
+                        * such, we need to be a bit more careful on when
+                        * parsing the frame. However, BSS AC Access Delay
+                        * element is not supposed to be included in
+                        * (Re)Association Request frames, so this should not
+                        * cause problems.
+                        */
+                       wpa_ie = pos; /* WAPI IE */
+                       break;
                }
                pos += 2 + pos[1];
        }
@@ -581,20 +527,6 @@ void ath6kl_disconnect(struct ath6kl_vif *vif)
 
 /* WMI Event handlers */
 
-static const char *get_hw_id_string(u32 id)
-{
-       switch (id) {
-       case AR6003_REV1_VERSION:
-               return "1.0";
-       case AR6003_REV2_VERSION:
-               return "2.0";
-       case AR6003_REV3_VERSION:
-               return "2.1.1";
-       default:
-               return "unknown";
-       }
-}
-
 void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver)
 {
        struct ath6kl *ar = devt;
@@ -617,13 +549,6 @@ void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver)
        /* indicate to the waiting thread that the ready event was received */
        set_bit(WMI_READY, &ar->flag);
        wake_up(&ar->event_wq);
-
-       if (test_and_clear_bit(FIRST_BOOT, &ar->flag)) {
-               ath6kl_info("hw %s fw %s%s\n",
-                           get_hw_id_string(ar->wiphy->hw_version),
-                           ar->wiphy->fw_version,
-                           test_bit(TESTMODE, &ar->flag) ? " testmode" : "");
-       }
 }
 
 void ath6kl_scan_complete_evt(struct ath6kl_vif *vif, int status)
@@ -1077,21 +1002,11 @@ static int ath6kl_open(struct net_device *dev)
 
 static int ath6kl_close(struct net_device *dev)
 {
-       struct ath6kl *ar = ath6kl_priv(dev);
        struct ath6kl_vif *vif = netdev_priv(dev);
 
        netif_stop_queue(dev);
 
-       ath6kl_disconnect(vif);
-
-       if (test_bit(WMI_READY, &ar->flag)) {
-               if (ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0xFFFF,
-                                             0, 0, 0, 0, 0, 0, 0, 0, 0))
-                       return -EIO;
-
-       }
-
-       ath6kl_cfg80211_scan_complete_event(vif, true);
+       ath6kl_cfg80211_stop(vif);
 
        clear_bit(WLAN_ENABLED, &vif->flags);
 
index e69ca5e..15c3f56 100644 (file)
@@ -40,8 +40,12 @@ struct ath6kl_sdio {
        struct bus_request bus_req[BUS_REQUEST_MAX_NUM];
 
        struct ath6kl *ar;
+
        u8 *dma_buffer;
 
+       /* protects access to dma_buffer */
+       struct mutex dma_buffer_mutex;
+
        /* scatter request list head */
        struct list_head scat_req;
 
@@ -396,6 +400,7 @@ static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf,
        if (buf_needs_bounce(buf)) {
                if (!ar_sdio->dma_buffer)
                        return -ENOMEM;
+               mutex_lock(&ar_sdio->dma_buffer_mutex);
                tbuf = ar_sdio->dma_buffer;
                memcpy(tbuf, buf, len);
                bounced = true;
@@ -406,6 +411,9 @@ static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf,
        if ((request & HIF_READ) && bounced)
                memcpy(buf, tbuf, len);
 
+       if (bounced)
+               mutex_unlock(&ar_sdio->dma_buffer_mutex);
+
        return ret;
 }
 
@@ -799,7 +807,28 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
                return ret;
        }
 
-       if ((flags & MMC_PM_WAKE_SDIO_IRQ) && wow) {
+       if (!(flags & MMC_PM_WAKE_SDIO_IRQ))
+               goto deepsleep;
+
+       /* sdio irq wakes up host */
+
+       if (ar->state == ATH6KL_STATE_SCHED_SCAN) {
+               ret =  ath6kl_cfg80211_suspend(ar,
+                                              ATH6KL_CFG_SUSPEND_SCHED_SCAN,
+                                              NULL);
+               if (ret) {
+                       ath6kl_warn("Schedule scan suspend failed: %d", ret);
+                       return ret;
+               }
+
+               ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
+               if (ret)
+                       ath6kl_warn("set sdio wake irq flag failed: %d\n", ret);
+
+               return ret;
+       }
+
+       if (wow) {
                /*
                 * The host sdio controller is capable of keep power and
                 * sdio irq wake up at this point. It's fine to continue
@@ -816,6 +845,7 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
                return ret;
        }
 
+deepsleep:
        return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP, NULL);
 }
 
@@ -839,6 +869,8 @@ static int ath6kl_sdio_resume(struct ath6kl *ar)
 
        case ATH6KL_STATE_WOW:
                break;
+       case ATH6KL_STATE_SCHED_SCAN:
+               break;
        }
 
        ath6kl_cfg80211_resume(ar);
@@ -846,6 +878,264 @@ static int ath6kl_sdio_resume(struct ath6kl *ar)
        return 0;
 }
 
+/* set the window address register (using 4-byte register access ). */
+static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr)
+{
+       int status;
+       u8 addr_val[4];
+       s32 i;
+
+       /*
+        * Write bytes 1,2,3 of the register to set the upper address bytes,
+        * the LSB is written last to initiate the access cycle
+        */
+
+       for (i = 1; i <= 3; i++) {
+               /*
+                * Fill the buffer with the address byte value we want to
+                * hit 4 times.
+                */
+               memset(addr_val, ((u8 *)&addr)[i], 4);
+
+               /*
+                * Hit each byte of the register address with a 4-byte
+                * write operation to the same address, this is a harmless
+                * operation.
+                */
+               status = ath6kl_sdio_read_write_sync(ar, reg_addr + i, addr_val,
+                                            4, HIF_WR_SYNC_BYTE_FIX);
+               if (status)
+                       break;
+       }
+
+       if (status) {
+               ath6kl_err("%s: failed to write initial bytes of 0x%x "
+                          "to window reg: 0x%X\n", __func__,
+                          addr, reg_addr);
+               return status;
+       }
+
+       /*
+        * Write the address register again, this time write the whole
+        * 4-byte value. The effect here is that the LSB write causes the
+        * cycle to start, the extra 3 byte write to bytes 1,2,3 has no
+        * effect since we are writing the same values again
+        */
+       status = ath6kl_sdio_read_write_sync(ar, reg_addr, (u8 *)(&addr),
+                                    4, HIF_WR_SYNC_BYTE_INC);
+
+       if (status) {
+               ath6kl_err("%s: failed to write 0x%x to window reg: 0x%X\n",
+                          __func__, addr, reg_addr);
+               return status;
+       }
+
+       return 0;
+}
+
+static int ath6kl_sdio_diag_read32(struct ath6kl *ar, u32 address, u32 *data)
+{
+       int status;
+
+       /* set window register to start read cycle */
+       status = ath6kl_set_addrwin_reg(ar, WINDOW_READ_ADDR_ADDRESS,
+                                       address);
+
+       if (status)
+               return status;
+
+       /* read the data */
+       status = ath6kl_sdio_read_write_sync(ar, WINDOW_DATA_ADDRESS,
+                               (u8 *)data, sizeof(u32), HIF_RD_SYNC_BYTE_INC);
+       if (status) {
+               ath6kl_err("%s: failed to read from window data addr\n",
+                       __func__);
+               return status;
+       }
+
+       return status;
+}
+
+static int ath6kl_sdio_diag_write32(struct ath6kl *ar, u32 address,
+                                   __le32 data)
+{
+       int status;
+       u32 val = (__force u32) data;
+
+       /* set write data */
+       status = ath6kl_sdio_read_write_sync(ar, WINDOW_DATA_ADDRESS,
+                               (u8 *) &val, sizeof(u32), HIF_WR_SYNC_BYTE_INC);
+       if (status) {
+               ath6kl_err("%s: failed to write 0x%x to window data addr\n",
+                          __func__, data);
+               return status;
+       }
+
+       /* set window register, which starts the write cycle */
+       return ath6kl_set_addrwin_reg(ar, WINDOW_WRITE_ADDR_ADDRESS,
+                                     address);
+}
+
+static int ath6kl_sdio_bmi_credits(struct ath6kl *ar)
+{
+       u32 addr;
+       unsigned long timeout;
+       int ret;
+
+       ar->bmi.cmd_credits = 0;
+
+       /* Read the counter register to get the command credits */
+       addr = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4;
+
+       timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
+       while (time_before(jiffies, timeout) && !ar->bmi.cmd_credits) {
+
+               /*
+                * Hit the credit counter with a 4-byte access, the first byte
+                * read will hit the counter and cause a decrement, while the
+                * remaining 3 bytes has no effect. The rationale behind this
+                * is to make all HIF accesses 4-byte aligned.
+                */
+               ret = ath6kl_sdio_read_write_sync(ar, addr,
+                                        (u8 *)&ar->bmi.cmd_credits, 4,
+                                        HIF_RD_SYNC_BYTE_INC);
+               if (ret) {
+                       ath6kl_err("Unable to decrement the command credit "
+                                               "count register: %d\n", ret);
+                       return ret;
+               }
+
+               /* The counter is only 8 bits.
+                * Ignore anything in the upper 3 bytes
+                */
+               ar->bmi.cmd_credits &= 0xFF;
+       }
+
+       if (!ar->bmi.cmd_credits) {
+               ath6kl_err("bmi communication timeout\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int ath6kl_bmi_get_rx_lkahd(struct ath6kl *ar)
+{
+       unsigned long timeout;
+       u32 rx_word = 0;
+       int ret = 0;
+
+       timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
+       while ((time_before(jiffies, timeout)) && !rx_word) {
+               ret = ath6kl_sdio_read_write_sync(ar,
+                                       RX_LOOKAHEAD_VALID_ADDRESS,
+                                       (u8 *)&rx_word, sizeof(rx_word),
+                                       HIF_RD_SYNC_BYTE_INC);
+               if (ret) {
+                       ath6kl_err("unable to read RX_LOOKAHEAD_VALID\n");
+                       return ret;
+               }
+
+                /* all we really want is one bit */
+               rx_word &= (1 << ENDPOINT1);
+       }
+
+       if (!rx_word) {
+               ath6kl_err("bmi_recv_buf FIFO empty\n");
+               return -EINVAL;
+       }
+
+       return ret;
+}
+
+static int ath6kl_sdio_bmi_write(struct ath6kl *ar, u8 *buf, u32 len)
+{
+       int ret;
+       u32 addr;
+
+       ret = ath6kl_sdio_bmi_credits(ar);
+       if (ret)
+               return ret;
+
+       addr = ar->mbox_info.htc_addr;
+
+       ret = ath6kl_sdio_read_write_sync(ar, addr, buf, len,
+                                         HIF_WR_SYNC_BYTE_INC);
+       if (ret)
+               ath6kl_err("unable to send the bmi data to the device\n");
+
+       return ret;
+}
+
+static int ath6kl_sdio_bmi_read(struct ath6kl *ar, u8 *buf, u32 len)
+{
+       int ret;
+       u32 addr;
+
+       /*
+        * During normal bootup, small reads may be required.
+        * Rather than issue an HIF Read and then wait as the Target
+        * adds successive bytes to the FIFO, we wait here until
+        * we know that response data is available.
+        *
+        * This allows us to cleanly timeout on an unexpected
+        * Target failure rather than risk problems at the HIF level.
+        * In particular, this avoids SDIO timeouts and possibly garbage
+        * data on some host controllers.  And on an interconnect
+        * such as Compact Flash (as well as some SDIO masters) which
+        * does not provide any indication on data timeout, it avoids
+        * a potential hang or garbage response.
+        *
+        * Synchronization is more difficult for reads larger than the
+        * size of the MBOX FIFO (128B), because the Target is unable
+        * to push the 129th byte of data until AFTER the Host posts an
+        * HIF Read and removes some FIFO data.  So for large reads the
+        * Host proceeds to post an HIF Read BEFORE all the data is
+        * actually available to read.  Fortunately, large BMI reads do
+        * not occur in practice -- they're supported for debug/development.
+        *
+        * So Host/Target BMI synchronization is divided into these cases:
+        *  CASE 1: length < 4
+        *        Should not happen
+        *
+        *  CASE 2: 4 <= length <= 128
+        *        Wait for first 4 bytes to be in FIFO
+        *        If CONSERVATIVE_BMI_READ is enabled, also wait for
+        *        a BMI command credit, which indicates that the ENTIRE
+        *        response is available in the the FIFO
+        *
+        *  CASE 3: length > 128
+        *        Wait for the first 4 bytes to be in FIFO
+        *
+        * For most uses, a small timeout should be sufficient and we will
+        * usually see a response quickly; but there may be some unusual
+        * (debug) cases of BMI_EXECUTE where we want an larger timeout.
+        * For now, we use an unbounded busy loop while waiting for
+        * BMI_EXECUTE.
+        *
+        * If BMI_EXECUTE ever needs to support longer-latency execution,
+        * especially in production, this code needs to be enhanced to sleep
+        * and yield.  Also note that BMI_COMMUNICATION_TIMEOUT is currently
+        * a function of Host processor speed.
+        */
+       if (len >= 4) { /* NB: Currently, always true */
+               ret = ath6kl_bmi_get_rx_lkahd(ar);
+               if (ret)
+                       return ret;
+       }
+
+       addr = ar->mbox_info.htc_addr;
+       ret = ath6kl_sdio_read_write_sync(ar, addr, buf, len,
+                                 HIF_RD_SYNC_BYTE_INC);
+       if (ret) {
+               ath6kl_err("Unable to read the bmi data from the device: %d\n",
+                          ret);
+               return ret;
+       }
+
+       return 0;
+}
+
 static void ath6kl_sdio_stop(struct ath6kl *ar)
 {
        struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
@@ -890,6 +1180,10 @@ static const struct ath6kl_hif_ops ath6kl_sdio_ops = {
        .cleanup_scatter = ath6kl_sdio_cleanup_scatter,
        .suspend = ath6kl_sdio_suspend,
        .resume = ath6kl_sdio_resume,
+       .diag_read32 = ath6kl_sdio_diag_read32,
+       .diag_write32 = ath6kl_sdio_diag_write32,
+       .bmi_read = ath6kl_sdio_bmi_read,
+       .bmi_write = ath6kl_sdio_bmi_write,
        .power_on = ath6kl_sdio_power_on,
        .power_off = ath6kl_sdio_power_off,
        .stop = ath6kl_sdio_stop,
@@ -958,6 +1252,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
        spin_lock_init(&ar_sdio->lock);
        spin_lock_init(&ar_sdio->scat_lock);
        spin_lock_init(&ar_sdio->wr_async_lock);
+       mutex_init(&ar_sdio->dma_buffer_mutex);
 
        INIT_LIST_HEAD(&ar_sdio->scat_req);
        INIT_LIST_HEAD(&ar_sdio->bus_req_freeq);
@@ -976,8 +1271,10 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
        }
 
        ar_sdio->ar = ar;
+       ar->hif_type = ATH6KL_HIF_TYPE_SDIO;
        ar->hif_priv = ar_sdio;
        ar->hif_ops = &ath6kl_sdio_ops;
+       ar->bmi.max_data_size = 256;
 
        ath6kl_sdio_set_mbox_info(ar);
 
@@ -1027,13 +1324,15 @@ static void ath6kl_sdio_remove(struct sdio_func *func)
 static const struct sdio_device_id ath6kl_sdio_devices[] = {
        {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x0))},
        {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x1))},
+       {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x0))},
+       {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x1))},
        {},
 };
 
 MODULE_DEVICE_TABLE(sdio, ath6kl_sdio_devices);
 
 static struct sdio_driver ath6kl_sdio_driver = {
-       .name = "ath6kl",
+       .name = "ath6kl_sdio",
        .id_table = ath6kl_sdio_devices,
        .probe = ath6kl_sdio_probe,
        .remove = ath6kl_sdio_remove,
@@ -1063,13 +1362,19 @@ MODULE_AUTHOR("Atheros Communications, Inc.");
 MODULE_DESCRIPTION("Driver support for Atheros AR600x SDIO devices");
 MODULE_LICENSE("Dual BSD/GPL");
 
-MODULE_FIRMWARE(AR6003_REV2_OTP_FILE);
-MODULE_FIRMWARE(AR6003_REV2_FIRMWARE_FILE);
-MODULE_FIRMWARE(AR6003_REV2_PATCH_FILE);
-MODULE_FIRMWARE(AR6003_REV2_BOARD_DATA_FILE);
-MODULE_FIRMWARE(AR6003_REV2_DEFAULT_BOARD_DATA_FILE);
-MODULE_FIRMWARE(AR6003_REV3_OTP_FILE);
-MODULE_FIRMWARE(AR6003_REV3_FIRMWARE_FILE);
-MODULE_FIRMWARE(AR6003_REV3_PATCH_FILE);
-MODULE_FIRMWARE(AR6003_REV3_BOARD_DATA_FILE);
-MODULE_FIRMWARE(AR6003_REV3_DEFAULT_BOARD_DATA_FILE);
+MODULE_FIRMWARE(AR6003_HW_2_0_OTP_FILE);
+MODULE_FIRMWARE(AR6003_HW_2_0_FIRMWARE_FILE);
+MODULE_FIRMWARE(AR6003_HW_2_0_PATCH_FILE);
+MODULE_FIRMWARE(AR6003_HW_2_0_BOARD_DATA_FILE);
+MODULE_FIRMWARE(AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE);
+MODULE_FIRMWARE(AR6003_HW_2_1_1_OTP_FILE);
+MODULE_FIRMWARE(AR6003_HW_2_1_1_FIRMWARE_FILE);
+MODULE_FIRMWARE(AR6003_HW_2_1_1_PATCH_FILE);
+MODULE_FIRMWARE(AR6003_HW_2_1_1_BOARD_DATA_FILE);
+MODULE_FIRMWARE(AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE);
+MODULE_FIRMWARE(AR6004_HW_1_0_FIRMWARE_FILE);
+MODULE_FIRMWARE(AR6004_HW_1_0_BOARD_DATA_FILE);
+MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE);
+MODULE_FIRMWARE(AR6004_HW_1_1_FIRMWARE_FILE);
+MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE);
+MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);
index 687e2b3..108a723 100644 (file)
@@ -20,7 +20,7 @@
 #define AR6003_BOARD_DATA_SZ           1024
 #define AR6003_BOARD_EXT_DATA_SZ       768
 
-#define AR6004_BOARD_DATA_SZ     7168
+#define AR6004_BOARD_DATA_SZ     6144
 #define AR6004_BOARD_EXT_DATA_SZ 0
 
 #define RESET_CONTROL_ADDRESS          0x00000000
@@ -334,20 +334,6 @@ struct host_interest {
        (((target_type) == TARGET_TYPE_AR6003) ? AR6003_VTOP(vaddr) : \
        (((target_type) == TARGET_TYPE_AR6004) ? AR6004_VTOP(vaddr) : 0))
 
-#define AR6003_REV2_APP_LOAD_ADDRESS            0x543180
-#define AR6003_REV2_BOARD_EXT_DATA_ADDRESS      0x57E500
-#define AR6003_REV2_DATASET_PATCH_ADDRESS       0x57e884
-#define AR6003_REV2_RAM_RESERVE_SIZE            6912
-
-#define AR6003_REV3_APP_LOAD_ADDRESS            0x545000
-#define AR6003_REV3_BOARD_EXT_DATA_ADDRESS      0x542330
-#define AR6003_REV3_DATASET_PATCH_ADDRESS       0x57FF74
-#define AR6003_REV3_RAM_RESERVE_SIZE            512
-
-#define AR6004_REV1_BOARD_DATA_ADDRESS          0x435400
-#define AR6004_REV1_BOARD_EXT_DATA_ADDRESS      0x437000
-#define AR6004_REV1_RAM_RESERVE_SIZE            11264
-
 #define ATH6KL_FWLOG_PAYLOAD_SIZE              1500
 
 struct ath6kl_dbglog_buf {
index d9cff2b..506a303 100644 (file)
@@ -453,11 +453,11 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
                set_bit(WMI_CTRL_EP_FULL, &ar->flag);
                spin_unlock_bh(&ar->lock);
                ath6kl_err("wmi ctrl ep is full\n");
-               goto stop_adhoc_netq;
+               return action;
        }
 
        if (packet->info.tx.tag == ATH6KL_CONTROL_PKT_TAG)
-               goto stop_adhoc_netq;
+               return action;
 
        /*
         * The last MAX_HI_COOKIE_NUM "batch" of cookies are reserved for
@@ -465,20 +465,18 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
         */
        if (ar->ac_stream_pri_map[ar->ep2ac_map[endpoint]] <
            ar->hiac_stream_active_pri &&
-           ar->cookie_count <= MAX_HI_COOKIE_NUM) {
+           ar->cookie_count <= MAX_HI_COOKIE_NUM)
                /*
                 * Give preference to the highest priority stream by
                 * dropping the packets which overflowed.
                 */
                action = HTC_SEND_FULL_DROP;
-               goto stop_adhoc_netq;
-       }
 
-stop_adhoc_netq:
        /* FIXME: Locking */
        spin_lock_bh(&ar->list_lock);
        list_for_each_entry(vif, &ar->vif_list, list) {
-               if (vif->nw_type == ADHOC_NETWORK) {
+               if (vif->nw_type == ADHOC_NETWORK ||
+                   action != HTC_SEND_FULL_DROP) {
                        spin_unlock_bh(&ar->list_lock);
 
                        spin_lock_bh(&vif->if_lock);
@@ -543,7 +541,7 @@ void ath6kl_tx_complete(void *context, struct list_head *packet_queue)
        int status;
        enum htc_endpoint_id eid;
        bool wake_event = false;
-       bool flushing[MAX_NUM_VIF] = {false};
+       bool flushing[ATH6KL_VIF_MAX] = {false};
        u8 if_idx;
        struct ath6kl_vif *vif;
 
@@ -571,8 +569,6 @@ void ath6kl_tx_complete(void *context, struct list_head *packet_queue)
                if (!skb || !skb->data)
                        goto fatal;
 
-               packet->buf = skb->data;
-
                __skb_queue_tail(&skb_queue, skb);
 
                if (!status && (packet->act_len != skb->len))
@@ -593,10 +589,10 @@ void ath6kl_tx_complete(void *context, struct list_head *packet_queue)
 
                if (eid == ar->ctrl_ep) {
                        if_idx = wmi_cmd_hdr_get_if_idx(
-                               (struct wmi_cmd_hdr *) skb->data);
+                               (struct wmi_cmd_hdr *) packet->buf);
                } else {
                        if_idx = wmi_data_hdr_get_if_idx(
-                               (struct wmi_data_hdr *) skb->data);
+                               (struct wmi_data_hdr *) packet->buf);
                }
 
                vif = ath6kl_get_vif_by_index(ar, if_idx);
diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c
new file mode 100644 (file)
index 0000000..e3cf397
--- /dev/null
@@ -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);
index 922344d..f6f2aa2 100644 (file)
@@ -85,7 +85,7 @@ struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx)
 {
        struct ath6kl_vif *vif, *found = NULL;
 
-       if (WARN_ON(if_idx > (MAX_NUM_VIF - 1)))
+       if (WARN_ON(if_idx > (ar->vif_max - 1)))
                return NULL;
 
        /* FIXME: Locking */
@@ -187,7 +187,7 @@ int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb,
        struct wmi_data_hdr *data_hdr;
        int ret;
 
-       if (WARN_ON(skb == NULL || (if_idx > MAX_NUM_VIF - 1)))
+       if (WARN_ON(skb == NULL || (if_idx > wmi->parent_dev->vif_max - 1)))
                return -EINVAL;
 
        if (tx_meta_info) {
@@ -977,6 +977,13 @@ static int ath6kl_wmi_tkip_micerr_event_rx(struct wmi *wmi, u8 *datap, int len,
        return 0;
 }
 
+void ath6kl_wmi_sscan_timer(unsigned long ptr)
+{
+       struct ath6kl_vif *vif = (struct ath6kl_vif *) ptr;
+
+       cfg80211_sched_scan_results(vif->ar->wiphy);
+}
+
 static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
                                       struct ath6kl_vif *vif)
 {
@@ -1066,6 +1073,21 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
                return -ENOMEM;
        cfg80211_put_bss(bss);
 
+       /*
+        * Firmware doesn't return any event when scheduled scan has
+        * finished, so we need to use a timer to find out when there are
+        * no more results.
+        *
+        * The timer is started from the first bss info received, otherwise
+        * the timer would not ever fire if the scan interval is short
+        * enough.
+        */
+       if (ar->state == ATH6KL_STATE_SCHED_SCAN &&
+           !timer_pending(&vif->sched_scan_timer)) {
+               mod_timer(&vif->sched_scan_timer, jiffies +
+                         msecs_to_jiffies(ATH6KL_SCHED_SCAN_RESULT_DELAY));
+       }
+
        return 0;
 }
 
@@ -1620,7 +1642,7 @@ int ath6kl_wmi_cmd_send(struct wmi *wmi, u8 if_idx, struct sk_buff *skb,
        int ret;
        u16 info1;
 
-       if (WARN_ON(skb == NULL || (if_idx > (MAX_NUM_VIF - 1))))
+       if (WARN_ON(skb == NULL || (if_idx > (wmi->parent_dev->vif_max - 1))))
                return -EINVAL;
 
        ath6kl_dbg(ATH6KL_DBG_WMI, "wmi tx id %d len %d flag %d\n",
@@ -1682,7 +1704,8 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, u8 if_idx,
                           u8 pairwise_crypto_len,
                           enum crypto_type group_crypto,
                           u8 group_crypto_len, int ssid_len, u8 *ssid,
-                          u8 *bssid, u16 channel, u32 ctrl_flags)
+                          u8 *bssid, u16 channel, u32 ctrl_flags,
+                          u8 nw_subtype)
 {
        struct sk_buff *skb;
        struct wmi_connect_cmd *cc;
@@ -1722,6 +1745,7 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, u8 if_idx,
        cc->grp_crypto_len = group_crypto_len;
        cc->ch = cpu_to_le16(channel);
        cc->ctrl_flags = cpu_to_le32(ctrl_flags);
+       cc->nw_subtype = nw_subtype;
 
        if (bssid != NULL)
                memcpy(cc->bssid, bssid, ETH_ALEN);
@@ -1774,6 +1798,72 @@ int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx)
        return ret;
 }
 
+int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
+                            enum wmi_scan_type scan_type,
+                            u32 force_fgscan, u32 is_legacy,
+                            u32 home_dwell_time, u32 force_scan_interval,
+                            s8 num_chan, u16 *ch_list, u32 no_cck, u32 *rates)
+{
+       struct sk_buff *skb;
+       struct wmi_begin_scan_cmd *sc;
+       s8 size;
+       int i, band, ret;
+       struct ath6kl *ar = wmi->parent_dev;
+       int num_rates;
+
+       size = sizeof(struct wmi_begin_scan_cmd);
+
+       if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN))
+               return -EINVAL;
+
+       if (num_chan > WMI_MAX_CHANNELS)
+               return -EINVAL;
+
+       if (num_chan)
+               size += sizeof(u16) * (num_chan - 1);
+
+       skb = ath6kl_wmi_get_new_buf(size);
+       if (!skb)
+               return -ENOMEM;
+
+       sc = (struct wmi_begin_scan_cmd *) skb->data;
+       sc->scan_type = scan_type;
+       sc->force_fg_scan = cpu_to_le32(force_fgscan);
+       sc->is_legacy = cpu_to_le32(is_legacy);
+       sc->home_dwell_time = cpu_to_le32(home_dwell_time);
+       sc->force_scan_intvl = cpu_to_le32(force_scan_interval);
+       sc->no_cck = cpu_to_le32(no_cck);
+       sc->num_ch = num_chan;
+
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+               struct ieee80211_supported_band *sband =
+                   ar->wiphy->bands[band];
+               u32 ratemask = rates[band];
+               u8 *supp_rates = sc->supp_rates[band].rates;
+               num_rates = 0;
+
+               for (i = 0; i < sband->n_bitrates; i++) {
+                       if ((BIT(i) & ratemask) == 0)
+                               continue; /* skip rate */
+                       supp_rates[num_rates++] =
+                           (u8) (sband->bitrates[i].bitrate / 5);
+               }
+               sc->supp_rates[band].nrates = num_rates;
+       }
+
+       for (i = 0; i < num_chan; i++)
+               sc->ch_list[i] = cpu_to_le16(ch_list[i]);
+
+       ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_BEGIN_SCAN_CMDID,
+                                 NO_SYNC_WMIFLAG);
+
+       return ret;
+}
+
+/* ath6kl_wmi_start_scan_cmd is to be deprecated. Use
+ * ath6kl_wmi_begin_scan_cmd instead. The new function supports P2P
+ * mgmt operations using station interface.
+ */
 int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx,
                             enum wmi_scan_type scan_type,
                             u32 force_fgscan, u32 is_legacy,
@@ -2940,7 +3030,10 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
        p = (struct wmi_set_appie_cmd *) skb->data;
        p->mgmt_frm_type = mgmt_frm_type;
        p->ie_len = ie_len;
-       memcpy(p->ie_info, ie, ie_len);
+
+       if (ie != NULL && ie_len > 0)
+               memcpy(p->ie_info, ie, ie_len);
+
        return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_APPIE_CMDID,
                                   NO_SYNC_WMIFLAG);
 }
@@ -2981,6 +3074,10 @@ int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx, u32 freq, u32 dur)
                                   NO_SYNC_WMIFLAG);
 }
 
+/* ath6kl_wmi_send_action_cmd is to be deprecated. Use
+ * ath6kl_wmi_send_mgmt_cmd instead. The new function supports P2P
+ * mgmt operations using station interface.
+ */
 int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
                               u32 wait, const u8 *data, u16 data_len)
 {
@@ -3018,14 +3115,57 @@ int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
                                   NO_SYNC_WMIFLAG);
 }
 
+int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
+                              u32 wait, const u8 *data, u16 data_len,
+                              u32 no_cck)
+{
+       struct sk_buff *skb;
+       struct wmi_send_mgmt_cmd *p;
+       u8 *buf;
+
+       if (wait)
+               return -EINVAL; /* Offload for wait not supported */
+
+       buf = kmalloc(data_len, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len);
+       if (!skb) {
+               kfree(buf);
+               return -ENOMEM;
+       }
+
+       kfree(wmi->last_mgmt_tx_frame);
+       memcpy(buf, data, data_len);
+       wmi->last_mgmt_tx_frame = buf;
+       wmi->last_mgmt_tx_frame_len = data_len;
+
+       ath6kl_dbg(ATH6KL_DBG_WMI, "send_action_cmd: id=%u freq=%u wait=%u "
+                  "len=%u\n", id, freq, wait, data_len);
+       p = (struct wmi_send_mgmt_cmd *) skb->data;
+       p->id = cpu_to_le32(id);
+       p->freq = cpu_to_le32(freq);
+       p->wait = cpu_to_le32(wait);
+       p->no_cck = cpu_to_le32(no_cck);
+       p->len = cpu_to_le16(data_len);
+       memcpy(p->data, data, data_len);
+       return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SEND_MGMT_CMDID,
+                                  NO_SYNC_WMIFLAG);
+}
+
 int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq,
                                       const u8 *dst, const u8 *data,
                                       u16 data_len)
 {
        struct sk_buff *skb;
        struct wmi_p2p_probe_response_cmd *p;
+       size_t cmd_len = sizeof(*p) + data_len;
 
-       skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len);
+       if (data_len == 0)
+               cmd_len++; /* work around target minimum length requirement */
+
+       skb = ath6kl_wmi_get_new_buf(cmd_len);
        if (!skb)
                return -ENOMEM;
 
index 76342d5..42ac311 100644 (file)
@@ -329,6 +329,10 @@ enum wmi_cmd_id {
        WMI_SYNCHRONIZE_CMDID,
        WMI_CREATE_PSTREAM_CMDID,
        WMI_DELETE_PSTREAM_CMDID,
+       /* WMI_START_SCAN_CMDID is to be deprecated. Use
+        * WMI_BEGIN_SCAN_CMDID instead. The new cmd supports P2P mgmt
+        * operations using station interface.
+        */
        WMI_START_SCAN_CMDID,
        WMI_SET_SCAN_PARAMS_CMDID,
        WMI_SET_BSS_FILTER_CMDID,
@@ -542,12 +546,61 @@ enum wmi_cmd_id {
        WMI_GTK_OFFLOAD_OP_CMDID,
        WMI_REMAIN_ON_CHNL_CMDID,
        WMI_CANCEL_REMAIN_ON_CHNL_CMDID,
+       /* WMI_SEND_ACTION_CMDID is to be deprecated. Use
+        * WMI_SEND_MGMT_CMDID instead. The new cmd supports P2P mgmt
+        * operations using station interface.
+        */
        WMI_SEND_ACTION_CMDID,
        WMI_PROBE_REQ_REPORT_CMDID,
        WMI_DISABLE_11B_RATES_CMDID,
        WMI_SEND_PROBE_RESPONSE_CMDID,
        WMI_GET_P2P_INFO_CMDID,
        WMI_AP_JOIN_BSS_CMDID,
+
+       WMI_SMPS_ENABLE_CMDID,
+       WMI_SMPS_CONFIG_CMDID,
+       WMI_SET_RATECTRL_PARM_CMDID,
+       /*  LPL specific commands*/
+       WMI_LPL_FORCE_ENABLE_CMDID,
+       WMI_LPL_SET_POLICY_CMDID,
+       WMI_LPL_GET_POLICY_CMDID,
+       WMI_LPL_GET_HWSTATE_CMDID,
+       WMI_LPL_SET_PARAMS_CMDID,
+       WMI_LPL_GET_PARAMS_CMDID,
+
+       WMI_SET_BUNDLE_PARAM_CMDID,
+
+       /*GreenTx specific commands*/
+
+       WMI_GREENTX_PARAMS_CMDID,
+
+       WMI_RTT_MEASREQ_CMDID,
+       WMI_RTT_CAPREQ_CMDID,
+       WMI_RTT_STATUSREQ_CMDID,
+
+       /* WPS Commands */
+       WMI_WPS_START_CMDID,
+       WMI_GET_WPS_STATUS_CMDID,
+
+       /* More P2P commands */
+       WMI_SET_NOA_CMDID,
+       WMI_GET_NOA_CMDID,
+       WMI_SET_OPPPS_CMDID,
+       WMI_GET_OPPPS_CMDID,
+       WMI_ADD_PORT_CMDID,
+       WMI_DEL_PORT_CMDID,
+
+       /* 802.11w cmd */
+       WMI_SET_RSN_CAP_CMDID,
+       WMI_GET_RSN_CAP_CMDID,
+       WMI_SET_IGTK_CMDID,
+
+       WMI_RX_FILTER_COALESCE_FILTER_OP_CMDID,
+       WMI_RX_FILTER_SET_FRAME_TEST_LIST_CMDID,
+
+       WMI_SEND_MGMT_CMDID,
+       WMI_BEGIN_SCAN_CMDID,
+
 };
 
 enum wmi_mgmt_frame_type {
@@ -567,6 +620,14 @@ enum network_type {
        AP_NETWORK = 0x10,
 };
 
+enum network_subtype {
+       SUBTYPE_NONE,
+       SUBTYPE_BT,
+       SUBTYPE_P2PDEV,
+       SUBTYPE_P2PCLIENT,
+       SUBTYPE_P2PGO,
+};
+
 enum dot11_auth_mode {
        OPEN_AUTH = 0x01,
        SHARED_AUTH = 0x02,
@@ -639,6 +700,7 @@ struct wmi_connect_cmd {
        __le16 ch;
        u8 bssid[ETH_ALEN];
        __le32 ctrl_flags;
+       u8 nw_subtype;
 } __packed;
 
 /* WMI_RECONNECT_CMDID */
@@ -726,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);