Skip to content

Commit

Permalink
ath10k: mac80211 driver for Qualcomm Atheros 802.11ac CQA98xx devices
Browse files Browse the repository at this point in the history
Here's a new mac80211 driver for Qualcomm Atheros 802.11ac QCA98xx devices.
A major difference from ath9k is that there's now a firmware and
that's why we had to implement a new driver.

The wiki page for the driver is:

http://wireless.kernel.org/en/users/Drivers/ath10k

The driver has had many authors, they are listed here alphabetically:

Bartosz Markowski <[email protected]>
Janusz Dziedzic <[email protected]>
Kalle Valo <[email protected]>
Marek Kwaczynski <[email protected]>
Marek Puzyniak <[email protected]>
Michal Kazior <[email protected]>
Sujith Manoharan <[email protected]>

Signed-off-by: Kalle Valo <[email protected]>
  • Loading branch information
kvalo committed Jun 12, 2013
1 parent 8b3e7be commit 5e3dd15
Show file tree
Hide file tree
Showing 32 changed files with 22,094 additions and 0 deletions.
1 change: 1 addition & 0 deletions drivers/net/wireless/ath/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions drivers/net/wireless/ath/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
39 changes: 39 additions & 0 deletions drivers/net/wireless/ath/ath10k/Kconfig
Original file line number Diff line number Diff line change
@@ -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.

20 changes: 20 additions & 0 deletions drivers/net/wireless/ath/ath10k/Makefile
Original file line number Diff line number Diff line change
@@ -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)
295 changes: 295 additions & 0 deletions drivers/net/wireless/ath/ath10k/bmi.c
Original file line number Diff line number Diff line change
@@ -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;
}
Loading

0 comments on commit 5e3dd15

Please sign in to comment.