Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 640f5950 authored by John W. Linville's avatar John W. Linville
Browse files

Merge branch 'for-linville' of git://github.com/kvalo/ath6kl

parents 7c4559c9 7e95e365
Loading
Loading
Loading
Loading
+21 −4
Original line number Diff line number Diff line
config ATH6KL
	tristate "Atheros ath6kl support"
	tristate "Atheros mobile chipsets support"

config ATH6KL_SDIO
	tristate "Atheros ath6kl SDIO support"
	depends on ATH6KL
	depends on MMC
	depends on CFG80211
	---help---
	  This module adds support for wireless adapters based on
	  Atheros AR6003 chipset running over SDIO. If you choose to
	  build it as a module, it will be called ath6kl. Pls note
	  that AR6002 and AR6001 are not supported by this driver.
	  Atheros AR6003 and AR6004 chipsets running over SDIO. If you
	  choose to build it as a module, it will be called ath6kl_sdio.
	  Please note that AR6002 and AR6001 are not supported by this
	  driver.

config ATH6KL_USB
	tristate "Atheros ath6kl USB support"
	depends on ATH6KL
	depends on USB
	depends on CFG80211
	depends on EXPERIMENTAL
	---help---
	  This module adds support for wireless adapters based on
	  Atheros AR6004 chipset running over USB. This is still under
	  implementation and it isn't functional. If you choose to
	  build it as a module, it will be called ath6kl_usb.

config ATH6KL_DEBUG
	bool "Atheros ath6kl debugging"
+25 −12
Original line number Diff line number Diff line
@@ -21,17 +21,30 @@
# Author(s): ="Atheros"
#------------------------------------------------------------------------------

obj-$(CONFIG_ATH6KL) := ath6kl.o
ath6kl-y += debug.o
ath6kl-y += hif.o
ath6kl-y += htc.o
ath6kl-y += bmi.o
ath6kl-y += cfg80211.o
ath6kl-y += init.o
ath6kl-y += main.o
ath6kl-y += txrx.o
ath6kl-y += wmi.o
ath6kl-y += sdio.o
ath6kl-$(CONFIG_NL80211_TESTMODE) += testmode.o
obj-$(CONFIG_ATH6KL_SDIO) := ath6kl_sdio.o
ath6kl_sdio-y += debug.o
ath6kl_sdio-y += hif.o
ath6kl_sdio-y += htc.o
ath6kl_sdio-y += bmi.o
ath6kl_sdio-y += cfg80211.o
ath6kl_sdio-y += init.o
ath6kl_sdio-y += main.o
ath6kl_sdio-y += txrx.o
ath6kl_sdio-y += wmi.o
ath6kl_sdio-y += sdio.o
ath6kl_sdio-$(CONFIG_NL80211_TESTMODE) += testmode.o

obj-$(CONFIG_ATH6KL_USB) += ath6kl_usb.o
ath6kl_usb-y += debug.o
ath6kl_usb-y += hif.o
ath6kl_usb-y += htc.o
ath6kl_usb-y += bmi.o
ath6kl_usb-y += cfg80211.o
ath6kl_usb-y += init.o
ath6kl_usb-y += main.o
ath6kl_usb-y += txrx.o
ath6kl_usb-y += wmi.o
ath6kl_usb-y += usb.o
ath6kl_usb-$(CONFIG_NL80211_TESTMODE) += testmode.o

ccflags-y += -D__CHECK_ENDIAN__
+50 −195
Original line number Diff line number Diff line
@@ -19,165 +19,6 @@
#include "target.h"
#include "debug.h"

static int ath6kl_get_bmi_cmd_credits(struct ath6kl *ar)
{
	u32 addr;
	unsigned long timeout;
	int ret;

	ar->bmi.cmd_credits = 0;

	/* Read the counter register to get the command credits */
	addr = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4;

	timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
	while (time_before(jiffies, timeout) && !ar->bmi.cmd_credits) {

		/*
		 * Hit the credit counter with a 4-byte access, the first byte
		 * read will hit the counter and cause a decrement, while the
		 * remaining 3 bytes has no effect. The rationale behind this
		 * is to make all HIF accesses 4-byte aligned.
		 */
		ret = hif_read_write_sync(ar, addr,
					 (u8 *)&ar->bmi.cmd_credits, 4,
					 HIF_RD_SYNC_BYTE_INC);
		if (ret) {
			ath6kl_err("Unable to decrement the command credit count register: %d\n",
				   ret);
			return ret;
		}

		/* The counter is only 8 bits.
		 * Ignore anything in the upper 3 bytes
		 */
		ar->bmi.cmd_credits &= 0xFF;
	}

	if (!ar->bmi.cmd_credits) {
		ath6kl_err("bmi communication timeout\n");
		return -ETIMEDOUT;
	}

	return 0;
}

static int ath6kl_bmi_get_rx_lkahd(struct ath6kl *ar)
{
	unsigned long timeout;
	u32 rx_word = 0;
	int ret = 0;

	timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
	while (time_before(jiffies, timeout) && !rx_word) {
		ret = hif_read_write_sync(ar, RX_LOOKAHEAD_VALID_ADDRESS,
					  (u8 *)&rx_word, sizeof(rx_word),
					  HIF_RD_SYNC_BYTE_INC);
		if (ret) {
			ath6kl_err("unable to read RX_LOOKAHEAD_VALID\n");
			return ret;
		}

		 /* all we really want is one bit */
		rx_word &= (1 << ENDPOINT1);
	}

	if (!rx_word) {
		ath6kl_err("bmi_recv_buf FIFO empty\n");
		return -EINVAL;
	}

	return ret;
}

static int ath6kl_bmi_send_buf(struct ath6kl *ar, u8 *buf, u32 len)
{
	int ret;
	u32 addr;

	ret = ath6kl_get_bmi_cmd_credits(ar);
	if (ret)
		return ret;

	addr = ar->mbox_info.htc_addr;

	ret = hif_read_write_sync(ar, addr, buf, len,
				  HIF_WR_SYNC_BYTE_INC);
	if (ret)
		ath6kl_err("unable to send the bmi data to the device\n");

	return ret;
}

static int ath6kl_bmi_recv_buf(struct ath6kl *ar, u8 *buf, u32 len)
{
	int ret;
	u32 addr;

	/*
	 * During normal bootup, small reads may be required.
	 * Rather than issue an HIF Read and then wait as the Target
	 * adds successive bytes to the FIFO, we wait here until
	 * we know that response data is available.
	 *
	 * This allows us to cleanly timeout on an unexpected
	 * Target failure rather than risk problems at the HIF level.
	 * In particular, this avoids SDIO timeouts and possibly garbage
	 * data on some host controllers.  And on an interconnect
	 * such as Compact Flash (as well as some SDIO masters) which
	 * does not provide any indication on data timeout, it avoids
	 * a potential hang or garbage response.
	 *
	 * Synchronization is more difficult for reads larger than the
	 * size of the MBOX FIFO (128B), because the Target is unable
	 * to push the 129th byte of data until AFTER the Host posts an
	 * HIF Read and removes some FIFO data.  So for large reads the
	 * Host proceeds to post an HIF Read BEFORE all the data is
	 * actually available to read.  Fortunately, large BMI reads do
	 * not occur in practice -- they're supported for debug/development.
	 *
	 * So Host/Target BMI synchronization is divided into these cases:
	 *  CASE 1: length < 4
	 *        Should not happen
	 *
	 *  CASE 2: 4 <= length <= 128
	 *        Wait for first 4 bytes to be in FIFO
	 *        If CONSERVATIVE_BMI_READ is enabled, also wait for
	 *        a BMI command credit, which indicates that the ENTIRE
	 *        response is available in the the FIFO
	 *
	 *  CASE 3: length > 128
	 *        Wait for the first 4 bytes to be in FIFO
	 *
	 * For most uses, a small timeout should be sufficient and we will
	 * usually see a response quickly; but there may be some unusual
	 * (debug) cases of BMI_EXECUTE where we want an larger timeout.
	 * For now, we use an unbounded busy loop while waiting for
	 * BMI_EXECUTE.
	 *
	 * If BMI_EXECUTE ever needs to support longer-latency execution,
	 * especially in production, this code needs to be enhanced to sleep
	 * and yield.  Also note that BMI_COMMUNICATION_TIMEOUT is currently
	 * a function of Host processor speed.
	 */
	if (len >= 4) { /* NB: Currently, always true */
		ret = ath6kl_bmi_get_rx_lkahd(ar);
		if (ret)
			return ret;
	}

	addr = ar->mbox_info.htc_addr;
	ret = hif_read_write_sync(ar, addr, buf, len,
				  HIF_RD_SYNC_BYTE_INC);
	if (ret) {
		ath6kl_err("Unable to read the bmi data from the device: %d\n",
			   ret);
		return ret;
	}

	return 0;
}

int ath6kl_bmi_done(struct ath6kl *ar)
{
	int ret;
@@ -190,7 +31,7 @@ int ath6kl_bmi_done(struct ath6kl *ar)

	ar->bmi.done_sent = true;

	ret = ath6kl_bmi_send_buf(ar, (u8 *)&cid, sizeof(cid));
	ret = ath6kl_hif_bmi_write(ar, (u8 *)&cid, sizeof(cid));
	if (ret) {
		ath6kl_err("Unable to send bmi done: %d\n", ret);
		return ret;
@@ -210,14 +51,20 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar,
		return -EACCES;
	}

	ret = ath6kl_bmi_send_buf(ar, (u8 *)&cid, sizeof(cid));
	ret = ath6kl_hif_bmi_write(ar, (u8 *)&cid, sizeof(cid));
	if (ret) {
		ath6kl_err("Unable to send get target info: %d\n", ret);
		return ret;
	}

	ret = ath6kl_bmi_recv_buf(ar, (u8 *)&targ_info->version,
	if (ar->hif_type == ATH6KL_HIF_TYPE_USB) {
		ret = ath6kl_hif_bmi_read(ar, (u8 *)targ_info,
					  sizeof(*targ_info));
	} else {
		ret = ath6kl_hif_bmi_read(ar, (u8 *)&targ_info->version,
				sizeof(targ_info->version));
	}

	if (ret) {
		ath6kl_err("Unable to recv target info: %d\n", ret);
		return ret;
@@ -225,7 +72,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar,

	if (le32_to_cpu(targ_info->version) == TARGET_VERSION_SENTINAL) {
		/* Determine how many bytes are in the Target's targ_info */
		ret = ath6kl_bmi_recv_buf(ar,
		ret = ath6kl_hif_bmi_read(ar,
				   (u8 *)&targ_info->byte_count,
				   sizeof(targ_info->byte_count));
		if (ret) {
@@ -244,7 +91,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar,
		}

		/* Read the remainder of the targ_info */
		ret = ath6kl_bmi_recv_buf(ar,
		ret = ath6kl_hif_bmi_read(ar,
				   ((u8 *)targ_info) +
				   sizeof(targ_info->byte_count),
				   sizeof(*targ_info) -
@@ -276,8 +123,8 @@ int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
		return -EACCES;
	}

	size = BMI_DATASZ_MAX + sizeof(cid) + sizeof(addr) + sizeof(len);
	if (size > MAX_BMI_CMDBUF_SZ) {
	size = ar->bmi.max_data_size + sizeof(cid) + sizeof(addr) + sizeof(len);
	if (size > ar->bmi.max_cmd_size) {
		WARN_ON(1);
		return -EINVAL;
	}
@@ -290,8 +137,8 @@ int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
	len_remain = len;

	while (len_remain) {
		rx_len = (len_remain < BMI_DATASZ_MAX) ?
					len_remain : BMI_DATASZ_MAX;
		rx_len = (len_remain < ar->bmi.max_data_size) ?
					len_remain : ar->bmi.max_data_size;
		offset = 0;
		memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
		offset += sizeof(cid);
@@ -300,13 +147,13 @@ int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
		memcpy(&(ar->bmi.cmd_buf[offset]), &rx_len, sizeof(rx_len));
		offset += sizeof(len);

		ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
		ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
		if (ret) {
			ath6kl_err("Unable to write to the device: %d\n",
				   ret);
			return ret;
		}
		ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, rx_len);
		ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, rx_len);
		if (ret) {
			ath6kl_err("Unable to read from the device: %d\n",
				   ret);
@@ -326,7 +173,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
	u32 offset;
	u32 len_remain, tx_len;
	const u32 header = sizeof(cid) + sizeof(addr) + sizeof(len);
	u8 aligned_buf[BMI_DATASZ_MAX];
	u8 aligned_buf[400];
	u8 *src;

	if (ar->bmi.done_sent) {
@@ -334,12 +181,15 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
		return -EACCES;
	}

	if ((BMI_DATASZ_MAX + header) > MAX_BMI_CMDBUF_SZ) {
	if ((ar->bmi.max_data_size + header) > ar->bmi.max_cmd_size) {
		WARN_ON(1);
		return -EINVAL;
	}

	memset(ar->bmi.cmd_buf, 0, BMI_DATASZ_MAX + header);
	if (WARN_ON(ar->bmi.max_data_size > sizeof(aligned_buf)))
		return -E2BIG;

	memset(ar->bmi.cmd_buf, 0, ar->bmi.max_data_size + header);

	ath6kl_dbg(ATH6KL_DBG_BMI,
		  "bmi write memory: addr: 0x%x, len: %d\n", addr, len);
@@ -348,7 +198,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
	while (len_remain) {
		src = &buf[len - len_remain];

		if (len_remain < (BMI_DATASZ_MAX - header)) {
		if (len_remain < (ar->bmi.max_data_size - header)) {
			if (len_remain & 3) {
				/* align it with 4 bytes */
				len_remain = len_remain +
@@ -358,7 +208,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
			}
			tx_len = len_remain;
		} else {
			tx_len = (BMI_DATASZ_MAX - header);
			tx_len = (ar->bmi.max_data_size - header);
		}

		offset = 0;
@@ -371,7 +221,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
		memcpy(&(ar->bmi.cmd_buf[offset]), src, tx_len);
		offset += tx_len;

		ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
		ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
		if (ret) {
			ath6kl_err("Unable to write to the device: %d\n",
				   ret);
@@ -396,7 +246,7 @@ int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param)
	}

	size = sizeof(cid) + sizeof(addr) + sizeof(param);
	if (size > MAX_BMI_CMDBUF_SZ) {
	if (size > ar->bmi.max_cmd_size) {
		WARN_ON(1);
		return -EINVAL;
	}
@@ -413,13 +263,13 @@ int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param)
	memcpy(&(ar->bmi.cmd_buf[offset]), param, sizeof(*param));
	offset += sizeof(*param);

	ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
	ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
	if (ret) {
		ath6kl_err("Unable to write to the device: %d\n", ret);
		return ret;
	}

	ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param));
	ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, sizeof(*param));
	if (ret) {
		ath6kl_err("Unable to read from the device: %d\n", ret);
		return ret;
@@ -443,7 +293,7 @@ int ath6kl_bmi_set_app_start(struct ath6kl *ar, u32 addr)
	}

	size = sizeof(cid) + sizeof(addr);
	if (size > MAX_BMI_CMDBUF_SZ) {
	if (size > ar->bmi.max_cmd_size) {
		WARN_ON(1);
		return -EINVAL;
	}
@@ -457,7 +307,7 @@ int ath6kl_bmi_set_app_start(struct ath6kl *ar, u32 addr)
	memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
	offset += sizeof(addr);

	ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
	ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
	if (ret) {
		ath6kl_err("Unable to write to the device: %d\n", ret);
		return ret;
@@ -479,7 +329,7 @@ int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param)
	}

	size = sizeof(cid) + sizeof(addr);
	if (size > MAX_BMI_CMDBUF_SZ) {
	if (size > ar->bmi.max_cmd_size) {
		WARN_ON(1);
		return -EINVAL;
	}
@@ -493,13 +343,13 @@ int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param)
	memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
	offset += sizeof(addr);

	ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
	ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
	if (ret) {
		ath6kl_err("Unable to write to the device: %d\n", ret);
		return ret;
	}

	ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param));
	ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, sizeof(*param));
	if (ret) {
		ath6kl_err("Unable to read from the device: %d\n", ret);
		return ret;
@@ -522,7 +372,7 @@ int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param)
	}

	size = sizeof(cid) + sizeof(addr) + sizeof(param);
	if (size > MAX_BMI_CMDBUF_SZ) {
	if (size > ar->bmi.max_cmd_size) {
		WARN_ON(1);
		return -EINVAL;
	}
@@ -540,7 +390,7 @@ int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param)
	memcpy(&(ar->bmi.cmd_buf[offset]), &param, sizeof(param));
	offset += sizeof(param);

	ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
	ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
	if (ret) {
		ath6kl_err("Unable to write to the device: %d\n", ret);
		return ret;
@@ -563,8 +413,8 @@ int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len)
		return -EACCES;
	}

	size = BMI_DATASZ_MAX + header;
	if (size > MAX_BMI_CMDBUF_SZ) {
	size = ar->bmi.max_data_size + header;
	if (size > ar->bmi.max_cmd_size) {
		WARN_ON(1);
		return -EINVAL;
	}
@@ -575,8 +425,8 @@ int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len)

	len_remain = len;
	while (len_remain) {
		tx_len = (len_remain < (BMI_DATASZ_MAX - header)) ?
			  len_remain : (BMI_DATASZ_MAX - header);
		tx_len = (len_remain < (ar->bmi.max_data_size - header)) ?
			  len_remain : (ar->bmi.max_data_size - header);

		offset = 0;
		memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
@@ -587,7 +437,7 @@ int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len)
			tx_len);
		offset += tx_len;

		ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
		ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
		if (ret) {
			ath6kl_err("Unable to write to the device: %d\n",
				   ret);
@@ -613,7 +463,7 @@ int ath6kl_bmi_lz_stream_start(struct ath6kl *ar, u32 addr)
	}

	size = sizeof(cid) + sizeof(addr);
	if (size > MAX_BMI_CMDBUF_SZ) {
	if (size > ar->bmi.max_cmd_size) {
		WARN_ON(1);
		return -EINVAL;
	}
@@ -629,7 +479,7 @@ int ath6kl_bmi_lz_stream_start(struct ath6kl *ar, u32 addr)
	memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
	offset += sizeof(addr);

	ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
	ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
	if (ret) {
		ath6kl_err("Unable to start LZ stream to the device: %d\n",
			   ret);
@@ -677,8 +527,13 @@ void ath6kl_bmi_reset(struct ath6kl *ar)

int ath6kl_bmi_init(struct ath6kl *ar)
{
	ar->bmi.cmd_buf = kzalloc(MAX_BMI_CMDBUF_SZ, GFP_ATOMIC);
	if (WARN_ON(ar->bmi.max_data_size == 0))
		return -EINVAL;

	/* cmd + addr + len + data_size */
	ar->bmi.max_cmd_size = ar->bmi.max_data_size + (sizeof(u32) * 3);

	ar->bmi.cmd_buf = kzalloc(ar->bmi.max_cmd_size, GFP_ATOMIC);
	if (!ar->bmi.cmd_buf)
		return -ENOMEM;

+0 −6
Original line number Diff line number Diff line
@@ -44,12 +44,6 @@
 * BMI handles all required Target-side cache flushing.
 */

#define MAX_BMI_CMDBUF_SZ (BMI_DATASZ_MAX + \
			   (sizeof(u32) * 3 /* cmd + addr + len */))

/* Maximum data size used for BMI transfers */
#define BMI_DATASZ_MAX                      256

/* BMI Commands */

#define BMI_NO_COMMAND                      0
+298 −84

File changed.

Preview size limit exceeded, changes collapsed.

Loading