mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-03-24 04:08:00 +08:00
Merge branch 'ath6kl-next' of master.kernel.org:/pub/scm/linux/kernel/git/kvalo/ath6kl
This commit is contained in:
commit
392e741939
@ -25,5 +25,6 @@ config ATH_DEBUG
|
||||
source "drivers/net/wireless/ath/ath5k/Kconfig"
|
||||
source "drivers/net/wireless/ath/ath9k/Kconfig"
|
||||
source "drivers/net/wireless/ath/carl9170/Kconfig"
|
||||
source "drivers/net/wireless/ath/ath6kl/Kconfig"
|
||||
|
||||
endif
|
||||
|
@ -1,6 +1,7 @@
|
||||
obj-$(CONFIG_ATH5K) += ath5k/
|
||||
obj-$(CONFIG_ATH9K_HW) += ath9k/
|
||||
obj-$(CONFIG_CARL9170) += carl9170/
|
||||
obj-$(CONFIG_ATH6KL) += ath6kl/
|
||||
|
||||
obj-$(CONFIG_ATH_COMMON) += ath.o
|
||||
|
||||
|
15
drivers/net/wireless/ath/ath6kl/Kconfig
Normal file
15
drivers/net/wireless/ath/ath6kl/Kconfig
Normal file
@ -0,0 +1,15 @@
|
||||
config ATH6KL
|
||||
tristate "Atheros ath6kl support"
|
||||
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.
|
||||
|
||||
config ATH6KL_DEBUG
|
||||
bool "Atheros ath6kl debugging"
|
||||
depends on ATH6KL
|
||||
---help---
|
||||
Enables debug support
|
35
drivers/net/wireless/ath/ath6kl/Makefile
Normal file
35
drivers/net/wireless/ath/ath6kl/Makefile
Normal file
@ -0,0 +1,35 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2004-2010 Atheros Communications Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
#
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
#
|
||||
# Author(s): ="Atheros"
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
obj-$(CONFIG_ATH6KL) := ath6kl.o
|
||||
ath6kl-y += debug.o
|
||||
ath6kl-y += htc_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 += node.o
|
||||
ath6kl-y += sdio.o
|
692
drivers/net/wireless/ath/ath6kl/bmi.c
Normal file
692
drivers/net/wireless/ath/ath6kl/bmi.c
Normal file
@ -0,0 +1,692 @@
|
||||
/*
|
||||
* Copyright (c) 2004-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 "core.h"
|
||||
#include "hif-ops.h"
|
||||
#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, bool need_timeout)
|
||||
{
|
||||
unsigned long timeout;
|
||||
u32 rx_word = 0;
|
||||
int ret = 0;
|
||||
|
||||
timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
|
||||
while ((!need_timeout || 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, bool want_timeout)
|
||||
{
|
||||
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, want_timeout);
|
||||
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;
|
||||
u32 cid = BMI_DONE;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath6kl_dbg(ATH6KL_DBG_BMI, "bmi done skipped\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ar->bmi.done_sent = true;
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, (u8 *)&cid, sizeof(cid));
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to send bmi done: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ath6kl_bmi_cleanup(ar);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_get_target_info(struct ath6kl *ar,
|
||||
struct ath6kl_bmi_target_info *targ_info)
|
||||
{
|
||||
int ret;
|
||||
u32 cid = BMI_GET_TARGET_INFO;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
ret = ath6kl_bmi_send_buf(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), true);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to recv target info: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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,
|
||||
(u8 *)&targ_info->byte_count,
|
||||
sizeof(targ_info->byte_count),
|
||||
true);
|
||||
if (ret) {
|
||||
ath6kl_err("unable to read target info byte count: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* The target's targ_info doesn't match the host's targ_info.
|
||||
* We need to do some backwards compatibility to make this work.
|
||||
*/
|
||||
if (le32_to_cpu(targ_info->byte_count) != sizeof(*targ_info)) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Read the remainder of the targ_info */
|
||||
ret = ath6kl_bmi_recv_buf(ar,
|
||||
((u8 *)targ_info) +
|
||||
sizeof(targ_info->byte_count),
|
||||
sizeof(*targ_info) -
|
||||
sizeof(targ_info->byte_count),
|
||||
true);
|
||||
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to read target info (%d bytes): %d\n",
|
||||
targ_info->byte_count, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BMI, "target info (ver: 0x%x type: 0x%x)\n",
|
||||
targ_info->version, targ_info->type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
|
||||
{
|
||||
u32 cid = BMI_READ_MEMORY;
|
||||
int ret;
|
||||
u32 offset;
|
||||
u32 len_remain, rx_len;
|
||||
u16 size;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
size = BMI_DATASZ_MAX + sizeof(cid) + sizeof(addr) + sizeof(len);
|
||||
if (size > MAX_BMI_CMDBUF_SZ) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
memset(ar->bmi.cmd_buf, 0, size);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BMI,
|
||||
"bmi read memory: device: addr: 0x%x, len: %d\n",
|
||||
addr, len);
|
||||
|
||||
len_remain = len;
|
||||
|
||||
while (len_remain) {
|
||||
rx_len = (len_remain < BMI_DATASZ_MAX) ?
|
||||
len_remain : BMI_DATASZ_MAX;
|
||||
offset = 0;
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
|
||||
offset += sizeof(addr);
|
||||
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);
|
||||
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, true);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to read from the device: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
memcpy(&buf[len - len_remain], ar->bmi.cmd_buf, rx_len);
|
||||
len_remain -= rx_len; addr += rx_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
|
||||
{
|
||||
u32 cid = BMI_WRITE_MEMORY;
|
||||
int ret;
|
||||
u32 offset;
|
||||
u32 len_remain, tx_len;
|
||||
const u32 header = sizeof(cid) + sizeof(addr) + sizeof(len);
|
||||
u8 aligned_buf[BMI_DATASZ_MAX];
|
||||
u8 *src;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
if ((BMI_DATASZ_MAX + header) > MAX_BMI_CMDBUF_SZ) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(ar->bmi.cmd_buf, 0, BMI_DATASZ_MAX + header);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BMI,
|
||||
"bmi write memory: addr: 0x%x, len: %d\n", addr, len);
|
||||
|
||||
len_remain = len;
|
||||
while (len_remain) {
|
||||
src = &buf[len - len_remain];
|
||||
|
||||
if (len_remain < (BMI_DATASZ_MAX - header)) {
|
||||
if (len_remain & 3) {
|
||||
/* align it with 4 bytes */
|
||||
len_remain = len_remain +
|
||||
(4 - (len_remain & 3));
|
||||
memcpy(aligned_buf, src, len_remain);
|
||||
src = aligned_buf;
|
||||
}
|
||||
tx_len = len_remain;
|
||||
} else {
|
||||
tx_len = (BMI_DATASZ_MAX - header);
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
|
||||
offset += sizeof(addr);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len));
|
||||
offset += sizeof(tx_len);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), src, tx_len);
|
||||
offset += tx_len;
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to write to the device: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
len_remain -= tx_len; addr += tx_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param)
|
||||
{
|
||||
u32 cid = BMI_EXECUTE;
|
||||
int ret;
|
||||
u32 offset;
|
||||
u16 size;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
size = sizeof(cid) + sizeof(addr) + sizeof(param);
|
||||
if (size > MAX_BMI_CMDBUF_SZ) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
memset(ar->bmi.cmd_buf, 0, size);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BMI, "bmi execute: addr: 0x%x, param: %d)\n",
|
||||
addr, *param);
|
||||
|
||||
offset = 0;
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
|
||||
offset += sizeof(addr);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), param, sizeof(*param));
|
||||
offset += sizeof(*param);
|
||||
|
||||
ret = ath6kl_bmi_send_buf(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), false);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to read from the device: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
memcpy(param, ar->bmi.cmd_buf, sizeof(*param));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_set_app_start(struct ath6kl *ar, u32 addr)
|
||||
{
|
||||
u32 cid = BMI_SET_APP_START;
|
||||
int ret;
|
||||
u32 offset;
|
||||
u16 size;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
size = sizeof(cid) + sizeof(addr);
|
||||
if (size > MAX_BMI_CMDBUF_SZ) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
memset(ar->bmi.cmd_buf, 0, size);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BMI, "bmi set app start: addr: 0x%x\n", addr);
|
||||
|
||||
offset = 0;
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
|
||||
offset += sizeof(addr);
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to write to the device: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param)
|
||||
{
|
||||
u32 cid = BMI_READ_SOC_REGISTER;
|
||||
int ret;
|
||||
u32 offset;
|
||||
u16 size;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
size = sizeof(cid) + sizeof(addr);
|
||||
if (size > MAX_BMI_CMDBUF_SZ) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
memset(ar->bmi.cmd_buf, 0, size);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BMI, "bmi read SOC reg: addr: 0x%x\n", addr);
|
||||
|
||||
offset = 0;
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
|
||||
offset += sizeof(addr);
|
||||
|
||||
ret = ath6kl_bmi_send_buf(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), true);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to read from the device: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
memcpy(param, ar->bmi.cmd_buf, sizeof(*param));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param)
|
||||
{
|
||||
u32 cid = BMI_WRITE_SOC_REGISTER;
|
||||
int ret;
|
||||
u32 offset;
|
||||
u16 size;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
size = sizeof(cid) + sizeof(addr) + sizeof(param);
|
||||
if (size > MAX_BMI_CMDBUF_SZ) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
memset(ar->bmi.cmd_buf, 0, size);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BMI,
|
||||
"bmi write SOC reg: addr: 0x%x, param: %d\n",
|
||||
addr, param);
|
||||
|
||||
offset = 0;
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
|
||||
offset += sizeof(addr);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), ¶m, sizeof(param));
|
||||
offset += sizeof(param);
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to write to the device: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len)
|
||||
{
|
||||
u32 cid = BMI_LZ_DATA;
|
||||
int ret;
|
||||
u32 offset;
|
||||
u32 len_remain, tx_len;
|
||||
const u32 header = sizeof(cid) + sizeof(len);
|
||||
u16 size;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
size = BMI_DATASZ_MAX + header;
|
||||
if (size > MAX_BMI_CMDBUF_SZ) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
memset(ar->bmi.cmd_buf, 0, size);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BMI, "bmi send LZ data: len: %d)\n",
|
||||
len);
|
||||
|
||||
len_remain = len;
|
||||
while (len_remain) {
|
||||
tx_len = (len_remain < (BMI_DATASZ_MAX - header)) ?
|
||||
len_remain : (BMI_DATASZ_MAX - header);
|
||||
|
||||
offset = 0;
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len));
|
||||
offset += sizeof(tx_len);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &buf[len - len_remain],
|
||||
tx_len);
|
||||
offset += tx_len;
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to write to the device: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
len_remain -= tx_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_lz_stream_start(struct ath6kl *ar, u32 addr)
|
||||
{
|
||||
u32 cid = BMI_LZ_STREAM_START;
|
||||
int ret;
|
||||
u32 offset;
|
||||
u16 size;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
size = sizeof(cid) + sizeof(addr);
|
||||
if (size > MAX_BMI_CMDBUF_SZ) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
memset(ar->bmi.cmd_buf, 0, size);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BMI,
|
||||
"bmi LZ stream start: addr: 0x%x)\n",
|
||||
addr);
|
||||
|
||||
offset = 0;
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
|
||||
offset += sizeof(addr);
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to start LZ stream to the device: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_fast_download(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
|
||||
{
|
||||
int ret;
|
||||
u32 last_word = 0;
|
||||
u32 last_word_offset = len & ~0x3;
|
||||
u32 unaligned_bytes = len & 0x3;
|
||||
|
||||
ret = ath6kl_bmi_lz_stream_start(ar, addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (unaligned_bytes) {
|
||||
/* copy the last word into a zero padded buffer */
|
||||
memcpy(&last_word, &buf[last_word_offset], unaligned_bytes);
|
||||
}
|
||||
|
||||
ret = ath6kl_bmi_lz_data(ar, buf, last_word_offset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (unaligned_bytes)
|
||||
ret = ath6kl_bmi_lz_data(ar, (u8 *)&last_word, 4);
|
||||
|
||||
if (!ret) {
|
||||
/* Close compressed stream and open a new (fake) one.
|
||||
* This serves mainly to flush Target caches. */
|
||||
ret = ath6kl_bmi_lz_stream_start(ar, 0x00);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_init(struct ath6kl *ar)
|
||||
{
|
||||
ar->bmi.cmd_buf = kzalloc(MAX_BMI_CMDBUF_SZ, GFP_ATOMIC);
|
||||
|
||||
if (!ar->bmi.cmd_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ath6kl_bmi_cleanup(struct ath6kl *ar)
|
||||
{
|
||||
kfree(ar->bmi.cmd_buf);
|
||||
ar->bmi.cmd_buf = NULL;
|
||||
}
|
250
drivers/net/wireless/ath/ath6kl/bmi.h
Normal file
250
drivers/net/wireless/ath/ath6kl/bmi.h
Normal file
@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Copyright (c) 2004-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.
|
||||
*/
|
||||
|
||||
#ifndef BMI_H
|
||||
#define BMI_H
|
||||
|
||||
/*
|
||||
* Bootloader Messaging Interface (BMI)
|
||||
*
|
||||
* BMI is a very simple messaging interface used during initialization
|
||||
* to read memory, write memory, execute code, and to define an
|
||||
* application entry PC.
|
||||
*
|
||||
* It is used to download an application to ATH6KL, to provide
|
||||
* patches to code that is already resident on ATH6KL, and generally
|
||||
* to examine and modify state. The Host has an opportunity to use
|
||||
* BMI only once during bootup. Once the Host issues a BMI_DONE
|
||||
* command, this opportunity ends.
|
||||
*
|
||||
* The Host writes BMI requests to mailbox0, and reads BMI responses
|
||||
* from mailbox0. BMI requests all begin with a command
|
||||
* (see below for specific commands), and are followed by
|
||||
* command-specific data.
|
||||
*
|
||||
* Flow control:
|
||||
* The Host can only issue a command once the Target gives it a
|
||||
* "BMI Command Credit", using ATH6KL Counter #4. As soon as the
|
||||
* Target has completed a command, it issues another BMI Command
|
||||
* Credit (so the Host can issue the next command).
|
||||
*
|
||||
* 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
|
||||
|
||||
#define BMI_DONE 1
|
||||
/*
|
||||
* Semantics: Host is done using BMI
|
||||
* Request format:
|
||||
* u32 command (BMI_DONE)
|
||||
* Response format: none
|
||||
*/
|
||||
|
||||
#define BMI_READ_MEMORY 2
|
||||
/*
|
||||
* Semantics: Host reads ATH6KL memory
|
||||
* Request format:
|
||||
* u32 command (BMI_READ_MEMORY)
|
||||
* u32 address
|
||||
* u32 length, at most BMI_DATASZ_MAX
|
||||
* Response format:
|
||||
* u8 data[length]
|
||||
*/
|
||||
|
||||
#define BMI_WRITE_MEMORY 3
|
||||
/*
|
||||
* Semantics: Host writes ATH6KL memory
|
||||
* Request format:
|
||||
* u32 command (BMI_WRITE_MEMORY)
|
||||
* u32 address
|
||||
* u32 length, at most BMI_DATASZ_MAX
|
||||
* u8 data[length]
|
||||
* Response format: none
|
||||
*/
|
||||
|
||||
#define BMI_EXECUTE 4
|
||||
/*
|
||||
* Semantics: Causes ATH6KL to execute code
|
||||
* Request format:
|
||||
* u32 command (BMI_EXECUTE)
|
||||
* u32 address
|
||||
* u32 parameter
|
||||
* Response format:
|
||||
* u32 return value
|
||||
*/
|
||||
|
||||
#define BMI_SET_APP_START 5
|
||||
/*
|
||||
* Semantics: Set Target application starting address
|
||||
* Request format:
|
||||
* u32 command (BMI_SET_APP_START)
|
||||
* u32 address
|
||||
* Response format: none
|
||||
*/
|
||||
|
||||
#define BMI_READ_SOC_REGISTER 6
|
||||
/*
|
||||
* Semantics: Read a 32-bit Target SOC register.
|
||||
* Request format:
|
||||
* u32 command (BMI_READ_REGISTER)
|
||||
* u32 address
|
||||
* Response format:
|
||||
* u32 value
|
||||
*/
|
||||
|
||||
#define BMI_WRITE_SOC_REGISTER 7
|
||||
/*
|
||||
* Semantics: Write a 32-bit Target SOC register.
|
||||
* Request format:
|
||||
* u32 command (BMI_WRITE_REGISTER)
|
||||
* u32 address
|
||||
* u32 value
|
||||
*
|
||||
* Response format: none
|
||||
*/
|
||||
|
||||
#define BMI_GET_TARGET_ID 8
|
||||
#define BMI_GET_TARGET_INFO 8
|
||||
/*
|
||||
* Semantics: Fetch the 4-byte Target information
|
||||
* Request format:
|
||||
* u32 command (BMI_GET_TARGET_ID/INFO)
|
||||
* Response format1 (old firmware):
|
||||
* u32 TargetVersionID
|
||||
* Response format2 (newer firmware):
|
||||
* u32 TARGET_VERSION_SENTINAL
|
||||
* struct bmi_target_info;
|
||||
*/
|
||||
|
||||
#define TARGET_VERSION_SENTINAL 0xffffffff
|
||||
#define TARGET_TYPE_AR6003 3
|
||||
|
||||
#define BMI_ROMPATCH_INSTALL 9
|
||||
/*
|
||||
* Semantics: Install a ROM Patch.
|
||||
* Request format:
|
||||
* u32 command (BMI_ROMPATCH_INSTALL)
|
||||
* u32 Target ROM Address
|
||||
* u32 Target RAM Address or Value (depending on Target Type)
|
||||
* u32 Size, in bytes
|
||||
* u32 Activate? 1-->activate;
|
||||
* 0-->install but do not activate
|
||||
* Response format:
|
||||
* u32 PatchID
|
||||
*/
|
||||
|
||||
#define BMI_ROMPATCH_UNINSTALL 10
|
||||
/*
|
||||
* Semantics: Uninstall a previously-installed ROM Patch,
|
||||
* automatically deactivating, if necessary.
|
||||
* Request format:
|
||||
* u32 command (BMI_ROMPATCH_UNINSTALL)
|
||||
* u32 PatchID
|
||||
*
|
||||
* Response format: none
|
||||
*/
|
||||
|
||||
#define BMI_ROMPATCH_ACTIVATE 11
|
||||
/*
|
||||
* Semantics: Activate a list of previously-installed ROM Patches.
|
||||
* Request format:
|
||||
* u32 command (BMI_ROMPATCH_ACTIVATE)
|
||||
* u32 rompatch_count
|
||||
* u32 PatchID[rompatch_count]
|
||||
*
|
||||
* Response format: none
|
||||
*/
|
||||
|
||||
#define BMI_ROMPATCH_DEACTIVATE 12
|
||||
/*
|
||||
* Semantics: Deactivate a list of active ROM Patches.
|
||||
* Request format:
|
||||
* u32 command (BMI_ROMPATCH_DEACTIVATE)
|
||||
* u32 rompatch_count
|
||||
* u32 PatchID[rompatch_count]
|
||||
*
|
||||
* Response format: none
|
||||
*/
|
||||
|
||||
|
||||
#define BMI_LZ_STREAM_START 13
|
||||
/*
|
||||
* Semantics: Begin an LZ-compressed stream of input
|
||||
* which is to be uncompressed by the Target to an
|
||||
* output buffer at address. The output buffer must
|
||||
* be sufficiently large to hold the uncompressed
|
||||
* output from the compressed input stream. This BMI
|
||||
* command should be followed by a series of 1 or more
|
||||
* BMI_LZ_DATA commands.
|
||||
* u32 command (BMI_LZ_STREAM_START)
|
||||
* u32 address
|
||||
* Note: Not supported on all versions of ROM firmware.
|
||||
*/
|
||||
|
||||
#define BMI_LZ_DATA 14
|
||||
/*
|
||||
* Semantics: Host writes ATH6KL memory with LZ-compressed
|
||||
* data which is uncompressed by the Target. This command
|
||||
* must be preceded by a BMI_LZ_STREAM_START command. A series
|
||||
* of BMI_LZ_DATA commands are considered part of a single
|
||||
* input stream until another BMI_LZ_STREAM_START is issued.
|
||||
* Request format:
|
||||
* u32 command (BMI_LZ_DATA)
|
||||
* u32 length (of compressed data),
|
||||
* at most BMI_DATASZ_MAX
|
||||
* u8 CompressedData[length]
|
||||
* Response format: none
|
||||
* Note: Not supported on all versions of ROM firmware.
|
||||
*/
|
||||
|
||||
#define BMI_COMMUNICATION_TIMEOUT 1000 /* in msec */
|
||||
|
||||
struct ath6kl;
|
||||
struct ath6kl_bmi_target_info {
|
||||
__le32 byte_count; /* size of this structure */
|
||||
__le32 version; /* target version id */
|
||||
__le32 type; /* target type */
|
||||
} __packed;
|
||||
|
||||
int ath6kl_bmi_init(struct ath6kl *ar);
|
||||
void ath6kl_bmi_cleanup(struct ath6kl *ar);
|
||||
int ath6kl_bmi_done(struct ath6kl *ar);
|
||||
int ath6kl_bmi_get_target_info(struct ath6kl *ar,
|
||||
struct ath6kl_bmi_target_info *targ_info);
|
||||
int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len);
|
||||
int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len);
|
||||
int ath6kl_bmi_execute(struct ath6kl *ar,
|
||||
u32 addr, u32 *param);
|
||||
int ath6kl_bmi_set_app_start(struct ath6kl *ar,
|
||||
u32 addr);
|
||||
int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param);
|
||||
int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param);
|
||||
int ath6kl_bmi_lz_data(struct ath6kl *ar,
|
||||
u8 *buf, u32 len);
|
||||
int ath6kl_bmi_lz_stream_start(struct ath6kl *ar,
|
||||
u32 addr);
|
||||
int ath6kl_bmi_fast_download(struct ath6kl *ar,
|
||||
u32 addr, u8 *buf, u32 len);
|
||||
#endif
|
1538
drivers/net/wireless/ath/ath6kl/cfg80211.c
Normal file
1538
drivers/net/wireless/ath/ath6kl/cfg80211.c
Normal file
File diff suppressed because it is too large
Load Diff
39
drivers/net/wireless/ath/ath6kl/cfg80211.h
Normal file
39
drivers/net/wireless/ath/ath6kl/cfg80211.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#ifndef ATH6KL_CFG80211_H
|
||||
#define ATH6KL_CFG80211_H
|
||||
|
||||
struct wireless_dev *ath6kl_cfg80211_init(struct device *dev);
|
||||
void ath6kl_cfg80211_deinit(struct ath6kl *ar);
|
||||
|
||||
void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status);
|
||||
|
||||
void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel,
|
||||
u8 *bssid, u16 listen_intvl,
|
||||
u16 beacon_intvl,
|
||||
enum network_type nw_type,
|
||||
u8 beacon_ie_len, u8 assoc_req_len,
|
||||
u8 assoc_resp_len, u8 *assoc_info);
|
||||
|
||||
void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason,
|
||||
u8 *bssid, u8 assoc_resp_len,
|
||||
u8 *assoc_info, u16 proto_reason);
|
||||
|
||||
void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl *ar, u8 keyid,
|
||||
bool ismcast);
|
||||
|
||||
#endif /* ATH6KL_CFG80211_H */
|
180
drivers/net/wireless/ath/ath6kl/common.h
Normal file
180
drivers/net/wireless/ath/ath6kl/common.h
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (c) 2010-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.
|
||||
*/
|
||||
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#define ATH6KL_MAX_IE 256
|
||||
|
||||
extern int ath6kl_printk(const char *level, const char *fmt, ...);
|
||||
|
||||
#define A_CACHE_LINE_PAD 128
|
||||
|
||||
/*
|
||||
* Reflects the version of binary interface exposed by ATH6KL target
|
||||
* firmware. Needs to be incremented by 1 for any change in the firmware
|
||||
* that requires upgrade of the driver on the host side for the change to
|
||||
* work correctly
|
||||
*/
|
||||
#define ATH6KL_ABI_VERSION 1
|
||||
|
||||
#define SIGNAL_QUALITY_METRICS_NUM_MAX 2
|
||||
|
||||
enum {
|
||||
SIGNAL_QUALITY_METRICS_SNR = 0,
|
||||
SIGNAL_QUALITY_METRICS_RSSI,
|
||||
SIGNAL_QUALITY_METRICS_ALL,
|
||||
};
|
||||
|
||||
/*
|
||||
* Data Path
|
||||
*/
|
||||
|
||||
#define WMI_MAX_TX_DATA_FRAME_LENGTH \
|
||||
(1500 + sizeof(struct wmi_data_hdr) + \
|
||||
sizeof(struct ethhdr) + \
|
||||
sizeof(struct ath6kl_llc_snap_hdr))
|
||||
|
||||
/* An AMSDU frame */ /* The MAX AMSDU length of AR6003 is 3839 */
|
||||
#define WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH \
|
||||
(3840 + sizeof(struct wmi_data_hdr) + \
|
||||
sizeof(struct ethhdr) + \
|
||||
sizeof(struct ath6kl_llc_snap_hdr))
|
||||
|
||||
#define EPPING_ALIGNMENT_PAD \
|
||||
(((sizeof(struct htc_frame_hdr) + 3) & (~0x3)) \
|
||||
- sizeof(struct htc_frame_hdr))
|
||||
|
||||
struct ath6kl_llc_snap_hdr {
|
||||
u8 dsap;
|
||||
u8 ssap;
|
||||
u8 cntl;
|
||||
u8 org_code[3];
|
||||
__be16 eth_type;
|
||||
} __packed;
|
||||
|
||||
enum crypto_type {
|
||||
NONE_CRYPT = 0x01,
|
||||
WEP_CRYPT = 0x02,
|
||||
TKIP_CRYPT = 0x04,
|
||||
AES_CRYPT = 0x08,
|
||||
};
|
||||
|
||||
#define ATH6KL_NODE_HASHSIZE 32
|
||||
/* simple hash is enough for variation of macaddr */
|
||||
#define ATH6KL_NODE_HASH(addr) \
|
||||
(((const u8 *)(addr))[ETH_ALEN - 1] % \
|
||||
ATH6KL_NODE_HASHSIZE)
|
||||
|
||||
/*
|
||||
* Table of ath6kl_node instances. Each ieee80211com
|
||||
* has at least one for holding the scan candidates.
|
||||
* When operating as an access point or in ibss mode there
|
||||
* is a second table for associated stations or neighbors.
|
||||
*/
|
||||
struct ath6kl_node_table {
|
||||
spinlock_t nt_nodelock; /* on node table */
|
||||
struct bss *nt_node_first; /* information of all nodes */
|
||||
struct bss *nt_node_last; /* information of all nodes */
|
||||
struct bss *nt_hash[ATH6KL_NODE_HASHSIZE];
|
||||
const char *nt_name; /* for debugging */
|
||||
u32 nt_node_age; /* node aging time */
|
||||
};
|
||||
|
||||
#define WLAN_NODE_INACT_TIMEOUT_MSEC 120000
|
||||
#define WLAN_NODE_INACT_CNT 4
|
||||
|
||||
struct ath6kl_common_ie {
|
||||
u16 ie_chan;
|
||||
u8 *ie_tstamp;
|
||||
u8 *ie_ssid;
|
||||
u8 *ie_rates;
|
||||
u8 *ie_xrates;
|
||||
u8 *ie_country;
|
||||
u8 *ie_wpa;
|
||||
u8 *ie_rsn;
|
||||
u8 *ie_wmm;
|
||||
u8 *ie_ath;
|
||||
u16 ie_capInfo;
|
||||
u16 ie_beaconInt;
|
||||
u8 *ie_tim;
|
||||
u8 *ie_chswitch;
|
||||
u8 ie_erp;
|
||||
u8 *ie_wsc;
|
||||
u8 *ie_htcap;
|
||||
u8 *ie_htop;
|
||||
};
|
||||
|
||||
struct bss {
|
||||
u8 ni_macaddr[ETH_ALEN];
|
||||
u8 ni_snr;
|
||||
s16 ni_rssi;
|
||||
struct bss *ni_list_next;
|
||||
struct bss *ni_list_prev;
|
||||
struct bss *ni_hash_next;
|
||||
struct bss *ni_hash_prev;
|
||||
struct ath6kl_common_ie ni_cie;
|
||||
u8 *ni_buf;
|
||||
u16 ni_framelen;
|
||||
struct ath6kl_node_table *ni_table;
|
||||
u32 ni_refcnt;
|
||||
|
||||
u32 ni_tstamp;
|
||||
u32 ni_actcnt;
|
||||
};
|
||||
|
||||
struct htc_endpoint_credit_dist;
|
||||
struct ath6kl;
|
||||
enum htc_credit_dist_reason;
|
||||
struct htc_credit_state_info;
|
||||
|
||||
struct bss *wlan_node_alloc(int wh_size);
|
||||
void wlan_node_free(struct bss *ni);
|
||||
void wlan_setup_node(struct ath6kl_node_table *nt, struct bss *ni,
|
||||
const u8 *mac_addr);
|
||||
struct bss *wlan_find_node(struct ath6kl_node_table *nt,
|
||||
const u8 *mac_addr);
|
||||
void wlan_node_reclaim(struct ath6kl_node_table *nt, struct bss *ni);
|
||||
void wlan_free_allnodes(struct ath6kl_node_table *nt);
|
||||
void wlan_iterate_nodes(struct ath6kl_node_table *nt, void *arg);
|
||||
|
||||
void wlan_node_table_init(struct ath6kl_node_table *nt);
|
||||
void wlan_node_table_cleanup(struct ath6kl_node_table *nt);
|
||||
|
||||
void wlan_refresh_inactive_nodes(struct ath6kl *ar);
|
||||
|
||||
struct bss *wlan_find_ssid_node(struct ath6kl_node_table *nt, u8 *ssid,
|
||||
u32 ssid_len, bool is_wpa2, bool match_ssid);
|
||||
|
||||
void wlan_node_return(struct ath6kl_node_table *nt, struct bss *ni);
|
||||
|
||||
int ath6k_setup_credit_dist(void *htc_handle,
|
||||
struct htc_credit_state_info *cred_info);
|
||||
void ath6k_credit_distribute(struct htc_credit_state_info *cred_inf,
|
||||
struct list_head *epdist_list,
|
||||
enum htc_credit_dist_reason reason);
|
||||
void ath6k_credit_init(struct htc_credit_state_info *cred_inf,
|
||||
struct list_head *ep_list,
|
||||
int tot_credits);
|
||||
void ath6k_seek_credits(struct htc_credit_state_info *cred_inf,
|
||||
struct htc_endpoint_credit_dist *ep_dist);
|
||||
struct ath6kl *ath6kl_core_alloc(struct device *sdev);
|
||||
int ath6kl_core_init(struct ath6kl *ar);
|
||||
int ath6kl_unavail_ev(struct ath6kl *ar);
|
||||
struct sk_buff *ath6kl_buf_alloc(int size);
|
||||
#endif /* COMMON_H */
|
544
drivers/net/wireless/ath/ath6kl/core.h
Normal file
544
drivers/net/wireless/ath/ath6kl/core.h
Normal file
@ -0,0 +1,544 @@
|
||||
/*
|
||||
* Copyright (c) 2010-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.
|
||||
*/
|
||||
|
||||
#ifndef CORE_H
|
||||
#define CORE_H
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/sched.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include "htc.h"
|
||||
#include "wmi.h"
|
||||
#include "bmi.h"
|
||||
|
||||
#define MAX_ATH6KL 1
|
||||
#define ATH6KL_MAX_RX_BUFFERS 16
|
||||
#define ATH6KL_BUFFER_SIZE 1664
|
||||
#define ATH6KL_MAX_AMSDU_RX_BUFFERS 4
|
||||
#define ATH6KL_AMSDU_REFILL_THRESHOLD 3
|
||||
#define ATH6KL_AMSDU_BUFFER_SIZE (WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH + 128)
|
||||
#define MAX_MSDU_SUBFRAME_PAYLOAD_LEN 1508
|
||||
#define MIN_MSDU_SUBFRAME_PAYLOAD_LEN 46
|
||||
|
||||
#define USER_SAVEDKEYS_STAT_INIT 0
|
||||
#define USER_SAVEDKEYS_STAT_RUN 1
|
||||
|
||||
#define ATH6KL_TX_TIMEOUT 10
|
||||
#define ATH6KL_MAX_ENDPOINTS 4
|
||||
#define MAX_NODE_NUM 15
|
||||
|
||||
/* MAX_HI_COOKIE_NUM are reserved for high priority traffic */
|
||||
#define MAX_DEF_COOKIE_NUM 180
|
||||
#define MAX_HI_COOKIE_NUM 18 /* 10% of MAX_COOKIE_NUM */
|
||||
#define MAX_COOKIE_NUM (MAX_DEF_COOKIE_NUM + MAX_HI_COOKIE_NUM)
|
||||
|
||||
#define MAX_DEFAULT_SEND_QUEUE_DEPTH (MAX_DEF_COOKIE_NUM / WMM_NUM_AC)
|
||||
|
||||
#define DISCON_TIMER_INTVAL 10000 /* in msec */
|
||||
#define A_DEFAULT_LISTEN_INTERVAL 100
|
||||
#define A_MAX_WOW_LISTEN_INTERVAL 1000
|
||||
|
||||
/* AR6003 1.0 definitions */
|
||||
#define AR6003_REV1_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_PATCH_FILE "ath6k/AR6003/hw2.0/data.patch.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"
|
||||
|
||||
/* 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_PATCH_FILE "ath6k/AR6003/hw2.1.1/data.patch.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"
|
||||
|
||||
/* Per STA data, used in AP mode */
|
||||
#define STA_PS_AWAKE BIT(0)
|
||||
#define STA_PS_SLEEP BIT(1)
|
||||
#define STA_PS_POLLED BIT(2)
|
||||
|
||||
/* HTC TX packet tagging definitions */
|
||||
#define ATH6KL_CONTROL_PKT_TAG HTC_TX_PACKET_TAG_USER_DEFINED
|
||||
#define ATH6KL_DATA_PKT_TAG (ATH6KL_CONTROL_PKT_TAG + 1)
|
||||
|
||||
#define AR6003_CUST_DATA_SIZE 16
|
||||
|
||||
#define AGGR_WIN_IDX(x, y) ((x) % (y))
|
||||
#define AGGR_INCR_IDX(x, y) AGGR_WIN_IDX(((x) + 1), (y))
|
||||
#define AGGR_DCRM_IDX(x, y) AGGR_WIN_IDX(((x) - 1), (y))
|
||||
#define ATH6KL_MAX_SEQ_NO 0xFFF
|
||||
#define ATH6KL_NEXT_SEQ_NO(x) (((x) + 1) & ATH6KL_MAX_SEQ_NO)
|
||||
|
||||
#define NUM_OF_TIDS 8
|
||||
#define AGGR_SZ_DEFAULT 8
|
||||
|
||||
#define AGGR_WIN_SZ_MIN 2
|
||||
#define AGGR_WIN_SZ_MAX 8
|
||||
|
||||
#define TID_WINDOW_SZ(_x) ((_x) << 1)
|
||||
|
||||
#define AGGR_NUM_OF_FREE_NETBUFS 16
|
||||
|
||||
#define AGGR_RX_TIMEOUT 400 /* in ms */
|
||||
|
||||
#define WMI_TIMEOUT (2 * HZ)
|
||||
|
||||
#define MBOX_YIELD_LIMIT 99
|
||||
|
||||
/* configuration lags */
|
||||
/*
|
||||
* ATH6KL_CONF_IGNORE_ERP_BARKER: Ignore the barker premable in
|
||||
* ERP IE of beacon to determine the short premable support when
|
||||
* sending (Re)Assoc req.
|
||||
* ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN: Don't send the power
|
||||
* module state transition failure events which happen during
|
||||
* scan, to the host.
|
||||
*/
|
||||
#define ATH6KL_CONF_IGNORE_ERP_BARKER BIT(0)
|
||||
#define ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN BIT(1)
|
||||
#define ATH6KL_CONF_ENABLE_11N BIT(2)
|
||||
#define ATH6KL_CONF_ENABLE_TX_BURST BIT(3)
|
||||
|
||||
enum wlan_low_pwr_state {
|
||||
WLAN_POWER_STATE_ON,
|
||||
WLAN_POWER_STATE_CUT_PWR,
|
||||
WLAN_POWER_STATE_DEEP_SLEEP,
|
||||
WLAN_POWER_STATE_WOW
|
||||
};
|
||||
|
||||
enum sme_state {
|
||||
SME_DISCONNECTED,
|
||||
SME_CONNECTING,
|
||||
SME_CONNECTED
|
||||
};
|
||||
|
||||
struct skb_hold_q {
|
||||
struct sk_buff *skb;
|
||||
bool is_amsdu;
|
||||
u16 seq_no;
|
||||
};
|
||||
|
||||
struct rxtid {
|
||||
bool aggr;
|
||||
bool progress;
|
||||
bool timer_mon;
|
||||
u16 win_sz;
|
||||
u16 seq_next;
|
||||
u32 hold_q_sz;
|
||||
struct skb_hold_q *hold_q;
|
||||
struct sk_buff_head q;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct rxtid_stats {
|
||||
u32 num_into_aggr;
|
||||
u32 num_dups;
|
||||
u32 num_oow;
|
||||
u32 num_mpdu;
|
||||
u32 num_amsdu;
|
||||
u32 num_delivered;
|
||||
u32 num_timeouts;
|
||||
u32 num_hole;
|
||||
u32 num_bar;
|
||||
};
|
||||
|
||||
struct aggr_info {
|
||||
u8 aggr_sz;
|
||||
u8 timer_scheduled;
|
||||
struct timer_list timer;
|
||||
struct net_device *dev;
|
||||
struct rxtid rx_tid[NUM_OF_TIDS];
|
||||
struct sk_buff_head free_q;
|
||||
struct rxtid_stats stat[NUM_OF_TIDS];
|
||||
};
|
||||
|
||||
struct ath6kl_wep_key {
|
||||
u8 key_index;
|
||||
u8 key_len;
|
||||
u8 key[64];
|
||||
};
|
||||
|
||||
#define ATH6KL_KEY_SEQ_LEN 8
|
||||
|
||||
struct ath6kl_key {
|
||||
u8 key[WLAN_MAX_KEY_LEN];
|
||||
u8 key_len;
|
||||
u8 seq[ATH6KL_KEY_SEQ_LEN];
|
||||
u8 seq_len;
|
||||
u32 cipher;
|
||||
};
|
||||
|
||||
struct ath6kl_node_mapping {
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
u8 ep_id;
|
||||
u8 tx_pend;
|
||||
};
|
||||
|
||||
struct ath6kl_cookie {
|
||||
struct sk_buff *skb;
|
||||
u32 map_no;
|
||||
struct htc_packet htc_pkt;
|
||||
struct ath6kl_cookie *arc_list_next;
|
||||
};
|
||||
|
||||
struct ath6kl_sta {
|
||||
u16 sta_flags;
|
||||
u8 mac[ETH_ALEN];
|
||||
u8 aid;
|
||||
u8 keymgmt;
|
||||
u8 ucipher;
|
||||
u8 auth;
|
||||
u8 wpa_ie[ATH6KL_MAX_IE];
|
||||
struct sk_buff_head psq;
|
||||
spinlock_t psq_lock;
|
||||
};
|
||||
|
||||
struct ath6kl_version {
|
||||
u32 target_ver;
|
||||
u32 wlan_ver;
|
||||
u32 abi_ver;
|
||||
};
|
||||
|
||||
struct ath6kl_bmi {
|
||||
u32 cmd_credits;
|
||||
bool done_sent;
|
||||
u8 *cmd_buf;
|
||||
};
|
||||
|
||||
struct target_stats {
|
||||
u64 tx_pkt;
|
||||
u64 tx_byte;
|
||||
u64 tx_ucast_pkt;
|
||||
u64 tx_ucast_byte;
|
||||
u64 tx_mcast_pkt;
|
||||
u64 tx_mcast_byte;
|
||||
u64 tx_bcast_pkt;
|
||||
u64 tx_bcast_byte;
|
||||
u64 tx_rts_success_cnt;
|
||||
u64 tx_pkt_per_ac[4];
|
||||
|
||||
u64 tx_err;
|
||||
u64 tx_fail_cnt;
|
||||
u64 tx_retry_cnt;
|
||||
u64 tx_mult_retry_cnt;
|
||||
u64 tx_rts_fail_cnt;
|
||||
|
||||
u64 rx_pkt;
|
||||
u64 rx_byte;
|
||||
u64 rx_ucast_pkt;
|
||||
u64 rx_ucast_byte;
|
||||
u64 rx_mcast_pkt;
|
||||
u64 rx_mcast_byte;
|
||||
u64 rx_bcast_pkt;
|
||||
u64 rx_bcast_byte;
|
||||
u64 rx_frgment_pkt;
|
||||
|
||||
u64 rx_err;
|
||||
u64 rx_crc_err;
|
||||
u64 rx_key_cache_miss;
|
||||
u64 rx_decrypt_err;
|
||||
u64 rx_dupl_frame;
|
||||
|
||||
u64 tkip_local_mic_fail;
|
||||
u64 tkip_cnter_measures_invoked;
|
||||
u64 tkip_replays;
|
||||
u64 tkip_fmt_err;
|
||||
u64 ccmp_fmt_err;
|
||||
u64 ccmp_replays;
|
||||
|
||||
u64 pwr_save_fail_cnt;
|
||||
|
||||
u64 cs_bmiss_cnt;
|
||||
u64 cs_low_rssi_cnt;
|
||||
u64 cs_connect_cnt;
|
||||
u64 cs_discon_cnt;
|
||||
|
||||
s32 tx_ucast_rate;
|
||||
s32 rx_ucast_rate;
|
||||
|
||||
u32 lq_val;
|
||||
|
||||
u32 wow_pkt_dropped;
|
||||
u16 wow_evt_discarded;
|
||||
|
||||
s16 noise_floor_calib;
|
||||
s16 cs_rssi;
|
||||
s16 cs_ave_beacon_rssi;
|
||||
u8 cs_ave_beacon_snr;
|
||||
u8 cs_last_roam_msec;
|
||||
u8 cs_snr;
|
||||
|
||||
u8 wow_host_pkt_wakeups;
|
||||
u8 wow_host_evt_wakeups;
|
||||
|
||||
u32 arp_received;
|
||||
u32 arp_matched;
|
||||
u32 arp_replied;
|
||||
};
|
||||
|
||||
struct ath6kl_mbox_info {
|
||||
u32 htc_addr;
|
||||
u32 htc_ext_addr;
|
||||
u32 htc_ext_sz;
|
||||
|
||||
u32 block_size;
|
||||
|
||||
u32 gmbox_addr;
|
||||
|
||||
u32 gmbox_sz;
|
||||
};
|
||||
|
||||
/*
|
||||
* 802.11i defines an extended IV for use with non-WEP ciphers.
|
||||
* When the EXTIV bit is set in the key id byte an additional
|
||||
* 4 bytes immediately follow the IV for TKIP. For CCMP the
|
||||
* EXTIV bit is likewise set but the 8 bytes represent the
|
||||
* CCMP header rather than IV+extended-IV.
|
||||
*/
|
||||
|
||||
#define ATH6KL_KEYBUF_SIZE 16
|
||||
#define ATH6KL_MICBUF_SIZE (8+8) /* space for both tx and rx */
|
||||
|
||||
#define ATH6KL_KEY_XMIT 0x01
|
||||
#define ATH6KL_KEY_RECV 0x02
|
||||
#define ATH6KL_KEY_DEFAULT 0x80 /* default xmit key */
|
||||
|
||||
/*
|
||||
* WPA/RSN get/set key request. Specify the key/cipher
|
||||
* type and whether the key is to be used for sending and/or
|
||||
* receiving. The key index should be set only when working
|
||||
* with global keys (use IEEE80211_KEYIX_NONE for ``no index'').
|
||||
* Otherwise a unicast/pairwise key is specified by the bssid
|
||||
* (on a station) or mac address (on an ap). They key length
|
||||
* must include any MIC key data; otherwise it should be no
|
||||
* more than ATH6KL_KEYBUF_SIZE.
|
||||
*/
|
||||
struct ath6kl_req_key {
|
||||
u8 ik_type; /* key/cipher type */
|
||||
u8 ik_pad;
|
||||
u16 ik_keyix; /* key index */
|
||||
u8 ik_keylen; /* key length in bytes */
|
||||
u8 ik_flags;
|
||||
u8 ik_macaddr[ETH_ALEN];
|
||||
u64 ik_keyrsc; /* key receive sequence counter */
|
||||
u64 ik_keytsc; /* key transmit sequence counter */
|
||||
u8 ik_keydata[ATH6KL_KEYBUF_SIZE + ATH6KL_MICBUF_SIZE];
|
||||
};
|
||||
|
||||
/* Flag info */
|
||||
#define WMI_ENABLED 0
|
||||
#define WMI_READY 1
|
||||
#define CONNECTED 2
|
||||
#define STATS_UPDATE_PEND 3
|
||||
#define CONNECT_PEND 4
|
||||
#define WMM_ENABLED 5
|
||||
#define NETQ_STOPPED 6
|
||||
#define WMI_CTRL_EP_FULL 7
|
||||
#define DTIM_EXPIRED 8
|
||||
#define DESTROY_IN_PROGRESS 9
|
||||
#define NETDEV_REGISTERED 10
|
||||
#define SKIP_SCAN 11
|
||||
#define WLAN_ENABLED 12
|
||||
|
||||
struct ath6kl {
|
||||
struct device *dev;
|
||||
struct net_device *net_dev;
|
||||
struct ath6kl_bmi bmi;
|
||||
const struct ath6kl_hif_ops *hif_ops;
|
||||
struct wmi *wmi;
|
||||
int tx_pending[ENDPOINT_MAX];
|
||||
int total_tx_data_pend;
|
||||
struct htc_target *htc_target;
|
||||
void *hif_priv;
|
||||
spinlock_t lock;
|
||||
struct semaphore sem;
|
||||
int ssid_len;
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
u8 next_mode;
|
||||
u8 nw_type;
|
||||
u8 dot11_auth_mode;
|
||||
u8 auth_mode;
|
||||
u8 prwise_crypto;
|
||||
u8 prwise_crypto_len;
|
||||
u8 grp_crypto;
|
||||
u8 grp_crpto_len;
|
||||
u8 def_txkey_index;
|
||||
struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1];
|
||||
u8 bssid[ETH_ALEN];
|
||||
u8 req_bssid[ETH_ALEN];
|
||||
u16 ch_hint;
|
||||
u16 bss_ch;
|
||||
u16 listen_intvl_b;
|
||||
u16 listen_intvl_t;
|
||||
struct ath6kl_version version;
|
||||
u32 target_type;
|
||||
u8 tx_pwr;
|
||||
struct net_device_stats net_stats;
|
||||
struct target_stats target_stats;
|
||||
struct ath6kl_node_mapping node_map[MAX_NODE_NUM];
|
||||
u8 ibss_ps_enable;
|
||||
u8 node_num;
|
||||
u8 next_ep_id;
|
||||
struct ath6kl_cookie *cookie_list;
|
||||
u32 cookie_count;
|
||||
enum htc_endpoint_id ac2ep_map[WMM_NUM_AC];
|
||||
bool ac_stream_active[WMM_NUM_AC];
|
||||
u8 ac_stream_pri_map[WMM_NUM_AC];
|
||||
u8 hiac_stream_active_pri;
|
||||
u8 ep2ac_map[ENDPOINT_MAX];
|
||||
enum htc_endpoint_id ctrl_ep;
|
||||
struct htc_credit_state_info credit_state_info;
|
||||
u32 connect_ctrl_flags;
|
||||
u32 user_key_ctrl;
|
||||
u8 usr_bss_filter;
|
||||
struct ath6kl_sta sta_list[AP_MAX_NUM_STA];
|
||||
u8 sta_list_index;
|
||||
struct ath6kl_req_key ap_mode_bkey;
|
||||
struct sk_buff_head mcastpsq;
|
||||
spinlock_t mcastpsq_lock;
|
||||
u8 intra_bss;
|
||||
struct aggr_info *aggr_cntxt;
|
||||
struct wmi_ap_mode_stat ap_stats;
|
||||
u8 ap_country_code[3];
|
||||
struct list_head amsdu_rx_buffer_queue;
|
||||
struct timer_list disconnect_timer;
|
||||
u8 rx_meta_ver;
|
||||
struct wireless_dev *wdev;
|
||||
struct cfg80211_scan_request *scan_req;
|
||||
struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1];
|
||||
enum sme_state sme_state;
|
||||
enum wlan_low_pwr_state wlan_pwr_state;
|
||||
struct wmi_scan_params_cmd sc_params;
|
||||
#define AR_MCAST_FILTER_MAC_ADDR_SIZE 4
|
||||
u8 auto_auth_stage;
|
||||
|
||||
u16 conf_flags;
|
||||
wait_queue_head_t event_wq;
|
||||
struct ath6kl_mbox_info mbox_info;
|
||||
|
||||
struct ath6kl_cookie cookie_mem[MAX_COOKIE_NUM];
|
||||
int reconnect_flag;
|
||||
unsigned long flag;
|
||||
|
||||
u8 *fw_board;
|
||||
size_t fw_board_len;
|
||||
|
||||
u8 *fw_otp;
|
||||
size_t fw_otp_len;
|
||||
|
||||
u8 *fw;
|
||||
size_t fw_len;
|
||||
|
||||
u8 *fw_patch;
|
||||
size_t fw_patch_len;
|
||||
|
||||
struct workqueue_struct *ath6kl_wq;
|
||||
|
||||
struct ath6kl_node_table scan_table;
|
||||
};
|
||||
|
||||
static inline void *ath6kl_priv(struct net_device *dev)
|
||||
{
|
||||
return wdev_priv(dev->ieee80211_ptr);
|
||||
}
|
||||
|
||||
static inline void ath6kl_deposit_credit_to_ep(struct htc_credit_state_info
|
||||
*cred_info,
|
||||
struct htc_endpoint_credit_dist
|
||||
*ep_dist, int credits)
|
||||
{
|
||||
ep_dist->credits += credits;
|
||||
ep_dist->cred_assngd += credits;
|
||||
cred_info->cur_free_credits -= credits;
|
||||
}
|
||||
|
||||
void ath6kl_destroy(struct net_device *dev, unsigned int unregister);
|
||||
int ath6kl_configure_target(struct ath6kl *ar);
|
||||
void ath6kl_detect_error(unsigned long ptr);
|
||||
void disconnect_timer_handler(unsigned long ptr);
|
||||
void init_netdev(struct net_device *dev);
|
||||
void ath6kl_cookie_init(struct ath6kl *ar);
|
||||
void ath6kl_cookie_cleanup(struct ath6kl *ar);
|
||||
void ath6kl_rx(struct htc_target *target, struct htc_packet *packet);
|
||||
void ath6kl_tx_complete(void *context, struct list_head *packet_queue);
|
||||
enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
|
||||
struct htc_packet *packet);
|
||||
void ath6kl_stop_txrx(struct ath6kl *ar);
|
||||
void ath6kl_cleanup_amsdu_rxbufs(struct ath6kl *ar);
|
||||
int ath6kl_access_datadiag(struct ath6kl *ar, u32 address,
|
||||
u8 *data, u32 length, bool read);
|
||||
int ath6kl_read_reg_diag(struct ath6kl *ar, u32 *address, u32 *data);
|
||||
void ath6kl_init_profile_info(struct ath6kl *ar);
|
||||
void ath6kl_tx_data_cleanup(struct ath6kl *ar);
|
||||
void ath6kl_stop_endpoint(struct net_device *dev, bool keep_profile,
|
||||
bool get_dbglogs);
|
||||
|
||||
struct ath6kl_cookie *ath6kl_alloc_cookie(struct ath6kl *ar);
|
||||
void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie);
|
||||
int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev);
|
||||
|
||||
struct aggr_info *aggr_init(struct net_device *dev);
|
||||
void ath6kl_rx_refill(struct htc_target *target,
|
||||
enum htc_endpoint_id endpoint);
|
||||
void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count);
|
||||
struct htc_packet *ath6kl_alloc_amsdu_rxbuf(struct htc_target *target,
|
||||
enum htc_endpoint_id endpoint,
|
||||
int len);
|
||||
void aggr_module_destroy(struct aggr_info *aggr_info);
|
||||
void aggr_reset_state(struct aggr_info *aggr_info);
|
||||
|
||||
struct ath6kl_sta *ath6kl_find_sta(struct ath6kl *ar, u8 * node_addr);
|
||||
struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid);
|
||||
|
||||
void ath6kl_ready_event(void *devt, u8 * datap, u32 sw_ver, u32 abi_ver);
|
||||
int ath6kl_control_tx(void *devt, struct sk_buff *skb,
|
||||
enum htc_endpoint_id eid);
|
||||
void ath6kl_connect_event(struct ath6kl *ar, u16 channel,
|
||||
u8 *bssid, u16 listen_int,
|
||||
u16 beacon_int, enum network_type net_type,
|
||||
u8 beacon_ie_len, u8 assoc_req_len,
|
||||
u8 assoc_resp_len, u8 *assoc_info);
|
||||
void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason,
|
||||
u8 *bssid, u8 assoc_resp_len,
|
||||
u8 *assoc_info, u16 prot_reason_status);
|
||||
void ath6kl_tkip_micerr_event(struct ath6kl *ar, u8 keyid, bool ismcast);
|
||||
void ath6kl_txpwr_rx_evt(void *devt, u8 tx_pwr);
|
||||
void ath6kl_scan_complete_evt(struct ath6kl *ar, int status);
|
||||
void ath6kl_tgt_stats_event(struct ath6kl *ar, u8 *ptr, u32 len);
|
||||
void ath6kl_indicate_tx_activity(void *devt, u8 traffic_class, bool active);
|
||||
enum htc_endpoint_id ath6kl_ac2_endpoint_id(void *devt, u8 ac);
|
||||
|
||||
void ath6kl_pspoll_event(struct ath6kl *ar, u8 aid);
|
||||
|
||||
void ath6kl_dtimexpiry_event(struct ath6kl *ar);
|
||||
void ath6kl_disconnect(struct ath6kl *ar);
|
||||
void aggr_recv_delba_req_evt(struct ath6kl *ar, u8 tid);
|
||||
void aggr_recv_addba_req_evt(struct ath6kl *ar, u8 tid, u16 seq_no,
|
||||
u8 win_sz);
|
||||
void ath6kl_wakeup_event(void *dev);
|
||||
void ath6kl_target_failure(struct ath6kl *ar);
|
||||
|
||||
void ath6kl_cfg80211_scan_node(struct wiphy *wiphy, struct bss *ni);
|
||||
#endif /* CORE_H */
|
150
drivers/net/wireless/ath/ath6kl/debug.c
Normal file
150
drivers/net/wireless/ath/ath6kl/debug.c
Normal file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (c) 2004-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 "core.h"
|
||||
#include "debug.h"
|
||||
|
||||
int ath6kl_printk(const char *level, const char *fmt, ...)
|
||||
{
|
||||
struct va_format vaf;
|
||||
va_list args;
|
||||
int rtn;
|
||||
|
||||
va_start(args, fmt);
|
||||
|
||||
vaf.fmt = fmt;
|
||||
vaf.va = &args;
|
||||
|
||||
rtn = printk("%sath6kl: %pV", level, &vaf);
|
||||
|
||||
va_end(args);
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ATH6KL_DEBUG
|
||||
void ath6kl_dump_registers(struct ath6kl_device *dev,
|
||||
struct ath6kl_irq_proc_registers *irq_proc_reg,
|
||||
struct ath6kl_irq_enable_reg *irq_enable_reg)
|
||||
{
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, ("<------- Register Table -------->\n"));
|
||||
|
||||
if (irq_proc_reg != NULL) {
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"Host Int status: 0x%x\n",
|
||||
irq_proc_reg->host_int_status);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"CPU Int status: 0x%x\n",
|
||||
irq_proc_reg->cpu_int_status);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"Error Int status: 0x%x\n",
|
||||
irq_proc_reg->error_int_status);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"Counter Int status: 0x%x\n",
|
||||
irq_proc_reg->counter_int_status);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"Mbox Frame: 0x%x\n",
|
||||
irq_proc_reg->mbox_frame);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"Rx Lookahead Valid: 0x%x\n",
|
||||
irq_proc_reg->rx_lkahd_valid);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"Rx Lookahead 0: 0x%x\n",
|
||||
irq_proc_reg->rx_lkahd[0]);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"Rx Lookahead 1: 0x%x\n",
|
||||
irq_proc_reg->rx_lkahd[1]);
|
||||
|
||||
if (dev->ar->mbox_info.gmbox_addr != 0) {
|
||||
/*
|
||||
* If the target supports GMBOX hardware, dump some
|
||||
* additional state.
|
||||
*/
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"GMBOX Host Int status 2: 0x%x\n",
|
||||
irq_proc_reg->host_int_status2);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"GMBOX RX Avail: 0x%x\n",
|
||||
irq_proc_reg->gmbox_rx_avail);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"GMBOX lookahead alias 0: 0x%x\n",
|
||||
irq_proc_reg->rx_gmbox_lkahd_alias[0]);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"GMBOX lookahead alias 1: 0x%x\n",
|
||||
irq_proc_reg->rx_gmbox_lkahd_alias[1]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (irq_enable_reg != NULL) {
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"Int status Enable: 0x%x\n",
|
||||
irq_enable_reg->int_status_en);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, "Counter Int status Enable: 0x%x\n",
|
||||
irq_enable_reg->cntr_int_status_en);
|
||||
}
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, "<------------------------------->\n");
|
||||
}
|
||||
|
||||
static void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist)
|
||||
{
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"--- endpoint: %d svc_id: 0x%X ---\n",
|
||||
ep_dist->endpoint, ep_dist->svc_id);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, " dist_flags : 0x%X\n",
|
||||
ep_dist->dist_flags);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, " cred_norm : %d\n",
|
||||
ep_dist->cred_norm);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, " cred_min : %d\n",
|
||||
ep_dist->cred_min);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, " credits : %d\n",
|
||||
ep_dist->credits);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, " cred_assngd : %d\n",
|
||||
ep_dist->cred_assngd);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, " seek_cred : %d\n",
|
||||
ep_dist->seek_cred);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, " cred_sz : %d\n",
|
||||
ep_dist->cred_sz);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, " cred_per_msg : %d\n",
|
||||
ep_dist->cred_per_msg);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, " cred_to_dist : %d\n",
|
||||
ep_dist->cred_to_dist);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, " txq_depth : %d\n",
|
||||
get_queue_depth(&((struct htc_endpoint *)
|
||||
ep_dist->htc_rsvd)->txq));
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"----------------------------------\n");
|
||||
}
|
||||
|
||||
void dump_cred_dist_stats(struct htc_target *target)
|
||||
{
|
||||
struct htc_endpoint_credit_dist *ep_list;
|
||||
|
||||
if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_TRC))
|
||||
return;
|
||||
|
||||
list_for_each_entry(ep_list, &target->cred_dist_list, list)
|
||||
dump_cred_dist(ep_list);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:%p dist:%p\n",
|
||||
target->cred_dist_cntxt, NULL);
|
||||
ath6kl_dbg(ATH6KL_DBG_TRC, "credit distribution, total : %d, free : %d\n",
|
||||
target->cred_dist_cntxt->total_avail_credits,
|
||||
target->cred_dist_cntxt->cur_free_credits);
|
||||
}
|
||||
|
||||
#endif
|
105
drivers/net/wireless/ath/ath6kl/debug.h
Normal file
105
drivers/net/wireless/ath/ath6kl/debug.h
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
#include "htc_hif.h"
|
||||
|
||||
enum ATH6K_DEBUG_MASK {
|
||||
ATH6KL_DBG_WLAN_CONNECT = BIT(0), /* wlan connect */
|
||||
ATH6KL_DBG_WLAN_SCAN = BIT(1), /* wlan scan */
|
||||
ATH6KL_DBG_WLAN_TX = BIT(2), /* wlan tx */
|
||||
ATH6KL_DBG_WLAN_RX = BIT(3), /* wlan rx */
|
||||
ATH6KL_DBG_BMI = BIT(4), /* bmi tracing */
|
||||
ATH6KL_DBG_HTC_SEND = BIT(5), /* htc send */
|
||||
ATH6KL_DBG_HTC_RECV = BIT(6), /* htc recv */
|
||||
ATH6KL_DBG_IRQ = BIT(7), /* interrupt processing */
|
||||
ATH6KL_DBG_PM = BIT(8), /* power management */
|
||||
ATH6KL_DBG_WLAN_NODE = BIT(9), /* general wlan node tracing */
|
||||
ATH6KL_DBG_WMI = BIT(10), /* wmi tracing */
|
||||
ATH6KL_DBG_TRC = BIT(11), /* generic func tracing */
|
||||
ATH6KL_DBG_SCATTER = BIT(12), /* hif scatter tracing */
|
||||
ATH6KL_DBG_WLAN_CFG = BIT(13), /* cfg80211 i/f file tracing */
|
||||
ATH6KL_DBG_RAW_BYTES = BIT(14), /* dump tx/rx and wmi frames */
|
||||
ATH6KL_DBG_AGGR = BIT(15), /* aggregation */
|
||||
ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */
|
||||
};
|
||||
|
||||
extern unsigned int debug_mask;
|
||||
extern int ath6kl_printk(const char *level, const char *fmt, ...)
|
||||
__attribute__ ((format (printf, 2, 3)));
|
||||
|
||||
#define ath6kl_info(fmt, ...) \
|
||||
ath6kl_printk(KERN_INFO, fmt, ##__VA_ARGS__)
|
||||
#define ath6kl_err(fmt, ...) \
|
||||
ath6kl_printk(KERN_ERR, fmt, ##__VA_ARGS__)
|
||||
#define ath6kl_warn(fmt, ...) \
|
||||
ath6kl_printk(KERN_WARNING, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define AR_DBG_LVL_CHECK(mask) (debug_mask & mask)
|
||||
|
||||
#ifdef CONFIG_ATH6KL_DEBUG
|
||||
#define ath6kl_dbg(mask, fmt, ...) \
|
||||
({ \
|
||||
int rtn; \
|
||||
if (debug_mask & mask) \
|
||||
rtn = ath6kl_printk(KERN_DEBUG, fmt, ##__VA_ARGS__); \
|
||||
else \
|
||||
rtn = 0; \
|
||||
\
|
||||
rtn; \
|
||||
})
|
||||
|
||||
static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask,
|
||||
const char *msg, const void *buf,
|
||||
size_t len)
|
||||
{
|
||||
if (debug_mask & mask) {
|
||||
ath6kl_dbg(mask, "%s\n", msg);
|
||||
print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
void ath6kl_dump_registers(struct ath6kl_device *dev,
|
||||
struct ath6kl_irq_proc_registers *irq_proc_reg,
|
||||
struct ath6kl_irq_enable_reg *irq_en_reg);
|
||||
void dump_cred_dist_stats(struct htc_target *target);
|
||||
#else
|
||||
static inline int ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask,
|
||||
const char *msg, const void *buf,
|
||||
size_t len)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath6kl_dump_registers(struct ath6kl_device *dev,
|
||||
struct ath6kl_irq_proc_registers *irq_proc_reg,
|
||||
struct ath6kl_irq_enable_reg *irq_en_reg)
|
||||
{
|
||||
|
||||
}
|
||||
static inline void dump_cred_dist_stats(struct htc_target *target)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
72
drivers/net/wireless/ath/ath6kl/hif-ops.h
Normal file
72
drivers/net/wireless/ath/ath6kl/hif-ops.h
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2004-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.
|
||||
*/
|
||||
|
||||
#ifndef HIF_OPS_H
|
||||
#define HIF_OPS_H
|
||||
|
||||
#include "hif.h"
|
||||
|
||||
static inline int hif_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf,
|
||||
u32 len, u32 request)
|
||||
{
|
||||
return ar->hif_ops->read_write_sync(ar, addr, buf, len, request);
|
||||
}
|
||||
|
||||
static inline int hif_write_async(struct ath6kl *ar, u32 address, u8 *buffer,
|
||||
u32 length, u32 request,
|
||||
struct htc_packet *packet)
|
||||
{
|
||||
return ar->hif_ops->write_async(ar, address, buffer, length,
|
||||
request, packet);
|
||||
}
|
||||
static inline void ath6kl_hif_irq_enable(struct ath6kl *ar)
|
||||
{
|
||||
return ar->hif_ops->irq_enable(ar);
|
||||
}
|
||||
|
||||
static inline void ath6kl_hif_irq_disable(struct ath6kl *ar)
|
||||
{
|
||||
return ar->hif_ops->irq_disable(ar);
|
||||
}
|
||||
|
||||
static inline struct hif_scatter_req *hif_scatter_req_get(struct ath6kl *ar)
|
||||
{
|
||||
return ar->hif_ops->scatter_req_get(ar);
|
||||
}
|
||||
|
||||
static inline void hif_scatter_req_add(struct ath6kl *ar,
|
||||
struct hif_scatter_req *s_req)
|
||||
{
|
||||
return ar->hif_ops->scatter_req_add(ar, s_req);
|
||||
}
|
||||
|
||||
static inline int ath6kl_hif_enable_scatter(struct ath6kl *ar)
|
||||
{
|
||||
return ar->hif_ops->enable_scatter(ar);
|
||||
}
|
||||
|
||||
static inline int ath6kl_hif_scat_req_rw(struct ath6kl *ar,
|
||||
struct hif_scatter_req *scat_req)
|
||||
{
|
||||
return ar->hif_ops->scat_req_rw(ar, scat_req);
|
||||
}
|
||||
|
||||
static inline void ath6kl_hif_cleanup_scatter(struct ath6kl *ar)
|
||||
{
|
||||
return ar->hif_ops->cleanup_scatter(ar);
|
||||
}
|
||||
|
||||
#endif
|
207
drivers/net/wireless/ath/ath6kl/hif.h
Normal file
207
drivers/net/wireless/ath/ath6kl/hif.h
Normal file
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (c) 2004-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.
|
||||
*/
|
||||
|
||||
#ifndef HIF_H
|
||||
#define HIF_H
|
||||
|
||||
#include "common.h"
|
||||
#include "core.h"
|
||||
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
#define BUS_REQUEST_MAX_NUM 64
|
||||
#define HIF_MBOX_BLOCK_SIZE 128
|
||||
#define HIF_MBOX0_BLOCK_SIZE 1
|
||||
|
||||
#define HIF_DMA_BUFFER_SIZE (32 * 1024)
|
||||
#define CMD53_FIXED_ADDRESS 1
|
||||
#define CMD53_INCR_ADDRESS 2
|
||||
|
||||
#define MAX_SCATTER_REQUESTS 4
|
||||
#define MAX_SCATTER_ENTRIES_PER_REQ 16
|
||||
#define MAX_SCATTER_REQ_TRANSFER_SIZE (32 * 1024)
|
||||
|
||||
#define MANUFACTURER_ID_AR6003_BASE 0x300
|
||||
/* SDIO manufacturer ID and Codes */
|
||||
#define MANUFACTURER_ID_ATH6KL_BASE_MASK 0xFF00
|
||||
#define MANUFACTURER_CODE 0x271 /* Atheros */
|
||||
|
||||
/* Mailbox address in SDIO address space */
|
||||
#define HIF_MBOX_BASE_ADDR 0x800
|
||||
#define HIF_MBOX_WIDTH 0x800
|
||||
|
||||
#define HIF_MBOX_END_ADDR (HTC_MAILBOX_NUM_MAX * HIF_MBOX_WIDTH - 1)
|
||||
|
||||
/* version 1 of the chip has only a 12K extended mbox range */
|
||||
#define HIF_MBOX0_EXT_BASE_ADDR 0x4000
|
||||
#define HIF_MBOX0_EXT_WIDTH (12*1024)
|
||||
|
||||
/* GMBOX addresses */
|
||||
#define HIF_GMBOX_BASE_ADDR 0x7000
|
||||
#define HIF_GMBOX_WIDTH 0x4000
|
||||
|
||||
/* interrupt mode register */
|
||||
#define CCCR_SDIO_IRQ_MODE_REG 0xF0
|
||||
|
||||
/* mode to enable special 4-bit interrupt assertion without clock */
|
||||
#define SDIO_IRQ_MODE_ASYNC_4BIT_IRQ (1 << 0)
|
||||
|
||||
struct bus_request {
|
||||
struct list_head list;
|
||||
|
||||
/* request data */
|
||||
u32 address;
|
||||
|
||||
u8 *buffer;
|
||||
u32 length;
|
||||
u32 request;
|
||||
struct htc_packet *packet;
|
||||
int status;
|
||||
|
||||
/* this is a scatter request */
|
||||
struct hif_scatter_req *scat_req;
|
||||
};
|
||||
|
||||
/* direction of transfer (read/write) */
|
||||
#define HIF_READ 0x00000001
|
||||
#define HIF_WRITE 0x00000002
|
||||
#define HIF_DIR_MASK (HIF_READ | HIF_WRITE)
|
||||
|
||||
/*
|
||||
* emode - This indicates the whether the command is to be executed in a
|
||||
* blocking or non-blocking fashion (HIF_SYNCHRONOUS/
|
||||
* HIF_ASYNCHRONOUS). The read/write data paths in HTC have been
|
||||
* implemented using the asynchronous mode allowing the the bus
|
||||
* driver to indicate the completion of operation through the
|
||||
* registered callback routine. The requirement primarily comes
|
||||
* from the contexts these operations get called from (a driver's
|
||||
* transmit context or the ISR context in case of receive).
|
||||
* Support for both of these modes is essential.
|
||||
*/
|
||||
#define HIF_SYNCHRONOUS 0x00000010
|
||||
#define HIF_ASYNCHRONOUS 0x00000020
|
||||
#define HIF_EMODE_MASK (HIF_SYNCHRONOUS | HIF_ASYNCHRONOUS)
|
||||
|
||||
/*
|
||||
* dmode - An interface may support different kinds of commands based on
|
||||
* the tradeoff between the amount of data it can carry and the
|
||||
* setup time. Byte and Block modes are supported (HIF_BYTE_BASIS/
|
||||
* HIF_BLOCK_BASIS). In case of latter, the data is rounded off
|
||||
* to the nearest block size by padding. The size of the block is
|
||||
* configurable at compile time using the HIF_BLOCK_SIZE and is
|
||||
* negotiated with the target during initialization after the
|
||||
* ATH6KL interrupts are enabled.
|
||||
*/
|
||||
#define HIF_BYTE_BASIS 0x00000040
|
||||
#define HIF_BLOCK_BASIS 0x00000080
|
||||
#define HIF_DMODE_MASK (HIF_BYTE_BASIS | HIF_BLOCK_BASIS)
|
||||
|
||||
/*
|
||||
* amode - This indicates if the address has to be incremented on ATH6KL
|
||||
* after every read/write operation (HIF?FIXED_ADDRESS/
|
||||
* HIF_INCREMENTAL_ADDRESS).
|
||||
*/
|
||||
#define HIF_FIXED_ADDRESS 0x00000100
|
||||
#define HIF_INCREMENTAL_ADDRESS 0x00000200
|
||||
#define HIF_AMODE_MASK (HIF_FIXED_ADDRESS | HIF_INCREMENTAL_ADDRESS)
|
||||
|
||||
#define HIF_WR_ASYNC_BYTE_INC \
|
||||
(HIF_WRITE | HIF_ASYNCHRONOUS | \
|
||||
HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
|
||||
|
||||
#define HIF_WR_ASYNC_BLOCK_INC \
|
||||
(HIF_WRITE | HIF_ASYNCHRONOUS | \
|
||||
HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
|
||||
|
||||
#define HIF_WR_SYNC_BYTE_FIX \
|
||||
(HIF_WRITE | HIF_SYNCHRONOUS | \
|
||||
HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
|
||||
|
||||
#define HIF_WR_SYNC_BYTE_INC \
|
||||
(HIF_WRITE | HIF_SYNCHRONOUS | \
|
||||
HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
|
||||
|
||||
#define HIF_WR_SYNC_BLOCK_INC \
|
||||
(HIF_WRITE | HIF_SYNCHRONOUS | \
|
||||
HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
|
||||
|
||||
#define HIF_RD_SYNC_BYTE_INC \
|
||||
(HIF_READ | HIF_SYNCHRONOUS | \
|
||||
HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
|
||||
|
||||
#define HIF_RD_SYNC_BYTE_FIX \
|
||||
(HIF_READ | HIF_SYNCHRONOUS | \
|
||||
HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
|
||||
|
||||
#define HIF_RD_ASYNC_BLOCK_FIX \
|
||||
(HIF_READ | HIF_ASYNCHRONOUS | \
|
||||
HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS)
|
||||
|
||||
#define HIF_RD_SYNC_BLOCK_FIX \
|
||||
(HIF_READ | HIF_SYNCHRONOUS | \
|
||||
HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS)
|
||||
|
||||
struct hif_scatter_item {
|
||||
u8 *buf;
|
||||
int len;
|
||||
struct htc_packet *packet;
|
||||
};
|
||||
|
||||
struct hif_scatter_req {
|
||||
struct list_head list;
|
||||
/* address for the read/write operation */
|
||||
u32 addr;
|
||||
|
||||
/* request flags */
|
||||
u32 req;
|
||||
|
||||
/* total length of entire transfer */
|
||||
u32 len;
|
||||
|
||||
bool virt_scat;
|
||||
|
||||
void (*complete) (struct htc_target *, struct hif_scatter_req *);
|
||||
int status;
|
||||
int scat_entries;
|
||||
|
||||
struct bus_request *busrequest;
|
||||
struct scatterlist *sgentries;
|
||||
|
||||
/* bounce buffer for upper layers to copy to/from */
|
||||
u8 *virt_dma_buf;
|
||||
|
||||
struct hif_scatter_item scat_list[1];
|
||||
};
|
||||
|
||||
struct ath6kl_hif_ops {
|
||||
int (*read_write_sync)(struct ath6kl *ar, u32 addr, u8 *buf,
|
||||
u32 len, u32 request);
|
||||
int (*write_async)(struct ath6kl *ar, u32 address, u8 *buffer,
|
||||
u32 length, u32 request, struct htc_packet *packet);
|
||||
|
||||
void (*irq_enable)(struct ath6kl *ar);
|
||||
void (*irq_disable)(struct ath6kl *ar);
|
||||
|
||||
struct hif_scatter_req *(*scatter_req_get)(struct ath6kl *ar);
|
||||
void (*scatter_req_add)(struct ath6kl *ar,
|
||||
struct hif_scatter_req *s_req);
|
||||
int (*enable_scatter)(struct ath6kl *ar);
|
||||
int (*scat_req_rw) (struct ath6kl *ar,
|
||||
struct hif_scatter_req *scat_req);
|
||||
void (*cleanup_scatter)(struct ath6kl *ar);
|
||||
};
|
||||
|
||||
#endif
|
2456
drivers/net/wireless/ath/ath6kl/htc.c
Normal file
2456
drivers/net/wireless/ath/ath6kl/htc.c
Normal file
File diff suppressed because it is too large
Load Diff
604
drivers/net/wireless/ath/ath6kl/htc.h
Normal file
604
drivers/net/wireless/ath/ath6kl/htc.h
Normal file
@ -0,0 +1,604 @@
|
||||
/*
|
||||
* Copyright (c) 2004-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.
|
||||
*/
|
||||
|
||||
#ifndef HTC_H
|
||||
#define HTC_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/* frame header flags */
|
||||
|
||||
/* send direction */
|
||||
#define HTC_FLAGS_NEED_CREDIT_UPDATE (1 << 0)
|
||||
#define HTC_FLAGS_SEND_BUNDLE (1 << 1)
|
||||
|
||||
/* receive direction */
|
||||
#define HTC_FLG_RX_UNUSED (1 << 0)
|
||||
#define HTC_FLG_RX_TRAILER (1 << 1)
|
||||
/* Bundle count maske and shift */
|
||||
#define HTC_FLG_RX_BNDL_CNT (0xF0)
|
||||
#define HTC_FLG_RX_BNDL_CNT_S 4
|
||||
|
||||
#define HTC_HDR_LENGTH (sizeof(struct htc_frame_hdr))
|
||||
#define HTC_MAX_PAYLOAD_LENGTH (4096 - sizeof(struct htc_frame_hdr))
|
||||
|
||||
/* HTC control message IDs */
|
||||
|
||||
#define HTC_MSG_READY_ID 1
|
||||
#define HTC_MSG_CONN_SVC_ID 2
|
||||
#define HTC_MSG_CONN_SVC_RESP_ID 3
|
||||
#define HTC_MSG_SETUP_COMPLETE_ID 4
|
||||
#define HTC_MSG_SETUP_COMPLETE_EX_ID 5
|
||||
|
||||
#define HTC_MAX_CTRL_MSG_LEN 256
|
||||
|
||||
#define HTC_VERSION_2P0 0x00
|
||||
#define HTC_VERSION_2P1 0x01
|
||||
|
||||
#define HTC_SERVICE_META_DATA_MAX_LENGTH 128
|
||||
|
||||
#define HTC_CONN_FLGS_THRESH_LVL_QUAT 0x0
|
||||
#define HTC_CONN_FLGS_THRESH_LVL_HALF 0x1
|
||||
#define HTC_CONN_FLGS_THRESH_LVL_THREE_QUAT 0x2
|
||||
#define HTC_CONN_FLGS_REDUCE_CRED_DRIB 0x4
|
||||
#define HTC_CONN_FLGS_THRESH_MASK 0x3
|
||||
|
||||
/* connect response status codes */
|
||||
#define HTC_SERVICE_SUCCESS 0
|
||||
#define HTC_SERVICE_NOT_FOUND 1
|
||||
#define HTC_SERVICE_FAILED 2
|
||||
|
||||
/* no resources (i.e. no more endpoints) */
|
||||
#define HTC_SERVICE_NO_RESOURCES 3
|
||||
|
||||
/* specific service is not allowing any more endpoints */
|
||||
#define HTC_SERVICE_NO_MORE_EP 4
|
||||
|
||||
/* report record IDs */
|
||||
#define HTC_RECORD_NULL 0
|
||||
#define HTC_RECORD_CREDITS 1
|
||||
#define HTC_RECORD_LOOKAHEAD 2
|
||||
#define HTC_RECORD_LOOKAHEAD_BUNDLE 3
|
||||
|
||||
#define HTC_SETUP_COMP_FLG_RX_BNDL_EN (1 << 0)
|
||||
|
||||
#define MAKE_SERVICE_ID(group, index) \
|
||||
(int)(((int)group << 8) | (int)(index))
|
||||
|
||||
/* NOTE: service ID of 0x0000 is reserved and should never be used */
|
||||
#define HTC_CTRL_RSVD_SVC MAKE_SERVICE_ID(RSVD_SERVICE_GROUP, 1)
|
||||
#define WMI_CONTROL_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 0)
|
||||
#define WMI_DATA_BE_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 1)
|
||||
#define WMI_DATA_BK_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 2)
|
||||
#define WMI_DATA_VI_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 3)
|
||||
#define WMI_DATA_VO_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 4)
|
||||
#define WMI_MAX_SERVICES 5
|
||||
|
||||
/* reserved and used to flush ALL packets */
|
||||
#define HTC_TX_PACKET_TAG_ALL 0
|
||||
#define HTC_SERVICE_TX_PACKET_TAG 1
|
||||
#define HTC_TX_PACKET_TAG_USER_DEFINED (HTC_SERVICE_TX_PACKET_TAG + 9)
|
||||
|
||||
/* more packets on this endpoint are being fetched */
|
||||
#define HTC_RX_FLAGS_INDICATE_MORE_PKTS (1 << 0)
|
||||
|
||||
/* TODO.. for BMI */
|
||||
#define ENDPOINT1 0
|
||||
/* TODO -remove me, but we have to fix BMI first */
|
||||
#define HTC_MAILBOX_NUM_MAX 4
|
||||
|
||||
/* enable send bundle padding for this endpoint */
|
||||
#define HTC_FLGS_TX_BNDL_PAD_EN (1 << 0)
|
||||
#define HTC_EP_ACTIVE ((u32) (1u << 31))
|
||||
|
||||
/* HTC operational parameters */
|
||||
#define HTC_TARGET_RESPONSE_TIMEOUT 2000 /* in ms */
|
||||
#define HTC_TARGET_DEBUG_INTR_MASK 0x01
|
||||
#define HTC_TARGET_CREDIT_INTR_MASK 0xF0
|
||||
|
||||
#define HTC_HOST_MAX_MSG_PER_BUNDLE 8
|
||||
#define HTC_MIN_HTC_MSGS_TO_BUNDLE 2
|
||||
|
||||
/* packet flags */
|
||||
|
||||
#define HTC_RX_PKT_IGNORE_LOOKAHEAD (1 << 0)
|
||||
#define HTC_RX_PKT_REFRESH_HDR (1 << 1)
|
||||
#define HTC_RX_PKT_PART_OF_BUNDLE (1 << 2)
|
||||
#define HTC_RX_PKT_NO_RECYCLE (1 << 3)
|
||||
|
||||
#define NUM_CONTROL_BUFFERS 8
|
||||
#define NUM_CONTROL_TX_BUFFERS 2
|
||||
#define NUM_CONTROL_RX_BUFFERS (NUM_CONTROL_BUFFERS - NUM_CONTROL_TX_BUFFERS)
|
||||
|
||||
#define HTC_RECV_WAIT_BUFFERS (1 << 0)
|
||||
#define HTC_OP_STATE_STOPPING (1 << 0)
|
||||
|
||||
/*
|
||||
* The frame header length and message formats defined herein were selected
|
||||
* to accommodate optimal alignment for target processing. This reduces
|
||||
* code size and improves performance. Any changes to the header length may
|
||||
* alter the alignment and cause exceptions on the target. When adding to
|
||||
* the messagestructures insure that fields are properly aligned.
|
||||
*/
|
||||
|
||||
/* HTC frame header
|
||||
*
|
||||
* NOTE: do not remove or re-arrange the fields, these are minimally
|
||||
* required to take advantage of 4-byte lookaheads in some hardware
|
||||
* implementations.
|
||||
*/
|
||||
struct htc_frame_hdr {
|
||||
u8 eid;
|
||||
u8 flags;
|
||||
|
||||
/* length of data (including trailer) that follows the header */
|
||||
__le16 payld_len;
|
||||
|
||||
/* end of 4-byte lookahead */
|
||||
|
||||
u8 ctrl[2];
|
||||
} __packed;
|
||||
|
||||
/* HTC ready message */
|
||||
struct htc_ready_msg {
|
||||
__le16 msg_id;
|
||||
__le16 cred_cnt;
|
||||
__le16 cred_sz;
|
||||
u8 max_ep;
|
||||
u8 pad;
|
||||
} __packed;
|
||||
|
||||
/* extended HTC ready message */
|
||||
struct htc_ready_ext_msg {
|
||||
struct htc_ready_msg ver2_0_info;
|
||||
u8 htc_ver;
|
||||
u8 msg_per_htc_bndl;
|
||||
} __packed;
|
||||
|
||||
/* connect service */
|
||||
struct htc_conn_service_msg {
|
||||
__le16 msg_id;
|
||||
__le16 svc_id;
|
||||
__le16 conn_flags;
|
||||
u8 svc_meta_len;
|
||||
u8 pad;
|
||||
} __packed;
|
||||
|
||||
/* connect response */
|
||||
struct htc_conn_service_resp {
|
||||
__le16 msg_id;
|
||||
__le16 svc_id;
|
||||
u8 status;
|
||||
u8 eid;
|
||||
__le16 max_msg_sz;
|
||||
u8 svc_meta_len;
|
||||
u8 pad;
|
||||
} __packed;
|
||||
|
||||
struct htc_setup_comp_msg {
|
||||
__le16 msg_id;
|
||||
} __packed;
|
||||
|
||||
/* extended setup completion message */
|
||||
struct htc_setup_comp_ext_msg {
|
||||
__le16 msg_id;
|
||||
__le32 flags;
|
||||
u8 msg_per_rxbndl;
|
||||
u8 Rsvd[3];
|
||||
} __packed;
|
||||
|
||||
struct htc_record_hdr {
|
||||
u8 rec_id;
|
||||
u8 len;
|
||||
} __packed;
|
||||
|
||||
struct htc_credit_report {
|
||||
u8 eid;
|
||||
u8 credits;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* NOTE: The lk_ahd array is guarded by a pre_valid
|
||||
* and Post Valid guard bytes. The pre_valid bytes must
|
||||
* equal the inverse of the post_valid byte.
|
||||
*/
|
||||
struct htc_lookahead_report {
|
||||
u8 pre_valid;
|
||||
u8 lk_ahd[4];
|
||||
u8 post_valid;
|
||||
} __packed;
|
||||
|
||||
struct htc_bundle_lkahd_rpt {
|
||||
u8 lk_ahd[4];
|
||||
} __packed;
|
||||
|
||||
/* Current service IDs */
|
||||
|
||||
enum htc_service_grp_ids {
|
||||
RSVD_SERVICE_GROUP = 0,
|
||||
WMI_SERVICE_GROUP = 1,
|
||||
|
||||
HTC_TEST_GROUP = 254,
|
||||
HTC_SERVICE_GROUP_LAST = 255
|
||||
};
|
||||
|
||||
/* ------ endpoint IDS ------ */
|
||||
|
||||
enum htc_endpoint_id {
|
||||
ENDPOINT_UNUSED = -1,
|
||||
ENDPOINT_0 = 0,
|
||||
ENDPOINT_1 = 1,
|
||||
ENDPOINT_2 = 2,
|
||||
ENDPOINT_3,
|
||||
ENDPOINT_4,
|
||||
ENDPOINT_5,
|
||||
ENDPOINT_6,
|
||||
ENDPOINT_7,
|
||||
ENDPOINT_8,
|
||||
ENDPOINT_MAX,
|
||||
};
|
||||
|
||||
struct htc_tx_packet_info {
|
||||
u16 tag;
|
||||
int cred_used;
|
||||
u8 flags;
|
||||
int seqno;
|
||||
};
|
||||
|
||||
struct htc_rx_packet_info {
|
||||
u32 exp_hdr;
|
||||
u32 rx_flags;
|
||||
u32 indicat_flags;
|
||||
};
|
||||
|
||||
struct htc_target;
|
||||
|
||||
/* wrapper around endpoint-specific packets */
|
||||
struct htc_packet {
|
||||
struct list_head list;
|
||||
|
||||
/* caller's per packet specific context */
|
||||
void *pkt_cntxt;
|
||||
|
||||
/*
|
||||
* the true buffer start , the caller can store the real
|
||||
* buffer start here. In receive callbacks, the HTC layer
|
||||
* sets buf to the start of the payload past the header.
|
||||
* This field allows the caller to reset buf when it recycles
|
||||
* receive packets back to HTC.
|
||||
*/
|
||||
u8 *buf_start;
|
||||
|
||||
/*
|
||||
* Pointer to the start of the buffer. In the transmit
|
||||
* direction this points to the start of the payload. In the
|
||||
* receive direction, however, the buffer when queued up
|
||||
* points to the start of the HTC header but when returned
|
||||
* to the caller points to the start of the payload
|
||||
*/
|
||||
u8 *buf;
|
||||
u32 buf_len;
|
||||
|
||||
/* actual length of payload */
|
||||
u32 act_len;
|
||||
|
||||
/* endpoint that this packet was sent/recv'd from */
|
||||
enum htc_endpoint_id endpoint;
|
||||
|
||||
/* completion status */
|
||||
|
||||
int status;
|
||||
union {
|
||||
struct htc_tx_packet_info tx;
|
||||
struct htc_rx_packet_info rx;
|
||||
} info;
|
||||
|
||||
void (*completion) (struct htc_target *, struct htc_packet *);
|
||||
struct htc_target *context;
|
||||
};
|
||||
|
||||
enum htc_send_full_action {
|
||||
HTC_SEND_FULL_KEEP = 0,
|
||||
HTC_SEND_FULL_DROP = 1,
|
||||
};
|
||||
|
||||
struct htc_ep_callbacks {
|
||||
void (*rx) (struct htc_target *, struct htc_packet *);
|
||||
void (*rx_refill) (struct htc_target *, enum htc_endpoint_id endpoint);
|
||||
enum htc_send_full_action (*tx_full) (struct htc_target *,
|
||||
struct htc_packet *);
|
||||
struct htc_packet *(*rx_allocthresh) (struct htc_target *,
|
||||
enum htc_endpoint_id, int);
|
||||
int rx_alloc_thresh;
|
||||
int rx_refill_thresh;
|
||||
};
|
||||
|
||||
/* service connection information */
|
||||
struct htc_service_connect_req {
|
||||
u16 svc_id;
|
||||
u16 conn_flags;
|
||||
struct htc_ep_callbacks ep_cb;
|
||||
int max_txq_depth;
|
||||
u32 flags;
|
||||
unsigned int max_rxmsg_sz;
|
||||
};
|
||||
|
||||
/* service connection response information */
|
||||
struct htc_service_connect_resp {
|
||||
u8 buf_len;
|
||||
u8 act_len;
|
||||
enum htc_endpoint_id endpoint;
|
||||
unsigned int len_max;
|
||||
u8 resp_code;
|
||||
};
|
||||
|
||||
/* endpoint distributionstructure */
|
||||
struct htc_endpoint_credit_dist {
|
||||
struct list_head list;
|
||||
|
||||
/* Service ID (set by HTC) */
|
||||
u16 svc_id;
|
||||
|
||||
/* endpoint for this distributionstruct (set by HTC) */
|
||||
enum htc_endpoint_id endpoint;
|
||||
|
||||
u32 dist_flags;
|
||||
|
||||
/*
|
||||
* credits for normal operation, anything above this
|
||||
* indicates the endpoint is over-subscribed.
|
||||
*/
|
||||
int cred_norm;
|
||||
|
||||
/* floor for credit distribution */
|
||||
int cred_min;
|
||||
|
||||
int cred_assngd;
|
||||
|
||||
/* current credits available */
|
||||
int credits;
|
||||
|
||||
/*
|
||||
* pending credits to distribute on this endpoint, this
|
||||
* is set by HTC when credit reports arrive. The credit
|
||||
* distribution functions sets this to zero when it distributes
|
||||
* the credits.
|
||||
*/
|
||||
int cred_to_dist;
|
||||
|
||||
/*
|
||||
* the number of credits that the current pending TX packet needs
|
||||
* to transmit. This is set by HTC when endpoint needs credits in
|
||||
* order to transmit.
|
||||
*/
|
||||
int seek_cred;
|
||||
|
||||
/* size in bytes of each credit */
|
||||
int cred_sz;
|
||||
|
||||
/* credits required for a maximum sized messages */
|
||||
int cred_per_msg;
|
||||
|
||||
/* reserved for HTC use */
|
||||
void *htc_rsvd;
|
||||
|
||||
/*
|
||||
* current depth of TX queue , i.e. messages waiting for credits
|
||||
* This field is valid only when HTC_CREDIT_DIST_ACTIVITY_CHANGE
|
||||
* or HTC_CREDIT_DIST_SEND_COMPLETE is indicated on an endpoint
|
||||
* that has non-zero credits to recover.
|
||||
*/
|
||||
int txq_depth;
|
||||
};
|
||||
|
||||
/*
|
||||
* credit distibution code that is passed into the distrbution function,
|
||||
* there are mandatory and optional codes that must be handled
|
||||
*/
|
||||
enum htc_credit_dist_reason {
|
||||
HTC_CREDIT_DIST_SEND_COMPLETE = 0,
|
||||
HTC_CREDIT_DIST_ACTIVITY_CHANGE = 1,
|
||||
HTC_CREDIT_DIST_SEEK_CREDITS,
|
||||
};
|
||||
|
||||
struct htc_credit_state_info {
|
||||
int total_avail_credits;
|
||||
int cur_free_credits;
|
||||
struct list_head lowestpri_ep_dist;
|
||||
};
|
||||
|
||||
/* endpoint statistics */
|
||||
struct htc_endpoint_stats {
|
||||
/*
|
||||
* number of times the host set the credit-low flag in a send
|
||||
* message on this endpoint
|
||||
*/
|
||||
u32 cred_low_indicate;
|
||||
|
||||
u32 tx_issued;
|
||||
u32 tx_pkt_bundled;
|
||||
u32 tx_bundles;
|
||||
u32 tx_dropped;
|
||||
|
||||
/* running count of total credit reports received for this endpoint */
|
||||
u32 tx_cred_rpt;
|
||||
|
||||
/* credit reports received from this endpoint's RX packets */
|
||||
u32 cred_rpt_from_rx;
|
||||
|
||||
/* credit reports received from RX packets of other endpoints */
|
||||
u32 cred_rpt_from_other;
|
||||
|
||||
/* credit reports received from endpoint 0 RX packets */
|
||||
u32 cred_rpt_ep0;
|
||||
|
||||
/* count of credits received via Rx packets on this endpoint */
|
||||
u32 cred_from_rx;
|
||||
|
||||
/* count of credits received via another endpoint */
|
||||
u32 cred_from_other;
|
||||
|
||||
/* count of credits received via another endpoint */
|
||||
u32 cred_from_ep0;
|
||||
|
||||
/* count of consummed credits */
|
||||
u32 cred_cosumd;
|
||||
|
||||
/* count of credits returned */
|
||||
u32 cred_retnd;
|
||||
|
||||
u32 rx_pkts;
|
||||
|
||||
/* count of lookahead records found in Rx msg */
|
||||
u32 rx_lkahds;
|
||||
|
||||
/* count of recv packets received in a bundle */
|
||||
u32 rx_bundl;
|
||||
|
||||
/* count of number of bundled lookaheads */
|
||||
u32 rx_bundle_lkahd;
|
||||
|
||||
/* count of the number of bundle indications from the HTC header */
|
||||
u32 rx_bundle_from_hdr;
|
||||
|
||||
/* the number of times the recv allocation threshold was hit */
|
||||
u32 rx_alloc_thresh_hit;
|
||||
|
||||
/* total number of bytes */
|
||||
u32 rxalloc_thresh_byte;
|
||||
};
|
||||
|
||||
struct htc_endpoint {
|
||||
enum htc_endpoint_id eid;
|
||||
u16 svc_id;
|
||||
struct list_head txq;
|
||||
struct list_head rx_bufq;
|
||||
struct htc_endpoint_credit_dist cred_dist;
|
||||
struct htc_ep_callbacks ep_cb;
|
||||
int max_txq_depth;
|
||||
int len_max;
|
||||
int tx_proc_cnt;
|
||||
int rx_proc_cnt;
|
||||
struct htc_target *target;
|
||||
u8 seqno;
|
||||
u32 conn_flags;
|
||||
struct htc_endpoint_stats ep_st;
|
||||
};
|
||||
|
||||
struct htc_control_buffer {
|
||||
struct htc_packet packet;
|
||||
u8 *buf;
|
||||
};
|
||||
|
||||
struct ath6kl_device;
|
||||
|
||||
/* our HTC target state */
|
||||
struct htc_target {
|
||||
struct htc_endpoint endpoint[ENDPOINT_MAX];
|
||||
struct list_head cred_dist_list;
|
||||
struct list_head free_ctrl_txbuf;
|
||||
struct list_head free_ctrl_rxbuf;
|
||||
struct htc_credit_state_info *cred_dist_cntxt;
|
||||
int tgt_creds;
|
||||
unsigned int tgt_cred_sz;
|
||||
spinlock_t htc_lock;
|
||||
spinlock_t rx_lock;
|
||||
spinlock_t tx_lock;
|
||||
struct ath6kl_device *dev;
|
||||
u32 htc_flags;
|
||||
u32 rx_st_flags;
|
||||
enum htc_endpoint_id ep_waiting;
|
||||
u8 htc_tgt_ver;
|
||||
|
||||
/* max messages per bundle for HTC */
|
||||
int msg_per_bndl_max;
|
||||
|
||||
bool tx_bndl_enable;
|
||||
int rx_bndl_enable;
|
||||
int max_rx_bndl_sz;
|
||||
int max_tx_bndl_sz;
|
||||
|
||||
u32 block_sz;
|
||||
u32 block_mask;
|
||||
|
||||
int max_scat_entries;
|
||||
int max_xfer_szper_scatreq;
|
||||
|
||||
int chk_irq_status_cnt;
|
||||
};
|
||||
|
||||
void *htc_create(struct ath6kl *ar);
|
||||
void htc_set_credit_dist(struct htc_target *target,
|
||||
struct htc_credit_state_info *cred_info,
|
||||
u16 svc_pri_order[], int len);
|
||||
int htc_wait_target(struct htc_target *target);
|
||||
int htc_start(struct htc_target *target);
|
||||
int htc_conn_service(struct htc_target *target,
|
||||
struct htc_service_connect_req *req,
|
||||
struct htc_service_connect_resp *resp);
|
||||
int htc_tx(struct htc_target *target, struct htc_packet *packet);
|
||||
void htc_stop(struct htc_target *target);
|
||||
void htc_cleanup(struct htc_target *target);
|
||||
void htc_flush_txep(struct htc_target *target,
|
||||
enum htc_endpoint_id endpoint, u16 tag);
|
||||
void htc_flush_rx_buf(struct htc_target *target);
|
||||
void htc_indicate_activity_change(struct htc_target *target,
|
||||
enum htc_endpoint_id endpoint, bool active);
|
||||
int htc_get_rxbuf_num(struct htc_target *target, enum htc_endpoint_id endpoint);
|
||||
int htc_add_rxbuf_multiple(struct htc_target *target, struct list_head *pktq);
|
||||
int htc_rxmsg_pending_handler(struct htc_target *target, u32 msg_look_ahead[],
|
||||
int *n_pkts);
|
||||
|
||||
static inline void set_htc_pkt_info(struct htc_packet *packet, void *context,
|
||||
u8 *buf, unsigned int len,
|
||||
enum htc_endpoint_id eid, u16 tag)
|
||||
{
|
||||
packet->pkt_cntxt = context;
|
||||
packet->buf = buf;
|
||||
packet->act_len = len;
|
||||
packet->endpoint = eid;
|
||||
packet->info.tx.tag = tag;
|
||||
}
|
||||
|
||||
static inline void htc_rxpkt_reset(struct htc_packet *packet)
|
||||
{
|
||||
packet->buf = packet->buf_start;
|
||||
packet->act_len = 0;
|
||||
}
|
||||
|
||||
static inline void set_htc_rxpkt_info(struct htc_packet *packet, void *context,
|
||||
u8 *buf, unsigned long len,
|
||||
enum htc_endpoint_id eid)
|
||||
{
|
||||
packet->pkt_cntxt = context;
|
||||
packet->buf = buf;
|
||||
packet->buf_start = buf;
|
||||
packet->buf_len = len;
|
||||
packet->endpoint = eid;
|
||||
}
|
||||
|
||||
static inline int get_queue_depth(struct list_head *queue)
|
||||
{
|
||||
struct list_head *tmp_list;
|
||||
int depth = 0;
|
||||
|
||||
list_for_each(tmp_list, queue)
|
||||
depth++;
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
#endif
|
641
drivers/net/wireless/ath/ath6kl/htc_hif.c
Normal file
641
drivers/net/wireless/ath/ath6kl/htc_hif.c
Normal file
@ -0,0 +1,641 @@
|
||||
/*
|
||||
* 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 "core.h"
|
||||
#include "target.h"
|
||||
#include "hif-ops.h"
|
||||
#include "htc_hif.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define MAILBOX_FOR_BLOCK_SIZE 1
|
||||
|
||||
#define ATH6KL_TIME_QUANTUM 10 /* in ms */
|
||||
|
||||
static int ath6kldev_cp_scat_dma_buf(struct hif_scatter_req *req, bool from_dma)
|
||||
{
|
||||
u8 *buf;
|
||||
int i;
|
||||
|
||||
buf = req->virt_dma_buf;
|
||||
|
||||
for (i = 0; i < req->scat_entries; i++) {
|
||||
|
||||
if (from_dma)
|
||||
memcpy(req->scat_list[i].buf, buf,
|
||||
req->scat_list[i].len);
|
||||
else
|
||||
memcpy(buf, req->scat_list[i].buf,
|
||||
req->scat_list[i].len);
|
||||
|
||||
buf += req->scat_list[i].len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kldev_rw_comp_handler(void *context, int status)
|
||||
{
|
||||
struct htc_packet *packet = context;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
|
||||
"ath6kldev_rw_comp_handler (pkt:0x%p , status: %d\n",
|
||||
packet, status);
|
||||
|
||||
packet->status = status;
|
||||
packet->completion(packet->context, packet);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kldev_proc_dbg_intr(struct ath6kl_device *dev)
|
||||
{
|
||||
u32 dummy;
|
||||
int status;
|
||||
|
||||
ath6kl_err("target debug interrupt\n");
|
||||
|
||||
ath6kl_target_failure(dev->ar);
|
||||
|
||||
/*
|
||||
* read counter to clear the interrupt, the debug error interrupt is
|
||||
* counter 0.
|
||||
*/
|
||||
status = hif_read_write_sync(dev->ar, COUNT_DEC_ADDRESS,
|
||||
(u8 *)&dummy, 4, HIF_RD_SYNC_BYTE_INC);
|
||||
if (status)
|
||||
WARN_ON(1);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* mailbox recv message polling */
|
||||
int ath6kldev_poll_mboxmsg_rx(struct ath6kl_device *dev, u32 *lk_ahd,
|
||||
int timeout)
|
||||
{
|
||||
struct ath6kl_irq_proc_registers *rg;
|
||||
int status = 0, i;
|
||||
u8 htc_mbox = 1 << HTC_MAILBOX;
|
||||
|
||||
for (i = timeout / ATH6KL_TIME_QUANTUM; i > 0; i--) {
|
||||
/* this is the standard HIF way, load the reg table */
|
||||
status = hif_read_write_sync(dev->ar, HOST_INT_STATUS_ADDRESS,
|
||||
(u8 *) &dev->irq_proc_reg,
|
||||
sizeof(dev->irq_proc_reg),
|
||||
HIF_RD_SYNC_BYTE_INC);
|
||||
|
||||
if (status) {
|
||||
ath6kl_err("failed to read reg table\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
/* check for MBOX data and valid lookahead */
|
||||
if (dev->irq_proc_reg.host_int_status & htc_mbox) {
|
||||
if (dev->irq_proc_reg.rx_lkahd_valid &
|
||||
htc_mbox) {
|
||||
/*
|
||||
* Mailbox has a message and the look ahead
|
||||
* is valid.
|
||||
*/
|
||||
rg = &dev->irq_proc_reg;
|
||||
*lk_ahd =
|
||||
le32_to_cpu(rg->rx_lkahd[HTC_MAILBOX]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* delay a little */
|
||||
mdelay(ATH6KL_TIME_QUANTUM);
|
||||
ath6kl_dbg(ATH6KL_DBG_HTC_RECV, "retry mbox poll : %d\n", i);
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
ath6kl_err("timeout waiting for recv message\n");
|
||||
status = -ETIME;
|
||||
/* check if the target asserted */
|
||||
if (dev->irq_proc_reg.counter_int_status &
|
||||
ATH6KL_TARGET_DEBUG_INTR_MASK)
|
||||
/*
|
||||
* Target failure handler will be called in case of
|
||||
* an assert.
|
||||
*/
|
||||
ath6kldev_proc_dbg_intr(dev);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable packet reception (used in case the host runs out of buffers)
|
||||
* using the interrupt enable registers through the host I/F
|
||||
*/
|
||||
int ath6kldev_rx_control(struct ath6kl_device *dev, bool enable_rx)
|
||||
{
|
||||
struct ath6kl_irq_enable_reg regs;
|
||||
int status = 0;
|
||||
|
||||
/* take the lock to protect interrupt enable shadows */
|
||||
spin_lock_bh(&dev->lock);
|
||||
|
||||
if (enable_rx)
|
||||
dev->irq_en_reg.int_status_en |=
|
||||
SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01);
|
||||
else
|
||||
dev->irq_en_reg.int_status_en &=
|
||||
~SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01);
|
||||
|
||||
memcpy(®s, &dev->irq_en_reg, sizeof(regs));
|
||||
|
||||
spin_unlock_bh(&dev->lock);
|
||||
|
||||
status = hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS,
|
||||
®s.int_status_en,
|
||||
sizeof(struct ath6kl_irq_enable_reg),
|
||||
HIF_WR_SYNC_BYTE_INC);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int ath6kldev_submit_scat_req(struct ath6kl_device *dev,
|
||||
struct hif_scatter_req *scat_req, bool read)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if (read) {
|
||||
scat_req->req = HIF_RD_SYNC_BLOCK_FIX;
|
||||
scat_req->addr = dev->ar->mbox_info.htc_addr;
|
||||
} else {
|
||||
scat_req->req = HIF_WR_ASYNC_BLOCK_INC;
|
||||
|
||||
scat_req->addr =
|
||||
(scat_req->len > HIF_MBOX_WIDTH) ?
|
||||
dev->ar->mbox_info.htc_ext_addr :
|
||||
dev->ar->mbox_info.htc_addr;
|
||||
}
|
||||
|
||||
ath6kl_dbg((ATH6KL_DBG_HTC_RECV | ATH6KL_DBG_HTC_SEND),
|
||||
"ath6kldev_submit_scat_req, entries: %d, total len: %d mbox:0x%X (mode: %s : %s)\n",
|
||||
scat_req->scat_entries, scat_req->len,
|
||||
scat_req->addr, !read ? "async" : "sync",
|
||||
(read) ? "rd" : "wr");
|
||||
|
||||
if (!read && scat_req->virt_scat) {
|
||||
status = ath6kldev_cp_scat_dma_buf(scat_req, false);
|
||||
if (status) {
|
||||
scat_req->status = status;
|
||||
scat_req->complete(dev->ar->htc_target, scat_req);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
status = ath6kl_hif_scat_req_rw(dev->ar, scat_req);
|
||||
|
||||
if (read) {
|
||||
/* in sync mode, we can touch the scatter request */
|
||||
scat_req->status = status;
|
||||
if (!status && scat_req->virt_scat)
|
||||
scat_req->status =
|
||||
ath6kldev_cp_scat_dma_buf(scat_req, true);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ath6kldev_proc_counter_intr(struct ath6kl_device *dev)
|
||||
{
|
||||
u8 counter_int_status;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ, "counter interrupt\n");
|
||||
|
||||
counter_int_status = dev->irq_proc_reg.counter_int_status &
|
||||
dev->irq_en_reg.cntr_int_status_en;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ,
|
||||
"valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n",
|
||||
counter_int_status);
|
||||
|
||||
/*
|
||||
* NOTE: other modules like GMBOX may use the counter interrupt for
|
||||
* credit flow control on other counters, we only need to check for
|
||||
* the debug assertion counter interrupt.
|
||||
*/
|
||||
if (counter_int_status & ATH6KL_TARGET_DEBUG_INTR_MASK)
|
||||
return ath6kldev_proc_dbg_intr(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kldev_proc_err_intr(struct ath6kl_device *dev)
|
||||
{
|
||||
int status;
|
||||
u8 error_int_status;
|
||||
u8 reg_buf[4];
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ, "error interrupt\n");
|
||||
|
||||
error_int_status = dev->irq_proc_reg.error_int_status & 0x0F;
|
||||
if (!error_int_status) {
|
||||
WARN_ON(1);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ,
|
||||
"valid interrupt source(s) in ERROR_INT_STATUS: 0x%x\n",
|
||||
error_int_status);
|
||||
|
||||
if (MS(ERROR_INT_STATUS_WAKEUP, error_int_status))
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ, "error : wakeup\n");
|
||||
|
||||
if (MS(ERROR_INT_STATUS_RX_UNDERFLOW, error_int_status))
|
||||
ath6kl_err("rx underflow\n");
|
||||
|
||||
if (MS(ERROR_INT_STATUS_TX_OVERFLOW, error_int_status))
|
||||
ath6kl_err("tx overflow\n");
|
||||
|
||||
/* Clear the interrupt */
|
||||
dev->irq_proc_reg.error_int_status &= ~error_int_status;
|
||||
|
||||
/* set W1C value to clear the interrupt, this hits the register first */
|
||||
reg_buf[0] = error_int_status;
|
||||
reg_buf[1] = 0;
|
||||
reg_buf[2] = 0;
|
||||
reg_buf[3] = 0;
|
||||
|
||||
status = hif_read_write_sync(dev->ar, ERROR_INT_STATUS_ADDRESS,
|
||||
reg_buf, 4, HIF_WR_SYNC_BYTE_FIX);
|
||||
|
||||
if (status)
|
||||
WARN_ON(1);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ath6kldev_proc_cpu_intr(struct ath6kl_device *dev)
|
||||
{
|
||||
int status;
|
||||
u8 cpu_int_status;
|
||||
u8 reg_buf[4];
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ, "cpu interrupt\n");
|
||||
|
||||
cpu_int_status = dev->irq_proc_reg.cpu_int_status &
|
||||
dev->irq_en_reg.cpu_int_status_en;
|
||||
if (!cpu_int_status) {
|
||||
WARN_ON(1);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ,
|
||||
"valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n",
|
||||
cpu_int_status);
|
||||
|
||||
/* Clear the interrupt */
|
||||
dev->irq_proc_reg.cpu_int_status &= ~cpu_int_status;
|
||||
|
||||
/*
|
||||
* Set up the register transfer buffer to hit the register 4 times ,
|
||||
* this is done to make the access 4-byte aligned to mitigate issues
|
||||
* with host bus interconnects that restrict bus transfer lengths to
|
||||
* be a multiple of 4-bytes.
|
||||
*/
|
||||
|
||||
/* set W1C value to clear the interrupt, this hits the register first */
|
||||
reg_buf[0] = cpu_int_status;
|
||||
/* the remaining are set to zero which have no-effect */
|
||||
reg_buf[1] = 0;
|
||||
reg_buf[2] = 0;
|
||||
reg_buf[3] = 0;
|
||||
|
||||
status = hif_read_write_sync(dev->ar, CPU_INT_STATUS_ADDRESS,
|
||||
reg_buf, 4, HIF_WR_SYNC_BYTE_FIX);
|
||||
|
||||
if (status)
|
||||
WARN_ON(1);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* process pending interrupts synchronously */
|
||||
static int proc_pending_irqs(struct ath6kl_device *dev, bool *done)
|
||||
{
|
||||
struct ath6kl_irq_proc_registers *rg;
|
||||
int status = 0;
|
||||
u8 host_int_status = 0;
|
||||
u32 lk_ahd = 0;
|
||||
u8 htc_mbox = 1 << HTC_MAILBOX;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ, "proc_pending_irqs: (dev: 0x%p)\n", dev);
|
||||
|
||||
/*
|
||||
* NOTE: HIF implementation guarantees that the context of this
|
||||
* call allows us to perform SYNCHRONOUS I/O, that is we can block,
|
||||
* sleep or call any API that can block or switch thread/task
|
||||
* contexts. This is a fully schedulable context.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Process pending intr only when int_status_en is clear, it may
|
||||
* result in unnecessary bus transaction otherwise. Target may be
|
||||
* unresponsive at the time.
|
||||
*/
|
||||
if (dev->irq_en_reg.int_status_en) {
|
||||
/*
|
||||
* Read the first 28 bytes of the HTC register table. This
|
||||
* will yield us the value of different int status
|
||||
* registers and the lookahead registers.
|
||||
*
|
||||
* length = sizeof(int_status) + sizeof(cpu_int_status)
|
||||
* + sizeof(error_int_status) +
|
||||
* sizeof(counter_int_status) +
|
||||
* sizeof(mbox_frame) + sizeof(rx_lkahd_valid)
|
||||
* + sizeof(hole) + sizeof(rx_lkahd) +
|
||||
* sizeof(int_status_en) +
|
||||
* sizeof(cpu_int_status_en) +
|
||||
* sizeof(err_int_status_en) +
|
||||
* sizeof(cntr_int_status_en);
|
||||
*/
|
||||
status = hif_read_write_sync(dev->ar, HOST_INT_STATUS_ADDRESS,
|
||||
(u8 *) &dev->irq_proc_reg,
|
||||
sizeof(dev->irq_proc_reg),
|
||||
HIF_RD_SYNC_BYTE_INC);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
if (AR_DBG_LVL_CHECK(ATH6KL_DBG_IRQ))
|
||||
ath6kl_dump_registers(dev, &dev->irq_proc_reg,
|
||||
&dev->irq_en_reg);
|
||||
|
||||
/* Update only those registers that are enabled */
|
||||
host_int_status = dev->irq_proc_reg.host_int_status &
|
||||
dev->irq_en_reg.int_status_en;
|
||||
|
||||
/* Look at mbox status */
|
||||
if (host_int_status & htc_mbox) {
|
||||
/*
|
||||
* Mask out pending mbox value, we use "lookAhead as
|
||||
* the real flag for mbox processing.
|
||||
*/
|
||||
host_int_status &= ~htc_mbox;
|
||||
if (dev->irq_proc_reg.rx_lkahd_valid &
|
||||
htc_mbox) {
|
||||
rg = &dev->irq_proc_reg;
|
||||
lk_ahd = le32_to_cpu(rg->rx_lkahd[HTC_MAILBOX]);
|
||||
if (!lk_ahd)
|
||||
ath6kl_err("lookAhead is zero!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!host_int_status && !lk_ahd) {
|
||||
*done = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (lk_ahd) {
|
||||
int fetched = 0;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ,
|
||||
"pending mailbox msg, lk_ahd: 0x%X\n", lk_ahd);
|
||||
/*
|
||||
* Mailbox Interrupt, the HTC layer may issue async
|
||||
* requests to empty the mailbox. When emptying the recv
|
||||
* mailbox we use the async handler above called from the
|
||||
* completion routine of the callers read request. This can
|
||||
* improve performance by reducing context switching when
|
||||
* we rapidly pull packets.
|
||||
*/
|
||||
status = htc_rxmsg_pending_handler(dev->htc_cnxt,
|
||||
&lk_ahd, &fetched);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
if (!fetched)
|
||||
/*
|
||||
* HTC could not pull any messages out due to lack
|
||||
* of resources.
|
||||
*/
|
||||
dev->htc_cnxt->chk_irq_status_cnt = 0;
|
||||
}
|
||||
|
||||
/* now handle the rest of them */
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ,
|
||||
"valid interrupt source(s) for other interrupts: 0x%x\n",
|
||||
host_int_status);
|
||||
|
||||
if (MS(HOST_INT_STATUS_CPU, host_int_status)) {
|
||||
/* CPU Interrupt */
|
||||
status = ath6kldev_proc_cpu_intr(dev);
|
||||
if (status)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (MS(HOST_INT_STATUS_ERROR, host_int_status)) {
|
||||
/* Error Interrupt */
|
||||
status = ath6kldev_proc_err_intr(dev);
|
||||
if (status)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (MS(HOST_INT_STATUS_COUNTER, host_int_status))
|
||||
/* Counter Interrupt */
|
||||
status = ath6kldev_proc_counter_intr(dev);
|
||||
|
||||
out:
|
||||
/*
|
||||
* An optimization to bypass reading the IRQ status registers
|
||||
* unecessarily which can re-wake the target, if upper layers
|
||||
* determine that we are in a low-throughput mode, we can rely on
|
||||
* taking another interrupt rather than re-checking the status
|
||||
* registers which can re-wake the target.
|
||||
*
|
||||
* NOTE : for host interfaces that makes use of detecting pending
|
||||
* mbox messages at hif can not use this optimization due to
|
||||
* possible side effects, SPI requires the host to drain all
|
||||
* messages from the mailbox before exiting the ISR routine.
|
||||
*/
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ,
|
||||
"bypassing irq status re-check, forcing done\n");
|
||||
|
||||
if (!dev->htc_cnxt->chk_irq_status_cnt)
|
||||
*done = true;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ,
|
||||
"proc_pending_irqs: (done:%d, status=%d\n", *done, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* interrupt handler, kicks off all interrupt processing */
|
||||
int ath6kldev_intr_bh_handler(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_device *dev = ar->htc_target->dev;
|
||||
int status = 0;
|
||||
bool done = false;
|
||||
|
||||
/*
|
||||
* Reset counter used to flag a re-scan of IRQ status registers on
|
||||
* the target.
|
||||
*/
|
||||
dev->htc_cnxt->chk_irq_status_cnt = 0;
|
||||
|
||||
/*
|
||||
* IRQ processing is synchronous, interrupt status registers can be
|
||||
* re-read.
|
||||
*/
|
||||
while (!done) {
|
||||
status = proc_pending_irqs(dev, &done);
|
||||
if (status)
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ath6kldev_enable_intrs(struct ath6kl_device *dev)
|
||||
{
|
||||
struct ath6kl_irq_enable_reg regs;
|
||||
int status;
|
||||
|
||||
spin_lock_bh(&dev->lock);
|
||||
|
||||
/* Enable all but ATH6KL CPU interrupts */
|
||||
dev->irq_en_reg.int_status_en =
|
||||
SM(INT_STATUS_ENABLE_ERROR, 0x01) |
|
||||
SM(INT_STATUS_ENABLE_CPU, 0x01) |
|
||||
SM(INT_STATUS_ENABLE_COUNTER, 0x01);
|
||||
|
||||
/*
|
||||
* NOTE: There are some cases where HIF can do detection of
|
||||
* pending mbox messages which is disabled now.
|
||||
*/
|
||||
dev->irq_en_reg.int_status_en |= SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01);
|
||||
|
||||
/* Set up the CPU Interrupt status Register */
|
||||
dev->irq_en_reg.cpu_int_status_en = 0;
|
||||
|
||||
/* Set up the Error Interrupt status Register */
|
||||
dev->irq_en_reg.err_int_status_en =
|
||||
SM(ERROR_STATUS_ENABLE_RX_UNDERFLOW, 0x01) |
|
||||
SM(ERROR_STATUS_ENABLE_TX_OVERFLOW, 0x1);
|
||||
|
||||
/*
|
||||
* Enable Counter interrupt status register to get fatal errors for
|
||||
* debugging.
|
||||
*/
|
||||
dev->irq_en_reg.cntr_int_status_en = SM(COUNTER_INT_STATUS_ENABLE_BIT,
|
||||
ATH6KL_TARGET_DEBUG_INTR_MASK);
|
||||
memcpy(®s, &dev->irq_en_reg, sizeof(regs));
|
||||
|
||||
spin_unlock_bh(&dev->lock);
|
||||
|
||||
status = hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS,
|
||||
®s.int_status_en, sizeof(regs),
|
||||
HIF_WR_SYNC_BYTE_INC);
|
||||
|
||||
if (status)
|
||||
ath6kl_err("failed to update interrupt ctl reg err: %d\n",
|
||||
status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int ath6kldev_disable_intrs(struct ath6kl_device *dev)
|
||||
{
|
||||
struct ath6kl_irq_enable_reg regs;
|
||||
|
||||
spin_lock_bh(&dev->lock);
|
||||
/* Disable all interrupts */
|
||||
dev->irq_en_reg.int_status_en = 0;
|
||||
dev->irq_en_reg.cpu_int_status_en = 0;
|
||||
dev->irq_en_reg.err_int_status_en = 0;
|
||||
dev->irq_en_reg.cntr_int_status_en = 0;
|
||||
memcpy(®s, &dev->irq_en_reg, sizeof(regs));
|
||||
spin_unlock_bh(&dev->lock);
|
||||
|
||||
return hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS,
|
||||
®s.int_status_en, sizeof(regs),
|
||||
HIF_WR_SYNC_BYTE_INC);
|
||||
}
|
||||
|
||||
/* enable device interrupts */
|
||||
int ath6kldev_unmask_intrs(struct ath6kl_device *dev)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
/*
|
||||
* Make sure interrupt are disabled before unmasking at the HIF
|
||||
* layer. The rationale here is that between device insertion
|
||||
* (where we clear the interrupts the first time) and when HTC
|
||||
* is finally ready to handle interrupts, other software can perform
|
||||
* target "soft" resets. The ATH6KL interrupt enables reset back to an
|
||||
* "enabled" state when this happens.
|
||||
*/
|
||||
ath6kldev_disable_intrs(dev);
|
||||
|
||||
/* unmask the host controller interrupts */
|
||||
ath6kl_hif_irq_enable(dev->ar);
|
||||
status = ath6kldev_enable_intrs(dev);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* disable all device interrupts */
|
||||
int ath6kldev_mask_intrs(struct ath6kl_device *dev)
|
||||
{
|
||||
/*
|
||||
* Mask the interrupt at the HIF layer to avoid any stray interrupt
|
||||
* taken while we zero out our shadow registers in
|
||||
* ath6kldev_disable_intrs().
|
||||
*/
|
||||
ath6kl_hif_irq_disable(dev->ar);
|
||||
|
||||
return ath6kldev_disable_intrs(dev);
|
||||
}
|
||||
|
||||
int ath6kldev_setup(struct ath6kl_device *dev)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
spin_lock_init(&dev->lock);
|
||||
|
||||
/*
|
||||
* NOTE: we actually get the block size of a mailbox other than 0,
|
||||
* for SDIO the block size on mailbox 0 is artificially set to 1.
|
||||
* So we use the block size that is set for the other 3 mailboxes.
|
||||
*/
|
||||
dev->htc_cnxt->block_sz = dev->ar->mbox_info.block_size;
|
||||
|
||||
/* must be a power of 2 */
|
||||
if ((dev->htc_cnxt->block_sz & (dev->htc_cnxt->block_sz - 1)) != 0) {
|
||||
WARN_ON(1);
|
||||
goto fail_setup;
|
||||
}
|
||||
|
||||
/* assemble mask, used for padding to a block */
|
||||
dev->htc_cnxt->block_mask = dev->htc_cnxt->block_sz - 1;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_TRC, "block size: %d, mbox addr:0x%X\n",
|
||||
dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_TRC,
|
||||
"hif interrupt processing is sync only\n");
|
||||
|
||||
status = ath6kldev_disable_intrs(dev);
|
||||
|
||||
fail_setup:
|
||||
return status;
|
||||
|
||||
}
|
92
drivers/net/wireless/ath/ath6kl/htc_hif.h
Normal file
92
drivers/net/wireless/ath/ath6kl/htc_hif.h
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef HTC_HIF_H
|
||||
#define HTC_HIF_H
|
||||
|
||||
#include "htc.h"
|
||||
#include "hif.h"
|
||||
|
||||
#define ATH6KL_MAILBOXES 4
|
||||
|
||||
/* HTC runs over mailbox 0 */
|
||||
#define HTC_MAILBOX 0
|
||||
|
||||
#define ATH6KL_TARGET_DEBUG_INTR_MASK 0x01
|
||||
|
||||
#define OTHER_INTS_ENABLED (INT_STATUS_ENABLE_ERROR_MASK | \
|
||||
INT_STATUS_ENABLE_CPU_MASK | \
|
||||
INT_STATUS_ENABLE_COUNTER_MASK)
|
||||
|
||||
#define ATH6KL_REG_IO_BUFFER_SIZE 32
|
||||
#define ATH6KL_MAX_REG_IO_BUFFERS 8
|
||||
#define ATH6KL_SCATTER_ENTRIES_PER_REQ 16
|
||||
#define ATH6KL_MAX_TRANSFER_SIZE_PER_SCATTER (16 * 1024)
|
||||
#define ATH6KL_SCATTER_REQS 4
|
||||
|
||||
#ifndef A_CACHE_LINE_PAD
|
||||
#define A_CACHE_LINE_PAD 128
|
||||
#endif
|
||||
#define ATH6KL_MIN_SCATTER_ENTRIES_PER_REQ 2
|
||||
#define ATH6KL_MIN_TRANSFER_SIZE_PER_SCATTER (4 * 1024)
|
||||
|
||||
struct ath6kl_irq_proc_registers {
|
||||
u8 host_int_status;
|
||||
u8 cpu_int_status;
|
||||
u8 error_int_status;
|
||||
u8 counter_int_status;
|
||||
u8 mbox_frame;
|
||||
u8 rx_lkahd_valid;
|
||||
u8 host_int_status2;
|
||||
u8 gmbox_rx_avail;
|
||||
__le32 rx_lkahd[2];
|
||||
__le32 rx_gmbox_lkahd_alias[2];
|
||||
} __packed;
|
||||
|
||||
struct ath6kl_irq_enable_reg {
|
||||
u8 int_status_en;
|
||||
u8 cpu_int_status_en;
|
||||
u8 err_int_status_en;
|
||||
u8 cntr_int_status_en;
|
||||
} __packed;
|
||||
|
||||
struct ath6kl_device {
|
||||
spinlock_t lock;
|
||||
u8 pad1[A_CACHE_LINE_PAD];
|
||||
struct ath6kl_irq_proc_registers irq_proc_reg;
|
||||
u8 pad2[A_CACHE_LINE_PAD];
|
||||
struct ath6kl_irq_enable_reg irq_en_reg;
|
||||
u8 pad3[A_CACHE_LINE_PAD];
|
||||
struct htc_target *htc_cnxt;
|
||||
struct ath6kl *ar;
|
||||
};
|
||||
|
||||
int ath6kldev_setup(struct ath6kl_device *dev);
|
||||
int ath6kldev_unmask_intrs(struct ath6kl_device *dev);
|
||||
int ath6kldev_mask_intrs(struct ath6kl_device *dev);
|
||||
int ath6kldev_poll_mboxmsg_rx(struct ath6kl_device *dev,
|
||||
u32 *lk_ahd, int timeout);
|
||||
int ath6kldev_rx_control(struct ath6kl_device *dev, bool enable_rx);
|
||||
int ath6kldev_disable_intrs(struct ath6kl_device *dev);
|
||||
|
||||
int ath6kldev_rw_comp_handler(void *context, int status);
|
||||
int ath6kldev_intr_bh_handler(struct ath6kl *ar);
|
||||
|
||||
/* Scatter Function and Definitions */
|
||||
int ath6kldev_submit_scat_req(struct ath6kl_device *dev,
|
||||
struct hif_scatter_req *scat_req, bool read);
|
||||
|
||||
#endif /*ATH6KL_H_ */
|
1303
drivers/net/wireless/ath/ath6kl/init.c
Normal file
1303
drivers/net/wireless/ath/ath6kl/init.c
Normal file
File diff suppressed because it is too large
Load Diff
1337
drivers/net/wireless/ath/ath6kl/main.c
Normal file
1337
drivers/net/wireless/ath/ath6kl/main.c
Normal file
File diff suppressed because it is too large
Load Diff
234
drivers/net/wireless/ath/ath6kl/node.c
Normal file
234
drivers/net/wireless/ath/ath6kl/node.c
Normal file
@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (c) 2004-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 "htc.h"
|
||||
#include "wmi.h"
|
||||
#include "debug.h"
|
||||
|
||||
struct bss *wlan_node_alloc(int wh_size)
|
||||
{
|
||||
struct bss *ni;
|
||||
|
||||
ni = kzalloc(sizeof(struct bss), GFP_ATOMIC);
|
||||
|
||||
if ((ni != NULL) && wh_size) {
|
||||
ni->ni_buf = kmalloc(wh_size, GFP_ATOMIC);
|
||||
if (ni->ni_buf == NULL) {
|
||||
kfree(ni);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ni;
|
||||
}
|
||||
|
||||
void wlan_node_free(struct bss *ni)
|
||||
{
|
||||
kfree(ni->ni_buf);
|
||||
kfree(ni);
|
||||
}
|
||||
|
||||
void wlan_setup_node(struct ath6kl_node_table *nt, struct bss *ni,
|
||||
const u8 *mac_addr)
|
||||
{
|
||||
int hash;
|
||||
|
||||
memcpy(ni->ni_macaddr, mac_addr, ETH_ALEN);
|
||||
hash = ATH6KL_NODE_HASH(mac_addr);
|
||||
ni->ni_refcnt = 1;
|
||||
|
||||
ni->ni_tstamp = jiffies_to_msecs(jiffies);
|
||||
ni->ni_actcnt = WLAN_NODE_INACT_CNT;
|
||||
|
||||
spin_lock_bh(&nt->nt_nodelock);
|
||||
|
||||
/* insert at the end of the node list */
|
||||
ni->ni_list_next = NULL;
|
||||
ni->ni_list_prev = nt->nt_node_last;
|
||||
if (nt->nt_node_last != NULL)
|
||||
nt->nt_node_last->ni_list_next = ni;
|
||||
|
||||
nt->nt_node_last = ni;
|
||||
if (nt->nt_node_first == NULL)
|
||||
nt->nt_node_first = ni;
|
||||
|
||||
/* insert into the hash list */
|
||||
ni->ni_hash_next = nt->nt_hash[hash];
|
||||
if (ni->ni_hash_next != NULL)
|
||||
nt->nt_hash[hash]->ni_hash_prev = ni;
|
||||
|
||||
ni->ni_hash_prev = NULL;
|
||||
nt->nt_hash[hash] = ni;
|
||||
|
||||
spin_unlock_bh(&nt->nt_nodelock);
|
||||
}
|
||||
|
||||
struct bss *wlan_find_node(struct ath6kl_node_table *nt,
|
||||
const u8 *mac_addr)
|
||||
{
|
||||
struct bss *ni, *found_ni = NULL;
|
||||
int hash;
|
||||
|
||||
spin_lock_bh(&nt->nt_nodelock);
|
||||
|
||||
hash = ATH6KL_NODE_HASH(mac_addr);
|
||||
for (ni = nt->nt_hash[hash]; ni; ni = ni->ni_hash_next) {
|
||||
if (memcmp(ni->ni_macaddr, mac_addr, ETH_ALEN) == 0) {
|
||||
ni->ni_refcnt++;
|
||||
found_ni = ni;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_bh(&nt->nt_nodelock);
|
||||
|
||||
return found_ni;
|
||||
}
|
||||
|
||||
void wlan_node_reclaim(struct ath6kl_node_table *nt, struct bss *ni)
|
||||
{
|
||||
int hash;
|
||||
|
||||
spin_lock_bh(&nt->nt_nodelock);
|
||||
|
||||
if (ni->ni_list_prev == NULL)
|
||||
/* fix list head */
|
||||
nt->nt_node_first = ni->ni_list_next;
|
||||
else
|
||||
ni->ni_list_prev->ni_list_next = ni->ni_list_next;
|
||||
|
||||
if (ni->ni_list_next == NULL)
|
||||
/* fix list tail */
|
||||
nt->nt_node_last = ni->ni_list_prev;
|
||||
else
|
||||
ni->ni_list_next->ni_list_prev = ni->ni_list_prev;
|
||||
|
||||
if (ni->ni_hash_prev == NULL) {
|
||||
/* first in list so fix the list head */
|
||||
hash = ATH6KL_NODE_HASH(ni->ni_macaddr);
|
||||
nt->nt_hash[hash] = ni->ni_hash_next;
|
||||
} else {
|
||||
ni->ni_hash_prev->ni_hash_next = ni->ni_hash_next;
|
||||
}
|
||||
|
||||
if (ni->ni_hash_next != NULL)
|
||||
ni->ni_hash_next->ni_hash_prev = ni->ni_hash_prev;
|
||||
|
||||
wlan_node_free(ni);
|
||||
|
||||
spin_unlock_bh(&nt->nt_nodelock);
|
||||
}
|
||||
|
||||
static void wlan_node_dec_free(struct bss *ni)
|
||||
{
|
||||
if ((ni->ni_refcnt--) == 1)
|
||||
wlan_node_free(ni);
|
||||
}
|
||||
|
||||
void wlan_free_allnodes(struct ath6kl_node_table *nt)
|
||||
{
|
||||
struct bss *ni;
|
||||
|
||||
while ((ni = nt->nt_node_first) != NULL)
|
||||
wlan_node_reclaim(nt, ni);
|
||||
}
|
||||
|
||||
void wlan_iterate_nodes(struct ath6kl_node_table *nt, void *arg)
|
||||
{
|
||||
struct bss *ni;
|
||||
|
||||
spin_lock_bh(&nt->nt_nodelock);
|
||||
for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) {
|
||||
ni->ni_refcnt++;
|
||||
ath6kl_cfg80211_scan_node(arg, ni);
|
||||
wlan_node_dec_free(ni);
|
||||
}
|
||||
spin_unlock_bh(&nt->nt_nodelock);
|
||||
}
|
||||
|
||||
void wlan_node_table_init(struct ath6kl_node_table *nt)
|
||||
{
|
||||
ath6kl_dbg(ATH6KL_DBG_WLAN_NODE, "node table = 0x%lx\n",
|
||||
(unsigned long)nt);
|
||||
|
||||
memset(nt, 0, sizeof(struct ath6kl_node_table));
|
||||
|
||||
spin_lock_init(&nt->nt_nodelock);
|
||||
|
||||
nt->nt_node_age = WLAN_NODE_INACT_TIMEOUT_MSEC;
|
||||
}
|
||||
|
||||
void wlan_refresh_inactive_nodes(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_node_table *nt = &ar->scan_table;
|
||||
struct bss *bss;
|
||||
u32 now;
|
||||
|
||||
now = jiffies_to_msecs(jiffies);
|
||||
bss = nt->nt_node_first;
|
||||
while (bss != NULL) {
|
||||
/* refresh all nodes except the current bss */
|
||||
if (memcmp(ar->bssid, bss->ni_macaddr, ETH_ALEN) != 0) {
|
||||
if (((now - bss->ni_tstamp) > nt->nt_node_age)
|
||||
|| --bss->ni_actcnt == 0) {
|
||||
wlan_node_reclaim(nt, bss);
|
||||
}
|
||||
}
|
||||
bss = bss->ni_list_next;
|
||||
}
|
||||
}
|
||||
|
||||
void wlan_node_table_cleanup(struct ath6kl_node_table *nt)
|
||||
{
|
||||
wlan_free_allnodes(nt);
|
||||
}
|
||||
|
||||
struct bss *wlan_find_ssid_node(struct ath6kl_node_table *nt, u8 * ssid,
|
||||
u32 ssid_len, bool is_wpa2, bool match_ssid)
|
||||
{
|
||||
struct bss *ni, *found_ni = NULL;
|
||||
u8 *ie_ssid;
|
||||
|
||||
spin_lock_bh(&nt->nt_nodelock);
|
||||
|
||||
for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) {
|
||||
|
||||
ie_ssid = ni->ni_cie.ie_ssid;
|
||||
|
||||
if ((ie_ssid[1] <= IEEE80211_MAX_SSID_LEN) &&
|
||||
(memcmp(ssid, &ie_ssid[2], ssid_len) == 0)) {
|
||||
|
||||
if (match_ssid ||
|
||||
(is_wpa2 && ni->ni_cie.ie_rsn != NULL) ||
|
||||
(!is_wpa2 && ni->ni_cie.ie_wpa != NULL)) {
|
||||
ni->ni_refcnt++;
|
||||
found_ni = ni;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_bh(&nt->nt_nodelock);
|
||||
|
||||
return found_ni;
|
||||
}
|
||||
|
||||
void wlan_node_return(struct ath6kl_node_table *nt, struct bss *ni)
|
||||
{
|
||||
spin_lock_bh(&nt->nt_nodelock);
|
||||
wlan_node_dec_free(ni);
|
||||
spin_unlock_bh(&nt->nt_nodelock);
|
||||
}
|
912
drivers/net/wireless/ath/ath6kl/sdio.c
Normal file
912
drivers/net/wireless/ath/ath6kl/sdio.c
Normal file
@ -0,0 +1,912 @@
|
||||
/*
|
||||
* Copyright (c) 2004-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/mmc/card.h>
|
||||
#include <linux/mmc/mmc.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/sdio_func.h>
|
||||
#include <linux/mmc/sdio_ids.h>
|
||||
#include <linux/mmc/sdio.h>
|
||||
#include <linux/mmc/sd.h>
|
||||
#include "htc_hif.h"
|
||||
#include "hif-ops.h"
|
||||
#include "target.h"
|
||||
#include "debug.h"
|
||||
|
||||
struct ath6kl_sdio {
|
||||
struct sdio_func *func;
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
/* free list */
|
||||
struct list_head bus_req_freeq;
|
||||
|
||||
/* available bus requests */
|
||||
struct bus_request bus_req[BUS_REQUEST_MAX_NUM];
|
||||
|
||||
struct ath6kl *ar;
|
||||
u8 *dma_buffer;
|
||||
|
||||
/* scatter request list head */
|
||||
struct list_head scat_req;
|
||||
|
||||
spinlock_t scat_lock;
|
||||
bool is_disabled;
|
||||
atomic_t irq_handling;
|
||||
const struct sdio_device_id *id;
|
||||
struct work_struct wr_async_work;
|
||||
struct list_head wr_asyncq;
|
||||
spinlock_t wr_async_lock;
|
||||
};
|
||||
|
||||
#define CMD53_ARG_READ 0
|
||||
#define CMD53_ARG_WRITE 1
|
||||
#define CMD53_ARG_BLOCK_BASIS 1
|
||||
#define CMD53_ARG_FIXED_ADDRESS 0
|
||||
#define CMD53_ARG_INCR_ADDRESS 1
|
||||
|
||||
static inline struct ath6kl_sdio *ath6kl_sdio_priv(struct ath6kl *ar)
|
||||
{
|
||||
return ar->hif_priv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Macro to check if DMA buffer is WORD-aligned and DMA-able.
|
||||
* Most host controllers assume the buffer is DMA'able and will
|
||||
* bug-check otherwise (i.e. buffers on the stack). virt_addr_valid
|
||||
* check fails on stack memory.
|
||||
*/
|
||||
static inline bool buf_needs_bounce(u8 *buf)
|
||||
{
|
||||
return ((unsigned long) buf & 0x3) || !virt_addr_valid(buf);
|
||||
}
|
||||
|
||||
static void ath6kl_sdio_set_mbox_info(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_mbox_info *mbox_info = &ar->mbox_info;
|
||||
|
||||
/* EP1 has an extended range */
|
||||
mbox_info->htc_addr = HIF_MBOX_BASE_ADDR;
|
||||
mbox_info->htc_ext_addr = HIF_MBOX0_EXT_BASE_ADDR;
|
||||
mbox_info->htc_ext_sz = HIF_MBOX0_EXT_WIDTH;
|
||||
mbox_info->block_size = HIF_MBOX_BLOCK_SIZE;
|
||||
mbox_info->gmbox_addr = HIF_GMBOX_BASE_ADDR;
|
||||
mbox_info->gmbox_sz = HIF_GMBOX_WIDTH;
|
||||
}
|
||||
|
||||
static inline void ath6kl_sdio_set_cmd53_arg(u32 *arg, u8 rw, u8 func,
|
||||
u8 mode, u8 opcode, u32 addr,
|
||||
u16 blksz)
|
||||
{
|
||||
*arg = (((rw & 1) << 31) |
|
||||
((func & 0x7) << 28) |
|
||||
((mode & 1) << 27) |
|
||||
((opcode & 1) << 26) |
|
||||
((addr & 0x1FFFF) << 9) |
|
||||
(blksz & 0x1FF));
|
||||
}
|
||||
|
||||
static inline void ath6kl_sdio_set_cmd52_arg(u32 *arg, u8 write, u8 raw,
|
||||
unsigned int address,
|
||||
unsigned char val)
|
||||
{
|
||||
const u8 func = 0;
|
||||
|
||||
*arg = ((write & 1) << 31) |
|
||||
((func & 0x7) << 28) |
|
||||
((raw & 1) << 27) |
|
||||
(1 << 26) |
|
||||
((address & 0x1FFFF) << 9) |
|
||||
(1 << 8) |
|
||||
(val & 0xFF);
|
||||
}
|
||||
|
||||
static int ath6kl_sdio_func0_cmd52_wr_byte(struct mmc_card *card,
|
||||
unsigned int address,
|
||||
unsigned char byte)
|
||||
{
|
||||
struct mmc_command io_cmd;
|
||||
|
||||
memset(&io_cmd, 0, sizeof(io_cmd));
|
||||
ath6kl_sdio_set_cmd52_arg(&io_cmd.arg, 1, 0, address, byte);
|
||||
io_cmd.opcode = SD_IO_RW_DIRECT;
|
||||
io_cmd.flags = MMC_RSP_R5 | MMC_CMD_AC;
|
||||
|
||||
return mmc_wait_for_cmd(card->host, &io_cmd, 0);
|
||||
}
|
||||
|
||||
static int ath6kl_sdio_io(struct sdio_func *func, u32 request, u32 addr,
|
||||
u8 *buf, u32 len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (request & HIF_WRITE) {
|
||||
if (addr >= HIF_MBOX_BASE_ADDR &&
|
||||
addr <= HIF_MBOX_END_ADDR)
|
||||
addr += (HIF_MBOX_WIDTH - len);
|
||||
|
||||
if (addr == HIF_MBOX0_EXT_BASE_ADDR)
|
||||
addr += HIF_MBOX0_EXT_WIDTH - len;
|
||||
|
||||
if (request & HIF_FIXED_ADDRESS)
|
||||
ret = sdio_writesb(func, addr, buf, len);
|
||||
else
|
||||
ret = sdio_memcpy_toio(func, addr, buf, len);
|
||||
} else {
|
||||
if (request & HIF_FIXED_ADDRESS)
|
||||
ret = sdio_readsb(func, buf, addr, len);
|
||||
else
|
||||
ret = sdio_memcpy_fromio(func, buf, addr, len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct bus_request *ath6kl_sdio_alloc_busreq(struct ath6kl_sdio *ar_sdio)
|
||||
{
|
||||
struct bus_request *bus_req;
|
||||
unsigned long flag;
|
||||
|
||||
spin_lock_irqsave(&ar_sdio->lock, flag);
|
||||
|
||||
if (list_empty(&ar_sdio->bus_req_freeq)) {
|
||||
spin_unlock_irqrestore(&ar_sdio->lock, flag);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bus_req = list_first_entry(&ar_sdio->bus_req_freeq,
|
||||
struct bus_request, list);
|
||||
list_del(&bus_req->list);
|
||||
|
||||
spin_unlock_irqrestore(&ar_sdio->lock, flag);
|
||||
ath6kl_dbg(ATH6KL_DBG_TRC, "%s: bus request 0x%p\n", __func__, bus_req);
|
||||
|
||||
return bus_req;
|
||||
}
|
||||
|
||||
static void ath6kl_sdio_free_bus_req(struct ath6kl_sdio *ar_sdio,
|
||||
struct bus_request *bus_req)
|
||||
{
|
||||
unsigned long flag;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_TRC, "%s: bus request 0x%p\n", __func__, bus_req);
|
||||
|
||||
spin_lock_irqsave(&ar_sdio->lock, flag);
|
||||
list_add_tail(&bus_req->list, &ar_sdio->bus_req_freeq);
|
||||
spin_unlock_irqrestore(&ar_sdio->lock, flag);
|
||||
}
|
||||
|
||||
static void ath6kl_sdio_setup_scat_data(struct hif_scatter_req *scat_req,
|
||||
struct mmc_data *data)
|
||||
{
|
||||
struct scatterlist *sg;
|
||||
int i;
|
||||
|
||||
data->blksz = HIF_MBOX_BLOCK_SIZE;
|
||||
data->blocks = scat_req->len / HIF_MBOX_BLOCK_SIZE;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_SCATTER,
|
||||
"hif-scatter: (%s) addr: 0x%X, (block len: %d, block count: %d) , (tot:%d,sg:%d)\n",
|
||||
(scat_req->req & HIF_WRITE) ? "WR" : "RD", scat_req->addr,
|
||||
data->blksz, data->blocks, scat_req->len,
|
||||
scat_req->scat_entries);
|
||||
|
||||
data->flags = (scat_req->req & HIF_WRITE) ? MMC_DATA_WRITE :
|
||||
MMC_DATA_READ;
|
||||
|
||||
/* fill SG entries */
|
||||
sg = scat_req->sgentries;
|
||||
sg_init_table(sg, scat_req->scat_entries);
|
||||
|
||||
/* assemble SG list */
|
||||
for (i = 0; i < scat_req->scat_entries; i++, sg++) {
|
||||
if ((unsigned long)scat_req->scat_list[i].buf & 0x3)
|
||||
/*
|
||||
* Some scatter engines can handle unaligned
|
||||
* buffers, print this as informational only.
|
||||
*/
|
||||
ath6kl_dbg(ATH6KL_DBG_SCATTER,
|
||||
"(%s) scatter buffer is unaligned 0x%p\n",
|
||||
scat_req->req & HIF_WRITE ? "WR" : "RD",
|
||||
scat_req->scat_list[i].buf);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_SCATTER, "%d: addr:0x%p, len:%d\n",
|
||||
i, scat_req->scat_list[i].buf,
|
||||
scat_req->scat_list[i].len);
|
||||
|
||||
sg_set_buf(sg, scat_req->scat_list[i].buf,
|
||||
scat_req->scat_list[i].len);
|
||||
}
|
||||
|
||||
/* set scatter-gather table for request */
|
||||
data->sg = scat_req->sgentries;
|
||||
data->sg_len = scat_req->scat_entries;
|
||||
}
|
||||
|
||||
static int ath6kl_sdio_scat_rw(struct ath6kl_sdio *ar_sdio,
|
||||
struct bus_request *req)
|
||||
{
|
||||
struct mmc_request mmc_req;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_data data;
|
||||
struct hif_scatter_req *scat_req;
|
||||
u8 opcode, rw;
|
||||
int status, len;
|
||||
|
||||
scat_req = req->scat_req;
|
||||
|
||||
if (scat_req->virt_scat) {
|
||||
len = scat_req->len;
|
||||
if (scat_req->req & HIF_BLOCK_BASIS)
|
||||
len = round_down(len, HIF_MBOX_BLOCK_SIZE);
|
||||
|
||||
status = ath6kl_sdio_io(ar_sdio->func, scat_req->req,
|
||||
scat_req->addr, scat_req->virt_dma_buf,
|
||||
len);
|
||||
goto scat_complete;
|
||||
}
|
||||
|
||||
memset(&mmc_req, 0, sizeof(struct mmc_request));
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
memset(&data, 0, sizeof(struct mmc_data));
|
||||
|
||||
ath6kl_sdio_setup_scat_data(scat_req, &data);
|
||||
|
||||
opcode = (scat_req->req & HIF_FIXED_ADDRESS) ?
|
||||
CMD53_ARG_FIXED_ADDRESS : CMD53_ARG_INCR_ADDRESS;
|
||||
|
||||
rw = (scat_req->req & HIF_WRITE) ? CMD53_ARG_WRITE : CMD53_ARG_READ;
|
||||
|
||||
/* Fixup the address so that the last byte will fall on MBOX EOM */
|
||||
if (scat_req->req & HIF_WRITE) {
|
||||
if (scat_req->addr == HIF_MBOX_BASE_ADDR)
|
||||
scat_req->addr += HIF_MBOX_WIDTH - scat_req->len;
|
||||
else
|
||||
/* Uses extended address range */
|
||||
scat_req->addr += HIF_MBOX0_EXT_WIDTH - scat_req->len;
|
||||
}
|
||||
|
||||
/* set command argument */
|
||||
ath6kl_sdio_set_cmd53_arg(&cmd.arg, rw, ar_sdio->func->num,
|
||||
CMD53_ARG_BLOCK_BASIS, opcode, scat_req->addr,
|
||||
data.blocks);
|
||||
|
||||
cmd.opcode = SD_IO_RW_EXTENDED;
|
||||
cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
|
||||
|
||||
mmc_req.cmd = &cmd;
|
||||
mmc_req.data = &data;
|
||||
|
||||
mmc_set_data_timeout(&data, ar_sdio->func->card);
|
||||
/* synchronous call to process request */
|
||||
mmc_wait_for_req(ar_sdio->func->card->host, &mmc_req);
|
||||
|
||||
status = cmd.error ? cmd.error : data.error;
|
||||
|
||||
scat_complete:
|
||||
scat_req->status = status;
|
||||
|
||||
if (scat_req->status)
|
||||
ath6kl_err("Scatter write request failed:%d\n",
|
||||
scat_req->status);
|
||||
|
||||
if (scat_req->req & HIF_ASYNCHRONOUS)
|
||||
scat_req->complete(ar_sdio->ar->htc_target, scat_req);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ath6kl_sdio_alloc_prep_scat_req(struct ath6kl_sdio *ar_sdio,
|
||||
int n_scat_entry, int n_scat_req,
|
||||
bool virt_scat)
|
||||
{
|
||||
struct hif_scatter_req *s_req;
|
||||
struct bus_request *bus_req;
|
||||
int i, scat_req_sz, scat_list_sz, sg_sz, buf_sz;
|
||||
u8 *virt_buf;
|
||||
|
||||
scat_list_sz = (n_scat_entry - 1) * sizeof(struct hif_scatter_item);
|
||||
scat_req_sz = sizeof(*s_req) + scat_list_sz;
|
||||
|
||||
if (!virt_scat)
|
||||
sg_sz = sizeof(struct scatterlist) * n_scat_entry;
|
||||
else
|
||||
buf_sz = 2 * L1_CACHE_BYTES +
|
||||
ATH6KL_MAX_TRANSFER_SIZE_PER_SCATTER;
|
||||
|
||||
for (i = 0; i < n_scat_req; i++) {
|
||||
/* allocate the scatter request */
|
||||
s_req = kzalloc(scat_req_sz, GFP_KERNEL);
|
||||
if (!s_req)
|
||||
return -ENOMEM;
|
||||
|
||||
if (virt_scat) {
|
||||
virt_buf = kzalloc(buf_sz, GFP_KERNEL);
|
||||
if (!virt_buf) {
|
||||
kfree(s_req);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
s_req->virt_dma_buf =
|
||||
(u8 *)L1_CACHE_ALIGN((unsigned long)virt_buf);
|
||||
} else {
|
||||
/* allocate sglist */
|
||||
s_req->sgentries = kzalloc(sg_sz, GFP_KERNEL);
|
||||
|
||||
if (!s_req->sgentries) {
|
||||
kfree(s_req);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
/* allocate a bus request for this scatter request */
|
||||
bus_req = ath6kl_sdio_alloc_busreq(ar_sdio);
|
||||
if (!bus_req) {
|
||||
kfree(s_req->sgentries);
|
||||
kfree(s_req->virt_dma_buf);
|
||||
kfree(s_req);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* assign the scatter request to this bus request */
|
||||
bus_req->scat_req = s_req;
|
||||
s_req->busrequest = bus_req;
|
||||
|
||||
s_req->virt_scat = virt_scat;
|
||||
|
||||
/* add it to the scatter pool */
|
||||
hif_scatter_req_add(ar_sdio->ar, s_req);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf,
|
||||
u32 len, u32 request)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
|
||||
u8 *tbuf = NULL;
|
||||
int ret;
|
||||
bool bounced = false;
|
||||
|
||||
if (request & HIF_BLOCK_BASIS)
|
||||
len = round_down(len, HIF_MBOX_BLOCK_SIZE);
|
||||
|
||||
if (buf_needs_bounce(buf)) {
|
||||
if (!ar_sdio->dma_buffer)
|
||||
return -ENOMEM;
|
||||
tbuf = ar_sdio->dma_buffer;
|
||||
memcpy(tbuf, buf, len);
|
||||
bounced = true;
|
||||
} else
|
||||
tbuf = buf;
|
||||
|
||||
sdio_claim_host(ar_sdio->func);
|
||||
ret = ath6kl_sdio_io(ar_sdio->func, request, addr, tbuf, len);
|
||||
if ((request & HIF_READ) && bounced)
|
||||
memcpy(buf, tbuf, len);
|
||||
sdio_release_host(ar_sdio->func);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __ath6kl_sdio_write_async(struct ath6kl_sdio *ar_sdio,
|
||||
struct bus_request *req)
|
||||
{
|
||||
if (req->scat_req)
|
||||
ath6kl_sdio_scat_rw(ar_sdio, req);
|
||||
else {
|
||||
void *context;
|
||||
int status;
|
||||
|
||||
status = ath6kl_sdio_read_write_sync(ar_sdio->ar, req->address,
|
||||
req->buffer, req->length,
|
||||
req->request);
|
||||
context = req->packet;
|
||||
ath6kl_sdio_free_bus_req(ar_sdio, req);
|
||||
ath6kldev_rw_comp_handler(context, status);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath6kl_sdio_write_async_work(struct work_struct *work)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio;
|
||||
unsigned long flags;
|
||||
struct bus_request *req, *tmp_req;
|
||||
|
||||
ar_sdio = container_of(work, struct ath6kl_sdio, wr_async_work);
|
||||
sdio_claim_host(ar_sdio->func);
|
||||
|
||||
spin_lock_irqsave(&ar_sdio->wr_async_lock, flags);
|
||||
list_for_each_entry_safe(req, tmp_req, &ar_sdio->wr_asyncq, list) {
|
||||
list_del(&req->list);
|
||||
spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags);
|
||||
__ath6kl_sdio_write_async(ar_sdio, req);
|
||||
spin_lock_irqsave(&ar_sdio->wr_async_lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags);
|
||||
|
||||
sdio_release_host(ar_sdio->func);
|
||||
}
|
||||
|
||||
static void ath6kl_sdio_irq_handler(struct sdio_func *func)
|
||||
{
|
||||
int status;
|
||||
struct ath6kl_sdio *ar_sdio;
|
||||
|
||||
ar_sdio = sdio_get_drvdata(func);
|
||||
atomic_set(&ar_sdio->irq_handling, 1);
|
||||
|
||||
/*
|
||||
* Release the host during interrups so we can pick it back up when
|
||||
* we process commands.
|
||||
*/
|
||||
sdio_release_host(ar_sdio->func);
|
||||
|
||||
status = ath6kldev_intr_bh_handler(ar_sdio->ar);
|
||||
sdio_claim_host(ar_sdio->func);
|
||||
atomic_set(&ar_sdio->irq_handling, 0);
|
||||
WARN_ON(status && status != -ECANCELED);
|
||||
}
|
||||
|
||||
static int ath6kl_sdio_power_on(struct ath6kl_sdio *ar_sdio)
|
||||
{
|
||||
struct sdio_func *func = ar_sdio->func;
|
||||
int ret = 0;
|
||||
|
||||
if (!ar_sdio->is_disabled)
|
||||
return 0;
|
||||
|
||||
sdio_claim_host(func);
|
||||
|
||||
ret = sdio_enable_func(func);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to enable sdio func: %d)\n", ret);
|
||||
sdio_release_host(func);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sdio_release_host(func);
|
||||
|
||||
/*
|
||||
* Wait for hardware to initialise. It should take a lot less than
|
||||
* 10 ms but let's be conservative here.
|
||||
*/
|
||||
msleep(10);
|
||||
|
||||
ar_sdio->is_disabled = false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath6kl_sdio_power_off(struct ath6kl_sdio *ar_sdio)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (ar_sdio->is_disabled)
|
||||
return 0;
|
||||
|
||||
/* Disable the card */
|
||||
sdio_claim_host(ar_sdio->func);
|
||||
ret = sdio_disable_func(ar_sdio->func);
|
||||
sdio_release_host(ar_sdio->func);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ar_sdio->is_disabled = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath6kl_sdio_write_async(struct ath6kl *ar, u32 address, u8 *buffer,
|
||||
u32 length, u32 request,
|
||||
struct htc_packet *packet)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
|
||||
struct bus_request *bus_req;
|
||||
unsigned long flags;
|
||||
|
||||
bus_req = ath6kl_sdio_alloc_busreq(ar_sdio);
|
||||
|
||||
if (!bus_req)
|
||||
return -ENOMEM;
|
||||
|
||||
bus_req->address = address;
|
||||
bus_req->buffer = buffer;
|
||||
bus_req->length = length;
|
||||
bus_req->request = request;
|
||||
bus_req->packet = packet;
|
||||
|
||||
spin_lock_irqsave(&ar_sdio->wr_async_lock, flags);
|
||||
list_add_tail(&bus_req->list, &ar_sdio->wr_asyncq);
|
||||
spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags);
|
||||
queue_work(ar->ath6kl_wq, &ar_sdio->wr_async_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath6kl_sdio_irq_enable(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
|
||||
int ret;
|
||||
|
||||
sdio_claim_host(ar_sdio->func);
|
||||
|
||||
/* Register the isr */
|
||||
ret = sdio_claim_irq(ar_sdio->func, ath6kl_sdio_irq_handler);
|
||||
if (ret)
|
||||
ath6kl_err("Failed to claim sdio irq: %d\n", ret);
|
||||
|
||||
sdio_release_host(ar_sdio->func);
|
||||
}
|
||||
|
||||
static void ath6kl_sdio_irq_disable(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
|
||||
int ret;
|
||||
|
||||
sdio_claim_host(ar_sdio->func);
|
||||
|
||||
/* Mask our function IRQ */
|
||||
while (atomic_read(&ar_sdio->irq_handling)) {
|
||||
sdio_release_host(ar_sdio->func);
|
||||
schedule_timeout(HZ / 10);
|
||||
sdio_claim_host(ar_sdio->func);
|
||||
}
|
||||
|
||||
ret = sdio_release_irq(ar_sdio->func);
|
||||
if (ret)
|
||||
ath6kl_err("Failed to release sdio irq: %d\n", ret);
|
||||
|
||||
sdio_release_host(ar_sdio->func);
|
||||
}
|
||||
|
||||
static struct hif_scatter_req *ath6kl_sdio_scatter_req_get(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
|
||||
struct hif_scatter_req *node = NULL;
|
||||
unsigned long flag;
|
||||
|
||||
spin_lock_irqsave(&ar_sdio->scat_lock, flag);
|
||||
|
||||
if (!list_empty(&ar_sdio->scat_req)) {
|
||||
node = list_first_entry(&ar_sdio->scat_req,
|
||||
struct hif_scatter_req, list);
|
||||
list_del(&node->list);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ar_sdio->scat_lock, flag);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static void ath6kl_sdio_scatter_req_add(struct ath6kl *ar,
|
||||
struct hif_scatter_req *s_req)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
|
||||
unsigned long flag;
|
||||
|
||||
spin_lock_irqsave(&ar_sdio->scat_lock, flag);
|
||||
|
||||
list_add_tail(&s_req->list, &ar_sdio->scat_req);
|
||||
|
||||
spin_unlock_irqrestore(&ar_sdio->scat_lock, flag);
|
||||
|
||||
}
|
||||
|
||||
/* scatter gather read write request */
|
||||
static int ath6kl_sdio_async_rw_scatter(struct ath6kl *ar,
|
||||
struct hif_scatter_req *scat_req)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
|
||||
u32 request = scat_req->req;
|
||||
int status = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (!scat_req->len)
|
||||
return -EINVAL;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_SCATTER,
|
||||
"hif-scatter: total len: %d scatter entries: %d\n",
|
||||
scat_req->len, scat_req->scat_entries);
|
||||
|
||||
if (request & HIF_SYNCHRONOUS) {
|
||||
sdio_claim_host(ar_sdio->func);
|
||||
status = ath6kl_sdio_scat_rw(ar_sdio, scat_req->busrequest);
|
||||
sdio_release_host(ar_sdio->func);
|
||||
} else {
|
||||
spin_lock_irqsave(&ar_sdio->wr_async_lock, flags);
|
||||
list_add_tail(&scat_req->busrequest->list, &ar_sdio->wr_asyncq);
|
||||
spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags);
|
||||
queue_work(ar->ath6kl_wq, &ar_sdio->wr_async_work);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* clean up scatter support */
|
||||
static void ath6kl_sdio_cleanup_scatter(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
|
||||
struct hif_scatter_req *s_req, *tmp_req;
|
||||
unsigned long flag;
|
||||
|
||||
/* empty the free list */
|
||||
spin_lock_irqsave(&ar_sdio->scat_lock, flag);
|
||||
list_for_each_entry_safe(s_req, tmp_req, &ar_sdio->scat_req, list) {
|
||||
list_del(&s_req->list);
|
||||
spin_unlock_irqrestore(&ar_sdio->scat_lock, flag);
|
||||
|
||||
if (s_req->busrequest)
|
||||
ath6kl_sdio_free_bus_req(ar_sdio, s_req->busrequest);
|
||||
kfree(s_req->virt_dma_buf);
|
||||
kfree(s_req->sgentries);
|
||||
kfree(s_req);
|
||||
|
||||
spin_lock_irqsave(&ar_sdio->scat_lock, flag);
|
||||
}
|
||||
spin_unlock_irqrestore(&ar_sdio->scat_lock, flag);
|
||||
}
|
||||
|
||||
/* setup of HIF scatter resources */
|
||||
static int ath6kl_sdio_enable_scatter(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
|
||||
struct htc_target *target = ar->htc_target;
|
||||
int ret;
|
||||
bool virt_scat = false;
|
||||
|
||||
/* check if host supports scatter and it meets our requirements */
|
||||
if (ar_sdio->func->card->host->max_segs < MAX_SCATTER_ENTRIES_PER_REQ) {
|
||||
ath6kl_err("host only supports scatter of :%d entries, need: %d\n",
|
||||
ar_sdio->func->card->host->max_segs,
|
||||
MAX_SCATTER_ENTRIES_PER_REQ);
|
||||
virt_scat = true;
|
||||
}
|
||||
|
||||
if (!virt_scat) {
|
||||
ret = ath6kl_sdio_alloc_prep_scat_req(ar_sdio,
|
||||
MAX_SCATTER_ENTRIES_PER_REQ,
|
||||
MAX_SCATTER_REQUESTS, virt_scat);
|
||||
|
||||
if (!ret) {
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"hif-scatter enabled: max scatter req : %d entries: %d\n",
|
||||
MAX_SCATTER_REQUESTS,
|
||||
MAX_SCATTER_ENTRIES_PER_REQ);
|
||||
|
||||
target->max_scat_entries = MAX_SCATTER_ENTRIES_PER_REQ;
|
||||
target->max_xfer_szper_scatreq =
|
||||
MAX_SCATTER_REQ_TRANSFER_SIZE;
|
||||
} else {
|
||||
ath6kl_sdio_cleanup_scatter(ar);
|
||||
ath6kl_warn("hif scatter resource setup failed, trying virtual scatter method\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (virt_scat || ret) {
|
||||
ret = ath6kl_sdio_alloc_prep_scat_req(ar_sdio,
|
||||
ATH6KL_SCATTER_ENTRIES_PER_REQ,
|
||||
ATH6KL_SCATTER_REQS, virt_scat);
|
||||
|
||||
if (ret) {
|
||||
ath6kl_err("failed to alloc virtual scatter resources !\n");
|
||||
ath6kl_sdio_cleanup_scatter(ar);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"Vitual scatter enabled, max_scat_req:%d, entries:%d\n",
|
||||
ATH6KL_SCATTER_REQS, ATH6KL_SCATTER_ENTRIES_PER_REQ);
|
||||
|
||||
target->max_scat_entries = ATH6KL_SCATTER_ENTRIES_PER_REQ;
|
||||
target->max_xfer_szper_scatreq =
|
||||
ATH6KL_MAX_TRANSFER_SIZE_PER_SCATTER;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ath6kl_hif_ops ath6kl_sdio_ops = {
|
||||
.read_write_sync = ath6kl_sdio_read_write_sync,
|
||||
.write_async = ath6kl_sdio_write_async,
|
||||
.irq_enable = ath6kl_sdio_irq_enable,
|
||||
.irq_disable = ath6kl_sdio_irq_disable,
|
||||
.scatter_req_get = ath6kl_sdio_scatter_req_get,
|
||||
.scatter_req_add = ath6kl_sdio_scatter_req_add,
|
||||
.enable_scatter = ath6kl_sdio_enable_scatter,
|
||||
.scat_req_rw = ath6kl_sdio_async_rw_scatter,
|
||||
.cleanup_scatter = ath6kl_sdio_cleanup_scatter,
|
||||
};
|
||||
|
||||
static int ath6kl_sdio_probe(struct sdio_func *func,
|
||||
const struct sdio_device_id *id)
|
||||
{
|
||||
int ret;
|
||||
struct ath6kl_sdio *ar_sdio;
|
||||
struct ath6kl *ar;
|
||||
int count;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_TRC,
|
||||
"%s: func: 0x%X, vendor id: 0x%X, dev id: 0x%X, block size: 0x%X/0x%X\n",
|
||||
__func__, func->num, func->vendor,
|
||||
func->device, func->max_blksize, func->cur_blksize);
|
||||
|
||||
ar_sdio = kzalloc(sizeof(struct ath6kl_sdio), GFP_KERNEL);
|
||||
if (!ar_sdio)
|
||||
return -ENOMEM;
|
||||
|
||||
ar_sdio->dma_buffer = kzalloc(HIF_DMA_BUFFER_SIZE, GFP_KERNEL);
|
||||
if (!ar_sdio->dma_buffer) {
|
||||
ret = -ENOMEM;
|
||||
goto err_hif;
|
||||
}
|
||||
|
||||
ar_sdio->func = func;
|
||||
sdio_set_drvdata(func, ar_sdio);
|
||||
|
||||
ar_sdio->id = id;
|
||||
ar_sdio->is_disabled = true;
|
||||
|
||||
spin_lock_init(&ar_sdio->lock);
|
||||
spin_lock_init(&ar_sdio->scat_lock);
|
||||
spin_lock_init(&ar_sdio->wr_async_lock);
|
||||
|
||||
INIT_LIST_HEAD(&ar_sdio->scat_req);
|
||||
INIT_LIST_HEAD(&ar_sdio->bus_req_freeq);
|
||||
INIT_LIST_HEAD(&ar_sdio->wr_asyncq);
|
||||
|
||||
INIT_WORK(&ar_sdio->wr_async_work, ath6kl_sdio_write_async_work);
|
||||
|
||||
for (count = 0; count < BUS_REQUEST_MAX_NUM; count++)
|
||||
ath6kl_sdio_free_bus_req(ar_sdio, &ar_sdio->bus_req[count]);
|
||||
|
||||
ar = ath6kl_core_alloc(&ar_sdio->func->dev);
|
||||
if (!ar) {
|
||||
ath6kl_err("Failed to alloc ath6kl core\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_dma;
|
||||
}
|
||||
|
||||
ar_sdio->ar = ar;
|
||||
ar->hif_priv = ar_sdio;
|
||||
ar->hif_ops = &ath6kl_sdio_ops;
|
||||
|
||||
ath6kl_sdio_set_mbox_info(ar);
|
||||
|
||||
sdio_claim_host(func);
|
||||
|
||||
if ((ar_sdio->id->device & MANUFACTURER_ID_ATH6KL_BASE_MASK) >=
|
||||
MANUFACTURER_ID_AR6003_BASE) {
|
||||
/* enable 4-bit ASYNC interrupt on AR6003 or later */
|
||||
ret = ath6kl_sdio_func0_cmd52_wr_byte(func->card,
|
||||
CCCR_SDIO_IRQ_MODE_REG,
|
||||
SDIO_IRQ_MODE_ASYNC_4BIT_IRQ);
|
||||
if (ret) {
|
||||
ath6kl_err("Failed to enable 4-bit async irq mode %d\n",
|
||||
ret);
|
||||
sdio_release_host(func);
|
||||
goto err_dma;
|
||||
}
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_TRC, "4-bit async irq mode enabled\n");
|
||||
}
|
||||
|
||||
/* give us some time to enable, in ms */
|
||||
func->enable_timeout = 100;
|
||||
|
||||
sdio_release_host(func);
|
||||
|
||||
ret = ath6kl_sdio_power_on(ar_sdio);
|
||||
if (ret)
|
||||
goto err_dma;
|
||||
|
||||
sdio_claim_host(func);
|
||||
|
||||
ret = sdio_set_block_size(func, HIF_MBOX_BLOCK_SIZE);
|
||||
if (ret) {
|
||||
ath6kl_err("Set sdio block size %d failed: %d)\n",
|
||||
HIF_MBOX_BLOCK_SIZE, ret);
|
||||
sdio_release_host(func);
|
||||
goto err_off;
|
||||
}
|
||||
|
||||
sdio_release_host(func);
|
||||
|
||||
ret = ath6kl_core_init(ar);
|
||||
if (ret) {
|
||||
ath6kl_err("Failed to init ath6kl core\n");
|
||||
goto err_off;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err_off:
|
||||
ath6kl_sdio_power_off(ar_sdio);
|
||||
err_dma:
|
||||
kfree(ar_sdio->dma_buffer);
|
||||
err_hif:
|
||||
kfree(ar_sdio);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath6kl_sdio_remove(struct sdio_func *func)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio;
|
||||
|
||||
ar_sdio = sdio_get_drvdata(func);
|
||||
|
||||
ath6kl_stop_txrx(ar_sdio->ar);
|
||||
cancel_work_sync(&ar_sdio->wr_async_work);
|
||||
|
||||
ath6kl_unavail_ev(ar_sdio->ar);
|
||||
|
||||
ath6kl_sdio_power_off(ar_sdio);
|
||||
|
||||
kfree(ar_sdio->dma_buffer);
|
||||
kfree(ar_sdio);
|
||||
}
|
||||
|
||||
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))},
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(sdio, ath6kl_sdio_devices);
|
||||
|
||||
static struct sdio_driver ath6kl_sdio_driver = {
|
||||
.name = "ath6kl_sdio",
|
||||
.id_table = ath6kl_sdio_devices,
|
||||
.probe = ath6kl_sdio_probe,
|
||||
.remove = ath6kl_sdio_remove,
|
||||
};
|
||||
|
||||
static int __init ath6kl_sdio_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sdio_register_driver(&ath6kl_sdio_driver);
|
||||
if (ret)
|
||||
ath6kl_err("sdio driver registration failed: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit ath6kl_sdio_exit(void)
|
||||
{
|
||||
sdio_unregister_driver(&ath6kl_sdio_driver);
|
||||
}
|
||||
|
||||
module_init(ath6kl_sdio_init);
|
||||
module_exit(ath6kl_sdio_exit);
|
||||
|
||||
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);
|
331
drivers/net/wireless/ath/ath6kl/target.h
Normal file
331
drivers/net/wireless/ath/ath6kl/target.h
Normal file
@ -0,0 +1,331 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2010 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.
|
||||
*/
|
||||
|
||||
#ifndef TARGET_H
|
||||
#define TARGET_H
|
||||
|
||||
#define AR6003_BOARD_DATA_SZ 1024
|
||||
#define AR6003_BOARD_EXT_DATA_SZ 768
|
||||
|
||||
#define RESET_CONTROL_ADDRESS 0x00000000
|
||||
#define RESET_CONTROL_COLD_RST 0x00000100
|
||||
#define RESET_CONTROL_MBOX_RST 0x00000004
|
||||
|
||||
#define CPU_CLOCK_STANDARD_S 0
|
||||
#define CPU_CLOCK_STANDARD 0x00000003
|
||||
#define CPU_CLOCK_ADDRESS 0x00000020
|
||||
|
||||
#define CLOCK_CONTROL_ADDRESS 0x00000028
|
||||
#define CLOCK_CONTROL_LF_CLK32_S 2
|
||||
#define CLOCK_CONTROL_LF_CLK32 0x00000004
|
||||
|
||||
#define SYSTEM_SLEEP_ADDRESS 0x000000c4
|
||||
#define SYSTEM_SLEEP_DISABLE_S 0
|
||||
#define SYSTEM_SLEEP_DISABLE 0x00000001
|
||||
|
||||
#define LPO_CAL_ADDRESS 0x000000e0
|
||||
#define LPO_CAL_ENABLE_S 20
|
||||
#define LPO_CAL_ENABLE 0x00100000
|
||||
|
||||
#define GPIO_PIN10_ADDRESS 0x00000050
|
||||
#define GPIO_PIN11_ADDRESS 0x00000054
|
||||
#define GPIO_PIN12_ADDRESS 0x00000058
|
||||
#define GPIO_PIN13_ADDRESS 0x0000005c
|
||||
|
||||
#define HOST_INT_STATUS_ADDRESS 0x00000400
|
||||
#define HOST_INT_STATUS_ERROR_S 7
|
||||
#define HOST_INT_STATUS_ERROR 0x00000080
|
||||
|
||||
#define HOST_INT_STATUS_CPU_S 6
|
||||
#define HOST_INT_STATUS_CPU 0x00000040
|
||||
|
||||
#define HOST_INT_STATUS_COUNTER_S 4
|
||||
#define HOST_INT_STATUS_COUNTER 0x00000010
|
||||
|
||||
#define CPU_INT_STATUS_ADDRESS 0x00000401
|
||||
|
||||
#define ERROR_INT_STATUS_ADDRESS 0x00000402
|
||||
#define ERROR_INT_STATUS_WAKEUP_S 2
|
||||
#define ERROR_INT_STATUS_WAKEUP 0x00000004
|
||||
|
||||
#define ERROR_INT_STATUS_RX_UNDERFLOW_S 1
|
||||
#define ERROR_INT_STATUS_RX_UNDERFLOW 0x00000002
|
||||
|
||||
#define ERROR_INT_STATUS_TX_OVERFLOW_S 0
|
||||
#define ERROR_INT_STATUS_TX_OVERFLOW 0x00000001
|
||||
|
||||
#define COUNTER_INT_STATUS_ADDRESS 0x00000403
|
||||
#define COUNTER_INT_STATUS_COUNTER_S 0
|
||||
#define COUNTER_INT_STATUS_COUNTER 0x000000ff
|
||||
|
||||
#define RX_LOOKAHEAD_VALID_ADDRESS 0x00000405
|
||||
|
||||
#define INT_STATUS_ENABLE_ADDRESS 0x00000418
|
||||
#define INT_STATUS_ENABLE_ERROR_S 7
|
||||
#define INT_STATUS_ENABLE_ERROR 0x00000080
|
||||
|
||||
#define INT_STATUS_ENABLE_CPU_S 6
|
||||
#define INT_STATUS_ENABLE_CPU 0x00000040
|
||||
|
||||
#define INT_STATUS_ENABLE_INT_S 5
|
||||
#define INT_STATUS_ENABLE_INT 0x00000020
|
||||
#define INT_STATUS_ENABLE_COUNTER_S 4
|
||||
#define INT_STATUS_ENABLE_COUNTER 0x00000010
|
||||
|
||||
#define INT_STATUS_ENABLE_MBOX_DATA_S 0
|
||||
#define INT_STATUS_ENABLE_MBOX_DATA 0x0000000f
|
||||
|
||||
#define CPU_INT_STATUS_ENABLE_ADDRESS 0x00000419
|
||||
#define CPU_INT_STATUS_ENABLE_BIT_S 0
|
||||
#define CPU_INT_STATUS_ENABLE_BIT 0x000000ff
|
||||
|
||||
#define ERROR_STATUS_ENABLE_ADDRESS 0x0000041a
|
||||
#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_S 1
|
||||
#define ERROR_STATUS_ENABLE_RX_UNDERFLOW 0x00000002
|
||||
|
||||
#define ERROR_STATUS_ENABLE_TX_OVERFLOW_S 0
|
||||
#define ERROR_STATUS_ENABLE_TX_OVERFLOW 0x00000001
|
||||
|
||||
#define COUNTER_INT_STATUS_ENABLE_ADDRESS 0x0000041b
|
||||
#define COUNTER_INT_STATUS_ENABLE_BIT_S 0
|
||||
#define COUNTER_INT_STATUS_ENABLE_BIT 0x000000ff
|
||||
|
||||
#define COUNT_ADDRESS 0x00000420
|
||||
|
||||
#define COUNT_DEC_ADDRESS 0x00000440
|
||||
|
||||
#define WINDOW_DATA_ADDRESS 0x00000474
|
||||
#define WINDOW_WRITE_ADDR_ADDRESS 0x00000478
|
||||
#define WINDOW_READ_ADDR_ADDRESS 0x0000047c
|
||||
#define CPU_DBG_SEL_ADDRESS 0x00000483
|
||||
#define CPU_DBG_ADDRESS 0x00000484
|
||||
|
||||
#define LOCAL_SCRATCH_ADDRESS 0x000000c0
|
||||
#define ATH6KL_OPTION_SLEEP_DISABLE 0x08
|
||||
|
||||
#define RTC_BASE_ADDRESS 0x00004000
|
||||
#define GPIO_BASE_ADDRESS 0x00014000
|
||||
#define MBOX_BASE_ADDRESS 0x00018000
|
||||
#define ANALOG_INTF_BASE_ADDRESS 0x0001c000
|
||||
|
||||
/* real name of the register is unknown */
|
||||
#define ATH6KL_ANALOG_PLL_REGISTER (ANALOG_INTF_BASE_ADDRESS + 0x284)
|
||||
|
||||
#define SM(f, v) (((v) << f##_S) & f)
|
||||
#define MS(f, v) (((v) & f) >> f##_S)
|
||||
|
||||
/*
|
||||
* xxx_HOST_INTEREST_ADDRESS is the address in Target RAM of the
|
||||
* host_interest structure.
|
||||
*
|
||||
* Host Interest is shared between Host and Target in order to coordinate
|
||||
* between the two, and is intended to remain constant (with additions only
|
||||
* at the end).
|
||||
*/
|
||||
#define ATH6KL_HI_START_ADDR 0x00540600
|
||||
|
||||
/*
|
||||
* These are items that the Host may need to access
|
||||
* via BMI or via the Diagnostic Window. The position
|
||||
* of items in this structure must remain constant.
|
||||
* across firmware revisions!
|
||||
*
|
||||
* Types for each item must be fixed size across target and host platforms.
|
||||
* The structure is used only to calculate offset for each register with
|
||||
* HI_ITEM() macro, no values are stored to it.
|
||||
*
|
||||
* More items may be added at the end.
|
||||
*/
|
||||
struct host_interest {
|
||||
/*
|
||||
* Pointer to application-defined area, if any.
|
||||
* Set by Target application during startup.
|
||||
*/
|
||||
u32 hi_app_host_interest; /* 0x00 */
|
||||
|
||||
/* Pointer to register dump area, valid after Target crash. */
|
||||
u32 hi_failure_state; /* 0x04 */
|
||||
|
||||
/* Pointer to debug logging header */
|
||||
u32 hi_dbglog_hdr; /* 0x08 */
|
||||
|
||||
u32 hi_unused1; /* 0x0c */
|
||||
|
||||
/*
|
||||
* General-purpose flag bits, similar to ATH6KL_OPTION_* flags.
|
||||
* Can be used by application rather than by OS.
|
||||
*/
|
||||
u32 hi_option_flag; /* 0x10 */
|
||||
|
||||
/*
|
||||
* Boolean that determines whether or not to
|
||||
* display messages on the serial port.
|
||||
*/
|
||||
u32 hi_serial_enable; /* 0x14 */
|
||||
|
||||
/* Start address of DataSet index, if any */
|
||||
u32 hi_dset_list_head; /* 0x18 */
|
||||
|
||||
/* Override Target application start address */
|
||||
u32 hi_app_start; /* 0x1c */
|
||||
|
||||
/* Clock and voltage tuning */
|
||||
u32 hi_skip_clock_init; /* 0x20 */
|
||||
u32 hi_core_clock_setting; /* 0x24 */
|
||||
u32 hi_cpu_clock_setting; /* 0x28 */
|
||||
u32 hi_system_sleep_setting; /* 0x2c */
|
||||
u32 hi_xtal_control_setting; /* 0x30 */
|
||||
u32 hi_pll_ctrl_setting_24ghz; /* 0x34 */
|
||||
u32 hi_pll_ctrl_setting_5ghz; /* 0x38 */
|
||||
u32 hi_ref_voltage_trim_setting; /* 0x3c */
|
||||
u32 hi_clock_info; /* 0x40 */
|
||||
|
||||
/*
|
||||
* Flash configuration overrides, used only
|
||||
* when firmware is not executing from flash.
|
||||
* (When using flash, modify the global variables
|
||||
* with equivalent names.)
|
||||
*/
|
||||
u32 hi_bank0_addr_value; /* 0x44 */
|
||||
u32 hi_bank0_read_value; /* 0x48 */
|
||||
u32 hi_bank0_write_value; /* 0x4c */
|
||||
u32 hi_bank0_config_value; /* 0x50 */
|
||||
|
||||
/* Pointer to Board Data */
|
||||
u32 hi_board_data; /* 0x54 */
|
||||
u32 hi_board_data_initialized; /* 0x58 */
|
||||
|
||||
u32 hi_dset_ram_index_tbl; /* 0x5c */
|
||||
|
||||
u32 hi_desired_baud_rate; /* 0x60 */
|
||||
u32 hi_dbglog_config; /* 0x64 */
|
||||
u32 hi_end_ram_reserve_sz; /* 0x68 */
|
||||
u32 hi_mbox_io_block_sz; /* 0x6c */
|
||||
|
||||
u32 hi_num_bpatch_streams; /* 0x70 -- unused */
|
||||
u32 hi_mbox_isr_yield_limit; /* 0x74 */
|
||||
|
||||
u32 hi_refclk_hz; /* 0x78 */
|
||||
u32 hi_ext_clk_detected; /* 0x7c */
|
||||
u32 hi_dbg_uart_txpin; /* 0x80 */
|
||||
u32 hi_dbg_uart_rxpin; /* 0x84 */
|
||||
u32 hi_hci_uart_baud; /* 0x88 */
|
||||
u32 hi_hci_uart_pin_assignments; /* 0x8C */
|
||||
/*
|
||||
* NOTE: byte [0] = tx pin, [1] = rx pin, [2] = rts pin, [3] = cts
|
||||
* pin
|
||||
*/
|
||||
u32 hi_hci_uart_baud_scale_val; /* 0x90 */
|
||||
u32 hi_hci_uart_baud_step_val; /* 0x94 */
|
||||
|
||||
u32 hi_allocram_start; /* 0x98 */
|
||||
u32 hi_allocram_sz; /* 0x9c */
|
||||
u32 hi_hci_bridge_flags; /* 0xa0 */
|
||||
u32 hi_hci_uart_support_pins; /* 0xa4 */
|
||||
/*
|
||||
* NOTE: byte [0] = RESET pin (bit 7 is polarity),
|
||||
* bytes[1]..bytes[3] are for future use
|
||||
*/
|
||||
u32 hi_hci_uart_pwr_mgmt_params; /* 0xa8 */
|
||||
/*
|
||||
* 0xa8 - [1]: 0 = UART FC active low, 1 = UART FC active high
|
||||
* [31:16]: wakeup timeout in ms
|
||||
*/
|
||||
|
||||
/* Pointer to extended board data */
|
||||
u32 hi_board_ext_data; /* 0xac */
|
||||
u32 hi_board_ext_data_config; /* 0xb0 */
|
||||
|
||||
/*
|
||||
* Bit [0] : valid
|
||||
* Bit[31:16: size
|
||||
*/
|
||||
/*
|
||||
* hi_reset_flag is used to do some stuff when target reset.
|
||||
* such as restore app_start after warm reset or
|
||||
* preserve host Interest area, or preserve ROM data, literals etc.
|
||||
*/
|
||||
u32 hi_reset_flag; /* 0xb4 */
|
||||
/* indicate hi_reset_flag is valid */
|
||||
u32 hi_reset_flag_valid; /* 0xb8 */
|
||||
u32 hi_hci_uart_pwr_mgmt_params_ext; /* 0xbc */
|
||||
/*
|
||||
* 0xbc - [31:0]: idle timeout in ms
|
||||
*/
|
||||
/* ACS flags */
|
||||
u32 hi_acs_flags; /* 0xc0 */
|
||||
u32 hi_console_flags; /* 0xc4 */
|
||||
u32 hi_nvram_state; /* 0xc8 */
|
||||
u32 hi_option_flag2; /* 0xcc */
|
||||
|
||||
/* If non-zero, override values sent to Host in WMI_READY event. */
|
||||
u32 hi_sw_version_override; /* 0xd0 */
|
||||
u32 hi_abi_version_override; /* 0xd4 */
|
||||
|
||||
/*
|
||||
* Percentage of high priority RX traffic to total expected RX traffic -
|
||||
* applicable only to ar6004
|
||||
*/
|
||||
u32 hi_hp_rx_traffic_ratio; /* 0xd8 */
|
||||
|
||||
/* test applications flags */
|
||||
u32 hi_test_apps_related ; /* 0xdc */
|
||||
/* location of test script */
|
||||
u32 hi_ota_testscript; /* 0xe0 */
|
||||
/* location of CAL data */
|
||||
u32 hi_cal_data; /* 0xe4 */
|
||||
/* Number of packet log buffers */
|
||||
u32 hi_pktlog_num_buffers; /* 0xe8 */
|
||||
|
||||
} __packed;
|
||||
|
||||
#define HI_ITEM(item) offsetof(struct host_interest, item)
|
||||
|
||||
#define HI_OPTION_MAC_ADDR_METHOD_SHIFT 3
|
||||
|
||||
#define HI_OPTION_FW_MODE_IBSS 0x0
|
||||
#define HI_OPTION_FW_MODE_BSS_STA 0x1
|
||||
#define HI_OPTION_FW_MODE_AP 0x2
|
||||
|
||||
#define HI_OPTION_NUM_DEV_SHIFT 0x9
|
||||
|
||||
#define HI_OPTION_FW_BRIDGE_SHIFT 0x04
|
||||
|
||||
/* Fw Mode/SubMode Mask
|
||||
|------------------------------------------------------------------------------|
|
||||
| SUB | SUB | SUB | SUB | | | |
|
||||
| MODE[3] | MODE[2] | MODE[1] | MODE[0] | MODE[3] | MODE[2] | MODE[1] | MODE[0|
|
||||
| (2) | (2) | (2) | (2) | (2) | (2) | (2) | (2)
|
||||
|------------------------------------------------------------------------------|
|
||||
*/
|
||||
#define HI_OPTION_FW_MODE_SHIFT 0xC
|
||||
|
||||
/* Convert a Target virtual address into a Target physical address */
|
||||
#define TARG_VTOP(vaddr) (vaddr & 0x001fffff)
|
||||
|
||||
#define AR6003_REV2_APP_START_OVERRIDE 0x944C00
|
||||
#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_START_OVERRIDE 0x945d00
|
||||
#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
|
||||
|
||||
#endif
|
1457
drivers/net/wireless/ath/ath6kl/txrx.c
Normal file
1457
drivers/net/wireless/ath/ath6kl/txrx.c
Normal file
File diff suppressed because it is too large
Load Diff
2743
drivers/net/wireless/ath/ath6kl/wmi.c
Normal file
2743
drivers/net/wireless/ath/ath6kl/wmi.c
Normal file
File diff suppressed because it is too large
Load Diff
2018
drivers/net/wireless/ath/ath6kl/wmi.h
Normal file
2018
drivers/net/wireless/ath/ath6kl/wmi.h
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user