提交 392e7419 编写于 作者: J John W. Linville

Merge branch 'ath6kl-next' of master.kernel.org:/pub/scm/linux/kernel/git/kvalo/ath6kl

...@@ -25,5 +25,6 @@ config ATH_DEBUG ...@@ -25,5 +25,6 @@ config ATH_DEBUG
source "drivers/net/wireless/ath/ath5k/Kconfig" source "drivers/net/wireless/ath/ath5k/Kconfig"
source "drivers/net/wireless/ath/ath9k/Kconfig" source "drivers/net/wireless/ath/ath9k/Kconfig"
source "drivers/net/wireless/ath/carl9170/Kconfig" source "drivers/net/wireless/ath/carl9170/Kconfig"
source "drivers/net/wireless/ath/ath6kl/Kconfig"
endif endif
obj-$(CONFIG_ATH5K) += ath5k/ obj-$(CONFIG_ATH5K) += ath5k/
obj-$(CONFIG_ATH9K_HW) += ath9k/ obj-$(CONFIG_ATH9K_HW) += ath9k/
obj-$(CONFIG_CARL9170) += carl9170/ obj-$(CONFIG_CARL9170) += carl9170/
obj-$(CONFIG_ATH6KL) += ath6kl/
obj-$(CONFIG_ATH_COMMON) += ath.o obj-$(CONFIG_ATH_COMMON) += ath.o
......
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
#------------------------------------------------------------------------------
# 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 {
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 */
/*
* 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 */
/*
* 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_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
/*
* 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
/*
* 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
此差异已折叠。
/*
* 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
此差异已折叠。
/*
* 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_ */
此差异已折叠。
此差异已折叠。
/*
* 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);
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册