Merge branch 'for-linville-ath10k' of git://github.com/kvalo/ath6kl
This commit is contained in:
commit
b70727e8a6
|
@ -31,5 +31,6 @@ source "drivers/net/wireless/ath/carl9170/Kconfig"
|
|||
source "drivers/net/wireless/ath/ath6kl/Kconfig"
|
||||
source "drivers/net/wireless/ath/ar5523/Kconfig"
|
||||
source "drivers/net/wireless/ath/wil6210/Kconfig"
|
||||
source "drivers/net/wireless/ath/ath10k/Kconfig"
|
||||
|
||||
endif
|
||||
|
|
|
@ -4,6 +4,7 @@ obj-$(CONFIG_CARL9170) += carl9170/
|
|||
obj-$(CONFIG_ATH6KL) += ath6kl/
|
||||
obj-$(CONFIG_AR5523) += ar5523/
|
||||
obj-$(CONFIG_WIL6210) += wil6210/
|
||||
obj-$(CONFIG_ATH10K) += ath10k/
|
||||
|
||||
obj-$(CONFIG_ATH_COMMON) += ath.o
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
config ATH10K
|
||||
tristate "Atheros 802.11ac wireless cards support"
|
||||
depends on MAC80211
|
||||
select ATH_COMMON
|
||||
---help---
|
||||
This module adds support for wireless adapters based on
|
||||
Atheros IEEE 802.11ac family of chipsets.
|
||||
|
||||
If you choose to build a module, it'll be called ath10k.
|
||||
|
||||
config ATH10K_PCI
|
||||
tristate "Atheros ath10k PCI support"
|
||||
depends on ATH10K && PCI
|
||||
---help---
|
||||
This module adds support for PCIE bus
|
||||
|
||||
config ATH10K_DEBUG
|
||||
bool "Atheros ath10k debugging"
|
||||
depends on ATH10K
|
||||
---help---
|
||||
Enables debug support
|
||||
|
||||
If unsure, say Y to make it easier to debug problems.
|
||||
|
||||
config ATH10K_DEBUGFS
|
||||
bool "Atheros ath10k debugfs support"
|
||||
depends on ATH10K
|
||||
---help---
|
||||
Enabled debugfs support
|
||||
|
||||
If unsure, say Y to make it easier to debug problems.
|
||||
|
||||
config ATH10K_TRACING
|
||||
bool "Atheros ath10k tracing support"
|
||||
depends on ATH10K
|
||||
depends on EVENT_TRACING
|
||||
---help---
|
||||
Select this to ath10k use tracing infrastructure.
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
obj-$(CONFIG_ATH10K) += ath10k_core.o
|
||||
ath10k_core-y += mac.o \
|
||||
debug.o \
|
||||
core.o \
|
||||
htc.o \
|
||||
htt.o \
|
||||
htt_rx.o \
|
||||
htt_tx.o \
|
||||
txrx.o \
|
||||
wmi.o \
|
||||
bmi.o
|
||||
|
||||
ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o
|
||||
|
||||
obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o
|
||||
ath10k_pci-y += pci.o \
|
||||
ce.o
|
||||
|
||||
# for tracing framework to find trace.h
|
||||
CFLAGS_trace.o := -I$(src)
|
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2013 Qualcomm Atheros, 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 "bmi.h"
|
||||
#include "hif.h"
|
||||
#include "debug.h"
|
||||
#include "htc.h"
|
||||
|
||||
int ath10k_bmi_done(struct ath10k *ar)
|
||||
{
|
||||
struct bmi_cmd cmd;
|
||||
u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.done);
|
||||
int ret;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath10k_dbg(ATH10K_DBG_CORE, "%s skipped\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ar->bmi.done_sent = true;
|
||||
cmd.id = __cpu_to_le32(BMI_DONE);
|
||||
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
|
||||
if (ret) {
|
||||
ath10k_warn("unable to write to the device: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_CORE, "BMI done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_bmi_get_target_info(struct ath10k *ar,
|
||||
struct bmi_target_info *target_info)
|
||||
{
|
||||
struct bmi_cmd cmd;
|
||||
union bmi_resp resp;
|
||||
u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.get_target_info);
|
||||
u32 resplen = sizeof(resp.get_target_info);
|
||||
int ret;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath10k_warn("BMI Get Target Info Command disallowed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
cmd.id = __cpu_to_le32(BMI_GET_TARGET_INFO);
|
||||
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
|
||||
if (ret) {
|
||||
ath10k_warn("unable to get target info from device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (resplen < sizeof(resp.get_target_info)) {
|
||||
ath10k_warn("invalid get_target_info response length (%d)\n",
|
||||
resplen);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
target_info->version = __le32_to_cpu(resp.get_target_info.version);
|
||||
target_info->type = __le32_to_cpu(resp.get_target_info.type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_bmi_read_memory(struct ath10k *ar,
|
||||
u32 address, void *buffer, u32 length)
|
||||
{
|
||||
struct bmi_cmd cmd;
|
||||
union bmi_resp resp;
|
||||
u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.read_mem);
|
||||
u32 rxlen;
|
||||
int ret;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath10k_warn("command disallowed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_CORE,
|
||||
"%s: (device: 0x%p, address: 0x%x, length: %d)\n",
|
||||
__func__, ar, address, length);
|
||||
|
||||
while (length) {
|
||||
rxlen = min_t(u32, length, BMI_MAX_DATA_SIZE);
|
||||
|
||||
cmd.id = __cpu_to_le32(BMI_READ_MEMORY);
|
||||
cmd.read_mem.addr = __cpu_to_le32(address);
|
||||
cmd.read_mem.len = __cpu_to_le32(rxlen);
|
||||
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen,
|
||||
&resp, &rxlen);
|
||||
if (ret) {
|
||||
ath10k_warn("unable to read from the device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
memcpy(buffer, resp.read_mem.payload, rxlen);
|
||||
address += rxlen;
|
||||
buffer += rxlen;
|
||||
length -= rxlen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_bmi_write_memory(struct ath10k *ar,
|
||||
u32 address, const void *buffer, u32 length)
|
||||
{
|
||||
struct bmi_cmd cmd;
|
||||
u32 hdrlen = sizeof(cmd.id) + sizeof(cmd.write_mem);
|
||||
u32 txlen;
|
||||
int ret;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath10k_warn("command disallowed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_CORE,
|
||||
"%s: (device: 0x%p, address: 0x%x, length: %d)\n",
|
||||
__func__, ar, address, length);
|
||||
|
||||
while (length) {
|
||||
txlen = min(length, BMI_MAX_DATA_SIZE - hdrlen);
|
||||
|
||||
/* copy before roundup to avoid reading beyond buffer*/
|
||||
memcpy(cmd.write_mem.payload, buffer, txlen);
|
||||
txlen = roundup(txlen, 4);
|
||||
|
||||
cmd.id = __cpu_to_le32(BMI_WRITE_MEMORY);
|
||||
cmd.write_mem.addr = __cpu_to_le32(address);
|
||||
cmd.write_mem.len = __cpu_to_le32(txlen);
|
||||
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
|
||||
NULL, NULL);
|
||||
if (ret) {
|
||||
ath10k_warn("unable to write to the device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* fixup roundup() so `length` zeroes out for last chunk */
|
||||
txlen = min(txlen, length);
|
||||
|
||||
address += txlen;
|
||||
buffer += txlen;
|
||||
length -= txlen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param)
|
||||
{
|
||||
struct bmi_cmd cmd;
|
||||
union bmi_resp resp;
|
||||
u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.execute);
|
||||
u32 resplen = sizeof(resp.execute);
|
||||
int ret;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath10k_warn("command disallowed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_CORE,
|
||||
"%s: (device: 0x%p, address: 0x%x, param: %d)\n",
|
||||
__func__, ar, address, *param);
|
||||
|
||||
cmd.id = __cpu_to_le32(BMI_EXECUTE);
|
||||
cmd.execute.addr = __cpu_to_le32(address);
|
||||
cmd.execute.param = __cpu_to_le32(*param);
|
||||
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
|
||||
if (ret) {
|
||||
ath10k_warn("unable to read from the device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (resplen < sizeof(resp.execute)) {
|
||||
ath10k_warn("invalid execute response length (%d)\n",
|
||||
resplen);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*param = __le32_to_cpu(resp.execute.result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length)
|
||||
{
|
||||
struct bmi_cmd cmd;
|
||||
u32 hdrlen = sizeof(cmd.id) + sizeof(cmd.lz_data);
|
||||
u32 txlen;
|
||||
int ret;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath10k_warn("command disallowed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
while (length) {
|
||||
txlen = min(length, BMI_MAX_DATA_SIZE - hdrlen);
|
||||
|
||||
WARN_ON_ONCE(txlen & 3);
|
||||
|
||||
cmd.id = __cpu_to_le32(BMI_LZ_DATA);
|
||||
cmd.lz_data.len = __cpu_to_le32(txlen);
|
||||
memcpy(cmd.lz_data.payload, buffer, txlen);
|
||||
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
|
||||
NULL, NULL);
|
||||
if (ret) {
|
||||
ath10k_warn("unable to write to the device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
buffer += txlen;
|
||||
length -= txlen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address)
|
||||
{
|
||||
struct bmi_cmd cmd;
|
||||
u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.lz_start);
|
||||
int ret;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath10k_warn("command disallowed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
cmd.id = __cpu_to_le32(BMI_LZ_STREAM_START);
|
||||
cmd.lz_start.addr = __cpu_to_le32(address);
|
||||
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
|
||||
if (ret) {
|
||||
ath10k_warn("unable to Start LZ Stream to the device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_bmi_fast_download(struct ath10k *ar,
|
||||
u32 address, const void *buffer, u32 length)
|
||||
{
|
||||
u8 trailer[4] = {};
|
||||
u32 head_len = rounddown(length, 4);
|
||||
u32 trailer_len = length - head_len;
|
||||
int ret;
|
||||
|
||||
ret = ath10k_bmi_lz_stream_start(ar, address);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* copy the last word into a zero padded buffer */
|
||||
if (trailer_len > 0)
|
||||
memcpy(trailer, buffer + head_len, trailer_len);
|
||||
|
||||
ret = ath10k_bmi_lz_data(ar, buffer, head_len);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (trailer_len > 0)
|
||||
ret = ath10k_bmi_lz_data(ar, trailer, 4);
|
||||
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Close compressed stream and open a new (fake) one.
|
||||
* This serves mainly to flush Target caches.
|
||||
*/
|
||||
ret = ath10k_bmi_lz_stream_start(ar, 0x00);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2013 Qualcomm Atheros, 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_
|
||||
|
||||
#include "core.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 QCA988x, to provide
|
||||
* patches to code that is already resident on QCA988x, 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 AR8K 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.
|
||||
*/
|
||||
|
||||
/* Maximum data size used for BMI transfers */
|
||||
#define BMI_MAX_DATA_SIZE 256
|
||||
|
||||
/* len = cmd + addr + length */
|
||||
#define BMI_MAX_CMDBUF_SIZE (BMI_MAX_DATA_SIZE + \
|
||||
sizeof(u32) + \
|
||||
sizeof(u32) + \
|
||||
sizeof(u32))
|
||||
|
||||
/* BMI Commands */
|
||||
|
||||
enum bmi_cmd_id {
|
||||
BMI_NO_COMMAND = 0,
|
||||
BMI_DONE = 1,
|
||||
BMI_READ_MEMORY = 2,
|
||||
BMI_WRITE_MEMORY = 3,
|
||||
BMI_EXECUTE = 4,
|
||||
BMI_SET_APP_START = 5,
|
||||
BMI_READ_SOC_REGISTER = 6,
|
||||
BMI_READ_SOC_WORD = 6,
|
||||
BMI_WRITE_SOC_REGISTER = 7,
|
||||
BMI_WRITE_SOC_WORD = 7,
|
||||
BMI_GET_TARGET_ID = 8,
|
||||
BMI_GET_TARGET_INFO = 8,
|
||||
BMI_ROMPATCH_INSTALL = 9,
|
||||
BMI_ROMPATCH_UNINSTALL = 10,
|
||||
BMI_ROMPATCH_ACTIVATE = 11,
|
||||
BMI_ROMPATCH_DEACTIVATE = 12,
|
||||
BMI_LZ_STREAM_START = 13, /* should be followed by LZ_DATA */
|
||||
BMI_LZ_DATA = 14,
|
||||
BMI_NVRAM_PROCESS = 15,
|
||||
};
|
||||
|
||||
#define BMI_NVRAM_SEG_NAME_SZ 16
|
||||
|
||||
struct bmi_cmd {
|
||||
__le32 id; /* enum bmi_cmd_id */
|
||||
union {
|
||||
struct {
|
||||
} done;
|
||||
struct {
|
||||
__le32 addr;
|
||||
__le32 len;
|
||||
} read_mem;
|
||||
struct {
|
||||
__le32 addr;
|
||||
__le32 len;
|
||||
u8 payload[0];
|
||||
} write_mem;
|
||||
struct {
|
||||
__le32 addr;
|
||||
__le32 param;
|
||||
} execute;
|
||||
struct {
|
||||
__le32 addr;
|
||||
} set_app_start;
|
||||
struct {
|
||||
__le32 addr;
|
||||
} read_soc_reg;
|
||||
struct {
|
||||
__le32 addr;
|
||||
__le32 value;
|
||||
} write_soc_reg;
|
||||
struct {
|
||||
} get_target_info;
|
||||
struct {
|
||||
__le32 rom_addr;
|
||||
__le32 ram_addr; /* or value */
|
||||
__le32 size;
|
||||
__le32 activate; /* 0=install, but dont activate */
|
||||
} rompatch_install;
|
||||
struct {
|
||||
__le32 patch_id;
|
||||
} rompatch_uninstall;
|
||||
struct {
|
||||
__le32 count;
|
||||
__le32 patch_ids[0]; /* length of @count */
|
||||
} rompatch_activate;
|
||||
struct {
|
||||
__le32 count;
|
||||
__le32 patch_ids[0]; /* length of @count */
|
||||
} rompatch_deactivate;
|
||||
struct {
|
||||
__le32 addr;
|
||||
} lz_start;
|
||||
struct {
|
||||
__le32 len; /* max BMI_MAX_DATA_SIZE */
|
||||
u8 payload[0]; /* length of @len */
|
||||
} lz_data;
|
||||
struct {
|
||||
u8 name[BMI_NVRAM_SEG_NAME_SZ];
|
||||
} nvram_process;
|
||||
u8 payload[BMI_MAX_CMDBUF_SIZE];
|
||||
};
|
||||
} __packed;
|
||||
|
||||
union bmi_resp {
|
||||
struct {
|
||||
u8 payload[0];
|
||||
} read_mem;
|
||||
struct {
|
||||
__le32 result;
|
||||
} execute;
|
||||
struct {
|
||||
__le32 value;
|
||||
} read_soc_reg;
|
||||
struct {
|
||||
__le32 len;
|
||||
__le32 version;
|
||||
__le32 type;
|
||||
} get_target_info;
|
||||
struct {
|
||||
__le32 patch_id;
|
||||
} rompatch_install;
|
||||
struct {
|
||||
__le32 patch_id;
|
||||
} rompatch_uninstall;
|
||||
struct {
|
||||
/* 0 = nothing executed
|
||||
* otherwise = NVRAM segment return value */
|
||||
__le32 result;
|
||||
} nvram_process;
|
||||
u8 payload[BMI_MAX_CMDBUF_SIZE];
|
||||
} __packed;
|
||||
|
||||
struct bmi_target_info {
|
||||
u32 version;
|
||||
u32 type;
|
||||
};
|
||||
|
||||
|
||||
/* in msec */
|
||||
#define BMI_COMMUNICATION_TIMEOUT_HZ (1*HZ)
|
||||
|
||||
#define BMI_CE_NUM_TO_TARG 0
|
||||
#define BMI_CE_NUM_TO_HOST 1
|
||||
|
||||
int ath10k_bmi_done(struct ath10k *ar);
|
||||
int ath10k_bmi_get_target_info(struct ath10k *ar,
|
||||
struct bmi_target_info *target_info);
|
||||
int ath10k_bmi_read_memory(struct ath10k *ar, u32 address,
|
||||
void *buffer, u32 length);
|
||||
int ath10k_bmi_write_memory(struct ath10k *ar, u32 address,
|
||||
const void *buffer, u32 length);
|
||||
|
||||
#define ath10k_bmi_read32(ar, item, val) \
|
||||
({ \
|
||||
int ret; \
|
||||
u32 addr; \
|
||||
__le32 tmp; \
|
||||
\
|
||||
addr = host_interest_item_address(HI_ITEM(item)); \
|
||||
ret = ath10k_bmi_read_memory(ar, addr, (u8 *)&tmp, 4); \
|
||||
*val = __le32_to_cpu(tmp); \
|
||||
ret; \
|
||||
})
|
||||
|
||||
#define ath10k_bmi_write32(ar, item, val) \
|
||||
({ \
|
||||
int ret; \
|
||||
u32 address; \
|
||||
__le32 v = __cpu_to_le32(val); \
|
||||
\
|
||||
address = host_interest_item_address(HI_ITEM(item)); \
|
||||
ret = ath10k_bmi_write_memory(ar, address, \
|
||||
(u8 *)&v, sizeof(v)); \
|
||||
ret; \
|
||||
})
|
||||
|
||||
int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param);
|
||||
int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address);
|
||||
int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length);
|
||||
int ath10k_bmi_fast_download(struct ath10k *ar, u32 address,
|
||||
const void *buffer, u32 length);
|
||||
#endif /* _BMI_H_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,516 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2013 Qualcomm Atheros, 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 _CE_H_
|
||||
#define _CE_H_
|
||||
|
||||
#include "hif.h"
|
||||
|
||||
|
||||
/* Maximum number of Copy Engine's supported */
|
||||
#define CE_COUNT_MAX 8
|
||||
#define CE_HTT_H2T_MSG_SRC_NENTRIES 2048
|
||||
|
||||
/* Descriptor rings must be aligned to this boundary */
|
||||
#define CE_DESC_RING_ALIGN 8
|
||||
#define CE_SENDLIST_ITEMS_MAX 12
|
||||
#define CE_SEND_FLAG_GATHER 0x00010000
|
||||
|
||||
/*
|
||||
* Copy Engine support: low-level Target-side Copy Engine API.
|
||||
* This is a hardware access layer used by code that understands
|
||||
* how to use copy engines.
|
||||
*/
|
||||
|
||||
struct ce_state;
|
||||
|
||||
|
||||
/* Copy Engine operational state */
|
||||
enum ce_op_state {
|
||||
CE_UNUSED,
|
||||
CE_PAUSED,
|
||||
CE_RUNNING,
|
||||
};
|
||||
|
||||
#define CE_DESC_FLAGS_GATHER (1 << 0)
|
||||
#define CE_DESC_FLAGS_BYTE_SWAP (1 << 1)
|
||||
#define CE_DESC_FLAGS_META_DATA_MASK 0xFFFC
|
||||
#define CE_DESC_FLAGS_META_DATA_LSB 3
|
||||
|
||||
struct ce_desc {
|
||||
__le32 addr;
|
||||
__le16 nbytes;
|
||||
__le16 flags; /* %CE_DESC_FLAGS_ */
|
||||
};
|
||||
|
||||
/* Copy Engine Ring internal state */
|
||||
struct ce_ring_state {
|
||||
/* Number of entries in this ring; must be power of 2 */
|
||||
unsigned int nentries;
|
||||
unsigned int nentries_mask;
|
||||
|
||||
/*
|
||||
* For dest ring, this is the next index to be processed
|
||||
* by software after it was/is received into.
|
||||
*
|
||||
* For src ring, this is the last descriptor that was sent
|
||||
* and completion processed by software.
|
||||
*
|
||||
* Regardless of src or dest ring, this is an invariant
|
||||
* (modulo ring size):
|
||||
* write index >= read index >= sw_index
|
||||
*/
|
||||
unsigned int sw_index;
|
||||
/* cached copy */
|
||||
unsigned int write_index;
|
||||
/*
|
||||
* For src ring, this is the next index not yet processed by HW.
|
||||
* This is a cached copy of the real HW index (read index), used
|
||||
* for avoiding reading the HW index register more often than
|
||||
* necessary.
|
||||
* This extends the invariant:
|
||||
* write index >= read index >= hw_index >= sw_index
|
||||
*
|
||||
* For dest ring, this is currently unused.
|
||||
*/
|
||||
/* cached copy */
|
||||
unsigned int hw_index;
|
||||
|
||||
/* Start of DMA-coherent area reserved for descriptors */
|
||||
/* Host address space */
|
||||
void *base_addr_owner_space_unaligned;
|
||||
/* CE address space */
|
||||
u32 base_addr_ce_space_unaligned;
|
||||
|
||||
/*
|
||||
* Actual start of descriptors.
|
||||
* Aligned to descriptor-size boundary.
|
||||
* Points into reserved DMA-coherent area, above.
|
||||
*/
|
||||
/* Host address space */
|
||||
void *base_addr_owner_space;
|
||||
|
||||
/* CE address space */
|
||||
u32 base_addr_ce_space;
|
||||
/*
|
||||
* Start of shadow copy of descriptors, within regular memory.
|
||||
* Aligned to descriptor-size boundary.
|
||||
*/
|
||||
void *shadow_base_unaligned;
|
||||
struct ce_desc *shadow_base;
|
||||
|
||||
void **per_transfer_context;
|
||||
};
|
||||
|
||||
/* Copy Engine internal state */
|
||||
struct ce_state {
|
||||
struct ath10k *ar;
|
||||
unsigned int id;
|
||||
|
||||
unsigned int attr_flags;
|
||||
|
||||
u32 ctrl_addr;
|
||||
enum ce_op_state state;
|
||||
|
||||
void (*send_cb) (struct ce_state *ce_state,
|
||||
void *per_transfer_send_context,
|
||||
u32 buffer,
|
||||
unsigned int nbytes,
|
||||
unsigned int transfer_id);
|
||||
void (*recv_cb) (struct ce_state *ce_state,
|
||||
void *per_transfer_recv_context,
|
||||
u32 buffer,
|
||||
unsigned int nbytes,
|
||||
unsigned int transfer_id,
|
||||
unsigned int flags);
|
||||
|
||||
unsigned int src_sz_max;
|
||||
struct ce_ring_state *src_ring;
|
||||
struct ce_ring_state *dest_ring;
|
||||
};
|
||||
|
||||
struct ce_sendlist_item {
|
||||
/* e.g. buffer or desc list */
|
||||
dma_addr_t data;
|
||||
union {
|
||||
/* simple buffer */
|
||||
unsigned int nbytes;
|
||||
/* Rx descriptor list */
|
||||
unsigned int ndesc;
|
||||
} u;
|
||||
/* externally-specified flags; OR-ed with internal flags */
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
struct ce_sendlist {
|
||||
unsigned int num_items;
|
||||
struct ce_sendlist_item item[CE_SENDLIST_ITEMS_MAX];
|
||||
};
|
||||
|
||||
/* Copy Engine settable attributes */
|
||||
struct ce_attr;
|
||||
|
||||
/*==================Send====================*/
|
||||
|
||||
/* ath10k_ce_send flags */
|
||||
#define CE_SEND_FLAG_BYTE_SWAP 1
|
||||
|
||||
/*
|
||||
* Queue a source buffer to be sent to an anonymous destination buffer.
|
||||
* ce - which copy engine to use
|
||||
* buffer - address of buffer
|
||||
* nbytes - number of bytes to send
|
||||
* transfer_id - arbitrary ID; reflected to destination
|
||||
* flags - CE_SEND_FLAG_* values
|
||||
* Returns 0 on success; otherwise an error status.
|
||||
*
|
||||
* Note: If no flags are specified, use CE's default data swap mode.
|
||||
*
|
||||
* Implementation note: pushes 1 buffer to Source ring
|
||||
*/
|
||||
int ath10k_ce_send(struct ce_state *ce_state,
|
||||
void *per_transfer_send_context,
|
||||
u32 buffer,
|
||||
unsigned int nbytes,
|
||||
/* 14 bits */
|
||||
unsigned int transfer_id,
|
||||
unsigned int flags);
|
||||
|
||||
void ath10k_ce_send_cb_register(struct ce_state *ce_state,
|
||||
void (*send_cb) (struct ce_state *ce_state,
|
||||
void *transfer_context,
|
||||
u32 buffer,
|
||||
unsigned int nbytes,
|
||||
unsigned int transfer_id),
|
||||
int disable_interrupts);
|
||||
|
||||
/* Append a simple buffer (address/length) to a sendlist. */
|
||||
void ath10k_ce_sendlist_buf_add(struct ce_sendlist *sendlist,
|
||||
u32 buffer,
|
||||
unsigned int nbytes,
|
||||
/* OR-ed with internal flags */
|
||||
u32 flags);
|
||||
|
||||
/*
|
||||
* Queue a "sendlist" of buffers to be sent using gather to a single
|
||||
* anonymous destination buffer
|
||||
* ce - which copy engine to use
|
||||
* sendlist - list of simple buffers to send using gather
|
||||
* transfer_id - arbitrary ID; reflected to destination
|
||||
* Returns 0 on success; otherwise an error status.
|
||||
*
|
||||
* Implemenation note: Pushes multiple buffers with Gather to Source ring.
|
||||
*/
|
||||
int ath10k_ce_sendlist_send(struct ce_state *ce_state,
|
||||
void *per_transfer_send_context,
|
||||
struct ce_sendlist *sendlist,
|
||||
/* 14 bits */
|
||||
unsigned int transfer_id);
|
||||
|
||||
/*==================Recv=======================*/
|
||||
|
||||
/*
|
||||
* Make a buffer available to receive. The buffer must be at least of a
|
||||
* minimal size appropriate for this copy engine (src_sz_max attribute).
|
||||
* ce - which copy engine to use
|
||||
* per_transfer_recv_context - context passed back to caller's recv_cb
|
||||
* buffer - address of buffer in CE space
|
||||
* Returns 0 on success; otherwise an error status.
|
||||
*
|
||||
* Implemenation note: Pushes a buffer to Dest ring.
|
||||
*/
|
||||
int ath10k_ce_recv_buf_enqueue(struct ce_state *ce_state,
|
||||
void *per_transfer_recv_context,
|
||||
u32 buffer);
|
||||
|
||||
void ath10k_ce_recv_cb_register(struct ce_state *ce_state,
|
||||
void (*recv_cb) (struct ce_state *ce_state,
|
||||
void *transfer_context,
|
||||
u32 buffer,
|
||||
unsigned int nbytes,
|
||||
unsigned int transfer_id,
|
||||
unsigned int flags));
|
||||
|
||||
/* recv flags */
|
||||
/* Data is byte-swapped */
|
||||
#define CE_RECV_FLAG_SWAPPED 1
|
||||
|
||||
/*
|
||||
* Supply data for the next completed unprocessed receive descriptor.
|
||||
* Pops buffer from Dest ring.
|
||||
*/
|
||||
int ath10k_ce_completed_recv_next(struct ce_state *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
u32 *bufferp,
|
||||
unsigned int *nbytesp,
|
||||
unsigned int *transfer_idp,
|
||||
unsigned int *flagsp);
|
||||
/*
|
||||
* Supply data for the next completed unprocessed send descriptor.
|
||||
* Pops 1 completed send buffer from Source ring.
|
||||
*/
|
||||
int ath10k_ce_completed_send_next(struct ce_state *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
u32 *bufferp,
|
||||
unsigned int *nbytesp,
|
||||
unsigned int *transfer_idp);
|
||||
|
||||
/*==================CE Engine Initialization=======================*/
|
||||
|
||||
/* Initialize an instance of a CE */
|
||||
struct ce_state *ath10k_ce_init(struct ath10k *ar,
|
||||
unsigned int ce_id,
|
||||
const struct ce_attr *attr);
|
||||
|
||||
/*==================CE Engine Shutdown=======================*/
|
||||
/*
|
||||
* Support clean shutdown by allowing the caller to revoke
|
||||
* receive buffers. Target DMA must be stopped before using
|
||||
* this API.
|
||||
*/
|
||||
int ath10k_ce_revoke_recv_next(struct ce_state *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
u32 *bufferp);
|
||||
|
||||
/*
|
||||
* Support clean shutdown by allowing the caller to cancel
|
||||
* pending sends. Target DMA must be stopped before using
|
||||
* this API.
|
||||
*/
|
||||
int ath10k_ce_cancel_send_next(struct ce_state *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
u32 *bufferp,
|
||||
unsigned int *nbytesp,
|
||||
unsigned int *transfer_idp);
|
||||
|
||||
void ath10k_ce_deinit(struct ce_state *ce_state);
|
||||
|
||||
/*==================CE Interrupt Handlers====================*/
|
||||
void ath10k_ce_per_engine_service_any(struct ath10k *ar);
|
||||
void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id);
|
||||
void ath10k_ce_disable_interrupts(struct ath10k *ar);
|
||||
|
||||
/* ce_attr.flags values */
|
||||
/* Use NonSnooping PCIe accesses? */
|
||||
#define CE_ATTR_NO_SNOOP 1
|
||||
|
||||
/* Byte swap data words */
|
||||
#define CE_ATTR_BYTE_SWAP_DATA 2
|
||||
|
||||
/* Swizzle descriptors? */
|
||||
#define CE_ATTR_SWIZZLE_DESCRIPTORS 4
|
||||
|
||||
/* no interrupt on copy completion */
|
||||
#define CE_ATTR_DIS_INTR 8
|
||||
|
||||
/* Attributes of an instance of a Copy Engine */
|
||||
struct ce_attr {
|
||||
/* CE_ATTR_* values */
|
||||
unsigned int flags;
|
||||
|
||||
/* currently not in use */
|
||||
unsigned int priority;
|
||||
|
||||
/* #entries in source ring - Must be a power of 2 */
|
||||
unsigned int src_nentries;
|
||||
|
||||
/*
|
||||
* Max source send size for this CE.
|
||||
* This is also the minimum size of a destination buffer.
|
||||
*/
|
||||
unsigned int src_sz_max;
|
||||
|
||||
/* #entries in destination ring - Must be a power of 2 */
|
||||
unsigned int dest_nentries;
|
||||
|
||||
/* Future use */
|
||||
void *reserved;
|
||||
};
|
||||
|
||||
/*
|
||||
* When using sendlist_send to transfer multiple buffer fragments, the
|
||||
* transfer context of each fragment, except last one, will be filled
|
||||
* with CE_SENDLIST_ITEM_CTXT. ce_completed_send will return success for
|
||||
* each fragment done with send and the transfer context would be
|
||||
* CE_SENDLIST_ITEM_CTXT. Upper layer could use this to identify the
|
||||
* status of a send completion.
|
||||
*/
|
||||
#define CE_SENDLIST_ITEM_CTXT ((void *)0xcecebeef)
|
||||
|
||||
#define SR_BA_ADDRESS 0x0000
|
||||
#define SR_SIZE_ADDRESS 0x0004
|
||||
#define DR_BA_ADDRESS 0x0008
|
||||
#define DR_SIZE_ADDRESS 0x000c
|
||||
#define CE_CMD_ADDRESS 0x0018
|
||||
|
||||
#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_MSB 17
|
||||
#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB 17
|
||||
#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK 0x00020000
|
||||
#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_SET(x) \
|
||||
(((0 | (x)) << CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB) & \
|
||||
CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK)
|
||||
|
||||
#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MSB 16
|
||||
#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB 16
|
||||
#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK 0x00010000
|
||||
#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_GET(x) \
|
||||
(((x) & CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) >> \
|
||||
CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB)
|
||||
#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_SET(x) \
|
||||
(((0 | (x)) << CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB) & \
|
||||
CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK)
|
||||
|
||||
#define CE_CTRL1_DMAX_LENGTH_MSB 15
|
||||
#define CE_CTRL1_DMAX_LENGTH_LSB 0
|
||||
#define CE_CTRL1_DMAX_LENGTH_MASK 0x0000ffff
|
||||
#define CE_CTRL1_DMAX_LENGTH_GET(x) \
|
||||
(((x) & CE_CTRL1_DMAX_LENGTH_MASK) >> CE_CTRL1_DMAX_LENGTH_LSB)
|
||||
#define CE_CTRL1_DMAX_LENGTH_SET(x) \
|
||||
(((0 | (x)) << CE_CTRL1_DMAX_LENGTH_LSB) & CE_CTRL1_DMAX_LENGTH_MASK)
|
||||
|
||||
#define CE_CTRL1_ADDRESS 0x0010
|
||||
#define CE_CTRL1_HW_MASK 0x0007ffff
|
||||
#define CE_CTRL1_SW_MASK 0x0007ffff
|
||||
#define CE_CTRL1_HW_WRITE_MASK 0x00000000
|
||||
#define CE_CTRL1_SW_WRITE_MASK 0x0007ffff
|
||||
#define CE_CTRL1_RSTMASK 0xffffffff
|
||||
#define CE_CTRL1_RESET 0x00000080
|
||||
|
||||
#define CE_CMD_HALT_STATUS_MSB 3
|
||||
#define CE_CMD_HALT_STATUS_LSB 3
|
||||
#define CE_CMD_HALT_STATUS_MASK 0x00000008
|
||||
#define CE_CMD_HALT_STATUS_GET(x) \
|
||||
(((x) & CE_CMD_HALT_STATUS_MASK) >> CE_CMD_HALT_STATUS_LSB)
|
||||
#define CE_CMD_HALT_STATUS_SET(x) \
|
||||
(((0 | (x)) << CE_CMD_HALT_STATUS_LSB) & CE_CMD_HALT_STATUS_MASK)
|
||||
#define CE_CMD_HALT_STATUS_RESET 0
|
||||
#define CE_CMD_HALT_MSB 0
|
||||
#define CE_CMD_HALT_MASK 0x00000001
|
||||
|
||||
#define HOST_IE_COPY_COMPLETE_MSB 0
|
||||
#define HOST_IE_COPY_COMPLETE_LSB 0
|
||||
#define HOST_IE_COPY_COMPLETE_MASK 0x00000001
|
||||
#define HOST_IE_COPY_COMPLETE_GET(x) \
|
||||
(((x) & HOST_IE_COPY_COMPLETE_MASK) >> HOST_IE_COPY_COMPLETE_LSB)
|
||||
#define HOST_IE_COPY_COMPLETE_SET(x) \
|
||||
(((0 | (x)) << HOST_IE_COPY_COMPLETE_LSB) & HOST_IE_COPY_COMPLETE_MASK)
|
||||
#define HOST_IE_COPY_COMPLETE_RESET 0
|
||||
#define HOST_IE_ADDRESS 0x002c
|
||||
|
||||
#define HOST_IS_DST_RING_LOW_WATERMARK_MASK 0x00000010
|
||||
#define HOST_IS_DST_RING_HIGH_WATERMARK_MASK 0x00000008
|
||||
#define HOST_IS_SRC_RING_LOW_WATERMARK_MASK 0x00000004
|
||||
#define HOST_IS_SRC_RING_HIGH_WATERMARK_MASK 0x00000002
|
||||
#define HOST_IS_COPY_COMPLETE_MASK 0x00000001
|
||||
#define HOST_IS_ADDRESS 0x0030
|
||||
|
||||
#define MISC_IE_ADDRESS 0x0034
|
||||
|
||||
#define MISC_IS_AXI_ERR_MASK 0x00000400
|
||||
|
||||
#define MISC_IS_DST_ADDR_ERR_MASK 0x00000200
|
||||
#define MISC_IS_SRC_LEN_ERR_MASK 0x00000100
|
||||
#define MISC_IS_DST_MAX_LEN_VIO_MASK 0x00000080
|
||||
#define MISC_IS_DST_RING_OVERFLOW_MASK 0x00000040
|
||||
#define MISC_IS_SRC_RING_OVERFLOW_MASK 0x00000020
|
||||
|
||||
#define MISC_IS_ADDRESS 0x0038
|
||||
|
||||
#define SR_WR_INDEX_ADDRESS 0x003c
|
||||
|
||||
#define DST_WR_INDEX_ADDRESS 0x0040
|
||||
|
||||
#define CURRENT_SRRI_ADDRESS 0x0044
|
||||
|
||||
#define CURRENT_DRRI_ADDRESS 0x0048
|
||||
|
||||
#define SRC_WATERMARK_LOW_MSB 31
|
||||
#define SRC_WATERMARK_LOW_LSB 16
|
||||
#define SRC_WATERMARK_LOW_MASK 0xffff0000
|
||||
#define SRC_WATERMARK_LOW_GET(x) \
|
||||
(((x) & SRC_WATERMARK_LOW_MASK) >> SRC_WATERMARK_LOW_LSB)
|
||||
#define SRC_WATERMARK_LOW_SET(x) \
|
||||
(((0 | (x)) << SRC_WATERMARK_LOW_LSB) & SRC_WATERMARK_LOW_MASK)
|
||||
#define SRC_WATERMARK_LOW_RESET 0
|
||||
#define SRC_WATERMARK_HIGH_MSB 15
|
||||
#define SRC_WATERMARK_HIGH_LSB 0
|
||||
#define SRC_WATERMARK_HIGH_MASK 0x0000ffff
|
||||
#define SRC_WATERMARK_HIGH_GET(x) \
|
||||
(((x) & SRC_WATERMARK_HIGH_MASK) >> SRC_WATERMARK_HIGH_LSB)
|
||||
#define SRC_WATERMARK_HIGH_SET(x) \
|
||||
(((0 | (x)) << SRC_WATERMARK_HIGH_LSB) & SRC_WATERMARK_HIGH_MASK)
|
||||
#define SRC_WATERMARK_HIGH_RESET 0
|
||||
#define SRC_WATERMARK_ADDRESS 0x004c
|
||||
|
||||
#define DST_WATERMARK_LOW_LSB 16
|
||||
#define DST_WATERMARK_LOW_MASK 0xffff0000
|
||||
#define DST_WATERMARK_LOW_SET(x) \
|
||||
(((0 | (x)) << DST_WATERMARK_LOW_LSB) & DST_WATERMARK_LOW_MASK)
|
||||
#define DST_WATERMARK_LOW_RESET 0
|
||||
#define DST_WATERMARK_HIGH_MSB 15
|
||||
#define DST_WATERMARK_HIGH_LSB 0
|
||||
#define DST_WATERMARK_HIGH_MASK 0x0000ffff
|
||||
#define DST_WATERMARK_HIGH_GET(x) \
|
||||
(((x) & DST_WATERMARK_HIGH_MASK) >> DST_WATERMARK_HIGH_LSB)
|
||||
#define DST_WATERMARK_HIGH_SET(x) \
|
||||
(((0 | (x)) << DST_WATERMARK_HIGH_LSB) & DST_WATERMARK_HIGH_MASK)
|
||||
#define DST_WATERMARK_HIGH_RESET 0
|
||||
#define DST_WATERMARK_ADDRESS 0x0050
|
||||
|
||||
|
||||
static inline u32 ath10k_ce_base_address(unsigned int ce_id)
|
||||
{
|
||||
return CE0_BASE_ADDRESS + (CE1_BASE_ADDRESS - CE0_BASE_ADDRESS) * ce_id;
|
||||
}
|
||||
|
||||
#define CE_WATERMARK_MASK (HOST_IS_SRC_RING_LOW_WATERMARK_MASK | \
|
||||
HOST_IS_SRC_RING_HIGH_WATERMARK_MASK | \
|
||||
HOST_IS_DST_RING_LOW_WATERMARK_MASK | \
|
||||
HOST_IS_DST_RING_HIGH_WATERMARK_MASK)
|
||||
|
||||
#define CE_ERROR_MASK (MISC_IS_AXI_ERR_MASK | \
|
||||
MISC_IS_DST_ADDR_ERR_MASK | \
|
||||
MISC_IS_SRC_LEN_ERR_MASK | \
|
||||
MISC_IS_DST_MAX_LEN_VIO_MASK | \
|
||||
MISC_IS_DST_RING_OVERFLOW_MASK | \
|
||||
MISC_IS_SRC_RING_OVERFLOW_MASK)
|
||||
|
||||
#define CE_SRC_RING_TO_DESC(baddr, idx) \
|
||||
(&(((struct ce_desc *)baddr)[idx]))
|
||||
|
||||
#define CE_DEST_RING_TO_DESC(baddr, idx) \
|
||||
(&(((struct ce_desc *)baddr)[idx]))
|
||||
|
||||
/* Ring arithmetic (modulus number of entries in ring, which is a pwr of 2). */
|
||||
#define CE_RING_DELTA(nentries_mask, fromidx, toidx) \
|
||||
(((int)(toidx)-(int)(fromidx)) & (nentries_mask))
|
||||
|
||||
#define CE_RING_IDX_INCR(nentries_mask, idx) (((idx) + 1) & (nentries_mask))
|
||||
|
||||
#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB 8
|
||||
#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK 0x0000ff00
|
||||
#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET(x) \
|
||||
(((x) & CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK) >> \
|
||||
CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB)
|
||||
#define CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS 0x0000
|
||||
|
||||
#define CE_INTERRUPT_SUMMARY(ar) \
|
||||
CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET( \
|
||||
ath10k_pci_read32((ar), CE_WRAPPER_BASE_ADDRESS + \
|
||||
CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS))
|
||||
|
||||
#endif /* _CE_H_ */
|
|
@ -0,0 +1,665 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/firmware.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "mac.h"
|
||||
#include "htc.h"
|
||||
#include "hif.h"
|
||||
#include "wmi.h"
|
||||
#include "bmi.h"
|
||||
#include "debug.h"
|
||||
#include "htt.h"
|
||||
|
||||
unsigned int ath10k_debug_mask;
|
||||
static bool uart_print;
|
||||
static unsigned int ath10k_p2p;
|
||||
module_param_named(debug_mask, ath10k_debug_mask, uint, 0644);
|
||||
module_param(uart_print, bool, 0644);
|
||||
module_param_named(p2p, ath10k_p2p, uint, 0644);
|
||||
MODULE_PARM_DESC(debug_mask, "Debugging mask");
|
||||
MODULE_PARM_DESC(uart_print, "Uart target debugging");
|
||||
MODULE_PARM_DESC(p2p, "Enable ath10k P2P support");
|
||||
|
||||
static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
{
|
||||
.id = QCA988X_HW_1_0_VERSION,
|
||||
.name = "qca988x hw1.0",
|
||||
.patch_load_addr = QCA988X_HW_1_0_PATCH_LOAD_ADDR,
|
||||
.fw = {
|
||||
.dir = QCA988X_HW_1_0_FW_DIR,
|
||||
.fw = QCA988X_HW_1_0_FW_FILE,
|
||||
.otp = QCA988X_HW_1_0_OTP_FILE,
|
||||
.board = QCA988X_HW_1_0_BOARD_DATA_FILE,
|
||||
},
|
||||
},
|
||||
{
|
||||
.id = QCA988X_HW_2_0_VERSION,
|
||||
.name = "qca988x hw2.0",
|
||||
.patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR,
|
||||
.fw = {
|
||||
.dir = QCA988X_HW_2_0_FW_DIR,
|
||||
.fw = QCA988X_HW_2_0_FW_FILE,
|
||||
.otp = QCA988X_HW_2_0_OTP_FILE,
|
||||
.board = QCA988X_HW_2_0_BOARD_DATA_FILE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static void ath10k_send_suspend_complete(struct ath10k *ar)
|
||||
{
|
||||
ath10k_dbg(ATH10K_DBG_CORE, "%s\n", __func__);
|
||||
|
||||
ar->is_target_paused = true;
|
||||
wake_up(&ar->event_queue);
|
||||
}
|
||||
|
||||
static int ath10k_check_fw_version(struct ath10k *ar)
|
||||
{
|
||||
char version[32];
|
||||
|
||||
if (ar->fw_version_major >= SUPPORTED_FW_MAJOR &&
|
||||
ar->fw_version_minor >= SUPPORTED_FW_MINOR &&
|
||||
ar->fw_version_release >= SUPPORTED_FW_RELEASE &&
|
||||
ar->fw_version_build >= SUPPORTED_FW_BUILD)
|
||||
return 0;
|
||||
|
||||
snprintf(version, sizeof(version), "%u.%u.%u.%u",
|
||||
SUPPORTED_FW_MAJOR, SUPPORTED_FW_MINOR,
|
||||
SUPPORTED_FW_RELEASE, SUPPORTED_FW_BUILD);
|
||||
|
||||
ath10k_warn("WARNING: Firmware version %s is not officially supported.\n",
|
||||
ar->hw->wiphy->fw_version);
|
||||
ath10k_warn("Please upgrade to version %s (or newer)\n", version);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_init_connect_htc(struct ath10k *ar)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = ath10k_wmi_connect_htc_service(ar);
|
||||
if (status)
|
||||
goto conn_fail;
|
||||
|
||||
/* Start HTC */
|
||||
status = ath10k_htc_start(ar->htc);
|
||||
if (status)
|
||||
goto conn_fail;
|
||||
|
||||
/* Wait for WMI event to be ready */
|
||||
status = ath10k_wmi_wait_for_service_ready(ar);
|
||||
if (status <= 0) {
|
||||
ath10k_warn("wmi service ready event not received");
|
||||
status = -ETIMEDOUT;
|
||||
goto timeout;
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_CORE, "core wmi ready\n");
|
||||
return 0;
|
||||
|
||||
timeout:
|
||||
ath10k_htc_stop(ar->htc);
|
||||
conn_fail:
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ath10k_init_configure_target(struct ath10k *ar)
|
||||
{
|
||||
u32 param_host;
|
||||
int ret;
|
||||
|
||||
/* tell target which HTC version it is used*/
|
||||
ret = ath10k_bmi_write32(ar, hi_app_host_interest,
|
||||
HTC_PROTOCOL_VERSION);
|
||||
if (ret) {
|
||||
ath10k_err("settings HTC version failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* set the firmware mode to STA/IBSS/AP */
|
||||
ret = ath10k_bmi_read32(ar, hi_option_flag, ¶m_host);
|
||||
if (ret) {
|
||||
ath10k_err("setting firmware mode (1/2) failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* TODO following parameters need to be re-visited. */
|
||||
/* num_device */
|
||||
param_host |= (1 << HI_OPTION_NUM_DEV_SHIFT);
|
||||
/* Firmware mode */
|
||||
/* FIXME: Why FW_MODE_AP ??.*/
|
||||
param_host |= (HI_OPTION_FW_MODE_AP << HI_OPTION_FW_MODE_SHIFT);
|
||||
/* mac_addr_method */
|
||||
param_host |= (1 << HI_OPTION_MAC_ADDR_METHOD_SHIFT);
|
||||
/* firmware_bridge */
|
||||
param_host |= (0 << HI_OPTION_FW_BRIDGE_SHIFT);
|
||||
/* fwsubmode */
|
||||
param_host |= (0 << HI_OPTION_FW_SUBMODE_SHIFT);
|
||||
|
||||
ret = ath10k_bmi_write32(ar, hi_option_flag, param_host);
|
||||
if (ret) {
|
||||
ath10k_err("setting firmware mode (2/2) failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* We do all byte-swapping on the host */
|
||||
ret = ath10k_bmi_write32(ar, hi_be, 0);
|
||||
if (ret) {
|
||||
ath10k_err("setting host CPU BE mode failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* FW descriptor/Data swap flags */
|
||||
ret = ath10k_bmi_write32(ar, hi_fw_swap, 0);
|
||||
|
||||
if (ret) {
|
||||
ath10k_err("setting FW data/desc swap flags failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar,
|
||||
const char *dir,
|
||||
const char *file)
|
||||
{
|
||||
char filename[100];
|
||||
const struct firmware *fw;
|
||||
int ret;
|
||||
|
||||
if (file == NULL)
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
if (dir == NULL)
|
||||
dir = ".";
|
||||
|
||||
snprintf(filename, sizeof(filename), "%s/%s", dir, file);
|
||||
ret = request_firmware(&fw, filename, ar->dev);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return fw;
|
||||
}
|
||||
|
||||
static int ath10k_push_board_ext_data(struct ath10k *ar,
|
||||
const struct firmware *fw)
|
||||
{
|
||||
u32 board_data_size = QCA988X_BOARD_DATA_SZ;
|
||||
u32 board_ext_data_size = QCA988X_BOARD_EXT_DATA_SZ;
|
||||
u32 board_ext_data_addr;
|
||||
int ret;
|
||||
|
||||
ret = ath10k_bmi_read32(ar, hi_board_ext_data, &board_ext_data_addr);
|
||||
if (ret) {
|
||||
ath10k_err("could not read board ext data addr (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_CORE,
|
||||
"ath10k: Board extended Data download addr: 0x%x\n",
|
||||
board_ext_data_addr);
|
||||
|
||||
if (board_ext_data_addr == 0)
|
||||
return 0;
|
||||
|
||||
if (fw->size != (board_data_size + board_ext_data_size)) {
|
||||
ath10k_err("invalid board (ext) data sizes %zu != %d+%d\n",
|
||||
fw->size, board_data_size, board_ext_data_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = ath10k_bmi_write_memory(ar, board_ext_data_addr,
|
||||
fw->data + board_data_size,
|
||||
board_ext_data_size);
|
||||
if (ret) {
|
||||
ath10k_err("could not write board ext data (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath10k_bmi_write32(ar, hi_board_ext_data_config,
|
||||
(board_ext_data_size << 16) | 1);
|
||||
if (ret) {
|
||||
ath10k_err("could not write board ext data bit (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_download_board_data(struct ath10k *ar)
|
||||
{
|
||||
u32 board_data_size = QCA988X_BOARD_DATA_SZ;
|
||||
u32 address;
|
||||
const struct firmware *fw;
|
||||
int ret;
|
||||
|
||||
fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir,
|
||||
ar->hw_params.fw.board);
|
||||
if (IS_ERR(fw)) {
|
||||
ath10k_err("could not fetch board data fw file (%ld)\n",
|
||||
PTR_ERR(fw));
|
||||
return PTR_ERR(fw);
|
||||
}
|
||||
|
||||
ret = ath10k_push_board_ext_data(ar, fw);
|
||||
if (ret) {
|
||||
ath10k_err("could not push board ext data (%d)\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = ath10k_bmi_read32(ar, hi_board_data, &address);
|
||||
if (ret) {
|
||||
ath10k_err("could not read board data addr (%d)\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = ath10k_bmi_write_memory(ar, address, fw->data,
|
||||
min_t(u32, board_data_size, fw->size));
|
||||
if (ret) {
|
||||
ath10k_err("could not write board data (%d)\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = ath10k_bmi_write32(ar, hi_board_data_initialized, 1);
|
||||
if (ret) {
|
||||
ath10k_err("could not write board data bit (%d)\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
release_firmware(fw);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_download_and_run_otp(struct ath10k *ar)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
u32 address;
|
||||
u32 exec_param;
|
||||
int ret;
|
||||
|
||||
/* OTP is optional */
|
||||
|
||||
if (ar->hw_params.fw.otp == NULL) {
|
||||
ath10k_info("otp file not defined\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
address = ar->hw_params.patch_load_addr;
|
||||
|
||||
fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir,
|
||||
ar->hw_params.fw.otp);
|
||||
if (IS_ERR(fw)) {
|
||||
ath10k_warn("could not fetch otp (%ld)\n", PTR_ERR(fw));
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size);
|
||||
if (ret) {
|
||||
ath10k_err("could not write otp (%d)\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exec_param = 0;
|
||||
ret = ath10k_bmi_execute(ar, address, &exec_param);
|
||||
if (ret) {
|
||||
ath10k_err("could not execute otp (%d)\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
release_firmware(fw);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_download_fw(struct ath10k *ar)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
u32 address;
|
||||
int ret;
|
||||
|
||||
if (ar->hw_params.fw.fw == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
address = ar->hw_params.patch_load_addr;
|
||||
|
||||
fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir,
|
||||
ar->hw_params.fw.fw);
|
||||
if (IS_ERR(fw)) {
|
||||
ath10k_err("could not fetch fw (%ld)\n", PTR_ERR(fw));
|
||||
return PTR_ERR(fw);
|
||||
}
|
||||
|
||||
ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size);
|
||||
if (ret) {
|
||||
ath10k_err("could not write fw (%d)\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
release_firmware(fw);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_init_download_firmware(struct ath10k *ar)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ath10k_download_board_data(ar);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ath10k_download_and_run_otp(ar);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ath10k_download_fw(ar);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_init_uart(struct ath10k *ar)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Explicitly setting UART prints to zero as target turns it on
|
||||
* based on scratch registers.
|
||||
*/
|
||||
ret = ath10k_bmi_write32(ar, hi_serial_enable, 0);
|
||||
if (ret) {
|
||||
ath10k_warn("could not disable UART prints (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!uart_print) {
|
||||
ath10k_info("UART prints disabled\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, 7);
|
||||
if (ret) {
|
||||
ath10k_warn("could not enable UART prints (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath10k_bmi_write32(ar, hi_serial_enable, 1);
|
||||
if (ret) {
|
||||
ath10k_warn("could not enable UART prints (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ath10k_info("UART prints enabled\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_init_hw_params(struct ath10k *ar)
|
||||
{
|
||||
const struct ath10k_hw_params *uninitialized_var(hw_params);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ath10k_hw_params_list); i++) {
|
||||
hw_params = &ath10k_hw_params_list[i];
|
||||
|
||||
if (hw_params->id == ar->target_version)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(ath10k_hw_params_list)) {
|
||||
ath10k_err("Unsupported hardware version: 0x%x\n",
|
||||
ar->target_version);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ar->hw_params = *hw_params;
|
||||
|
||||
ath10k_info("Hardware name %s version 0x%x\n",
|
||||
ar->hw_params.name, ar->target_version);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
|
||||
enum ath10k_bus bus,
|
||||
const struct ath10k_hif_ops *hif_ops)
|
||||
{
|
||||
struct ath10k *ar;
|
||||
|
||||
ar = ath10k_mac_create();
|
||||
if (!ar)
|
||||
return NULL;
|
||||
|
||||
ar->ath_common.priv = ar;
|
||||
ar->ath_common.hw = ar->hw;
|
||||
|
||||
ar->p2p = !!ath10k_p2p;
|
||||
ar->dev = dev;
|
||||
|
||||
ar->hif.priv = hif_priv;
|
||||
ar->hif.ops = hif_ops;
|
||||
ar->hif.bus = bus;
|
||||
|
||||
ar->free_vdev_map = 0xFF; /* 8 vdevs */
|
||||
|
||||
init_completion(&ar->scan.started);
|
||||
init_completion(&ar->scan.completed);
|
||||
init_completion(&ar->scan.on_channel);
|
||||
|
||||
init_completion(&ar->install_key_done);
|
||||
init_completion(&ar->vdev_setup_done);
|
||||
|
||||
setup_timer(&ar->scan.timeout, ath10k_reset_scan, (unsigned long)ar);
|
||||
|
||||
ar->workqueue = create_singlethread_workqueue("ath10k_wq");
|
||||
if (!ar->workqueue)
|
||||
goto err_wq;
|
||||
|
||||
mutex_init(&ar->conf_mutex);
|
||||
spin_lock_init(&ar->data_lock);
|
||||
|
||||
INIT_LIST_HEAD(&ar->peers);
|
||||
init_waitqueue_head(&ar->peer_mapping_wq);
|
||||
|
||||
init_completion(&ar->offchan_tx_completed);
|
||||
INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work);
|
||||
skb_queue_head_init(&ar->offchan_tx_queue);
|
||||
|
||||
init_waitqueue_head(&ar->event_queue);
|
||||
|
||||
return ar;
|
||||
|
||||
err_wq:
|
||||
ath10k_mac_destroy(ar);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_core_create);
|
||||
|
||||
void ath10k_core_destroy(struct ath10k *ar)
|
||||
{
|
||||
flush_workqueue(ar->workqueue);
|
||||
destroy_workqueue(ar->workqueue);
|
||||
|
||||
ath10k_mac_destroy(ar);
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_core_destroy);
|
||||
|
||||
|
||||
int ath10k_core_register(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_htc_ops htc_ops;
|
||||
struct bmi_target_info target_info;
|
||||
int status;
|
||||
|
||||
memset(&target_info, 0, sizeof(target_info));
|
||||
status = ath10k_bmi_get_target_info(ar, &target_info);
|
||||
if (status)
|
||||
goto err;
|
||||
|
||||
ar->target_version = target_info.version;
|
||||
ar->hw->wiphy->hw_version = target_info.version;
|
||||
|
||||
status = ath10k_init_hw_params(ar);
|
||||
if (status)
|
||||
goto err;
|
||||
|
||||
if (ath10k_init_configure_target(ar)) {
|
||||
status = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
status = ath10k_init_download_firmware(ar);
|
||||
if (status)
|
||||
goto err;
|
||||
|
||||
status = ath10k_init_uart(ar);
|
||||
if (status)
|
||||
goto err;
|
||||
|
||||
htc_ops.target_send_suspend_complete = ath10k_send_suspend_complete;
|
||||
|
||||
ar->htc = ath10k_htc_create(ar, &htc_ops);
|
||||
if (IS_ERR(ar->htc)) {
|
||||
status = PTR_ERR(ar->htc);
|
||||
ath10k_err("could not create HTC (%d)\n", status);
|
||||
goto err;
|
||||
}
|
||||
|
||||
status = ath10k_bmi_done(ar);
|
||||
if (status)
|
||||
goto err_htc_destroy;
|
||||
|
||||
status = ath10k_wmi_attach(ar);
|
||||
if (status) {
|
||||
ath10k_err("WMI attach failed: %d\n", status);
|
||||
goto err_htc_destroy;
|
||||
}
|
||||
|
||||
status = ath10k_htc_wait_target(ar->htc);
|
||||
if (status)
|
||||
goto err_wmi_detach;
|
||||
|
||||
ar->htt = ath10k_htt_attach(ar);
|
||||
if (!ar->htt) {
|
||||
status = -ENOMEM;
|
||||
goto err_wmi_detach;
|
||||
}
|
||||
|
||||
status = ath10k_init_connect_htc(ar);
|
||||
if (status)
|
||||
goto err_htt_detach;
|
||||
|
||||
ath10k_info("firmware %s booted\n", ar->hw->wiphy->fw_version);
|
||||
|
||||
status = ath10k_check_fw_version(ar);
|
||||
if (status)
|
||||
goto err_disconnect_htc;
|
||||
|
||||
status = ath10k_wmi_cmd_init(ar);
|
||||
if (status) {
|
||||
ath10k_err("could not send WMI init command (%d)\n", status);
|
||||
goto err_disconnect_htc;
|
||||
}
|
||||
|
||||
status = ath10k_wmi_wait_for_unified_ready(ar);
|
||||
if (status <= 0) {
|
||||
ath10k_err("wmi unified ready event not received\n");
|
||||
status = -ETIMEDOUT;
|
||||
goto err_disconnect_htc;
|
||||
}
|
||||
|
||||
status = ath10k_htt_attach_target(ar->htt);
|
||||
if (status)
|
||||
goto err_disconnect_htc;
|
||||
|
||||
status = ath10k_mac_register(ar);
|
||||
if (status)
|
||||
goto err_disconnect_htc;
|
||||
|
||||
status = ath10k_debug_create(ar);
|
||||
if (status) {
|
||||
ath10k_err("unable to initialize debugfs\n");
|
||||
goto err_unregister_mac;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unregister_mac:
|
||||
ath10k_mac_unregister(ar);
|
||||
err_disconnect_htc:
|
||||
ath10k_htc_stop(ar->htc);
|
||||
err_htt_detach:
|
||||
ath10k_htt_detach(ar->htt);
|
||||
err_wmi_detach:
|
||||
ath10k_wmi_detach(ar);
|
||||
err_htc_destroy:
|
||||
ath10k_htc_destroy(ar->htc);
|
||||
err:
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_core_register);
|
||||
|
||||
void ath10k_core_unregister(struct ath10k *ar)
|
||||
{
|
||||
/* We must unregister from mac80211 before we stop HTC and HIF.
|
||||
* Otherwise we will fail to submit commands to FW and mac80211 will be
|
||||
* unhappy about callback failures. */
|
||||
ath10k_mac_unregister(ar);
|
||||
ath10k_htc_stop(ar->htc);
|
||||
ath10k_htt_detach(ar->htt);
|
||||
ath10k_wmi_detach(ar);
|
||||
ath10k_htc_destroy(ar->htc);
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_core_unregister);
|
||||
|
||||
int ath10k_core_target_suspend(struct ath10k *ar)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_CORE, "%s: called", __func__);
|
||||
|
||||
ret = ath10k_wmi_pdev_suspend_target(ar);
|
||||
if (ret)
|
||||
ath10k_warn("could not suspend target (%d)\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_core_target_suspend);
|
||||
|
||||
int ath10k_core_target_resume(struct ath10k *ar)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_CORE, "%s: called", __func__);
|
||||
|
||||
ret = ath10k_wmi_pdev_resume_target(ar);
|
||||
if (ret)
|
||||
ath10k_warn("could not resume target (%d)\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_core_target_resume);
|
||||
|
||||
MODULE_AUTHOR("Qualcomm Atheros");
|
||||
MODULE_DESCRIPTION("Core module for QCA988X PCIe devices.");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
|
@ -0,0 +1,369 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2013 Qualcomm Atheros, 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/completion.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "htc.h"
|
||||
#include "hw.h"
|
||||
#include "targaddrs.h"
|
||||
#include "wmi.h"
|
||||
#include "../ath.h"
|
||||
#include "../regd.h"
|
||||
|
||||
#define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB)
|
||||
#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
|
||||
#define WO(_f) ((_f##_OFFSET) >> 2)
|
||||
|
||||
#define ATH10K_SCAN_ID 0
|
||||
#define WMI_READY_TIMEOUT (5 * HZ)
|
||||
#define ATH10K_FLUSH_TIMEOUT_HZ (5*HZ)
|
||||
|
||||
/* Antenna noise floor */
|
||||
#define ATH10K_DEFAULT_NOISE_FLOOR -95
|
||||
|
||||
struct ath10k;
|
||||
|
||||
enum ath10k_bus {
|
||||
ATH10K_BUS_PCI,
|
||||
};
|
||||
|
||||
struct ath10k_skb_cb {
|
||||
dma_addr_t paddr;
|
||||
bool is_mapped;
|
||||
bool is_aborted;
|
||||
|
||||
struct {
|
||||
u8 vdev_id;
|
||||
u16 msdu_id;
|
||||
u8 tid;
|
||||
bool is_offchan;
|
||||
bool is_conf;
|
||||
bool discard;
|
||||
bool no_ack;
|
||||
u8 refcount;
|
||||
struct sk_buff *txfrag;
|
||||
struct sk_buff *msdu;
|
||||
} __packed htt;
|
||||
|
||||
/* 4 bytes left on 64bit arch */
|
||||
} __packed;
|
||||
|
||||
static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb)
|
||||
{
|
||||
BUILD_BUG_ON(sizeof(struct ath10k_skb_cb) >
|
||||
IEEE80211_TX_INFO_DRIVER_DATA_SIZE);
|
||||
return (struct ath10k_skb_cb *)&IEEE80211_SKB_CB(skb)->driver_data;
|
||||
}
|
||||
|
||||
static inline int ath10k_skb_map(struct device *dev, struct sk_buff *skb)
|
||||
{
|
||||
if (ATH10K_SKB_CB(skb)->is_mapped)
|
||||
return -EINVAL;
|
||||
|
||||
ATH10K_SKB_CB(skb)->paddr = dma_map_single(dev, skb->data, skb->len,
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
if (unlikely(dma_mapping_error(dev, ATH10K_SKB_CB(skb)->paddr)))
|
||||
return -EIO;
|
||||
|
||||
ATH10K_SKB_CB(skb)->is_mapped = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ath10k_skb_unmap(struct device *dev, struct sk_buff *skb)
|
||||
{
|
||||
if (!ATH10K_SKB_CB(skb)->is_mapped)
|
||||
return -EINVAL;
|
||||
|
||||
dma_unmap_single(dev, ATH10K_SKB_CB(skb)->paddr, skb->len,
|
||||
DMA_TO_DEVICE);
|
||||
ATH10K_SKB_CB(skb)->is_mapped = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u32 host_interest_item_address(u32 item_offset)
|
||||
{
|
||||
return QCA988X_HOST_INTEREST_ADDRESS + item_offset;
|
||||
}
|
||||
|
||||
struct ath10k_bmi {
|
||||
bool done_sent;
|
||||
};
|
||||
|
||||
struct ath10k_wmi {
|
||||
enum ath10k_htc_ep_id eid;
|
||||
struct completion service_ready;
|
||||
struct completion unified_ready;
|
||||
atomic_t pending_tx_count;
|
||||
wait_queue_head_t wq;
|
||||
|
||||
struct sk_buff_head wmi_event_list;
|
||||
struct work_struct wmi_event_work;
|
||||
};
|
||||
|
||||
struct ath10k_peer_stat {
|
||||
u8 peer_macaddr[ETH_ALEN];
|
||||
u32 peer_rssi;
|
||||
u32 peer_tx_rate;
|
||||
};
|
||||
|
||||
struct ath10k_target_stats {
|
||||
/* PDEV stats */
|
||||
s32 ch_noise_floor;
|
||||
u32 tx_frame_count;
|
||||
u32 rx_frame_count;
|
||||
u32 rx_clear_count;
|
||||
u32 cycle_count;
|
||||
u32 phy_err_count;
|
||||
u32 chan_tx_power;
|
||||
|
||||
/* PDEV TX stats */
|
||||
s32 comp_queued;
|
||||
s32 comp_delivered;
|
||||
s32 msdu_enqued;
|
||||
s32 mpdu_enqued;
|
||||
s32 wmm_drop;
|
||||
s32 local_enqued;
|
||||
s32 local_freed;
|
||||
s32 hw_queued;
|
||||
s32 hw_reaped;
|
||||
s32 underrun;
|
||||
s32 tx_abort;
|
||||
s32 mpdus_requed;
|
||||
u32 tx_ko;
|
||||
u32 data_rc;
|
||||
u32 self_triggers;
|
||||
u32 sw_retry_failure;
|
||||
u32 illgl_rate_phy_err;
|
||||
u32 pdev_cont_xretry;
|
||||
u32 pdev_tx_timeout;
|
||||
u32 pdev_resets;
|
||||
u32 phy_underrun;
|
||||
u32 txop_ovf;
|
||||
|
||||
/* PDEV RX stats */
|
||||
s32 mid_ppdu_route_change;
|
||||
s32 status_rcvd;
|
||||
s32 r0_frags;
|
||||
s32 r1_frags;
|
||||
s32 r2_frags;
|
||||
s32 r3_frags;
|
||||
s32 htt_msdus;
|
||||
s32 htt_mpdus;
|
||||
s32 loc_msdus;
|
||||
s32 loc_mpdus;
|
||||
s32 oversize_amsdu;
|
||||
s32 phy_errs;
|
||||
s32 phy_err_drop;
|
||||
s32 mpdu_errs;
|
||||
|
||||
/* VDEV STATS */
|
||||
|
||||
/* PEER STATS */
|
||||
u8 peers;
|
||||
struct ath10k_peer_stat peer_stat[TARGET_NUM_PEERS];
|
||||
|
||||
/* TODO: Beacon filter stats */
|
||||
|
||||
};
|
||||
|
||||
#define ATH10K_MAX_NUM_PEER_IDS (1 << 11) /* htt rx_desc limit */
|
||||
|
||||
struct ath10k_peer {
|
||||
struct list_head list;
|
||||
int vdev_id;
|
||||
u8 addr[ETH_ALEN];
|
||||
DECLARE_BITMAP(peer_ids, ATH10K_MAX_NUM_PEER_IDS);
|
||||
struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
|
||||
};
|
||||
|
||||
#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ)
|
||||
|
||||
struct ath10k_vif {
|
||||
u32 vdev_id;
|
||||
enum wmi_vdev_type vdev_type;
|
||||
enum wmi_vdev_subtype vdev_subtype;
|
||||
u32 beacon_interval;
|
||||
u32 dtim_period;
|
||||
|
||||
struct ath10k *ar;
|
||||
struct ieee80211_vif *vif;
|
||||
|
||||
struct ieee80211_key_conf *wep_keys[WMI_MAX_KEY_INDEX + 1];
|
||||
u8 def_wep_key_index;
|
||||
|
||||
u16 tx_seq_no;
|
||||
|
||||
union {
|
||||
struct {
|
||||
u8 bssid[ETH_ALEN];
|
||||
u32 uapsd;
|
||||
} sta;
|
||||
struct {
|
||||
/* 127 stations; wmi limit */
|
||||
u8 tim_bitmap[16];
|
||||
u8 tim_len;
|
||||
u32 ssid_len;
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
bool hidden_ssid;
|
||||
/* P2P_IE with NoA attribute for P2P_GO case */
|
||||
u32 noa_len;
|
||||
u8 *noa_data;
|
||||
} ap;
|
||||
struct {
|
||||
u8 bssid[ETH_ALEN];
|
||||
} ibss;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct ath10k_vif_iter {
|
||||
u32 vdev_id;
|
||||
struct ath10k_vif *arvif;
|
||||
};
|
||||
|
||||
struct ath10k_debug {
|
||||
struct dentry *debugfs_phy;
|
||||
|
||||
struct ath10k_target_stats target_stats;
|
||||
u32 wmi_service_bitmap[WMI_SERVICE_BM_SIZE];
|
||||
|
||||
struct completion event_stats_compl;
|
||||
};
|
||||
|
||||
struct ath10k {
|
||||
struct ath_common ath_common;
|
||||
struct ieee80211_hw *hw;
|
||||
struct device *dev;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
|
||||
u32 target_version;
|
||||
u8 fw_version_major;
|
||||
u32 fw_version_minor;
|
||||
u16 fw_version_release;
|
||||
u16 fw_version_build;
|
||||
u32 phy_capability;
|
||||
u32 hw_min_tx_power;
|
||||
u32 hw_max_tx_power;
|
||||
u32 ht_cap_info;
|
||||
u32 vht_cap_info;
|
||||
|
||||
struct targetdef *targetdef;
|
||||
struct hostdef *hostdef;
|
||||
|
||||
bool p2p;
|
||||
|
||||
struct {
|
||||
void *priv;
|
||||
enum ath10k_bus bus;
|
||||
const struct ath10k_hif_ops *ops;
|
||||
} hif;
|
||||
|
||||
struct ath10k_wmi wmi;
|
||||
|
||||
wait_queue_head_t event_queue;
|
||||
bool is_target_paused;
|
||||
|
||||
struct ath10k_bmi bmi;
|
||||
|
||||
struct ath10k_htc *htc;
|
||||
struct ath10k_htt *htt;
|
||||
|
||||
struct ath10k_hw_params {
|
||||
u32 id;
|
||||
const char *name;
|
||||
u32 patch_load_addr;
|
||||
|
||||
struct ath10k_hw_params_fw {
|
||||
const char *dir;
|
||||
const char *fw;
|
||||
const char *otp;
|
||||
const char *board;
|
||||
} fw;
|
||||
} hw_params;
|
||||
|
||||
struct {
|
||||
struct completion started;
|
||||
struct completion completed;
|
||||
struct completion on_channel;
|
||||
struct timer_list timeout;
|
||||
bool is_roc;
|
||||
bool in_progress;
|
||||
bool aborting;
|
||||
int vdev_id;
|
||||
int roc_freq;
|
||||
} scan;
|
||||
|
||||
struct {
|
||||
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
|
||||
} mac;
|
||||
|
||||
/* should never be NULL; needed for regular htt rx */
|
||||
struct ieee80211_channel *rx_channel;
|
||||
|
||||
/* valid during scan; needed for mgmt rx during scan */
|
||||
struct ieee80211_channel *scan_channel;
|
||||
|
||||
int free_vdev_map;
|
||||
int monitor_vdev_id;
|
||||
bool monitor_enabled;
|
||||
bool monitor_present;
|
||||
unsigned int filter_flags;
|
||||
|
||||
struct wmi_pdev_set_wmm_params_arg wmm_params;
|
||||
struct completion install_key_done;
|
||||
|
||||
struct completion vdev_setup_done;
|
||||
|
||||
struct workqueue_struct *workqueue;
|
||||
|
||||
/* prevents concurrent FW reconfiguration */
|
||||
struct mutex conf_mutex;
|
||||
|
||||
/* protects shared structure data */
|
||||
spinlock_t data_lock;
|
||||
|
||||
struct list_head peers;
|
||||
wait_queue_head_t peer_mapping_wq;
|
||||
|
||||
struct work_struct offchan_tx_work;
|
||||
struct sk_buff_head offchan_tx_queue;
|
||||
struct completion offchan_tx_completed;
|
||||
struct sk_buff *offchan_tx_skb;
|
||||
|
||||
#ifdef CONFIG_ATH10K_DEBUGFS
|
||||
struct ath10k_debug debug;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
|
||||
enum ath10k_bus bus,
|
||||
const struct ath10k_hif_ops *hif_ops);
|
||||
void ath10k_core_destroy(struct ath10k *ar);
|
||||
|
||||
int ath10k_core_register(struct ath10k *ar);
|
||||
void ath10k_core_unregister(struct ath10k *ar);
|
||||
|
||||
int ath10k_core_target_suspend(struct ath10k *ar);
|
||||
int ath10k_core_target_resume(struct ath10k *ar);
|
||||
|
||||
#endif /* _CORE_H_ */
|
|
@ -0,0 +1,503 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "debug.h"
|
||||
|
||||
static int ath10k_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("%sath10k: %pV", level, &vaf);
|
||||
|
||||
va_end(args);
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
int ath10k_info(const char *fmt, ...)
|
||||
{
|
||||
struct va_format vaf = {
|
||||
.fmt = fmt,
|
||||
};
|
||||
va_list args;
|
||||
int ret;
|
||||
|
||||
va_start(args, fmt);
|
||||
vaf.va = &args;
|
||||
ret = ath10k_printk(KERN_INFO, "%pV", &vaf);
|
||||
trace_ath10k_log_info(&vaf);
|
||||
va_end(args);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_info);
|
||||
|
||||
int ath10k_err(const char *fmt, ...)
|
||||
{
|
||||
struct va_format vaf = {
|
||||
.fmt = fmt,
|
||||
};
|
||||
va_list args;
|
||||
int ret;
|
||||
|
||||
va_start(args, fmt);
|
||||
vaf.va = &args;
|
||||
ret = ath10k_printk(KERN_ERR, "%pV", &vaf);
|
||||
trace_ath10k_log_err(&vaf);
|
||||
va_end(args);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_err);
|
||||
|
||||
int ath10k_warn(const char *fmt, ...)
|
||||
{
|
||||
struct va_format vaf = {
|
||||
.fmt = fmt,
|
||||
};
|
||||
va_list args;
|
||||
int ret = 0;
|
||||
|
||||
va_start(args, fmt);
|
||||
vaf.va = &args;
|
||||
|
||||
if (net_ratelimit())
|
||||
ret = ath10k_printk(KERN_WARNING, "%pV", &vaf);
|
||||
|
||||
trace_ath10k_log_warn(&vaf);
|
||||
|
||||
va_end(args);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_warn);
|
||||
|
||||
#ifdef CONFIG_ATH10K_DEBUGFS
|
||||
|
||||
void ath10k_debug_read_service_map(struct ath10k *ar,
|
||||
void *service_map,
|
||||
size_t map_size)
|
||||
{
|
||||
memcpy(ar->debug.wmi_service_bitmap, service_map, map_size);
|
||||
}
|
||||
|
||||
static ssize_t ath10k_read_wmi_services(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath10k *ar = file->private_data;
|
||||
char *buf;
|
||||
unsigned int len = 0, buf_len = 1500;
|
||||
const char *status;
|
||||
ssize_t ret_cnt;
|
||||
int i;
|
||||
|
||||
buf = kzalloc(buf_len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
if (len > buf_len)
|
||||
len = buf_len;
|
||||
|
||||
for (i = 0; i < WMI_SERVICE_LAST; i++) {
|
||||
if (WMI_SERVICE_IS_ENABLED(ar->debug.wmi_service_bitmap, i))
|
||||
status = "enabled";
|
||||
else
|
||||
status = "disabled";
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"0x%02x - %20s - %s\n",
|
||||
i, wmi_service_name(i), status);
|
||||
}
|
||||
|
||||
ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
kfree(buf);
|
||||
return ret_cnt;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_wmi_services = {
|
||||
.read = ath10k_read_wmi_services,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
void ath10k_debug_read_target_stats(struct ath10k *ar,
|
||||
struct wmi_stats_event *ev)
|
||||
{
|
||||
u8 *tmp = ev->data;
|
||||
struct ath10k_target_stats *stats;
|
||||
int num_pdev_stats, num_vdev_stats, num_peer_stats;
|
||||
struct wmi_pdev_stats *ps;
|
||||
int i;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
stats = &ar->debug.target_stats;
|
||||
|
||||
num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); /* 0 or 1 */
|
||||
num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); /* 0 or max vdevs */
|
||||
num_peer_stats = __le32_to_cpu(ev->num_peer_stats); /* 0 or max peers */
|
||||
|
||||
if (num_pdev_stats) {
|
||||
ps = (struct wmi_pdev_stats *)tmp;
|
||||
|
||||
stats->ch_noise_floor = __le32_to_cpu(ps->chan_nf);
|
||||
stats->tx_frame_count = __le32_to_cpu(ps->tx_frame_count);
|
||||
stats->rx_frame_count = __le32_to_cpu(ps->rx_frame_count);
|
||||
stats->rx_clear_count = __le32_to_cpu(ps->rx_clear_count);
|
||||
stats->cycle_count = __le32_to_cpu(ps->cycle_count);
|
||||
stats->phy_err_count = __le32_to_cpu(ps->phy_err_count);
|
||||
stats->chan_tx_power = __le32_to_cpu(ps->chan_tx_pwr);
|
||||
|
||||
stats->comp_queued = __le32_to_cpu(ps->wal.tx.comp_queued);
|
||||
stats->comp_delivered =
|
||||
__le32_to_cpu(ps->wal.tx.comp_delivered);
|
||||
stats->msdu_enqued = __le32_to_cpu(ps->wal.tx.msdu_enqued);
|
||||
stats->mpdu_enqued = __le32_to_cpu(ps->wal.tx.mpdu_enqued);
|
||||
stats->wmm_drop = __le32_to_cpu(ps->wal.tx.wmm_drop);
|
||||
stats->local_enqued = __le32_to_cpu(ps->wal.tx.local_enqued);
|
||||
stats->local_freed = __le32_to_cpu(ps->wal.tx.local_freed);
|
||||
stats->hw_queued = __le32_to_cpu(ps->wal.tx.hw_queued);
|
||||
stats->hw_reaped = __le32_to_cpu(ps->wal.tx.hw_reaped);
|
||||
stats->underrun = __le32_to_cpu(ps->wal.tx.underrun);
|
||||
stats->tx_abort = __le32_to_cpu(ps->wal.tx.tx_abort);
|
||||
stats->mpdus_requed = __le32_to_cpu(ps->wal.tx.mpdus_requed);
|
||||
stats->tx_ko = __le32_to_cpu(ps->wal.tx.tx_ko);
|
||||
stats->data_rc = __le32_to_cpu(ps->wal.tx.data_rc);
|
||||
stats->self_triggers = __le32_to_cpu(ps->wal.tx.self_triggers);
|
||||
stats->sw_retry_failure =
|
||||
__le32_to_cpu(ps->wal.tx.sw_retry_failure);
|
||||
stats->illgl_rate_phy_err =
|
||||
__le32_to_cpu(ps->wal.tx.illgl_rate_phy_err);
|
||||
stats->pdev_cont_xretry =
|
||||
__le32_to_cpu(ps->wal.tx.pdev_cont_xretry);
|
||||
stats->pdev_tx_timeout =
|
||||
__le32_to_cpu(ps->wal.tx.pdev_tx_timeout);
|
||||
stats->pdev_resets = __le32_to_cpu(ps->wal.tx.pdev_resets);
|
||||
stats->phy_underrun = __le32_to_cpu(ps->wal.tx.phy_underrun);
|
||||
stats->txop_ovf = __le32_to_cpu(ps->wal.tx.txop_ovf);
|
||||
|
||||
stats->mid_ppdu_route_change =
|
||||
__le32_to_cpu(ps->wal.rx.mid_ppdu_route_change);
|
||||
stats->status_rcvd = __le32_to_cpu(ps->wal.rx.status_rcvd);
|
||||
stats->r0_frags = __le32_to_cpu(ps->wal.rx.r0_frags);
|
||||
stats->r1_frags = __le32_to_cpu(ps->wal.rx.r1_frags);
|
||||
stats->r2_frags = __le32_to_cpu(ps->wal.rx.r2_frags);
|
||||
stats->r3_frags = __le32_to_cpu(ps->wal.rx.r3_frags);
|
||||
stats->htt_msdus = __le32_to_cpu(ps->wal.rx.htt_msdus);
|
||||
stats->htt_mpdus = __le32_to_cpu(ps->wal.rx.htt_mpdus);
|
||||
stats->loc_msdus = __le32_to_cpu(ps->wal.rx.loc_msdus);
|
||||
stats->loc_mpdus = __le32_to_cpu(ps->wal.rx.loc_mpdus);
|
||||
stats->oversize_amsdu =
|
||||
__le32_to_cpu(ps->wal.rx.oversize_amsdu);
|
||||
stats->phy_errs = __le32_to_cpu(ps->wal.rx.phy_errs);
|
||||
stats->phy_err_drop = __le32_to_cpu(ps->wal.rx.phy_err_drop);
|
||||
stats->mpdu_errs = __le32_to_cpu(ps->wal.rx.mpdu_errs);
|
||||
|
||||
tmp += sizeof(struct wmi_pdev_stats);
|
||||
}
|
||||
|
||||
/* 0 or max vdevs */
|
||||
/* Currently firmware does not support VDEV stats */
|
||||
if (num_vdev_stats) {
|
||||
struct wmi_vdev_stats *vdev_stats;
|
||||
|
||||
for (i = 0; i < num_vdev_stats; i++) {
|
||||
vdev_stats = (struct wmi_vdev_stats *)tmp;
|
||||
tmp += sizeof(struct wmi_vdev_stats);
|
||||
}
|
||||
}
|
||||
|
||||
if (num_peer_stats) {
|
||||
struct wmi_peer_stats *peer_stats;
|
||||
struct ath10k_peer_stat *s;
|
||||
|
||||
stats->peers = num_peer_stats;
|
||||
|
||||
for (i = 0; i < num_peer_stats; i++) {
|
||||
peer_stats = (struct wmi_peer_stats *)tmp;
|
||||
s = &stats->peer_stat[i];
|
||||
|
||||
WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_stats->peer_macaddr,
|
||||
s->peer_macaddr);
|
||||
s->peer_rssi = __le32_to_cpu(peer_stats->peer_rssi);
|
||||
s->peer_tx_rate =
|
||||
__le32_to_cpu(peer_stats->peer_tx_rate);
|
||||
|
||||
tmp += sizeof(struct wmi_peer_stats);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
complete(&ar->debug.event_stats_compl);
|
||||
}
|
||||
|
||||
static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath10k *ar = file->private_data;
|
||||
struct ath10k_target_stats *fw_stats;
|
||||
char *buf;
|
||||
unsigned int len = 0, buf_len = 2500;
|
||||
ssize_t ret_cnt;
|
||||
long left;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
fw_stats = &ar->debug.target_stats;
|
||||
|
||||
buf = kzalloc(buf_len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT);
|
||||
if (ret) {
|
||||
ath10k_warn("could not request stats (%d)\n", ret);
|
||||
kfree(buf);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
left = wait_for_completion_timeout(&ar->debug.event_stats_compl, 1*HZ);
|
||||
|
||||
if (left <= 0) {
|
||||
kfree(buf);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n",
|
||||
"ath10k PDEV stats");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
|
||||
"=================");
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Channel noise floor", fw_stats->ch_noise_floor);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"Channel TX power", fw_stats->chan_tx_power);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"TX frame count", fw_stats->tx_frame_count);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"RX frame count", fw_stats->rx_frame_count);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"RX clear count", fw_stats->rx_clear_count);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"Cycle count", fw_stats->cycle_count);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"PHY error count", fw_stats->phy_err_count);
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n",
|
||||
"ath10k PDEV TX stats");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
|
||||
"=================");
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"HTT cookies queued", fw_stats->comp_queued);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"HTT cookies disp.", fw_stats->comp_delivered);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MSDU queued", fw_stats->msdu_enqued);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MPDU queued", fw_stats->mpdu_enqued);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MSDUs dropped", fw_stats->wmm_drop);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Local enqued", fw_stats->local_enqued);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Local freed", fw_stats->local_freed);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"HW queued", fw_stats->hw_queued);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"PPDUs reaped", fw_stats->hw_reaped);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Num underruns", fw_stats->underrun);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"PPDUs cleaned", fw_stats->tx_abort);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MPDUs requed", fw_stats->mpdus_requed);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Excessive retries", fw_stats->tx_ko);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"HW rate", fw_stats->data_rc);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Sched self tiggers", fw_stats->self_triggers);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Dropped due to SW retries",
|
||||
fw_stats->sw_retry_failure);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Illegal rate phy errors",
|
||||
fw_stats->illgl_rate_phy_err);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Pdev continous xretry", fw_stats->pdev_cont_xretry);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"TX timeout", fw_stats->pdev_tx_timeout);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"PDEV resets", fw_stats->pdev_resets);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"PHY underrun", fw_stats->phy_underrun);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MPDU is more than txop limit", fw_stats->txop_ovf);
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n",
|
||||
"ath10k PDEV RX stats");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
|
||||
"=================");
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Mid PPDU route change",
|
||||
fw_stats->mid_ppdu_route_change);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Tot. number of statuses", fw_stats->status_rcvd);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Extra frags on rings 0", fw_stats->r0_frags);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Extra frags on rings 1", fw_stats->r1_frags);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Extra frags on rings 2", fw_stats->r2_frags);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Extra frags on rings 3", fw_stats->r3_frags);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MSDUs delivered to HTT", fw_stats->htt_msdus);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MPDUs delivered to HTT", fw_stats->htt_mpdus);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MSDUs delivered to stack", fw_stats->loc_msdus);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MPDUs delivered to stack", fw_stats->loc_mpdus);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"Oversized AMSUs", fw_stats->oversize_amsdu);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"PHY errors", fw_stats->phy_errs);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"PHY errors drops", fw_stats->phy_err_drop);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
|
||||
"MPDU errors (FCS, MIC, ENC)", fw_stats->mpdu_errs);
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n",
|
||||
"ath10k PEER stats");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
|
||||
"=================");
|
||||
|
||||
for (i = 0; i < fw_stats->peers; i++) {
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %pM\n",
|
||||
"Peer MAC address",
|
||||
fw_stats->peer_stat[i].peer_macaddr);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"Peer RSSI", fw_stats->peer_stat[i].peer_rssi);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"Peer TX rate",
|
||||
fw_stats->peer_stat[i].peer_tx_rate);
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
}
|
||||
|
||||
if (len > buf_len)
|
||||
len = buf_len;
|
||||
|
||||
ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
kfree(buf);
|
||||
return ret_cnt;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_fw_stats = {
|
||||
.read = ath10k_read_fw_stats,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
int ath10k_debug_create(struct ath10k *ar)
|
||||
{
|
||||
ar->debug.debugfs_phy = debugfs_create_dir("ath10k",
|
||||
ar->hw->wiphy->debugfsdir);
|
||||
|
||||
if (!ar->debug.debugfs_phy)
|
||||
return -ENOMEM;
|
||||
|
||||
init_completion(&ar->debug.event_stats_compl);
|
||||
|
||||
debugfs_create_file("fw_stats", S_IRUSR, ar->debug.debugfs_phy, ar,
|
||||
&fops_fw_stats);
|
||||
|
||||
debugfs_create_file("wmi_services", S_IRUSR, ar->debug.debugfs_phy, ar,
|
||||
&fops_wmi_services);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_ATH10K_DEBUGFS */
|
||||
|
||||
#ifdef CONFIG_ATH10K_DEBUG
|
||||
void ath10k_dbg(enum ath10k_debug_mask mask, const char *fmt, ...)
|
||||
{
|
||||
struct va_format vaf;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
|
||||
vaf.fmt = fmt;
|
||||
vaf.va = &args;
|
||||
|
||||
if (ath10k_debug_mask & mask)
|
||||
ath10k_printk(KERN_DEBUG, "%pV", &vaf);
|
||||
|
||||
trace_ath10k_log_dbg(mask, &vaf);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_dbg);
|
||||
|
||||
void ath10k_dbg_dump(enum ath10k_debug_mask mask,
|
||||
const char *msg, const char *prefix,
|
||||
const void *buf, size_t len)
|
||||
{
|
||||
if (ath10k_debug_mask & mask) {
|
||||
if (msg)
|
||||
ath10k_dbg(mask, "%s\n", msg);
|
||||
|
||||
print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len);
|
||||
}
|
||||
|
||||
/* tracing code doesn't like null strings :/ */
|
||||
trace_ath10k_log_dbg_dump(msg ? msg : "", prefix ? prefix : "",
|
||||
buf, len);
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_dbg_dump);
|
||||
|
||||
#endif /* CONFIG_ATH10K_DEBUG */
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2013 Qualcomm Atheros, 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 <linux/types.h>
|
||||
#include "trace.h"
|
||||
|
||||
enum ath10k_debug_mask {
|
||||
ATH10K_DBG_PCI = 0x00000001,
|
||||
ATH10K_DBG_WMI = 0x00000002,
|
||||
ATH10K_DBG_HTC = 0x00000004,
|
||||
ATH10K_DBG_HTT = 0x00000008,
|
||||
ATH10K_DBG_MAC = 0x00000010,
|
||||
ATH10K_DBG_CORE = 0x00000020,
|
||||
ATH10K_DBG_PCI_DUMP = 0x00000040,
|
||||
ATH10K_DBG_HTT_DUMP = 0x00000080,
|
||||
ATH10K_DBG_MGMT = 0x00000100,
|
||||
ATH10K_DBG_DATA = 0x00000200,
|
||||
ATH10K_DBG_ANY = 0xffffffff,
|
||||
};
|
||||
|
||||
extern unsigned int ath10k_debug_mask;
|
||||
|
||||
extern __printf(1, 2) int ath10k_info(const char *fmt, ...);
|
||||
extern __printf(1, 2) int ath10k_err(const char *fmt, ...);
|
||||
extern __printf(1, 2) int ath10k_warn(const char *fmt, ...);
|
||||
|
||||
#ifdef CONFIG_ATH10K_DEBUGFS
|
||||
int ath10k_debug_create(struct ath10k *ar);
|
||||
void ath10k_debug_read_service_map(struct ath10k *ar,
|
||||
void *service_map,
|
||||
size_t map_size);
|
||||
void ath10k_debug_read_target_stats(struct ath10k *ar,
|
||||
struct wmi_stats_event *ev);
|
||||
|
||||
#else
|
||||
static inline int ath10k_debug_create(struct ath10k *ar)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ath10k_debug_read_service_map(struct ath10k *ar,
|
||||
void *service_map,
|
||||
size_t map_size)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath10k_debug_read_target_stats(struct ath10k *ar,
|
||||
struct wmi_stats_event *ev)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_ATH10K_DEBUGFS */
|
||||
|
||||
#ifdef CONFIG_ATH10K_DEBUG
|
||||
extern __printf(2, 3) void ath10k_dbg(enum ath10k_debug_mask mask,
|
||||
const char *fmt, ...);
|
||||
void ath10k_dbg_dump(enum ath10k_debug_mask mask,
|
||||
const char *msg, const char *prefix,
|
||||
const void *buf, size_t len);
|
||||
#else /* CONFIG_ATH10K_DEBUG */
|
||||
|
||||
static inline int ath10k_dbg(enum ath10k_debug_mask dbg_mask,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ath10k_dbg_dump(enum ath10k_debug_mask mask,
|
||||
const char *msg, const char *prefix,
|
||||
const void *buf, size_t len)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_ATH10K_DEBUG */
|
||||
#endif /* _DEBUG_H_ */
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2013 Qualcomm Atheros, 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 <linux/kernel.h>
|
||||
#include "core.h"
|
||||
|
||||
struct ath10k_hif_cb {
|
||||
int (*tx_completion)(struct ath10k *ar,
|
||||
struct sk_buff *wbuf,
|
||||
unsigned transfer_id);
|
||||
int (*rx_completion)(struct ath10k *ar,
|
||||
struct sk_buff *wbuf,
|
||||
u8 pipe_id);
|
||||
};
|
||||
|
||||
struct ath10k_hif_ops {
|
||||
/* Send the head of a buffer to HIF for transmission to the target. */
|
||||
int (*send_head)(struct ath10k *ar, u8 pipe_id,
|
||||
unsigned int transfer_id,
|
||||
unsigned int nbytes,
|
||||
struct sk_buff *buf);
|
||||
|
||||
/*
|
||||
* API to handle HIF-specific BMI message exchanges, this API is
|
||||
* synchronous and only allowed to be called from a context that
|
||||
* can block (sleep)
|
||||
*/
|
||||
int (*exchange_bmi_msg)(struct ath10k *ar,
|
||||
void *request, u32 request_len,
|
||||
void *response, u32 *response_len);
|
||||
|
||||
int (*start)(struct ath10k *ar);
|
||||
|
||||
void (*stop)(struct ath10k *ar);
|
||||
|
||||
int (*map_service_to_pipe)(struct ath10k *ar, u16 service_id,
|
||||
u8 *ul_pipe, u8 *dl_pipe,
|
||||
int *ul_is_polled, int *dl_is_polled);
|
||||
|
||||
void (*get_default_pipe)(struct ath10k *ar, u8 *ul_pipe, u8 *dl_pipe);
|
||||
|
||||
/*
|
||||
* Check if prior sends have completed.
|
||||
*
|
||||
* Check whether the pipe in question has any completed
|
||||
* sends that have not yet been processed.
|
||||
* This function is only relevant for HIF pipes that are configured
|
||||
* to be polled rather than interrupt-driven.
|
||||
*/
|
||||
void (*send_complete_check)(struct ath10k *ar, u8 pipe_id, int force);
|
||||
|
||||
void (*init)(struct ath10k *ar,
|
||||
struct ath10k_hif_cb *callbacks);
|
||||
|
||||
u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id);
|
||||
};
|
||||
|
||||
|
||||
static inline int ath10k_hif_send_head(struct ath10k *ar, u8 pipe_id,
|
||||
unsigned int transfer_id,
|
||||
unsigned int nbytes,
|
||||
struct sk_buff *buf)
|
||||
{
|
||||
return ar->hif.ops->send_head(ar, pipe_id, transfer_id, nbytes, buf);
|
||||
}
|
||||
|
||||
static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar,
|
||||
void *request, u32 request_len,
|
||||
void *response, u32 *response_len)
|
||||
{
|
||||
return ar->hif.ops->exchange_bmi_msg(ar, request, request_len,
|
||||
response, response_len);
|
||||
}
|
||||
|
||||
static inline int ath10k_hif_start(struct ath10k *ar)
|
||||
{
|
||||
return ar->hif.ops->start(ar);
|
||||
}
|
||||
|
||||
static inline void ath10k_hif_stop(struct ath10k *ar)
|
||||
{
|
||||
return ar->hif.ops->stop(ar);
|
||||
}
|
||||
|
||||
static inline int ath10k_hif_map_service_to_pipe(struct ath10k *ar,
|
||||
u16 service_id,
|
||||
u8 *ul_pipe, u8 *dl_pipe,
|
||||
int *ul_is_polled,
|
||||
int *dl_is_polled)
|
||||
{
|
||||
return ar->hif.ops->map_service_to_pipe(ar, service_id,
|
||||
ul_pipe, dl_pipe,
|
||||
ul_is_polled, dl_is_polled);
|
||||
}
|
||||
|
||||
static inline void ath10k_hif_get_default_pipe(struct ath10k *ar,
|
||||
u8 *ul_pipe, u8 *dl_pipe)
|
||||
{
|
||||
ar->hif.ops->get_default_pipe(ar, ul_pipe, dl_pipe);
|
||||
}
|
||||
|
||||
static inline void ath10k_hif_send_complete_check(struct ath10k *ar,
|
||||
u8 pipe_id, int force)
|
||||
{
|
||||
ar->hif.ops->send_complete_check(ar, pipe_id, force);
|
||||
}
|
||||
|
||||
static inline void ath10k_hif_init(struct ath10k *ar,
|
||||
struct ath10k_hif_cb *callbacks)
|
||||
{
|
||||
ar->hif.ops->init(ar, callbacks);
|
||||
}
|
||||
|
||||
static inline u16 ath10k_hif_get_free_queue_number(struct ath10k *ar,
|
||||
u8 pipe_id)
|
||||
{
|
||||
return ar->hif.ops->get_free_queue_number(ar, pipe_id);
|
||||
}
|
||||
|
||||
#endif /* _HIF_H_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,368 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2013 Qualcomm Atheros, 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 <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/timer.h>
|
||||
|
||||
struct ath10k;
|
||||
|
||||
/****************/
|
||||
/* HTC protocol */
|
||||
/****************/
|
||||
|
||||
/*
|
||||
* HTC - host-target control protocol
|
||||
*
|
||||
* tx packets are generally <htc_hdr><payload>
|
||||
* rx packets are more complex: <htc_hdr><payload><trailer>
|
||||
*
|
||||
* The payload + trailer length is stored in len.
|
||||
* To get payload-only length one needs to payload - trailer_len.
|
||||
*
|
||||
* Trailer contains (possibly) multiple <htc_record>.
|
||||
* Each record is a id-len-value.
|
||||
*
|
||||
* HTC header flags, control_byte0, control_byte1
|
||||
* have different meaning depending whether its tx
|
||||
* or rx.
|
||||
*
|
||||
* Alignment: htc_hdr, payload and trailer are
|
||||
* 4-byte aligned.
|
||||
*/
|
||||
|
||||
enum ath10k_htc_tx_flags {
|
||||
ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE = 0x01,
|
||||
ATH10K_HTC_FLAG_SEND_BUNDLE = 0x02
|
||||
};
|
||||
|
||||
enum ath10k_htc_rx_flags {
|
||||
ATH10K_HTC_FLAG_TRAILER_PRESENT = 0x02,
|
||||
ATH10K_HTC_FLAG_BUNDLE_MASK = 0xF0
|
||||
};
|
||||
|
||||
struct ath10k_htc_hdr {
|
||||
u8 eid; /* @enum ath10k_htc_ep_id */
|
||||
u8 flags; /* @enum ath10k_htc_tx_flags, ath10k_htc_rx_flags */
|
||||
__le16 len;
|
||||
union {
|
||||
u8 trailer_len; /* for rx */
|
||||
u8 control_byte0;
|
||||
} __packed;
|
||||
union {
|
||||
u8 seq_no; /* for tx */
|
||||
u8 control_byte1;
|
||||
} __packed;
|
||||
u8 pad0;
|
||||
u8 pad1;
|
||||
} __packed __aligned(4);
|
||||
|
||||
enum ath10k_ath10k_htc_msg_id {
|
||||
ATH10K_HTC_MSG_READY_ID = 1,
|
||||
ATH10K_HTC_MSG_CONNECT_SERVICE_ID = 2,
|
||||
ATH10K_HTC_MSG_CONNECT_SERVICE_RESP_ID = 3,
|
||||
ATH10K_HTC_MSG_SETUP_COMPLETE_ID = 4,
|
||||
ATH10K_HTC_MSG_SETUP_COMPLETE_EX_ID = 5,
|
||||
ATH10K_HTC_MSG_SEND_SUSPEND_COMPLETE = 6
|
||||
};
|
||||
|
||||
enum ath10k_htc_version {
|
||||
ATH10K_HTC_VERSION_2P0 = 0x00, /* 2.0 */
|
||||
ATH10K_HTC_VERSION_2P1 = 0x01, /* 2.1 */
|
||||
};
|
||||
|
||||
enum ath10k_htc_conn_flags {
|
||||
ATH10K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_ONE_FOURTH = 0x0,
|
||||
ATH10K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_ONE_HALF = 0x1,
|
||||
ATH10K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_THREE_FOURTHS = 0x2,
|
||||
ATH10K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_UNITY = 0x3,
|
||||
#define ATH10K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_MASK 0x3
|
||||
ATH10K_HTC_CONN_FLAGS_REDUCE_CREDIT_DRIBBLE = 1 << 2,
|
||||
ATH10K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL = 1 << 3
|
||||
#define ATH10K_HTC_CONN_FLAGS_RECV_ALLOC_MASK 0xFF00
|
||||
#define ATH10K_HTC_CONN_FLAGS_RECV_ALLOC_LSB 8
|
||||
};
|
||||
|
||||
enum ath10k_htc_conn_svc_status {
|
||||
ATH10K_HTC_CONN_SVC_STATUS_SUCCESS = 0,
|
||||
ATH10K_HTC_CONN_SVC_STATUS_NOT_FOUND = 1,
|
||||
ATH10K_HTC_CONN_SVC_STATUS_FAILED = 2,
|
||||
ATH10K_HTC_CONN_SVC_STATUS_NO_RESOURCES = 3,
|
||||
ATH10K_HTC_CONN_SVC_STATUS_NO_MORE_EP = 4
|
||||
};
|
||||
|
||||
struct ath10k_ath10k_htc_msg_hdr {
|
||||
__le16 message_id; /* @enum htc_message_id */
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_unknown {
|
||||
u8 pad0;
|
||||
u8 pad1;
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_ready {
|
||||
__le16 credit_count;
|
||||
__le16 credit_size;
|
||||
u8 max_endpoints;
|
||||
u8 pad0;
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_ready_extended {
|
||||
struct ath10k_htc_ready base;
|
||||
u8 htc_version; /* @enum ath10k_htc_version */
|
||||
u8 max_msgs_per_htc_bundle;
|
||||
u8 pad0;
|
||||
u8 pad1;
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_conn_svc {
|
||||
__le16 service_id;
|
||||
__le16 flags; /* @enum ath10k_htc_conn_flags */
|
||||
u8 pad0;
|
||||
u8 pad1;
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_conn_svc_response {
|
||||
__le16 service_id;
|
||||
u8 status; /* @enum ath10k_htc_conn_svc_status */
|
||||
u8 eid;
|
||||
__le16 max_msg_size;
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_setup_complete_extended {
|
||||
u8 pad0;
|
||||
u8 pad1;
|
||||
__le32 flags; /* @enum htc_setup_complete_flags */
|
||||
u8 max_msgs_per_bundled_recv;
|
||||
u8 pad2;
|
||||
u8 pad3;
|
||||
u8 pad4;
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_msg {
|
||||
struct ath10k_ath10k_htc_msg_hdr hdr;
|
||||
union {
|
||||
/* host-to-target */
|
||||
struct ath10k_htc_conn_svc connect_service;
|
||||
struct ath10k_htc_ready ready;
|
||||
struct ath10k_htc_ready_extended ready_ext;
|
||||
struct ath10k_htc_unknown unknown;
|
||||
struct ath10k_htc_setup_complete_extended setup_complete_ext;
|
||||
|
||||
/* target-to-host */
|
||||
struct ath10k_htc_conn_svc_response connect_service_response;
|
||||
};
|
||||
} __packed __aligned(4);
|
||||
|
||||
enum ath10k_ath10k_htc_record_id {
|
||||
ATH10K_HTC_RECORD_NULL = 0,
|
||||
ATH10K_HTC_RECORD_CREDITS = 1
|
||||
};
|
||||
|
||||
struct ath10k_ath10k_htc_record_hdr {
|
||||
u8 id; /* @enum ath10k_ath10k_htc_record_id */
|
||||
u8 len;
|
||||
u8 pad0;
|
||||
u8 pad1;
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_credit_report {
|
||||
u8 eid; /* @enum ath10k_htc_ep_id */
|
||||
u8 credits;
|
||||
u8 pad0;
|
||||
u8 pad1;
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_record {
|
||||
struct ath10k_ath10k_htc_record_hdr hdr;
|
||||
union {
|
||||
struct ath10k_htc_credit_report credit_report[0];
|
||||
u8 pauload[0];
|
||||
};
|
||||
} __packed __aligned(4);
|
||||
|
||||
/*
|
||||
* note: the trailer offset is dynamic depending
|
||||
* on payload length. this is only a struct layout draft
|
||||
*/
|
||||
struct ath10k_htc_frame {
|
||||
struct ath10k_htc_hdr hdr;
|
||||
union {
|
||||
struct ath10k_htc_msg msg;
|
||||
u8 payload[0];
|
||||
};
|
||||
struct ath10k_htc_record trailer[0];
|
||||
} __packed __aligned(4);
|
||||
|
||||
|
||||
/*******************/
|
||||
/* Host-side stuff */
|
||||
/*******************/
|
||||
|
||||
enum ath10k_htc_svc_gid {
|
||||
ATH10K_HTC_SVC_GRP_RSVD = 0,
|
||||
ATH10K_HTC_SVC_GRP_WMI = 1,
|
||||
ATH10K_HTC_SVC_GRP_NMI = 2,
|
||||
ATH10K_HTC_SVC_GRP_HTT = 3,
|
||||
|
||||
ATH10K_HTC_SVC_GRP_TEST = 254,
|
||||
ATH10K_HTC_SVC_GRP_LAST = 255,
|
||||
};
|
||||
|
||||
#define SVC(group, idx) \
|
||||
(int)(((int)(group) << 8) | (int)(idx))
|
||||
|
||||
enum ath10k_htc_svc_id {
|
||||
/* NOTE: service ID of 0x0000 is reserved and should never be used */
|
||||
ATH10K_HTC_SVC_ID_RESERVED = 0x0000,
|
||||
ATH10K_HTC_SVC_ID_UNUSED = ATH10K_HTC_SVC_ID_RESERVED,
|
||||
|
||||
ATH10K_HTC_SVC_ID_RSVD_CTRL = SVC(ATH10K_HTC_SVC_GRP_RSVD, 1),
|
||||
ATH10K_HTC_SVC_ID_WMI_CONTROL = SVC(ATH10K_HTC_SVC_GRP_WMI, 0),
|
||||
ATH10K_HTC_SVC_ID_WMI_DATA_BE = SVC(ATH10K_HTC_SVC_GRP_WMI, 1),
|
||||
ATH10K_HTC_SVC_ID_WMI_DATA_BK = SVC(ATH10K_HTC_SVC_GRP_WMI, 2),
|
||||
ATH10K_HTC_SVC_ID_WMI_DATA_VI = SVC(ATH10K_HTC_SVC_GRP_WMI, 3),
|
||||
ATH10K_HTC_SVC_ID_WMI_DATA_VO = SVC(ATH10K_HTC_SVC_GRP_WMI, 4),
|
||||
|
||||
ATH10K_HTC_SVC_ID_NMI_CONTROL = SVC(ATH10K_HTC_SVC_GRP_NMI, 0),
|
||||
ATH10K_HTC_SVC_ID_NMI_DATA = SVC(ATH10K_HTC_SVC_GRP_NMI, 1),
|
||||
|
||||
ATH10K_HTC_SVC_ID_HTT_DATA_MSG = SVC(ATH10K_HTC_SVC_GRP_HTT, 0),
|
||||
|
||||
/* raw stream service (i.e. flash, tcmd, calibration apps) */
|
||||
ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS = SVC(ATH10K_HTC_SVC_GRP_TEST, 0),
|
||||
};
|
||||
|
||||
#undef SVC
|
||||
|
||||
enum ath10k_htc_ep_id {
|
||||
ATH10K_HTC_EP_UNUSED = -1,
|
||||
ATH10K_HTC_EP_0 = 0,
|
||||
ATH10K_HTC_EP_1 = 1,
|
||||
ATH10K_HTC_EP_2,
|
||||
ATH10K_HTC_EP_3,
|
||||
ATH10K_HTC_EP_4,
|
||||
ATH10K_HTC_EP_5,
|
||||
ATH10K_HTC_EP_6,
|
||||
ATH10K_HTC_EP_7,
|
||||
ATH10K_HTC_EP_8,
|
||||
ATH10K_HTC_EP_COUNT,
|
||||
};
|
||||
|
||||
struct ath10k_htc_ops {
|
||||
void (*target_send_suspend_complete)(struct ath10k *ar);
|
||||
};
|
||||
|
||||
struct ath10k_htc_ep_ops {
|
||||
void (*ep_tx_complete)(struct ath10k *, struct sk_buff *);
|
||||
void (*ep_rx_complete)(struct ath10k *, struct sk_buff *);
|
||||
};
|
||||
|
||||
/* service connection information */
|
||||
struct ath10k_htc_svc_conn_req {
|
||||
u16 service_id;
|
||||
struct ath10k_htc_ep_ops ep_ops;
|
||||
int max_send_queue_depth;
|
||||
};
|
||||
|
||||
/* service connection response information */
|
||||
struct ath10k_htc_svc_conn_resp {
|
||||
u8 buffer_len;
|
||||
u8 actual_len;
|
||||
enum ath10k_htc_ep_id eid;
|
||||
unsigned int max_msg_len;
|
||||
u8 connect_resp_code;
|
||||
};
|
||||
|
||||
#define ATH10K_NUM_CONTROL_TX_BUFFERS 2
|
||||
#define ATH10K_HTC_MAX_LEN 4096
|
||||
#define ATH10K_HTC_MAX_CTRL_MSG_LEN 256
|
||||
#define ATH10K_HTC_WAIT_TIMEOUT_HZ (1*HZ)
|
||||
#define ATH10K_HTC_CONTROL_BUFFER_SIZE (ATH10K_HTC_MAX_CTRL_MSG_LEN + \
|
||||
sizeof(struct ath10k_htc_hdr))
|
||||
#define ATH10K_HTC_CONN_SVC_TIMEOUT_HZ (1*HZ)
|
||||
|
||||
struct ath10k_htc_ep {
|
||||
struct ath10k_htc *htc;
|
||||
enum ath10k_htc_ep_id eid;
|
||||
enum ath10k_htc_svc_id service_id;
|
||||
struct ath10k_htc_ep_ops ep_ops;
|
||||
|
||||
int max_tx_queue_depth;
|
||||
int max_ep_message_len;
|
||||
u8 ul_pipe_id;
|
||||
u8 dl_pipe_id;
|
||||
int ul_is_polled; /* call HIF to get tx completions */
|
||||
int dl_is_polled; /* call HIF to fetch rx (not implemented) */
|
||||
|
||||
struct sk_buff_head tx_queue;
|
||||
|
||||
u8 seq_no; /* for debugging */
|
||||
int tx_credits;
|
||||
int tx_credit_size;
|
||||
int tx_credits_per_max_message;
|
||||
bool tx_credit_flow_enabled;
|
||||
|
||||
struct work_struct send_work;
|
||||
};
|
||||
|
||||
struct ath10k_htc_svc_tx_credits {
|
||||
u16 service_id;
|
||||
u8 credit_allocation;
|
||||
};
|
||||
|
||||
struct ath10k_htc {
|
||||
struct ath10k *ar;
|
||||
struct ath10k_htc_ep endpoint[ATH10K_HTC_EP_COUNT];
|
||||
|
||||
/* protects endpoint and stopping fields */
|
||||
spinlock_t tx_lock;
|
||||
|
||||
struct ath10k_htc_ops htc_ops;
|
||||
|
||||
u8 control_resp_buffer[ATH10K_HTC_MAX_CTRL_MSG_LEN];
|
||||
int control_resp_len;
|
||||
|
||||
struct completion ctl_resp;
|
||||
|
||||
int total_transmit_credits;
|
||||
struct ath10k_htc_svc_tx_credits service_tx_alloc[ATH10K_HTC_EP_COUNT];
|
||||
int target_credit_size;
|
||||
|
||||
bool stopping;
|
||||
};
|
||||
|
||||
struct ath10k_htc *ath10k_htc_create(struct ath10k *ar,
|
||||
struct ath10k_htc_ops *htc_ops);
|
||||
int ath10k_htc_wait_target(struct ath10k_htc *htc);
|
||||
int ath10k_htc_start(struct ath10k_htc *htc);
|
||||
int ath10k_htc_connect_service(struct ath10k_htc *htc,
|
||||
struct ath10k_htc_svc_conn_req *conn_req,
|
||||
struct ath10k_htc_svc_conn_resp *conn_resp);
|
||||
int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid,
|
||||
struct sk_buff *packet);
|
||||
void ath10k_htc_stop(struct ath10k_htc *htc);
|
||||
void ath10k_htc_destroy(struct ath10k_htc *htc);
|
||||
struct sk_buff *ath10k_htc_alloc_skb(int size);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "htt.h"
|
||||
#include "core.h"
|
||||
#include "debug.h"
|
||||
|
||||
static int ath10k_htt_htc_attach(struct ath10k_htt *htt)
|
||||
{
|
||||
struct ath10k_htc_svc_conn_req conn_req;
|
||||
struct ath10k_htc_svc_conn_resp conn_resp;
|
||||
int status;
|
||||
|
||||
memset(&conn_req, 0, sizeof(conn_req));
|
||||
memset(&conn_resp, 0, sizeof(conn_resp));
|
||||
|
||||
conn_req.ep_ops.ep_tx_complete = ath10k_htt_htc_tx_complete;
|
||||
conn_req.ep_ops.ep_rx_complete = ath10k_htt_t2h_msg_handler;
|
||||
|
||||
/* connect to control service */
|
||||
conn_req.service_id = ATH10K_HTC_SVC_ID_HTT_DATA_MSG;
|
||||
|
||||
status = ath10k_htc_connect_service(htt->ar->htc, &conn_req,
|
||||
&conn_resp);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
htt->eid = conn_resp.eid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_htt *htt;
|
||||
int ret;
|
||||
|
||||
htt = kzalloc(sizeof(*htt), GFP_KERNEL);
|
||||
if (!htt)
|
||||
return NULL;
|
||||
|
||||
htt->ar = ar;
|
||||
htt->max_throughput_mbps = 800;
|
||||
|
||||
/*
|
||||
* Connect to HTC service.
|
||||
* This has to be done before calling ath10k_htt_rx_attach,
|
||||
* since ath10k_htt_rx_attach involves sending a rx ring configure
|
||||
* message to the target.
|
||||
*/
|
||||
if (ath10k_htt_htc_attach(htt))
|
||||
goto err_htc_attach;
|
||||
|
||||
ret = ath10k_htt_tx_attach(htt);
|
||||
if (ret) {
|
||||
ath10k_err("could not attach htt tx (%d)\n", ret);
|
||||
goto err_htc_attach;
|
||||
}
|
||||
|
||||
if (ath10k_htt_rx_attach(htt))
|
||||
goto err_rx_attach;
|
||||
|
||||
/*
|
||||
* Prefetch enough data to satisfy target
|
||||
* classification engine.
|
||||
* This is for LL chips. HL chips will probably
|
||||
* transfer all frame in the tx fragment.
|
||||
*/
|
||||
htt->prefetch_len =
|
||||
36 + /* 802.11 + qos + ht */
|
||||
4 + /* 802.1q */
|
||||
8 + /* llc snap */
|
||||
2; /* ip4 dscp or ip6 priority */
|
||||
|
||||
return htt;
|
||||
|
||||
err_rx_attach:
|
||||
ath10k_htt_tx_detach(htt);
|
||||
err_htc_attach:
|
||||
kfree(htt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define HTT_TARGET_VERSION_TIMEOUT_HZ (3*HZ)
|
||||
|
||||
static int ath10k_htt_verify_version(struct ath10k_htt *htt)
|
||||
{
|
||||
ath10k_dbg(ATH10K_DBG_HTT,
|
||||
"htt target version %d.%d; host version %d.%d\n",
|
||||
htt->target_version_major,
|
||||
htt->target_version_minor,
|
||||
HTT_CURRENT_VERSION_MAJOR,
|
||||
HTT_CURRENT_VERSION_MINOR);
|
||||
|
||||
if (htt->target_version_major != HTT_CURRENT_VERSION_MAJOR) {
|
||||
ath10k_err("htt major versions are incompatible!\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
if (htt->target_version_minor != HTT_CURRENT_VERSION_MINOR)
|
||||
ath10k_warn("htt minor version differ but still compatible\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_htt_attach_target(struct ath10k_htt *htt)
|
||||
{
|
||||
int status;
|
||||
|
||||
init_completion(&htt->target_version_received);
|
||||
|
||||
status = ath10k_htt_h2t_ver_req_msg(htt);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = wait_for_completion_timeout(&htt->target_version_received,
|
||||
HTT_TARGET_VERSION_TIMEOUT_HZ);
|
||||
if (status <= 0) {
|
||||
ath10k_warn("htt version request timed out\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
status = ath10k_htt_verify_version(htt);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
return ath10k_htt_send_rx_ring_cfg_ll(htt);
|
||||
}
|
||||
|
||||
void ath10k_htt_detach(struct ath10k_htt *htt)
|
||||
{
|
||||
ath10k_htt_rx_detach(htt);
|
||||
ath10k_htt_tx_detach(htt);
|
||||
kfree(htt);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,510 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include "htt.h"
|
||||
#include "mac.h"
|
||||
#include "hif.h"
|
||||
#include "txrx.h"
|
||||
#include "debug.h"
|
||||
|
||||
void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt)
|
||||
{
|
||||
htt->num_pending_tx--;
|
||||
if (htt->num_pending_tx == htt->max_num_pending_tx - 1)
|
||||
ieee80211_wake_queues(htt->ar->hw);
|
||||
}
|
||||
|
||||
static void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt)
|
||||
{
|
||||
spin_lock_bh(&htt->tx_lock);
|
||||
__ath10k_htt_tx_dec_pending(htt);
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
}
|
||||
|
||||
static int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_bh(&htt->tx_lock);
|
||||
|
||||
if (htt->num_pending_tx >= htt->max_num_pending_tx) {
|
||||
ret = -EBUSY;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
htt->num_pending_tx++;
|
||||
if (htt->num_pending_tx == htt->max_num_pending_tx)
|
||||
ieee80211_stop_queues(htt->ar->hw);
|
||||
|
||||
exit:
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt)
|
||||
{
|
||||
int msdu_id;
|
||||
|
||||
lockdep_assert_held(&htt->tx_lock);
|
||||
|
||||
msdu_id = find_first_zero_bit(htt->used_msdu_ids,
|
||||
htt->max_num_pending_tx);
|
||||
if (msdu_id == htt->max_num_pending_tx)
|
||||
return -ENOBUFS;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", msdu_id);
|
||||
__set_bit(msdu_id, htt->used_msdu_ids);
|
||||
return msdu_id;
|
||||
}
|
||||
|
||||
void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id)
|
||||
{
|
||||
lockdep_assert_held(&htt->tx_lock);
|
||||
|
||||
if (!test_bit(msdu_id, htt->used_msdu_ids))
|
||||
ath10k_warn("trying to free unallocated msdu_id %d\n", msdu_id);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_HTT, "htt tx free msdu_id %hu\n", msdu_id);
|
||||
__clear_bit(msdu_id, htt->used_msdu_ids);
|
||||
}
|
||||
|
||||
int ath10k_htt_tx_attach(struct ath10k_htt *htt)
|
||||
{
|
||||
u8 pipe;
|
||||
|
||||
spin_lock_init(&htt->tx_lock);
|
||||
init_waitqueue_head(&htt->empty_tx_wq);
|
||||
|
||||
/* At the beginning free queue number should hint us the maximum
|
||||
* queue length */
|
||||
pipe = htt->ar->htc->endpoint[htt->eid].ul_pipe_id;
|
||||
htt->max_num_pending_tx = ath10k_hif_get_free_queue_number(htt->ar,
|
||||
pipe);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_HTT, "htt tx max num pending tx %d\n",
|
||||
htt->max_num_pending_tx);
|
||||
|
||||
htt->pending_tx = kzalloc(sizeof(*htt->pending_tx) *
|
||||
htt->max_num_pending_tx, GFP_KERNEL);
|
||||
if (!htt->pending_tx)
|
||||
return -ENOMEM;
|
||||
|
||||
htt->used_msdu_ids = kzalloc(sizeof(unsigned long) *
|
||||
BITS_TO_LONGS(htt->max_num_pending_tx),
|
||||
GFP_KERNEL);
|
||||
if (!htt->used_msdu_ids) {
|
||||
kfree(htt->pending_tx);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt)
|
||||
{
|
||||
struct sk_buff *txdesc;
|
||||
int msdu_id;
|
||||
|
||||
/* No locks needed. Called after communication with the device has
|
||||
* been stopped. */
|
||||
|
||||
for (msdu_id = 0; msdu_id < htt->max_num_pending_tx; msdu_id++) {
|
||||
if (!test_bit(msdu_id, htt->used_msdu_ids))
|
||||
continue;
|
||||
|
||||
txdesc = htt->pending_tx[msdu_id];
|
||||
if (!txdesc)
|
||||
continue;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n",
|
||||
msdu_id);
|
||||
|
||||
if (ATH10K_SKB_CB(txdesc)->htt.refcount > 0)
|
||||
ATH10K_SKB_CB(txdesc)->htt.refcount = 1;
|
||||
|
||||
ATH10K_SKB_CB(txdesc)->htt.discard = true;
|
||||
ath10k_txrx_tx_unref(htt, txdesc);
|
||||
}
|
||||
}
|
||||
|
||||
void ath10k_htt_tx_detach(struct ath10k_htt *htt)
|
||||
{
|
||||
ath10k_htt_tx_cleanup_pending(htt);
|
||||
kfree(htt->pending_tx);
|
||||
kfree(htt->used_msdu_ids);
|
||||
return;
|
||||
}
|
||||
|
||||
void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
|
||||
struct ath10k_htt *htt = ar->htt;
|
||||
|
||||
if (skb_cb->htt.is_conf) {
|
||||
dev_kfree_skb_any(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (skb_cb->is_aborted) {
|
||||
skb_cb->htt.discard = true;
|
||||
|
||||
/* if the skbuff is aborted we need to make sure we'll free up
|
||||
* the tx resources, we can't simply run tx_unref() 2 times
|
||||
* because if htt tx completion came in earlier we'd access
|
||||
* unallocated memory */
|
||||
if (skb_cb->htt.refcount > 1)
|
||||
skb_cb->htt.refcount = 1;
|
||||
}
|
||||
|
||||
ath10k_txrx_tx_unref(htt, skb);
|
||||
}
|
||||
|
||||
int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct htt_cmd *cmd;
|
||||
int len = 0;
|
||||
int ret;
|
||||
|
||||
len += sizeof(cmd->hdr);
|
||||
len += sizeof(cmd->ver_req);
|
||||
|
||||
skb = ath10k_htc_alloc_skb(len);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
skb_put(skb, len);
|
||||
cmd = (struct htt_cmd *)skb->data;
|
||||
cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_VERSION_REQ;
|
||||
|
||||
ATH10K_SKB_CB(skb)->htt.is_conf = true;
|
||||
|
||||
ret = ath10k_htc_send(htt->ar->htc, htt->eid, skb);
|
||||
if (ret) {
|
||||
dev_kfree_skb_any(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct htt_cmd *cmd;
|
||||
struct htt_rx_ring_setup_ring *ring;
|
||||
const int num_rx_ring = 1;
|
||||
u16 flags;
|
||||
u32 fw_idx;
|
||||
int len;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* the HW expects the buffer to be an integral number of 4-byte
|
||||
* "words"
|
||||
*/
|
||||
BUILD_BUG_ON(!IS_ALIGNED(HTT_RX_BUF_SIZE, 4));
|
||||
BUILD_BUG_ON((HTT_RX_BUF_SIZE & HTT_MAX_CACHE_LINE_SIZE_MASK) != 0);
|
||||
|
||||
len = sizeof(cmd->hdr) + sizeof(cmd->rx_setup.hdr)
|
||||
+ (sizeof(*ring) * num_rx_ring);
|
||||
skb = ath10k_htc_alloc_skb(len);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
skb_put(skb, len);
|
||||
|
||||
cmd = (struct htt_cmd *)skb->data;
|
||||
ring = &cmd->rx_setup.rings[0];
|
||||
|
||||
cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_RX_RING_CFG;
|
||||
cmd->rx_setup.hdr.num_rings = 1;
|
||||
|
||||
/* FIXME: do we need all of this? */
|
||||
flags = 0;
|
||||
flags |= HTT_RX_RING_FLAGS_MAC80211_HDR;
|
||||
flags |= HTT_RX_RING_FLAGS_MSDU_PAYLOAD;
|
||||
flags |= HTT_RX_RING_FLAGS_PPDU_START;
|
||||
flags |= HTT_RX_RING_FLAGS_PPDU_END;
|
||||
flags |= HTT_RX_RING_FLAGS_MPDU_START;
|
||||
flags |= HTT_RX_RING_FLAGS_MPDU_END;
|
||||
flags |= HTT_RX_RING_FLAGS_MSDU_START;
|
||||
flags |= HTT_RX_RING_FLAGS_MSDU_END;
|
||||
flags |= HTT_RX_RING_FLAGS_RX_ATTENTION;
|
||||
flags |= HTT_RX_RING_FLAGS_FRAG_INFO;
|
||||
flags |= HTT_RX_RING_FLAGS_UNICAST_RX;
|
||||
flags |= HTT_RX_RING_FLAGS_MULTICAST_RX;
|
||||
flags |= HTT_RX_RING_FLAGS_CTRL_RX;
|
||||
flags |= HTT_RX_RING_FLAGS_MGMT_RX;
|
||||
flags |= HTT_RX_RING_FLAGS_NULL_RX;
|
||||
flags |= HTT_RX_RING_FLAGS_PHY_DATA_RX;
|
||||
|
||||
fw_idx = __le32_to_cpu(*htt->rx_ring.alloc_idx.vaddr);
|
||||
|
||||
ring->fw_idx_shadow_reg_paddr =
|
||||
__cpu_to_le32(htt->rx_ring.alloc_idx.paddr);
|
||||
ring->rx_ring_base_paddr = __cpu_to_le32(htt->rx_ring.base_paddr);
|
||||
ring->rx_ring_len = __cpu_to_le16(htt->rx_ring.size);
|
||||
ring->rx_ring_bufsize = __cpu_to_le16(HTT_RX_BUF_SIZE);
|
||||
ring->flags = __cpu_to_le16(flags);
|
||||
ring->fw_idx_init_val = __cpu_to_le16(fw_idx);
|
||||
|
||||
#define desc_offset(x) (offsetof(struct htt_rx_desc, x) / 4)
|
||||
|
||||
ring->mac80211_hdr_offset = __cpu_to_le16(desc_offset(rx_hdr_status));
|
||||
ring->msdu_payload_offset = __cpu_to_le16(desc_offset(msdu_payload));
|
||||
ring->ppdu_start_offset = __cpu_to_le16(desc_offset(ppdu_start));
|
||||
ring->ppdu_end_offset = __cpu_to_le16(desc_offset(ppdu_end));
|
||||
ring->mpdu_start_offset = __cpu_to_le16(desc_offset(mpdu_start));
|
||||
ring->mpdu_end_offset = __cpu_to_le16(desc_offset(mpdu_end));
|
||||
ring->msdu_start_offset = __cpu_to_le16(desc_offset(msdu_start));
|
||||
ring->msdu_end_offset = __cpu_to_le16(desc_offset(msdu_end));
|
||||
ring->rx_attention_offset = __cpu_to_le16(desc_offset(attention));
|
||||
ring->frag_info_offset = __cpu_to_le16(desc_offset(frag_info));
|
||||
|
||||
#undef desc_offset
|
||||
|
||||
ATH10K_SKB_CB(skb)->htt.is_conf = true;
|
||||
|
||||
ret = ath10k_htc_send(htt->ar->htc, htt->eid, skb);
|
||||
if (ret) {
|
||||
dev_kfree_skb_any(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
||||
{
|
||||
struct device *dev = htt->ar->dev;
|
||||
struct ath10k_skb_cb *skb_cb;
|
||||
struct sk_buff *txdesc = NULL;
|
||||
struct htt_cmd *cmd;
|
||||
u8 vdev_id = ATH10K_SKB_CB(msdu)->htt.vdev_id;
|
||||
int len = 0;
|
||||
int msdu_id = -1;
|
||||
int res;
|
||||
|
||||
|
||||
res = ath10k_htt_tx_inc_pending(htt);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
len += sizeof(cmd->hdr);
|
||||
len += sizeof(cmd->mgmt_tx);
|
||||
|
||||
txdesc = ath10k_htc_alloc_skb(len);
|
||||
if (!txdesc) {
|
||||
res = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
spin_lock_bh(&htt->tx_lock);
|
||||
msdu_id = ath10k_htt_tx_alloc_msdu_id(htt);
|
||||
if (msdu_id < 0) {
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
res = msdu_id;
|
||||
goto err;
|
||||
}
|
||||
htt->pending_tx[msdu_id] = txdesc;
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
|
||||
res = ath10k_skb_map(dev, msdu);
|
||||
if (res)
|
||||
goto err;
|
||||
|
||||
skb_put(txdesc, len);
|
||||
cmd = (struct htt_cmd *)txdesc->data;
|
||||
cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_MGMT_TX;
|
||||
cmd->mgmt_tx.msdu_paddr = __cpu_to_le32(ATH10K_SKB_CB(msdu)->paddr);
|
||||
cmd->mgmt_tx.len = __cpu_to_le32(msdu->len);
|
||||
cmd->mgmt_tx.desc_id = __cpu_to_le32(msdu_id);
|
||||
cmd->mgmt_tx.vdev_id = __cpu_to_le32(vdev_id);
|
||||
memcpy(cmd->mgmt_tx.hdr, msdu->data,
|
||||
min_t(int, msdu->len, HTT_MGMT_FRM_HDR_DOWNLOAD_LEN));
|
||||
|
||||
/* refcount is decremented by HTC and HTT completions until it reaches
|
||||
* zero and is freed */
|
||||
skb_cb = ATH10K_SKB_CB(txdesc);
|
||||
skb_cb->htt.msdu_id = msdu_id;
|
||||
skb_cb->htt.refcount = 2;
|
||||
skb_cb->htt.msdu = msdu;
|
||||
|
||||
res = ath10k_htc_send(htt->ar->htc, htt->eid, txdesc);
|
||||
if (res)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
ath10k_skb_unmap(dev, msdu);
|
||||
|
||||
if (txdesc)
|
||||
dev_kfree_skb_any(txdesc);
|
||||
if (msdu_id >= 0) {
|
||||
spin_lock_bh(&htt->tx_lock);
|
||||
htt->pending_tx[msdu_id] = NULL;
|
||||
ath10k_htt_tx_free_msdu_id(htt, msdu_id);
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
}
|
||||
ath10k_htt_tx_dec_pending(htt);
|
||||
return res;
|
||||
}
|
||||
|
||||
int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
||||
{
|
||||
struct device *dev = htt->ar->dev;
|
||||
struct htt_cmd *cmd;
|
||||
struct htt_data_tx_desc_frag *tx_frags;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
|
||||
struct ath10k_skb_cb *skb_cb;
|
||||
struct sk_buff *txdesc = NULL;
|
||||
struct sk_buff *txfrag = NULL;
|
||||
u8 vdev_id = ATH10K_SKB_CB(msdu)->htt.vdev_id;
|
||||
u8 tid;
|
||||
int prefetch_len, desc_len, frag_len;
|
||||
dma_addr_t frags_paddr;
|
||||
int msdu_id = -1;
|
||||
int res;
|
||||
u8 flags0;
|
||||
u16 flags1;
|
||||
|
||||
res = ath10k_htt_tx_inc_pending(htt);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
prefetch_len = min(htt->prefetch_len, msdu->len);
|
||||
prefetch_len = roundup(prefetch_len, 4);
|
||||
|
||||
desc_len = sizeof(cmd->hdr) + sizeof(cmd->data_tx) + prefetch_len;
|
||||
frag_len = sizeof(*tx_frags) * 2;
|
||||
|
||||
txdesc = ath10k_htc_alloc_skb(desc_len);
|
||||
if (!txdesc) {
|
||||
res = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
txfrag = dev_alloc_skb(frag_len);
|
||||
if (!txfrag) {
|
||||
res = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!IS_ALIGNED((unsigned long)txdesc->data, 4)) {
|
||||
ath10k_warn("htt alignment check failed. dropping packet.\n");
|
||||
res = -EIO;
|
||||
goto err;
|
||||
}
|
||||
|
||||
spin_lock_bh(&htt->tx_lock);
|
||||
msdu_id = ath10k_htt_tx_alloc_msdu_id(htt);
|
||||
if (msdu_id < 0) {
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
res = msdu_id;
|
||||
goto err;
|
||||
}
|
||||
htt->pending_tx[msdu_id] = txdesc;
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
|
||||
res = ath10k_skb_map(dev, msdu);
|
||||
if (res)
|
||||
goto err;
|
||||
|
||||
/* tx fragment list must be terminated with zero-entry */
|
||||
skb_put(txfrag, frag_len);
|
||||
tx_frags = (struct htt_data_tx_desc_frag *)txfrag->data;
|
||||
tx_frags[0].paddr = __cpu_to_le32(ATH10K_SKB_CB(msdu)->paddr);
|
||||
tx_frags[0].len = __cpu_to_le32(msdu->len);
|
||||
tx_frags[1].paddr = __cpu_to_le32(0);
|
||||
tx_frags[1].len = __cpu_to_le32(0);
|
||||
|
||||
res = ath10k_skb_map(dev, txfrag);
|
||||
if (res)
|
||||
goto err;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_HTT, "txfrag 0x%llx msdu 0x%llx\n",
|
||||
(unsigned long long) ATH10K_SKB_CB(txfrag)->paddr,
|
||||
(unsigned long long) ATH10K_SKB_CB(msdu)->paddr);
|
||||
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "txfrag: ",
|
||||
txfrag->data, frag_len);
|
||||
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "msdu: ",
|
||||
msdu->data, msdu->len);
|
||||
|
||||
skb_put(txdesc, desc_len);
|
||||
cmd = (struct htt_cmd *)txdesc->data;
|
||||
memset(cmd, 0, desc_len);
|
||||
|
||||
tid = ATH10K_SKB_CB(msdu)->htt.tid;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_HTT, "htt data tx using tid %hhu\n", tid);
|
||||
|
||||
flags0 = 0;
|
||||
if (!ieee80211_has_protected(hdr->frame_control))
|
||||
flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT;
|
||||
flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
|
||||
flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI,
|
||||
HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
|
||||
|
||||
flags1 = 0;
|
||||
flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID);
|
||||
flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID);
|
||||
|
||||
frags_paddr = ATH10K_SKB_CB(txfrag)->paddr;
|
||||
|
||||
cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM;
|
||||
cmd->data_tx.flags0 = flags0;
|
||||
cmd->data_tx.flags1 = __cpu_to_le16(flags1);
|
||||
cmd->data_tx.len = __cpu_to_le16(msdu->len);
|
||||
cmd->data_tx.id = __cpu_to_le16(msdu_id);
|
||||
cmd->data_tx.frags_paddr = __cpu_to_le32(frags_paddr);
|
||||
cmd->data_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID);
|
||||
|
||||
memcpy(cmd->data_tx.prefetch, msdu->data, prefetch_len);
|
||||
|
||||
/* refcount is decremented by HTC and HTT completions until it reaches
|
||||
* zero and is freed */
|
||||
skb_cb = ATH10K_SKB_CB(txdesc);
|
||||
skb_cb->htt.msdu_id = msdu_id;
|
||||
skb_cb->htt.refcount = 2;
|
||||
skb_cb->htt.txfrag = txfrag;
|
||||
skb_cb->htt.msdu = msdu;
|
||||
|
||||
res = ath10k_htc_send(htt->ar->htc, htt->eid, txdesc);
|
||||
if (res)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
if (txfrag)
|
||||
ath10k_skb_unmap(dev, txfrag);
|
||||
if (txdesc)
|
||||
dev_kfree_skb_any(txdesc);
|
||||
if (txfrag)
|
||||
dev_kfree_skb_any(txfrag);
|
||||
if (msdu_id >= 0) {
|
||||
spin_lock_bh(&htt->tx_lock);
|
||||
htt->pending_tx[msdu_id] = NULL;
|
||||
ath10k_htt_tx_free_msdu_id(htt, msdu_id);
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
}
|
||||
ath10k_htt_tx_dec_pending(htt);
|
||||
ath10k_skb_unmap(dev, msdu);
|
||||
return res;
|
||||
}
|
|
@ -0,0 +1,304 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2013 Qualcomm Atheros, 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 _HW_H_
|
||||
#define _HW_H_
|
||||
|
||||
#include "targaddrs.h"
|
||||
|
||||
/* Supported FW version */
|
||||
#define SUPPORTED_FW_MAJOR 1
|
||||
#define SUPPORTED_FW_MINOR 0
|
||||
#define SUPPORTED_FW_RELEASE 0
|
||||
#define SUPPORTED_FW_BUILD 629
|
||||
|
||||
/* QCA988X 1.0 definitions */
|
||||
#define QCA988X_HW_1_0_VERSION 0x4000002c
|
||||
#define QCA988X_HW_1_0_FW_DIR "ath10k/QCA988X/hw1.0"
|
||||
#define QCA988X_HW_1_0_FW_FILE "firmware.bin"
|
||||
#define QCA988X_HW_1_0_OTP_FILE "otp.bin"
|
||||
#define QCA988X_HW_1_0_BOARD_DATA_FILE "board.bin"
|
||||
#define QCA988X_HW_1_0_PATCH_LOAD_ADDR 0x1234
|
||||
|
||||
/* QCA988X 2.0 definitions */
|
||||
#define QCA988X_HW_2_0_VERSION 0x4100016c
|
||||
#define QCA988X_HW_2_0_FW_DIR "ath10k/QCA988X/hw2.0"
|
||||
#define QCA988X_HW_2_0_FW_FILE "firmware.bin"
|
||||
#define QCA988X_HW_2_0_OTP_FILE "otp.bin"
|
||||
#define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin"
|
||||
#define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234
|
||||
|
||||
/* Known pecularities:
|
||||
* - current FW doesn't support raw rx mode (last tested v599)
|
||||
* - current FW dumps upon raw tx mode (last tested v599)
|
||||
* - raw appears in nwifi decap, raw and nwifi appear in ethernet decap
|
||||
* - raw have FCS, nwifi doesn't
|
||||
* - ethernet frames have 802.11 header decapped and parts (base hdr, cipher
|
||||
* param, llc/snap) are aligned to 4byte boundaries each */
|
||||
enum ath10k_hw_txrx_mode {
|
||||
ATH10K_HW_TXRX_RAW = 0,
|
||||
ATH10K_HW_TXRX_NATIVE_WIFI = 1,
|
||||
ATH10K_HW_TXRX_ETHERNET = 2,
|
||||
};
|
||||
|
||||
enum ath10k_mcast2ucast_mode {
|
||||
ATH10K_MCAST2UCAST_DISABLED = 0,
|
||||
ATH10K_MCAST2UCAST_ENABLED = 1,
|
||||
};
|
||||
|
||||
#define TARGET_NUM_VDEVS 8
|
||||
#define TARGET_NUM_PEER_AST 2
|
||||
#define TARGET_NUM_WDS_ENTRIES 32
|
||||
#define TARGET_DMA_BURST_SIZE 0
|
||||
#define TARGET_MAC_AGGR_DELIM 0
|
||||
#define TARGET_AST_SKID_LIMIT 16
|
||||
#define TARGET_NUM_PEERS 16
|
||||
#define TARGET_NUM_OFFLOAD_PEERS 0
|
||||
#define TARGET_NUM_OFFLOAD_REORDER_BUFS 0
|
||||
#define TARGET_NUM_PEER_KEYS 2
|
||||
#define TARGET_NUM_TIDS (2 * ((TARGET_NUM_PEERS) + (TARGET_NUM_VDEVS)))
|
||||
#define TARGET_TX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2))
|
||||
#define TARGET_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2))
|
||||
#define TARGET_RX_TIMEOUT_LO_PRI 100
|
||||
#define TARGET_RX_TIMEOUT_HI_PRI 40
|
||||
#define TARGET_RX_DECAP_MODE ATH10K_HW_TXRX_ETHERNET
|
||||
#define TARGET_SCAN_MAX_PENDING_REQS 4
|
||||
#define TARGET_BMISS_OFFLOAD_MAX_VDEV 3
|
||||
#define TARGET_ROAM_OFFLOAD_MAX_VDEV 3
|
||||
#define TARGET_ROAM_OFFLOAD_MAX_AP_PROFILES 8
|
||||
#define TARGET_GTK_OFFLOAD_MAX_VDEV 3
|
||||
#define TARGET_NUM_MCAST_GROUPS 0
|
||||
#define TARGET_NUM_MCAST_TABLE_ELEMS 0
|
||||
#define TARGET_MCAST2UCAST_MODE ATH10K_MCAST2UCAST_DISABLED
|
||||
#define TARGET_TX_DBG_LOG_SIZE 1024
|
||||
#define TARGET_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK 0
|
||||
#define TARGET_VOW_CONFIG 0
|
||||
#define TARGET_NUM_MSDU_DESC (1024 + 400)
|
||||
#define TARGET_MAX_FRAG_ENTRIES 0
|
||||
|
||||
|
||||
/* Number of Copy Engines supported */
|
||||
#define CE_COUNT 8
|
||||
|
||||
/*
|
||||
* Total number of PCIe MSI interrupts requested for all interrupt sources.
|
||||
* PCIe standard forces this to be a power of 2.
|
||||
* Some Host OS's limit MSI requests that can be granted to 8
|
||||
* so for now we abide by this limit and avoid requesting more
|
||||
* than that.
|
||||
*/
|
||||
#define MSI_NUM_REQUEST_LOG2 3
|
||||
#define MSI_NUM_REQUEST (1<<MSI_NUM_REQUEST_LOG2)
|
||||
|
||||
/*
|
||||
* Granted MSIs are assigned as follows:
|
||||
* Firmware uses the first
|
||||
* Remaining MSIs, if any, are used by Copy Engines
|
||||
* This mapping is known to both Target firmware and Host software.
|
||||
* It may be changed as long as Host and Target are kept in sync.
|
||||
*/
|
||||
/* MSI for firmware (errors, etc.) */
|
||||
#define MSI_ASSIGN_FW 0
|
||||
|
||||
/* MSIs for Copy Engines */
|
||||
#define MSI_ASSIGN_CE_INITIAL 1
|
||||
#define MSI_ASSIGN_CE_MAX 7
|
||||
|
||||
/* as of IP3.7.1 */
|
||||
#define RTC_STATE_V_ON 3
|
||||
|
||||
#define RTC_STATE_COLD_RESET_MASK 0x00000400
|
||||
#define RTC_STATE_V_LSB 0
|
||||
#define RTC_STATE_V_MASK 0x00000007
|
||||
#define RTC_STATE_ADDRESS 0x0000
|
||||
#define PCIE_SOC_WAKE_V_MASK 0x00000001
|
||||
#define PCIE_SOC_WAKE_ADDRESS 0x0004
|
||||
#define PCIE_SOC_WAKE_RESET 0x00000000
|
||||
#define SOC_GLOBAL_RESET_ADDRESS 0x0008
|
||||
|
||||
#define RTC_SOC_BASE_ADDRESS 0x00004000
|
||||
#define RTC_WMAC_BASE_ADDRESS 0x00005000
|
||||
#define MAC_COEX_BASE_ADDRESS 0x00006000
|
||||
#define BT_COEX_BASE_ADDRESS 0x00007000
|
||||
#define SOC_PCIE_BASE_ADDRESS 0x00008000
|
||||
#define SOC_CORE_BASE_ADDRESS 0x00009000
|
||||
#define WLAN_UART_BASE_ADDRESS 0x0000c000
|
||||
#define WLAN_SI_BASE_ADDRESS 0x00010000
|
||||
#define WLAN_GPIO_BASE_ADDRESS 0x00014000
|
||||
#define WLAN_ANALOG_INTF_BASE_ADDRESS 0x0001c000
|
||||
#define WLAN_MAC_BASE_ADDRESS 0x00020000
|
||||
#define EFUSE_BASE_ADDRESS 0x00030000
|
||||
#define FPGA_REG_BASE_ADDRESS 0x00039000
|
||||
#define WLAN_UART2_BASE_ADDRESS 0x00054c00
|
||||
#define CE_WRAPPER_BASE_ADDRESS 0x00057000
|
||||
#define CE0_BASE_ADDRESS 0x00057400
|
||||
#define CE1_BASE_ADDRESS 0x00057800
|
||||
#define CE2_BASE_ADDRESS 0x00057c00
|
||||
#define CE3_BASE_ADDRESS 0x00058000
|
||||
#define CE4_BASE_ADDRESS 0x00058400
|
||||
#define CE5_BASE_ADDRESS 0x00058800
|
||||
#define CE6_BASE_ADDRESS 0x00058c00
|
||||
#define CE7_BASE_ADDRESS 0x00059000
|
||||
#define DBI_BASE_ADDRESS 0x00060000
|
||||
#define WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x0006c000
|
||||
#define PCIE_LOCAL_BASE_ADDRESS 0x00080000
|
||||
|
||||
#define SOC_RESET_CONTROL_OFFSET 0x00000000
|
||||
#define SOC_RESET_CONTROL_SI0_RST_MASK 0x00000001
|
||||
#define SOC_CPU_CLOCK_OFFSET 0x00000020
|
||||
#define SOC_CPU_CLOCK_STANDARD_LSB 0
|
||||
#define SOC_CPU_CLOCK_STANDARD_MASK 0x00000003
|
||||
#define SOC_CLOCK_CONTROL_OFFSET 0x00000028
|
||||
#define SOC_CLOCK_CONTROL_SI0_CLK_MASK 0x00000001
|
||||
#define SOC_SYSTEM_SLEEP_OFFSET 0x000000c4
|
||||
#define SOC_LPO_CAL_OFFSET 0x000000e0
|
||||
#define SOC_LPO_CAL_ENABLE_LSB 20
|
||||
#define SOC_LPO_CAL_ENABLE_MASK 0x00100000
|
||||
|
||||
#define WLAN_RESET_CONTROL_COLD_RST_MASK 0x00000008
|
||||
#define WLAN_RESET_CONTROL_WARM_RST_MASK 0x00000004
|
||||
#define WLAN_SYSTEM_SLEEP_DISABLE_LSB 0
|
||||
#define WLAN_SYSTEM_SLEEP_DISABLE_MASK 0x00000001
|
||||
|
||||
#define WLAN_GPIO_PIN0_ADDRESS 0x00000028
|
||||
#define WLAN_GPIO_PIN0_CONFIG_MASK 0x00007800
|
||||
#define WLAN_GPIO_PIN1_ADDRESS 0x0000002c
|
||||
#define WLAN_GPIO_PIN1_CONFIG_MASK 0x00007800
|
||||
#define WLAN_GPIO_PIN10_ADDRESS 0x00000050
|
||||
#define WLAN_GPIO_PIN11_ADDRESS 0x00000054
|
||||
#define WLAN_GPIO_PIN12_ADDRESS 0x00000058
|
||||
#define WLAN_GPIO_PIN13_ADDRESS 0x0000005c
|
||||
|
||||
#define CLOCK_GPIO_OFFSET 0xffffffff
|
||||
#define CLOCK_GPIO_BT_CLK_OUT_EN_LSB 0
|
||||
#define CLOCK_GPIO_BT_CLK_OUT_EN_MASK 0
|
||||
|
||||
#define SI_CONFIG_OFFSET 0x00000000
|
||||
#define SI_CONFIG_BIDIR_OD_DATA_LSB 18
|
||||
#define SI_CONFIG_BIDIR_OD_DATA_MASK 0x00040000
|
||||
#define SI_CONFIG_I2C_LSB 16
|
||||
#define SI_CONFIG_I2C_MASK 0x00010000
|
||||
#define SI_CONFIG_POS_SAMPLE_LSB 7
|
||||
#define SI_CONFIG_POS_SAMPLE_MASK 0x00000080
|
||||
#define SI_CONFIG_INACTIVE_DATA_LSB 5
|
||||
#define SI_CONFIG_INACTIVE_DATA_MASK 0x00000020
|
||||
#define SI_CONFIG_INACTIVE_CLK_LSB 4
|
||||
#define SI_CONFIG_INACTIVE_CLK_MASK 0x00000010
|
||||
#define SI_CONFIG_DIVIDER_LSB 0
|
||||
#define SI_CONFIG_DIVIDER_MASK 0x0000000f
|
||||
#define SI_CS_OFFSET 0x00000004
|
||||
#define SI_CS_DONE_ERR_MASK 0x00000400
|
||||
#define SI_CS_DONE_INT_MASK 0x00000200
|
||||
#define SI_CS_START_LSB 8
|
||||
#define SI_CS_START_MASK 0x00000100
|
||||
#define SI_CS_RX_CNT_LSB 4
|
||||
#define SI_CS_RX_CNT_MASK 0x000000f0
|
||||
#define SI_CS_TX_CNT_LSB 0
|
||||
#define SI_CS_TX_CNT_MASK 0x0000000f
|
||||
|
||||
#define SI_TX_DATA0_OFFSET 0x00000008
|
||||
#define SI_TX_DATA1_OFFSET 0x0000000c
|
||||
#define SI_RX_DATA0_OFFSET 0x00000010
|
||||
#define SI_RX_DATA1_OFFSET 0x00000014
|
||||
|
||||
#define CORE_CTRL_CPU_INTR_MASK 0x00002000
|
||||
#define CORE_CTRL_ADDRESS 0x0000
|
||||
#define PCIE_INTR_ENABLE_ADDRESS 0x0008
|
||||
#define PCIE_INTR_CLR_ADDRESS 0x0014
|
||||
#define SCRATCH_3_ADDRESS 0x0030
|
||||
|
||||
/* Firmware indications to the Host via SCRATCH_3 register. */
|
||||
#define FW_INDICATOR_ADDRESS (SOC_CORE_BASE_ADDRESS + SCRATCH_3_ADDRESS)
|
||||
#define FW_IND_EVENT_PENDING 1
|
||||
#define FW_IND_INITIALIZED 2
|
||||
|
||||
/* HOST_REG interrupt from firmware */
|
||||
#define PCIE_INTR_FIRMWARE_MASK 0x00000400
|
||||
#define PCIE_INTR_CE_MASK_ALL 0x0007f800
|
||||
|
||||
#define DRAM_BASE_ADDRESS 0x00400000
|
||||
|
||||
#define MISSING 0
|
||||
|
||||
#define SYSTEM_SLEEP_OFFSET SOC_SYSTEM_SLEEP_OFFSET
|
||||
#define WLAN_SYSTEM_SLEEP_OFFSET SOC_SYSTEM_SLEEP_OFFSET
|
||||
#define WLAN_RESET_CONTROL_OFFSET SOC_RESET_CONTROL_OFFSET
|
||||
#define CLOCK_CONTROL_OFFSET SOC_CLOCK_CONTROL_OFFSET
|
||||
#define CLOCK_CONTROL_SI0_CLK_MASK SOC_CLOCK_CONTROL_SI0_CLK_MASK
|
||||
#define RESET_CONTROL_MBOX_RST_MASK MISSING
|
||||
#define RESET_CONTROL_SI0_RST_MASK SOC_RESET_CONTROL_SI0_RST_MASK
|
||||
#define GPIO_BASE_ADDRESS WLAN_GPIO_BASE_ADDRESS
|
||||
#define GPIO_PIN0_OFFSET WLAN_GPIO_PIN0_ADDRESS
|
||||
#define GPIO_PIN1_OFFSET WLAN_GPIO_PIN1_ADDRESS
|
||||
#define GPIO_PIN0_CONFIG_MASK WLAN_GPIO_PIN0_CONFIG_MASK
|
||||
#define GPIO_PIN1_CONFIG_MASK WLAN_GPIO_PIN1_CONFIG_MASK
|
||||
#define SI_BASE_ADDRESS WLAN_SI_BASE_ADDRESS
|
||||
#define SCRATCH_BASE_ADDRESS SOC_CORE_BASE_ADDRESS
|
||||
#define LOCAL_SCRATCH_OFFSET 0x18
|
||||
#define CPU_CLOCK_OFFSET SOC_CPU_CLOCK_OFFSET
|
||||
#define LPO_CAL_OFFSET SOC_LPO_CAL_OFFSET
|
||||
#define GPIO_PIN10_OFFSET WLAN_GPIO_PIN10_ADDRESS
|
||||
#define GPIO_PIN11_OFFSET WLAN_GPIO_PIN11_ADDRESS
|
||||
#define GPIO_PIN12_OFFSET WLAN_GPIO_PIN12_ADDRESS
|
||||
#define GPIO_PIN13_OFFSET WLAN_GPIO_PIN13_ADDRESS
|
||||
#define CPU_CLOCK_STANDARD_LSB SOC_CPU_CLOCK_STANDARD_LSB
|
||||
#define CPU_CLOCK_STANDARD_MASK SOC_CPU_CLOCK_STANDARD_MASK
|
||||
#define LPO_CAL_ENABLE_LSB SOC_LPO_CAL_ENABLE_LSB
|
||||
#define LPO_CAL_ENABLE_MASK SOC_LPO_CAL_ENABLE_MASK
|
||||
#define ANALOG_INTF_BASE_ADDRESS WLAN_ANALOG_INTF_BASE_ADDRESS
|
||||
#define MBOX_BASE_ADDRESS MISSING
|
||||
#define INT_STATUS_ENABLE_ERROR_LSB MISSING
|
||||
#define INT_STATUS_ENABLE_ERROR_MASK MISSING
|
||||
#define INT_STATUS_ENABLE_CPU_LSB MISSING
|
||||
#define INT_STATUS_ENABLE_CPU_MASK MISSING
|
||||
#define INT_STATUS_ENABLE_COUNTER_LSB MISSING
|
||||
#define INT_STATUS_ENABLE_COUNTER_MASK MISSING
|
||||
#define INT_STATUS_ENABLE_MBOX_DATA_LSB MISSING
|
||||
#define INT_STATUS_ENABLE_MBOX_DATA_MASK MISSING
|
||||
#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB MISSING
|
||||
#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK MISSING
|
||||
#define ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB MISSING
|
||||
#define ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK MISSING
|
||||
#define COUNTER_INT_STATUS_ENABLE_BIT_LSB MISSING
|
||||
#define COUNTER_INT_STATUS_ENABLE_BIT_MASK MISSING
|
||||
#define INT_STATUS_ENABLE_ADDRESS MISSING
|
||||
#define CPU_INT_STATUS_ENABLE_BIT_LSB MISSING
|
||||
#define CPU_INT_STATUS_ENABLE_BIT_MASK MISSING
|
||||
#define HOST_INT_STATUS_ADDRESS MISSING
|
||||
#define CPU_INT_STATUS_ADDRESS MISSING
|
||||
#define ERROR_INT_STATUS_ADDRESS MISSING
|
||||
#define ERROR_INT_STATUS_WAKEUP_MASK MISSING
|
||||
#define ERROR_INT_STATUS_WAKEUP_LSB MISSING
|
||||
#define ERROR_INT_STATUS_RX_UNDERFLOW_MASK MISSING
|
||||
#define ERROR_INT_STATUS_RX_UNDERFLOW_LSB MISSING
|
||||
#define ERROR_INT_STATUS_TX_OVERFLOW_MASK MISSING
|
||||
#define ERROR_INT_STATUS_TX_OVERFLOW_LSB MISSING
|
||||
#define COUNT_DEC_ADDRESS MISSING
|
||||
#define HOST_INT_STATUS_CPU_MASK MISSING
|
||||
#define HOST_INT_STATUS_CPU_LSB MISSING
|
||||
#define HOST_INT_STATUS_ERROR_MASK MISSING
|
||||
#define HOST_INT_STATUS_ERROR_LSB MISSING
|
||||
#define HOST_INT_STATUS_COUNTER_MASK MISSING
|
||||
#define HOST_INT_STATUS_COUNTER_LSB MISSING
|
||||
#define RX_LOOKAHEAD_VALID_ADDRESS MISSING
|
||||
#define WINDOW_DATA_ADDRESS MISSING
|
||||
#define WINDOW_READ_ADDR_ADDRESS MISSING
|
||||
#define WINDOW_WRITE_ADDR_ADDRESS MISSING
|
||||
|
||||
#define RTC_STATE_V_GET(x) (((x) & RTC_STATE_V_MASK) >> RTC_STATE_V_LSB)
|
||||
|
||||
#endif /* _HW_H_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2013 Qualcomm Atheros, 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 _MAC_H_
|
||||
#define _MAC_H_
|
||||
|
||||
#include <net/mac80211.h>
|
||||
#include "core.h"
|
||||
|
||||
struct ath10k_generic_iter {
|
||||
struct ath10k *ar;
|
||||
int ret;
|
||||
};
|
||||
|
||||
struct ath10k *ath10k_mac_create(void);
|
||||
void ath10k_mac_destroy(struct ath10k *ar);
|
||||
int ath10k_mac_register(struct ath10k *ar);
|
||||
void ath10k_mac_unregister(struct ath10k *ar);
|
||||
struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id);
|
||||
void ath10k_reset_scan(unsigned long ptr);
|
||||
void ath10k_offchan_tx_purge(struct ath10k *ar);
|
||||
void ath10k_offchan_tx_work(struct work_struct *work);
|
||||
|
||||
static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif)
|
||||
{
|
||||
return (struct ath10k_vif *)vif->drv_priv;
|
||||
}
|
||||
|
||||
static inline void ath10k_tx_h_seq_no(struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct ieee80211_vif *vif = info->control.vif;
|
||||
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
|
||||
if (arvif->tx_seq_no == 0)
|
||||
arvif->tx_seq_no = 0x1000;
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
|
||||
arvif->tx_seq_no += 0x10;
|
||||
hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
|
||||
hdr->seq_ctrl |= cpu_to_le16(arvif->tx_seq_no);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _MAC_H_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,355 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2013 Qualcomm Atheros, 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 _PCI_H_
|
||||
#define _PCI_H_
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "hw.h"
|
||||
#include "ce.h"
|
||||
|
||||
/* FW dump area */
|
||||
#define REG_DUMP_COUNT_QCA988X 60
|
||||
|
||||
/*
|
||||
* maximum number of bytes that can be handled atomically by DiagRead/DiagWrite
|
||||
*/
|
||||
#define DIAG_TRANSFER_LIMIT 2048
|
||||
|
||||
/*
|
||||
* maximum number of bytes that can be
|
||||
* handled atomically by DiagRead/DiagWrite
|
||||
*/
|
||||
#define DIAG_TRANSFER_LIMIT 2048
|
||||
|
||||
struct bmi_xfer {
|
||||
struct completion done;
|
||||
bool wait_for_resp;
|
||||
u32 resp_len;
|
||||
};
|
||||
|
||||
struct ath10k_pci_compl {
|
||||
struct list_head list;
|
||||
int send_or_recv;
|
||||
struct ce_state *ce_state;
|
||||
struct hif_ce_pipe_info *pipe_info;
|
||||
void *transfer_context;
|
||||
unsigned int nbytes;
|
||||
unsigned int transfer_id;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
/* compl_state.send_or_recv */
|
||||
#define HIF_CE_COMPLETE_FREE 0
|
||||
#define HIF_CE_COMPLETE_SEND 1
|
||||
#define HIF_CE_COMPLETE_RECV 2
|
||||
|
||||
/*
|
||||
* PCI-specific Target state
|
||||
*
|
||||
* NOTE: Structure is shared between Host software and Target firmware!
|
||||
*
|
||||
* Much of this may be of interest to the Host so
|
||||
* HOST_INTEREST->hi_interconnect_state points here
|
||||
* (and all members are 32-bit quantities in order to
|
||||
* facilitate Host access). In particular, Host software is
|
||||
* required to initialize pipe_cfg_addr and svc_to_pipe_map.
|
||||
*/
|
||||
struct pcie_state {
|
||||
/* Pipe configuration Target address */
|
||||
/* NB: ce_pipe_config[CE_COUNT] */
|
||||
u32 pipe_cfg_addr;
|
||||
|
||||
/* Service to pipe map Target address */
|
||||
/* NB: service_to_pipe[PIPE_TO_CE_MAP_CN] */
|
||||
u32 svc_to_pipe_map;
|
||||
|
||||
/* number of MSI interrupts requested */
|
||||
u32 msi_requested;
|
||||
|
||||
/* number of MSI interrupts granted */
|
||||
u32 msi_granted;
|
||||
|
||||
/* Message Signalled Interrupt address */
|
||||
u32 msi_addr;
|
||||
|
||||
/* Base data */
|
||||
u32 msi_data;
|
||||
|
||||
/*
|
||||
* Data for firmware interrupt;
|
||||
* MSI data for other interrupts are
|
||||
* in various SoC registers
|
||||
*/
|
||||
u32 msi_fw_intr_data;
|
||||
|
||||
/* PCIE_PWR_METHOD_* */
|
||||
u32 power_mgmt_method;
|
||||
|
||||
/* PCIE_CONFIG_FLAG_* */
|
||||
u32 config_flags;
|
||||
};
|
||||
|
||||
/* PCIE_CONFIG_FLAG definitions */
|
||||
#define PCIE_CONFIG_FLAG_ENABLE_L1 0x0000001
|
||||
|
||||
/* Host software's Copy Engine configuration. */
|
||||
#define CE_ATTR_FLAGS 0
|
||||
|
||||
/*
|
||||
* Configuration information for a Copy Engine pipe.
|
||||
* Passed from Host to Target during startup (one per CE).
|
||||
*
|
||||
* NOTE: Structure is shared between Host software and Target firmware!
|
||||
*/
|
||||
struct ce_pipe_config {
|
||||
u32 pipenum;
|
||||
u32 pipedir;
|
||||
u32 nentries;
|
||||
u32 nbytes_max;
|
||||
u32 flags;
|
||||
u32 reserved;
|
||||
};
|
||||
|
||||
/*
|
||||
* Directions for interconnect pipe configuration.
|
||||
* These definitions may be used during configuration and are shared
|
||||
* between Host and Target.
|
||||
*
|
||||
* Pipe Directions are relative to the Host, so PIPEDIR_IN means
|
||||
* "coming IN over air through Target to Host" as with a WiFi Rx operation.
|
||||
* Conversely, PIPEDIR_OUT means "going OUT from Host through Target over air"
|
||||
* as with a WiFi Tx operation. This is somewhat awkward for the "middle-man"
|
||||
* Target since things that are "PIPEDIR_OUT" are coming IN to the Target
|
||||
* over the interconnect.
|
||||
*/
|
||||
#define PIPEDIR_NONE 0
|
||||
#define PIPEDIR_IN 1 /* Target-->Host, WiFi Rx direction */
|
||||
#define PIPEDIR_OUT 2 /* Host->Target, WiFi Tx direction */
|
||||
#define PIPEDIR_INOUT 3 /* bidirectional */
|
||||
|
||||
/* Establish a mapping between a service/direction and a pipe. */
|
||||
struct service_to_pipe {
|
||||
u32 service_id;
|
||||
u32 pipedir;
|
||||
u32 pipenum;
|
||||
};
|
||||
|
||||
enum ath10k_pci_features {
|
||||
ATH10K_PCI_FEATURE_MSI_X = 0,
|
||||
ATH10K_PCI_FEATURE_HW_1_0_WARKAROUND = 1,
|
||||
|
||||
/* keep last */
|
||||
ATH10K_PCI_FEATURE_COUNT
|
||||
};
|
||||
|
||||
/* Per-pipe state. */
|
||||
struct hif_ce_pipe_info {
|
||||
/* Handle of underlying Copy Engine */
|
||||
struct ce_state *ce_hdl;
|
||||
|
||||
/* Our pipe number; facilitiates use of pipe_info ptrs. */
|
||||
u8 pipe_num;
|
||||
|
||||
/* Convenience back pointer to hif_ce_state. */
|
||||
struct ath10k *hif_ce_state;
|
||||
|
||||
size_t buf_sz;
|
||||
|
||||
/* protects compl_free and num_send_allowed */
|
||||
spinlock_t pipe_lock;
|
||||
|
||||
/* List of free CE completion slots */
|
||||
struct list_head compl_free;
|
||||
|
||||
/* Limit the number of outstanding send requests. */
|
||||
int num_sends_allowed;
|
||||
|
||||
struct ath10k_pci *ar_pci;
|
||||
struct tasklet_struct intr;
|
||||
};
|
||||
|
||||
struct ath10k_pci {
|
||||
struct pci_dev *pdev;
|
||||
struct device *dev;
|
||||
struct ath10k *ar;
|
||||
void __iomem *mem;
|
||||
int cacheline_sz;
|
||||
|
||||
DECLARE_BITMAP(features, ATH10K_PCI_FEATURE_COUNT);
|
||||
|
||||
/*
|
||||
* Number of MSI interrupts granted, 0 --> using legacy PCI line
|
||||
* interrupts.
|
||||
*/
|
||||
int num_msi_intrs;
|
||||
|
||||
struct tasklet_struct intr_tq;
|
||||
struct tasklet_struct msi_fw_err;
|
||||
|
||||
/* Number of Copy Engines supported */
|
||||
unsigned int ce_count;
|
||||
|
||||
int started;
|
||||
|
||||
atomic_t keep_awake_count;
|
||||
bool verified_awake;
|
||||
|
||||
/* List of CE completions to be processed */
|
||||
struct list_head compl_process;
|
||||
|
||||
/* protects compl_processing and compl_process */
|
||||
spinlock_t compl_lock;
|
||||
|
||||
bool compl_processing;
|
||||
|
||||
struct hif_ce_pipe_info pipe_info[CE_COUNT_MAX];
|
||||
|
||||
struct ath10k_hif_cb msg_callbacks_current;
|
||||
|
||||
/* Target address used to signal a pending firmware event */
|
||||
u32 fw_indicator_address;
|
||||
|
||||
/* Copy Engine used for Diagnostic Accesses */
|
||||
struct ce_state *ce_diag;
|
||||
|
||||
/* FIXME: document what this really protects */
|
||||
spinlock_t ce_lock;
|
||||
|
||||
/* Map CE id to ce_state */
|
||||
struct ce_state *ce_id_to_state[CE_COUNT_MAX];
|
||||
|
||||
/* makes sure that dummy reads are atomic */
|
||||
spinlock_t hw_v1_workaround_lock;
|
||||
};
|
||||
|
||||
static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
|
||||
{
|
||||
return ar->hif.priv;
|
||||
}
|
||||
|
||||
static inline u32 ath10k_pci_reg_read32(void __iomem *mem, u32 addr)
|
||||
{
|
||||
return ioread32(mem + PCIE_LOCAL_BASE_ADDRESS + addr);
|
||||
}
|
||||
|
||||
static inline void ath10k_pci_reg_write32(void __iomem *mem, u32 addr, u32 val)
|
||||
{
|
||||
iowrite32(val, mem + PCIE_LOCAL_BASE_ADDRESS + addr);
|
||||
}
|
||||
|
||||
#define ATH_PCI_RESET_WAIT_MAX 10 /* ms */
|
||||
#define PCIE_WAKE_TIMEOUT 5000 /* 5ms */
|
||||
|
||||
#define BAR_NUM 0
|
||||
|
||||
#define CDC_WAR_MAGIC_STR 0xceef0000
|
||||
#define CDC_WAR_DATA_CE 4
|
||||
|
||||
/*
|
||||
* TODO: Should be a function call specific to each Target-type.
|
||||
* This convoluted macro converts from Target CPU Virtual Address Space to CE
|
||||
* Address Space. As part of this process, we conservatively fetch the current
|
||||
* PCIE_BAR. MOST of the time, this should match the upper bits of PCI space
|
||||
* for this device; but that's not guaranteed.
|
||||
*/
|
||||
#define TARG_CPU_SPACE_TO_CE_SPACE(ar, pci_addr, addr) \
|
||||
(((ioread32((pci_addr)+(SOC_CORE_BASE_ADDRESS| \
|
||||
CORE_CTRL_ADDRESS)) & 0x7ff) << 21) | \
|
||||
0x100000 | ((addr) & 0xfffff))
|
||||
|
||||
/* Wait up to this many Ms for a Diagnostic Access CE operation to complete */
|
||||
#define DIAG_ACCESS_CE_TIMEOUT_MS 10
|
||||
|
||||
/*
|
||||
* This API allows the Host to access Target registers directly
|
||||
* and relatively efficiently over PCIe.
|
||||
* This allows the Host to avoid extra overhead associated with
|
||||
* sending a message to firmware and waiting for a response message
|
||||
* from firmware, as is done on other interconnects.
|
||||
*
|
||||
* Yet there is some complexity with direct accesses because the
|
||||
* Target's power state is not known a priori. The Host must issue
|
||||
* special PCIe reads/writes in order to explicitly wake the Target
|
||||
* and to verify that it is awake and will remain awake.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* Use ath10k_pci_read32 and ath10k_pci_write32 to access Target space.
|
||||
* These calls must be bracketed by ath10k_pci_wake and
|
||||
* ath10k_pci_sleep. A single BEGIN/END pair is adequate for
|
||||
* multiple READ/WRITE operations.
|
||||
*
|
||||
* Use ath10k_pci_wake to put the Target in a state in
|
||||
* which it is legal for the Host to directly access it. This
|
||||
* may involve waking the Target from a low power state, which
|
||||
* may take up to 2Ms!
|
||||
*
|
||||
* Use ath10k_pci_sleep to tell the Target that as far as
|
||||
* this code path is concerned, it no longer needs to remain
|
||||
* directly accessible. BEGIN/END is under a reference counter;
|
||||
* multiple code paths may issue BEGIN/END on a single targid.
|
||||
*/
|
||||
static inline void ath10k_pci_write32(struct ath10k *ar, u32 offset,
|
||||
u32 value)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
void __iomem *addr = ar_pci->mem;
|
||||
|
||||
if (test_bit(ATH10K_PCI_FEATURE_HW_1_0_WARKAROUND, ar_pci->features)) {
|
||||
unsigned long irq_flags;
|
||||
|
||||
spin_lock_irqsave(&ar_pci->hw_v1_workaround_lock, irq_flags);
|
||||
|
||||
ioread32(addr+offset+4); /* 3rd read prior to write */
|
||||
ioread32(addr+offset+4); /* 2nd read prior to write */
|
||||
ioread32(addr+offset+4); /* 1st read prior to write */
|
||||
iowrite32(value, addr+offset);
|
||||
|
||||
spin_unlock_irqrestore(&ar_pci->hw_v1_workaround_lock,
|
||||
irq_flags);
|
||||
} else {
|
||||
iowrite32(value, addr+offset);
|
||||
}
|
||||
}
|
||||
|
||||
static inline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
|
||||
return ioread32(ar_pci->mem + offset);
|
||||
}
|
||||
|
||||
extern unsigned int ath10k_target_ps;
|
||||
|
||||
void ath10k_do_pci_wake(struct ath10k *ar);
|
||||
void ath10k_do_pci_sleep(struct ath10k *ar);
|
||||
|
||||
static inline void ath10k_pci_wake(struct ath10k *ar)
|
||||
{
|
||||
if (ath10k_target_ps)
|
||||
ath10k_do_pci_wake(ar);
|
||||
}
|
||||
|
||||
static inline void ath10k_pci_sleep(struct ath10k *ar)
|
||||
{
|
||||
if (ath10k_target_ps)
|
||||
ath10k_do_pci_sleep(ar);
|
||||
}
|
||||
|
||||
#endif /* _PCI_H_ */
|
|
@ -0,0 +1,990 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2013 Qualcomm Atheros, 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 _RX_DESC_H_
|
||||
#define _RX_DESC_H_
|
||||
|
||||
enum rx_attention_flags {
|
||||
RX_ATTENTION_FLAGS_FIRST_MPDU = 1 << 0,
|
||||
RX_ATTENTION_FLAGS_LAST_MPDU = 1 << 1,
|
||||
RX_ATTENTION_FLAGS_MCAST_BCAST = 1 << 2,
|
||||
RX_ATTENTION_FLAGS_PEER_IDX_INVALID = 1 << 3,
|
||||
RX_ATTENTION_FLAGS_PEER_IDX_TIMEOUT = 1 << 4,
|
||||
RX_ATTENTION_FLAGS_POWER_MGMT = 1 << 5,
|
||||
RX_ATTENTION_FLAGS_NON_QOS = 1 << 6,
|
||||
RX_ATTENTION_FLAGS_NULL_DATA = 1 << 7,
|
||||
RX_ATTENTION_FLAGS_MGMT_TYPE = 1 << 8,
|
||||
RX_ATTENTION_FLAGS_CTRL_TYPE = 1 << 9,
|
||||
RX_ATTENTION_FLAGS_MORE_DATA = 1 << 10,
|
||||
RX_ATTENTION_FLAGS_EOSP = 1 << 11,
|
||||
RX_ATTENTION_FLAGS_U_APSD_TRIGGER = 1 << 12,
|
||||
RX_ATTENTION_FLAGS_FRAGMENT = 1 << 13,
|
||||
RX_ATTENTION_FLAGS_ORDER = 1 << 14,
|
||||
RX_ATTENTION_FLAGS_CLASSIFICATION = 1 << 15,
|
||||
RX_ATTENTION_FLAGS_OVERFLOW_ERR = 1 << 16,
|
||||
RX_ATTENTION_FLAGS_MSDU_LENGTH_ERR = 1 << 17,
|
||||
RX_ATTENTION_FLAGS_TCP_UDP_CHKSUM_FAIL = 1 << 18,
|
||||
RX_ATTENTION_FLAGS_IP_CHKSUM_FAIL = 1 << 19,
|
||||
RX_ATTENTION_FLAGS_SA_IDX_INVALID = 1 << 20,
|
||||
RX_ATTENTION_FLAGS_DA_IDX_INVALID = 1 << 21,
|
||||
RX_ATTENTION_FLAGS_SA_IDX_TIMEOUT = 1 << 22,
|
||||
RX_ATTENTION_FLAGS_DA_IDX_TIMEOUT = 1 << 23,
|
||||
RX_ATTENTION_FLAGS_ENCRYPT_REQUIRED = 1 << 24,
|
||||
RX_ATTENTION_FLAGS_DIRECTED = 1 << 25,
|
||||
RX_ATTENTION_FLAGS_BUFFER_FRAGMENT = 1 << 26,
|
||||
RX_ATTENTION_FLAGS_MPDU_LENGTH_ERR = 1 << 27,
|
||||
RX_ATTENTION_FLAGS_TKIP_MIC_ERR = 1 << 28,
|
||||
RX_ATTENTION_FLAGS_DECRYPT_ERR = 1 << 29,
|
||||
RX_ATTENTION_FLAGS_FCS_ERR = 1 << 30,
|
||||
RX_ATTENTION_FLAGS_MSDU_DONE = 1 << 31,
|
||||
};
|
||||
|
||||
struct rx_attention {
|
||||
__le32 flags; /* %RX_ATTENTION_FLAGS_ */
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* first_mpdu
|
||||
* Indicates the first MSDU of the PPDU. If both first_mpdu
|
||||
* and last_mpdu are set in the MSDU then this is a not an
|
||||
* A-MPDU frame but a stand alone MPDU. Interior MPDU in an
|
||||
* A-MPDU shall have both first_mpdu and last_mpdu bits set to
|
||||
* 0. The PPDU start status will only be valid when this bit
|
||||
* is set.
|
||||
*
|
||||
* last_mpdu
|
||||
* Indicates the last MSDU of the last MPDU of the PPDU. The
|
||||
* PPDU end status will only be valid when this bit is set.
|
||||
*
|
||||
* mcast_bcast
|
||||
* Multicast / broadcast indicator. Only set when the MAC
|
||||
* address 1 bit 0 is set indicating mcast/bcast and the BSSID
|
||||
* matches one of the 4 BSSID registers. Only set when
|
||||
* first_msdu is set.
|
||||
*
|
||||
* peer_idx_invalid
|
||||
* Indicates no matching entries within the the max search
|
||||
* count. Only set when first_msdu is set.
|
||||
*
|
||||
* peer_idx_timeout
|
||||
* Indicates an unsuccessful search for the peer index due to
|
||||
* timeout. Only set when first_msdu is set.
|
||||
*
|
||||
* power_mgmt
|
||||
* Power management bit set in the 802.11 header. Only set
|
||||
* when first_msdu is set.
|
||||
*
|
||||
* non_qos
|
||||
* Set if packet is not a non-QoS data frame. Only set when
|
||||
* first_msdu is set.
|
||||
*
|
||||
* null_data
|
||||
* Set if frame type indicates either null data or QoS null
|
||||
* data format. Only set when first_msdu is set.
|
||||
*
|
||||
* mgmt_type
|
||||
* Set if packet is a management packet. Only set when
|
||||
* first_msdu is set.
|
||||
*
|
||||
* ctrl_type
|
||||
* Set if packet is a control packet. Only set when first_msdu
|
||||
* is set.
|
||||
*
|
||||
* more_data
|
||||
* Set if more bit in frame control is set. Only set when
|
||||
* first_msdu is set.
|
||||
*
|
||||
* eosp
|
||||
* Set if the EOSP (end of service period) bit in the QoS
|
||||
* control field is set. Only set when first_msdu is set.
|
||||
*
|
||||
* u_apsd_trigger
|
||||
* Set if packet is U-APSD trigger. Key table will have bits
|
||||
* per TID to indicate U-APSD trigger.
|
||||
*
|
||||
* fragment
|
||||
* Indicates that this is an 802.11 fragment frame. This is
|
||||
* set when either the more_frag bit is set in the frame
|
||||
* control or the fragment number is not zero. Only set when
|
||||
* first_msdu is set.
|
||||
*
|
||||
* order
|
||||
* Set if the order bit in the frame control is set. Only set
|
||||
* when first_msdu is set.
|
||||
*
|
||||
* classification
|
||||
* Indicates that this status has a corresponding MSDU that
|
||||
* requires FW processing. The OLE will have classification
|
||||
* ring mask registers which will indicate the ring(s) for
|
||||
* packets and descriptors which need FW attention.
|
||||
*
|
||||
* overflow_err
|
||||
* PCU Receive FIFO does not have enough space to store the
|
||||
* full receive packet. Enough space is reserved in the
|
||||
* receive FIFO for the status is written. This MPDU remaining
|
||||
* packets in the PPDU will be filtered and no Ack response
|
||||
* will be transmitted.
|
||||
*
|
||||
* msdu_length_err
|
||||
* Indicates that the MSDU length from the 802.3 encapsulated
|
||||
* length field extends beyond the MPDU boundary.
|
||||
*
|
||||
* tcp_udp_chksum_fail
|
||||
* Indicates that the computed checksum (tcp_udp_chksum) did
|
||||
* not match the checksum in the TCP/UDP header.
|
||||
*
|
||||
* ip_chksum_fail
|
||||
* Indicates that the computed checksum did not match the
|
||||
* checksum in the IP header.
|
||||
*
|
||||
* sa_idx_invalid
|
||||
* Indicates no matching entry was found in the address search
|
||||
* table for the source MAC address.
|
||||
*
|
||||
* da_idx_invalid
|
||||
* Indicates no matching entry was found in the address search
|
||||
* table for the destination MAC address.
|
||||
*
|
||||
* sa_idx_timeout
|
||||
* Indicates an unsuccessful search for the source MAC address
|
||||
* due to the expiring of the search timer.
|
||||
*
|
||||
* da_idx_timeout
|
||||
* Indicates an unsuccessful search for the destination MAC
|
||||
* address due to the expiring of the search timer.
|
||||
*
|
||||
* encrypt_required
|
||||
* Indicates that this data type frame is not encrypted even if
|
||||
* the policy for this MPDU requires encryption as indicated in
|
||||
* the peer table key type.
|
||||
*
|
||||
* directed
|
||||
* MPDU is a directed packet which means that the RA matched
|
||||
* our STA addresses. In proxySTA it means that the TA matched
|
||||
* an entry in our address search table with the corresponding
|
||||
* 'no_ack' bit is the address search entry cleared.
|
||||
*
|
||||
* buffer_fragment
|
||||
* Indicates that at least one of the rx buffers has been
|
||||
* fragmented. If set the FW should look at the rx_frag_info
|
||||
* descriptor described below.
|
||||
*
|
||||
* mpdu_length_err
|
||||
* Indicates that the MPDU was pre-maturely terminated
|
||||
* resulting in a truncated MPDU. Don't trust the MPDU length
|
||||
* field.
|
||||
*
|
||||
* tkip_mic_err
|
||||
* Indicates that the MPDU Michael integrity check failed
|
||||
*
|
||||
* decrypt_err
|
||||
* Indicates that the MPDU decrypt integrity check failed
|
||||
*
|
||||
* fcs_err
|
||||
* Indicates that the MPDU FCS check failed
|
||||
*
|
||||
* msdu_done
|
||||
* If set indicates that the RX packet data, RX header data, RX
|
||||
* PPDU start descriptor, RX MPDU start/end descriptor, RX MSDU
|
||||
* start/end descriptors and RX Attention descriptor are all
|
||||
* valid. This bit must be in the last octet of the
|
||||
* descriptor.
|
||||
*/
|
||||
|
||||
struct rx_frag_info {
|
||||
u8 ring0_more_count;
|
||||
u8 ring1_more_count;
|
||||
u8 ring2_more_count;
|
||||
u8 ring3_more_count;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* ring0_more_count
|
||||
* Indicates the number of more buffers associated with RX DMA
|
||||
* ring 0. Field is filled in by the RX_DMA.
|
||||
*
|
||||
* ring1_more_count
|
||||
* Indicates the number of more buffers associated with RX DMA
|
||||
* ring 1. Field is filled in by the RX_DMA.
|
||||
*
|
||||
* ring2_more_count
|
||||
* Indicates the number of more buffers associated with RX DMA
|
||||
* ring 2. Field is filled in by the RX_DMA.
|
||||
*
|
||||
* ring3_more_count
|
||||
* Indicates the number of more buffers associated with RX DMA
|
||||
* ring 3. Field is filled in by the RX_DMA.
|
||||
*/
|
||||
|
||||
enum htt_rx_mpdu_encrypt_type {
|
||||
HTT_RX_MPDU_ENCRYPT_WEP40 = 0,
|
||||
HTT_RX_MPDU_ENCRYPT_WEP104 = 1,
|
||||
HTT_RX_MPDU_ENCRYPT_TKIP_WITHOUT_MIC = 2,
|
||||
HTT_RX_MPDU_ENCRYPT_WEP128 = 3,
|
||||
HTT_RX_MPDU_ENCRYPT_TKIP_WPA = 4,
|
||||
HTT_RX_MPDU_ENCRYPT_WAPI = 5,
|
||||
HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2 = 6,
|
||||
HTT_RX_MPDU_ENCRYPT_NONE = 7,
|
||||
};
|
||||
|
||||
#define RX_MPDU_START_INFO0_PEER_IDX_MASK 0x000007ff
|
||||
#define RX_MPDU_START_INFO0_PEER_IDX_LSB 0
|
||||
#define RX_MPDU_START_INFO0_SEQ_NUM_MASK 0x0fff0000
|
||||
#define RX_MPDU_START_INFO0_SEQ_NUM_LSB 16
|
||||
#define RX_MPDU_START_INFO0_ENCRYPT_TYPE_MASK 0xf0000000
|
||||
#define RX_MPDU_START_INFO0_ENCRYPT_TYPE_LSB 28
|
||||
#define RX_MPDU_START_INFO0_FROM_DS (1 << 11)
|
||||
#define RX_MPDU_START_INFO0_TO_DS (1 << 12)
|
||||
#define RX_MPDU_START_INFO0_ENCRYPTED (1 << 13)
|
||||
#define RX_MPDU_START_INFO0_RETRY (1 << 14)
|
||||
#define RX_MPDU_START_INFO0_TXBF_H_INFO (1 << 15)
|
||||
|
||||
#define RX_MPDU_START_INFO1_TID_MASK 0xf0000000
|
||||
#define RX_MPDU_START_INFO1_TID_LSB 28
|
||||
#define RX_MPDU_START_INFO1_DIRECTED (1 << 16)
|
||||
|
||||
struct rx_mpdu_start {
|
||||
__le32 info0;
|
||||
union {
|
||||
struct {
|
||||
__le32 pn31_0;
|
||||
__le32 info1; /* %RX_MPDU_START_INFO1_ */
|
||||
} __packed;
|
||||
struct {
|
||||
u8 pn[6];
|
||||
} __packed;
|
||||
} __packed;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* peer_idx
|
||||
* The index of the address search table which associated with
|
||||
* the peer table entry corresponding to this MPDU. Only valid
|
||||
* when first_msdu is set.
|
||||
*
|
||||
* fr_ds
|
||||
* Set if the from DS bit is set in the frame control. Only
|
||||
* valid when first_msdu is set.
|
||||
*
|
||||
* to_ds
|
||||
* Set if the to DS bit is set in the frame control. Only
|
||||
* valid when first_msdu is set.
|
||||
*
|
||||
* encrypted
|
||||
* Protected bit from the frame control. Only valid when
|
||||
* first_msdu is set.
|
||||
*
|
||||
* retry
|
||||
* Retry bit from the frame control. Only valid when
|
||||
* first_msdu is set.
|
||||
*
|
||||
* txbf_h_info
|
||||
* The MPDU data will contain H information. Primarily used
|
||||
* for debug.
|
||||
*
|
||||
* seq_num
|
||||
* The sequence number from the 802.11 header. Only valid when
|
||||
* first_msdu is set.
|
||||
*
|
||||
* encrypt_type
|
||||
* Indicates type of decrypt cipher used (as defined in the
|
||||
* peer table)
|
||||
* 0: WEP40
|
||||
* 1: WEP104
|
||||
* 2: TKIP without MIC
|
||||
* 3: WEP128
|
||||
* 4: TKIP (WPA)
|
||||
* 5: WAPI
|
||||
* 6: AES-CCM (WPA2)
|
||||
* 7: No cipher
|
||||
* Only valid when first_msdu_is set
|
||||
*
|
||||
* pn_31_0
|
||||
* Bits [31:0] of the PN number extracted from the IV field
|
||||
* WEP: IV = {key_id_octet, pn2, pn1, pn0}. Only pn[23:0] is
|
||||
* valid.
|
||||
* TKIP: IV = {pn5, pn4, pn3, pn2, key_id_octet, pn0,
|
||||
* WEPSeed[1], pn1}. Only pn[47:0] is valid.
|
||||
* AES-CCM: IV = {pn5, pn4, pn3, pn2, key_id_octet, 0x0, pn1,
|
||||
* pn0}. Only pn[47:0] is valid.
|
||||
* WAPI: IV = {key_id_octet, 0x0, pn15, pn14, pn13, pn12, pn11,
|
||||
* pn10, pn9, pn8, pn7, pn6, pn5, pn4, pn3, pn2, pn1, pn0}.
|
||||
* The ext_wapi_pn[127:48] in the rx_msdu_misc descriptor and
|
||||
* pn[47:0] are valid.
|
||||
* Only valid when first_msdu is set.
|
||||
*
|
||||
* pn_47_32
|
||||
* Bits [47:32] of the PN number. See description for
|
||||
* pn_31_0. The remaining PN fields are in the rx_msdu_end
|
||||
* descriptor
|
||||
*
|
||||
* pn
|
||||
* Use this field to access the pn without worrying about
|
||||
* byte-order and bitmasking/bitshifting.
|
||||
*
|
||||
* directed
|
||||
* See definition in RX attention descriptor
|
||||
*
|
||||
* reserved_2
|
||||
* Reserved: HW should fill with zero. FW should ignore.
|
||||
*
|
||||
* tid
|
||||
* The TID field in the QoS control field
|
||||
*/
|
||||
|
||||
#define RX_MPDU_END_INFO0_RESERVED_0_MASK 0x00001fff
|
||||
#define RX_MPDU_END_INFO0_RESERVED_0_LSB 0
|
||||
#define RX_MPDU_END_INFO0_POST_DELIM_CNT_MASK 0x0fff0000
|
||||
#define RX_MPDU_END_INFO0_POST_DELIM_CNT_LSB 16
|
||||
#define RX_MPDU_END_INFO0_OVERFLOW_ERR (1 << 13)
|
||||
#define RX_MPDU_END_INFO0_LAST_MPDU (1 << 14)
|
||||
#define RX_MPDU_END_INFO0_POST_DELIM_ERR (1 << 15)
|
||||
#define RX_MPDU_END_INFO0_MPDU_LENGTH_ERR (1 << 28)
|
||||
#define RX_MPDU_END_INFO0_TKIP_MIC_ERR (1 << 29)
|
||||
#define RX_MPDU_END_INFO0_DECRYPT_ERR (1 << 30)
|
||||
#define RX_MPDU_END_INFO0_FCS_ERR (1 << 31)
|
||||
|
||||
struct rx_mpdu_end {
|
||||
__le32 info0;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* reserved_0
|
||||
* Reserved
|
||||
*
|
||||
* overflow_err
|
||||
* PCU Receive FIFO does not have enough space to store the
|
||||
* full receive packet. Enough space is reserved in the
|
||||
* receive FIFO for the status is written. This MPDU remaining
|
||||
* packets in the PPDU will be filtered and no Ack response
|
||||
* will be transmitted.
|
||||
*
|
||||
* last_mpdu
|
||||
* Indicates that this is the last MPDU of a PPDU.
|
||||
*
|
||||
* post_delim_err
|
||||
* Indicates that a delimiter FCS error occurred after this
|
||||
* MPDU before the next MPDU. Only valid when last_msdu is
|
||||
* set.
|
||||
*
|
||||
* post_delim_cnt
|
||||
* Count of the delimiters after this MPDU. This requires the
|
||||
* last MPDU to be held until all the EOF descriptors have been
|
||||
* received. This may be inefficient in the future when
|
||||
* ML-MIMO is used. Only valid when last_mpdu is set.
|
||||
*
|
||||
* mpdu_length_err
|
||||
* See definition in RX attention descriptor
|
||||
*
|
||||
* tkip_mic_err
|
||||
* See definition in RX attention descriptor
|
||||
*
|
||||
* decrypt_err
|
||||
* See definition in RX attention descriptor
|
||||
*
|
||||
* fcs_err
|
||||
* See definition in RX attention descriptor
|
||||
*/
|
||||
|
||||
#define RX_MSDU_START_INFO0_MSDU_LENGTH_MASK 0x00003fff
|
||||
#define RX_MSDU_START_INFO0_MSDU_LENGTH_LSB 0
|
||||
#define RX_MSDU_START_INFO0_IP_OFFSET_MASK 0x000fc000
|
||||
#define RX_MSDU_START_INFO0_IP_OFFSET_LSB 14
|
||||
#define RX_MSDU_START_INFO0_RING_MASK_MASK 0x00f00000
|
||||
#define RX_MSDU_START_INFO0_RING_MASK_LSB 20
|
||||
#define RX_MSDU_START_INFO0_TCP_UDP_OFFSET_MASK 0x7f000000
|
||||
#define RX_MSDU_START_INFO0_TCP_UDP_OFFSET_LSB 24
|
||||
|
||||
#define RX_MSDU_START_INFO1_MSDU_NUMBER_MASK 0x000000ff
|
||||
#define RX_MSDU_START_INFO1_MSDU_NUMBER_LSB 0
|
||||
#define RX_MSDU_START_INFO1_DECAP_FORMAT_MASK 0x00000300
|
||||
#define RX_MSDU_START_INFO1_DECAP_FORMAT_LSB 8
|
||||
#define RX_MSDU_START_INFO1_SA_IDX_MASK 0x07ff0000
|
||||
#define RX_MSDU_START_INFO1_SA_IDX_LSB 16
|
||||
#define RX_MSDU_START_INFO1_IPV4_PROTO (1 << 10)
|
||||
#define RX_MSDU_START_INFO1_IPV6_PROTO (1 << 11)
|
||||
#define RX_MSDU_START_INFO1_TCP_PROTO (1 << 12)
|
||||
#define RX_MSDU_START_INFO1_UDP_PROTO (1 << 13)
|
||||
#define RX_MSDU_START_INFO1_IP_FRAG (1 << 14)
|
||||
#define RX_MSDU_START_INFO1_TCP_ONLY_ACK (1 << 15)
|
||||
|
||||
enum rx_msdu_decap_format {
|
||||
RX_MSDU_DECAP_RAW = 0,
|
||||
RX_MSDU_DECAP_NATIVE_WIFI = 1,
|
||||
RX_MSDU_DECAP_ETHERNET2_DIX = 2,
|
||||
RX_MSDU_DECAP_8023_SNAP_LLC = 3
|
||||
};
|
||||
|
||||
struct rx_msdu_start {
|
||||
__le32 info0; /* %RX_MSDU_START_INFO0_ */
|
||||
__le32 flow_id_crc;
|
||||
__le32 info1; /* %RX_MSDU_START_INFO1_ */
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* msdu_length
|
||||
* MSDU length in bytes after decapsulation. This field is
|
||||
* still valid for MPDU frames without A-MSDU. It still
|
||||
* represents MSDU length after decapsulation
|
||||
*
|
||||
* ip_offset
|
||||
* Indicates the IP offset in bytes from the start of the
|
||||
* packet after decapsulation. Only valid if ipv4_proto or
|
||||
* ipv6_proto is set.
|
||||
*
|
||||
* ring_mask
|
||||
* Indicates the destination RX rings for this MSDU.
|
||||
*
|
||||
* tcp_udp_offset
|
||||
* Indicates the offset in bytes to the start of TCP or UDP
|
||||
* header from the start of the IP header after decapsulation.
|
||||
* Only valid if tcp_prot or udp_prot is set. The value 0
|
||||
* indicates that the offset is longer than 127 bytes.
|
||||
*
|
||||
* reserved_0c
|
||||
* Reserved: HW should fill with zero. FW should ignore.
|
||||
*
|
||||
* flow_id_crc
|
||||
* The flow_id_crc runs CRC32 on the following information:
|
||||
* IPv4 option: dest_addr[31:0], src_addr [31:0], {24'b0,
|
||||
* protocol[7:0]}.
|
||||
* IPv6 option: dest_addr[127:0], src_addr [127:0], {24'b0,
|
||||
* next_header[7:0]}
|
||||
* UDP case: sort_port[15:0], dest_port[15:0]
|
||||
* TCP case: sort_port[15:0], dest_port[15:0],
|
||||
* {header_length[3:0], 6'b0, flags[5:0], window_size[15:0]},
|
||||
* {16'b0, urgent_ptr[15:0]}, all options except 32-bit
|
||||
* timestamp.
|
||||
*
|
||||
* msdu_number
|
||||
* Indicates the MSDU number within a MPDU. This value is
|
||||
* reset to zero at the start of each MPDU. If the number of
|
||||
* MSDU exceeds 255 this number will wrap using modulo 256.
|
||||
*
|
||||
* decap_format
|
||||
* Indicates the format after decapsulation:
|
||||
* 0: RAW: No decapsulation
|
||||
* 1: Native WiFi
|
||||
* 2: Ethernet 2 (DIX)
|
||||
* 3: 802.3 (SNAP/LLC)
|
||||
*
|
||||
* ipv4_proto
|
||||
* Set if L2 layer indicates IPv4 protocol.
|
||||
*
|
||||
* ipv6_proto
|
||||
* Set if L2 layer indicates IPv6 protocol.
|
||||
*
|
||||
* tcp_proto
|
||||
* Set if the ipv4_proto or ipv6_proto are set and the IP
|
||||
* protocol indicates TCP.
|
||||
*
|
||||
* udp_proto
|
||||
* Set if the ipv4_proto or ipv6_proto are set and the IP
|
||||
* protocol indicates UDP.
|
||||
*
|
||||
* ip_frag
|
||||
* Indicates that either the IP More frag bit is set or IP frag
|
||||
* number is non-zero. If set indicates that this is a
|
||||
* fragmented IP packet.
|
||||
*
|
||||
* tcp_only_ack
|
||||
* Set if only the TCP Ack bit is set in the TCP flags and if
|
||||
* the TCP payload is 0.
|
||||
*
|
||||
* sa_idx
|
||||
* The offset in the address table which matches the MAC source
|
||||
* address.
|
||||
*
|
||||
* reserved_2b
|
||||
* Reserved: HW should fill with zero. FW should ignore.
|
||||
*/
|
||||
|
||||
#define RX_MSDU_END_INFO0_REPORTED_MPDU_LENGTH_MASK 0x00003fff
|
||||
#define RX_MSDU_END_INFO0_REPORTED_MPDU_LENGTH_LSB 0
|
||||
#define RX_MSDU_END_INFO0_FIRST_MSDU (1 << 14)
|
||||
#define RX_MSDU_END_INFO0_LAST_MSDU (1 << 15)
|
||||
#define RX_MSDU_END_INFO0_PRE_DELIM_ERR (1 << 30)
|
||||
#define RX_MSDU_END_INFO0_RESERVED_3B (1 << 31)
|
||||
|
||||
struct rx_msdu_end {
|
||||
__le16 ip_hdr_cksum;
|
||||
__le16 tcp_hdr_cksum;
|
||||
u8 key_id_octet;
|
||||
u8 classification_filter;
|
||||
u8 wapi_pn[10];
|
||||
__le32 info0;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
*ip_hdr_chksum
|
||||
* This can include the IP header checksum or the pseudo header
|
||||
* checksum used by TCP/UDP checksum.
|
||||
*
|
||||
*tcp_udp_chksum
|
||||
* The value of the computed TCP/UDP checksum. A mode bit
|
||||
* selects whether this checksum is the full checksum or the
|
||||
* partial checksum which does not include the pseudo header.
|
||||
*
|
||||
*key_id_octet
|
||||
* The key ID octet from the IV. Only valid when first_msdu is
|
||||
* set.
|
||||
*
|
||||
*classification_filter
|
||||
* Indicates the number classification filter rule
|
||||
*
|
||||
*ext_wapi_pn_63_48
|
||||
* Extension PN (packet number) which is only used by WAPI.
|
||||
* This corresponds to WAPI PN bits [63:48] (pn6 and pn7). The
|
||||
* WAPI PN bits [63:0] are in the pn field of the rx_mpdu_start
|
||||
* descriptor.
|
||||
*
|
||||
*ext_wapi_pn_95_64
|
||||
* Extension PN (packet number) which is only used by WAPI.
|
||||
* This corresponds to WAPI PN bits [95:64] (pn8, pn9, pn10 and
|
||||
* pn11).
|
||||
*
|
||||
*ext_wapi_pn_127_96
|
||||
* Extension PN (packet number) which is only used by WAPI.
|
||||
* This corresponds to WAPI PN bits [127:96] (pn12, pn13, pn14,
|
||||
* pn15).
|
||||
*
|
||||
*reported_mpdu_length
|
||||
* MPDU length before decapsulation. Only valid when
|
||||
* first_msdu is set. This field is taken directly from the
|
||||
* length field of the A-MPDU delimiter or the preamble length
|
||||
* field for non-A-MPDU frames.
|
||||
*
|
||||
*first_msdu
|
||||
* Indicates the first MSDU of A-MSDU. If both first_msdu and
|
||||
* last_msdu are set in the MSDU then this is a non-aggregated
|
||||
* MSDU frame: normal MPDU. Interior MSDU in an A-MSDU shall
|
||||
* have both first_mpdu and last_mpdu bits set to 0.
|
||||
*
|
||||
*last_msdu
|
||||
* Indicates the last MSDU of the A-MSDU. MPDU end status is
|
||||
* only valid when last_msdu is set.
|
||||
*
|
||||
*reserved_3a
|
||||
* Reserved: HW should fill with zero. FW should ignore.
|
||||
*
|
||||
*pre_delim_err
|
||||
* Indicates that the first delimiter had a FCS failure. Only
|
||||
* valid when first_mpdu and first_msdu are set.
|
||||
*
|
||||
*reserved_3b
|
||||
* Reserved: HW should fill with zero. FW should ignore.
|
||||
*/
|
||||
|
||||
#define RX_PPDU_START_SIG_RATE_SELECT_OFDM 0
|
||||
#define RX_PPDU_START_SIG_RATE_SELECT_CCK 1
|
||||
|
||||
#define RX_PPDU_START_SIG_RATE_OFDM_48 0
|
||||
#define RX_PPDU_START_SIG_RATE_OFDM_24 1
|
||||
#define RX_PPDU_START_SIG_RATE_OFDM_12 2
|
||||
#define RX_PPDU_START_SIG_RATE_OFDM_6 3
|
||||
#define RX_PPDU_START_SIG_RATE_OFDM_54 4
|
||||
#define RX_PPDU_START_SIG_RATE_OFDM_36 5
|
||||
#define RX_PPDU_START_SIG_RATE_OFDM_18 6
|
||||
#define RX_PPDU_START_SIG_RATE_OFDM_9 7
|
||||
|
||||
#define RX_PPDU_START_SIG_RATE_CCK_LP_11 0
|
||||
#define RX_PPDU_START_SIG_RATE_CCK_LP_5_5 1
|
||||
#define RX_PPDU_START_SIG_RATE_CCK_LP_2 2
|
||||
#define RX_PPDU_START_SIG_RATE_CCK_LP_1 3
|
||||
#define RX_PPDU_START_SIG_RATE_CCK_SP_11 4
|
||||
#define RX_PPDU_START_SIG_RATE_CCK_SP_5_5 5
|
||||
#define RX_PPDU_START_SIG_RATE_CCK_SP_2 6
|
||||
|
||||
#define HTT_RX_PPDU_START_PREAMBLE_LEGACY 0x04
|
||||
#define HTT_RX_PPDU_START_PREAMBLE_HT 0x08
|
||||
#define HTT_RX_PPDU_START_PREAMBLE_HT_WITH_TXBF 0x09
|
||||
#define HTT_RX_PPDU_START_PREAMBLE_VHT 0x0C
|
||||
#define HTT_RX_PPDU_START_PREAMBLE_VHT_WITH_TXBF 0x0D
|
||||
|
||||
#define RX_PPDU_START_INFO0_IS_GREENFIELD (1 << 0)
|
||||
|
||||
#define RX_PPDU_START_INFO1_L_SIG_RATE_MASK 0x0000000f
|
||||
#define RX_PPDU_START_INFO1_L_SIG_RATE_LSB 0
|
||||
#define RX_PPDU_START_INFO1_L_SIG_LENGTH_MASK 0x0001ffe0
|
||||
#define RX_PPDU_START_INFO1_L_SIG_LENGTH_LSB 5
|
||||
#define RX_PPDU_START_INFO1_L_SIG_TAIL_MASK 0x00fc0000
|
||||
#define RX_PPDU_START_INFO1_L_SIG_TAIL_LSB 18
|
||||
#define RX_PPDU_START_INFO1_PREAMBLE_TYPE_MASK 0xff000000
|
||||
#define RX_PPDU_START_INFO1_PREAMBLE_TYPE_LSB 24
|
||||
#define RX_PPDU_START_INFO1_L_SIG_RATE_SELECT (1 << 4)
|
||||
#define RX_PPDU_START_INFO1_L_SIG_PARITY (1 << 17)
|
||||
|
||||
#define RX_PPDU_START_INFO2_HT_SIG_VHT_SIG_A_1_MASK 0x00ffffff
|
||||
#define RX_PPDU_START_INFO2_HT_SIG_VHT_SIG_A_1_LSB 0
|
||||
|
||||
#define RX_PPDU_START_INFO3_HT_SIG_VHT_SIG_A_2_MASK 0x00ffffff
|
||||
#define RX_PPDU_START_INFO3_HT_SIG_VHT_SIG_A_2_LSB 0
|
||||
#define RX_PPDU_START_INFO3_TXBF_H_INFO (1 << 24)
|
||||
|
||||
#define RX_PPDU_START_INFO4_VHT_SIG_B_MASK 0x1fffffff
|
||||
#define RX_PPDU_START_INFO4_VHT_SIG_B_LSB 0
|
||||
|
||||
#define RX_PPDU_START_INFO5_SERVICE_MASK 0x0000ffff
|
||||
#define RX_PPDU_START_INFO5_SERVICE_LSB 0
|
||||
|
||||
struct rx_ppdu_start {
|
||||
struct {
|
||||
u8 pri20_mhz;
|
||||
u8 ext20_mhz;
|
||||
u8 ext40_mhz;
|
||||
u8 ext80_mhz;
|
||||
} rssi_chains[4];
|
||||
u8 rssi_comb;
|
||||
__le16 rsvd0;
|
||||
u8 info0; /* %RX_PPDU_START_INFO0_ */
|
||||
__le32 info1; /* %RX_PPDU_START_INFO1_ */
|
||||
__le32 info2; /* %RX_PPDU_START_INFO2_ */
|
||||
__le32 info3; /* %RX_PPDU_START_INFO3_ */
|
||||
__le32 info4; /* %RX_PPDU_START_INFO4_ */
|
||||
__le32 info5; /* %RX_PPDU_START_INFO5_ */
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* rssi_chain0_pri20
|
||||
* RSSI of RX PPDU on chain 0 of primary 20 MHz bandwidth.
|
||||
* Value of 0x80 indicates invalid.
|
||||
*
|
||||
* rssi_chain0_sec20
|
||||
* RSSI of RX PPDU on chain 0 of secondary 20 MHz bandwidth.
|
||||
* Value of 0x80 indicates invalid.
|
||||
*
|
||||
* rssi_chain0_sec40
|
||||
* RSSI of RX PPDU on chain 0 of secondary 40 MHz bandwidth.
|
||||
* Value of 0x80 indicates invalid.
|
||||
*
|
||||
* rssi_chain0_sec80
|
||||
* RSSI of RX PPDU on chain 0 of secondary 80 MHz bandwidth.
|
||||
* Value of 0x80 indicates invalid.
|
||||
*
|
||||
* rssi_chain1_pri20
|
||||
* RSSI of RX PPDU on chain 1 of primary 20 MHz bandwidth.
|
||||
* Value of 0x80 indicates invalid.
|
||||
*
|
||||
* rssi_chain1_sec20
|
||||
* RSSI of RX PPDU on chain 1 of secondary 20 MHz bandwidth.
|
||||
* Value of 0x80 indicates invalid.
|
||||
*
|
||||
* rssi_chain1_sec40
|
||||
* RSSI of RX PPDU on chain 1 of secondary 40 MHz bandwidth.
|
||||
* Value of 0x80 indicates invalid.
|
||||
*
|
||||
* rssi_chain1_sec80
|
||||
* RSSI of RX PPDU on chain 1 of secondary 80 MHz bandwidth.
|
||||
* Value of 0x80 indicates invalid.
|
||||
*
|
||||
* rssi_chain2_pri20
|
||||
* RSSI of RX PPDU on chain 2 of primary 20 MHz bandwidth.
|
||||
* Value of 0x80 indicates invalid.
|
||||
*
|
||||
* rssi_chain2_sec20
|
||||
* RSSI of RX PPDU on chain 2 of secondary 20 MHz bandwidth.
|
||||
* Value of 0x80 indicates invalid.
|
||||
*
|
||||
* rssi_chain2_sec40
|
||||
* RSSI of RX PPDU on chain 2 of secondary 40 MHz bandwidth.
|
||||
* Value of 0x80 indicates invalid.
|
||||
*
|
||||
* rssi_chain2_sec80
|
||||
* RSSI of RX PPDU on chain 2 of secondary 80 MHz bandwidth.
|
||||
* Value of 0x80 indicates invalid.
|
||||
*
|
||||
* rssi_chain3_pri20
|
||||
* RSSI of RX PPDU on chain 3 of primary 20 MHz bandwidth.
|
||||
* Value of 0x80 indicates invalid.
|
||||
*
|
||||
* rssi_chain3_sec20
|
||||
* RSSI of RX PPDU on chain 3 of secondary 20 MHz bandwidth.
|
||||
* Value of 0x80 indicates invalid.
|
||||
*
|
||||
* rssi_chain3_sec40
|
||||
* RSSI of RX PPDU on chain 3 of secondary 40 MHz bandwidth.
|
||||
* Value of 0x80 indicates invalid.
|
||||
*
|
||||
* rssi_chain3_sec80
|
||||
* RSSI of RX PPDU on chain 3 of secondary 80 MHz bandwidth.
|
||||
* Value of 0x80 indicates invalid.
|
||||
*
|
||||
* rssi_comb
|
||||
* The combined RSSI of RX PPDU of all active chains and
|
||||
* bandwidths. Value of 0x80 indicates invalid.
|
||||
*
|
||||
* reserved_4a
|
||||
* Reserved: HW should fill with 0, FW should ignore.
|
||||
*
|
||||
* is_greenfield
|
||||
* Do we really support this?
|
||||
*
|
||||
* reserved_4b
|
||||
* Reserved: HW should fill with 0, FW should ignore.
|
||||
*
|
||||
* l_sig_rate
|
||||
* If l_sig_rate_select is 0:
|
||||
* 0x8: OFDM 48 Mbps
|
||||
* 0x9: OFDM 24 Mbps
|
||||
* 0xA: OFDM 12 Mbps
|
||||
* 0xB: OFDM 6 Mbps
|
||||
* 0xC: OFDM 54 Mbps
|
||||
* 0xD: OFDM 36 Mbps
|
||||
* 0xE: OFDM 18 Mbps
|
||||
* 0xF: OFDM 9 Mbps
|
||||
* If l_sig_rate_select is 1:
|
||||
* 0x8: CCK 11 Mbps long preamble
|
||||
* 0x9: CCK 5.5 Mbps long preamble
|
||||
* 0xA: CCK 2 Mbps long preamble
|
||||
* 0xB: CCK 1 Mbps long preamble
|
||||
* 0xC: CCK 11 Mbps short preamble
|
||||
* 0xD: CCK 5.5 Mbps short preamble
|
||||
* 0xE: CCK 2 Mbps short preamble
|
||||
*
|
||||
* l_sig_rate_select
|
||||
* Legacy signal rate select. If set then l_sig_rate indicates
|
||||
* CCK rates. If clear then l_sig_rate indicates OFDM rates.
|
||||
*
|
||||
* l_sig_length
|
||||
* Length of legacy frame in octets.
|
||||
*
|
||||
* l_sig_parity
|
||||
* Odd parity over l_sig_rate and l_sig_length
|
||||
*
|
||||
* l_sig_tail
|
||||
* Tail bits for Viterbi decoder
|
||||
*
|
||||
* preamble_type
|
||||
* Indicates the type of preamble ahead:
|
||||
* 0x4: Legacy (OFDM/CCK)
|
||||
* 0x8: HT
|
||||
* 0x9: HT with TxBF
|
||||
* 0xC: VHT
|
||||
* 0xD: VHT with TxBF
|
||||
* 0x80 - 0xFF: Reserved for special baseband data types such
|
||||
* as radar and spectral scan.
|
||||
*
|
||||
* ht_sig_vht_sig_a_1
|
||||
* If preamble_type == 0x8 or 0x9
|
||||
* HT-SIG (first 24 bits)
|
||||
* If preamble_type == 0xC or 0xD
|
||||
* VHT-SIG A (first 24 bits)
|
||||
* Else
|
||||
* Reserved
|
||||
*
|
||||
* reserved_6
|
||||
* Reserved: HW should fill with 0, FW should ignore.
|
||||
*
|
||||
* ht_sig_vht_sig_a_2
|
||||
* If preamble_type == 0x8 or 0x9
|
||||
* HT-SIG (last 24 bits)
|
||||
* If preamble_type == 0xC or 0xD
|
||||
* VHT-SIG A (last 24 bits)
|
||||
* Else
|
||||
* Reserved
|
||||
*
|
||||
* txbf_h_info
|
||||
* Indicates that the packet data carries H information which
|
||||
* is used for TxBF debug.
|
||||
*
|
||||
* reserved_7
|
||||
* Reserved: HW should fill with 0, FW should ignore.
|
||||
*
|
||||
* vht_sig_b
|
||||
* WiFi 1.0 and WiFi 2.0 will likely have this field to be all
|
||||
* 0s since the BB does not plan on decoding VHT SIG-B.
|
||||
*
|
||||
* reserved_8
|
||||
* Reserved: HW should fill with 0, FW should ignore.
|
||||
*
|
||||
* service
|
||||
* Service field from BB for OFDM, HT and VHT packets. CCK
|
||||
* packets will have service field of 0.
|
||||
*
|
||||
* reserved_9
|
||||
* Reserved: HW should fill with 0, FW should ignore.
|
||||
*/
|
||||
|
||||
|
||||
#define RX_PPDU_END_FLAGS_PHY_ERR (1 << 0)
|
||||
#define RX_PPDU_END_FLAGS_RX_LOCATION (1 << 1)
|
||||
#define RX_PPDU_END_FLAGS_TXBF_H_INFO (1 << 2)
|
||||
|
||||
#define RX_PPDU_END_INFO0_RX_ANTENNA_MASK 0x00ffffff
|
||||
#define RX_PPDU_END_INFO0_RX_ANTENNA_LSB 0
|
||||
#define RX_PPDU_END_INFO0_FLAGS_TX_HT_VHT_ACK (1 << 24)
|
||||
#define RX_PPDU_END_INFO0_BB_CAPTURED_CHANNEL (1 << 25)
|
||||
|
||||
#define RX_PPDU_END_INFO1_PPDU_DONE (1 << 15)
|
||||
|
||||
struct rx_ppdu_end {
|
||||
__le32 evm_p0;
|
||||
__le32 evm_p1;
|
||||
__le32 evm_p2;
|
||||
__le32 evm_p3;
|
||||
__le32 evm_p4;
|
||||
__le32 evm_p5;
|
||||
__le32 evm_p6;
|
||||
__le32 evm_p7;
|
||||
__le32 evm_p8;
|
||||
__le32 evm_p9;
|
||||
__le32 evm_p10;
|
||||
__le32 evm_p11;
|
||||
__le32 evm_p12;
|
||||
__le32 evm_p13;
|
||||
__le32 evm_p14;
|
||||
__le32 evm_p15;
|
||||
__le32 tsf_timestamp;
|
||||
__le32 wb_timestamp;
|
||||
u8 locationing_timestamp;
|
||||
u8 phy_err_code;
|
||||
__le16 flags; /* %RX_PPDU_END_FLAGS_ */
|
||||
__le32 info0; /* %RX_PPDU_END_INFO0_ */
|
||||
__le16 bb_length;
|
||||
__le16 info1; /* %RX_PPDU_END_INFO1_ */
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* evm_p0
|
||||
* EVM for pilot 0. Contain EVM for streams: 0, 1, 2 and 3.
|
||||
*
|
||||
* evm_p1
|
||||
* EVM for pilot 1. Contain EVM for streams: 0, 1, 2 and 3.
|
||||
*
|
||||
* evm_p2
|
||||
* EVM for pilot 2. Contain EVM for streams: 0, 1, 2 and 3.
|
||||
*
|
||||
* evm_p3
|
||||
* EVM for pilot 3. Contain EVM for streams: 0, 1, 2 and 3.
|
||||
*
|
||||
* evm_p4
|
||||
* EVM for pilot 4. Contain EVM for streams: 0, 1, 2 and 3.
|
||||
*
|
||||
* evm_p5
|
||||
* EVM for pilot 5. Contain EVM for streams: 0, 1, 2 and 3.
|
||||
*
|
||||
* evm_p6
|
||||
* EVM for pilot 6. Contain EVM for streams: 0, 1, 2 and 3.
|
||||
*
|
||||
* evm_p7
|
||||
* EVM for pilot 7. Contain EVM for streams: 0, 1, 2 and 3.
|
||||
*
|
||||
* evm_p8
|
||||
* EVM for pilot 8. Contain EVM for streams: 0, 1, 2 and 3.
|
||||
*
|
||||
* evm_p9
|
||||
* EVM for pilot 9. Contain EVM for streams: 0, 1, 2 and 3.
|
||||
*
|
||||
* evm_p10
|
||||
* EVM for pilot 10. Contain EVM for streams: 0, 1, 2 and 3.
|
||||
*
|
||||
* evm_p11
|
||||
* EVM for pilot 11. Contain EVM for streams: 0, 1, 2 and 3.
|
||||
*
|
||||
* evm_p12
|
||||
* EVM for pilot 12. Contain EVM for streams: 0, 1, 2 and 3.
|
||||
*
|
||||
* evm_p13
|
||||
* EVM for pilot 13. Contain EVM for streams: 0, 1, 2 and 3.
|
||||
*
|
||||
* evm_p14
|
||||
* EVM for pilot 14. Contain EVM for streams: 0, 1, 2 and 3.
|
||||
*
|
||||
* evm_p15
|
||||
* EVM for pilot 15. Contain EVM for streams: 0, 1, 2 and 3.
|
||||
*
|
||||
* tsf_timestamp
|
||||
* Receive TSF timestamp sampled on the rising edge of
|
||||
* rx_clear. For PHY errors this may be the current TSF when
|
||||
* phy_error is asserted if the rx_clear does not assert before
|
||||
* the end of the PHY error.
|
||||
*
|
||||
* wb_timestamp
|
||||
* WLAN/BT timestamp is a 1 usec resolution timestamp which
|
||||
* does not get updated based on receive beacon like TSF. The
|
||||
* same rules for capturing tsf_timestamp are used to capture
|
||||
* the wb_timestamp.
|
||||
*
|
||||
* locationing_timestamp
|
||||
* Timestamp used for locationing. This timestamp is used to
|
||||
* indicate fractions of usec. For example if the MAC clock is
|
||||
* running at 80 MHz, the timestamp will increment every 12.5
|
||||
* nsec. The value starts at 0 and increments to 79 and
|
||||
* returns to 0 and repeats. This information is valid for
|
||||
* every PPDU. This information can be used in conjunction
|
||||
* with wb_timestamp to capture large delta times.
|
||||
*
|
||||
* phy_err_code
|
||||
* See the 1.10.8.1.2 for the list of the PHY error codes.
|
||||
*
|
||||
* phy_err
|
||||
* Indicates a PHY error was detected for this PPDU.
|
||||
*
|
||||
* rx_location
|
||||
* Indicates that location information was requested.
|
||||
*
|
||||
* txbf_h_info
|
||||
* Indicates that the packet data carries H information which
|
||||
* is used for TxBF debug.
|
||||
*
|
||||
* reserved_18
|
||||
* Reserved: HW should fill with 0, FW should ignore.
|
||||
*
|
||||
* rx_antenna
|
||||
* Receive antenna value
|
||||
*
|
||||
* tx_ht_vht_ack
|
||||
* Indicates that a HT or VHT Ack/BA frame was transmitted in
|
||||
* response to this receive packet.
|
||||
*
|
||||
* bb_captured_channel
|
||||
* Indicates that the BB has captured a channel dump. FW can
|
||||
* then read the channel dump memory. This may indicate that
|
||||
* the channel was captured either based on PCU setting the
|
||||
* capture_channel bit BB descriptor or FW setting the
|
||||
* capture_channel mode bit.
|
||||
*
|
||||
* reserved_19
|
||||
* Reserved: HW should fill with 0, FW should ignore.
|
||||
*
|
||||
* bb_length
|
||||
* Indicates the number of bytes of baseband information for
|
||||
* PPDUs where the BB descriptor preamble type is 0x80 to 0xFF
|
||||
* which indicates that this is not a normal PPDU but rather
|
||||
* contains baseband debug information.
|
||||
*
|
||||
* reserved_20
|
||||
* Reserved: HW should fill with 0, FW should ignore.
|
||||
*
|
||||
* ppdu_done
|
||||
* PPDU end status is only valid when ppdu_done bit is set.
|
||||
* Every time HW sets this bit in memory FW/SW must clear this
|
||||
* bit in memory. FW will initialize all the ppdu_done dword
|
||||
* to 0.
|
||||
*/
|
||||
|
||||
#define FW_RX_DESC_INFO0_DISCARD (1 << 0)
|
||||
#define FW_RX_DESC_INFO0_FORWARD (1 << 1)
|
||||
#define FW_RX_DESC_INFO0_INSPECT (1 << 5)
|
||||
#define FW_RX_DESC_INFO0_EXT_MASK 0xC0
|
||||
#define FW_RX_DESC_INFO0_EXT_LSB 6
|
||||
|
||||
struct fw_rx_desc_base {
|
||||
u8 info0;
|
||||
} __packed;
|
||||
|
||||
#endif /* _RX_DESC_H_ */
|
|
@ -0,0 +1,449 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2013 Qualcomm Atheros, 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 __TARGADDRS_H__
|
||||
#define __TARGADDRS_H__
|
||||
|
||||
/*
|
||||
* xxx_HOST_INTEREST_ADDRESS is the address in Target RAM of the
|
||||
* host_interest structure. It must match the address of the _host_interest
|
||||
* symbol (see linker script).
|
||||
*
|
||||
* Host Interest is shared between Host and Target in order to coordinate
|
||||
* between the two, and is intended to remain constant (with additions only
|
||||
* at the end) across software releases.
|
||||
*
|
||||
* All addresses are available here so that it's possible to
|
||||
* write a single binary that works with all Target Types.
|
||||
* May be used in assembler code as well as C.
|
||||
*/
|
||||
#define QCA988X_HOST_INTEREST_ADDRESS 0x00400800
|
||||
#define HOST_INTEREST_MAX_SIZE 0x200
|
||||
|
||||
/*
|
||||
* These are items that the Host may need to access via BMI or via the
|
||||
* Diagnostic Window. The position of items in this structure must remain
|
||||
* constant across firmware revisions! Types for each item must be fixed
|
||||
* size across target and host platforms. More items may be added at the end.
|
||||
*/
|
||||
struct host_interest {
|
||||
/*
|
||||
* Pointer to application-defined area, if any.
|
||||
* Set by Target application during startup.
|
||||
*/
|
||||
u32 hi_app_host_interest; /* 0x00 */
|
||||
|
||||
/* Pointer to register dump area, valid after Target crash. */
|
||||
u32 hi_failure_state; /* 0x04 */
|
||||
|
||||
/* Pointer to debug logging header */
|
||||
u32 hi_dbglog_hdr; /* 0x08 */
|
||||
|
||||
u32 hi_unused0c; /* 0x0c */
|
||||
|
||||
/*
|
||||
* General-purpose flag bits, similar to SOC_OPTION_* flags.
|
||||
* Can be used by application rather than by OS.
|
||||
*/
|
||||
u32 hi_option_flag; /* 0x10 */
|
||||
|
||||
/*
|
||||
* Boolean that determines whether or not to
|
||||
* display messages on the serial port.
|
||||
*/
|
||||
u32 hi_serial_enable; /* 0x14 */
|
||||
|
||||
/* Start address of DataSet index, if any */
|
||||
u32 hi_dset_list_head; /* 0x18 */
|
||||
|
||||
/* Override Target application start address */
|
||||
u32 hi_app_start; /* 0x1c */
|
||||
|
||||
/* Clock and voltage tuning */
|
||||
u32 hi_skip_clock_init; /* 0x20 */
|
||||
u32 hi_core_clock_setting; /* 0x24 */
|
||||
u32 hi_cpu_clock_setting; /* 0x28 */
|
||||
u32 hi_system_sleep_setting; /* 0x2c */
|
||||
u32 hi_xtal_control_setting; /* 0x30 */
|
||||
u32 hi_pll_ctrl_setting_24ghz; /* 0x34 */
|
||||
u32 hi_pll_ctrl_setting_5ghz; /* 0x38 */
|
||||
u32 hi_ref_voltage_trim_setting; /* 0x3c */
|
||||
u32 hi_clock_info; /* 0x40 */
|
||||
|
||||
/* Host uses BE CPU or not */
|
||||
u32 hi_be; /* 0x44 */
|
||||
|
||||
u32 hi_stack; /* normal stack */ /* 0x48 */
|
||||
u32 hi_err_stack; /* error stack */ /* 0x4c */
|
||||
u32 hi_desired_cpu_speed_hz; /* 0x50 */
|
||||
|
||||
/* Pointer to Board Data */
|
||||
u32 hi_board_data; /* 0x54 */
|
||||
|
||||
/*
|
||||
* Indication of Board Data state:
|
||||
* 0: board data is not yet initialized.
|
||||
* 1: board data is initialized; unknown size
|
||||
* >1: number of bytes of initialized board data
|
||||
*/
|
||||
u32 hi_board_data_initialized; /* 0x58 */
|
||||
|
||||
u32 hi_dset_ram_index_table; /* 0x5c */
|
||||
|
||||
u32 hi_desired_baud_rate; /* 0x60 */
|
||||
u32 hi_dbglog_config; /* 0x64 */
|
||||
u32 hi_end_ram_reserve_sz; /* 0x68 */
|
||||
u32 hi_mbox_io_block_sz; /* 0x6c */
|
||||
|
||||
u32 hi_num_bpatch_streams; /* 0x70 -- unused */
|
||||
u32 hi_mbox_isr_yield_limit; /* 0x74 */
|
||||
|
||||
u32 hi_refclk_hz; /* 0x78 */
|
||||
u32 hi_ext_clk_detected; /* 0x7c */
|
||||
u32 hi_dbg_uart_txpin; /* 0x80 */
|
||||
u32 hi_dbg_uart_rxpin; /* 0x84 */
|
||||
u32 hi_hci_uart_baud; /* 0x88 */
|
||||
u32 hi_hci_uart_pin_assignments; /* 0x8C */
|
||||
|
||||
u32 hi_hci_uart_baud_scale_val; /* 0x90 */
|
||||
u32 hi_hci_uart_baud_step_val; /* 0x94 */
|
||||
|
||||
u32 hi_allocram_start; /* 0x98 */
|
||||
u32 hi_allocram_sz; /* 0x9c */
|
||||
u32 hi_hci_bridge_flags; /* 0xa0 */
|
||||
u32 hi_hci_uart_support_pins; /* 0xa4 */
|
||||
|
||||
u32 hi_hci_uart_pwr_mgmt_params; /* 0xa8 */
|
||||
|
||||
/*
|
||||
* 0xa8 - [1]: 0 = UART FC active low, 1 = UART FC active high
|
||||
* [31:16]: wakeup timeout in ms
|
||||
*/
|
||||
/* Pointer to extended board Data */
|
||||
u32 hi_board_ext_data; /* 0xac */
|
||||
u32 hi_board_ext_data_config; /* 0xb0 */
|
||||
/*
|
||||
* Bit [0] : valid
|
||||
* Bit[31:16: size
|
||||
*/
|
||||
/*
|
||||
* hi_reset_flag is used to do some stuff when target reset.
|
||||
* such as restore app_start after warm reset or
|
||||
* preserve host Interest area, or preserve ROM data, literals etc.
|
||||
*/
|
||||
u32 hi_reset_flag; /* 0xb4 */
|
||||
/* indicate hi_reset_flag is valid */
|
||||
u32 hi_reset_flag_valid; /* 0xb8 */
|
||||
u32 hi_hci_uart_pwr_mgmt_params_ext; /* 0xbc */
|
||||
/* 0xbc - [31:0]: idle timeout in ms */
|
||||
/* ACS flags */
|
||||
u32 hi_acs_flags; /* 0xc0 */
|
||||
u32 hi_console_flags; /* 0xc4 */
|
||||
u32 hi_nvram_state; /* 0xc8 */
|
||||
u32 hi_option_flag2; /* 0xcc */
|
||||
|
||||
/* If non-zero, override values sent to Host in WMI_READY event. */
|
||||
u32 hi_sw_version_override; /* 0xd0 */
|
||||
u32 hi_abi_version_override; /* 0xd4 */
|
||||
|
||||
/*
|
||||
* Percentage of high priority RX traffic to total expected RX traffic
|
||||
* applicable only to ar6004
|
||||
*/
|
||||
u32 hi_hp_rx_traffic_ratio; /* 0xd8 */
|
||||
|
||||
/* test applications flags */
|
||||
u32 hi_test_apps_related; /* 0xdc */
|
||||
/* location of test script */
|
||||
u32 hi_ota_testscript; /* 0xe0 */
|
||||
/* location of CAL data */
|
||||
u32 hi_cal_data; /* 0xe4 */
|
||||
|
||||
/* Number of packet log buffers */
|
||||
u32 hi_pktlog_num_buffers; /* 0xe8 */
|
||||
|
||||
/* wow extension configuration */
|
||||
u32 hi_wow_ext_config; /* 0xec */
|
||||
u32 hi_pwr_save_flags; /* 0xf0 */
|
||||
|
||||
/* Spatial Multiplexing Power Save (SMPS) options */
|
||||
u32 hi_smps_options; /* 0xf4 */
|
||||
|
||||
/* Interconnect-specific state */
|
||||
u32 hi_interconnect_state; /* 0xf8 */
|
||||
|
||||
/* Coex configuration flags */
|
||||
u32 hi_coex_config; /* 0xfc */
|
||||
|
||||
/* Early allocation support */
|
||||
u32 hi_early_alloc; /* 0x100 */
|
||||
/* FW swap field */
|
||||
/*
|
||||
* Bits of this 32bit word will be used to pass specific swap
|
||||
* instruction to FW
|
||||
*/
|
||||
/*
|
||||
* Bit 0 -- AP Nart descriptor no swap. When this bit is set
|
||||
* FW will not swap TX descriptor. Meaning packets are formed
|
||||
* on the target processor.
|
||||
*/
|
||||
/* Bit 1 - unused */
|
||||
u32 hi_fw_swap; /* 0x104 */
|
||||
} __packed;
|
||||
|
||||
#define HI_ITEM(item) offsetof(struct host_interest, item)
|
||||
|
||||
/* Bits defined in hi_option_flag */
|
||||
|
||||
/* Enable timer workaround */
|
||||
#define HI_OPTION_TIMER_WAR 0x01
|
||||
/* Limit BMI command credits */
|
||||
#define HI_OPTION_BMI_CRED_LIMIT 0x02
|
||||
/* Relay Dot11 hdr to/from host */
|
||||
#define HI_OPTION_RELAY_DOT11_HDR 0x04
|
||||
/* MAC addr method 0-locally administred 1-globally unique addrs */
|
||||
#define HI_OPTION_MAC_ADDR_METHOD 0x08
|
||||
/* Firmware Bridging */
|
||||
#define HI_OPTION_FW_BRIDGE 0x10
|
||||
/* Enable CPU profiling */
|
||||
#define HI_OPTION_ENABLE_PROFILE 0x20
|
||||
/* Disable debug logging */
|
||||
#define HI_OPTION_DISABLE_DBGLOG 0x40
|
||||
/* Skip Era Tracking */
|
||||
#define HI_OPTION_SKIP_ERA_TRACKING 0x80
|
||||
/* Disable PAPRD (debug) */
|
||||
#define HI_OPTION_PAPRD_DISABLE 0x100
|
||||
#define HI_OPTION_NUM_DEV_LSB 0x200
|
||||
#define HI_OPTION_NUM_DEV_MSB 0x800
|
||||
#define HI_OPTION_DEV_MODE_LSB 0x1000
|
||||
#define HI_OPTION_DEV_MODE_MSB 0x8000000
|
||||
/* Disable LowFreq Timer Stabilization */
|
||||
#define HI_OPTION_NO_LFT_STBL 0x10000000
|
||||
/* Skip regulatory scan */
|
||||
#define HI_OPTION_SKIP_REG_SCAN 0x20000000
|
||||
/*
|
||||
* Do regulatory scan during init before
|
||||
* sending WMI ready event to host
|
||||
*/
|
||||
#define HI_OPTION_INIT_REG_SCAN 0x40000000
|
||||
|
||||
/* REV6: Do not adjust memory map */
|
||||
#define HI_OPTION_SKIP_MEMMAP 0x80000000
|
||||
|
||||
#define HI_OPTION_MAC_ADDR_METHOD_SHIFT 3
|
||||
|
||||
/* 2 bits of hi_option_flag are used to represent 3 modes */
|
||||
#define HI_OPTION_FW_MODE_IBSS 0x0 /* IBSS Mode */
|
||||
#define HI_OPTION_FW_MODE_BSS_STA 0x1 /* STA Mode */
|
||||
#define HI_OPTION_FW_MODE_AP 0x2 /* AP Mode */
|
||||
#define HI_OPTION_FW_MODE_BT30AMP 0x3 /* BT30 AMP Mode */
|
||||
|
||||
/* 2 bits of hi_option flag are usedto represent 4 submodes */
|
||||
#define HI_OPTION_FW_SUBMODE_NONE 0x0 /* Normal mode */
|
||||
#define HI_OPTION_FW_SUBMODE_P2PDEV 0x1 /* p2p device mode */
|
||||
#define HI_OPTION_FW_SUBMODE_P2PCLIENT 0x2 /* p2p client mode */
|
||||
#define HI_OPTION_FW_SUBMODE_P2PGO 0x3 /* p2p go mode */
|
||||
|
||||
/* Num dev Mask */
|
||||
#define HI_OPTION_NUM_DEV_MASK 0x7
|
||||
#define HI_OPTION_NUM_DEV_SHIFT 0x9
|
||||
|
||||
/* firmware bridging */
|
||||
#define HI_OPTION_FW_BRIDGE_SHIFT 0x04
|
||||
|
||||
/*
|
||||
Fw Mode/SubMode Mask
|
||||
|-----------------------------------------------------------------------------|
|
||||
| SUB | SUB | SUB | SUB | | | | |
|
||||
|MODE[3] | MODE[2] | MODE[1] | MODE[0] | MODE[3] | MODE[2] | MODE[1] | MODE[0]|
|
||||
| (2) | (2) | (2) | (2) | (2) | (2) | (2) | (2) |
|
||||
|-----------------------------------------------------------------------------|
|
||||
*/
|
||||
#define HI_OPTION_FW_MODE_BITS 0x2
|
||||
#define HI_OPTION_FW_MODE_MASK 0x3
|
||||
#define HI_OPTION_FW_MODE_SHIFT 0xC
|
||||
#define HI_OPTION_ALL_FW_MODE_MASK 0xFF
|
||||
|
||||
#define HI_OPTION_FW_SUBMODE_BITS 0x2
|
||||
#define HI_OPTION_FW_SUBMODE_MASK 0x3
|
||||
#define HI_OPTION_FW_SUBMODE_SHIFT 0x14
|
||||
#define HI_OPTION_ALL_FW_SUBMODE_MASK 0xFF00
|
||||
#define HI_OPTION_ALL_FW_SUBMODE_SHIFT 0x8
|
||||
|
||||
|
||||
/* hi_option_flag2 options */
|
||||
#define HI_OPTION_OFFLOAD_AMSDU 0x01
|
||||
#define HI_OPTION_DFS_SUPPORT 0x02 /* Enable DFS support */
|
||||
#define HI_OPTION_ENABLE_RFKILL 0x04 /* RFKill Enable Feature*/
|
||||
#define HI_OPTION_RADIO_RETENTION_DISABLE 0x08 /* Disable radio retention */
|
||||
#define HI_OPTION_EARLY_CFG_DONE 0x10 /* Early configuration is complete */
|
||||
|
||||
#define HI_OPTION_RF_KILL_SHIFT 0x2
|
||||
#define HI_OPTION_RF_KILL_MASK 0x1
|
||||
|
||||
/* hi_reset_flag */
|
||||
/* preserve App Start address */
|
||||
#define HI_RESET_FLAG_PRESERVE_APP_START 0x01
|
||||
/* preserve host interest */
|
||||
#define HI_RESET_FLAG_PRESERVE_HOST_INTEREST 0x02
|
||||
/* preserve ROM data */
|
||||
#define HI_RESET_FLAG_PRESERVE_ROMDATA 0x04
|
||||
#define HI_RESET_FLAG_PRESERVE_NVRAM_STATE 0x08
|
||||
#define HI_RESET_FLAG_PRESERVE_BOOT_INFO 0x10
|
||||
#define HI_RESET_FLAG_WARM_RESET 0x20
|
||||
|
||||
/* define hi_fw_swap bits */
|
||||
#define HI_DESC_IN_FW_BIT 0x01
|
||||
|
||||
/* indicate the reset flag is valid */
|
||||
#define HI_RESET_FLAG_IS_VALID 0x12345678
|
||||
|
||||
/* ACS is enabled */
|
||||
#define HI_ACS_FLAGS_ENABLED (1 << 0)
|
||||
/* Use physical WWAN device */
|
||||
#define HI_ACS_FLAGS_USE_WWAN (1 << 1)
|
||||
/* Use test VAP */
|
||||
#define HI_ACS_FLAGS_TEST_VAP (1 << 2)
|
||||
|
||||
/*
|
||||
* CONSOLE FLAGS
|
||||
*
|
||||
* Bit Range Meaning
|
||||
* --------- --------------------------------
|
||||
* 2..0 UART ID (0 = Default)
|
||||
* 3 Baud Select (0 = 9600, 1 = 115200)
|
||||
* 30..4 Reserved
|
||||
* 31 Enable Console
|
||||
*
|
||||
*/
|
||||
|
||||
#define HI_CONSOLE_FLAGS_ENABLE (1 << 31)
|
||||
#define HI_CONSOLE_FLAGS_UART_MASK (0x7)
|
||||
#define HI_CONSOLE_FLAGS_UART_SHIFT 0
|
||||
#define HI_CONSOLE_FLAGS_BAUD_SELECT (1 << 3)
|
||||
|
||||
/* SM power save options */
|
||||
#define HI_SMPS_ALLOW_MASK (0x00000001)
|
||||
#define HI_SMPS_MODE_MASK (0x00000002)
|
||||
#define HI_SMPS_MODE_STATIC (0x00000000)
|
||||
#define HI_SMPS_MODE_DYNAMIC (0x00000002)
|
||||
#define HI_SMPS_DISABLE_AUTO_MODE (0x00000004)
|
||||
#define HI_SMPS_DATA_THRESH_MASK (0x000007f8)
|
||||
#define HI_SMPS_DATA_THRESH_SHIFT (3)
|
||||
#define HI_SMPS_RSSI_THRESH_MASK (0x0007f800)
|
||||
#define HI_SMPS_RSSI_THRESH_SHIFT (11)
|
||||
#define HI_SMPS_LOWPWR_CM_MASK (0x00380000)
|
||||
#define HI_SMPS_LOWPWR_CM_SHIFT (15)
|
||||
#define HI_SMPS_HIPWR_CM_MASK (0x03c00000)
|
||||
#define HI_SMPS_HIPWR_CM_SHIFT (19)
|
||||
|
||||
/*
|
||||
* WOW Extension configuration
|
||||
*
|
||||
* Bit Range Meaning
|
||||
* --------- --------------------------------
|
||||
* 8..0 Size of each WOW pattern (max 511)
|
||||
* 15..9 Number of patterns per list (max 127)
|
||||
* 17..16 Number of lists (max 4)
|
||||
* 30..18 Reserved
|
||||
* 31 Enabled
|
||||
*
|
||||
* set values (except enable) to zeros for default settings
|
||||
*/
|
||||
|
||||
#define HI_WOW_EXT_ENABLED_MASK (1 << 31)
|
||||
#define HI_WOW_EXT_NUM_LIST_SHIFT 16
|
||||
#define HI_WOW_EXT_NUM_LIST_MASK (0x3 << HI_WOW_EXT_NUM_LIST_SHIFT)
|
||||
#define HI_WOW_EXT_NUM_PATTERNS_SHIFT 9
|
||||
#define HI_WOW_EXT_NUM_PATTERNS_MASK (0x7F << HI_WOW_EXT_NUM_PATTERNS_SHIFT)
|
||||
#define HI_WOW_EXT_PATTERN_SIZE_SHIFT 0
|
||||
#define HI_WOW_EXT_PATTERN_SIZE_MASK (0x1FF << HI_WOW_EXT_PATTERN_SIZE_SHIFT)
|
||||
|
||||
#define HI_WOW_EXT_MAKE_CONFIG(num_lists, count, size) \
|
||||
((((num_lists) << HI_WOW_EXT_NUM_LIST_SHIFT) & \
|
||||
HI_WOW_EXT_NUM_LIST_MASK) | \
|
||||
(((count) << HI_WOW_EXT_NUM_PATTERNS_SHIFT) & \
|
||||
HI_WOW_EXT_NUM_PATTERNS_MASK) | \
|
||||
(((size) << HI_WOW_EXT_PATTERN_SIZE_SHIFT) & \
|
||||
HI_WOW_EXT_PATTERN_SIZE_MASK))
|
||||
|
||||
#define HI_WOW_EXT_GET_NUM_LISTS(config) \
|
||||
(((config) & HI_WOW_EXT_NUM_LIST_MASK) >> HI_WOW_EXT_NUM_LIST_SHIFT)
|
||||
#define HI_WOW_EXT_GET_NUM_PATTERNS(config) \
|
||||
(((config) & HI_WOW_EXT_NUM_PATTERNS_MASK) >> \
|
||||
HI_WOW_EXT_NUM_PATTERNS_SHIFT)
|
||||
#define HI_WOW_EXT_GET_PATTERN_SIZE(config) \
|
||||
(((config) & HI_WOW_EXT_PATTERN_SIZE_MASK) >> \
|
||||
HI_WOW_EXT_PATTERN_SIZE_SHIFT)
|
||||
|
||||
/*
|
||||
* Early allocation configuration
|
||||
* Support RAM bank configuration before BMI done and this eases the memory
|
||||
* allocation at very early stage
|
||||
* Bit Range Meaning
|
||||
* --------- ----------------------------------
|
||||
* [0:3] number of bank assigned to be IRAM
|
||||
* [4:15] reserved
|
||||
* [16:31] magic number
|
||||
*
|
||||
* Note:
|
||||
* 1. target firmware would check magic number and if it's a match, firmware
|
||||
* would consider the bits[0:15] are valid and base on that to calculate
|
||||
* the end of DRAM. Early allocation would be located at that area and
|
||||
* may be reclaimed when necesary
|
||||
* 2. if no magic number is found, early allocation would happen at "_end"
|
||||
* symbol of ROM which is located before the app-data and might NOT be
|
||||
* re-claimable. If this is adopted, link script should keep this in
|
||||
* mind to avoid data corruption.
|
||||
*/
|
||||
#define HI_EARLY_ALLOC_MAGIC 0x6d8a
|
||||
#define HI_EARLY_ALLOC_MAGIC_MASK 0xffff0000
|
||||
#define HI_EARLY_ALLOC_MAGIC_SHIFT 16
|
||||
#define HI_EARLY_ALLOC_IRAM_BANKS_MASK 0x0000000f
|
||||
#define HI_EARLY_ALLOC_IRAM_BANKS_SHIFT 0
|
||||
|
||||
#define HI_EARLY_ALLOC_VALID() \
|
||||
((((HOST_INTEREST->hi_early_alloc) & HI_EARLY_ALLOC_MAGIC_MASK) >> \
|
||||
HI_EARLY_ALLOC_MAGIC_SHIFT) == (HI_EARLY_ALLOC_MAGIC))
|
||||
#define HI_EARLY_ALLOC_GET_IRAM_BANKS() \
|
||||
(((HOST_INTEREST->hi_early_alloc) & HI_EARLY_ALLOC_IRAM_BANKS_MASK) \
|
||||
>> HI_EARLY_ALLOC_IRAM_BANKS_SHIFT)
|
||||
|
||||
/*power save flag bit definitions*/
|
||||
#define HI_PWR_SAVE_LPL_ENABLED 0x1
|
||||
/*b1-b3 reserved*/
|
||||
/*b4-b5 : dev0 LPL type : 0 - none
|
||||
1- Reduce Pwr Search
|
||||
2- Reduce Pwr Listen*/
|
||||
/*b6-b7 : dev1 LPL type and so on for Max 8 devices*/
|
||||
#define HI_PWR_SAVE_LPL_DEV0_LSB 4
|
||||
#define HI_PWR_SAVE_LPL_DEV_MASK 0x3
|
||||
/*power save related utility macros*/
|
||||
#define HI_LPL_ENABLED() \
|
||||
((HOST_INTEREST->hi_pwr_save_flags & HI_PWR_SAVE_LPL_ENABLED))
|
||||
#define HI_DEV_LPL_TYPE_GET(_devix) \
|
||||
(HOST_INTEREST->hi_pwr_save_flags & ((HI_PWR_SAVE_LPL_DEV_MASK) << \
|
||||
(HI_PWR_SAVE_LPL_DEV0_LSB + (_devix)*2)))
|
||||
|
||||
#define HOST_INTEREST_SMPS_IS_ALLOWED() \
|
||||
((HOST_INTEREST->hi_smps_options & HI_SMPS_ALLOW_MASK))
|
||||
|
||||
/* Reserve 1024 bytes for extended board data */
|
||||
#define QCA988X_BOARD_DATA_SZ 7168
|
||||
#define QCA988X_BOARD_EXT_DATA_SZ 0
|
||||
|
||||
#endif /* __TARGADDRS_H__ */
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "trace.h"
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2013 Qualcomm Atheros, 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.
|
||||
*/
|
||||
|
||||
#if !defined(_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
|
||||
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
#define _TRACE_H_
|
||||
|
||||
/* create empty functions when tracing is disabled */
|
||||
#if !defined(CONFIG_ATH10K_TRACING)
|
||||
#undef TRACE_EVENT
|
||||
#define TRACE_EVENT(name, proto, ...) \
|
||||
static inline void trace_ ## name(proto) {}
|
||||
#undef DECLARE_EVENT_CLASS
|
||||
#define DECLARE_EVENT_CLASS(...)
|
||||
#undef DEFINE_EVENT
|
||||
#define DEFINE_EVENT(evt_class, name, proto, ...) \
|
||||
static inline void trace_ ## name(proto) {}
|
||||
#endif /* !CONFIG_ATH10K_TRACING || __CHECKER__ */
|
||||
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM ath10k
|
||||
|
||||
#define ATH10K_MSG_MAX 200
|
||||
|
||||
DECLARE_EVENT_CLASS(ath10k_log_event,
|
||||
TP_PROTO(struct va_format *vaf),
|
||||
TP_ARGS(vaf),
|
||||
TP_STRUCT__entry(
|
||||
__dynamic_array(char, msg, ATH10K_MSG_MAX)
|
||||
),
|
||||
TP_fast_assign(
|
||||
WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
|
||||
ATH10K_MSG_MAX,
|
||||
vaf->fmt,
|
||||
*vaf->va) >= ATH10K_MSG_MAX);
|
||||
),
|
||||
TP_printk("%s", __get_str(msg))
|
||||
);
|
||||
|
||||
DEFINE_EVENT(ath10k_log_event, ath10k_log_err,
|
||||
TP_PROTO(struct va_format *vaf),
|
||||
TP_ARGS(vaf)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(ath10k_log_event, ath10k_log_warn,
|
||||
TP_PROTO(struct va_format *vaf),
|
||||
TP_ARGS(vaf)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(ath10k_log_event, ath10k_log_info,
|
||||
TP_PROTO(struct va_format *vaf),
|
||||
TP_ARGS(vaf)
|
||||
);
|
||||
|
||||
TRACE_EVENT(ath10k_log_dbg,
|
||||
TP_PROTO(unsigned int level, struct va_format *vaf),
|
||||
TP_ARGS(level, vaf),
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, level)
|
||||
__dynamic_array(char, msg, ATH10K_MSG_MAX)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->level = level;
|
||||
WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
|
||||
ATH10K_MSG_MAX,
|
||||
vaf->fmt,
|
||||
*vaf->va) >= ATH10K_MSG_MAX);
|
||||
),
|
||||
TP_printk("%s", __get_str(msg))
|
||||
);
|
||||
|
||||
TRACE_EVENT(ath10k_log_dbg_dump,
|
||||
TP_PROTO(const char *msg, const char *prefix,
|
||||
const void *buf, size_t buf_len),
|
||||
|
||||
TP_ARGS(msg, prefix, buf, buf_len),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string(msg, msg)
|
||||
__string(prefix, prefix)
|
||||
__field(size_t, buf_len)
|
||||
__dynamic_array(u8, buf, buf_len)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(msg, msg);
|
||||
__assign_str(prefix, prefix);
|
||||
__entry->buf_len = buf_len;
|
||||
memcpy(__get_dynamic_array(buf), buf, buf_len);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"%s/%s\n", __get_str(prefix), __get_str(msg)
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(ath10k_wmi_cmd,
|
||||
TP_PROTO(int id, void *buf, size_t buf_len),
|
||||
|
||||
TP_ARGS(id, buf, buf_len),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, id)
|
||||
__field(size_t, buf_len)
|
||||
__dynamic_array(u8, buf, buf_len)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->id = id;
|
||||
__entry->buf_len = buf_len;
|
||||
memcpy(__get_dynamic_array(buf), buf, buf_len);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"id %d len %zu",
|
||||
__entry->id,
|
||||
__entry->buf_len
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(ath10k_wmi_event,
|
||||
TP_PROTO(int id, void *buf, size_t buf_len),
|
||||
|
||||
TP_ARGS(id, buf, buf_len),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, id)
|
||||
__field(size_t, buf_len)
|
||||
__dynamic_array(u8, buf, buf_len)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->id = id;
|
||||
__entry->buf_len = buf_len;
|
||||
memcpy(__get_dynamic_array(buf), buf, buf_len);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"id %d len %zu",
|
||||
__entry->id,
|
||||
__entry->buf_len
|
||||
)
|
||||
);
|
||||
|
||||
#endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/
|
||||
|
||||
/* we don't want to use include/trace/events */
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
#define TRACE_INCLUDE_PATH .
|
||||
#undef TRACE_INCLUDE_FILE
|
||||
#define TRACE_INCLUDE_FILE trace
|
||||
|
||||
/* This part must be outside protection */
|
||||
#include <trace/define_trace.h>
|
|
@ -0,0 +1,417 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2013 Qualcomm Atheros, 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 "txrx.h"
|
||||
#include "htt.h"
|
||||
#include "mac.h"
|
||||
#include "debug.h"
|
||||
|
||||
static void ath10k_report_offchan_tx(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
if (!ATH10K_SKB_CB(skb)->htt.is_offchan)
|
||||
return;
|
||||
|
||||
/* If the original wait_for_completion() timed out before
|
||||
* {data,mgmt}_tx_completed() was called then we could complete
|
||||
* offchan_tx_completed for a different skb. Prevent this by using
|
||||
* offchan_tx_skb. */
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
if (ar->offchan_tx_skb != skb) {
|
||||
ath10k_warn("completed old offchannel frame\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
complete(&ar->offchan_tx_completed);
|
||||
ar->offchan_tx_skb = NULL; /* just for sanity */
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_HTT, "completed offchannel skb %p\n", skb);
|
||||
out:
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
void ath10k_txrx_tx_unref(struct ath10k_htt *htt, struct sk_buff *txdesc)
|
||||
{
|
||||
struct device *dev = htt->ar->dev;
|
||||
struct ieee80211_tx_info *info;
|
||||
struct sk_buff *txfrag = ATH10K_SKB_CB(txdesc)->htt.txfrag;
|
||||
struct sk_buff *msdu = ATH10K_SKB_CB(txdesc)->htt.msdu;
|
||||
int ret;
|
||||
|
||||
if (ATH10K_SKB_CB(txdesc)->htt.refcount == 0)
|
||||
return;
|
||||
|
||||
ATH10K_SKB_CB(txdesc)->htt.refcount--;
|
||||
|
||||
if (ATH10K_SKB_CB(txdesc)->htt.refcount > 0)
|
||||
return;
|
||||
|
||||
if (txfrag) {
|
||||
ret = ath10k_skb_unmap(dev, txfrag);
|
||||
if (ret)
|
||||
ath10k_warn("txfrag unmap failed (%d)\n", ret);
|
||||
|
||||
dev_kfree_skb_any(txfrag);
|
||||
}
|
||||
|
||||
ret = ath10k_skb_unmap(dev, msdu);
|
||||
if (ret)
|
||||
ath10k_warn("data skb unmap failed (%d)\n", ret);
|
||||
|
||||
ath10k_report_offchan_tx(htt->ar, msdu);
|
||||
|
||||
info = IEEE80211_SKB_CB(msdu);
|
||||
memset(&info->status, 0, sizeof(info->status));
|
||||
|
||||
if (ATH10K_SKB_CB(txdesc)->htt.discard) {
|
||||
ieee80211_free_txskb(htt->ar->hw, msdu);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
|
||||
info->flags |= IEEE80211_TX_STAT_ACK;
|
||||
|
||||
if (ATH10K_SKB_CB(txdesc)->htt.no_ack)
|
||||
info->flags &= ~IEEE80211_TX_STAT_ACK;
|
||||
|
||||
ieee80211_tx_status(htt->ar->hw, msdu);
|
||||
/* we do not own the msdu anymore */
|
||||
|
||||
exit:
|
||||
spin_lock_bh(&htt->tx_lock);
|
||||
htt->pending_tx[ATH10K_SKB_CB(txdesc)->htt.msdu_id] = NULL;
|
||||
ath10k_htt_tx_free_msdu_id(htt, ATH10K_SKB_CB(txdesc)->htt.msdu_id);
|
||||
__ath10k_htt_tx_dec_pending(htt);
|
||||
if (bitmap_empty(htt->used_msdu_ids, htt->max_num_pending_tx))
|
||||
wake_up(&htt->empty_tx_wq);
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
|
||||
dev_kfree_skb_any(txdesc);
|
||||
}
|
||||
|
||||
void ath10k_txrx_tx_completed(struct ath10k_htt *htt,
|
||||
const struct htt_tx_done *tx_done)
|
||||
{
|
||||
struct sk_buff *txdesc;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n",
|
||||
tx_done->msdu_id, !!tx_done->discard, !!tx_done->no_ack);
|
||||
|
||||
if (tx_done->msdu_id >= htt->max_num_pending_tx) {
|
||||
ath10k_warn("warning: msdu_id %d too big, ignoring\n",
|
||||
tx_done->msdu_id);
|
||||
return;
|
||||
}
|
||||
|
||||
txdesc = htt->pending_tx[tx_done->msdu_id];
|
||||
|
||||
ATH10K_SKB_CB(txdesc)->htt.discard = tx_done->discard;
|
||||
ATH10K_SKB_CB(txdesc)->htt.no_ack = tx_done->no_ack;
|
||||
|
||||
ath10k_txrx_tx_unref(htt, txdesc);
|
||||
}
|
||||
|
||||
static const u8 rx_legacy_rate_idx[] = {
|
||||
3, /* 0x00 - 11Mbps */
|
||||
2, /* 0x01 - 5.5Mbps */
|
||||
1, /* 0x02 - 2Mbps */
|
||||
0, /* 0x03 - 1Mbps */
|
||||
3, /* 0x04 - 11Mbps */
|
||||
2, /* 0x05 - 5.5Mbps */
|
||||
1, /* 0x06 - 2Mbps */
|
||||
0, /* 0x07 - 1Mbps */
|
||||
10, /* 0x08 - 48Mbps */
|
||||
8, /* 0x09 - 24Mbps */
|
||||
6, /* 0x0A - 12Mbps */
|
||||
4, /* 0x0B - 6Mbps */
|
||||
11, /* 0x0C - 54Mbps */
|
||||
9, /* 0x0D - 36Mbps */
|
||||
7, /* 0x0E - 18Mbps */
|
||||
5, /* 0x0F - 9Mbps */
|
||||
};
|
||||
|
||||
static void process_rx_rates(struct ath10k *ar, struct htt_rx_info *info,
|
||||
enum ieee80211_band band,
|
||||
struct ieee80211_rx_status *status)
|
||||
{
|
||||
u8 cck, rate, rate_idx, bw, sgi, mcs, nss;
|
||||
u8 info0 = info->rate.info0;
|
||||
u32 info1 = info->rate.info1;
|
||||
u32 info2 = info->rate.info2;
|
||||
u8 preamble = 0;
|
||||
|
||||
/* Check if valid fields */
|
||||
if (!(info0 & HTT_RX_INDICATION_INFO0_START_VALID))
|
||||
return;
|
||||
|
||||
preamble = MS(info1, HTT_RX_INDICATION_INFO1_PREAMBLE_TYPE);
|
||||
|
||||
switch (preamble) {
|
||||
case HTT_RX_LEGACY:
|
||||
cck = info0 & HTT_RX_INDICATION_INFO0_LEGACY_RATE_CCK;
|
||||
rate = MS(info0, HTT_RX_INDICATION_INFO0_LEGACY_RATE);
|
||||
rate_idx = 0;
|
||||
|
||||
if (rate < 0x08 || rate > 0x0F)
|
||||
break;
|
||||
|
||||
switch (band) {
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
if (cck)
|
||||
rate &= ~BIT(3);
|
||||
rate_idx = rx_legacy_rate_idx[rate];
|
||||
break;
|
||||
case IEEE80211_BAND_5GHZ:
|
||||
rate_idx = rx_legacy_rate_idx[rate];
|
||||
/* We are using same rate table registering
|
||||
HW - ath10k_rates[]. In case of 5GHz skip
|
||||
CCK rates, so -4 here */
|
||||
rate_idx -= 4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
status->rate_idx = rate_idx;
|
||||
break;
|
||||
case HTT_RX_HT:
|
||||
case HTT_RX_HT_WITH_TXBF:
|
||||
/* HT-SIG - Table 20-11 in info1 and info2 */
|
||||
mcs = info1 & 0x1F;
|
||||
nss = mcs >> 3;
|
||||
bw = (info1 >> 7) & 1;
|
||||
sgi = (info2 >> 7) & 1;
|
||||
|
||||
status->rate_idx = mcs;
|
||||
status->flag |= RX_FLAG_HT;
|
||||
if (sgi)
|
||||
status->flag |= RX_FLAG_SHORT_GI;
|
||||
if (bw)
|
||||
status->flag |= RX_FLAG_40MHZ;
|
||||
break;
|
||||
case HTT_RX_VHT:
|
||||
case HTT_RX_VHT_WITH_TXBF:
|
||||
/* VHT-SIG-A1 in info 1, VHT-SIG-A2 in info2
|
||||
TODO check this */
|
||||
mcs = (info2 >> 4) & 0x0F;
|
||||
nss = (info1 >> 10) & 0x07;
|
||||
bw = info1 & 3;
|
||||
sgi = info2 & 1;
|
||||
|
||||
status->rate_idx = mcs;
|
||||
status->vht_nss = nss;
|
||||
|
||||
if (sgi)
|
||||
status->flag |= RX_FLAG_SHORT_GI;
|
||||
|
||||
switch (bw) {
|
||||
/* 20MHZ */
|
||||
case 0:
|
||||
break;
|
||||
/* 40MHZ */
|
||||
case 1:
|
||||
status->flag |= RX_FLAG_40MHZ;
|
||||
break;
|
||||
/* 80MHZ */
|
||||
case 2:
|
||||
status->flag |= RX_FLAG_80MHZ;
|
||||
}
|
||||
|
||||
status->flag |= RX_FLAG_VHT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info)
|
||||
{
|
||||
struct ieee80211_rx_status *status;
|
||||
struct ieee80211_channel *ch;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)info->skb->data;
|
||||
|
||||
status = IEEE80211_SKB_RXCB(info->skb);
|
||||
memset(status, 0, sizeof(*status));
|
||||
|
||||
if (info->encrypt_type != HTT_RX_MPDU_ENCRYPT_NONE) {
|
||||
status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED |
|
||||
RX_FLAG_MMIC_STRIPPED;
|
||||
hdr->frame_control = __cpu_to_le16(
|
||||
__le16_to_cpu(hdr->frame_control) &
|
||||
~IEEE80211_FCTL_PROTECTED);
|
||||
}
|
||||
|
||||
if (info->status == HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR)
|
||||
status->flag |= RX_FLAG_MMIC_ERROR;
|
||||
|
||||
if (info->fcs_err)
|
||||
status->flag |= RX_FLAG_FAILED_FCS_CRC;
|
||||
|
||||
status->signal = info->signal;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
ch = ar->scan_channel;
|
||||
if (!ch)
|
||||
ch = ar->rx_channel;
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
if (!ch) {
|
||||
ath10k_warn("no channel configured; ignoring frame!\n");
|
||||
dev_kfree_skb_any(info->skb);
|
||||
return;
|
||||
}
|
||||
|
||||
process_rx_rates(ar, info, ch->band, status);
|
||||
status->band = ch->band;
|
||||
status->freq = ch->center_freq;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_DATA,
|
||||
"rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u\n",
|
||||
info->skb,
|
||||
info->skb->len,
|
||||
status->flag == 0 ? "legacy" : "",
|
||||
status->flag & RX_FLAG_HT ? "ht" : "",
|
||||
status->flag & RX_FLAG_VHT ? "vht" : "",
|
||||
status->flag & RX_FLAG_40MHZ ? "40" : "",
|
||||
status->flag & RX_FLAG_80MHZ ? "80" : "",
|
||||
status->flag & RX_FLAG_SHORT_GI ? "sgi " : "",
|
||||
status->rate_idx,
|
||||
status->vht_nss,
|
||||
status->freq,
|
||||
status->band);
|
||||
|
||||
ieee80211_rx(ar->hw, info->skb);
|
||||
}
|
||||
|
||||
struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id,
|
||||
const u8 *addr)
|
||||
{
|
||||
struct ath10k_peer *peer;
|
||||
|
||||
lockdep_assert_held(&ar->data_lock);
|
||||
|
||||
list_for_each_entry(peer, &ar->peers, list) {
|
||||
if (peer->vdev_id != vdev_id)
|
||||
continue;
|
||||
if (memcmp(peer->addr, addr, ETH_ALEN))
|
||||
continue;
|
||||
|
||||
return peer;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar,
|
||||
int peer_id)
|
||||
{
|
||||
struct ath10k_peer *peer;
|
||||
|
||||
lockdep_assert_held(&ar->data_lock);
|
||||
|
||||
list_for_each_entry(peer, &ar->peers, list)
|
||||
if (test_bit(peer_id, peer->peer_ids))
|
||||
return peer;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ath10k_wait_for_peer_common(struct ath10k *ar, int vdev_id,
|
||||
const u8 *addr, bool expect_mapped)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wait_event_timeout(ar->peer_mapping_wq, ({
|
||||
bool mapped;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
mapped = !!ath10k_peer_find(ar, vdev_id, addr);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
mapped == expect_mapped;
|
||||
}), 3*HZ);
|
||||
|
||||
if (ret <= 0)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_wait_for_peer_created(struct ath10k *ar, int vdev_id, const u8 *addr)
|
||||
{
|
||||
return ath10k_wait_for_peer_common(ar, vdev_id, addr, true);
|
||||
}
|
||||
|
||||
int ath10k_wait_for_peer_deleted(struct ath10k *ar, int vdev_id, const u8 *addr)
|
||||
{
|
||||
return ath10k_wait_for_peer_common(ar, vdev_id, addr, false);
|
||||
}
|
||||
|
||||
void ath10k_peer_map_event(struct ath10k_htt *htt,
|
||||
struct htt_peer_map_event *ev)
|
||||
{
|
||||
struct ath10k *ar = htt->ar;
|
||||
struct ath10k_peer *peer;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
peer = ath10k_peer_find(ar, ev->vdev_id, ev->addr);
|
||||
if (!peer) {
|
||||
peer = kzalloc(sizeof(*peer), GFP_ATOMIC);
|
||||
if (!peer)
|
||||
goto exit;
|
||||
|
||||
peer->vdev_id = ev->vdev_id;
|
||||
memcpy(peer->addr, ev->addr, ETH_ALEN);
|
||||
list_add(&peer->list, &ar->peers);
|
||||
wake_up(&ar->peer_mapping_wq);
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n",
|
||||
ev->vdev_id, ev->addr, ev->peer_id);
|
||||
|
||||
set_bit(ev->peer_id, peer->peer_ids);
|
||||
exit:
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
void ath10k_peer_unmap_event(struct ath10k_htt *htt,
|
||||
struct htt_peer_unmap_event *ev)
|
||||
{
|
||||
struct ath10k *ar = htt->ar;
|
||||
struct ath10k_peer *peer;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
peer = ath10k_peer_find_by_id(ar, ev->peer_id);
|
||||
if (!peer) {
|
||||
ath10k_warn("unknown peer id %d\n", ev->peer_id);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_HTT, "htt peer unmap vdev %d peer %pM id %d\n",
|
||||
peer->vdev_id, peer->addr, ev->peer_id);
|
||||
|
||||
clear_bit(ev->peer_id, peer->peer_ids);
|
||||
|
||||
if (bitmap_empty(peer->peer_ids, ATH10K_MAX_NUM_PEER_IDS)) {
|
||||
list_del(&peer->list);
|
||||
kfree(peer);
|
||||
wake_up(&ar->peer_mapping_wq);
|
||||
}
|
||||
|
||||
exit:
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2013 Qualcomm Atheros, 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 _TXRX_H_
|
||||
#define _TXRX_H_
|
||||
|
||||
#include "htt.h"
|
||||
|
||||
void ath10k_txrx_tx_unref(struct ath10k_htt *htt, struct sk_buff *txdesc);
|
||||
void ath10k_txrx_tx_completed(struct ath10k_htt *htt,
|
||||
const struct htt_tx_done *tx_done);
|
||||
void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info);
|
||||
|
||||
struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id,
|
||||
const u8 *addr);
|
||||
int ath10k_wait_for_peer_created(struct ath10k *ar, int vdev_id,
|
||||
const u8 *addr);
|
||||
int ath10k_wait_for_peer_deleted(struct ath10k *ar, int vdev_id,
|
||||
const u8 *addr);
|
||||
|
||||
void ath10k_peer_map_event(struct ath10k_htt *htt,
|
||||
struct htt_peer_map_event *ev);
|
||||
void ath10k_peer_unmap_event(struct ath10k_htt *htt,
|
||||
struct htt_peer_unmap_event *ev);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue