提交 bdcd8170 编写于 作者: K Kalle Valo

Add ath6kl cleaned up driver

Last May we started working on cleaning up ath6kl driver which is
currently in staging. The work has happened in a separate
ath6kl-cleanup tree:

http://git.kernel.org/?p=linux/kernel/git/kvalo/ath6kl-cleanup.git;a=summary

After over 1100 (!) patches we have now reached a state where I would
like to start discussing about pushing the driver to the wireless
trees and replacing the staging driver.

The driver is now a lot smaller and looks like a proper Linux driver.
The size of the driver (measured with simple wc -l) dropped from 49
kLOC to 18 kLOC and the number of the .c and .h files dropped from 107
to 22. Most importantly the number of subdirectories reduced from 26
to zero :)

There are two remaining checkpatch warnings in the driver which we
decided to omit for now:

drivers/net/wireless/ath/ath6kl/debug.c:31:
  WARNING: printk() should include KERN_ facility level
drivers/net/wireless/ath/ath6kl/sdio.c:527:
  WARNING: msleep < 20ms can sleep for up to 20ms;
  see Documentation/timers/timers-howto.txt

The driver has endian annotations for all the hardware specific
structures and there are no sparse errors. Unfortunately I don't have
any big endian hardware to test that right now.

We have been testing the driver both on x86 and arm platforms. The
code is also compiled with sparc and parisc cross compilers.

Notable missing features compared to the current staging driver are:

o HCI over SDIO support
o nl80211 testmode
o firmware logging
o suspend support

Testmode, firmware logging and suspend support will be added soon. HCI
over SDIO support will be more difficult as the HCI driver needs to
share code with the wifi driver. This is something we need to research
more.

Also I want to point out the changes I did for signed endian support.
As I wasn't able to find any support for signed endian annotations I
decided to follow what NTFS has done and added my own. Grep for sle16
and sle32, especially from wmi.h.

Various people have been working on the cleanup, the hall of
fame based on number of patches is:

   543  Vasanthakumar Thiagarajan
   403  Raja Mani
   252  Kalle Valo
    16  Vivek Natarajan
    12  Suraj Sumangala
     3  Joe Perches
     2  Jouni Malinen
Signed-off-by: NVasanthakumar Thiagarajan <vthiagar@qca.qualcomm.com>
Signed-off-by: NRaja Mani <rmani@qca.qualcomm.com>
Signed-off-by: NVivek Natarajan <nataraja@qca.qualcomm.com>
Signed-off-by: NSuraj Sumangala <surajs@qca.qualcomm.com>
Signed-off-by: NJoe Perches <joe@perches.com>
Signed-off-by: NJouni Malinen <jouni@qca.qualcomm.com>
Signed-off-by: NKalle Valo <kvalo@qca.qualcomm.com>
上级 f749b946
......@@ -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
obj-$(CONFIG_ATH5K) += ath5k/
obj-$(CONFIG_ATH9K_HW) += ath9k/
obj-$(CONFIG_CARL9170) += carl9170/
obj-$(CONFIG_ATH6KL) += ath6kl/
obj-$(CONFIG_ATH_COMMON) += ath.o
......
config ATH6KL
tristate "Atheros ath6kl support"
depends on MMC
depends on CFG80211
select WIRELESS_EXT
select WEXT_PRIV
---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
#------------------------------------------------------------------------------
# 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
/*
* 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]), &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;
}
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;
}
/*
* 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
此差异已折叠。
/*
* 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 */
/*
* 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 {
void *nt_wmi; /* back reference */
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 (*f) (void *arg, struct bss *),
void *arg);
void wlan_node_table_init(void *wmip, struct ath6kl_node_table *nt);
void wlan_node_table_cleanup(struct ath6kl_node_table *nt);
void wlan_refresh_inactive_nodes(struct ath6kl_node_table *nt);
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 */
/*
* 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
};
enum ath6kl_wlan_state {
WLAN_DISABLED,
WLAN_ENABLED
};
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
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;
enum ath6kl_wlan_state wlan_state;
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;
};
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);
#endif /* CORE_H */
/*
* 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
/*
* 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_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
/*
* 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,
struct hif_dev_scat_sup_info *info)
{
return ar->hif_ops->enable_scatter(ar, info);
}
static inline void ath6kl_hif_cleanup_scatter(struct ath6kl *ar)
{
return ar->hif_ops->cleanup_scatter(ar);
}
#endif
/*
* 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;
u32 flags;
void (*complete) (struct hif_scatter_req *);
int status;
struct htc_endpoint *ep;
int scat_entries;
struct hif_scatter_req_priv *req_priv;
/* bounce buffer for upper layers to copy to/from */
u8 *virt_dma_buf;
struct hif_scatter_item scat_list[1];
};
struct hif_dev_scat_sup_info {
int (*rw_scat_func) (struct ath6kl *ar, struct hif_scatter_req *);
int max_scat_entries;
int max_xfer_szper_scatreq;
};
struct hif_scatter_req_priv {
struct bus_request *busrequest;
struct scatterlist sgentries[MAX_SCATTER_ENTRIES_PER_REQ];
};
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,
struct hif_dev_scat_sup_info *info);
void (*cleanup_scatter)(struct ath6kl *ar);
};
#endif
此差异已折叠。
/*
* 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)
/* scatter request flags */
#define HTC_SCAT_REQ_FLG_PART_BNDL (1 << 0)
#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;
};
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);
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
此差异已折叠。
/*
* 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;
/* buffers for ASYNC I/O */
struct ath6kl_async_reg_io_buffer {
struct htc_packet packet;
u8 pad1[A_CACHE_LINE_PAD];
/* cache-line safe with pads around */
u8 buf[ATH6KL_REG_IO_BUFFER_SIZE];
u8 pad2[A_CACHE_LINE_PAD];
};
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];
u32 block_sz;
u32 block_mask;
struct htc_target *htc_cnxt;
struct list_head reg_io;
struct ath6kl_async_reg_io_buffer reg_io_buf[ATH6KL_MAX_REG_IO_BUFFERS];
int (*msg_pending) (struct htc_target *target, u32 lk_ahds[],
int *npkts_fetched);
struct hif_dev_scat_sup_info hif_scat_info;
bool virt_scat;
int max_rx_bndl_sz;
int max_tx_bndl_sz;
int chk_irq_status_cnt;
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_setup_msg_bndl(struct ath6kl_device *dev, int max_msg_per_xfer);
int ath6kldev_submit_scat_req(struct ath6kl_device *dev,
struct hif_scatter_req *scat_req, bool read);
#endif /*ATH6KL_H_ */
此差异已折叠。
此差异已折叠。
/*
* 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 (*f) (void *arg, struct bss *), 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++;
(*f) (arg, ni);
wlan_node_dec_free(ni);
}
spin_unlock_bh(&nt->nt_nodelock);
}
void wlan_node_table_init(void *wmi, 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_wmi = wmi;
nt->nt_node_age = WLAN_NODE_INACT_TIMEOUT_MSEC;
}
void wlan_refresh_inactive_nodes(struct ath6kl_node_table *nt)
{
struct bss *bss;
u8 my_bssid[ETH_ALEN];
u32 now;
ath6kl_wmi_get_current_bssid(nt->nt_wmi, my_bssid);
now = jiffies_to_msecs(jiffies);
bss = nt->nt_node_first;
while (bss != NULL) {
/* refresh all nodes except the current bss */
if (memcmp(my_bssid, bss->ni_macaddr, sizeof(my_bssid)) != 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);
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册