diff options
Diffstat (limited to 'drivers/net/wireless/ath')
182 files changed, 30906 insertions, 15204 deletions
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 1abf1d42117..c63d1159db5 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -25,6 +25,23 @@ config ATH_DEBUG  	  Say Y, if you want to debug atheros wireless drivers.  	  Right now only ath9k makes use of this. +config ATH_REG_DYNAMIC_USER_REG_HINTS +	bool "Atheros dynamic user regulatory hints" +	depends on CFG80211_CERTIFICATION_ONUS +	default n +	---help--- +	  Say N. This should only be enabled in countries where +	  this feature is explicitly allowed and only on cards that +	  specifically have been tested for this. + +config ATH_REG_DYNAMIC_USER_CERT_TESTING +	bool "Atheros dynamic user regulatory testing" +	depends on ATH_REG_DYNAMIC_USER_REG_HINTS && CFG80211_CERTIFICATION_ONUS +	default n +	---help--- +	  Say N. This should only be enabled on systems +	  undergoing certification testing. +  source "drivers/net/wireless/ath/ath5k/Kconfig"  source "drivers/net/wireless/ath/ath9k/Kconfig"  source "drivers/net/wireless/ath/carl9170/Kconfig" @@ -32,5 +49,6 @@ 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" +source "drivers/net/wireless/ath/wcn36xx/Kconfig"  endif diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile index fb05cfd1936..7d023b0f13b 100644 --- a/drivers/net/wireless/ath/Makefile +++ b/drivers/net/wireless/ath/Makefile @@ -5,13 +5,16 @@ obj-$(CONFIG_ATH6KL)		+= ath6kl/  obj-$(CONFIG_AR5523)		+= ar5523/  obj-$(CONFIG_WIL6210)		+= wil6210/  obj-$(CONFIG_ATH10K)		+= ath10k/ +obj-$(CONFIG_WCN36XX)		+= wcn36xx/  obj-$(CONFIG_ATH_COMMON)	+= ath.o  ath-objs :=	main.o \  		regd.o \  		hw.o \ -		key.o +		key.o \ +		dfs_pattern_detector.o \ +		dfs_pri_detector.o  ath-$(CONFIG_ATH_DEBUG) += debug.o  ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index 17d7fece35d..f92050617ae 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -25,7 +25,6 @@   * that and only has minimal functionality.   */  #include <linux/compiler.h> -#include <linux/init.h>  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/list.h> @@ -1091,7 +1090,8 @@ static int ar5523_set_rts_threshold(struct ieee80211_hw *hw, u32 value)  	return ret;  } -static void ar5523_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +static void ar5523_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +			 u32 queues, bool drop)  {  	struct ar5523 *ar = hw->priv; @@ -1762,9 +1762,10 @@ static struct usb_device_id ar5523_id_table[] = {  	AR5523_DEVICE_UX(0x2001, 0x3a00),	/* Dlink / DWLAG132 */  	AR5523_DEVICE_UG(0x2001, 0x3a02),	/* Dlink / DWLG132 */  	AR5523_DEVICE_UX(0x2001, 0x3a04),	/* Dlink / DWLAG122 */ +	AR5523_DEVICE_UG(0x07d1, 0x3a07),	/* D-Link / WUA-2340 rev A1 */  	AR5523_DEVICE_UG(0x1690, 0x0712),	/* Gigaset / AR5523 */  	AR5523_DEVICE_UG(0x1690, 0x0710),	/* Gigaset / SMCWUSBTG */ -	AR5523_DEVICE_UG(0x129b, 0x160c),	/* Gigaset / USB stick 108 +	AR5523_DEVICE_UG(0x129b, 0x160b),	/* Gigaset / USB stick 108  						   (CyberTAN Technology) */  	AR5523_DEVICE_UG(0x16ab, 0x7801),	/* Globalsun / AR5523_1 */  	AR5523_DEVICE_UX(0x16ab, 0x7811),	/* Globalsun / AR5523_2 */ diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index e0ba7cd1425..a889fd66fc6 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -17,6 +17,7 @@  #ifndef ATH_H  #define ATH_H +#include <linux/etherdevice.h>  #include <linux/skbuff.h>  #include <linux/if_ether.h>  #include <linux/spinlock.h> @@ -55,6 +56,15 @@ enum ath_device_state {  	ATH_HW_INITIALIZED,  }; +enum ath_op_flags { +	ATH_OP_INVALID, +	ATH_OP_BEACONS, +	ATH_OP_ANI_RUN, +	ATH_OP_PRIM_STA_VIF, +	ATH_OP_HW_RESET, +	ATH_OP_SCANNING, +}; +  enum ath_bus_type {  	ATH_PCI,  	ATH_AHB, @@ -62,7 +72,7 @@ enum ath_bus_type {  };  struct reg_dmn_pair_mapping { -	u16 regDmnEnum; +	u16 reg_domain;  	u16 reg_5ghz_ctl;  	u16 reg_2ghz_ctl;  }; @@ -129,6 +139,7 @@ struct ath_common {  	struct ieee80211_hw *hw;  	int debug_mask;  	enum ath_device_state state; +	unsigned long op_flags;  	struct ath_ani ani; @@ -160,11 +171,15 @@ struct ath_common {  	bool btcoex_enabled;  	bool disable_ani;  	bool bt_ant_diversity; + +	int last_rssi; +	struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];  };  struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,  				u32 len,  				gfp_t gfp_mask); +bool ath_is_mybeacon(struct ath_common *common, struct ieee80211_hdr *hdr);  void ath_hw_setbssidmask(struct ath_common *common);  void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key); diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig index 82e8088ca9b..a6f5285235a 100644 --- a/drivers/net/wireless/ath/ath10k/Kconfig +++ b/drivers/net/wireless/ath/ath10k/Kconfig @@ -37,3 +37,10 @@ config ATH10K_TRACING  	---help---  	  Select this to ath10k use tracing infrastructure. +config ATH10K_DFS_CERTIFIED +	bool "Atheros DFS support for certified platforms" +	depends on ATH10K && CFG80211_CERTIFICATION_ONUS +	default n +	---help--- +	This option enables DFS support for initiating radiation on +	ath10k. diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c index 744da6d1c40..17d221abd58 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.c +++ b/drivers/net/wireless/ath/ath10k/bmi.c @@ -22,7 +22,8 @@  void ath10k_bmi_start(struct ath10k *ar)  { -	ath10k_dbg(ATH10K_DBG_CORE, "BMI started\n"); +	ath10k_dbg(ATH10K_DBG_BMI, "bmi start\n"); +  	ar->bmi.done_sent = false;  } @@ -32,8 +33,10 @@ int ath10k_bmi_done(struct ath10k *ar)  	u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.done);  	int ret; +	ath10k_dbg(ATH10K_DBG_BMI, "bmi done\n"); +  	if (ar->bmi.done_sent) { -		ath10k_dbg(ATH10K_DBG_CORE, "%s skipped\n", __func__); +		ath10k_dbg(ATH10K_DBG_BMI, "bmi skipped\n");  		return 0;  	} @@ -46,7 +49,6 @@ int ath10k_bmi_done(struct ath10k *ar)  		return ret;  	} -	ath10k_dbg(ATH10K_DBG_CORE, "BMI done\n");  	return 0;  } @@ -59,6 +61,8 @@ int ath10k_bmi_get_target_info(struct ath10k *ar,  	u32 resplen = sizeof(resp.get_target_info);  	int ret; +	ath10k_dbg(ATH10K_DBG_BMI, "bmi get target info\n"); +  	if (ar->bmi.done_sent) {  		ath10k_warn("BMI Get Target Info Command disallowed\n");  		return -EBUSY; @@ -80,6 +84,7 @@ int ath10k_bmi_get_target_info(struct ath10k *ar,  	target_info->version = __le32_to_cpu(resp.get_target_info.version);  	target_info->type    = __le32_to_cpu(resp.get_target_info.type); +  	return 0;  } @@ -92,15 +97,14 @@ int ath10k_bmi_read_memory(struct ath10k *ar,  	u32 rxlen;  	int ret; +	ath10k_dbg(ATH10K_DBG_BMI, "bmi read address 0x%x length %d\n", +		   address, length); +  	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); @@ -133,15 +137,14 @@ int ath10k_bmi_write_memory(struct ath10k *ar,  	u32 txlen;  	int ret; +	ath10k_dbg(ATH10K_DBG_BMI, "bmi write address 0x%x length %d\n", +		   address, length); +  	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); @@ -172,7 +175,7 @@ int ath10k_bmi_write_memory(struct ath10k *ar,  	return 0;  } -int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param) +int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result)  {  	struct bmi_cmd cmd;  	union bmi_resp resp; @@ -180,18 +183,17 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param)  	u32 resplen = sizeof(resp.execute);  	int ret; +	ath10k_dbg(ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n", +		   address, param); +  	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); +	cmd.execute.param = __cpu_to_le32(param);  	ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);  	if (ret) { @@ -202,10 +204,13 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param)  	if (resplen < sizeof(resp.execute)) {  		ath10k_warn("invalid execute response length (%d)\n",  			    resplen); -		return ret; +		return -EIO;  	} -	*param = __le32_to_cpu(resp.execute.result); +	*result = __le32_to_cpu(resp.execute.result); + +	ath10k_dbg(ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result); +  	return 0;  } @@ -216,6 +221,9 @@ int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length)  	u32 txlen;  	int ret; +	ath10k_dbg(ATH10K_DBG_BMI, "bmi lz data buffer 0x%p length %d\n", +		   buffer, length); +  	if (ar->bmi.done_sent) {  		ath10k_warn("command disallowed\n");  		return -EBUSY; @@ -250,6 +258,9 @@ int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address)  	u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.lz_start);  	int ret; +	ath10k_dbg(ATH10K_DBG_BMI, "bmi lz stream start address 0x%x\n", +		   address); +  	if (ar->bmi.done_sent) {  		ath10k_warn("command disallowed\n");  		return -EBUSY; @@ -275,6 +286,10 @@ int ath10k_bmi_fast_download(struct ath10k *ar,  	u32 trailer_len = length - head_len;  	int ret; +	ath10k_dbg(ATH10K_DBG_BMI, +		   "bmi fast download address 0x%x buffer 0x%p length %d\n", +		   address, buffer, length); +  	ret = ath10k_bmi_lz_stream_start(ar, address);  	if (ret)  		return ret; diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h index 8d81ce1cec2..111ab701465 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.h +++ b/drivers/net/wireless/ath/ath10k/bmi.h @@ -201,7 +201,8 @@ int ath10k_bmi_write_memory(struct ath10k *ar, u32 address,  									\  		addr = host_interest_item_address(HI_ITEM(item));	\  		ret = ath10k_bmi_read_memory(ar, addr, (u8 *)&tmp, 4); \ -		*val = __le32_to_cpu(tmp);				\ +		if (!ret)						\ +			*val = __le32_to_cpu(tmp);			\  		ret;							\  	 }) @@ -217,7 +218,7 @@ int ath10k_bmi_write_memory(struct ath10k *ar, u32 address,  		ret;							\  	}) -int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param); +int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result);  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, diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index f8b969f518f..d185dc0cd12 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -76,36 +76,7 @@ static inline void ath10k_ce_src_ring_write_index_set(struct ath10k *ar,  						      u32 ce_ctrl_addr,  						      unsigned int n)  { -	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	void __iomem *indicator_addr; - -	if (!test_bit(ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND, ar_pci->features)) { -		ath10k_pci_write32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS, n); -		return; -	} - -	/* workaround for QCA988x_1.0 HW CE */ -	indicator_addr = ar_pci->mem + ce_ctrl_addr + DST_WATERMARK_ADDRESS; - -	if (ce_ctrl_addr == ath10k_ce_base_address(CDC_WAR_DATA_CE)) { -		iowrite32((CDC_WAR_MAGIC_STR | n), indicator_addr); -	} else { -		unsigned long irq_flags; -		local_irq_save(irq_flags); -		iowrite32(1, indicator_addr); - -		/* -		 * PCIE write waits for ACK in IPQ8K, there is no -		 * need to read back value. -		 */ -		(void)ioread32(indicator_addr); -		(void)ioread32(indicator_addr); /* conservative */ - -		ath10k_pci_write32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS, n); - -		iowrite32(0, indicator_addr); -		local_irq_restore(irq_flags); -	} +	ath10k_pci_write32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS, n);  }  static inline u32 ath10k_ce_src_ring_write_index_get(struct ath10k *ar, @@ -272,6 +243,16 @@ static inline void ath10k_ce_error_intr_enable(struct ath10k *ar,  			   misc_ie_addr | CE_ERROR_MASK);  } +static inline void ath10k_ce_error_intr_disable(struct ath10k *ar, +						u32 ce_ctrl_addr) +{ +	u32 misc_ie_addr = ath10k_pci_read32(ar, +					     ce_ctrl_addr + MISC_IE_ADDRESS); + +	ath10k_pci_write32(ar, ce_ctrl_addr + MISC_IE_ADDRESS, +			   misc_ie_addr & ~CE_ERROR_MASK); +} +  static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar,  						     u32 ce_ctrl_addr,  						     unsigned int mask) @@ -285,15 +266,15 @@ static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar,   * ath10k_ce_sendlist_send.   * The caller takes responsibility for any needed locking.   */ -static int ath10k_ce_send_nolock(struct ce_state *ce_state, -				 void *per_transfer_context, -				 u32 buffer, -				 unsigned int nbytes, -				 unsigned int transfer_id, -				 unsigned int flags) +int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, +			  void *per_transfer_context, +			  u32 buffer, +			  unsigned int nbytes, +			  unsigned int transfer_id, +			  unsigned int flags)  {  	struct ath10k *ar = ce_state->ar; -	struct ce_ring_state *src_ring = ce_state->src_ring; +	struct ath10k_ce_ring *src_ring = ce_state->src_ring;  	struct ce_desc *desc, *sdesc;  	unsigned int nentries_mask = src_ring->nentries_mask;  	unsigned int sw_index = src_ring->sw_index; @@ -306,11 +287,13 @@ static int ath10k_ce_send_nolock(struct ce_state *ce_state,  		ath10k_warn("%s: send more we can (nbytes: %d, max: %d)\n",  			    __func__, nbytes, ce_state->src_sz_max); -	ath10k_pci_wake(ar); +	ret = ath10k_pci_wake(ar); +	if (ret) +		return ret;  	if (unlikely(CE_RING_DELTA(nentries_mask,  				   write_index, sw_index - 1) <= 0)) { -		ret = -EIO; +		ret = -ENOSR;  		goto exit;  	} @@ -346,7 +329,34 @@ exit:  	return ret;  } -int ath10k_ce_send(struct ce_state *ce_state, +void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe) +{ +	struct ath10k *ar = pipe->ar; +	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); +	struct ath10k_ce_ring *src_ring = pipe->src_ring; +	u32 ctrl_addr = pipe->ctrl_addr; + +	lockdep_assert_held(&ar_pci->ce_lock); + +	/* +	 * This function must be called only if there is an incomplete +	 * scatter-gather transfer (before index register is updated) +	 * that needs to be cleaned up. +	 */ +	if (WARN_ON_ONCE(src_ring->write_index == src_ring->sw_index)) +		return; + +	if (WARN_ON_ONCE(src_ring->write_index == +			 ath10k_ce_src_ring_write_index_get(ar, ctrl_addr))) +		return; + +	src_ring->write_index--; +	src_ring->write_index &= src_ring->nentries_mask; + +	src_ring->per_transfer_context[src_ring->write_index] = NULL; +} + +int ath10k_ce_send(struct ath10k_ce_pipe *ce_state,  		   void *per_transfer_context,  		   u32 buffer,  		   unsigned int nbytes, @@ -365,77 +375,26 @@ int ath10k_ce_send(struct ce_state *ce_state,  	return ret;  } -void ath10k_ce_sendlist_buf_add(struct ce_sendlist *sendlist, u32 buffer, -				unsigned int nbytes, u32 flags) -{ -	unsigned int num_items = sendlist->num_items; -	struct ce_sendlist_item *item; - -	item = &sendlist->item[num_items]; -	item->data = buffer; -	item->u.nbytes = nbytes; -	item->flags = flags; -	sendlist->num_items++; -} - -int ath10k_ce_sendlist_send(struct ce_state *ce_state, -			    void *per_transfer_context, -			    struct ce_sendlist *sendlist, -			    unsigned int transfer_id) +int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe)  { -	struct ce_ring_state *src_ring = ce_state->src_ring; -	struct ce_sendlist_item *item; -	struct ath10k *ar = ce_state->ar; +	struct ath10k *ar = pipe->ar;  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	unsigned int nentries_mask = src_ring->nentries_mask; -	unsigned int num_items = sendlist->num_items; -	unsigned int sw_index; -	unsigned int write_index; -	int i, delta, ret = -ENOMEM; +	int delta;  	spin_lock_bh(&ar_pci->ce_lock); - -	sw_index = src_ring->sw_index; -	write_index = src_ring->write_index; - -	delta = CE_RING_DELTA(nentries_mask, write_index, sw_index - 1); - -	if (delta >= num_items) { -		/* -		 * Handle all but the last item uniformly. -		 */ -		for (i = 0; i < num_items - 1; i++) { -			item = &sendlist->item[i]; -			ret = ath10k_ce_send_nolock(ce_state, -						    CE_SENDLIST_ITEM_CTXT, -						    (u32) item->data, -						    item->u.nbytes, transfer_id, -						    item->flags | -						    CE_SEND_FLAG_GATHER); -			if (ret) -				ath10k_warn("CE send failed for item: %d\n", i); -		} -		/* -		 * Provide valid context pointer for final item. -		 */ -		item = &sendlist->item[i]; -		ret = ath10k_ce_send_nolock(ce_state, per_transfer_context, -					    (u32) item->data, item->u.nbytes, -					    transfer_id, item->flags); -		if (ret) -			ath10k_warn("CE send failed for last item: %d\n", i); -	} - +	delta = CE_RING_DELTA(pipe->src_ring->nentries_mask, +			      pipe->src_ring->write_index, +			      pipe->src_ring->sw_index - 1);  	spin_unlock_bh(&ar_pci->ce_lock); -	return ret; +	return delta;  } -int ath10k_ce_recv_buf_enqueue(struct ce_state *ce_state, +int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state,  			       void *per_recv_context,  			       u32 buffer)  { -	struct ce_ring_state *dest_ring = ce_state->dest_ring; +	struct ath10k_ce_ring *dest_ring = ce_state->dest_ring;  	u32 ctrl_addr = ce_state->ctrl_addr;  	struct ath10k *ar = ce_state->ar;  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); @@ -448,7 +407,9 @@ int ath10k_ce_recv_buf_enqueue(struct ce_state *ce_state,  	write_index = dest_ring->write_index;  	sw_index = dest_ring->sw_index; -	ath10k_pci_wake(ar); +	ret = ath10k_pci_wake(ar); +	if (ret) +		goto out;  	if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) > 0) {  		struct ce_desc *base = dest_ring->base_addr_owner_space; @@ -470,6 +431,8 @@ int ath10k_ce_recv_buf_enqueue(struct ce_state *ce_state,  		ret = -EIO;  	}  	ath10k_pci_sleep(ar); + +out:  	spin_unlock_bh(&ar_pci->ce_lock);  	return ret; @@ -479,14 +442,14 @@ int ath10k_ce_recv_buf_enqueue(struct ce_state *ce_state,   * Guts of ath10k_ce_completed_recv_next.   * The caller takes responsibility for any necessary locking.   */ -static int ath10k_ce_completed_recv_next_nolock(struct ce_state *ce_state, +static int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state,  						void **per_transfer_contextp,  						u32 *bufferp,  						unsigned int *nbytesp,  						unsigned int *transfer_idp,  						unsigned int *flagsp)  { -	struct ce_ring_state *dest_ring = ce_state->dest_ring; +	struct ath10k_ce_ring *dest_ring = ce_state->dest_ring;  	unsigned int nentries_mask = dest_ring->nentries_mask;  	unsigned int sw_index = dest_ring->sw_index; @@ -535,7 +498,7 @@ static int ath10k_ce_completed_recv_next_nolock(struct ce_state *ce_state,  	return 0;  } -int ath10k_ce_completed_recv_next(struct ce_state *ce_state, +int ath10k_ce_completed_recv_next(struct ath10k_ce_pipe *ce_state,  				  void **per_transfer_contextp,  				  u32 *bufferp,  				  unsigned int *nbytesp, @@ -556,11 +519,11 @@ int ath10k_ce_completed_recv_next(struct ce_state *ce_state,  	return ret;  } -int ath10k_ce_revoke_recv_next(struct ce_state *ce_state, +int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state,  			       void **per_transfer_contextp,  			       u32 *bufferp)  { -	struct ce_ring_state *dest_ring; +	struct ath10k_ce_ring *dest_ring;  	unsigned int nentries_mask;  	unsigned int sw_index;  	unsigned int write_index; @@ -612,19 +575,20 @@ int ath10k_ce_revoke_recv_next(struct ce_state *ce_state,   * Guts of ath10k_ce_completed_send_next.   * The caller takes responsibility for any necessary locking.   */ -static int ath10k_ce_completed_send_next_nolock(struct ce_state *ce_state, +static int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,  						void **per_transfer_contextp,  						u32 *bufferp,  						unsigned int *nbytesp,  						unsigned int *transfer_idp)  { -	struct ce_ring_state *src_ring = ce_state->src_ring; +	struct ath10k_ce_ring *src_ring = ce_state->src_ring;  	u32 ctrl_addr = ce_state->ctrl_addr;  	struct ath10k *ar = ce_state->ar;  	unsigned int nentries_mask = src_ring->nentries_mask;  	unsigned int sw_index = src_ring->sw_index; +	struct ce_desc *sdesc, *sbase;  	unsigned int read_index; -	int ret = -EIO; +	int ret;  	if (src_ring->hw_index == sw_index) {  		/* @@ -634,48 +598,54 @@ static int ath10k_ce_completed_send_next_nolock(struct ce_state *ce_state,  		 * the SW has really caught up to the HW, or if the cached  		 * value of the HW index has become stale.  		 */ -		ath10k_pci_wake(ar); + +		ret = ath10k_pci_wake(ar); +		if (ret) +			return ret; +  		src_ring->hw_index =  			ath10k_ce_src_ring_read_index_get(ar, ctrl_addr);  		src_ring->hw_index &= nentries_mask; +  		ath10k_pci_sleep(ar);  	} +  	read_index = src_ring->hw_index; -	if ((read_index != sw_index) && (read_index != 0xffffffff)) { -		struct ce_desc *sbase = src_ring->shadow_base; -		struct ce_desc *sdesc = CE_SRC_RING_TO_DESC(sbase, sw_index); +	if ((read_index == sw_index) || (read_index == 0xffffffff)) +		return -EIO; -		/* Return data from completed source descriptor */ -		*bufferp = __le32_to_cpu(sdesc->addr); -		*nbytesp = __le16_to_cpu(sdesc->nbytes); -		*transfer_idp = MS(__le16_to_cpu(sdesc->flags), -						CE_DESC_FLAGS_META_DATA); +	sbase = src_ring->shadow_base; +	sdesc = CE_SRC_RING_TO_DESC(sbase, sw_index); -		if (per_transfer_contextp) -			*per_transfer_contextp = -				src_ring->per_transfer_context[sw_index]; +	/* Return data from completed source descriptor */ +	*bufferp = __le32_to_cpu(sdesc->addr); +	*nbytesp = __le16_to_cpu(sdesc->nbytes); +	*transfer_idp = MS(__le16_to_cpu(sdesc->flags), +			   CE_DESC_FLAGS_META_DATA); -		/* sanity */ -		src_ring->per_transfer_context[sw_index] = NULL; +	if (per_transfer_contextp) +		*per_transfer_contextp = +			src_ring->per_transfer_context[sw_index]; -		/* Update sw_index */ -		sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); -		src_ring->sw_index = sw_index; -		ret = 0; -	} +	/* sanity */ +	src_ring->per_transfer_context[sw_index] = NULL; -	return ret; +	/* Update sw_index */ +	sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); +	src_ring->sw_index = sw_index; + +	return 0;  }  /* NB: Modeled after ath10k_ce_completed_send_next */ -int ath10k_ce_cancel_send_next(struct ce_state *ce_state, +int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state,  			       void **per_transfer_contextp,  			       u32 *bufferp,  			       unsigned int *nbytesp,  			       unsigned int *transfer_idp)  { -	struct ce_ring_state *src_ring; +	struct ath10k_ce_ring *src_ring;  	unsigned int nentries_mask;  	unsigned int sw_index;  	unsigned int write_index; @@ -727,7 +697,7 @@ int ath10k_ce_cancel_send_next(struct ce_state *ce_state,  	return ret;  } -int ath10k_ce_completed_send_next(struct ce_state *ce_state, +int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state,  				  void **per_transfer_contextp,  				  u32 *bufferp,  				  unsigned int *nbytesp, @@ -756,53 +726,29 @@ int ath10k_ce_completed_send_next(struct ce_state *ce_state,  void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id)  {  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	struct ce_state *ce_state = ar_pci->ce_id_to_state[ce_id]; +	struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];  	u32 ctrl_addr = ce_state->ctrl_addr; -	void *transfer_context; -	u32 buf; -	unsigned int nbytes; -	unsigned int id; -	unsigned int flags; +	int ret; + +	ret = ath10k_pci_wake(ar); +	if (ret) +		return; -	ath10k_pci_wake(ar);  	spin_lock_bh(&ar_pci->ce_lock);  	/* Clear the copy-complete interrupts that will be handled here. */  	ath10k_ce_engine_int_status_clear(ar, ctrl_addr,  					  HOST_IS_COPY_COMPLETE_MASK); -	if (ce_state->recv_cb) { -		/* -		 * Pop completed recv buffers and call the registered -		 * recv callback for each -		 */ -		while (ath10k_ce_completed_recv_next_nolock(ce_state, -							    &transfer_context, -							    &buf, &nbytes, -							    &id, &flags) == 0) { -			spin_unlock_bh(&ar_pci->ce_lock); -			ce_state->recv_cb(ce_state, transfer_context, buf, -					  nbytes, id, flags); -			spin_lock_bh(&ar_pci->ce_lock); -		} -	} +	spin_unlock_bh(&ar_pci->ce_lock); -	if (ce_state->send_cb) { -		/* -		 * Pop completed send buffers and call the registered -		 * send callback for each -		 */ -		while (ath10k_ce_completed_send_next_nolock(ce_state, -							    &transfer_context, -							    &buf, -							    &nbytes, -							    &id) == 0) { -			spin_unlock_bh(&ar_pci->ce_lock); -			ce_state->send_cb(ce_state, transfer_context, -					  buf, nbytes, id); -			spin_lock_bh(&ar_pci->ce_lock); -		} -	} +	if (ce_state->recv_cb) +		ce_state->recv_cb(ce_state); + +	if (ce_state->send_cb) +		ce_state->send_cb(ce_state); + +	spin_lock_bh(&ar_pci->ce_lock);  	/*  	 * Misc CE interrupts are not being handled, but still need @@ -822,14 +768,16 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id)  void ath10k_ce_per_engine_service_any(struct ath10k *ar)  { -	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	int ce_id; +	int ce_id, ret;  	u32 intr_summary; -	ath10k_pci_wake(ar); +	ret = ath10k_pci_wake(ar); +	if (ret) +		return; +  	intr_summary = CE_INTERRUPT_SUMMARY(ar); -	for (ce_id = 0; intr_summary && (ce_id < ar_pci->ce_count); ce_id++) { +	for (ce_id = 0; intr_summary && (ce_id < CE_COUNT); ce_id++) {  		if (intr_summary & (1 << ce_id))  			intr_summary &= ~(1 << ce_id);  		else @@ -849,13 +797,16 @@ void ath10k_ce_per_engine_service_any(struct ath10k *ar)   *   * Called with ce_lock held.   */ -static void ath10k_ce_per_engine_handler_adjust(struct ce_state *ce_state, +static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state,  						int disable_copy_compl_intr)  {  	u32 ctrl_addr = ce_state->ctrl_addr;  	struct ath10k *ar = ce_state->ar; +	int ret; -	ath10k_pci_wake(ar); +	ret = ath10k_pci_wake(ar); +	if (ret) +		return;  	if ((!disable_copy_compl_intr) &&  	    (ce_state->send_cb || ce_state->recv_cb)) @@ -868,27 +819,29 @@ static void ath10k_ce_per_engine_handler_adjust(struct ce_state *ce_state,  	ath10k_pci_sleep(ar);  } -void ath10k_ce_disable_interrupts(struct ath10k *ar) +int ath10k_ce_disable_interrupts(struct ath10k *ar)  { -	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	int ce_id; +	int ce_id, ret; -	ath10k_pci_wake(ar); -	for (ce_id = 0; ce_id < ar_pci->ce_count; ce_id++) { -		struct ce_state *ce_state = ar_pci->ce_id_to_state[ce_id]; -		u32 ctrl_addr = ce_state->ctrl_addr; +	ret = ath10k_pci_wake(ar); +	if (ret) +		return ret; + +	for (ce_id = 0; ce_id < CE_COUNT; ce_id++) { +		u32 ctrl_addr = ath10k_ce_base_address(ce_id);  		ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr); +		ath10k_ce_error_intr_disable(ar, ctrl_addr); +		ath10k_ce_watermark_intr_disable(ar, ctrl_addr);  	} +  	ath10k_pci_sleep(ar); + +	return 0;  } -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), +void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state, +				void (*send_cb)(struct ath10k_ce_pipe *),  				int disable_interrupts)  {  	struct ath10k *ar = ce_state->ar; @@ -900,13 +853,8 @@ void ath10k_ce_send_cb_register(struct ce_state *ce_state,  	spin_unlock_bh(&ar_pci->ce_lock);  } -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)) +void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state, +				void (*recv_cb)(struct ath10k_ce_pipe *))  {  	struct ath10k *ar = ce_state->ar;  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); @@ -919,37 +867,18 @@ void ath10k_ce_recv_cb_register(struct ce_state *ce_state,  static int ath10k_ce_init_src_ring(struct ath10k *ar,  				   unsigned int ce_id, -				   struct ce_state *ce_state,  				   const struct ce_attr *attr)  {  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	struct ce_ring_state *src_ring; -	unsigned int nentries = attr->src_nentries; -	unsigned int ce_nbytes; -	u32 ctrl_addr = ath10k_ce_base_address(ce_id); -	dma_addr_t base_addr; -	char *ptr; - -	nentries = roundup_pow_of_two(nentries); - -	if (ce_state->src_ring) { -		WARN_ON(ce_state->src_ring->nentries != nentries); -		return 0; -	} - -	ce_nbytes = sizeof(struct ce_ring_state) + (nentries * sizeof(void *)); -	ptr = kzalloc(ce_nbytes, GFP_KERNEL); -	if (ptr == NULL) -		return -ENOMEM; +	struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; +	struct ath10k_ce_ring *src_ring = ce_state->src_ring; +	u32 nentries, ctrl_addr = ath10k_ce_base_address(ce_id); -	ce_state->src_ring = (struct ce_ring_state *)ptr; -	src_ring = ce_state->src_ring; +	nentries = roundup_pow_of_two(attr->src_nentries); -	ptr += sizeof(struct ce_ring_state); -	src_ring->nentries = nentries; -	src_ring->nentries_mask = nentries - 1; +	memset(src_ring->per_transfer_context, 0, +	       nentries * sizeof(*src_ring->per_transfer_context)); -	ath10k_pci_wake(ar);  	src_ring->sw_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr);  	src_ring->sw_index &= src_ring->nentries_mask;  	src_ring->hw_index = src_ring->sw_index; @@ -957,19 +886,90 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar,  	src_ring->write_index =  		ath10k_ce_src_ring_write_index_get(ar, ctrl_addr);  	src_ring->write_index &= src_ring->nentries_mask; -	ath10k_pci_sleep(ar); -	src_ring->per_transfer_context = (void **)ptr; +	ath10k_ce_src_ring_base_addr_set(ar, ctrl_addr, +					 src_ring->base_addr_ce_space); +	ath10k_ce_src_ring_size_set(ar, ctrl_addr, nentries); +	ath10k_ce_src_ring_dmax_set(ar, ctrl_addr, attr->src_sz_max); +	ath10k_ce_src_ring_byte_swap_set(ar, ctrl_addr, 0); +	ath10k_ce_src_ring_lowmark_set(ar, ctrl_addr, 0); +	ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, nentries); + +	ath10k_dbg(ATH10K_DBG_BOOT, +		   "boot init ce src ring id %d entries %d base_addr %p\n", +		   ce_id, nentries, src_ring->base_addr_owner_space); + +	return 0; +} + +static int ath10k_ce_init_dest_ring(struct ath10k *ar, +				    unsigned int ce_id, +				    const struct ce_attr *attr) +{ +	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); +	struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; +	struct ath10k_ce_ring *dest_ring = ce_state->dest_ring; +	u32 nentries, ctrl_addr = ath10k_ce_base_address(ce_id); + +	nentries = roundup_pow_of_two(attr->dest_nentries); + +	memset(dest_ring->per_transfer_context, 0, +	       nentries * sizeof(*dest_ring->per_transfer_context)); + +	dest_ring->sw_index = ath10k_ce_dest_ring_read_index_get(ar, ctrl_addr); +	dest_ring->sw_index &= dest_ring->nentries_mask; +	dest_ring->write_index = +		ath10k_ce_dest_ring_write_index_get(ar, ctrl_addr); +	dest_ring->write_index &= dest_ring->nentries_mask; + +	ath10k_ce_dest_ring_base_addr_set(ar, ctrl_addr, +					  dest_ring->base_addr_ce_space); +	ath10k_ce_dest_ring_size_set(ar, ctrl_addr, nentries); +	ath10k_ce_dest_ring_byte_swap_set(ar, ctrl_addr, 0); +	ath10k_ce_dest_ring_lowmark_set(ar, ctrl_addr, 0); +	ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, nentries); + +	ath10k_dbg(ATH10K_DBG_BOOT, +		   "boot ce dest ring id %d entries %d base_addr %p\n", +		   ce_id, nentries, dest_ring->base_addr_owner_space); + +	return 0; +} + +static struct ath10k_ce_ring * +ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id, +			 const struct ce_attr *attr) +{ +	struct ath10k_ce_ring *src_ring; +	u32 nentries = attr->src_nentries; +	dma_addr_t base_addr; + +	nentries = roundup_pow_of_two(nentries); + +	src_ring = kzalloc(sizeof(*src_ring) + +			   (nentries * +			    sizeof(*src_ring->per_transfer_context)), +			   GFP_KERNEL); +	if (src_ring == NULL) +		return ERR_PTR(-ENOMEM); + +	src_ring->nentries = nentries; +	src_ring->nentries_mask = nentries - 1;  	/*  	 * Legacy platforms that do not support cache  	 * coherent DMA are unsupported  	 */  	src_ring->base_addr_owner_space_unaligned = -		pci_alloc_consistent(ar_pci->pdev, -				     (nentries * sizeof(struct ce_desc) + -				      CE_DESC_RING_ALIGN), -				     &base_addr); +		dma_alloc_coherent(ar->dev, +				   (nentries * sizeof(struct ce_desc) + +				    CE_DESC_RING_ALIGN), +				   &base_addr, GFP_KERNEL); +	if (!src_ring->base_addr_owner_space_unaligned) { +		kfree(src_ring); +		return ERR_PTR(-ENOMEM); +	} +  	src_ring->base_addr_ce_space_unaligned = base_addr;  	src_ring->base_addr_owner_space = PTR_ALIGN( @@ -986,75 +986,57 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar,  	src_ring->shadow_base_unaligned =  		kmalloc((nentries * sizeof(struct ce_desc) +  			 CE_DESC_RING_ALIGN), GFP_KERNEL); +	if (!src_ring->shadow_base_unaligned) { +		dma_free_coherent(ar->dev, +				  (nentries * sizeof(struct ce_desc) + +				   CE_DESC_RING_ALIGN), +				  src_ring->base_addr_owner_space, +				  src_ring->base_addr_ce_space); +		kfree(src_ring); +		return ERR_PTR(-ENOMEM); +	}  	src_ring->shadow_base = PTR_ALIGN(  			src_ring->shadow_base_unaligned,  			CE_DESC_RING_ALIGN); -	ath10k_pci_wake(ar); -	ath10k_ce_src_ring_base_addr_set(ar, ctrl_addr, -					 src_ring->base_addr_ce_space); -	ath10k_ce_src_ring_size_set(ar, ctrl_addr, nentries); -	ath10k_ce_src_ring_dmax_set(ar, ctrl_addr, attr->src_sz_max); -	ath10k_ce_src_ring_byte_swap_set(ar, ctrl_addr, 0); -	ath10k_ce_src_ring_lowmark_set(ar, ctrl_addr, 0); -	ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, nentries); -	ath10k_pci_sleep(ar); - -	return 0; +	return src_ring;  } -static int ath10k_ce_init_dest_ring(struct ath10k *ar, -				    unsigned int ce_id, -				    struct ce_state *ce_state, -				    const struct ce_attr *attr) +static struct ath10k_ce_ring * +ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id, +			  const struct ce_attr *attr)  { -	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	struct ce_ring_state *dest_ring; -	unsigned int nentries = attr->dest_nentries; -	unsigned int ce_nbytes; -	u32 ctrl_addr = ath10k_ce_base_address(ce_id); +	struct ath10k_ce_ring *dest_ring; +	u32 nentries;  	dma_addr_t base_addr; -	char *ptr; - -	nentries = roundup_pow_of_two(nentries); - -	if (ce_state->dest_ring) { -		WARN_ON(ce_state->dest_ring->nentries != nentries); -		return 0; -	} -	ce_nbytes = sizeof(struct ce_ring_state) + (nentries * sizeof(void *)); -	ptr = kzalloc(ce_nbytes, GFP_KERNEL); -	if (ptr == NULL) -		return -ENOMEM; +	nentries = roundup_pow_of_two(attr->dest_nentries); -	ce_state->dest_ring = (struct ce_ring_state *)ptr; -	dest_ring = ce_state->dest_ring; +	dest_ring = kzalloc(sizeof(*dest_ring) + +			    (nentries * +			     sizeof(*dest_ring->per_transfer_context)), +			    GFP_KERNEL); +	if (dest_ring == NULL) +		return ERR_PTR(-ENOMEM); -	ptr += sizeof(struct ce_ring_state);  	dest_ring->nentries = nentries;  	dest_ring->nentries_mask = nentries - 1; -	ath10k_pci_wake(ar); -	dest_ring->sw_index = ath10k_ce_dest_ring_read_index_get(ar, ctrl_addr); -	dest_ring->sw_index &= dest_ring->nentries_mask; -	dest_ring->write_index = -		ath10k_ce_dest_ring_write_index_get(ar, ctrl_addr); -	dest_ring->write_index &= dest_ring->nentries_mask; -	ath10k_pci_sleep(ar); - -	dest_ring->per_transfer_context = (void **)ptr; -  	/*  	 * Legacy platforms that do not support cache  	 * coherent DMA are unsupported  	 */  	dest_ring->base_addr_owner_space_unaligned = -		pci_alloc_consistent(ar_pci->pdev, -				     (nentries * sizeof(struct ce_desc) + -				      CE_DESC_RING_ALIGN), -				     &base_addr); +		dma_alloc_coherent(ar->dev, +				   (nentries * sizeof(struct ce_desc) + +				    CE_DESC_RING_ALIGN), +				   &base_addr, GFP_KERNEL); +	if (!dest_ring->base_addr_owner_space_unaligned) { +		kfree(dest_ring); +		return ERR_PTR(-ENOMEM); +	} +  	dest_ring->base_addr_ce_space_unaligned = base_addr;  	/* @@ -1071,124 +1053,161 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar,  			dest_ring->base_addr_ce_space_unaligned,  			CE_DESC_RING_ALIGN); -	ath10k_pci_wake(ar); -	ath10k_ce_dest_ring_base_addr_set(ar, ctrl_addr, -					  dest_ring->base_addr_ce_space); -	ath10k_ce_dest_ring_size_set(ar, ctrl_addr, nentries); -	ath10k_ce_dest_ring_byte_swap_set(ar, ctrl_addr, 0); -	ath10k_ce_dest_ring_lowmark_set(ar, ctrl_addr, 0); -	ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, nentries); -	ath10k_pci_sleep(ar); - -	return 0; +	return dest_ring;  } -static struct ce_state *ath10k_ce_init_state(struct ath10k *ar, -					     unsigned int ce_id, -					     const struct ce_attr *attr) +/* + * Initialize a Copy Engine based on caller-supplied attributes. + * This may be called once to initialize both source and destination + * rings or it may be called twice for separate source and destination + * initialization. It may be that only one side or the other is + * initialized by software/firmware. + */ +int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id, +			const struct ce_attr *attr)  {  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	struct ce_state *ce_state = NULL; -	u32 ctrl_addr = ath10k_ce_base_address(ce_id); +	struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; +	int ret; + +	/* +	 * Make sure there's enough CE ringbuffer entries for HTT TX to avoid +	 * additional TX locking checks. +	 * +	 * For the lack of a better place do the check here. +	 */ +	BUILD_BUG_ON(2*TARGET_NUM_MSDU_DESC > +		     (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); +	BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC > +		     (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); + +	ret = ath10k_pci_wake(ar); +	if (ret) +		return ret;  	spin_lock_bh(&ar_pci->ce_lock); +	ce_state->ar = ar; +	ce_state->id = ce_id; +	ce_state->ctrl_addr = ath10k_ce_base_address(ce_id); +	ce_state->attr_flags = attr->flags; +	ce_state->src_sz_max = attr->src_sz_max; +	spin_unlock_bh(&ar_pci->ce_lock); -	if (!ar_pci->ce_id_to_state[ce_id]) { -		ce_state = kzalloc(sizeof(*ce_state), GFP_ATOMIC); -		if (ce_state == NULL) { -			spin_unlock_bh(&ar_pci->ce_lock); -			return NULL; +	if (attr->src_nentries) { +		ret = ath10k_ce_init_src_ring(ar, ce_id, attr); +		if (ret) { +			ath10k_err("Failed to initialize CE src ring for ID: %d (%d)\n", +				   ce_id, ret); +			goto out;  		} +	} -		ar_pci->ce_id_to_state[ce_id] = ce_state; -		ce_state->ar = ar; -		ce_state->id = ce_id; -		ce_state->ctrl_addr = ctrl_addr; -		ce_state->state = CE_RUNNING; -		/* Save attribute flags */ -		ce_state->attr_flags = attr->flags; -		ce_state->src_sz_max = attr->src_sz_max; +	if (attr->dest_nentries) { +		ret = ath10k_ce_init_dest_ring(ar, ce_id, attr); +		if (ret) { +			ath10k_err("Failed to initialize CE dest ring for ID: %d (%d)\n", +				   ce_id, ret); +			goto out; +		}  	} -	spin_unlock_bh(&ar_pci->ce_lock); +out: +	ath10k_pci_sleep(ar); +	return ret; +} + +static void ath10k_ce_deinit_src_ring(struct ath10k *ar, unsigned int ce_id) +{ +	u32 ctrl_addr = ath10k_ce_base_address(ce_id); -	return ce_state; +	ath10k_ce_src_ring_base_addr_set(ar, ctrl_addr, 0); +	ath10k_ce_src_ring_size_set(ar, ctrl_addr, 0); +	ath10k_ce_src_ring_dmax_set(ar, ctrl_addr, 0); +	ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, 0);  } -/* - * Initialize a Copy Engine based on caller-supplied attributes. - * This may be called once to initialize both source and destination - * rings or it may be called twice for separate source and destination - * initialization. It may be that only one side or the other is - * initialized by software/firmware. - */ -struct ce_state *ath10k_ce_init(struct ath10k *ar, -				unsigned int ce_id, -				const struct ce_attr *attr) +static void ath10k_ce_deinit_dest_ring(struct ath10k *ar, unsigned int ce_id)  { -	struct ce_state *ce_state;  	u32 ctrl_addr = ath10k_ce_base_address(ce_id); -	ce_state = ath10k_ce_init_state(ar, ce_id, attr); -	if (!ce_state) { -		ath10k_err("Failed to initialize CE state for ID: %d\n", ce_id); -		return NULL; -	} +	ath10k_ce_dest_ring_base_addr_set(ar, ctrl_addr, 0); +	ath10k_ce_dest_ring_size_set(ar, ctrl_addr, 0); +	ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, 0); +} + +void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id) +{ +	int ret; + +	ret = ath10k_pci_wake(ar); +	if (ret) +		return; + +	ath10k_ce_deinit_src_ring(ar, ce_id); +	ath10k_ce_deinit_dest_ring(ar, ce_id); + +	ath10k_pci_sleep(ar); +} + +int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, +			 const struct ce_attr *attr) +{ +	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); +	struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; +	int ret;  	if (attr->src_nentries) { -		if (ath10k_ce_init_src_ring(ar, ce_id, ce_state, attr)) { -			ath10k_err("Failed to initialize CE src ring for ID: %d\n", -				   ce_id); -			ath10k_ce_deinit(ce_state); -			return NULL; +		ce_state->src_ring = ath10k_ce_alloc_src_ring(ar, ce_id, attr); +		if (IS_ERR(ce_state->src_ring)) { +			ret = PTR_ERR(ce_state->src_ring); +			ath10k_err("failed to allocate copy engine source ring %d: %d\n", +				   ce_id, ret); +			ce_state->src_ring = NULL; +			return ret;  		}  	}  	if (attr->dest_nentries) { -		if (ath10k_ce_init_dest_ring(ar, ce_id, ce_state, attr)) { -			ath10k_err("Failed to initialize CE dest ring for ID: %d\n", -				   ce_id); -			ath10k_ce_deinit(ce_state); -			return NULL; +		ce_state->dest_ring = ath10k_ce_alloc_dest_ring(ar, ce_id, +								attr); +		if (IS_ERR(ce_state->dest_ring)) { +			ret = PTR_ERR(ce_state->dest_ring); +			ath10k_err("failed to allocate copy engine destination ring %d: %d\n", +				   ce_id, ret); +			ce_state->dest_ring = NULL; +			return ret;  		}  	} -	/* Enable CE error interrupts */ -	ath10k_pci_wake(ar); -	ath10k_ce_error_intr_enable(ar, ctrl_addr); -	ath10k_pci_sleep(ar); - -	return ce_state; +	return 0;  } -void ath10k_ce_deinit(struct ce_state *ce_state) +void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id)  { -	unsigned int ce_id = ce_state->id; -	struct ath10k *ar = ce_state->ar;  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - -	ce_state->state = CE_UNUSED; -	ar_pci->ce_id_to_state[ce_id] = NULL; +	struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];  	if (ce_state->src_ring) {  		kfree(ce_state->src_ring->shadow_base_unaligned); -		pci_free_consistent(ar_pci->pdev, -				    (ce_state->src_ring->nentries * -				     sizeof(struct ce_desc) + -				     CE_DESC_RING_ALIGN), -				    ce_state->src_ring->base_addr_owner_space, -				    ce_state->src_ring->base_addr_ce_space); +		dma_free_coherent(ar->dev, +				  (ce_state->src_ring->nentries * +				   sizeof(struct ce_desc) + +				   CE_DESC_RING_ALIGN), +				  ce_state->src_ring->base_addr_owner_space, +				  ce_state->src_ring->base_addr_ce_space);  		kfree(ce_state->src_ring);  	}  	if (ce_state->dest_ring) { -		pci_free_consistent(ar_pci->pdev, -				    (ce_state->dest_ring->nentries * -				     sizeof(struct ce_desc) + -				     CE_DESC_RING_ALIGN), -				    ce_state->dest_ring->base_addr_owner_space, -				    ce_state->dest_ring->base_addr_ce_space); +		dma_free_coherent(ar->dev, +				  (ce_state->dest_ring->nentries * +				   sizeof(struct ce_desc) + +				   CE_DESC_RING_ALIGN), +				  ce_state->dest_ring->base_addr_owner_space, +				  ce_state->dest_ring->base_addr_ce_space);  		kfree(ce_state->dest_ring);  	} -	kfree(ce_state); + +	ce_state->src_ring = NULL; +	ce_state->dest_ring = NULL;  } diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index c17f07c026f..7a5a36fc59c 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -23,11 +23,10 @@  /* Maximum number of Copy Engine's supported */  #define CE_COUNT_MAX 8 -#define CE_HTT_H2T_MSG_SRC_NENTRIES 2048 +#define CE_HTT_H2T_MSG_SRC_NENTRIES 4096  /* 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  /* @@ -36,16 +35,9 @@   * how to use copy engines.   */ -struct ce_state; +struct ath10k_ce_pipe; -/* 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 @@ -57,8 +49,7 @@ struct ce_desc {  	__le16 flags; /* %CE_DESC_FLAGS_ */  }; -/* Copy Engine Ring internal state */ -struct ce_ring_state { +struct ath10k_ce_ring {  	/* Number of entries in this ring; must be power of 2 */  	unsigned int nentries;  	unsigned int nentries_mask; @@ -113,52 +104,24 @@ struct ce_ring_state {  	void *shadow_base_unaligned;  	struct ce_desc *shadow_base; -	void **per_transfer_context; +	/* keep last */ +	void *per_transfer_context[0];  }; -/* Copy Engine internal state */ -struct ce_state { +struct ath10k_ce_pipe {  	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; -}; +	void (*send_cb)(struct ath10k_ce_pipe *); +	void (*recv_cb)(struct ath10k_ce_pipe *); -struct ce_sendlist { -	unsigned int num_items; -	struct ce_sendlist_item item[CE_SENDLIST_ITEMS_MAX]; +	unsigned int src_sz_max; +	struct ath10k_ce_ring *src_ring; +	struct ath10k_ce_ring *dest_ring;  };  /* Copy Engine settable attributes */ @@ -182,7 +145,7 @@ struct ce_attr;   *   * Implementation note: pushes 1 buffer to Source ring   */ -int ath10k_ce_send(struct ce_state *ce_state, +int ath10k_ce_send(struct ath10k_ce_pipe *ce_state,  		   void *per_transfer_send_context,  		   u32 buffer,  		   unsigned int nbytes, @@ -190,36 +153,20 @@ int ath10k_ce_send(struct ce_state *ce_state,  		   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); +int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, +			  void *per_transfer_context, +			  u32 buffer, +			  unsigned int nbytes, +			  unsigned int transfer_id, +			  unsigned int flags); -/* 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); +void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe); -/* - * 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); +void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state, +				void (*send_cb)(struct ath10k_ce_pipe *), +				int disable_interrupts); + +int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe);  /*==================Recv=======================*/ @@ -233,17 +180,12 @@ int ath10k_ce_sendlist_send(struct ce_state *ce_state,   *   * Implemenation note: Pushes a buffer to Dest ring.   */ -int ath10k_ce_recv_buf_enqueue(struct ce_state *ce_state, +int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *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)); +void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state, +				void (*recv_cb)(struct ath10k_ce_pipe *));  /* recv flags */  /* Data is byte-swapped */ @@ -253,7 +195,7 @@ void ath10k_ce_recv_cb_register(struct ce_state *ce_state,   * 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, +int ath10k_ce_completed_recv_next(struct ath10k_ce_pipe *ce_state,  				  void **per_transfer_contextp,  				  u32 *bufferp,  				  unsigned int *nbytesp, @@ -263,7 +205,7 @@ int ath10k_ce_completed_recv_next(struct ce_state *ce_state,   * 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, +int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state,  			   void **per_transfer_contextp,  			   u32 *bufferp,  			   unsigned int *nbytesp, @@ -271,10 +213,12 @@ int ath10k_ce_completed_send_next(struct ce_state *ce_state,  /*==================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); +int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id, +			const struct ce_attr *attr); +void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id); +int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, +			  const struct ce_attr *attr); +void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id);  /*==================CE Engine Shutdown=======================*/  /* @@ -282,7 +226,7 @@ struct ce_state *ath10k_ce_init(struct ath10k *ar,   * receive buffers.  Target DMA must be stopped before using   * this API.   */ -int ath10k_ce_revoke_recv_next(struct ce_state *ce_state, +int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state,  			       void **per_transfer_contextp,  			       u32 *bufferp); @@ -291,18 +235,16 @@ int ath10k_ce_revoke_recv_next(struct ce_state *ce_state,   * pending sends.  Target DMA must be stopped before using   * this API.   */ -int ath10k_ce_cancel_send_next(struct ce_state *ce_state, +int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *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); +int ath10k_ce_disable_interrupts(struct ath10k *ar);  /* ce_attr.flags values */  /* Use NonSnooping PCIe accesses? */ @@ -322,9 +264,6 @@ 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; @@ -336,21 +275,8 @@ struct ce_attr {  	/* #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 diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 7226c23b956..e6c56c5bb0f 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -39,17 +39,6 @@ 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, @@ -64,61 +53,9 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {  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; +	ath10k_dbg(ATH10K_DBG_BOOT, "boot suspend complete\n"); -	/* 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; +	complete(&ar->target_suspend);  }  static int ath10k_init_configure_target(struct ath10k *ar) @@ -200,8 +137,7 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar,  	return fw;  } -static int ath10k_push_board_ext_data(struct ath10k *ar, -				      const struct firmware *fw) +static int ath10k_push_board_ext_data(struct ath10k *ar)  {  	u32 board_data_size = QCA988X_BOARD_DATA_SZ;  	u32 board_ext_data_size = QCA988X_BOARD_EXT_DATA_SZ; @@ -214,21 +150,21 @@ static int ath10k_push_board_ext_data(struct ath10k *ar,  		return ret;  	} -	ath10k_dbg(ATH10K_DBG_CORE, -		   "ath10k: Board extended Data download addr: 0x%x\n", +	ath10k_dbg(ATH10K_DBG_BOOT, +		   "boot push board extended data 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)) { +	if (ar->board_len != (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); +			   ar->board_len, board_data_size, board_ext_data_size);  		return -EINVAL;  	}  	ret = ath10k_bmi_write_memory(ar, board_ext_data_addr, -				      fw->data + board_data_size, +				      ar->board_data + board_data_size,  				      board_ext_data_size);  	if (ret) {  		ath10k_err("could not write board ext data (%d)\n", ret); @@ -247,12 +183,11 @@ static int ath10k_push_board_ext_data(struct ath10k *ar,  static int ath10k_download_board_data(struct ath10k *ar)  { -	const struct firmware *fw = ar->board_data;  	u32 board_data_size = QCA988X_BOARD_DATA_SZ;  	u32 address;  	int ret; -	ret = ath10k_push_board_ext_data(ar, fw); +	ret = ath10k_push_board_ext_data(ar);  	if (ret) {  		ath10k_err("could not push board ext data (%d)\n", ret);  		goto exit; @@ -264,8 +199,9 @@ static int ath10k_download_board_data(struct ath10k *ar)  		goto exit;  	} -	ret = ath10k_bmi_write_memory(ar, address, fw->data, -				      min_t(u32, board_data_size, fw->size)); +	ret = ath10k_bmi_write_memory(ar, address, ar->board_data, +				      min_t(u32, board_data_size, +					    ar->board_len));  	if (ret) {  		ath10k_err("could not write board data (%d)\n", ret);  		goto exit; @@ -283,42 +219,51 @@ exit:  static int ath10k_download_and_run_otp(struct ath10k *ar)  { -	const struct firmware *fw = ar->otp; -	u32 address = ar->hw_params.patch_load_addr; -	u32 exec_param; +	u32 result, address = ar->hw_params.patch_load_addr;  	int ret;  	/* OTP is optional */ -	if (!ar->otp) +	if (!ar->otp_data || !ar->otp_len) { +		ath10k_warn("Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n", +			    ar->otp_data, ar->otp_len);  		return 0; +	} + +	ath10k_dbg(ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n", +		   address, ar->otp_len); -	ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size); +	ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len);  	if (ret) {  		ath10k_err("could not write otp (%d)\n", ret); -		goto exit; +		return ret;  	} -	exec_param = 0; -	ret = ath10k_bmi_execute(ar, address, &exec_param); +	ret = ath10k_bmi_execute(ar, address, 0, &result);  	if (ret) {  		ath10k_err("could not execute otp (%d)\n", ret); -		goto exit; +		return ret;  	} -exit: -	return ret; +	ath10k_dbg(ATH10K_DBG_BOOT, "boot otp execute result %d\n", result); + +	if (result != 0) { +		ath10k_err("otp calibration failed: %d", result); +		return -EINVAL; +	} + +	return 0;  }  static int ath10k_download_fw(struct ath10k *ar)  { -	const struct firmware *fw = ar->firmware;  	u32 address;  	int ret;  	address = ar->hw_params.patch_load_addr; -	ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size); +	ret = ath10k_bmi_fast_download(ar, address, ar->firmware_data, +				       ar->firmware_len);  	if (ret) {  		ath10k_err("could not write fw (%d)\n", ret);  		goto exit; @@ -330,8 +275,8 @@ exit:  static void ath10k_core_free_firmware_files(struct ath10k *ar)  { -	if (ar->board_data && !IS_ERR(ar->board_data)) -		release_firmware(ar->board_data); +	if (ar->board && !IS_ERR(ar->board)) +		release_firmware(ar->board);  	if (ar->otp && !IS_ERR(ar->otp))  		release_firmware(ar->otp); @@ -339,12 +284,20 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar)  	if (ar->firmware && !IS_ERR(ar->firmware))  		release_firmware(ar->firmware); +	ar->board = NULL;  	ar->board_data = NULL; +	ar->board_len = 0; +  	ar->otp = NULL; +	ar->otp_data = NULL; +	ar->otp_len = 0; +  	ar->firmware = NULL; +	ar->firmware_data = NULL; +	ar->firmware_len = 0;  } -static int ath10k_core_fetch_firmware_files(struct ath10k *ar) +static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)  {  	int ret = 0; @@ -358,15 +311,18 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)  		return -EINVAL;  	} -	ar->board_data = ath10k_fetch_fw_file(ar, -					      ar->hw_params.fw.dir, -					      ar->hw_params.fw.board); -	if (IS_ERR(ar->board_data)) { -		ret = PTR_ERR(ar->board_data); +	ar->board = ath10k_fetch_fw_file(ar, +					 ar->hw_params.fw.dir, +					 ar->hw_params.fw.board); +	if (IS_ERR(ar->board)) { +		ret = PTR_ERR(ar->board);  		ath10k_err("could not fetch board data (%d)\n", ret);  		goto err;  	} +	ar->board_data = ar->board->data; +	ar->board_len = ar->board->size; +  	ar->firmware = ath10k_fetch_fw_file(ar,  					    ar->hw_params.fw.dir,  					    ar->hw_params.fw.fw); @@ -376,6 +332,9 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)  		goto err;  	} +	ar->firmware_data = ar->firmware->data; +	ar->firmware_len = ar->firmware->size; +  	/* OTP may be undefined. If so, don't fetch it at all */  	if (ar->hw_params.fw.otp == NULL)  		return 0; @@ -389,6 +348,9 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)  		goto err;  	} +	ar->otp_data = ar->otp->data; +	ar->otp_len = ar->otp->size; +  	return 0;  err: @@ -396,21 +358,220 @@ err:  	return ret;  } +static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) +{ +	size_t magic_len, len, ie_len; +	int ie_id, i, index, bit, ret; +	struct ath10k_fw_ie *hdr; +	const u8 *data; +	__le32 *timestamp; + +	/* first fetch the firmware file (firmware-*.bin) */ +	ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name); +	if (IS_ERR(ar->firmware)) { +		ath10k_err("could not fetch firmware file '%s/%s': %ld\n", +			   ar->hw_params.fw.dir, name, PTR_ERR(ar->firmware)); +		return PTR_ERR(ar->firmware); +	} + +	data = ar->firmware->data; +	len = ar->firmware->size; + +	/* magic also includes the null byte, check that as well */ +	magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1; + +	if (len < magic_len) { +		ath10k_err("firmware file '%s/%s' too small to contain magic: %zu\n", +			   ar->hw_params.fw.dir, name, len); +		ret = -EINVAL; +		goto err; +	} + +	if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) { +		ath10k_err("invalid firmware magic\n"); +		ret = -EINVAL; +		goto err; +	} + +	/* jump over the padding */ +	magic_len = ALIGN(magic_len, 4); + +	len -= magic_len; +	data += magic_len; + +	/* loop elements */ +	while (len > sizeof(struct ath10k_fw_ie)) { +		hdr = (struct ath10k_fw_ie *)data; + +		ie_id = le32_to_cpu(hdr->id); +		ie_len = le32_to_cpu(hdr->len); + +		len -= sizeof(*hdr); +		data += sizeof(*hdr); + +		if (len < ie_len) { +			ath10k_err("invalid length for FW IE %d (%zu < %zu)\n", +				   ie_id, len, ie_len); +			ret = -EINVAL; +			goto err; +		} + +		switch (ie_id) { +		case ATH10K_FW_IE_FW_VERSION: +			if (ie_len > sizeof(ar->hw->wiphy->fw_version) - 1) +				break; + +			memcpy(ar->hw->wiphy->fw_version, data, ie_len); +			ar->hw->wiphy->fw_version[ie_len] = '\0'; + +			ath10k_dbg(ATH10K_DBG_BOOT, +				   "found fw version %s\n", +				    ar->hw->wiphy->fw_version); +			break; +		case ATH10K_FW_IE_TIMESTAMP: +			if (ie_len != sizeof(u32)) +				break; + +			timestamp = (__le32 *)data; + +			ath10k_dbg(ATH10K_DBG_BOOT, "found fw timestamp %d\n", +				   le32_to_cpup(timestamp)); +			break; +		case ATH10K_FW_IE_FEATURES: +			ath10k_dbg(ATH10K_DBG_BOOT, +				   "found firmware features ie (%zd B)\n", +				   ie_len); + +			for (i = 0; i < ATH10K_FW_FEATURE_COUNT; i++) { +				index = i / 8; +				bit = i % 8; + +				if (index == ie_len) +					break; + +				if (data[index] & (1 << bit)) { +					ath10k_dbg(ATH10K_DBG_BOOT, +						   "Enabling feature bit: %i\n", +						   i); +					__set_bit(i, ar->fw_features); +				} +			} + +			ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "", +					ar->fw_features, +					sizeof(ar->fw_features)); +			break; +		case ATH10K_FW_IE_FW_IMAGE: +			ath10k_dbg(ATH10K_DBG_BOOT, +				   "found fw image ie (%zd B)\n", +				   ie_len); + +			ar->firmware_data = data; +			ar->firmware_len = ie_len; + +			break; +		case ATH10K_FW_IE_OTP_IMAGE: +			ath10k_dbg(ATH10K_DBG_BOOT, +				   "found otp image ie (%zd B)\n", +				   ie_len); + +			ar->otp_data = data; +			ar->otp_len = ie_len; + +			break; +		default: +			ath10k_warn("Unknown FW IE: %u\n", +				    le32_to_cpu(hdr->id)); +			break; +		} + +		/* jump over the padding */ +		ie_len = ALIGN(ie_len, 4); + +		len -= ie_len; +		data += ie_len; +	} + +	if (!ar->firmware_data || !ar->firmware_len) { +		ath10k_warn("No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n", +			    ar->hw_params.fw.dir, name); +		ret = -ENOMEDIUM; +		goto err; +	} + +	/* now fetch the board file */ +	if (ar->hw_params.fw.board == NULL) { +		ath10k_err("board data file not defined"); +		ret = -EINVAL; +		goto err; +	} + +	ar->board = ath10k_fetch_fw_file(ar, +					 ar->hw_params.fw.dir, +					 ar->hw_params.fw.board); +	if (IS_ERR(ar->board)) { +		ret = PTR_ERR(ar->board); +		ath10k_err("could not fetch board data '%s/%s' (%d)\n", +			   ar->hw_params.fw.dir, ar->hw_params.fw.board, +			   ret); +		goto err; +	} + +	ar->board_data = ar->board->data; +	ar->board_len = ar->board->size; + +	return 0; + +err: +	ath10k_core_free_firmware_files(ar); +	return ret; +} + +static int ath10k_core_fetch_firmware_files(struct ath10k *ar) +{ +	int ret; + +	ar->fw_api = 2; +	ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); + +	ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API2_FILE); +	if (ret == 0) +		goto success; + +	ar->fw_api = 1; +	ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); + +	ret = ath10k_core_fetch_firmware_api_1(ar); +	if (ret) +		return ret; + +success: +	ath10k_dbg(ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api); + +	return 0; +} +  static int ath10k_init_download_firmware(struct ath10k *ar)  {  	int ret;  	ret = ath10k_download_board_data(ar); -	if (ret) +	if (ret) { +		ath10k_err("failed to download board data: %d\n", ret);  		return ret; +	}  	ret = ath10k_download_and_run_otp(ar); -	if (ret) +	if (ret) { +		ath10k_err("failed to run otp: %d\n", ret);  		return ret; +	}  	ret = ath10k_download_fw(ar); -	if (ret) +	if (ret) { +		ath10k_err("failed to download firmware: %d\n", ret);  		return ret; +	}  	return ret;  } @@ -429,10 +590,8 @@ static int ath10k_init_uart(struct ath10k *ar)  		return ret;  	} -	if (!uart_print) { -		ath10k_info("UART prints disabled\n"); +	if (!uart_print)  		return 0; -	}  	ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, 7);  	if (ret) { @@ -446,6 +605,13 @@ static int ath10k_init_uart(struct ath10k *ar)  		return ret;  	} +	/* Set the UART baud rate to 19200. */ +	ret = ath10k_bmi_write32(ar, hi_desired_baud_rate, 19200); +	if (ret) { +		ath10k_warn("could not set the baud rate (%d)\n", ret); +		return ret; +	} +  	ath10k_info("UART prints enabled\n");  	return 0;  } @@ -470,8 +636,8 @@ static int ath10k_init_hw_params(struct ath10k *ar)  	ar->hw_params = *hw_params; -	ath10k_info("Hardware name %s version 0x%x\n", -		    ar->hw_params.name, ar->target_version); +	ath10k_dbg(ATH10K_DBG_BOOT, "Hardware name %s version 0x%x\n", +		   ar->hw_params.name, ar->target_version);  	return 0;  } @@ -484,15 +650,19 @@ static void ath10k_core_restart(struct work_struct *work)  	switch (ar->state) {  	case ATH10K_STATE_ON: -		ath10k_halt(ar);  		ar->state = ATH10K_STATE_RESTARTING; +		del_timer_sync(&ar->scan.timeout); +		ath10k_reset_scan((unsigned long)ar);  		ieee80211_restart_hw(ar->hw);  		break;  	case ATH10K_STATE_OFF: -		/* this can happen if driver is being unloaded */ +		/* this can happen if driver is being unloaded +		 * or if the crash happens during FW probing */  		ath10k_warn("cannot restart a device that hasn't been started\n");  		break;  	case ATH10K_STATE_RESTARTING: +		/* hw restart might be requested from multiple places */ +		break;  	case ATH10K_STATE_RESTARTED:  		ar->state = ATH10K_STATE_WEDGED;  		/* fall through */ @@ -504,72 +674,12 @@ static void ath10k_core_restart(struct work_struct *work)  	mutex_unlock(&ar->conf_mutex);  } -struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, -				  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; - -	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); - -	INIT_WORK(&ar->restart_work, ath10k_core_restart); - -	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_start(struct ath10k *ar)  {  	int status; +	lockdep_assert_held(&ar->conf_mutex); +  	ath10k_bmi_start(ar);  	if (ath10k_init_configure_target(ar)) { @@ -604,51 +714,116 @@ int ath10k_core_start(struct ath10k *ar)  		goto err;  	} -	status = ath10k_htc_wait_target(&ar->htc); -	if (status) +	status = ath10k_htt_init(ar); +	if (status) { +		ath10k_err("failed to init htt: %d\n", status);  		goto err_wmi_detach; +	} -	status = ath10k_htt_attach(ar); +	status = ath10k_htt_tx_alloc(&ar->htt);  	if (status) { -		ath10k_err("could not attach htt (%d)\n", status); +		ath10k_err("failed to alloc htt tx: %d\n", status);  		goto err_wmi_detach;  	} -	status = ath10k_init_connect_htc(ar); -	if (status) -		goto err_htt_detach; +	status = ath10k_htt_rx_alloc(&ar->htt); +	if (status) { +		ath10k_err("failed to alloc htt rx: %d\n", status); +		goto err_htt_tx_detach; +	} -	ath10k_info("firmware %s booted\n", ar->hw->wiphy->fw_version); +	status = ath10k_hif_start(ar); +	if (status) { +		ath10k_err("could not start HIF: %d\n", status); +		goto err_htt_rx_detach; +	} -	status = ath10k_check_fw_version(ar); -	if (status) -		goto err_disconnect_htc; +	status = ath10k_htc_wait_target(&ar->htc); +	if (status) { +		ath10k_err("failed to connect to HTC: %d\n", status); +		goto err_hif_stop; +	} + +	status = ath10k_htt_connect(&ar->htt); +	if (status) { +		ath10k_err("failed to connect htt (%d)\n", status); +		goto err_hif_stop; +	} + +	status = ath10k_wmi_connect(ar); +	if (status) { +		ath10k_err("could not connect wmi: %d\n", status); +		goto err_hif_stop; +	} + +	status = ath10k_htc_start(&ar->htc); +	if (status) { +		ath10k_err("failed to start htc: %d\n", status); +		goto err_hif_stop; +	} + +	status = ath10k_wmi_wait_for_service_ready(ar); +	if (status <= 0) { +		ath10k_warn("wmi service ready event not received"); +		status = -ETIMEDOUT; +		goto err_htc_stop; +	} + +	ath10k_dbg(ATH10K_DBG_BOOT, "firmware %s booted\n", +		   ar->hw->wiphy->fw_version);  	status = ath10k_wmi_cmd_init(ar);  	if (status) {  		ath10k_err("could not send WMI init command (%d)\n", status); -		goto err_disconnect_htc; +		goto err_htc_stop;  	}  	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; +		goto err_htc_stop; +	} + +	status = ath10k_htt_setup(&ar->htt); +	if (status) { +		ath10k_err("failed to setup htt: %d\n", status); +		goto err_htc_stop;  	} -	status = ath10k_htt_attach_target(&ar->htt); +	status = ath10k_debug_start(ar);  	if (status) -		goto err_disconnect_htc; +		goto err_htc_stop; + +	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) +		ar->free_vdev_map = (1 << TARGET_10X_NUM_VDEVS) - 1; +	else +		ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1; + +	INIT_LIST_HEAD(&ar->arvifs); -	ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1; +	if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) +		ath10k_info("%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n", +			    ar->hw_params.name, +			    ar->target_version, +			    ar->chip_id, +			    ar->hw->wiphy->fw_version, +			    ar->fw_api, +			    ar->htt.target_version_major, +			    ar->htt.target_version_minor); + +	__set_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags);  	return 0; -err_disconnect_htc: +err_htc_stop:  	ath10k_htc_stop(&ar->htc); -err_htt_detach: -	ath10k_htt_detach(&ar->htt); +err_hif_stop: +	ath10k_hif_stop(ar); +err_htt_rx_detach: +	ath10k_htt_rx_free(&ar->htt); +err_htt_tx_detach: +	ath10k_htt_tx_free(&ar->htt);  err_wmi_detach:  	ath10k_wmi_detach(ar);  err: @@ -656,10 +831,41 @@ err:  }  EXPORT_SYMBOL(ath10k_core_start); +int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt) +{ +	int ret; + +	reinit_completion(&ar->target_suspend); + +	ret = ath10k_wmi_pdev_suspend_target(ar, suspend_opt); +	if (ret) { +		ath10k_warn("could not suspend target (%d)\n", ret); +		return ret; +	} + +	ret = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ); + +	if (ret == 0) { +		ath10k_warn("suspend timed out - target pause event never came\n"); +		return -ETIMEDOUT; +	} + +	return 0; +} +  void ath10k_core_stop(struct ath10k *ar)  { +	lockdep_assert_held(&ar->conf_mutex); + +	/* try to suspend target */ +	if (ar->state != ATH10K_STATE_RESTARTING) +		ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR); + +	ath10k_debug_stop(ar);  	ath10k_htc_stop(&ar->htc); -	ath10k_htt_detach(&ar->htt); +	ath10k_hif_stop(ar); +	ath10k_htt_tx_free(&ar->htt); +	ath10k_htt_rx_free(&ar->htt);  	ath10k_wmi_detach(ar);  }  EXPORT_SYMBOL(ath10k_core_stop); @@ -704,27 +910,62 @@ static int ath10k_core_probe_fw(struct ath10k *ar)  		return ret;  	} +	mutex_lock(&ar->conf_mutex); +  	ret = ath10k_core_start(ar);  	if (ret) {  		ath10k_err("could not init core (%d)\n", ret);  		ath10k_core_free_firmware_files(ar);  		ath10k_hif_power_down(ar); +		mutex_unlock(&ar->conf_mutex);  		return ret;  	}  	ath10k_core_stop(ar); + +	mutex_unlock(&ar->conf_mutex); +  	ath10k_hif_power_down(ar);  	return 0;  } -int ath10k_core_register(struct ath10k *ar) +static int ath10k_core_check_chip_id(struct ath10k *ar) +{ +	u32 hw_revision = MS(ar->chip_id, SOC_CHIP_ID_REV); + +	ath10k_dbg(ATH10K_DBG_BOOT, "boot chip_id 0x%08x hw_revision 0x%x\n", +		   ar->chip_id, hw_revision); + +	/* Check that we are not using hw1.0 (some of them have same pci id +	 * as hw2.0) before doing anything else as ath10k crashes horribly +	 * due to missing hw1.0 workarounds. */ +	switch (hw_revision) { +	case QCA988X_HW_1_0_CHIP_ID_REV: +		ath10k_err("ERROR: qca988x hw1.0 is not supported\n"); +		return -EOPNOTSUPP; + +	case QCA988X_HW_2_0_CHIP_ID_REV: +		/* known hardware revision, continue normally */ +		return 0; + +	default: +		ath10k_warn("Warning: hardware revision unknown (0x%x), expect problems\n", +			    ar->chip_id); +		return 0; +	} + +	return 0; +} + +static void ath10k_core_register_work(struct work_struct *work)  { +	struct ath10k *ar = container_of(work, struct ath10k, register_work);  	int status;  	status = ath10k_core_probe_fw(ar);  	if (status) {  		ath10k_err("could not probe fw (%d)\n", status); -		return status; +		goto err;  	}  	status = ath10k_mac_register(ar); @@ -739,26 +980,119 @@ int ath10k_core_register(struct ath10k *ar)  		goto err_unregister_mac;  	} -	return 0; +	set_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags); +	return;  err_unregister_mac:  	ath10k_mac_unregister(ar);  err_release_fw:  	ath10k_core_free_firmware_files(ar); -	return status; +err: +	device_release_driver(ar->dev); +	return; +} + +int ath10k_core_register(struct ath10k *ar, u32 chip_id) +{ +	int status; + +	ar->chip_id = chip_id; + +	status = ath10k_core_check_chip_id(ar); +	if (status) { +		ath10k_err("Unsupported chip id 0x%08x\n", ar->chip_id); +		return status; +	} + +	queue_work(ar->workqueue, &ar->register_work); + +	return 0;  }  EXPORT_SYMBOL(ath10k_core_register);  void ath10k_core_unregister(struct ath10k *ar)  { +	cancel_work_sync(&ar->register_work); + +	if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags)) +		return; +  	/* 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_core_free_firmware_files(ar); + +	ath10k_debug_destroy(ar);  }  EXPORT_SYMBOL(ath10k_core_unregister); +struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, +				  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; + +	init_completion(&ar->scan.started); +	init_completion(&ar->scan.completed); +	init_completion(&ar->scan.on_channel); +	init_completion(&ar->target_suspend); + +	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_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work); +	skb_queue_head_init(&ar->wmi_mgmt_tx_queue); + +	INIT_WORK(&ar->register_work, ath10k_core_register_work); +	INIT_WORK(&ar->restart_work, ath10k_core_restart); + +	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); +  MODULE_AUTHOR("Qualcomm Atheros");  MODULE_DESCRIPTION("Core module for QCA988X PCIe devices.");  MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index e4bba563ed4..68ceef61933 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -30,6 +30,7 @@  #include "wmi.h"  #include "../ath.h"  #include "../regd.h" +#include "../dfs_pattern_detector.h"  #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB)  #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) @@ -43,27 +44,37 @@  /* Antenna noise floor */  #define ATH10K_DEFAULT_NOISE_FLOOR -95 +#define ATH10K_MAX_NUM_MGMT_PENDING 128 + +/* number of failed packets */ +#define ATH10K_KICKOUT_THRESHOLD 50 + +/* + * Use insanely high numbers to make sure that the firmware implementation + * won't start, we have the same functionality already in hostapd. Unit + * is seconds. + */ +#define ATH10K_KEEPALIVE_MIN_IDLE 3747 +#define ATH10K_KEEPALIVE_MAX_IDLE 3895 +#define ATH10K_KEEPALIVE_MAX_UNRESPONSIVE 3900 +  struct ath10k;  struct ath10k_skb_cb {  	dma_addr_t paddr; -	bool is_mapped; -	bool is_aborted; +	u8 vdev_id;  	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; +		struct ath10k_htt_txbuf *txbuf; +		u32 txbuf_paddr;  	} __packed htt; -	/* 4 bytes left on 64bit arch */ +	struct { +		bool dtim_zero; +		bool deliver_cab; +	} bcn;  } __packed;  static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb) @@ -73,32 +84,6 @@ static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb)  	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; @@ -108,21 +93,33 @@ struct ath10k_bmi {  	bool done_sent;  }; +#define ATH10K_MAX_MEM_REQS 16 + +struct ath10k_mem_chunk { +	void *vaddr; +	dma_addr_t paddr; +	u32 len; +	u32 req_id; +}; +  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; +	wait_queue_head_t tx_credits_wq; +	struct wmi_cmd_map *cmd; +	struct wmi_vdev_param_map *vdev_param; +	struct wmi_pdev_param_map *pdev_param; -	struct sk_buff_head wmi_event_list; -	struct work_struct wmi_event_work; +	u32 num_mem_chunks; +	struct ath10k_mem_chunk mem_chunks[ATH10K_MAX_MEM_REQS];  };  struct ath10k_peer_stat {  	u8 peer_macaddr[ETH_ALEN];  	u32 peer_rssi;  	u32 peer_tx_rate; +	u32 peer_rx_rate; /* 10x only */  };  struct ath10k_target_stats { @@ -134,6 +131,12 @@ struct ath10k_target_stats {  	u32 cycle_count;  	u32 phy_err_count;  	u32 chan_tx_power; +	u32 ack_rx_bad; +	u32 rts_bad; +	u32 rts_good; +	u32 fcs_bad; +	u32 no_beacons; +	u32 mib_int_count;  	/* PDEV TX stats */  	s32 comp_queued; @@ -185,6 +188,14 @@ struct ath10k_target_stats {  }; +struct ath10k_dfs_stats { +	u32 phy_errors; +	u32 pulses_total; +	u32 pulses_detected; +	u32 pulses_discarded; +	u32 radar_detected; +}; +  #define ATH10K_MAX_NUM_PEER_IDS (1 << 11) /* htt rx_desc limit */  struct ath10k_peer { @@ -195,26 +206,49 @@ struct ath10k_peer {  	struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];  }; +struct ath10k_sta { +	struct ath10k_vif *arvif; + +	/* the following are protected by ar->data_lock */ +	u32 changed; /* IEEE80211_RC_* */ +	u32 bw; +	u32 nss; +	u32 smps; + +	struct work_struct update_wk; +}; +  #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ)  struct ath10k_vif { +	struct list_head list; +  	u32 vdev_id;  	enum wmi_vdev_type vdev_type;  	enum wmi_vdev_subtype vdev_subtype;  	u32 beacon_interval;  	u32 dtim_period; +	struct sk_buff *beacon; +	/* protected by data_lock */ +	bool beacon_sent;  	struct ath10k *ar;  	struct ieee80211_vif *vif; +	bool is_started; +	bool is_up; +	u32 aid; +	u8 bssid[ETH_ALEN]; + +	struct work_struct wep_key_work;  	struct ieee80211_key_conf *wep_keys[WMI_MAX_KEY_INDEX + 1]; -	u8 def_wep_key_index; +	u8 def_wep_key_idx; +	u8 def_wep_key_newidx;  	u16 tx_seq_no;  	union {  		struct { -			u8 bssid[ETH_ALEN];  			u32 uapsd;  		} sta;  		struct { @@ -228,10 +262,13 @@ struct ath10k_vif {  			u32 noa_len;  			u8 *noa_data;  		} ap; -		struct { -			u8 bssid[ETH_ALEN]; -		} ibss;  	} u; + +	u8 fixed_rate; +	u8 fixed_nss; +	u8 force_sgi; +	bool use_cts_prot; +	int num_legacy_stations;  };  struct ath10k_vif_iter { @@ -246,6 +283,13 @@ struct ath10k_debug {  	u32 wmi_service_bitmap[WMI_SERVICE_BM_SIZE];  	struct completion event_stats_compl; + +	unsigned long htt_stats_mask; +	struct delayed_work htt_stats_dwork; +	struct ath10k_dfs_stats dfs_stats; +	struct ath_dfs_pool_stats dfs_pool_stats; + +	u32 fw_dbglog_mask;  };  enum ath10k_state { @@ -270,12 +314,37 @@ enum ath10k_state {  	ATH10K_STATE_WEDGED,  }; +enum ath10k_fw_features { +	/* wmi_mgmt_rx_hdr contains extra RSSI information */ +	ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX = 0, + +	/* firmware from 10X branch */ +	ATH10K_FW_FEATURE_WMI_10X = 1, + +	/* firmware support tx frame management over WMI, otherwise it's HTT */ +	ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX = 2, + +	/* Firmware does not support P2P */ +	ATH10K_FW_FEATURE_NO_P2P = 3, + +	/* keep last */ +	ATH10K_FW_FEATURE_COUNT, +}; + +enum ath10k_dev_flags { +	/* Indicates that ath10k device is during CAC phase of DFS */ +	ATH10K_CAC_RUNNING, +	ATH10K_FLAG_FIRST_BOOT_DONE, +	ATH10K_FLAG_CORE_REGISTERED, +}; +  struct ath10k {  	struct ath_common ath_common;  	struct ieee80211_hw *hw;  	struct device *dev;  	u8 mac_addr[ETH_ALEN]; +	u32 chip_id;  	u32 target_version;  	u8 fw_version_major;  	u32 fw_version_minor; @@ -288,6 +357,8 @@ struct ath10k {  	u32 vht_cap_info;  	u32 num_rf_chains; +	DECLARE_BITMAP(fw_features, ATH10K_FW_FEATURE_COUNT); +  	struct targetdef *targetdef;  	struct hostdef *hostdef; @@ -298,8 +369,7 @@ struct ath10k {  		const struct ath10k_hif_ops *ops;  	} hif; -	wait_queue_head_t event_queue; -	bool is_target_paused; +	struct completion target_suspend;  	struct ath10k_bmi bmi;  	struct ath10k_wmi wmi; @@ -319,9 +389,19 @@ struct ath10k {  		} fw;  	} hw_params; -	const struct firmware *board_data; +	const struct firmware *board; +	const void *board_data; +	size_t board_len; +  	const struct firmware *otp; +	const void *otp_data; +	size_t otp_len; +  	const struct firmware *firmware; +	const void *firmware_data; +	size_t firmware_len; + +	int fw_api;  	struct {  		struct completion started; @@ -345,11 +425,27 @@ struct ath10k {  	/* valid during scan; needed for mgmt rx during scan */  	struct ieee80211_channel *scan_channel; +	/* current operating channel definition */ +	struct cfg80211_chan_def chandef; +  	int free_vdev_map; +	bool promisc; +	bool monitor;  	int monitor_vdev_id; -	bool monitor_enabled; -	bool monitor_present; +	bool monitor_started;  	unsigned int filter_flags; +	unsigned long dev_flags; +	u32 dfs_block_radar_events; + +	/* protected by conf_mutex */ +	bool radar_enabled; +	int num_started_vdevs; + +	/* Protected by conf-mutex */ +	u8 supp_tx_chainmask; +	u8 supp_rx_chainmask; +	u8 cfg_tx_chainmask; +	u8 cfg_rx_chainmask;  	struct wmi_pdev_set_wmm_params_arg wmm_params;  	struct completion install_key_done; @@ -364,16 +460,24 @@ struct ath10k {  	/* protects shared structure data */  	spinlock_t data_lock; +	struct list_head arvifs;  	struct list_head peers;  	wait_queue_head_t peer_mapping_wq; +	/* number of created peers; protected by data_lock */ +	int num_peers; +  	struct work_struct offchan_tx_work;  	struct sk_buff_head offchan_tx_queue;  	struct completion offchan_tx_completed;  	struct sk_buff *offchan_tx_skb; +	struct work_struct wmi_mgmt_tx_work; +	struct sk_buff_head wmi_mgmt_tx_queue; +  	enum ath10k_state state; +	struct work_struct register_work;  	struct work_struct restart_work;  	/* cycle count is reported twice for each visited channel during scan. @@ -382,6 +486,8 @@ struct ath10k {  	u32 survey_last_cycle_count;  	struct survey_info survey[ATH10K_NUM_CHANS]; +	struct dfs_pattern_detector *dfs_detector; +  #ifdef CONFIG_ATH10K_DEBUGFS  	struct ath10k_debug debug;  #endif @@ -392,8 +498,9 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,  void ath10k_core_destroy(struct ath10k *ar);  int ath10k_core_start(struct ath10k *ar); +int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt);  void ath10k_core_stop(struct ath10k *ar); -int ath10k_core_register(struct ath10k *ar); +int ath10k_core_register(struct ath10k *ar, u32 chip_id);  void ath10k_core_unregister(struct ath10k *ar);  #endif /* _CORE_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 3d65594fa09..1b7ff4ba122 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -21,6 +21,9 @@  #include "core.h"  #include "debug.h" +/* ms */ +#define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000 +  static int ath10k_printk(const char *level, const char *fmt, ...)  {  	struct va_format vaf; @@ -158,7 +161,7 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,  	u8 *tmp = ev->data;  	struct ath10k_target_stats *stats;  	int num_pdev_stats, num_vdev_stats, num_peer_stats; -	struct wmi_pdev_stats *ps; +	struct wmi_pdev_stats_10x *ps;  	int i;  	spin_lock_bh(&ar->data_lock); @@ -170,7 +173,7 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,  	num_peer_stats = __le32_to_cpu(ev->num_peer_stats); /* 0 or max peers */  	if (num_pdev_stats) { -		ps = (struct wmi_pdev_stats *)tmp; +		ps = (struct wmi_pdev_stats_10x *)tmp;  		stats->ch_noise_floor = __le32_to_cpu(ps->chan_nf);  		stats->tx_frame_count = __le32_to_cpu(ps->tx_frame_count); @@ -225,7 +228,18 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,  		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); +		if (test_bit(ATH10K_FW_FEATURE_WMI_10X, +			     ar->fw_features)) { +			stats->ack_rx_bad = __le32_to_cpu(ps->ack_rx_bad); +			stats->rts_bad = __le32_to_cpu(ps->rts_bad); +			stats->rts_good = __le32_to_cpu(ps->rts_good); +			stats->fcs_bad = __le32_to_cpu(ps->fcs_bad); +			stats->no_beacons = __le32_to_cpu(ps->no_beacons); +			stats->mib_int_count = __le32_to_cpu(ps->mib_int_count); +			tmp += sizeof(struct wmi_pdev_stats_10x); +		} else { +			tmp += sizeof(struct wmi_pdev_stats_old); +		}  	}  	/* 0 or max vdevs */ @@ -240,27 +254,33 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,  	}  	if (num_peer_stats) { -		struct wmi_peer_stats *peer_stats; +		struct wmi_peer_stats_10x *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; +			peer_stats = (struct wmi_peer_stats_10x *)tmp;  			s = &stats->peer_stat[i]; -			WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_stats->peer_macaddr, -						   s->peer_macaddr); +			memcpy(s->peer_macaddr, &peer_stats->peer_macaddr.addr, +			       ETH_ALEN);  			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); +			if (test_bit(ATH10K_FW_FEATURE_WMI_10X, +				     ar->fw_features)) { +				s->peer_rx_rate = +					__le32_to_cpu(peer_stats->peer_rx_rate); +				tmp += sizeof(struct wmi_peer_stats_10x); + +			} else { +				tmp += sizeof(struct wmi_peer_stats_old); +			}  		}  	}  	spin_unlock_bh(&ar->data_lock); -	mutex_unlock(&ar->conf_mutex);  	complete(&ar->debug.event_stats_compl);  } @@ -270,7 +290,7 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,  	struct ath10k *ar = file->private_data;  	struct ath10k_target_stats *fw_stats;  	char *buf = NULL; -	unsigned int len = 0, buf_len = 2500; +	unsigned int len = 0, buf_len = 8000;  	ssize_t ret_cnt = 0;  	long left;  	int i; @@ -318,6 +338,16 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,  			 "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, "%30s %10u\n", +			 "RTS bad count", fw_stats->rts_bad); +	len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", +			 "RTS good count", fw_stats->rts_good); +	len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", +			 "FCS bad count", fw_stats->fcs_bad); +	len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", +			 "No beacon count", fw_stats->no_beacons); +	len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", +			 "MIB int count", fw_stats->mib_int_count);  	len += scnprintf(buf + len, buf_len - len, "\n");  	len += scnprintf(buf + len, buf_len - len, "%30s\n", @@ -409,8 +439,8 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,  			 "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 (%d)\n", +			 "ath10k PEER stats", fw_stats->peers);  	len += scnprintf(buf + len, buf_len - len, "%30s\n\n",  				 "================="); @@ -423,6 +453,9 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,  		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, "%30s %u\n", +				 "Peer RX rate", +				 fw_stats->peer_stat[i].peer_rx_rate);  		len += scnprintf(buf + len, buf_len - len, "\n");  	}  	spin_unlock_bh(&ar->data_lock); @@ -449,27 +482,37 @@ static ssize_t ath10k_read_simulate_fw_crash(struct file *file,  					     char __user *user_buf,  					     size_t count, loff_t *ppos)  { -	const char buf[] = "To simulate firmware crash write the keyword" -			   " `crash` to this file.\nThis will force firmware" -			   " to report a crash to the host system.\n"; +	const char buf[] = "To simulate firmware crash write one of the" +			   " keywords to this file:\n `soft` - this will send" +			   " WMI_FORCE_FW_HANG_ASSERT to firmware if FW" +			   " supports that command.\n `hard` - this will send" +			   " to firmware command with illegal parameters" +			   " causing firmware crash.\n"; +  	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));  } +/* Simulate firmware crash: + * 'soft': Call wmi command causing firmware hang. This firmware hang is + * recoverable by warm firmware reset. + * 'hard': Force firmware crash by setting any vdev parameter for not allowed + * vdev id. This is hard firmware crash because it is recoverable only by cold + * firmware reset. + */  static ssize_t ath10k_write_simulate_fw_crash(struct file *file,  					      const char __user *user_buf,  					      size_t count, loff_t *ppos)  {  	struct ath10k *ar = file->private_data; -	char buf[32] = {}; +	char buf[32];  	int ret;  	mutex_lock(&ar->conf_mutex);  	simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); -	if (strcmp(buf, "crash") && strcmp(buf, "crash\n")) { -		ret = -EINVAL; -		goto exit; -	} + +	/* make sure that buf is null terminated */ +	buf[sizeof(buf) - 1] = 0;  	if (ar->state != ATH10K_STATE_ON &&  	    ar->state != ATH10K_STATE_RESTARTED) { @@ -477,14 +520,30 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file,  		goto exit;  	} -	ath10k_info("simulating firmware crash\n"); +	/* drop the possible '\n' from the end */ +	if (buf[count - 1] == '\n') { +		buf[count - 1] = 0; +		count--; +	} -	ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0); -	if (ret) -		ath10k_warn("failed to force fw hang (%d)\n", ret); +	if (!strcmp(buf, "soft")) { +		ath10k_info("simulating soft firmware crash\n"); +		ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0); +	} else if (!strcmp(buf, "hard")) { +		ath10k_info("simulating hard firmware crash\n"); +		ret = ath10k_wmi_vdev_set_param(ar, TARGET_NUM_VDEVS + 1, +					ar->wmi.vdev_param->rts_threshold, 0); +	} else { +		ret = -EINVAL; +		goto exit; +	} + +	if (ret) { +		ath10k_warn("failed to simulate firmware crash: %d\n", ret); +		goto exit; +	} -	if (ret == 0) -		ret = count; +	ret = count;  exit:  	mutex_unlock(&ar->conf_mutex); @@ -499,6 +558,287 @@ static const struct file_operations fops_simulate_fw_crash = {  	.llseek = default_llseek,  }; +static ssize_t ath10k_read_chip_id(struct file *file, char __user *user_buf, +				   size_t count, loff_t *ppos) +{ +	struct ath10k *ar = file->private_data; +	unsigned int len; +	char buf[50]; + +	len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->chip_id); + +	return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_chip_id = { +	.read = ath10k_read_chip_id, +	.open = simple_open, +	.owner = THIS_MODULE, +	.llseek = default_llseek, +}; + +static int ath10k_debug_htt_stats_req(struct ath10k *ar) +{ +	u64 cookie; +	int ret; + +	lockdep_assert_held(&ar->conf_mutex); + +	if (ar->debug.htt_stats_mask == 0) +		/* htt stats are disabled */ +		return 0; + +	if (ar->state != ATH10K_STATE_ON) +		return 0; + +	cookie = get_jiffies_64(); + +	ret = ath10k_htt_h2t_stats_req(&ar->htt, ar->debug.htt_stats_mask, +				       cookie); +	if (ret) { +		ath10k_warn("failed to send htt stats request: %d\n", ret); +		return ret; +	} + +	queue_delayed_work(ar->workqueue, &ar->debug.htt_stats_dwork, +			   msecs_to_jiffies(ATH10K_DEBUG_HTT_STATS_INTERVAL)); + +	return 0; +} + +static void ath10k_debug_htt_stats_dwork(struct work_struct *work) +{ +	struct ath10k *ar = container_of(work, struct ath10k, +					 debug.htt_stats_dwork.work); + +	mutex_lock(&ar->conf_mutex); + +	ath10k_debug_htt_stats_req(ar); + +	mutex_unlock(&ar->conf_mutex); +} + +static ssize_t ath10k_read_htt_stats_mask(struct file *file, +					    char __user *user_buf, +					    size_t count, loff_t *ppos) +{ +	struct ath10k *ar = file->private_data; +	char buf[32]; +	unsigned int len; + +	len = scnprintf(buf, sizeof(buf), "%lu\n", ar->debug.htt_stats_mask); + +	return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ath10k_write_htt_stats_mask(struct file *file, +					     const char __user *user_buf, +					     size_t count, loff_t *ppos) +{ +	struct ath10k *ar = file->private_data; +	unsigned long mask; +	int ret; + +	ret = kstrtoul_from_user(user_buf, count, 0, &mask); +	if (ret) +		return ret; + +	/* max 8 bit masks (for now) */ +	if (mask > 0xff) +		return -E2BIG; + +	mutex_lock(&ar->conf_mutex); + +	ar->debug.htt_stats_mask = mask; + +	ret = ath10k_debug_htt_stats_req(ar); +	if (ret) +		goto out; + +	ret = count; + +out: +	mutex_unlock(&ar->conf_mutex); + +	return ret; +} + +static const struct file_operations fops_htt_stats_mask = { +	.read = ath10k_read_htt_stats_mask, +	.write = ath10k_write_htt_stats_mask, +	.open = simple_open, +	.owner = THIS_MODULE, +	.llseek = default_llseek, +}; + +static ssize_t ath10k_read_fw_dbglog(struct file *file, +					    char __user *user_buf, +					    size_t count, loff_t *ppos) +{ +	struct ath10k *ar = file->private_data; +	unsigned int len; +	char buf[32]; + +	len = scnprintf(buf, sizeof(buf), "0x%08x\n", +			ar->debug.fw_dbglog_mask); + +	return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ath10k_write_fw_dbglog(struct file *file, +				      const char __user *user_buf, +				      size_t count, loff_t *ppos) +{ +	struct ath10k *ar = file->private_data; +	unsigned long mask; +	int ret; + +	ret = kstrtoul_from_user(user_buf, count, 0, &mask); +	if (ret) +		return ret; + +	mutex_lock(&ar->conf_mutex); + +	ar->debug.fw_dbglog_mask = mask; + +	if (ar->state == ATH10K_STATE_ON) { +		ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask); +		if (ret) { +			ath10k_warn("dbglog cfg failed from debugfs: %d\n", +				    ret); +			goto exit; +		} +	} + +	ret = count; + +exit: +	mutex_unlock(&ar->conf_mutex); + +	return ret; +} + +static const struct file_operations fops_fw_dbglog = { +	.read = ath10k_read_fw_dbglog, +	.write = ath10k_write_fw_dbglog, +	.open = simple_open, +	.owner = THIS_MODULE, +	.llseek = default_llseek, +}; + +int ath10k_debug_start(struct ath10k *ar) +{ +	int ret; + +	lockdep_assert_held(&ar->conf_mutex); + +	ret = ath10k_debug_htt_stats_req(ar); +	if (ret) +		/* continue normally anyway, this isn't serious */ +		ath10k_warn("failed to start htt stats workqueue: %d\n", ret); + +	if (ar->debug.fw_dbglog_mask) { +		ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask); +		if (ret) +			/* not serious */ +			ath10k_warn("failed to enable dbglog during start: %d", +				    ret); +	} + +	return 0; +} + +void ath10k_debug_stop(struct ath10k *ar) +{ +	lockdep_assert_held(&ar->conf_mutex); + +	/* Must not use _sync to avoid deadlock, we do that in +	 * ath10k_debug_destroy(). The check for htt_stats_mask is to avoid +	 * warning from del_timer(). */ +	if (ar->debug.htt_stats_mask != 0) +		cancel_delayed_work(&ar->debug.htt_stats_dwork); +} + +static ssize_t ath10k_write_simulate_radar(struct file *file, +					   const char __user *user_buf, +					   size_t count, loff_t *ppos) +{ +	struct ath10k *ar = file->private_data; + +	ieee80211_radar_detected(ar->hw); + +	return count; +} + +static const struct file_operations fops_simulate_radar = { +	.write = ath10k_write_simulate_radar, +	.open = simple_open, +	.owner = THIS_MODULE, +	.llseek = default_llseek, +}; + +#define ATH10K_DFS_STAT(s, p) (\ +	len += scnprintf(buf + len, size - len, "%-28s : %10u\n", s, \ +			 ar->debug.dfs_stats.p)) + +#define ATH10K_DFS_POOL_STAT(s, p) (\ +	len += scnprintf(buf + len, size - len, "%-28s : %10u\n", s, \ +			 ar->debug.dfs_pool_stats.p)) + +static ssize_t ath10k_read_dfs_stats(struct file *file, char __user *user_buf, +				     size_t count, loff_t *ppos) +{ +	int retval = 0, len = 0; +	const int size = 8000; +	struct ath10k *ar = file->private_data; +	char *buf; + +	buf = kzalloc(size, GFP_KERNEL); +	if (buf == NULL) +		return -ENOMEM; + +	if (!ar->dfs_detector) { +		len += scnprintf(buf + len, size - len, "DFS not enabled\n"); +		goto exit; +	} + +	ar->debug.dfs_pool_stats = +			ar->dfs_detector->get_stats(ar->dfs_detector); + +	len += scnprintf(buf + len, size - len, "Pulse detector statistics:\n"); + +	ATH10K_DFS_STAT("reported phy errors", phy_errors); +	ATH10K_DFS_STAT("pulse events reported", pulses_total); +	ATH10K_DFS_STAT("DFS pulses detected", pulses_detected); +	ATH10K_DFS_STAT("DFS pulses discarded", pulses_discarded); +	ATH10K_DFS_STAT("Radars detected", radar_detected); + +	len += scnprintf(buf + len, size - len, "Global Pool statistics:\n"); +	ATH10K_DFS_POOL_STAT("Pool references", pool_reference); +	ATH10K_DFS_POOL_STAT("Pulses allocated", pulse_allocated); +	ATH10K_DFS_POOL_STAT("Pulses alloc error", pulse_alloc_error); +	ATH10K_DFS_POOL_STAT("Pulses in use", pulse_used); +	ATH10K_DFS_POOL_STAT("Seqs. allocated", pseq_allocated); +	ATH10K_DFS_POOL_STAT("Seqs. alloc error", pseq_alloc_error); +	ATH10K_DFS_POOL_STAT("Seqs. in use", pseq_used); + +exit: +	if (len > size) +		len = size; + +	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); +	kfree(buf); + +	return retval; +} + +static const struct file_operations fops_dfs_stats = { +	.read = ath10k_read_dfs_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", @@ -507,6 +847,9 @@ int ath10k_debug_create(struct ath10k *ar)  	if (!ar->debug.debugfs_phy)  		return -ENOMEM; +	INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork, +			  ath10k_debug_htt_stats_dwork); +  	init_completion(&ar->debug.event_stats_compl);  	debugfs_create_file("fw_stats", S_IRUSR, ar->debug.debugfs_phy, ar, @@ -518,8 +861,37 @@ int ath10k_debug_create(struct ath10k *ar)  	debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy,  			    ar, &fops_simulate_fw_crash); +	debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy, +			    ar, &fops_chip_id); + +	debugfs_create_file("htt_stats_mask", S_IRUSR, ar->debug.debugfs_phy, +			    ar, &fops_htt_stats_mask); + +	debugfs_create_file("fw_dbglog", S_IRUSR, ar->debug.debugfs_phy, +			    ar, &fops_fw_dbglog); + +	if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) { +		debugfs_create_file("dfs_simulate_radar", S_IWUSR, +				    ar->debug.debugfs_phy, ar, +				    &fops_simulate_radar); + +		debugfs_create_bool("dfs_block_radar_events", S_IWUSR, +				    ar->debug.debugfs_phy, +				    &ar->dfs_block_radar_events); + +		debugfs_create_file("dfs_stats", S_IRUSR, +				    ar->debug.debugfs_phy, ar, +				    &fops_dfs_stats); +	} +  	return 0;  } + +void ath10k_debug_destroy(struct ath10k *ar) +{ +	cancel_delayed_work_sync(&ar->debug.htt_stats_dwork); +} +  #endif /* CONFIG_ATH10K_DEBUGFS */  #ifdef CONFIG_ATH10K_DEBUG diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index 168140c5402..a5824990bd2 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -27,34 +27,54 @@ enum ath10k_debug_mask {  	ATH10K_DBG_HTC		= 0x00000004,  	ATH10K_DBG_HTT		= 0x00000008,  	ATH10K_DBG_MAC		= 0x00000010, -	ATH10K_DBG_CORE		= 0x00000020, +	ATH10K_DBG_BOOT		= 0x00000020,  	ATH10K_DBG_PCI_DUMP	= 0x00000040,  	ATH10K_DBG_HTT_DUMP	= 0x00000080,  	ATH10K_DBG_MGMT		= 0x00000100,  	ATH10K_DBG_DATA		= 0x00000200, +	ATH10K_DBG_BMI		= 0x00000400, +	ATH10K_DBG_REGULATORY	= 0x00000800,  	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, ...); +__printf(1, 2) int ath10k_info(const char *fmt, ...); +__printf(1, 2) int ath10k_err(const char *fmt, ...); +__printf(1, 2) int ath10k_warn(const char *fmt, ...);  #ifdef CONFIG_ATH10K_DEBUGFS +int ath10k_debug_start(struct ath10k *ar); +void ath10k_debug_stop(struct ath10k *ar);  int ath10k_debug_create(struct ath10k *ar); +void ath10k_debug_destroy(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); +#define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++) +  #else +static inline int ath10k_debug_start(struct ath10k *ar) +{ +	return 0; +} + +static inline void ath10k_debug_stop(struct ath10k *ar) +{ +} +  static inline int ath10k_debug_create(struct ath10k *ar)  {  	return 0;  } +static inline void ath10k_debug_destroy(struct ath10k *ar) +{ +} +  static inline void ath10k_debug_read_service_map(struct ath10k *ar,  						 void *service_map,  						 size_t map_size) @@ -65,11 +85,14 @@ static inline void ath10k_debug_read_target_stats(struct ath10k *ar,  						  struct wmi_stats_event *ev)  {  } + +#define ATH10K_DFS_STAT_INC(ar, c) do { } while (0) +  #endif /* CONFIG_ATH10K_DEBUGFS */  #ifdef CONFIG_ATH10K_DEBUG -extern __printf(2, 3) void ath10k_dbg(enum ath10k_debug_mask mask, -				      const char *fmt, ...); +__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); diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h index dcdea68bcc0..2ac7beacddc 100644 --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h @@ -21,6 +21,14 @@  #include <linux/kernel.h>  #include "core.h" +struct ath10k_hif_sg_item { +	u16 transfer_id; +	void *transfer_context; /* NULL = tx completion callback not called */ +	void *vaddr; /* for debugging mostly */ +	u32 paddr; +	u16 len; +}; +  struct ath10k_hif_cb {  	int (*tx_completion)(struct ath10k *ar,  			     struct sk_buff *wbuf, @@ -31,11 +39,9 @@ struct ath10k_hif_cb {  };  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); +	/* send a scatter-gather list to the target */ +	int (*tx_sg)(struct ath10k *ar, u8 pipe_id, +		     struct ath10k_hif_sg_item *items, int n_items);  	/*  	 * API to handle HIF-specific BMI message exchanges, this API is @@ -86,12 +92,11 @@ struct ath10k_hif_ops {  }; -static inline int ath10k_hif_send_head(struct ath10k *ar, u8 pipe_id, -				       unsigned int transfer_id, -				       unsigned int nbytes, -				       struct sk_buff *buf) +static inline int ath10k_hif_tx_sg(struct ath10k *ar, u8 pipe_id, +				   struct ath10k_hif_sg_item *items, +				   int n_items)  { -	return ar->hif.ops->send_head(ar, pipe_id, transfer_id, nbytes, buf); +	return ar->hif.ops->tx_sg(ar, pipe_id, items, n_items);  }  static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar, diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index ef3329ef52f..e493db4b4a4 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -63,7 +63,9 @@ static struct sk_buff *ath10k_htc_build_tx_ctrl_skb(void *ar)  static inline void ath10k_htc_restore_tx_skb(struct ath10k_htc *htc,  					     struct sk_buff *skb)  { -	ath10k_skb_unmap(htc->ar->dev, skb); +	struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb); + +	dma_unmap_single(htc->ar->dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE);  	skb_pull(skb, sizeof(struct ath10k_htc_hdr));  } @@ -103,10 +105,10 @@ static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep,  	struct ath10k_htc_hdr *hdr;  	hdr = (struct ath10k_htc_hdr *)skb->data; -	memset(hdr, 0, sizeof(*hdr));  	hdr->eid = ep->eid;  	hdr->len = __cpu_to_le16(skb->len - sizeof(*hdr)); +	hdr->flags = 0;  	spin_lock_bh(&ep->htc->tx_lock);  	hdr->seq_no = ep->seq_no++; @@ -117,134 +119,16 @@ static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep,  	spin_unlock_bh(&ep->htc->tx_lock);  } -static int ath10k_htc_issue_skb(struct ath10k_htc *htc, -				struct ath10k_htc_ep *ep, -				struct sk_buff *skb, -				u8 credits) -{ -	struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb); -	int ret; - -	ath10k_dbg(ATH10K_DBG_HTC, "%s: ep %d skb %p\n", __func__, -		   ep->eid, skb); - -	ath10k_htc_prepare_tx_skb(ep, skb); - -	ret = ath10k_skb_map(htc->ar->dev, skb); -	if (ret) -		goto err; - -	ret = ath10k_hif_send_head(htc->ar, -				   ep->ul_pipe_id, -				   ep->eid, -				   skb->len, -				   skb); -	if (unlikely(ret)) -		goto err; - -	return 0; -err: -	ath10k_warn("HTC issue failed: %d\n", ret); - -	spin_lock_bh(&htc->tx_lock); -	ep->tx_credits += credits; -	spin_unlock_bh(&htc->tx_lock); - -	/* this is the simplest way to handle out-of-resources for non-credit -	 * based endpoints. credit based endpoints can still get -ENOSR, but -	 * this is highly unlikely as credit reservation should prevent that */ -	if (ret == -ENOSR) { -		spin_lock_bh(&htc->tx_lock); -		__skb_queue_head(&ep->tx_queue, skb); -		spin_unlock_bh(&htc->tx_lock); - -		return ret; -	} - -	skb_cb->is_aborted = true; -	ath10k_htc_notify_tx_completion(ep, skb); - -	return ret; -} - -static struct sk_buff *ath10k_htc_get_skb_credit_based(struct ath10k_htc *htc, -						       struct ath10k_htc_ep *ep, -						       u8 *credits) -{ -	struct sk_buff *skb; -	struct ath10k_skb_cb *skb_cb; -	int credits_required; -	int remainder; -	unsigned int transfer_len; - -	lockdep_assert_held(&htc->tx_lock); - -	skb = __skb_dequeue(&ep->tx_queue); -	if (!skb) -		return NULL; - -	skb_cb = ATH10K_SKB_CB(skb); -	transfer_len = skb->len; - -	if (likely(transfer_len <= htc->target_credit_size)) { -		credits_required = 1; -	} else { -		/* figure out how many credits this message requires */ -		credits_required = transfer_len / htc->target_credit_size; -		remainder = transfer_len % htc->target_credit_size; - -		if (remainder) -			credits_required++; -	} - -	ath10k_dbg(ATH10K_DBG_HTC, "Credits required %d got %d\n", -		   credits_required, ep->tx_credits); - -	if (ep->tx_credits < credits_required) { -		__skb_queue_head(&ep->tx_queue, skb); -		return NULL; -	} - -	ep->tx_credits -= credits_required; -	*credits = credits_required; -	return skb; -} - -static void ath10k_htc_send_work(struct work_struct *work) -{ -	struct ath10k_htc_ep *ep = container_of(work, -					struct ath10k_htc_ep, send_work); -	struct ath10k_htc *htc = ep->htc; -	struct sk_buff *skb; -	u8 credits = 0; -	int ret; - -	while (true) { -		if (ep->ul_is_polled) -			ath10k_htc_send_complete_check(ep, 0); - -		spin_lock_bh(&htc->tx_lock); -		if (ep->tx_credit_flow_enabled) -			skb = ath10k_htc_get_skb_credit_based(htc, ep, -							      &credits); -		else -			skb = __skb_dequeue(&ep->tx_queue); -		spin_unlock_bh(&htc->tx_lock); - -		if (!skb) -			break; - -		ret = ath10k_htc_issue_skb(htc, ep, skb, credits); -		if (ret == -ENOSR) -			break; -	} -} -  int ath10k_htc_send(struct ath10k_htc *htc,  		    enum ath10k_htc_ep_id eid,  		    struct sk_buff *skb)  {  	struct ath10k_htc_ep *ep = &htc->endpoint[eid]; +	struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb); +	struct ath10k_hif_sg_item sg_item; +	struct device *dev = htc->ar->dev; +	int credits = 0; +	int ret;  	if (htc->ar->state == ATH10K_STATE_WEDGED)  		return -ECOMM; @@ -254,18 +138,67 @@ int ath10k_htc_send(struct ath10k_htc *htc,  		return -ENOENT;  	} +	/* FIXME: This looks ugly, can we fix it? */  	spin_lock_bh(&htc->tx_lock);  	if (htc->stopped) {  		spin_unlock_bh(&htc->tx_lock);  		return -ESHUTDOWN;  	} +	spin_unlock_bh(&htc->tx_lock); -	__skb_queue_tail(&ep->tx_queue, skb);  	skb_push(skb, sizeof(struct ath10k_htc_hdr)); -	spin_unlock_bh(&htc->tx_lock); -	queue_work(htc->ar->workqueue, &ep->send_work); +	if (ep->tx_credit_flow_enabled) { +		credits = DIV_ROUND_UP(skb->len, htc->target_credit_size); +		spin_lock_bh(&htc->tx_lock); +		if (ep->tx_credits < credits) { +			spin_unlock_bh(&htc->tx_lock); +			ret = -EAGAIN; +			goto err_pull; +		} +		ep->tx_credits -= credits; +		ath10k_dbg(ATH10K_DBG_HTC, +			   "htc ep %d consumed %d credits (total %d)\n", +			   eid, credits, ep->tx_credits); +		spin_unlock_bh(&htc->tx_lock); +	} + +	ath10k_htc_prepare_tx_skb(ep, skb); + +	skb_cb->paddr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE); +	ret = dma_mapping_error(dev, skb_cb->paddr); +	if (ret) +		goto err_credits; + +	sg_item.transfer_id = ep->eid; +	sg_item.transfer_context = skb; +	sg_item.vaddr = skb->data; +	sg_item.paddr = skb_cb->paddr; +	sg_item.len = skb->len; + +	ret = ath10k_hif_tx_sg(htc->ar, ep->ul_pipe_id, &sg_item, 1); +	if (ret) +		goto err_unmap; +  	return 0; + +err_unmap: +	dma_unmap_single(dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE); +err_credits: +	if (ep->tx_credit_flow_enabled) { +		spin_lock_bh(&htc->tx_lock); +		ep->tx_credits += credits; +		ath10k_dbg(ATH10K_DBG_HTC, +			   "htc ep %d reverted %d credits back (total %d)\n", +			   eid, credits, ep->tx_credits); +		spin_unlock_bh(&htc->tx_lock); + +		if (ep->ep_ops.ep_tx_credits) +			ep->ep_ops.ep_tx_credits(htc->ar); +	} +err_pull: +	skb_pull(skb, sizeof(struct ath10k_htc_hdr)); +	return ret;  }  static int ath10k_htc_tx_completion_handler(struct ath10k *ar, @@ -275,42 +208,15 @@ static int ath10k_htc_tx_completion_handler(struct ath10k *ar,  	struct ath10k_htc *htc = &ar->htc;  	struct ath10k_htc_ep *ep = &htc->endpoint[eid]; +	if (WARN_ON_ONCE(!skb)) +		return 0; +  	ath10k_htc_notify_tx_completion(ep, skb);  	/* the skb now belongs to the completion handler */ -	/* note: when using TX credit flow, the re-checking of queues happens -	 * when credits flow back from the target.  in the non-TX credit case, -	 * we recheck after the packet completes */ -	spin_lock_bh(&htc->tx_lock); -	if (!ep->tx_credit_flow_enabled && !htc->stopped) -		queue_work(ar->workqueue, &ep->send_work); -	spin_unlock_bh(&htc->tx_lock); -  	return 0;  } -/* flush endpoint TX queue */ -static void ath10k_htc_flush_endpoint_tx(struct ath10k_htc *htc, -					 struct ath10k_htc_ep *ep) -{ -	struct sk_buff *skb; -	struct ath10k_skb_cb *skb_cb; - -	spin_lock_bh(&htc->tx_lock); -	for (;;) { -		skb = __skb_dequeue(&ep->tx_queue); -		if (!skb) -			break; - -		skb_cb = ATH10K_SKB_CB(skb); -		skb_cb->is_aborted = true; -		ath10k_htc_notify_tx_completion(ep, skb); -	} -	spin_unlock_bh(&htc->tx_lock); - -	cancel_work_sync(&ep->send_work); -} -  /***********/  /* Receive */  /***********/ @@ -334,14 +240,17 @@ ath10k_htc_process_credit_report(struct ath10k_htc *htc,  		if (report->eid >= ATH10K_HTC_EP_COUNT)  			break; -		ath10k_dbg(ATH10K_DBG_HTC, "ep %d got %d credits\n", -			   report->eid, report->credits); -  		ep = &htc->endpoint[report->eid];  		ep->tx_credits += report->credits; -		if (ep->tx_credits && !skb_queue_empty(&ep->tx_queue)) -			queue_work(htc->ar->workqueue, &ep->send_work); +		ath10k_dbg(ATH10K_DBG_HTC, "htc ep %d got %d credits (total %d)\n", +			   report->eid, report->credits, ep->tx_credits); + +		if (ep->ep_ops.ep_tx_credits) { +			spin_unlock_bh(&htc->tx_lock); +			ep->ep_ops.ep_tx_credits(htc->ar); +			spin_lock_bh(&htc->tx_lock); +		}  	}  	spin_unlock_bh(&htc->tx_lock);  } @@ -599,10 +508,8 @@ static void ath10k_htc_reset_endpoint_states(struct ath10k_htc *htc)  		ep->max_ep_message_len = 0;  		ep->max_tx_queue_depth = 0;  		ep->eid = i; -		skb_queue_head_init(&ep->tx_queue);  		ep->htc = htc;  		ep->tx_credit_flow_enabled = true; -		INIT_WORK(&ep->send_work, ath10k_htc_send_work);  	}  } @@ -647,14 +554,6 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)  	u16 credit_count;  	u16 credit_size; -	INIT_COMPLETION(htc->ctl_resp); - -	status = ath10k_hif_start(htc->ar); -	if (status) { -		ath10k_err("could not start HIF (%d)\n", status); -		goto err_start; -	} -  	status = wait_for_completion_timeout(&htc->ctl_resp,  					     ATH10K_HTC_WAIT_TIMEOUT_HZ);  	if (status <= 0) { @@ -662,15 +561,13 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)  			status = -ETIMEDOUT;  		ath10k_err("ctl_resp never came in (%d)\n", status); -		goto err_target; +		return status;  	}  	if (htc->control_resp_len < sizeof(msg->hdr) + sizeof(msg->ready)) {  		ath10k_err("Invalid HTC ready msg len:%d\n",  			   htc->control_resp_len); - -		status = -ECOMM; -		goto err_target; +		return -ECOMM;  	}  	msg = (struct ath10k_htc_msg *)htc->control_resp_buffer; @@ -680,8 +577,7 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)  	if (message_id != ATH10K_HTC_MSG_READY_ID) {  		ath10k_err("Invalid HTC ready msg: 0x%x\n", message_id); -		status = -ECOMM; -		goto err_target; +		return -ECOMM;  	}  	htc->total_transmit_credits = credit_count; @@ -694,9 +590,8 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)  	if ((htc->total_transmit_credits == 0) ||  	    (htc->target_credit_size == 0)) { -		status = -ECOMM;  		ath10k_err("Invalid credit size received\n"); -		goto err_target; +		return -ECOMM;  	}  	ath10k_htc_setup_target_buffer_assignments(htc); @@ -713,14 +608,10 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)  	status = ath10k_htc_connect_service(htc, &conn_req, &conn_resp);  	if (status) {  		ath10k_err("could not connect to htc service (%d)\n", status); -		goto err_target; +		return status;  	}  	return 0; -err_target: -	ath10k_hif_stop(htc->ar); -err_start: -	return status;  }  int ath10k_htc_connect_service(struct ath10k_htc *htc, @@ -752,8 +643,8 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,  	tx_alloc = ath10k_htc_get_credit_allocation(htc,  						    conn_req->service_id);  	if (!tx_alloc) -		ath10k_dbg(ATH10K_DBG_HTC, -			   "HTC Service %s does not allocate target credits\n", +		ath10k_dbg(ATH10K_DBG_BOOT, +			   "boot htc service %s does not allocate target credits\n",  			   htc_service_name(conn_req->service_id));  	skb = ath10k_htc_build_tx_ctrl_skb(htc->ar); @@ -772,17 +663,17 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,  	flags |= SM(tx_alloc, ATH10K_HTC_CONN_FLAGS_RECV_ALLOC); -	req_msg = &msg->connect_service; -	req_msg->flags = __cpu_to_le16(flags); -	req_msg->service_id = __cpu_to_le16(conn_req->service_id); -  	/* Only enable credit flow control for WMI ctrl service */  	if (conn_req->service_id != ATH10K_HTC_SVC_ID_WMI_CONTROL) {  		flags |= ATH10K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL;  		disable_credit_flow_ctrl = true;  	} -	INIT_COMPLETION(htc->ctl_resp); +	req_msg = &msg->connect_service; +	req_msg->flags = __cpu_to_le16(flags); +	req_msg->service_id = __cpu_to_le16(conn_req->service_id); + +	reinit_completion(&htc->ctl_resp);  	status = ath10k_htc_send(htc, ATH10K_HTC_EP_0, skb);  	if (status) { @@ -873,19 +764,19 @@ setup:  	if (status)  		return status; -	ath10k_dbg(ATH10K_DBG_HTC, -		   "HTC service: %s UL pipe: %d DL pipe: %d eid: %d ready\n", +	ath10k_dbg(ATH10K_DBG_BOOT, +		   "boot htc service '%s' ul pipe %d dl pipe %d eid %d ready\n",  		   htc_service_name(ep->service_id), ep->ul_pipe_id,  		   ep->dl_pipe_id, ep->eid); -	ath10k_dbg(ATH10K_DBG_HTC, -		   "EP %d UL polled: %d, DL polled: %d\n", +	ath10k_dbg(ATH10K_DBG_BOOT, +		   "boot htc ep %d ul polled %d dl polled %d\n",  		   ep->eid, ep->ul_is_polled, ep->dl_is_polled);  	if (disable_credit_flow_ctrl && ep->tx_credit_flow_enabled) {  		ep->tx_credit_flow_enabled = false; -		ath10k_dbg(ATH10K_DBG_HTC, -			   "HTC service: %s eid: %d TX flow control disabled\n", +		ath10k_dbg(ATH10K_DBG_BOOT, +			   "boot htc service '%s' eid %d TX flow control disabled\n",  			   htc_service_name(ep->service_id), assigned_eid);  	} @@ -939,25 +830,11 @@ int ath10k_htc_start(struct ath10k_htc *htc)  	return 0;  } -/* - * stop HTC communications, i.e. stop interrupt reception, and flush all - * queued buffers - */  void ath10k_htc_stop(struct ath10k_htc *htc)  { -	int i; -	struct ath10k_htc_ep *ep; -  	spin_lock_bh(&htc->tx_lock);  	htc->stopped = true;  	spin_unlock_bh(&htc->tx_lock); - -	for (i = ATH10K_HTC_EP_0; i < ATH10K_HTC_EP_COUNT; i++) { -		ep = &htc->endpoint[i]; -		ath10k_htc_flush_endpoint_tx(htc, ep); -	} - -	ath10k_hif_stop(htc->ar);  }  /* registered target arrival callback from the HIF layer */ diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h index e1dd8c76185..4716d331e6b 100644 --- a/drivers/net/wireless/ath/ath10k/htc.h +++ b/drivers/net/wireless/ath/ath10k/htc.h @@ -276,6 +276,7 @@ struct ath10k_htc_ops {  struct ath10k_htc_ep_ops {  	void (*ep_tx_complete)(struct ath10k *, struct sk_buff *);  	void (*ep_rx_complete)(struct ath10k *, struct sk_buff *); +	void (*ep_tx_credits)(struct ath10k *);  };  /* service connection information */ @@ -315,15 +316,11 @@ struct ath10k_htc_ep {  	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 { diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 39342c5cfcb..19c12cc8d66 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -22,7 +22,7 @@  #include "core.h"  #include "debug.h" -static int ath10k_htt_htc_attach(struct ath10k_htt *htt) +int ath10k_htt_connect(struct ath10k_htt *htt)  {  	struct ath10k_htc_svc_conn_req conn_req;  	struct ath10k_htc_svc_conn_resp conn_resp; @@ -48,39 +48,14 @@ static int ath10k_htt_htc_attach(struct ath10k_htt *htt)  	return 0;  } -int ath10k_htt_attach(struct ath10k *ar) +int ath10k_htt_init(struct ath10k *ar)  {  	struct ath10k_htt *htt = &ar->htt; -	int ret;  	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. -	 */ -	ret = ath10k_htt_htc_attach(htt); -	if (ret) { -		ath10k_err("could not attach htt htc (%d)\n", ret); -		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; -	} - -	ret = ath10k_htt_rx_attach(htt); -	if (ret) { -		ath10k_err("could not attach htt rx (%d)\n", ret); -		goto err_rx_attach; -	} - -	/*  	 * Prefetch enough data to satisfy target  	 * classification engine.  	 * This is for LL chips. HL chips will probably @@ -93,36 +68,26 @@ int ath10k_htt_attach(struct ath10k *ar)  		2; /* ip4 dscp or ip6 priority */  	return 0; - -err_rx_attach: -	ath10k_htt_tx_detach(htt); -err_htc_attach: -	return ret;  }  #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"); +	ath10k_dbg(ATH10K_DBG_BOOT, "htt target version %d.%d\n", +		   htt->target_version_major, htt->target_version_minor); + +	if (htt->target_version_major != 2 && +	    htt->target_version_major != 3) { +		ath10k_err("unsupported htt major version %d. supported versions are 2 and 3\n", +			   htt->target_version_major);  		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 ath10k_htt_setup(struct ath10k_htt *htt)  {  	int status; @@ -145,9 +110,3 @@ int ath10k_htt_attach_target(struct ath10k_htt *htt)  	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); -} diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 318be4629cd..9a263462c79 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -19,13 +19,13 @@  #define _HTT_H_  #include <linux/bug.h> +#include <linux/interrupt.h> +#include <linux/dmapool.h> +#include <net/mac80211.h>  #include "htc.h"  #include "rx_desc.h" -#define HTT_CURRENT_VERSION_MAJOR	2 -#define HTT_CURRENT_VERSION_MINOR	1 -  enum htt_dbg_stats_type {  	HTT_DBG_STATS_WAL_PDEV_TXRX = 1 << 0,  	HTT_DBG_STATS_RX_REORDER    = 1 << 1, @@ -45,6 +45,9 @@ enum htt_h2t_msg_type { /* host-to-target */  	HTT_H2T_MSG_TYPE_SYNC               = 4,  	HTT_H2T_MSG_TYPE_AGGR_CFG           = 5,  	HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG = 6, + +	/* This command is used for sending management frames in HTT < 3.0. +	 * HTT >= 3.0 uses TX_FRM for everything. */  	HTT_H2T_MSG_TYPE_MGMT_TX            = 7,  	HTT_H2T_NUM_MSGS /* keep this last */ @@ -1170,18 +1173,12 @@ struct htt_peer_unmap_event {  	u16 peer_id;  }; -struct htt_rx_info { -	struct sk_buff *skb; -	enum htt_rx_mpdu_status status; -	enum htt_rx_mpdu_encrypt_type encrypt_type; -	s8 signal; -	struct { -		u8 info0; -		u32 info1; -		u32 info2; -	} rate; -	bool fcs_err; -}; +struct ath10k_htt_txbuf { +	struct htt_data_tx_desc_frag frags[2]; +	struct ath10k_htc_hdr htc_hdr; +	struct htt_cmd_hdr cmd_hdr; +	struct htt_data_tx_desc cmd_tx; +} __packed;  struct ath10k_htt {  	struct ath10k *ar; @@ -1264,10 +1261,21 @@ struct ath10k_htt {  	struct sk_buff **pending_tx;  	unsigned long *used_msdu_ids; /* bitmap */  	wait_queue_head_t empty_tx_wq; +	struct dma_pool *tx_pool;  	/* set if host-fw communication goes haywire  	 * used to avoid further failures */  	bool rx_confused; +	struct tasklet_struct rx_replenish_task; + +	/* This is used to group tx/rx completions separately and process them +	 * in batches to reduce cache stalls */ +	struct tasklet_struct txrx_compl_task; +	struct sk_buff_head tx_compl_q; +	struct sk_buff_head rx_compl_q; + +	/* rx_status template */ +	struct ieee80211_rx_status rx_status;  };  #define RX_HTT_HDR_STATUS_LEN 64 @@ -1308,6 +1316,10 @@ struct htt_rx_desc {  #define HTT_RX_BUF_SIZE 1920  #define HTT_RX_MSDU_SIZE (HTT_RX_BUF_SIZE - (int)sizeof(struct htt_rx_desc)) +/* Refill a bunch of RX buffers for each refill round so that FW/HW can handle + * aggregated traffic more nicely. */ +#define ATH10K_HTT_MAX_NUM_REFILL 16 +  /*   * DMA_MAP expects the buffer to be an integral number of cache lines.   * Rather than checking the actual cache line size, this code makes a @@ -1316,17 +1328,20 @@ struct htt_rx_desc {  #define HTT_LOG2_MAX_CACHE_LINE_SIZE 7	/* 2^7 = 128 */  #define HTT_MAX_CACHE_LINE_SIZE_MASK ((1 << HTT_LOG2_MAX_CACHE_LINE_SIZE) - 1) -int ath10k_htt_attach(struct ath10k *ar); -int ath10k_htt_attach_target(struct ath10k_htt *htt); -void ath10k_htt_detach(struct ath10k_htt *htt); +int ath10k_htt_connect(struct ath10k_htt *htt); +int ath10k_htt_init(struct ath10k *ar); +int ath10k_htt_setup(struct ath10k_htt *htt); + +int ath10k_htt_tx_alloc(struct ath10k_htt *htt); +void ath10k_htt_tx_free(struct ath10k_htt *htt); + +int ath10k_htt_rx_alloc(struct ath10k_htt *htt); +void ath10k_htt_rx_free(struct ath10k_htt *htt); -int ath10k_htt_tx_attach(struct ath10k_htt *htt); -void ath10k_htt_tx_detach(struct ath10k_htt *htt); -int ath10k_htt_rx_attach(struct ath10k_htt *htt); -void ath10k_htt_rx_detach(struct ath10k_htt *htt);  void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb);  void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb);  int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt); +int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie);  int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt);  void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt); @@ -1334,4 +1349,5 @@ int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt);  void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id);  int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *);  int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *); +  #endif diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index e784c40b904..eebc860c365 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -20,6 +20,7 @@  #include "htt.h"  #include "txrx.h"  #include "debug.h" +#include "trace.h"  #include <linux/log2.h> @@ -40,6 +41,10 @@  /* when under memory pressure rx ring refill may fail and needs a retry */  #define HTT_RX_RING_REFILL_RETRY_MS 50 + +static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb); +static void ath10k_htt_txrx_compl_task(unsigned long ptr); +  static int ath10k_htt_rx_ring_size(struct ath10k_htt *htt)  {  	int size; @@ -177,10 +182,27 @@ static int ath10k_htt_rx_ring_fill_n(struct ath10k_htt *htt, int num)  static void ath10k_htt_rx_msdu_buff_replenish(struct ath10k_htt *htt)  { -	int ret, num_to_fill; +	int ret, num_deficit, num_to_fill; +	/* Refilling the whole RX ring buffer proves to be a bad idea. The +	 * reason is RX may take up significant amount of CPU cycles and starve +	 * other tasks, e.g. TX on an ethernet device while acting as a bridge +	 * with ath10k wlan interface. This ended up with very poor performance +	 * once CPU the host system was overwhelmed with RX on ath10k. +	 * +	 * By limiting the number of refills the replenishing occurs +	 * progressively. This in turns makes use of the fact tasklets are +	 * processed in FIFO order. This means actual RX processing can starve +	 * out refilling. If there's not enough buffers on RX ring FW will not +	 * report RX until it is refilled with enough buffers. This +	 * automatically balances load wrt to CPU power. +	 * +	 * This probably comes at a cost of lower maximum throughput but +	 * improves the avarage and stability. */  	spin_lock_bh(&htt->rx_ring.lock); -	num_to_fill = htt->rx_ring.fill_level - htt->rx_ring.fill_cnt; +	num_deficit = htt->rx_ring.fill_level - htt->rx_ring.fill_cnt; +	num_to_fill = min(ATH10K_HTT_MAX_NUM_REFILL, num_deficit); +	num_deficit -= num_to_fill;  	ret = ath10k_htt_rx_ring_fill_n(htt, num_to_fill);  	if (ret == -ENOMEM) {  		/* @@ -191,6 +213,8 @@ static void ath10k_htt_rx_msdu_buff_replenish(struct ath10k_htt *htt)  		 */  		mod_timer(&htt->rx_ring.refill_retry_timer, jiffies +  			  msecs_to_jiffies(HTT_RX_RING_REFILL_RETRY_MS)); +	} else if (num_deficit > 0) { +		tasklet_schedule(&htt->rx_replenish_task);  	}  	spin_unlock_bh(&htt->rx_ring.lock);  } @@ -201,30 +225,34 @@ static void ath10k_htt_rx_ring_refill_retry(unsigned long arg)  	ath10k_htt_rx_msdu_buff_replenish(htt);  } -static unsigned ath10k_htt_rx_ring_elems(struct ath10k_htt *htt) +static void ath10k_htt_rx_ring_clean_up(struct ath10k_htt *htt)  { -	return (__le32_to_cpu(*htt->rx_ring.alloc_idx.vaddr) - -		htt->rx_ring.sw_rd_idx.msdu_payld) & htt->rx_ring.size_mask; +	struct sk_buff *skb; +	int i; + +	for (i = 0; i < htt->rx_ring.size; i++) { +		skb = htt->rx_ring.netbufs_ring[i]; +		if (!skb) +			continue; + +		dma_unmap_single(htt->ar->dev, ATH10K_SKB_CB(skb)->paddr, +				 skb->len + skb_tailroom(skb), +				 DMA_FROM_DEVICE); +		dev_kfree_skb_any(skb); +		htt->rx_ring.netbufs_ring[i] = NULL; +	}  } -void ath10k_htt_rx_detach(struct ath10k_htt *htt) +void ath10k_htt_rx_free(struct ath10k_htt *htt)  { -	int sw_rd_idx = htt->rx_ring.sw_rd_idx.msdu_payld; -  	del_timer_sync(&htt->rx_ring.refill_retry_timer); +	tasklet_kill(&htt->rx_replenish_task); +	tasklet_kill(&htt->txrx_compl_task); -	while (sw_rd_idx != __le32_to_cpu(*(htt->rx_ring.alloc_idx.vaddr))) { -		struct sk_buff *skb = -				htt->rx_ring.netbufs_ring[sw_rd_idx]; -		struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb); +	skb_queue_purge(&htt->tx_compl_q); +	skb_queue_purge(&htt->rx_compl_q); -		dma_unmap_single(htt->ar->dev, cb->paddr, -				 skb->len + skb_tailroom(skb), -				 DMA_FROM_DEVICE); -		dev_kfree_skb_any(htt->rx_ring.netbufs_ring[sw_rd_idx]); -		sw_rd_idx++; -		sw_rd_idx &= htt->rx_ring.size_mask; -	} +	ath10k_htt_rx_ring_clean_up(htt);  	dma_free_coherent(htt->ar->dev,  			  (htt->rx_ring.size * @@ -245,20 +273,22 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt)  	int idx;  	struct sk_buff *msdu; -	spin_lock_bh(&htt->rx_ring.lock); +	lockdep_assert_held(&htt->rx_ring.lock); -	if (ath10k_htt_rx_ring_elems(htt) == 0) -		ath10k_warn("htt rx ring is empty!\n"); +	if (htt->rx_ring.fill_cnt == 0) { +		ath10k_warn("tried to pop sk_buff from an empty rx ring\n"); +		return NULL; +	}  	idx = htt->rx_ring.sw_rd_idx.msdu_payld;  	msdu = htt->rx_ring.netbufs_ring[idx]; +	htt->rx_ring.netbufs_ring[idx] = NULL;  	idx++;  	idx &= htt->rx_ring.size_mask;  	htt->rx_ring.sw_rd_idx.msdu_payld = idx;  	htt->rx_ring.fill_cnt--; -	spin_unlock_bh(&htt->rx_ring.lock);  	return msdu;  } @@ -273,6 +303,7 @@ static void ath10k_htt_rx_free_msdu_chain(struct sk_buff *skb)  	}  } +/* return: < 0 fatal error, 0 - non chained msdu, 1 chained msdu */  static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,  				   u8 **fw_desc, int *fw_desc_len,  				   struct sk_buff **head_msdu, @@ -282,12 +313,11 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,  	struct sk_buff *msdu;  	struct htt_rx_desc *rx_desc; -	if (ath10k_htt_rx_ring_elems(htt) == 0) -		ath10k_warn("htt rx ring is empty!\n"); +	lockdep_assert_held(&htt->rx_ring.lock);  	if (htt->rx_confused) {  		ath10k_warn("htt is confused. refusing rx\n"); -		return 0; +		return -1;  	}  	msdu = *head_msdu = ath10k_htt_rx_netbuf_pop(htt); @@ -299,7 +329,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,  				 msdu->len + skb_tailroom(msdu),  				 DMA_FROM_DEVICE); -		ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx: ", +		ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx pop: ",  				msdu->data, msdu->len + skb_tailroom(msdu));  		rx_desc = (struct htt_rx_desc *)msdu->data; @@ -392,8 +422,8 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,  					 next->len + skb_tailroom(next),  					 DMA_FROM_DEVICE); -			ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx: ", -					next->data, +			ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, +					"htt rx chained: ", next->data,  					next->len + skb_tailroom(next));  			skb_trim(next, 0); @@ -405,12 +435,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,  			msdu_chaining = 1;  		} -		if (msdu_len > 0) { -			/* This may suggest FW bug? */ -			ath10k_warn("htt rx msdu len not consumed (%d)\n", -				    msdu_len); -		} -  		last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) &  				RX_MSDU_END_INFO0_LAST_MSDU; @@ -425,6 +449,9 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,  	}  	*tail_msdu = msdu; +	if (*head_msdu == NULL) +		msdu_chaining = -1; +  	/*  	 * Don't refill the ring yet.  	 * @@ -441,7 +468,13 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,  	return msdu_chaining;  } -int ath10k_htt_rx_attach(struct ath10k_htt *htt) +static void ath10k_htt_rx_replenish_task(unsigned long ptr) +{ +	struct ath10k_htt *htt = (struct ath10k_htt *)ptr; +	ath10k_htt_rx_msdu_buff_replenish(htt); +} + +int ath10k_htt_rx_alloc(struct ath10k_htt *htt)  {  	dma_addr_t paddr;  	void *vaddr; @@ -467,7 +500,7 @@ int ath10k_htt_rx_attach(struct ath10k_htt *htt)  	htt->rx_ring.fill_level = ath10k_htt_rx_ring_fill_level(htt);  	htt->rx_ring.netbufs_ring = -		kmalloc(htt->rx_ring.size * sizeof(struct sk_buff *), +		kzalloc(htt->rx_ring.size * sizeof(struct sk_buff *),  			GFP_KERNEL);  	if (!htt->rx_ring.netbufs_ring)  		goto err_netbuf; @@ -501,7 +534,16 @@ int ath10k_htt_rx_attach(struct ath10k_htt *htt)  	if (__ath10k_htt_rx_ring_fill_n(htt, htt->rx_ring.fill_level))  		goto err_fill_ring; -	ath10k_dbg(ATH10K_DBG_HTT, "HTT RX ring size: %d, fill_level: %d\n", +	tasklet_init(&htt->rx_replenish_task, ath10k_htt_rx_replenish_task, +		     (unsigned long)htt); + +	skb_queue_head_init(&htt->tx_compl_q); +	skb_queue_head_init(&htt->rx_compl_q); + +	tasklet_init(&htt->txrx_compl_task, ath10k_htt_txrx_compl_task, +		     (unsigned long)htt); + +	ath10k_dbg(ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n",  		   htt->rx_ring.size, htt->rx_ring.fill_level);  	return 0; @@ -590,138 +632,342 @@ static bool ath10k_htt_rx_hdr_is_amsdu(struct ieee80211_hdr *hdr)  	return false;  } -static int ath10k_htt_rx_amsdu(struct ath10k_htt *htt, -			struct htt_rx_info *info) +struct rfc1042_hdr { +	u8 llc_dsap; +	u8 llc_ssap; +	u8 llc_ctrl; +	u8 snap_oui[3]; +	__be16 snap_type; +} __packed; + +struct amsdu_subframe_hdr { +	u8 dst[ETH_ALEN]; +	u8 src[ETH_ALEN]; +	__be16 len; +} __packed; + +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 ath10k_htt_rx_h_rates(struct ath10k *ar, +				  enum ieee80211_band band, +				  u8 info0, u32 info1, u32 info2, +				  struct ieee80211_rx_status *status) +{ +	u8 cck, rate, rate_idx, bw, sgi, mcs, nss; +	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) + 1; +		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->vht_flag |= RX_VHT_FLAG_80MHZ; +		} + +		status->flag |= RX_FLAG_VHT; +		break; +	default: +		break; +	} +} + +static void ath10k_htt_rx_h_protected(struct ath10k_htt *htt, +				      struct ieee80211_rx_status *rx_status, +				      struct sk_buff *skb, +				      enum htt_rx_mpdu_encrypt_type enctype, +				      enum rx_msdu_decap_format fmt, +				      bool dot11frag) +{ +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + +	rx_status->flag &= ~(RX_FLAG_DECRYPTED | +			     RX_FLAG_IV_STRIPPED | +			     RX_FLAG_MMIC_STRIPPED); + +	if (enctype == HTT_RX_MPDU_ENCRYPT_NONE) +		return; + +	/* +	 * There's no explicit rx descriptor flag to indicate whether a given +	 * frame has been decrypted or not. We're forced to use the decap +	 * format as an implicit indication. However fragmentation rx is always +	 * raw and it probably never reports undecrypted raws. +	 * +	 * This makes sure sniffed frames are reported as-is without stripping +	 * the protected flag. +	 */ +	if (fmt == RX_MSDU_DECAP_RAW && !dot11frag) +		return; + +	rx_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); +} + +static bool ath10k_htt_rx_h_channel(struct ath10k *ar, +				    struct ieee80211_rx_status *status) +{ +	struct ieee80211_channel *ch; + +	spin_lock_bh(&ar->data_lock); +	ch = ar->scan_channel; +	if (!ch) +		ch = ar->rx_channel; +	spin_unlock_bh(&ar->data_lock); + +	if (!ch) +		return false; + +	status->band = ch->band; +	status->freq = ch->center_freq; + +	return true; +} + +static void ath10k_process_rx(struct ath10k *ar, +			      struct ieee80211_rx_status *rx_status, +			      struct sk_buff *skb) +{ +	struct ieee80211_rx_status *status; + +	status = IEEE80211_SKB_RXCB(skb); +	*status = *rx_status; + +	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 flag 0x%x fcs-err %imic-err %i\n", +		   skb, +		   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->vht_flag & RX_VHT_FLAG_80MHZ ? "80" : "", +		   status->flag & RX_FLAG_SHORT_GI ? "sgi " : "", +		   status->rate_idx, +		   status->vht_nss, +		   status->freq, +		   status->band, status->flag, +		   !!(status->flag & RX_FLAG_FAILED_FCS_CRC), +		   !!(status->flag & RX_FLAG_MMIC_ERROR)); +	ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ", +			skb->data, skb->len); + +	ieee80211_rx(ar->hw, skb); +} + +static int ath10k_htt_rx_nwifi_hdrlen(struct ieee80211_hdr *hdr) +{ +	/* nwifi header is padded to 4 bytes. this fixes 4addr rx */ +	return round_up(ieee80211_hdrlen(hdr->frame_control), 4); +} + +static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt, +				struct ieee80211_rx_status *rx_status, +				struct sk_buff *skb_in)  {  	struct htt_rx_desc *rxd; -	struct sk_buff *amsdu; +	struct sk_buff *skb = skb_in;  	struct sk_buff *first; -	struct ieee80211_hdr *hdr; -	struct sk_buff *skb = info->skb;  	enum rx_msdu_decap_format fmt;  	enum htt_rx_mpdu_encrypt_type enctype; +	struct ieee80211_hdr *hdr; +	u8 hdr_buf[64], addr[ETH_ALEN], *qos;  	unsigned int hdr_len; -	int crypto_len;  	rxd = (void *)skb->data - sizeof(*rxd); -	fmt = MS(__le32_to_cpu(rxd->msdu_start.info1), -			RX_MSDU_START_INFO1_DECAP_FORMAT);  	enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0),  			RX_MPDU_START_INFO0_ENCRYPT_TYPE); -	/* FIXME: No idea what assumptions are safe here. Need logs */ -	if ((fmt == RX_MSDU_DECAP_RAW && skb->next) || -	    (fmt == RX_MSDU_DECAP_8023_SNAP_LLC)) { -		ath10k_htt_rx_free_msdu_chain(skb->next); -		skb->next = NULL; -		return -ENOTSUPP; -	} - -	/* A-MSDU max is a little less than 8K */ -	amsdu = dev_alloc_skb(8*1024); -	if (!amsdu) { -		ath10k_warn("A-MSDU allocation failed\n"); -		ath10k_htt_rx_free_msdu_chain(skb->next); -		skb->next = NULL; -		return -ENOMEM; -	} - -	if (fmt >= RX_MSDU_DECAP_NATIVE_WIFI) { -		int hdrlen; - -		hdr = (void *)rxd->rx_hdr_status; -		hdrlen = ieee80211_hdrlen(hdr->frame_control); -		memcpy(skb_put(amsdu, hdrlen), hdr, hdrlen); -	} +	hdr = (struct ieee80211_hdr *)rxd->rx_hdr_status; +	hdr_len = ieee80211_hdrlen(hdr->frame_control); +	memcpy(hdr_buf, hdr, hdr_len); +	hdr = (struct ieee80211_hdr *)hdr_buf;  	first = skb;  	while (skb) {  		void *decap_hdr; -		int decap_len = 0; +		int len;  		rxd = (void *)skb->data - sizeof(*rxd);  		fmt = MS(__le32_to_cpu(rxd->msdu_start.info1), -				RX_MSDU_START_INFO1_DECAP_FORMAT); +			 RX_MSDU_START_INFO1_DECAP_FORMAT);  		decap_hdr = (void *)rxd->rx_hdr_status; -		if (skb == first) { -			/* We receive linked A-MSDU subframe skbuffs. The -			 * first one contains the original 802.11 header (and -			 * possible crypto param) in the RX descriptor. The -			 * A-MSDU subframe header follows that. Each part is -			 * aligned to 4 byte boundary. */ - -			hdr = (void *)amsdu->data; -			hdr_len = ieee80211_hdrlen(hdr->frame_control); -			crypto_len = ath10k_htt_rx_crypto_param_len(enctype); - -			decap_hdr += roundup(hdr_len, 4); -			decap_hdr += roundup(crypto_len, 4); -		} - -		if (fmt == RX_MSDU_DECAP_ETHERNET2_DIX) { -			/* Ethernet2 decap inserts ethernet header in place of -			 * A-MSDU subframe header. */ -			skb_pull(skb, 6 + 6 + 2); +		skb->ip_summed = ath10k_htt_rx_get_csum_state(skb); -			/* A-MSDU subframe header length */ -			decap_len += 6 + 6 + 2; - -			/* Ethernet2 decap also strips the LLC/SNAP so we need -			 * to re-insert it. The LLC/SNAP follows A-MSDU -			 * subframe header. */ -			/* FIXME: Not all LLCs are 8 bytes long */ -			decap_len += 8; - -			memcpy(skb_put(amsdu, decap_len), decap_hdr, decap_len); +		/* First frame in an A-MSDU chain has more decapped data. */ +		if (skb == first) { +			len = round_up(ieee80211_hdrlen(hdr->frame_control), 4); +			len += round_up(ath10k_htt_rx_crypto_param_len(enctype), +					4); +			decap_hdr += len;  		} -		if (fmt == RX_MSDU_DECAP_NATIVE_WIFI) { -			/* Native Wifi decap inserts regular 802.11 header -			 * in place of A-MSDU subframe header. */ +		switch (fmt) { +		case RX_MSDU_DECAP_RAW: +			/* remove trailing FCS */ +			skb_trim(skb, skb->len - FCS_LEN); +			break; +		case RX_MSDU_DECAP_NATIVE_WIFI: +			/* pull decapped header and copy DA */  			hdr = (struct ieee80211_hdr *)skb->data; -			skb_pull(skb, ieee80211_hdrlen(hdr->frame_control)); +			hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr); +			memcpy(addr, ieee80211_get_DA(hdr), ETH_ALEN); +			skb_pull(skb, hdr_len); -			/* A-MSDU subframe header length */ -			decap_len += 6 + 6 + 2; +			/* push original 802.11 header */ +			hdr = (struct ieee80211_hdr *)hdr_buf; +			hdr_len = ieee80211_hdrlen(hdr->frame_control); +			memcpy(skb_push(skb, hdr_len), hdr, hdr_len); -			memcpy(skb_put(amsdu, decap_len), decap_hdr, decap_len); -		} +			/* original A-MSDU header has the bit set but we're +			 * not including A-MSDU subframe header */ +			hdr = (struct ieee80211_hdr *)skb->data; +			qos = ieee80211_get_qos_ctl(hdr); +			qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; -		if (fmt == RX_MSDU_DECAP_RAW) -			skb_trim(skb, skb->len - 4); /* remove FCS */ +			/* original 802.11 header has a different DA */ +			memcpy(ieee80211_get_DA(hdr), addr, ETH_ALEN); +			break; +		case RX_MSDU_DECAP_ETHERNET2_DIX: +			/* strip ethernet header and insert decapped 802.11 +			 * header, amsdu subframe header and rfc1042 header */ -		memcpy(skb_put(amsdu, skb->len), skb->data, skb->len); +			len = 0; +			len += sizeof(struct rfc1042_hdr); +			len += sizeof(struct amsdu_subframe_hdr); -		/* A-MSDU subframes are padded to 4bytes -		 * but relative to first subframe, not the whole MPDU */ -		if (skb->next && ((decap_len + skb->len) & 3)) { -			int padlen = 4 - ((decap_len + skb->len) & 3); -			memset(skb_put(amsdu, padlen), 0, padlen); +			skb_pull(skb, sizeof(struct ethhdr)); +			memcpy(skb_push(skb, len), decap_hdr, len); +			memcpy(skb_push(skb, hdr_len), hdr, hdr_len); +			break; +		case RX_MSDU_DECAP_8023_SNAP_LLC: +			/* insert decapped 802.11 header making a singly +			 * A-MSDU */ +			memcpy(skb_push(skb, hdr_len), hdr, hdr_len); +			break;  		} +		skb_in = skb; +		ath10k_htt_rx_h_protected(htt, rx_status, skb_in, enctype, fmt, +					  false);  		skb = skb->next; -	} +		skb_in->next = NULL; -	info->skb = amsdu; -	info->encrypt_type = enctype; +		if (skb) +			rx_status->flag |= RX_FLAG_AMSDU_MORE; +		else +			rx_status->flag &= ~RX_FLAG_AMSDU_MORE; -	ath10k_htt_rx_free_msdu_chain(first); +		ath10k_process_rx(htt->ar, rx_status, skb_in); +	} -	return 0; +	/* FIXME: It might be nice to re-assemble the A-MSDU when there's a +	 * monitor interface active for sniffing purposes. */  } -static int ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct htt_rx_info *info) +static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, +			       struct ieee80211_rx_status *rx_status, +			       struct sk_buff *skb)  { -	struct sk_buff *skb = info->skb;  	struct htt_rx_desc *rxd;  	struct ieee80211_hdr *hdr;  	enum rx_msdu_decap_format fmt;  	enum htt_rx_mpdu_encrypt_type enctype; +	int hdr_len; +	void *rfc1042;  	/* This shouldn't happen. If it does than it may be a FW bug. */  	if (skb->next) { -		ath10k_warn("received chained non A-MSDU frame\n"); +		ath10k_warn("htt rx received chained non A-MSDU frame\n");  		ath10k_htt_rx_free_msdu_chain(skb->next);  		skb->next = NULL;  	} @@ -731,77 +977,52 @@ static int ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct htt_rx_info *info)  			RX_MSDU_START_INFO1_DECAP_FORMAT);  	enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0),  			RX_MPDU_START_INFO0_ENCRYPT_TYPE); -	hdr = (void *)skb->data - RX_HTT_HDR_STATUS_LEN; +	hdr = (struct ieee80211_hdr *)rxd->rx_hdr_status; +	hdr_len = ieee80211_hdrlen(hdr->frame_control); + +	skb->ip_summed = ath10k_htt_rx_get_csum_state(skb);  	switch (fmt) {  	case RX_MSDU_DECAP_RAW:  		/* remove trailing FCS */ -		skb_trim(skb, skb->len - 4); +		skb_trim(skb, skb->len - FCS_LEN);  		break;  	case RX_MSDU_DECAP_NATIVE_WIFI: -		/* nothing to do here */ +		/* Pull decapped header */ +		hdr = (struct ieee80211_hdr *)skb->data; +		hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr); +		skb_pull(skb, hdr_len); + +		/* Push original header */ +		hdr = (struct ieee80211_hdr *)rxd->rx_hdr_status; +		hdr_len = ieee80211_hdrlen(hdr->frame_control); +		memcpy(skb_push(skb, hdr_len), hdr, hdr_len);  		break;  	case RX_MSDU_DECAP_ETHERNET2_DIX: -		/* macaddr[6] + macaddr[6] + ethertype[2] */ -		skb_pull(skb, 6 + 6 + 2); -		break; -	case RX_MSDU_DECAP_8023_SNAP_LLC: -		/* macaddr[6] + macaddr[6] + len[2] */ -		/* we don't need this for non-A-MSDU */ -		skb_pull(skb, 6 + 6 + 2); -		break; -	} +		/* strip ethernet header and insert decapped 802.11 header and +		 * rfc1042 header */ -	if (fmt == RX_MSDU_DECAP_ETHERNET2_DIX) { -		void *llc; -		int llclen; +		rfc1042 = hdr; +		rfc1042 += roundup(hdr_len, 4); +		rfc1042 += roundup(ath10k_htt_rx_crypto_param_len(enctype), 4); -		llclen = 8; -		llc  = hdr; -		llc += roundup(ieee80211_hdrlen(hdr->frame_control), 4); -		llc += roundup(ath10k_htt_rx_crypto_param_len(enctype), 4); +		skb_pull(skb, sizeof(struct ethhdr)); +		memcpy(skb_push(skb, sizeof(struct rfc1042_hdr)), +		       rfc1042, sizeof(struct rfc1042_hdr)); +		memcpy(skb_push(skb, hdr_len), hdr, hdr_len); +		break; +	case RX_MSDU_DECAP_8023_SNAP_LLC: +		/* remove A-MSDU subframe header and insert +		 * decapped 802.11 header. rfc1042 header is already there */ -		skb_push(skb, llclen); -		memcpy(skb->data, llc, llclen); +		skb_pull(skb, sizeof(struct amsdu_subframe_hdr)); +		memcpy(skb_push(skb, hdr_len), hdr, hdr_len); +		break;  	} -	if (fmt >= RX_MSDU_DECAP_ETHERNET2_DIX) { -		int len = ieee80211_hdrlen(hdr->frame_control); -		skb_push(skb, len); -		memcpy(skb->data, hdr, len); -	} +	ath10k_htt_rx_h_protected(htt, rx_status, skb, enctype, fmt, false); -	info->skb = skb; -	info->encrypt_type = enctype; -	return 0; -} - -static bool ath10k_htt_rx_has_decrypt_err(struct sk_buff *skb) -{ -	struct htt_rx_desc *rxd; -	u32 flags; - -	rxd = (void *)skb->data - sizeof(*rxd); -	flags = __le32_to_cpu(rxd->attention.flags); - -	if (flags & RX_ATTENTION_FLAGS_DECRYPT_ERR) -		return true; - -	return false; -} - -static bool ath10k_htt_rx_has_fcs_err(struct sk_buff *skb) -{ -	struct htt_rx_desc *rxd; -	u32 flags; - -	rxd = (void *)skb->data - sizeof(*rxd); -	flags = __le32_to_cpu(rxd->attention.flags); - -	if (flags & RX_ATTENTION_FLAGS_FCS_ERR) -		return true; - -	return false; +	ath10k_process_rx(htt->ar, rx_status, skb);  }  static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb) @@ -835,20 +1056,123 @@ static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb)  	return CHECKSUM_UNNECESSARY;  } +static int ath10k_unchain_msdu(struct sk_buff *msdu_head) +{ +	struct sk_buff *next = msdu_head->next; +	struct sk_buff *to_free = next; +	int space; +	int total_len = 0; + +	/* TODO:  Might could optimize this by using +	 * skb_try_coalesce or similar method to +	 * decrease copying, or maybe get mac80211 to +	 * provide a way to just receive a list of +	 * skb? +	 */ + +	msdu_head->next = NULL; + +	/* Allocate total length all at once. */ +	while (next) { +		total_len += next->len; +		next = next->next; +	} + +	space = total_len - skb_tailroom(msdu_head); +	if ((space > 0) && +	    (pskb_expand_head(msdu_head, 0, space, GFP_ATOMIC) < 0)) { +		/* TODO:  bump some rx-oom error stat */ +		/* put it back together so we can free the +		 * whole list at once. +		 */ +		msdu_head->next = to_free; +		return -1; +	} + +	/* Walk list again, copying contents into +	 * msdu_head +	 */ +	next = to_free; +	while (next) { +		skb_copy_from_linear_data(next, skb_put(msdu_head, next->len), +					  next->len); +		next = next->next; +	} + +	/* If here, we have consolidated skb.  Free the +	 * fragments and pass the main skb on up the +	 * stack. +	 */ +	ath10k_htt_rx_free_msdu_chain(to_free); +	return 0; +} + +static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt, +					struct sk_buff *head, +					enum htt_rx_mpdu_status status, +					bool channel_set, +					u32 attention) +{ +	if (head->len == 0) { +		ath10k_dbg(ATH10K_DBG_HTT, +			   "htt rx dropping due to zero-len\n"); +		return false; +	} + +	if (attention & RX_ATTENTION_FLAGS_DECRYPT_ERR) { +		ath10k_dbg(ATH10K_DBG_HTT, +			   "htt rx dropping due to decrypt-err\n"); +		return false; +	} + +	if (!channel_set) { +		ath10k_warn("no channel configured; ignoring frame!\n"); +		return false; +	} + +	/* Skip mgmt frames while we handle this in WMI */ +	if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL || +	    attention & RX_ATTENTION_FLAGS_MGMT_TYPE) { +		ath10k_dbg(ATH10K_DBG_HTT, "htt rx mgmt ctrl\n"); +		return false; +	} + +	if (status != HTT_RX_IND_MPDU_STATUS_OK && +	    status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR && +	    status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER && +	    !htt->ar->monitor_started) { +		ath10k_dbg(ATH10K_DBG_HTT, +			   "htt rx ignoring frame w/ status %d\n", +			   status); +		return false; +	} + +	if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) { +		ath10k_dbg(ATH10K_DBG_HTT, +			   "htt rx CAC running\n"); +		return false; +	} + +	return true; +} +  static void ath10k_htt_rx_handler(struct ath10k_htt *htt,  				  struct htt_rx_indication *rx)  { -	struct htt_rx_info info; +	struct ieee80211_rx_status *rx_status = &htt->rx_status;  	struct htt_rx_indication_mpdu_range *mpdu_ranges; +	struct htt_rx_desc *rxd; +	enum htt_rx_mpdu_status status;  	struct ieee80211_hdr *hdr;  	int num_mpdu_ranges; +	u32 attention;  	int fw_desc_len;  	u8 *fw_desc; +	bool channel_set;  	int i, j;  	int ret; -	int ip_summed; -	memset(&info, 0, sizeof(info)); +	lockdep_assert_held(&htt->rx_ring.lock);  	fw_desc_len = __le16_to_cpu(rx->prefix.fw_rx_desc_bytes);  	fw_desc = (u8 *)&rx->fw_desc; @@ -857,120 +1181,106 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,  			     HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES);  	mpdu_ranges = htt_rx_ind_get_mpdu_ranges(rx); +	/* Fill this once, while this is per-ppdu */ +	if (rx->ppdu.info0 & HTT_RX_INDICATION_INFO0_START_VALID) { +		memset(rx_status, 0, sizeof(*rx_status)); +		rx_status->signal  = ATH10K_DEFAULT_NOISE_FLOOR + +				     rx->ppdu.combined_rssi; +	} + +	if (rx->ppdu.info0 & HTT_RX_INDICATION_INFO0_END_VALID) { +		/* TSF available only in 32-bit */ +		rx_status->mactime = __le32_to_cpu(rx->ppdu.tsf) & 0xffffffff; +		rx_status->flag |= RX_FLAG_MACTIME_END; +	} + +	channel_set = ath10k_htt_rx_h_channel(htt->ar, rx_status); + +	if (channel_set) { +		ath10k_htt_rx_h_rates(htt->ar, rx_status->band, +				      rx->ppdu.info0, +				      __le32_to_cpu(rx->ppdu.info1), +				      __le32_to_cpu(rx->ppdu.info2), +				      rx_status); +	} +  	ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ",  			rx, sizeof(*rx) +  			(sizeof(struct htt_rx_indication_mpdu_range) *  				num_mpdu_ranges));  	for (i = 0; i < num_mpdu_ranges; i++) { -		info.status = mpdu_ranges[i].mpdu_range_status; +		status = mpdu_ranges[i].mpdu_range_status;  		for (j = 0; j < mpdu_ranges[i].mpdu_count; j++) {  			struct sk_buff *msdu_head, *msdu_tail; -			enum htt_rx_mpdu_status status; -			int msdu_chaining;  			msdu_head = NULL;  			msdu_tail = NULL; -			msdu_chaining = ath10k_htt_rx_amsdu_pop(htt, -							 &fw_desc, -							 &fw_desc_len, -							 &msdu_head, -							 &msdu_tail); - -			if (!msdu_head) { -				ath10k_warn("htt rx no data!\n"); -				continue; -			} - -			if (msdu_head->len == 0) { -				ath10k_dbg(ATH10K_DBG_HTT, -					   "htt rx dropping due to zero-len\n"); +			ret = ath10k_htt_rx_amsdu_pop(htt, +						      &fw_desc, +						      &fw_desc_len, +						      &msdu_head, +						      &msdu_tail); + +			if (ret < 0) { +				ath10k_warn("failed to pop amsdu from htt rx ring %d\n", +					    ret);  				ath10k_htt_rx_free_msdu_chain(msdu_head);  				continue;  			} -			if (ath10k_htt_rx_has_decrypt_err(msdu_head)) { -				ath10k_htt_rx_free_msdu_chain(msdu_head); -				continue; -			} +			rxd = container_of((void *)msdu_head->data, +					   struct htt_rx_desc, +					   msdu_payload); +			attention = __le32_to_cpu(rxd->attention.flags); -			status = info.status; - -			/* Skip mgmt frames while we handle this in WMI */ -			if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL) { +			if (!ath10k_htt_rx_amsdu_allowed(htt, msdu_head, +							 status, +							 channel_set, +							 attention)) {  				ath10k_htt_rx_free_msdu_chain(msdu_head);  				continue;  			} -			if (status != HTT_RX_IND_MPDU_STATUS_OK && -			    status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR && -			    !htt->ar->monitor_enabled) { -				ath10k_dbg(ATH10K_DBG_HTT, -					   "htt rx ignoring frame w/ status %d\n", -					   status); +			if (ret > 0 && +			    ath10k_unchain_msdu(msdu_head) < 0) {  				ath10k_htt_rx_free_msdu_chain(msdu_head);  				continue;  			} -			/* FIXME: we do not support chaining yet. -			 * this needs investigation */ -			if (msdu_chaining) { -				ath10k_warn("msdu_chaining is true\n"); -				ath10k_htt_rx_free_msdu_chain(msdu_head); -				continue; -			} - -			/* The skb is not yet processed and it may be -			 * reallocated. Since the offload is in the original -			 * skb extract the checksum now and assign it later */ -			ip_summed = ath10k_htt_rx_get_csum_state(msdu_head); - -			info.skb     = msdu_head; -			info.fcs_err = ath10k_htt_rx_has_fcs_err(msdu_head); -			info.signal  = ATH10K_DEFAULT_NOISE_FLOOR; -			info.signal += rx->ppdu.combined_rssi; +			if (attention & RX_ATTENTION_FLAGS_FCS_ERR) +				rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; +			else +				rx_status->flag &= ~RX_FLAG_FAILED_FCS_CRC; -			info.rate.info0 = rx->ppdu.info0; -			info.rate.info1 = __le32_to_cpu(rx->ppdu.info1); -			info.rate.info2 = __le32_to_cpu(rx->ppdu.info2); +			if (attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR) +				rx_status->flag |= RX_FLAG_MMIC_ERROR; +			else +				rx_status->flag &= ~RX_FLAG_MMIC_ERROR;  			hdr = ath10k_htt_rx_skb_get_hdr(msdu_head);  			if (ath10k_htt_rx_hdr_is_amsdu(hdr)) -				ret = ath10k_htt_rx_amsdu(htt, &info); +				ath10k_htt_rx_amsdu(htt, rx_status, msdu_head);  			else -				ret = ath10k_htt_rx_msdu(htt, &info); - -			if (ret && !info.fcs_err) { -				ath10k_warn("error processing msdus %d\n", ret); -				dev_kfree_skb_any(info.skb); -				continue; -			} - -			if (ath10k_htt_rx_hdr_is_amsdu((void *)info.skb->data)) -				ath10k_dbg(ATH10K_DBG_HTT, "htt mpdu is amsdu\n"); - -			info.skb->ip_summed = ip_summed; - -			ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt mpdu: ", -					info.skb->data, info.skb->len); -			ath10k_process_rx(htt->ar, &info); +				ath10k_htt_rx_msdu(htt, rx_status, msdu_head);  		}  	} -	ath10k_htt_rx_msdu_buff_replenish(htt); +	tasklet_schedule(&htt->rx_replenish_task);  }  static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,  				struct htt_rx_fragment_indication *frag)  {  	struct sk_buff *msdu_head, *msdu_tail; +	enum htt_rx_mpdu_encrypt_type enctype;  	struct htt_rx_desc *rxd;  	enum rx_msdu_decap_format fmt; -	struct htt_rx_info info = {}; +	struct ieee80211_rx_status *rx_status = &htt->rx_status;  	struct ieee80211_hdr *hdr; -	int msdu_chaining; +	int ret;  	bool tkip_mic_err;  	bool decrypt_err;  	u8 *fw_desc; @@ -982,23 +1292,23 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,  	msdu_head = NULL;  	msdu_tail = NULL; -	msdu_chaining = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len, -						&msdu_head, &msdu_tail); -	ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n"); +	spin_lock_bh(&htt->rx_ring.lock); +	ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len, +				      &msdu_head, &msdu_tail); +	spin_unlock_bh(&htt->rx_ring.lock); -	if (!msdu_head) { -		ath10k_warn("htt rx frag no data\n"); -		return; -	} +	ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n"); -	if (msdu_chaining || msdu_head != msdu_tail) { -		ath10k_warn("aggregation with fragmentation?!\n"); +	if (ret) { +		ath10k_warn("failed to pop amsdu from httr rx ring for fragmented rx %d\n", +			    ret);  		ath10k_htt_rx_free_msdu_chain(msdu_head);  		return;  	}  	/* FIXME: implement signal strength */ +	rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;  	hdr = (struct ieee80211_hdr *)msdu_head->data;  	rxd = (void *)msdu_head->data - sizeof(*rxd); @@ -1015,57 +1325,55 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,  		goto end;  	} -	info.skb = msdu_head; -	info.status = HTT_RX_IND_MPDU_STATUS_OK; -	info.encrypt_type = MS(__le32_to_cpu(rxd->mpdu_start.info0), -				RX_MPDU_START_INFO0_ENCRYPT_TYPE); -	info.skb->ip_summed = ath10k_htt_rx_get_csum_state(info.skb); +	enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0), +		     RX_MPDU_START_INFO0_ENCRYPT_TYPE); +	ath10k_htt_rx_h_protected(htt, rx_status, msdu_head, enctype, fmt, +				  true); +	msdu_head->ip_summed = ath10k_htt_rx_get_csum_state(msdu_head); -	if (tkip_mic_err) { +	if (tkip_mic_err)  		ath10k_warn("tkip mic error\n"); -		info.status = HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR; -	}  	if (decrypt_err) {  		ath10k_warn("decryption err in fragmented rx\n"); -		dev_kfree_skb_any(info.skb); +		dev_kfree_skb_any(msdu_head);  		goto end;  	} -	if (info.encrypt_type != HTT_RX_MPDU_ENCRYPT_NONE) { +	if (enctype != HTT_RX_MPDU_ENCRYPT_NONE) {  		hdrlen = ieee80211_hdrlen(hdr->frame_control); -		paramlen = ath10k_htt_rx_crypto_param_len(info.encrypt_type); +		paramlen = ath10k_htt_rx_crypto_param_len(enctype);  		/* It is more efficient to move the header than the payload */ -		memmove((void *)info.skb->data + paramlen, -			(void *)info.skb->data, +		memmove((void *)msdu_head->data + paramlen, +			(void *)msdu_head->data,  			hdrlen); -		skb_pull(info.skb, paramlen); -		hdr = (struct ieee80211_hdr *)info.skb->data; +		skb_pull(msdu_head, paramlen); +		hdr = (struct ieee80211_hdr *)msdu_head->data;  	}  	/* remove trailing FCS */  	trim  = 4;  	/* remove crypto trailer */ -	trim += ath10k_htt_rx_crypto_tail_len(info.encrypt_type); +	trim += ath10k_htt_rx_crypto_tail_len(enctype);  	/* last fragment of TKIP frags has MIC */  	if (!ieee80211_has_morefrags(hdr->frame_control) && -	    info.encrypt_type == HTT_RX_MPDU_ENCRYPT_TKIP_WPA) +	    enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA)  		trim += 8; -	if (trim > info.skb->len) { +	if (trim > msdu_head->len) {  		ath10k_warn("htt rx fragment: trailer longer than the frame itself? drop\n"); -		dev_kfree_skb_any(info.skb); +		dev_kfree_skb_any(msdu_head);  		goto end;  	} -	skb_trim(info.skb, info.skb->len - trim); +	skb_trim(msdu_head, msdu_head->len - trim); -	ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt frag mpdu: ", -			info.skb->data, info.skb->len); -	ath10k_process_rx(htt->ar, &info); +	ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ", +			msdu_head->data, msdu_head->len); +	ath10k_process_rx(htt->ar, rx_status, msdu_head);  end:  	if (fw_desc_len > 0) { @@ -1075,6 +1383,45 @@ end:  	}  } +static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar, +				       struct sk_buff *skb) +{ +	struct ath10k_htt *htt = &ar->htt; +	struct htt_resp *resp = (struct htt_resp *)skb->data; +	struct htt_tx_done tx_done = {}; +	int status = MS(resp->data_tx_completion.flags, HTT_DATA_TX_STATUS); +	__le16 msdu_id; +	int i; + +	lockdep_assert_held(&htt->tx_lock); + +	switch (status) { +	case HTT_DATA_TX_STATUS_NO_ACK: +		tx_done.no_ack = true; +		break; +	case HTT_DATA_TX_STATUS_OK: +		break; +	case HTT_DATA_TX_STATUS_DISCARD: +	case HTT_DATA_TX_STATUS_POSTPONE: +	case HTT_DATA_TX_STATUS_DOWNLOAD_FAIL: +		tx_done.discard = true; +		break; +	default: +		ath10k_warn("unhandled tx completion status %d\n", status); +		tx_done.discard = true; +		break; +	} + +	ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n", +		   resp->data_tx_completion.num_msdus); + +	for (i = 0; i < resp->data_tx_completion.num_msdus; i++) { +		msdu_id = resp->data_tx_completion.msdus[i]; +		tx_done.msdu_id = __le16_to_cpu(msdu_id); +		ath10k_txrx_tx_unref(htt, &tx_done); +	} +} +  void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)  {  	struct ath10k_htt *htt = &ar->htt; @@ -1084,7 +1431,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)  	if (!IS_ALIGNED((unsigned long)skb->data, 4))  		ath10k_warn("unaligned htt message, expect trouble\n"); -	ath10k_dbg(ATH10K_DBG_HTT, "HTT RX, msg_type: 0x%0X\n", +	ath10k_dbg(ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n",  		   resp->hdr.msg_type);  	switch (resp->hdr.msg_type) {  	case HTT_T2H_MSG_TYPE_VERSION_CONF: { @@ -1093,10 +1440,12 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)  		complete(&htt->target_version_received);  		break;  	} -	case HTT_T2H_MSG_TYPE_RX_IND: { -		ath10k_htt_rx_handler(htt, &resp->rx_ind); -		break; -	} +	case HTT_T2H_MSG_TYPE_RX_IND: +		spin_lock_bh(&htt->rx_ring.lock); +		__skb_queue_tail(&htt->rx_compl_q, skb); +		spin_unlock_bh(&htt->rx_ring.lock); +		tasklet_schedule(&htt->txrx_compl_task); +		return;  	case HTT_T2H_MSG_TYPE_PEER_MAP: {  		struct htt_peer_map_event ev = {  			.vdev_id = resp->peer_map.vdev_id, @@ -1131,44 +1480,17 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)  			break;  		} -		ath10k_txrx_tx_completed(htt, &tx_done); -		break; -	} -	case HTT_T2H_MSG_TYPE_TX_COMPL_IND: { -		struct htt_tx_done tx_done = {}; -		int status = MS(resp->data_tx_completion.flags, -				HTT_DATA_TX_STATUS); -		__le16 msdu_id; -		int i; - -		switch (status) { -		case HTT_DATA_TX_STATUS_NO_ACK: -			tx_done.no_ack = true; -			break; -		case HTT_DATA_TX_STATUS_OK: -			break; -		case HTT_DATA_TX_STATUS_DISCARD: -		case HTT_DATA_TX_STATUS_POSTPONE: -		case HTT_DATA_TX_STATUS_DOWNLOAD_FAIL: -			tx_done.discard = true; -			break; -		default: -			ath10k_warn("unhandled tx completion status %d\n", -				    status); -			tx_done.discard = true; -			break; -		} - -		ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n", -			   resp->data_tx_completion.num_msdus); - -		for (i = 0; i < resp->data_tx_completion.num_msdus; i++) { -			msdu_id = resp->data_tx_completion.msdus[i]; -			tx_done.msdu_id = __le16_to_cpu(msdu_id); -			ath10k_txrx_tx_completed(htt, &tx_done); -		} +		spin_lock_bh(&htt->tx_lock); +		ath10k_txrx_tx_unref(htt, &tx_done); +		spin_unlock_bh(&htt->tx_lock);  		break;  	} +	case HTT_T2H_MSG_TYPE_TX_COMPL_IND: +		spin_lock_bh(&htt->tx_lock); +		__skb_queue_tail(&htt->tx_compl_q, skb); +		spin_unlock_bh(&htt->tx_lock); +		tasklet_schedule(&htt->txrx_compl_task); +		return;  	case HTT_T2H_MSG_TYPE_SEC_IND: {  		struct ath10k *ar = htt->ar;  		struct htt_security_indication *ev = &resp->security_indication; @@ -1190,8 +1512,10 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)  	case HTT_T2H_MSG_TYPE_TEST:  		/* FIX THIS */  		break; -	case HTT_T2H_MSG_TYPE_TX_INSPECT_IND:  	case HTT_T2H_MSG_TYPE_STATS_CONF: +		trace_ath10k_htt_stats(skb->data, skb->len); +		break; +	case HTT_T2H_MSG_TYPE_TX_INSPECT_IND:  	case HTT_T2H_MSG_TYPE_RX_ADDBA:  	case HTT_T2H_MSG_TYPE_RX_DELBA:  	case HTT_T2H_MSG_TYPE_RX_FLUSH: @@ -1206,3 +1530,25 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)  	/* Free the indication buffer */  	dev_kfree_skb_any(skb);  } + +static void ath10k_htt_txrx_compl_task(unsigned long ptr) +{ +	struct ath10k_htt *htt = (struct ath10k_htt *)ptr; +	struct htt_resp *resp; +	struct sk_buff *skb; + +	spin_lock_bh(&htt->tx_lock); +	while ((skb = __skb_dequeue(&htt->tx_compl_q))) { +		ath10k_htt_rx_frm_tx_compl(htt->ar, skb); +		dev_kfree_skb_any(skb); +	} +	spin_unlock_bh(&htt->tx_lock); + +	spin_lock_bh(&htt->rx_ring.lock); +	while ((skb = __skb_dequeue(&htt->rx_compl_q))) { +		resp = (struct htt_resp *)skb->data; +		ath10k_htt_rx_handler(htt, &resp->rx_ind); +		dev_kfree_skb_any(skb); +	} +	spin_unlock_bh(&htt->rx_ring.lock); +} diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 656c2546b29..7064354d1f4 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -83,20 +83,17 @@ void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id)  	__clear_bit(msdu_id, htt->used_msdu_ids);  } -int ath10k_htt_tx_attach(struct ath10k_htt *htt) +int ath10k_htt_tx_alloc(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); +	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, htt->ar->fw_features)) +		htt->max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC; +	else +		htt->max_num_pending_tx = TARGET_NUM_MSDU_DESC; -	ath10k_dbg(ATH10K_DBG_HTT, "htt tx max num pending tx %d\n", +	ath10k_dbg(ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n",  		   htt->max_num_pending_tx);  	htt->pending_tx = kzalloc(sizeof(*htt->pending_tx) * @@ -112,66 +109,50 @@ int ath10k_htt_tx_attach(struct ath10k_htt *htt)  		return -ENOMEM;  	} +	htt->tx_pool = dma_pool_create("ath10k htt tx pool", htt->ar->dev, +				       sizeof(struct ath10k_htt_txbuf), 4, 0); +	if (!htt->tx_pool) { +		kfree(htt->used_msdu_ids); +		kfree(htt->pending_tx); +		return -ENOMEM; +	} +  	return 0;  } -static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt) +static void ath10k_htt_tx_free_pending(struct ath10k_htt *htt)  { -	struct sk_buff *txdesc; +	struct htt_tx_done tx_done = {0};  	int msdu_id; -	/* No locks needed. Called after communication with the device has -	 * been stopped. */ - +	spin_lock_bh(&htt->tx_lock);  	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; +		tx_done.discard = 1; +		tx_done.msdu_id = msdu_id; -		ATH10K_SKB_CB(txdesc)->htt.discard = true; -		ath10k_txrx_tx_unref(htt, txdesc); +		ath10k_txrx_tx_unref(htt, &tx_done);  	} +	spin_unlock_bh(&htt->tx_lock);  } -void ath10k_htt_tx_detach(struct ath10k_htt *htt) +void ath10k_htt_tx_free(struct ath10k_htt *htt)  { -	ath10k_htt_tx_cleanup_pending(htt); +	ath10k_htt_tx_free_pending(htt);  	kfree(htt->pending_tx);  	kfree(htt->used_msdu_ids); +	dma_pool_destroy(htt->tx_pool);  	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); +	dev_kfree_skb_any(skb);  }  int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt) @@ -192,10 +173,48 @@ int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt)  	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_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie) +{ +	struct htt_stats_req *req; +	struct sk_buff *skb; +	struct htt_cmd *cmd; +	int len = 0, ret; + +	len += sizeof(cmd->hdr); +	len += sizeof(cmd->stats_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_STATS_REQ; + +	req = &cmd->stats_req; + +	memset(req, 0, sizeof(*req)); + +	/* currently we support only max 8 bit masks so no need to worry +	 * about endian support */ +	req->upload_types[0] = mask; +	req->reset_types[0] = mask; +	req->stat_type = HTT_STATS_REQ_CFG_STAT_TYPE_INVALID; +	req->cookie_lsb = cpu_to_le32(cookie & 0xffffffff); +	req->cookie_msb = cpu_to_le32((cookie & 0xffffffff00000000ULL) >> 32);  	ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb);  	if (ret) { +		ath10k_warn("failed to send htt type stats request: %d", ret);  		dev_kfree_skb_any(skb);  		return ret;  	} @@ -279,8 +298,6 @@ int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt)  #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); @@ -293,10 +310,10 @@ int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt)  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; +	struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); +	u8 vdev_id = skb_cb->vdev_id;  	int len = 0;  	int msdu_id = -1;  	int res; @@ -304,30 +321,32 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)  	res = ath10k_htt_tx_inc_pending(htt);  	if (res) -		return res; +		goto err;  	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) { +	res = ath10k_htt_tx_alloc_msdu_id(htt); +	if (res < 0) {  		spin_unlock_bh(&htt->tx_lock); -		res = msdu_id; -		goto err; +		goto err_tx_dec;  	} -	htt->pending_tx[msdu_id] = txdesc; +	msdu_id = res; +	htt->pending_tx[msdu_id] = msdu;  	spin_unlock_bh(&htt->tx_lock); -	res = ath10k_skb_map(dev, msdu); +	txdesc = ath10k_htc_alloc_skb(len); +	if (!txdesc) { +		res = -ENOMEM; +		goto err_free_msdu_id; +	} + +	skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len, +				       DMA_TO_DEVICE); +	res = dma_mapping_error(dev, skb_cb->paddr);  	if (res) -		goto err; +		goto err_free_txdesc;  	skb_put(txdesc, len);  	cmd = (struct htt_cmd *)txdesc->data; @@ -339,174 +358,184 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)  	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; +	skb_cb->htt.txbuf = NULL;  	res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc);  	if (res) -		goto err; +		goto err_unmap_msdu;  	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); -	} +err_unmap_msdu: +	dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); +err_free_txdesc: +	dev_kfree_skb_any(txdesc); +err_free_msdu_id: +	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); +err_tx_dec:  	ath10k_htt_tx_dec_pending(htt); +err:  	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; +	struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); +	struct ath10k_hif_sg_item sg_items[2]; +	struct htt_data_tx_desc_frag *frags; +	u8 vdev_id = skb_cb->vdev_id; +	u8 tid = skb_cb->htt.tid; +	int prefetch_len;  	int res; -	u8 flags0; -	u16 flags1; +	u8 flags0 = 0; +	u16 msdu_id, flags1 = 0; +	dma_addr_t paddr; +	u32 frags_paddr; +	bool use_frags;  	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) { +	res = ath10k_htt_tx_alloc_msdu_id(htt); +	if (res < 0) {  		spin_unlock_bh(&htt->tx_lock); -		res = msdu_id; -		goto err; +		goto err_tx_dec;  	} -	htt->pending_tx[msdu_id] = txdesc; +	msdu_id = res; +	htt->pending_tx[msdu_id] = msdu;  	spin_unlock_bh(&htt->tx_lock); -	res = ath10k_skb_map(dev, msdu); +	prefetch_len = min(htt->prefetch_len, msdu->len); +	prefetch_len = roundup(prefetch_len, 4); + +	/* Since HTT 3.0 there is no separate mgmt tx command. However in case +	 * of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx +	 * fragment list host driver specifies directly frame pointer. */ +	use_frags = htt->target_version_major < 3 || +		    !ieee80211_is_mgmt(hdr->frame_control); + +	skb_cb->htt.txbuf = dma_pool_alloc(htt->tx_pool, GFP_ATOMIC, +					   &paddr); +	if (!skb_cb->htt.txbuf) +		goto err_free_msdu_id; +	skb_cb->htt.txbuf_paddr = paddr; + +	skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len, +				       DMA_TO_DEVICE); +	res = dma_mapping_error(dev, skb_cb->paddr);  	if (res) -		goto err; +		goto err_free_txbuf; -	/* 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); +	if (likely(use_frags)) { +		frags = skb_cb->htt.txbuf->frags; -	res = ath10k_skb_map(dev, txfrag); -	if (res) -		goto err; +		frags[0].paddr = __cpu_to_le32(skb_cb->paddr); +		frags[0].len = __cpu_to_le32(msdu->len); +		frags[1].paddr = 0; +		frags[1].len = 0; -	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); +		flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI, +			     HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); -	skb_put(txdesc, desc_len); -	cmd = (struct htt_cmd *)txdesc->data; -	memset(cmd, 0, desc_len); +		frags_paddr = skb_cb->htt.txbuf_paddr; +	} else { +		flags0 |= SM(ATH10K_HW_TXRX_MGMT, +			     HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); -	tid = ATH10K_SKB_CB(msdu)->htt.tid; +		frags_paddr = skb_cb->paddr; +	} -	ath10k_dbg(ATH10K_DBG_HTT, "htt data tx using tid %hhu\n", tid); +	/* Normally all commands go through HTC which manages tx credits for +	 * each endpoint and notifies when tx is completed. +	 * +	 * HTT endpoint is creditless so there's no need to care about HTC +	 * flags. In that case it is trivial to fill the HTC header here. +	 * +	 * MSDU transmission is considered completed upon HTT event. This +	 * implies no relevant resources can be freed until after the event is +	 * received. That's why HTC tx completion handler itself is ignored by +	 * setting NULL to transfer_context for all sg items. +	 * +	 * There is simply no point in pushing HTT TX_FRM through HTC tx path +	 * as it's a waste of resources. By bypassing HTC it is possible to +	 * avoid extra memory allocations, compress data structures and thus +	 * improve performance. */ + +	skb_cb->htt.txbuf->htc_hdr.eid = htt->eid; +	skb_cb->htt.txbuf->htc_hdr.len = __cpu_to_le16( +			sizeof(skb_cb->htt.txbuf->cmd_hdr) + +			sizeof(skb_cb->htt.txbuf->cmd_tx) + +			prefetch_len); +	skb_cb->htt.txbuf->htc_hdr.flags = 0; -	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);  	flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD;  	flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; -	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; +	skb_cb->htt.txbuf->cmd_hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM; +	skb_cb->htt.txbuf->cmd_tx.flags0 = flags0; +	skb_cb->htt.txbuf->cmd_tx.flags1 = __cpu_to_le16(flags1); +	skb_cb->htt.txbuf->cmd_tx.len = __cpu_to_le16(msdu->len); +	skb_cb->htt.txbuf->cmd_tx.id = __cpu_to_le16(msdu_id); +	skb_cb->htt.txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr); +	skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID); + +	ath10k_dbg(ATH10K_DBG_HTT, +		   "htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu\n", +		   flags0, flags1, msdu->len, msdu_id, frags_paddr, +		   (u32)skb_cb->paddr, vdev_id, tid); +	ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ", +			msdu->data, msdu->len); -	res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc); +	sg_items[0].transfer_id = 0; +	sg_items[0].transfer_context = NULL; +	sg_items[0].vaddr = &skb_cb->htt.txbuf->htc_hdr; +	sg_items[0].paddr = skb_cb->htt.txbuf_paddr + +			    sizeof(skb_cb->htt.txbuf->frags); +	sg_items[0].len = sizeof(skb_cb->htt.txbuf->htc_hdr) + +			  sizeof(skb_cb->htt.txbuf->cmd_hdr) + +			  sizeof(skb_cb->htt.txbuf->cmd_tx); + +	sg_items[1].transfer_id = 0; +	sg_items[1].transfer_context = NULL; +	sg_items[1].vaddr = msdu->data; +	sg_items[1].paddr = skb_cb->paddr; +	sg_items[1].len = prefetch_len; + +	res = ath10k_hif_tx_sg(htt->ar, +			       htt->ar->htc.endpoint[htt->eid].ul_pipe_id, +			       sg_items, ARRAY_SIZE(sg_items));  	if (res) -		goto err; +		goto err_unmap_msdu;  	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); -	} + +err_unmap_msdu: +	dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); +err_free_txbuf: +	dma_pool_free(htt->tx_pool, +		      skb_cb->htt.txbuf, +		      skb_cb->htt.txbuf_paddr); +err_free_msdu_id: +	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); +err_tx_dec:  	ath10k_htt_tx_dec_pending(htt); -	ath10k_skb_unmap(dev, msdu); +err:  	return res;  } diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 44ed5af0a20..007e855f4ba 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -20,28 +20,38 @@  #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 1.0 definitions (unsupported) */ +#define QCA988X_HW_1_0_CHIP_ID_REV	0x0  /* QCA988X 2.0 definitions */  #define QCA988X_HW_2_0_VERSION		0x4100016c +#define QCA988X_HW_2_0_CHIP_ID_REV	0x2  #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_FW_2_FILE	"firmware-2.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 +#define ATH10K_FW_API2_FILE		"firmware-2.bin" + +/* includes also the null byte */ +#define ATH10K_FIRMWARE_MAGIC               "QCA-ATH10K" + +struct ath10k_fw_ie { +	__le32 id; +	__le32 len; +	u8 data[0]; +}; + +enum ath10k_fw_ie_type { +	ATH10K_FW_IE_FW_VERSION = 0, +	ATH10K_FW_IE_TIMESTAMP = 1, +	ATH10K_FW_IE_FEATURES = 2, +	ATH10K_FW_IE_FW_IMAGE = 3, +	ATH10K_FW_IE_OTP_IMAGE = 4, +}; +  /* Known pecularities:   *  - current FW doesn't support raw rx mode (last tested v599)   *  - current FW dumps upon raw tx mode (last tested v599) @@ -53,6 +63,9 @@ enum ath10k_hw_txrx_mode {  	ATH10K_HW_TXRX_RAW = 0,  	ATH10K_HW_TXRX_NATIVE_WIFI = 1,  	ATH10K_HW_TXRX_ETHERNET = 2, + +	/* Valid for HTT >= 3.0. Used for management frames in TX_FRM. */ +	ATH10K_HW_TXRX_MGMT = 3,  };  enum ath10k_mcast2ucast_mode { @@ -60,6 +73,7 @@ enum ath10k_mcast2ucast_mode {  	ATH10K_MCAST2UCAST_ENABLED = 1,  }; +/* Target specific defines for MAIN firmware */  #define TARGET_NUM_VDEVS			8  #define TARGET_NUM_PEER_AST			2  #define TARGET_NUM_WDS_ENTRIES			32 @@ -75,7 +89,11 @@ enum ath10k_mcast2ucast_mode {  #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 + +/* Native Wifi decap mode is used to align IP frames to 4-byte boundaries and + * avoid a very expensive re-alignment in mac80211. */ +#define TARGET_RX_DECAP_MODE			ATH10K_HW_TXRX_NATIVE_WIFI +  #define TARGET_SCAN_MAX_PENDING_REQS		4  #define TARGET_BMISS_OFFLOAD_MAX_VDEV		3  #define TARGET_ROAM_OFFLOAD_MAX_VDEV		3 @@ -90,6 +108,37 @@ enum ath10k_mcast2ucast_mode {  #define TARGET_NUM_MSDU_DESC			(1024 + 400)  #define TARGET_MAX_FRAG_ENTRIES			0 +/* Target specific defines for 10.X firmware */ +#define TARGET_10X_NUM_VDEVS			16 +#define TARGET_10X_NUM_PEER_AST			2 +#define TARGET_10X_NUM_WDS_ENTRIES		32 +#define TARGET_10X_DMA_BURST_SIZE		0 +#define TARGET_10X_MAC_AGGR_DELIM		0 +#define TARGET_10X_AST_SKID_LIMIT		16 +#define TARGET_10X_NUM_PEERS			(128 + (TARGET_10X_NUM_VDEVS)) +#define TARGET_10X_NUM_PEERS_MAX		128 +#define TARGET_10X_NUM_OFFLOAD_PEERS		0 +#define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS	0 +#define TARGET_10X_NUM_PEER_KEYS		2 +#define TARGET_10X_NUM_TIDS			256 +#define TARGET_10X_TX_CHAIN_MASK		(BIT(0) | BIT(1) | BIT(2)) +#define TARGET_10X_RX_CHAIN_MASK		(BIT(0) | BIT(1) | BIT(2)) +#define TARGET_10X_RX_TIMEOUT_LO_PRI		100 +#define TARGET_10X_RX_TIMEOUT_HI_PRI		40 +#define TARGET_10X_RX_DECAP_MODE		ATH10K_HW_TXRX_NATIVE_WIFI +#define TARGET_10X_SCAN_MAX_PENDING_REQS	4 +#define TARGET_10X_BMISS_OFFLOAD_MAX_VDEV	2 +#define TARGET_10X_ROAM_OFFLOAD_MAX_VDEV	2 +#define TARGET_10X_ROAM_OFFLOAD_MAX_AP_PROFILES	8 +#define TARGET_10X_GTK_OFFLOAD_MAX_VDEV		3 +#define TARGET_10X_NUM_MCAST_GROUPS		0 +#define TARGET_10X_NUM_MCAST_TABLE_ELEMS	0 +#define TARGET_10X_MCAST2UCAST_MODE		ATH10K_MCAST2UCAST_DISABLED +#define TARGET_10X_TX_DBG_LOG_SIZE		1024 +#define TARGET_10X_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK 1 +#define TARGET_10X_VOW_CONFIG			0 +#define TARGET_10X_NUM_MSDU_DESC		(1024 + 400) +#define TARGET_10X_MAX_FRAG_ENTRIES		0  /* Number of Copy Engines supported */  #define CE_COUNT 8 @@ -157,8 +206,11 @@ enum ath10k_mcast2ucast_mode {  #define WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS	0x0006c000  #define PCIE_LOCAL_BASE_ADDRESS			0x00080000 +#define SOC_RESET_CONTROL_ADDRESS		0x00000000  #define SOC_RESET_CONTROL_OFFSET		0x00000000  #define SOC_RESET_CONTROL_SI0_RST_MASK		0x00000001 +#define SOC_RESET_CONTROL_CE_RST_MASK		0x00040000 +#define SOC_RESET_CONTROL_CPU_WARM_RST_MASK	0x00000040  #define SOC_CPU_CLOCK_OFFSET			0x00000020  #define SOC_CPU_CLOCK_STANDARD_LSB		0  #define SOC_CPU_CLOCK_STANDARD_MASK		0x00000003 @@ -168,6 +220,12 @@ enum ath10k_mcast2ucast_mode {  #define SOC_LPO_CAL_OFFSET			0x000000e0  #define SOC_LPO_CAL_ENABLE_LSB			20  #define SOC_LPO_CAL_ENABLE_MASK			0x00100000 +#define SOC_LF_TIMER_CONTROL0_ADDRESS		0x00000050 +#define SOC_LF_TIMER_CONTROL0_ENABLE_MASK	0x00000004 + +#define SOC_CHIP_ID_ADDRESS			0x000000ec +#define SOC_CHIP_ID_REV_LSB			8 +#define SOC_CHIP_ID_REV_MASK			0x00000f00  #define WLAN_RESET_CONTROL_COLD_RST_MASK	0x00000008  #define WLAN_RESET_CONTROL_WARM_RST_MASK	0x00000004 @@ -218,8 +276,10 @@ enum ath10k_mcast2ucast_mode {  #define CORE_CTRL_CPU_INTR_MASK			0x00002000  #define CORE_CTRL_ADDRESS			0x0000  #define PCIE_INTR_ENABLE_ADDRESS		0x0008 +#define PCIE_INTR_CAUSE_ADDRESS			0x000c  #define PCIE_INTR_CLR_ADDRESS			0x0014  #define SCRATCH_3_ADDRESS			0x0030 +#define CPU_INTR_ADDRESS			0x0010  /* Firmware indications to the Host via SCRATCH_3 register. */  #define FW_INDICATOR_ADDRESS	(SOC_CORE_BASE_ADDRESS + SCRATCH_3_ADDRESS) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index cf2ba4d850c..a21080028c5 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -54,7 +54,10 @@ static int ath10k_send_key(struct ath10k_vif *arvif,  	switch (key->cipher) {  	case WLAN_CIPHER_SUITE_CCMP:  		arg.key_cipher = WMI_CIPHER_AES_CCM; -		key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; +		if (arvif->vdev_type == WMI_VDEV_TYPE_AP) +			key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT; +		else +			key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;  		break;  	case WLAN_CIPHER_SUITE_TKIP:  		arg.key_cipher = WMI_CIPHER_TKIP; @@ -92,7 +95,7 @@ static int ath10k_install_key(struct ath10k_vif *arvif,  	lockdep_assert_held(&ar->conf_mutex); -	INIT_COMPLETION(ar->install_key_done); +	reinit_completion(&ar->install_key_done);  	ret = ath10k_send_key(arvif, key, cmd, macaddr);  	if (ret) @@ -165,7 +168,7 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif,  			first_errno = ret;  		if (ret) -			ath10k_warn("could not remove peer wep key %d (%d)\n", +			ath10k_warn("failed to remove peer wep key %d: %d\n",  				    i, ret);  		peer->keys[i] = NULL; @@ -213,7 +216,8 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif,  			first_errno = ret;  		if (ret) -			ath10k_warn("could not remove key for %pM\n", addr); +			ath10k_warn("failed to remove key for %pM: %d\n", +				    addr, ret);  	}  	return first_errno; @@ -322,37 +326,95 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)  	lockdep_assert_held(&ar->conf_mutex);  	ret = ath10k_wmi_peer_create(ar, vdev_id, addr); -	if (ret) +	if (ret) { +		ath10k_warn("failed to create wmi peer %pM on vdev %i: %i\n", +			    addr, vdev_id, ret);  		return ret; +	}  	ret = ath10k_wait_for_peer_created(ar, vdev_id, addr); -	if (ret) +	if (ret) { +		ath10k_warn("failed to wait for created wmi peer %pM on vdev %i: %i\n", +			    addr, vdev_id, ret); +		return ret; +	} +	spin_lock_bh(&ar->data_lock); +	ar->num_peers++; +	spin_unlock_bh(&ar->data_lock); + +	return 0; +} + +static int ath10k_mac_set_kickout(struct ath10k_vif *arvif) +{ +	struct ath10k *ar = arvif->ar; +	u32 param; +	int ret; + +	param = ar->wmi.pdev_param->sta_kickout_th; +	ret = ath10k_wmi_pdev_set_param(ar, param, +					ATH10K_KICKOUT_THRESHOLD); +	if (ret) { +		ath10k_warn("failed to set kickout threshold on vdev %i: %d\n", +			    arvif->vdev_id, ret); +		return ret; +	} + +	param = ar->wmi.vdev_param->ap_keepalive_min_idle_inactive_time_secs; +	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, +					ATH10K_KEEPALIVE_MIN_IDLE); +	if (ret) { +		ath10k_warn("failed to set keepalive minimum idle time on vdev %i: %d\n", +			    arvif->vdev_id, ret); +		return ret; +	} + +	param = ar->wmi.vdev_param->ap_keepalive_max_idle_inactive_time_secs; +	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, +					ATH10K_KEEPALIVE_MAX_IDLE); +	if (ret) { +		ath10k_warn("failed to set keepalive maximum idle time on vdev %i: %d\n", +			    arvif->vdev_id, ret); +		return ret; +	} + +	param = ar->wmi.vdev_param->ap_keepalive_max_unresponsive_time_secs; +	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, +					ATH10K_KEEPALIVE_MAX_UNRESPONSIVE); +	if (ret) { +		ath10k_warn("failed to set keepalive maximum unresponsive time on vdev %i: %d\n", +			    arvif->vdev_id, ret);  		return ret; +	}  	return 0;  }  static int  ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value)  { +	struct ath10k *ar = arvif->ar; +	u32 vdev_param; +  	if (value != 0xFFFFFFFF)  		value = min_t(u32, arvif->ar->hw->wiphy->rts_threshold,  			      ATH10K_RTS_MAX); -	return ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, -					 WMI_VDEV_PARAM_RTS_THRESHOLD, -					 value); +	vdev_param = ar->wmi.vdev_param->rts_threshold; +	return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value);  }  static int ath10k_mac_set_frag(struct ath10k_vif *arvif, u32 value)  { +	struct ath10k *ar = arvif->ar; +	u32 vdev_param; +  	if (value != 0xFFFFFFFF)  		value = clamp_t(u32, arvif->ar->hw->wiphy->frag_threshold,  				ATH10K_FRAGMT_THRESHOLD_MIN,  				ATH10K_FRAGMT_THRESHOLD_MAX); -	return ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, -					 WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD, -					 value); +	vdev_param = ar->wmi.vdev_param->fragmentation_threshold; +	return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value);  }  static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr) @@ -369,6 +431,10 @@ static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr)  	if (ret)  		return ret; +	spin_lock_bh(&ar->data_lock); +	ar->num_peers--; +	spin_unlock_bh(&ar->data_lock); +  	return 0;  } @@ -388,6 +454,7 @@ static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id)  		list_del(&peer->list);  		kfree(peer); +		ar->num_peers--;  	}  	spin_unlock_bh(&ar->data_lock);  } @@ -403,6 +470,7 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar)  		list_del(&peer->list);  		kfree(peer);  	} +	ar->num_peers = 0;  	spin_unlock_bh(&ar->data_lock);  } @@ -424,175 +492,114 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar)  	return 0;  } -static int ath10k_vdev_start(struct ath10k_vif *arvif) +static bool ath10k_monitor_is_enabled(struct ath10k *ar)  { -	struct ath10k *ar = arvif->ar; -	struct ieee80211_conf *conf = &ar->hw->conf; -	struct ieee80211_channel *channel = conf->chandef.chan; -	struct wmi_vdev_start_request_arg arg = {}; -	int ret = 0; -  	lockdep_assert_held(&ar->conf_mutex); -	INIT_COMPLETION(ar->vdev_setup_done); - -	arg.vdev_id = arvif->vdev_id; -	arg.dtim_period = arvif->dtim_period; -	arg.bcn_intval = arvif->beacon_interval; - -	arg.channel.freq = channel->center_freq; - -	arg.channel.band_center_freq1 = conf->chandef.center_freq1; +	ath10k_dbg(ATH10K_DBG_MAC, +		   "mac monitor refs: promisc %d monitor %d cac %d\n", +		   ar->promisc, ar->monitor, +		   test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)); -	arg.channel.mode = chan_to_phymode(&conf->chandef); - -	arg.channel.min_power = channel->max_power * 3; -	arg.channel.max_power = channel->max_power * 4; -	arg.channel.max_reg_power = channel->max_reg_power * 4; -	arg.channel.max_antenna_gain = channel->max_antenna_gain; - -	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { -		arg.ssid = arvif->u.ap.ssid; -		arg.ssid_len = arvif->u.ap.ssid_len; -		arg.hidden_ssid = arvif->u.ap.hidden_ssid; -	} else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { -		arg.ssid = arvif->vif->bss_conf.ssid; -		arg.ssid_len = arvif->vif->bss_conf.ssid_len; -	} - -	ret = ath10k_wmi_vdev_start(ar, &arg); -	if (ret) { -		ath10k_warn("WMI vdev start failed: ret %d\n", ret); -		return ret; -	} - -	ret = ath10k_vdev_setup_sync(ar); -	if (ret) { -		ath10k_warn("vdev setup failed %d\n", ret); -		return ret; -	} - -	return ret; -} - -static int ath10k_vdev_stop(struct ath10k_vif *arvif) -{ -	struct ath10k *ar = arvif->ar; -	int ret; - -	lockdep_assert_held(&ar->conf_mutex); - -	INIT_COMPLETION(ar->vdev_setup_done); - -	ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id); -	if (ret) { -		ath10k_warn("WMI vdev stop failed: ret %d\n", ret); -		return ret; -	} - -	ret = ath10k_vdev_setup_sync(ar); -	if (ret) { -		ath10k_warn("vdev setup failed %d\n", ret); -		return ret; -	} - -	return ret; +	return ar->promisc || ar->monitor || +	       test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);  } -static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) +static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)  { -	struct ieee80211_channel *channel = ar->hw->conf.chandef.chan; +	struct cfg80211_chan_def *chandef = &ar->chandef; +	struct ieee80211_channel *channel = chandef->chan;  	struct wmi_vdev_start_request_arg arg = {}; -	enum nl80211_channel_type type;  	int ret = 0;  	lockdep_assert_held(&ar->conf_mutex); -	type = cfg80211_get_chandef_type(&ar->hw->conf.chandef); -  	arg.vdev_id = vdev_id;  	arg.channel.freq = channel->center_freq; -	arg.channel.band_center_freq1 = ar->hw->conf.chandef.center_freq1; +	arg.channel.band_center_freq1 = chandef->center_freq1;  	/* TODO setup this dynamically, what in case we  	   don't have any vifs? */ -	arg.channel.mode = chan_to_phymode(&ar->hw->conf.chandef); +	arg.channel.mode = chan_to_phymode(chandef); +	arg.channel.chan_radar = +			!!(channel->flags & IEEE80211_CHAN_RADAR); -	arg.channel.min_power = channel->max_power * 3; -	arg.channel.max_power = channel->max_power * 4; -	arg.channel.max_reg_power = channel->max_reg_power * 4; -	arg.channel.max_antenna_gain = channel->max_antenna_gain; +	arg.channel.min_power = 0; +	arg.channel.max_power = channel->max_power * 2; +	arg.channel.max_reg_power = channel->max_reg_power * 2; +	arg.channel.max_antenna_gain = channel->max_antenna_gain * 2;  	ret = ath10k_wmi_vdev_start(ar, &arg);  	if (ret) { -		ath10k_warn("Monitor vdev start failed: ret %d\n", ret); +		ath10k_warn("failed to request monitor vdev %i start: %d\n", +			    vdev_id, ret);  		return ret;  	}  	ret = ath10k_vdev_setup_sync(ar);  	if (ret) { -		ath10k_warn("Monitor vdev setup failed %d\n", ret); +		ath10k_warn("failed to synchronize setup for monitor vdev %i: %d\n", +			    vdev_id, ret);  		return ret;  	}  	ret = ath10k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr);  	if (ret) { -		ath10k_warn("Monitor vdev up failed: %d\n", ret); +		ath10k_warn("failed to put up monitor vdev %i: %d\n", +			    vdev_id, ret);  		goto vdev_stop;  	}  	ar->monitor_vdev_id = vdev_id; -	ar->monitor_enabled = true; +	ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %i started\n", +		   ar->monitor_vdev_id);  	return 0;  vdev_stop:  	ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);  	if (ret) -		ath10k_warn("Monitor vdev stop failed: %d\n", ret); +		ath10k_warn("failed to stop monitor vdev %i after start failure: %d\n", +			    ar->monitor_vdev_id, ret);  	return ret;  } -static int ath10k_monitor_stop(struct ath10k *ar) +static int ath10k_monitor_vdev_stop(struct ath10k *ar)  {  	int ret = 0;  	lockdep_assert_held(&ar->conf_mutex); -	/* For some reasons, ath10k_wmi_vdev_down() here couse -	 * often ath10k_wmi_vdev_stop() to fail. Next we could -	 * not run monitor vdev and driver reload -	 * required. Don't see such problems we skip -	 * ath10k_wmi_vdev_down() here. -	 */ +	ret = ath10k_wmi_vdev_down(ar, ar->monitor_vdev_id); +	if (ret) +		ath10k_warn("failed to put down monitor vdev %i: %d\n", +			    ar->monitor_vdev_id, ret);  	ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);  	if (ret) -		ath10k_warn("Monitor vdev stop failed: %d\n", ret); +		ath10k_warn("failed to to request monitor vdev %i stop: %d\n", +			    ar->monitor_vdev_id, ret);  	ret = ath10k_vdev_setup_sync(ar);  	if (ret) -		ath10k_warn("Monitor_down sync failed: %d\n", ret); +		ath10k_warn("failed to synchronise monitor vdev %i: %d\n", +			    ar->monitor_vdev_id, ret); -	ar->monitor_enabled = false; +	ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %i stopped\n", +		   ar->monitor_vdev_id);  	return ret;  } -static int ath10k_monitor_create(struct ath10k *ar) +static int ath10k_monitor_vdev_create(struct ath10k *ar)  {  	int bit, ret = 0;  	lockdep_assert_held(&ar->conf_mutex); -	if (ar->monitor_present) { -		ath10k_warn("Monitor mode already enabled\n"); -		return 0; -	} -  	bit = ffs(ar->free_vdev_map);  	if (bit == 0) { -		ath10k_warn("No free VDEV slots\n"); +		ath10k_warn("failed to find free vdev id for monitor vdev\n");  		return -ENOMEM;  	} @@ -603,14 +610,14 @@ static int ath10k_monitor_create(struct ath10k *ar)  				     WMI_VDEV_TYPE_MONITOR,  				     0, ar->mac_addr);  	if (ret) { -		ath10k_warn("WMI vdev monitor create failed: ret %d\n", ret); +		ath10k_warn("failed to request monitor vdev %i creation: %d\n", +			    ar->monitor_vdev_id, ret);  		goto vdev_fail;  	} -	ath10k_dbg(ATH10K_DBG_MAC, "Monitor interface created, vdev id: %d\n", +	ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d created\n",  		   ar->monitor_vdev_id); -	ar->monitor_present = true;  	return 0;  vdev_fail: @@ -621,26 +628,266 @@ vdev_fail:  	return ret;  } -static int ath10k_monitor_destroy(struct ath10k *ar) +static int ath10k_monitor_vdev_delete(struct ath10k *ar)  {  	int ret = 0;  	lockdep_assert_held(&ar->conf_mutex); -	if (!ar->monitor_present) -		return 0; -  	ret = ath10k_wmi_vdev_delete(ar, ar->monitor_vdev_id);  	if (ret) { -		ath10k_warn("WMI vdev monitor delete failed: %d\n", ret); +		ath10k_warn("failed to request wmi monitor vdev %i removal: %d\n", +			    ar->monitor_vdev_id, ret);  		return ret;  	}  	ar->free_vdev_map |= 1 << (ar->monitor_vdev_id); -	ar->monitor_present = false; -	ath10k_dbg(ATH10K_DBG_MAC, "Monitor interface destroyed, vdev id: %d\n", +	ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n", +		   ar->monitor_vdev_id); +	return ret; +} + +static int ath10k_monitor_start(struct ath10k *ar) +{ +	int ret; + +	lockdep_assert_held(&ar->conf_mutex); + +	if (!ath10k_monitor_is_enabled(ar)) { +		ath10k_warn("trying to start monitor with no references\n"); +		return 0; +	} + +	if (ar->monitor_started) { +		ath10k_dbg(ATH10K_DBG_MAC, "mac monitor already started\n"); +		return 0; +	} + +	ret = ath10k_monitor_vdev_create(ar); +	if (ret) { +		ath10k_warn("failed to create monitor vdev: %d\n", ret); +		return ret; +	} + +	ret = ath10k_monitor_vdev_start(ar, ar->monitor_vdev_id); +	if (ret) { +		ath10k_warn("failed to start monitor vdev: %d\n", ret); +		ath10k_monitor_vdev_delete(ar); +		return ret; +	} + +	ar->monitor_started = true; +	ath10k_dbg(ATH10K_DBG_MAC, "mac monitor started\n"); + +	return 0; +} + +static void ath10k_monitor_stop(struct ath10k *ar) +{ +	int ret; + +	lockdep_assert_held(&ar->conf_mutex); + +	if (ath10k_monitor_is_enabled(ar)) { +		ath10k_dbg(ATH10K_DBG_MAC, +			   "mac monitor will be stopped later\n"); +		return; +	} + +	if (!ar->monitor_started) { +		ath10k_dbg(ATH10K_DBG_MAC, +			   "mac monitor probably failed to start earlier\n"); +		return; +	} + +	ret = ath10k_monitor_vdev_stop(ar); +	if (ret) +		ath10k_warn("failed to stop monitor vdev: %d\n", ret); + +	ret = ath10k_monitor_vdev_delete(ar); +	if (ret) +		ath10k_warn("failed to delete monitor vdev: %d\n", ret); + +	ar->monitor_started = false; +	ath10k_dbg(ATH10K_DBG_MAC, "mac monitor stopped\n"); +} + +static int ath10k_recalc_rtscts_prot(struct ath10k_vif *arvif) +{ +	struct ath10k *ar = arvif->ar; +	u32 vdev_param, rts_cts = 0; + +	lockdep_assert_held(&ar->conf_mutex); + +	vdev_param = ar->wmi.vdev_param->enable_rtscts; + +	if (arvif->use_cts_prot || arvif->num_legacy_stations > 0) +		rts_cts |= SM(WMI_RTSCTS_ENABLED, WMI_RTSCTS_SET); + +	if (arvif->num_legacy_stations > 0) +		rts_cts |= SM(WMI_RTSCTS_ACROSS_SW_RETRIES, +			      WMI_RTSCTS_PROFILE); + +	return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, +					 rts_cts); +} + +static int ath10k_start_cac(struct ath10k *ar) +{ +	int ret; + +	lockdep_assert_held(&ar->conf_mutex); + +	set_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); + +	ret = ath10k_monitor_start(ar); +	if (ret) { +		ath10k_warn("failed to start monitor (cac): %d\n", ret); +		clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); +		return ret; +	} + +	ath10k_dbg(ATH10K_DBG_MAC, "mac cac start monitor vdev %d\n",  		   ar->monitor_vdev_id); + +	return 0; +} + +static int ath10k_stop_cac(struct ath10k *ar) +{ +	lockdep_assert_held(&ar->conf_mutex); + +	/* CAC is not running - do nothing */ +	if (!test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) +		return 0; + +	clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); +	ath10k_monitor_stop(ar); + +	ath10k_dbg(ATH10K_DBG_MAC, "mac cac finished\n"); + +	return 0; +} + +static void ath10k_recalc_radar_detection(struct ath10k *ar) +{ +	int ret; + +	lockdep_assert_held(&ar->conf_mutex); + +	ath10k_stop_cac(ar); + +	if (!ar->radar_enabled) +		return; + +	if (ar->num_started_vdevs > 0) +		return; + +	ret = ath10k_start_cac(ar); +	if (ret) { +		/* +		 * Not possible to start CAC on current channel so starting +		 * radiation is not allowed, make this channel DFS_UNAVAILABLE +		 * by indicating that radar was detected. +		 */ +		ath10k_warn("failed to start CAC: %d\n", ret); +		ieee80211_radar_detected(ar->hw); +	} +} + +static int ath10k_vdev_start(struct ath10k_vif *arvif) +{ +	struct ath10k *ar = arvif->ar; +	struct cfg80211_chan_def *chandef = &ar->chandef; +	struct wmi_vdev_start_request_arg arg = {}; +	int ret = 0; + +	lockdep_assert_held(&ar->conf_mutex); + +	reinit_completion(&ar->vdev_setup_done); + +	arg.vdev_id = arvif->vdev_id; +	arg.dtim_period = arvif->dtim_period; +	arg.bcn_intval = arvif->beacon_interval; + +	arg.channel.freq = chandef->chan->center_freq; +	arg.channel.band_center_freq1 = chandef->center_freq1; +	arg.channel.mode = chan_to_phymode(chandef); + +	arg.channel.min_power = 0; +	arg.channel.max_power = chandef->chan->max_power * 2; +	arg.channel.max_reg_power = chandef->chan->max_reg_power * 2; +	arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2; + +	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { +		arg.ssid = arvif->u.ap.ssid; +		arg.ssid_len = arvif->u.ap.ssid_len; +		arg.hidden_ssid = arvif->u.ap.hidden_ssid; + +		/* For now allow DFS for AP mode */ +		arg.channel.chan_radar = +			!!(chandef->chan->flags & IEEE80211_CHAN_RADAR); +	} else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { +		arg.ssid = arvif->vif->bss_conf.ssid; +		arg.ssid_len = arvif->vif->bss_conf.ssid_len; +	} + +	ath10k_dbg(ATH10K_DBG_MAC, +		   "mac vdev %d start center_freq %d phymode %s\n", +		   arg.vdev_id, arg.channel.freq, +		   ath10k_wmi_phymode_str(arg.channel.mode)); + +	ret = ath10k_wmi_vdev_start(ar, &arg); +	if (ret) { +		ath10k_warn("failed to start WMI vdev %i: %d\n", +			    arg.vdev_id, ret); +		return ret; +	} + +	ret = ath10k_vdev_setup_sync(ar); +	if (ret) { +		ath10k_warn("failed to synchronise setup for vdev %i: %d\n", +			    arg.vdev_id, ret); +		return ret; +	} + +	ar->num_started_vdevs++; +	ath10k_recalc_radar_detection(ar); + +	return ret; +} + +static int ath10k_vdev_stop(struct ath10k_vif *arvif) +{ +	struct ath10k *ar = arvif->ar; +	int ret; + +	lockdep_assert_held(&ar->conf_mutex); + +	reinit_completion(&ar->vdev_setup_done); + +	ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id); +	if (ret) { +		ath10k_warn("failed to stop WMI vdev %i: %d\n", +			    arvif->vdev_id, ret); +		return ret; +	} + +	ret = ath10k_vdev_setup_sync(ar); +	if (ret) { +		ath10k_warn("failed to syncronise setup for vdev %i: %d\n", +			    arvif->vdev_id, ret); +		return ret; +	} + +	WARN_ON(ar->num_started_vdevs == 0); + +	if (ar->num_started_vdevs != 0) { +		ar->num_started_vdevs--; +		ath10k_recalc_radar_detection(ar); +	} +  	return ret;  } @@ -653,6 +900,22 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,  	if (!info->enable_beacon) {  		ath10k_vdev_stop(arvif); + +		arvif->is_started = false; +		arvif->is_up = false; + +		spin_lock_bh(&arvif->ar->data_lock); +		if (arvif->beacon) { +			dma_unmap_single(arvif->ar->dev, +					 ATH10K_SKB_CB(arvif->beacon)->paddr, +					 arvif->beacon->len, DMA_TO_DEVICE); +			dev_kfree_skb_any(arvif->beacon); + +			arvif->beacon = NULL; +			arvif->beacon_sent = false; +		} +		spin_unlock_bh(&arvif->ar->data_lock); +  		return;  	} @@ -662,19 +925,29 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,  	if (ret)  		return; -	ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, 0, info->bssid); +	arvif->aid = 0; +	memcpy(arvif->bssid, info->bssid, ETH_ALEN); + +	ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, +				 arvif->bssid);  	if (ret) { -		ath10k_warn("Failed to bring up VDEV: %d\n", -			    arvif->vdev_id); +		ath10k_warn("failed to bring up vdev %d: %i\n", +			    arvif->vdev_id, ret); +		ath10k_vdev_stop(arvif);  		return;  	} -	ath10k_dbg(ATH10K_DBG_MAC, "VDEV: %d up\n", arvif->vdev_id); + +	arvif->is_started = true; +	arvif->is_up = true; + +	ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);  }  static void ath10k_control_ibss(struct ath10k_vif *arvif,  				struct ieee80211_bss_conf *info,  				const u8 self_peer[ETH_ALEN])  { +	u32 vdev_param;  	int ret = 0;  	lockdep_assert_held(&arvif->ar->conf_mutex); @@ -682,84 +955,82 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,  	if (!info->ibss_joined) {  		ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, self_peer);  		if (ret) -			ath10k_warn("Failed to delete IBSS self peer:%pM for VDEV:%d ret:%d\n", +			ath10k_warn("failed to delete IBSS self peer %pM for vdev %d: %d\n",  				    self_peer, arvif->vdev_id, ret); -		if (is_zero_ether_addr(arvif->u.ibss.bssid)) +		if (is_zero_ether_addr(arvif->bssid))  			return;  		ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, -					 arvif->u.ibss.bssid); +					 arvif->bssid);  		if (ret) { -			ath10k_warn("Failed to delete IBSS BSSID peer:%pM for VDEV:%d ret:%d\n", -				    arvif->u.ibss.bssid, arvif->vdev_id, ret); +			ath10k_warn("failed to delete IBSS BSSID peer %pM for vdev %d: %d\n", +				    arvif->bssid, arvif->vdev_id, ret);  			return;  		} -		memset(arvif->u.ibss.bssid, 0, ETH_ALEN); +		memset(arvif->bssid, 0, ETH_ALEN);  		return;  	}  	ret = ath10k_peer_create(arvif->ar, arvif->vdev_id, self_peer);  	if (ret) { -		ath10k_warn("Failed to create IBSS self peer:%pM for VDEV:%d ret:%d\n", +		ath10k_warn("failed to create IBSS self peer %pM for vdev %d: %d\n",  			    self_peer, arvif->vdev_id, ret);  		return;  	} -	ret = ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, -					WMI_VDEV_PARAM_ATIM_WINDOW, +	vdev_param = arvif->ar->wmi.vdev_param->atim_window; +	ret = ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, vdev_param,  					ATH10K_DEFAULT_ATIM);  	if (ret) -		ath10k_warn("Failed to set IBSS ATIM for VDEV:%d ret:%d\n", +		ath10k_warn("failed to set IBSS ATIM for vdev %d: %d\n",  			    arvif->vdev_id, ret);  }  /*   * Review this when mac80211 gains per-interface powersave support.   */ -static void ath10k_ps_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)  { -	struct ath10k_generic_iter *ar_iter = data; -	struct ieee80211_conf *conf = &ar_iter->ar->hw->conf; -	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); +	struct ath10k *ar = arvif->ar; +	struct ieee80211_conf *conf = &ar->hw->conf;  	enum wmi_sta_powersave_param param;  	enum wmi_sta_ps_mode psmode;  	int ret;  	lockdep_assert_held(&arvif->ar->conf_mutex); -	if (vif->type != NL80211_IFTYPE_STATION) -		return; +	if (arvif->vif->type != NL80211_IFTYPE_STATION) +		return 0;  	if (conf->flags & IEEE80211_CONF_PS) {  		psmode = WMI_STA_PS_MODE_ENABLED;  		param = WMI_STA_PS_PARAM_INACTIVITY_TIME; -		ret = ath10k_wmi_set_sta_ps_param(ar_iter->ar, -						  arvif->vdev_id, -						  param, +		ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param,  						  conf->dynamic_ps_timeout);  		if (ret) { -			ath10k_warn("Failed to set inactivity time for VDEV: %d\n", -				    arvif->vdev_id); -			return; +			ath10k_warn("failed to set inactivity time for vdev %d: %i\n", +				    arvif->vdev_id, ret); +			return ret;  		} - -		ar_iter->ret = ret;  	} else {  		psmode = WMI_STA_PS_MODE_DISABLED;  	} -	ar_iter->ret = ath10k_wmi_set_psmode(ar_iter->ar, arvif->vdev_id, -					     psmode); -	if (ar_iter->ret) -		ath10k_warn("Failed to set PS Mode: %d for VDEV: %d\n", -			    psmode, arvif->vdev_id); -	else -		ath10k_dbg(ATH10K_DBG_MAC, "Set PS Mode: %d for VDEV: %d\n", -			   psmode, arvif->vdev_id); +	ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d psmode %s\n", +		   arvif->vdev_id, psmode ? "enable" : "disable"); + +	ret = ath10k_wmi_set_psmode(ar, arvif->vdev_id, psmode); +	if (ret) { +		ath10k_warn("failed to set PS Mode %d for vdev %d: %d\n", +			    psmode, arvif->vdev_id, ret); +		return ret; +	} + +	return 0;  }  /**********************/ @@ -880,7 +1151,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,  				   struct wmi_peer_assoc_complete_arg *arg)  {  	const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; -	int smps;  	int i, n;  	lockdep_assert_held(&ar->conf_mutex); @@ -926,17 +1196,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,  		arg->peer_flags |= WMI_PEER_STBC;  	} -	smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS; -	smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT; - -	if (smps == WLAN_HT_CAP_SM_PS_STATIC) { -		arg->peer_flags |= WMI_PEER_SPATIAL_MUX; -		arg->peer_flags |= WMI_PEER_STATIC_MIMOPS; -	} else if (smps == WLAN_HT_CAP_SM_PS_DYNAMIC) { -		arg->peer_flags |= WMI_PEER_SPATIAL_MUX; -		arg->peer_flags |= WMI_PEER_DYN_MIMOPS; -	} -  	if (ht_cap->mcs.rx_mask[1] && ht_cap->mcs.rx_mask[2])  		arg->peer_rate_caps |= WMI_RC_TS_FLAG;  	else if (ht_cap->mcs.rx_mask[1]) @@ -946,35 +1205,44 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,  		if (ht_cap->mcs.rx_mask[i/8] & (1 << i%8))  			arg->peer_ht_rates.rates[n++] = i; -	arg->peer_ht_rates.num_rates = n; -	arg->peer_num_spatial_streams = max((n+7) / 8, 1); +	/* +	 * This is a workaround for HT-enabled STAs which break the spec +	 * and have no HT capabilities RX mask (no HT RX MCS map). +	 * +	 * As per spec, in section 20.3.5 Modulation and coding scheme (MCS), +	 * MCS 0 through 7 are mandatory in 20MHz with 800 ns GI at all STAs. +	 * +	 * Firmware asserts if such situation occurs. +	 */ +	if (n == 0) { +		arg->peer_ht_rates.num_rates = 8; +		for (i = 0; i < arg->peer_ht_rates.num_rates; i++) +			arg->peer_ht_rates.rates[i] = i; +	} else { +		arg->peer_ht_rates.num_rates = n; +		arg->peer_num_spatial_streams = sta->rx_nss; +	} -	ath10k_dbg(ATH10K_DBG_MAC, "mcs cnt %d nss %d\n", +	ath10k_dbg(ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n", +		   arg->addr,  		   arg->peer_ht_rates.num_rates,  		   arg->peer_num_spatial_streams);  } -static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar, -				       struct ath10k_vif *arvif, -				       struct ieee80211_sta *sta, -				       struct ieee80211_bss_conf *bss_conf, -				       struct wmi_peer_assoc_complete_arg *arg) +static int ath10k_peer_assoc_qos_ap(struct ath10k *ar, +				    struct ath10k_vif *arvif, +				    struct ieee80211_sta *sta)  {  	u32 uapsd = 0;  	u32 max_sp = 0; +	int ret = 0;  	lockdep_assert_held(&ar->conf_mutex); -	if (sta->wme) -		arg->peer_flags |= WMI_PEER_QOS; -  	if (sta->wme && sta->uapsd_queues) { -		ath10k_dbg(ATH10K_DBG_MAC, "uapsd_queues: 0x%X, max_sp: %d\n", +		ath10k_dbg(ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n",  			   sta->uapsd_queues, sta->max_sp); -		arg->peer_flags |= WMI_PEER_APSD; -		arg->peer_flags |= WMI_RC_UAPSD_FLAG; -  		if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)  			uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN |  				 WMI_AP_PS_UAPSD_AC3_TRIGGER_EN; @@ -992,35 +1260,40 @@ static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar,  		if (sta->max_sp < MAX_WMI_AP_PS_PEER_PARAM_MAX_SP)  			max_sp = sta->max_sp; -		ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, -					   sta->addr, -					   WMI_AP_PS_PEER_PARAM_UAPSD, -					   uapsd); +		ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, +						 sta->addr, +						 WMI_AP_PS_PEER_PARAM_UAPSD, +						 uapsd); +		if (ret) { +			ath10k_warn("failed to set ap ps peer param uapsd for vdev %i: %d\n", +				    arvif->vdev_id, ret); +			return ret; +		} -		ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, -					   sta->addr, -					   WMI_AP_PS_PEER_PARAM_MAX_SP, -					   max_sp); +		ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, +						 sta->addr, +						 WMI_AP_PS_PEER_PARAM_MAX_SP, +						 max_sp); +		if (ret) { +			ath10k_warn("failed to set ap ps peer param max sp for vdev %i: %d\n", +				    arvif->vdev_id, ret); +			return ret; +		}  		/* TODO setup this based on STA listen interval and  		   beacon interval. Currently we don't know  		   sta->listen_interval - mac80211 patch required.  		   Currently use 10 seconds */ -		ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, -					   sta->addr, -					   WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, -					   10); +		ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, sta->addr, +					WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, 10); +		if (ret) { +			ath10k_warn("failed to set ap ps peer param ageout time for vdev %i: %d\n", +				    arvif->vdev_id, ret); +			return ret; +		}  	} -} -static void ath10k_peer_assoc_h_qos_sta(struct ath10k *ar, -					struct ath10k_vif *arvif, -					struct ieee80211_sta *sta, -					struct ieee80211_bss_conf *bss_conf, -					struct wmi_peer_assoc_complete_arg *arg) -{ -	if (bss_conf->qos) -		arg->peer_flags |= WMI_PEER_QOS; +	return 0;  }  static void ath10k_peer_assoc_h_vht(struct ath10k *ar, @@ -1028,14 +1301,27 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,  				    struct wmi_peer_assoc_complete_arg *arg)  {  	const struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; +	u8 ampdu_factor;  	if (!vht_cap->vht_supported)  		return;  	arg->peer_flags |= WMI_PEER_VHT; -  	arg->peer_vht_caps = vht_cap->cap; + +	ampdu_factor = (vht_cap->cap & +			IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) >> +		       IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; + +	/* Workaround: Some Netgear/Linksys 11ac APs set Rx A-MPDU factor to +	 * zero in VHT IE. Using it would result in degraded throughput. +	 * arg->peer_max_mpdu at this point contains HT max_mpdu so keep +	 * it if VHT max_mpdu is smaller. */ +	arg->peer_max_mpdu = max(arg->peer_max_mpdu, +				 (1U << (IEEE80211_HT_MAX_AMPDU_FACTOR + +					ampdu_factor)) - 1); +  	if (sta->bandwidth == IEEE80211_STA_RX_BW_80)  		arg->peer_flags |= WMI_PEER_80MHZ; @@ -1048,7 +1334,8 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,  	arg->peer_vht_rates.tx_mcs_set =  		__le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map); -	ath10k_dbg(ATH10K_DBG_MAC, "mac vht peer\n"); +	ath10k_dbg(ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n", +		   sta->addr, arg->peer_max_mpdu, arg->peer_flags);  }  static void ath10k_peer_assoc_h_qos(struct ath10k *ar, @@ -1059,10 +1346,17 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,  {  	switch (arvif->vdev_type) {  	case WMI_VDEV_TYPE_AP: -		ath10k_peer_assoc_h_qos_ap(ar, arvif, sta, bss_conf, arg); +		if (sta->wme) +			arg->peer_flags |= WMI_PEER_QOS; + +		if (sta->wme && sta->uapsd_queues) { +			arg->peer_flags |= WMI_PEER_APSD; +			arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG; +		}  		break;  	case WMI_VDEV_TYPE_STA: -		ath10k_peer_assoc_h_qos_sta(ar, arvif, sta, bss_conf, arg); +		if (bss_conf->qos) +			arg->peer_flags |= WMI_PEER_QOS;  		break;  	default:  		break; @@ -1076,8 +1370,6 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,  {  	enum wmi_phy_mode phymode = MODE_UNKNOWN; -	/* FIXME: add VHT */ -  	switch (ar->hw->conf.chandef.chan->band) {  	case IEEE80211_BAND_2GHZ:  		if (sta->ht_cap.ht_supported) { @@ -1091,7 +1383,17 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,  		break;  	case IEEE80211_BAND_5GHZ: -		if (sta->ht_cap.ht_supported) { +		/* +		 * Check VHT first. +		 */ +		if (sta->vht_cap.vht_supported) { +			if (sta->bandwidth == IEEE80211_STA_RX_BW_80) +				phymode = MODE_11AC_VHT80; +			else if (sta->bandwidth == IEEE80211_STA_RX_BW_40) +				phymode = MODE_11AC_VHT40; +			else if (sta->bandwidth == IEEE80211_STA_RX_BW_20) +				phymode = MODE_11AC_VHT20; +		} else if (sta->ht_cap.ht_supported) {  			if (sta->bandwidth == IEEE80211_STA_RX_BW_40)  				phymode = MODE_11NA_HT40;  			else @@ -1105,30 +1407,59 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,  		break;  	} +	ath10k_dbg(ATH10K_DBG_MAC, "mac peer %pM phymode %s\n", +		   sta->addr, ath10k_wmi_phymode_str(phymode)); +  	arg->peer_phymode = phymode;  	WARN_ON(phymode == MODE_UNKNOWN);  } -static int ath10k_peer_assoc(struct ath10k *ar, -			     struct ath10k_vif *arvif, -			     struct ieee80211_sta *sta, -			     struct ieee80211_bss_conf *bss_conf) +static int ath10k_peer_assoc_prepare(struct ath10k *ar, +				     struct ath10k_vif *arvif, +				     struct ieee80211_sta *sta, +				     struct ieee80211_bss_conf *bss_conf, +				     struct wmi_peer_assoc_complete_arg *arg)  { -	struct wmi_peer_assoc_complete_arg arg; -  	lockdep_assert_held(&ar->conf_mutex); -	memset(&arg, 0, sizeof(struct wmi_peer_assoc_complete_arg)); +	memset(arg, 0, sizeof(*arg)); -	ath10k_peer_assoc_h_basic(ar, arvif, sta, bss_conf, &arg); -	ath10k_peer_assoc_h_crypto(ar, arvif, &arg); -	ath10k_peer_assoc_h_rates(ar, sta, &arg); -	ath10k_peer_assoc_h_ht(ar, sta, &arg); -	ath10k_peer_assoc_h_vht(ar, sta, &arg); -	ath10k_peer_assoc_h_qos(ar, arvif, sta, bss_conf, &arg); -	ath10k_peer_assoc_h_phymode(ar, arvif, sta, &arg); +	ath10k_peer_assoc_h_basic(ar, arvif, sta, bss_conf, arg); +	ath10k_peer_assoc_h_crypto(ar, arvif, arg); +	ath10k_peer_assoc_h_rates(ar, sta, arg); +	ath10k_peer_assoc_h_ht(ar, sta, arg); +	ath10k_peer_assoc_h_vht(ar, sta, arg); +	ath10k_peer_assoc_h_qos(ar, arvif, sta, bss_conf, arg); +	ath10k_peer_assoc_h_phymode(ar, arvif, sta, arg); -	return ath10k_wmi_peer_assoc(ar, &arg); +	return 0; +} + +static const u32 ath10k_smps_map[] = { +	[WLAN_HT_CAP_SM_PS_STATIC] = WMI_PEER_SMPS_STATIC, +	[WLAN_HT_CAP_SM_PS_DYNAMIC] = WMI_PEER_SMPS_DYNAMIC, +	[WLAN_HT_CAP_SM_PS_INVALID] = WMI_PEER_SMPS_PS_NONE, +	[WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE, +}; + +static int ath10k_setup_peer_smps(struct ath10k *ar, struct ath10k_vif *arvif, +				  const u8 *addr, +				  const struct ieee80211_sta_ht_cap *ht_cap) +{ +	int smps; + +	if (!ht_cap->ht_supported) +		return 0; + +	smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS; +	smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT; + +	if (smps >= ARRAY_SIZE(ath10k_smps_map)) +		return -EINVAL; + +	return ath10k_wmi_peer_set_param(ar, arvif->vdev_id, addr, +					 WMI_PEER_SMPS_STATE, +					 ath10k_smps_map[smps]);  }  /* can be called only in mac80211 callbacks due to `key_count` usage */ @@ -1138,6 +1469,8 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,  {  	struct ath10k *ar = hw->priv;  	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); +	struct ieee80211_sta_ht_cap ht_cap; +	struct wmi_peer_assoc_complete_arg peer_arg;  	struct ieee80211_sta *ap_sta;  	int ret; @@ -1147,30 +1480,56 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,  	ap_sta = ieee80211_find_sta(vif, bss_conf->bssid);  	if (!ap_sta) { -		ath10k_warn("Failed to find station entry for %pM\n", -			    bss_conf->bssid); +		ath10k_warn("failed to find station entry for bss %pM vdev %i\n", +			    bss_conf->bssid, arvif->vdev_id);  		rcu_read_unlock();  		return;  	} -	ret = ath10k_peer_assoc(ar, arvif, ap_sta, bss_conf); +	/* ap_sta must be accessed only within rcu section which must be left +	 * before calling ath10k_setup_peer_smps() which might sleep. */ +	ht_cap = ap_sta->ht_cap; + +	ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta, +					bss_conf, &peer_arg);  	if (ret) { -		ath10k_warn("Peer assoc failed for %pM\n", bss_conf->bssid); +		ath10k_warn("failed to prepare peer assoc for %pM vdev %i: %d\n", +			    bss_conf->bssid, arvif->vdev_id, ret);  		rcu_read_unlock();  		return;  	}  	rcu_read_unlock(); -	ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, bss_conf->aid, -				 bss_conf->bssid); -	if (ret) -		ath10k_warn("VDEV: %d up failed: ret %d\n", +	ret = ath10k_wmi_peer_assoc(ar, &peer_arg); +	if (ret) { +		ath10k_warn("failed to run peer assoc for %pM vdev %i: %d\n", +			    bss_conf->bssid, arvif->vdev_id, ret); +		return; +	} + +	ret = ath10k_setup_peer_smps(ar, arvif, bss_conf->bssid, &ht_cap); +	if (ret) { +		ath10k_warn("failed to setup peer SMPS for vdev %i: %d\n",  			    arvif->vdev_id, ret); -	else -		ath10k_dbg(ATH10K_DBG_MAC, -			   "VDEV: %d associated, BSSID: %pM, AID: %d\n", -			   arvif->vdev_id, bss_conf->bssid, bss_conf->aid); +		return; +	} + +	ath10k_dbg(ATH10K_DBG_MAC, +		   "mac vdev %d up (associated) bssid %pM aid %d\n", +		   arvif->vdev_id, bss_conf->bssid, bss_conf->aid); + +	arvif->aid = bss_conf->aid; +	memcpy(arvif->bssid, bss_conf->bssid, ETH_ALEN); + +	ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid); +	if (ret) { +		ath10k_warn("failed to set vdev %d up: %d\n", +			    arvif->vdev_id, ret); +		return; +	} + +	arvif->is_up = true;  }  /* @@ -1191,10 +1550,11 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,  	 * No idea why this happens, even though VDEV-DOWN is supposed  	 * to be analogous to link down, so just stop the VDEV.  	 */ +	ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d stop (disassociated\n", +		   arvif->vdev_id); + +	/* FIXME: check return value */  	ret = ath10k_vdev_stop(arvif); -	if (!ret) -		ath10k_dbg(ATH10K_DBG_MAC, "VDEV: %d stopped\n", -			   arvif->vdev_id);  	/*  	 * If we don't call VDEV-DOWN after VDEV-STOP FW will remain active and @@ -1203,32 +1563,68 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,  	 * interfaces as it expects there is no rx when no interface is  	 * running.  	 */ +	ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d down\n", arvif->vdev_id); + +	/* FIXME: why don't we print error if wmi call fails? */  	ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); -	if (ret) -		ath10k_dbg(ATH10K_DBG_MAC, "VDEV: %d ath10k_wmi_vdev_down failed (%d)\n", -			   arvif->vdev_id, ret); -	ath10k_wmi_flush_tx(ar); +	arvif->def_wep_key_idx = 0; -	arvif->def_wep_key_index = 0; +	arvif->is_started = false; +	arvif->is_up = false;  }  static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, -				struct ieee80211_sta *sta) +				struct ieee80211_sta *sta, bool reassoc)  { +	struct wmi_peer_assoc_complete_arg peer_arg;  	int ret = 0;  	lockdep_assert_held(&ar->conf_mutex); -	ret = ath10k_peer_assoc(ar, arvif, sta, NULL); +	ret = ath10k_peer_assoc_prepare(ar, arvif, sta, NULL, &peer_arg);  	if (ret) { -		ath10k_warn("WMI peer assoc failed for %pM\n", sta->addr); +		ath10k_warn("failed to prepare WMI peer assoc for %pM vdev %i: %i\n", +			    sta->addr, arvif->vdev_id, ret);  		return ret;  	} +	peer_arg.peer_reassoc = reassoc; +	ret = ath10k_wmi_peer_assoc(ar, &peer_arg); +	if (ret) { +		ath10k_warn("failed to run peer assoc for STA %pM vdev %i: %d\n", +			    sta->addr, arvif->vdev_id, ret); +		return ret; +	} + +	ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap); +	if (ret) { +		ath10k_warn("failed to setup peer SMPS for vdev %d: %d\n", +			    arvif->vdev_id, ret); +		return ret; +	} + +	if (!sta->wme) { +		arvif->num_legacy_stations++; +		ret  = ath10k_recalc_rtscts_prot(arvif); +		if (ret) { +			ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n", +				    arvif->vdev_id, ret); +			return ret; +		} +	} +  	ret = ath10k_install_peer_wep_keys(arvif, sta->addr);  	if (ret) { -		ath10k_warn("could not install peer wep keys (%d)\n", ret); +		ath10k_warn("failed to install peer wep keys for vdev %i: %d\n", +			    arvif->vdev_id, ret); +		return ret; +	} + +	ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta); +	if (ret) { +		ath10k_warn("failed to set qos params for STA %pM for vdev %i: %d\n", +			    sta->addr, arvif->vdev_id, ret);  		return ret;  	} @@ -1242,9 +1638,20 @@ static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif,  	lockdep_assert_held(&ar->conf_mutex); +	if (!sta->wme) { +		arvif->num_legacy_stations--; +		ret = ath10k_recalc_rtscts_prot(arvif); +		if (ret) { +			ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n", +				    arvif->vdev_id, ret); +			return ret; +		} +	} +  	ret = ath10k_clear_peer_keys(arvif, sta->addr);  	if (ret) { -		ath10k_warn("could not clear all peer wep keys (%d)\n", ret); +		ath10k_warn("failed to clear all peer wep keys for vdev %i: %d\n", +			    arvif->vdev_id, ret);  		return ret;  	} @@ -1306,19 +1713,22 @@ static int ath10k_update_channel_list(struct ath10k *ar)  			ch->allow_vht = true;  			ch->allow_ibss = -				!(channel->flags & IEEE80211_CHAN_NO_IBSS); +				!(channel->flags & IEEE80211_CHAN_NO_IR);  			ch->ht40plus =  				!(channel->flags & IEEE80211_CHAN_NO_HT40PLUS); -			passive = channel->flags & IEEE80211_CHAN_PASSIVE_SCAN; +			ch->chan_radar = +				!!(channel->flags & IEEE80211_CHAN_RADAR); + +			passive = channel->flags & IEEE80211_CHAN_NO_IR;  			ch->passive = passive;  			ch->freq = channel->center_freq; -			ch->min_power = channel->max_power * 3; -			ch->max_power = channel->max_power * 4; -			ch->max_reg_power = channel->max_reg_power * 4; -			ch->max_antenna_gain = channel->max_antenna_gain; +			ch->min_power = 0; +			ch->max_power = channel->max_power * 2; +			ch->max_reg_power = channel->max_reg_power * 2; +			ch->max_antenna_gain = channel->max_antenna_gain * 2;  			ch->reg_class_id = 0; /* FIXME */  			/* FIXME: why use only legacy modes, why not any @@ -1333,8 +1743,8 @@ static int ath10k_update_channel_list(struct ath10k *ar)  				continue;  			ath10k_dbg(ATH10K_DBG_WMI, -				   "%s: [%zd/%d] freq %d maxpower %d regpower %d antenna %d mode %d\n", -				   __func__, ch - arg.channels, arg.n_channels, +				   "mac channel [%zd/%d] freq %d maxpower %d regpower %d antenna %d mode %d\n", +				    ch - arg.channels, arg.n_channels,  				   ch->freq, ch->max_power, ch->max_reg_power,  				   ch->max_antenna_gain, ch->mode); @@ -1348,29 +1758,55 @@ static int ath10k_update_channel_list(struct ath10k *ar)  	return ret;  } +static enum wmi_dfs_region +ath10k_mac_get_dfs_region(enum nl80211_dfs_regions dfs_region) +{ +	switch (dfs_region) { +	case NL80211_DFS_UNSET: +		return WMI_UNINIT_DFS_DOMAIN; +	case NL80211_DFS_FCC: +		return WMI_FCC_DFS_DOMAIN; +	case NL80211_DFS_ETSI: +		return WMI_ETSI_DFS_DOMAIN; +	case NL80211_DFS_JP: +		return WMI_MKK4_DFS_DOMAIN; +	} +	return WMI_UNINIT_DFS_DOMAIN; +} +  static void ath10k_regd_update(struct ath10k *ar)  {  	struct reg_dmn_pair_mapping *regpair;  	int ret; +	enum wmi_dfs_region wmi_dfs_reg; +	enum nl80211_dfs_regions nl_dfs_reg;  	lockdep_assert_held(&ar->conf_mutex);  	ret = ath10k_update_channel_list(ar);  	if (ret) -		ath10k_warn("could not update channel list (%d)\n", ret); +		ath10k_warn("failed to update channel list: %d\n", ret);  	regpair = ar->ath_common.regulatory.regpair; +	if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) { +		nl_dfs_reg = ar->dfs_detector->region; +		wmi_dfs_reg = ath10k_mac_get_dfs_region(nl_dfs_reg); +	} else { +		wmi_dfs_reg = WMI_UNINIT_DFS_DOMAIN; +	} +  	/* Target allows setting up per-band regdomain but ath_common provides  	 * a combined one only */  	ret = ath10k_wmi_pdev_set_regdomain(ar, -					    regpair->regDmnEnum, -					    regpair->regDmnEnum, /* 2ghz */ -					    regpair->regDmnEnum, /* 5ghz */ +					    regpair->reg_domain, +					    regpair->reg_domain, /* 2ghz */ +					    regpair->reg_domain, /* 5ghz */  					    regpair->reg_2ghz_ctl, -					    regpair->reg_5ghz_ctl); +					    regpair->reg_5ghz_ctl, +					    wmi_dfs_reg);  	if (ret) -		ath10k_warn("could not set pdev regdomain (%d)\n", ret); +		ath10k_warn("failed to set pdev regdomain: %d\n", ret);  }  static void ath10k_reg_notifier(struct wiphy *wiphy, @@ -1378,9 +1814,20 @@ static void ath10k_reg_notifier(struct wiphy *wiphy,  {  	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);  	struct ath10k *ar = hw->priv; +	bool result;  	ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory); +	if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) { +		ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs region 0x%x\n", +			   request->dfs_region); +		result = ar->dfs_detector->set_dfs_domain(ar->dfs_detector, +							  request->dfs_region); +		if (!result) +			ath10k_warn("DFS region 0x%X not supported, will trigger radar for every pulse\n", +				    request->dfs_region); +	} +  	mutex_lock(&ar->conf_mutex);  	if (ar->state == ATH10K_STATE_ON)  		ath10k_regd_update(ar); @@ -1391,6 +1838,33 @@ static void ath10k_reg_notifier(struct wiphy *wiphy,  /* TX handlers */  /***************/ +static u8 ath10k_tx_h_get_tid(struct ieee80211_hdr *hdr) +{ +	if (ieee80211_is_mgmt(hdr->frame_control)) +		return HTT_DATA_TX_EXT_TID_MGMT; + +	if (!ieee80211_is_data_qos(hdr->frame_control)) +		return HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST; + +	if (!is_unicast_ether_addr(ieee80211_get_DA(hdr))) +		return HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST; + +	return ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; +} + +static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar, +				  struct ieee80211_tx_info *info) +{ +	if (info->control.vif) +		return ath10k_vif_to_arvif(info->control.vif)->vdev_id; + +	if (ar->monitor_started) +		return ar->monitor_vdev_id; + +	ath10k_warn("failed to resolve vdev id\n"); +	return 0; +} +  /*   * Frames sent to the FW have to be in "Native Wifi" format.   * Strip the QoS field from the 802.11 header. @@ -1411,6 +1885,40 @@ static void ath10k_tx_h_qos_workaround(struct ieee80211_hw *hw,  	skb_pull(skb, IEEE80211_QOS_CTL_LEN);  } +static void ath10k_tx_wep_key_work(struct work_struct *work) +{ +	struct ath10k_vif *arvif = container_of(work, struct ath10k_vif, +						wep_key_work); +	int ret, keyidx = arvif->def_wep_key_newidx; + +	mutex_lock(&arvif->ar->conf_mutex); + +	if (arvif->ar->state != ATH10K_STATE_ON) +		goto unlock; + +	if (arvif->def_wep_key_idx == keyidx) +		goto unlock; + +	ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n", +		   arvif->vdev_id, keyidx); + +	ret = ath10k_wmi_vdev_set_param(arvif->ar, +					arvif->vdev_id, +					arvif->ar->wmi.vdev_param->def_keyid, +					keyidx); +	if (ret) { +		ath10k_warn("failed to update wep key index for vdev %d: %d\n", +			    arvif->vdev_id, +			    ret); +		goto unlock; +	} + +	arvif->def_wep_key_idx = keyidx; + +unlock: +	mutex_unlock(&arvif->ar->conf_mutex); +} +  static void ath10k_tx_h_update_wep_key(struct sk_buff *skb)  {  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -1419,11 +1927,6 @@ static void ath10k_tx_h_update_wep_key(struct sk_buff *skb)  	struct ath10k *ar = arvif->ar;  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;  	struct ieee80211_key_conf *key = info->control.hw_key; -	int ret; - -	/* TODO AP mode should be implemented */ -	if (vif->type != NL80211_IFTYPE_STATION) -		return;  	if (!ieee80211_has_protected(hdr->frame_control))  		return; @@ -1435,20 +1938,14 @@ static void ath10k_tx_h_update_wep_key(struct sk_buff *skb)  	    key->cipher != WLAN_CIPHER_SUITE_WEP104)  		return; -	if (key->keyidx == arvif->def_wep_key_index) +	if (key->keyidx == arvif->def_wep_key_idx)  		return; -	ath10k_dbg(ATH10K_DBG_MAC, "new wep keyidx will be %d\n", key->keyidx); - -	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, -					WMI_VDEV_PARAM_DEF_KEYID, -					key->keyidx); -	if (ret) { -		ath10k_warn("could not update wep keyidx (%d)\n", ret); -		return; -	} - -	arvif->def_wep_key_index = key->keyidx; +	/* FIXME: Most likely a few frames will be TXed with an old key. Simply +	 * queueing frames until key index is updated is not an option because +	 * sk_buff may need more processing to be done, e.g. offchannel */ +	arvif->def_wep_key_newidx = key->keyidx; +	ieee80211_queue_work(ar->hw, &arvif->wep_key_work);  }  static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, struct sk_buff *skb) @@ -1478,21 +1975,44 @@ static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, struct sk_buff *skb)  static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)  {  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; -	int ret; +	int ret = 0; -	if (ieee80211_is_mgmt(hdr->frame_control)) -		ret = ath10k_htt_mgmt_tx(&ar->htt, skb); -	else if (ieee80211_is_nullfunc(hdr->frame_control)) +	if (ar->htt.target_version_major >= 3) { +		/* Since HTT 3.0 there is no separate mgmt tx command */ +		ret = ath10k_htt_tx(&ar->htt, skb); +		goto exit; +	} + +	if (ieee80211_is_mgmt(hdr->frame_control)) { +		if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX, +			     ar->fw_features)) { +			if (skb_queue_len(&ar->wmi_mgmt_tx_queue) >= +			    ATH10K_MAX_NUM_MGMT_PENDING) { +				ath10k_warn("reached WMI management tranmist queue limit\n"); +				ret = -EBUSY; +				goto exit; +			} + +			skb_queue_tail(&ar->wmi_mgmt_tx_queue, skb); +			ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work); +		} else { +			ret = ath10k_htt_mgmt_tx(&ar->htt, skb); +		} +	} else if (!test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX, +			     ar->fw_features) && +		   ieee80211_is_nullfunc(hdr->frame_control)) {  		/* FW does not report tx status properly for NullFunc frames  		 * unless they are sent through mgmt tx path. mac80211 sends -		 * those frames when it detects link/beacon loss and depends on -		 * the tx status to be correct. */ +		 * those frames when it detects link/beacon loss and depends +		 * on the tx status to be correct. */  		ret = ath10k_htt_mgmt_tx(&ar->htt, skb); -	else +	} else {  		ret = ath10k_htt_tx(&ar->htt, skb); +	} +exit:  	if (ret) { -		ath10k_warn("tx failed (%d). dropping packet.\n", ret); +		ath10k_warn("failed to transmit packet, dropping: %d\n", ret);  		ieee80211_free_txskb(ar->hw, skb);  	}  } @@ -1534,30 +2054,31 @@ void ath10k_offchan_tx_work(struct work_struct *work)  		mutex_lock(&ar->conf_mutex); -		ath10k_dbg(ATH10K_DBG_MAC, "processing offchannel skb %p\n", +		ath10k_dbg(ATH10K_DBG_MAC, "mac offchannel skb %p\n",  			   skb);  		hdr = (struct ieee80211_hdr *)skb->data;  		peer_addr = ieee80211_get_DA(hdr); -		vdev_id = ATH10K_SKB_CB(skb)->htt.vdev_id; +		vdev_id = ATH10K_SKB_CB(skb)->vdev_id;  		spin_lock_bh(&ar->data_lock);  		peer = ath10k_peer_find(ar, vdev_id, peer_addr);  		spin_unlock_bh(&ar->data_lock);  		if (peer) +			/* FIXME: should this use ath10k_warn()? */  			ath10k_dbg(ATH10K_DBG_MAC, "peer %pM on vdev %d already present\n",  				   peer_addr, vdev_id);  		if (!peer) {  			ret = ath10k_peer_create(ar, vdev_id, peer_addr);  			if (ret) -				ath10k_warn("peer %pM on vdev %d not created (%d)\n", +				ath10k_warn("failed to create peer %pM on vdev %d: %d\n",  					    peer_addr, vdev_id, ret);  		}  		spin_lock_bh(&ar->data_lock); -		INIT_COMPLETION(ar->offchan_tx_completed); +		reinit_completion(&ar->offchan_tx_completed);  		ar->offchan_tx_skb = skb;  		spin_unlock_bh(&ar->data_lock); @@ -1572,7 +2093,7 @@ void ath10k_offchan_tx_work(struct work_struct *work)  		if (!peer) {  			ret = ath10k_peer_delete(ar, vdev_id, peer_addr);  			if (ret) -				ath10k_warn("peer %pM on vdev %d not deleted (%d)\n", +				ath10k_warn("failed to delete peer %pM on vdev %d: %d\n",  					    peer_addr, vdev_id, ret);  		} @@ -1580,6 +2101,39 @@ void ath10k_offchan_tx_work(struct work_struct *work)  	}  } +void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar) +{ +	struct sk_buff *skb; + +	for (;;) { +		skb = skb_dequeue(&ar->wmi_mgmt_tx_queue); +		if (!skb) +			break; + +		ieee80211_free_txskb(ar->hw, skb); +	} +} + +void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work) +{ +	struct ath10k *ar = container_of(work, struct ath10k, wmi_mgmt_tx_work); +	struct sk_buff *skb; +	int ret; + +	for (;;) { +		skb = skb_dequeue(&ar->wmi_mgmt_tx_queue); +		if (!skb) +			break; + +		ret = ath10k_wmi_mgmt_tx(ar, skb); +		if (ret) { +			ath10k_warn("failed to transmit management frame via WMI: %d\n", +				    ret); +			ieee80211_free_txskb(ar->hw, skb); +		} +	} +} +  /************/  /* Scanning */  /************/ @@ -1599,7 +2153,7 @@ void ath10k_reset_scan(unsigned long ptr)  		return;  	} -	ath10k_warn("scan timeout. resetting. fw issue?\n"); +	ath10k_warn("scan timed out, firmware problem?\n");  	if (ar->scan.is_roc)  		ieee80211_remain_on_channel_expired(ar->hw); @@ -1635,7 +2189,7 @@ static int ath10k_abort_scan(struct ath10k *ar)  	ret = ath10k_wmi_stop_scan(ar, &arg);  	if (ret) { -		ath10k_warn("could not submit wmi stop scan (%d)\n", ret); +		ath10k_warn("failed to stop wmi scan: %d\n", ret);  		spin_lock_bh(&ar->data_lock);  		ar->scan.in_progress = false;  		ath10k_offchan_tx_purge(ar); @@ -1643,8 +2197,6 @@ static int ath10k_abort_scan(struct ath10k *ar)  		return -EIO;  	} -	ath10k_wmi_flush_tx(ar); -  	ret = wait_for_completion_timeout(&ar->scan.completed, 3*HZ);  	if (ret == 0)  		ath10k_warn("timed out while waiting for scan to stop\n"); @@ -1657,7 +2209,7 @@ static int ath10k_abort_scan(struct ath10k *ar)  	spin_lock_bh(&ar->data_lock);  	if (ar->scan.in_progress) { -		ath10k_warn("could not stop scan. its still in progress\n"); +		ath10k_warn("failed to stop scan, it's still in progress\n");  		ar->scan.in_progress = false;  		ath10k_offchan_tx_purge(ar);  		ret = -ETIMEDOUT; @@ -1678,10 +2230,6 @@ static int ath10k_start_scan(struct ath10k *ar,  	if (ret)  		return ret; -	/* make sure we submit the command so the completion -	* timeout makes sense */ -	ath10k_wmi_flush_tx(ar); -  	ret = wait_for_completion_timeout(&ar->scan.started, 1*HZ);  	if (ret == 0) {  		ath10k_abort_scan(ar); @@ -1709,16 +2257,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;  	struct ath10k *ar = hw->priv; -	struct ath10k_vif *arvif = NULL; -	u32 vdev_id = 0; -	u8 tid; - -	if (info->control.vif) { -		arvif = ath10k_vif_to_arvif(info->control.vif); -		vdev_id = arvif->vdev_id; -	} else if (ar->monitor_enabled) { -		vdev_id = ar->monitor_vdev_id; -	} +	u8 tid, vdev_id;  	/* We should disable CCK RATE due to P2P */  	if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE) @@ -1726,12 +2265,8 @@ static void ath10k_tx(struct ieee80211_hw *hw,  	/* we must calculate tid before we apply qos workaround  	 * as we'd lose the qos control field */ -	tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST; -	if (ieee80211_is_data_qos(hdr->frame_control) && -	    is_unicast_ether_addr(ieee80211_get_DA(hdr))) { -		u8 *qc = ieee80211_get_qos_ctl(hdr); -		tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; -	} +	tid = ath10k_tx_h_get_tid(hdr); +	vdev_id = ath10k_tx_h_get_vdev_id(ar, info);  	/* it makes no sense to process injected frames like that */  	if (info->control.vif && @@ -1742,14 +2277,14 @@ static void ath10k_tx(struct ieee80211_hw *hw,  		ath10k_tx_h_seq_no(skb);  	} -	memset(ATH10K_SKB_CB(skb), 0, sizeof(*ATH10K_SKB_CB(skb))); -	ATH10K_SKB_CB(skb)->htt.vdev_id = vdev_id; +	ATH10K_SKB_CB(skb)->vdev_id = vdev_id; +	ATH10K_SKB_CB(skb)->htt.is_offchan = false;  	ATH10K_SKB_CB(skb)->htt.tid = tid;  	if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {  		spin_lock_bh(&ar->data_lock);  		ATH10K_SKB_CB(skb)->htt.is_offchan = true; -		ATH10K_SKB_CB(skb)->htt.vdev_id = ar->scan.vdev_id; +		ATH10K_SKB_CB(skb)->vdev_id = ar->scan.vdev_id;  		spin_unlock_bh(&ar->data_lock);  		ath10k_dbg(ATH10K_DBG_MAC, "queued offchannel skb %p\n", skb); @@ -1762,117 +2297,330 @@ static void ath10k_tx(struct ieee80211_hw *hw,  	ath10k_tx_htt(ar, skb);  } -/* - * Initialize various parameters with default vaules. - */ +/* Must not be called with conf_mutex held as workers can use that also. */ +static void ath10k_drain_tx(struct ath10k *ar) +{ +	/* make sure rcu-protected mac80211 tx path itself is drained */ +	synchronize_net(); + +	ath10k_offchan_tx_purge(ar); +	ath10k_mgmt_over_wmi_tx_purge(ar); + +	cancel_work_sync(&ar->offchan_tx_work); +	cancel_work_sync(&ar->wmi_mgmt_tx_work); +} +  void ath10k_halt(struct ath10k *ar)  { +	struct ath10k_vif *arvif; +  	lockdep_assert_held(&ar->conf_mutex); +	if (ath10k_monitor_is_enabled(ar)) { +		clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); +		ar->promisc = false; +		ar->monitor = false; +		ath10k_monitor_stop(ar); +	} +  	del_timer_sync(&ar->scan.timeout); -	ath10k_offchan_tx_purge(ar); +	ath10k_reset_scan((unsigned long)ar);  	ath10k_peer_cleanup_all(ar);  	ath10k_core_stop(ar);  	ath10k_hif_power_down(ar);  	spin_lock_bh(&ar->data_lock); -	if (ar->scan.in_progress) { -		del_timer(&ar->scan.timeout); -		ar->scan.in_progress = false; -		ieee80211_scan_completed(ar->hw, true); +	list_for_each_entry(arvif, &ar->arvifs, list) { +		if (!arvif->beacon) +			continue; + +		dma_unmap_single(arvif->ar->dev, +				 ATH10K_SKB_CB(arvif->beacon)->paddr, +				 arvif->beacon->len, DMA_TO_DEVICE); +		dev_kfree_skb_any(arvif->beacon); +		arvif->beacon = NULL;  	}  	spin_unlock_bh(&ar->data_lock);  } +static int ath10k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +{ +	struct ath10k *ar = hw->priv; + +	mutex_lock(&ar->conf_mutex); + +	if (ar->cfg_tx_chainmask) { +		*tx_ant = ar->cfg_tx_chainmask; +		*rx_ant = ar->cfg_rx_chainmask; +	} else { +		*tx_ant = ar->supp_tx_chainmask; +		*rx_ant = ar->supp_rx_chainmask; +	} + +	mutex_unlock(&ar->conf_mutex); + +	return 0; +} + +static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant) +{ +	int ret; + +	lockdep_assert_held(&ar->conf_mutex); + +	ar->cfg_tx_chainmask = tx_ant; +	ar->cfg_rx_chainmask = rx_ant; + +	if ((ar->state != ATH10K_STATE_ON) && +	    (ar->state != ATH10K_STATE_RESTARTED)) +		return 0; + +	ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->tx_chain_mask, +					tx_ant); +	if (ret) { +		ath10k_warn("failed to set tx-chainmask: %d, req 0x%x\n", +			    ret, tx_ant); +		return ret; +	} + +	ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->rx_chain_mask, +					rx_ant); +	if (ret) { +		ath10k_warn("failed to set rx-chainmask: %d, req 0x%x\n", +			    ret, rx_ant); +		return ret; +	} + +	return 0; +} + +static int ath10k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +{ +	struct ath10k *ar = hw->priv; +	int ret; + +	mutex_lock(&ar->conf_mutex); +	ret = __ath10k_set_antenna(ar, tx_ant, rx_ant); +	mutex_unlock(&ar->conf_mutex); +	return ret; +} +  static int ath10k_start(struct ieee80211_hw *hw)  {  	struct ath10k *ar = hw->priv;  	int ret = 0; +	/* +	 * This makes sense only when restarting hw. It is harmless to call +	 * uncoditionally. This is necessary to make sure no HTT/WMI tx +	 * commands will be submitted while restarting. +	 */ +	ath10k_drain_tx(ar); +  	mutex_lock(&ar->conf_mutex); -	if (ar->state != ATH10K_STATE_OFF && -	    ar->state != ATH10K_STATE_RESTARTING) { +	switch (ar->state) { +	case ATH10K_STATE_OFF: +		ar->state = ATH10K_STATE_ON; +		break; +	case ATH10K_STATE_RESTARTING: +		ath10k_halt(ar); +		ar->state = ATH10K_STATE_RESTARTED; +		break; +	case ATH10K_STATE_ON: +	case ATH10K_STATE_RESTARTED: +	case ATH10K_STATE_WEDGED: +		WARN_ON(1);  		ret = -EINVAL; -		goto exit; +		goto err;  	}  	ret = ath10k_hif_power_up(ar);  	if (ret) { -		ath10k_err("could not init hif (%d)\n", ret); -		ar->state = ATH10K_STATE_OFF; -		goto exit; +		ath10k_err("Could not init hif: %d\n", ret); +		goto err_off;  	}  	ret = ath10k_core_start(ar);  	if (ret) { -		ath10k_err("could not init core (%d)\n", ret); -		ath10k_hif_power_down(ar); -		ar->state = ATH10K_STATE_OFF; -		goto exit; +		ath10k_err("Could not init core: %d\n", ret); +		goto err_power_down;  	} -	if (ar->state == ATH10K_STATE_OFF) -		ar->state = ATH10K_STATE_ON; -	else if (ar->state == ATH10K_STATE_RESTARTING) -		ar->state = ATH10K_STATE_RESTARTED; +	ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pmf_qos, 1); +	if (ret) { +		ath10k_warn("failed to enable PMF QOS: %d\n", ret); +		goto err_core_stop; +	} -	ret = ath10k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PMF_QOS, 1); -	if (ret) -		ath10k_warn("could not enable WMI_PDEV_PARAM_PMF_QOS (%d)\n", -			    ret); +	ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 1); +	if (ret) { +		ath10k_warn("failed to enable dynamic BW: %d\n", ret); +		goto err_core_stop; +	} -	ret = ath10k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_DYNAMIC_BW, 0); -	if (ret) -		ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n", +	if (ar->cfg_tx_chainmask) +		__ath10k_set_antenna(ar, ar->cfg_tx_chainmask, +				     ar->cfg_rx_chainmask); + +	/* +	 * By default FW set ARP frames ac to voice (6). In that case ARP +	 * exchange is not working properly for UAPSD enabled AP. ARP requests +	 * which arrives with access category 0 are processed by network stack +	 * and send back with access category 0, but FW changes access category +	 * to 6. Set ARP frames access category to best effort (0) solves +	 * this problem. +	 */ + +	ret = ath10k_wmi_pdev_set_param(ar, +					ar->wmi.pdev_param->arp_ac_override, 0); +	if (ret) { +		ath10k_warn("failed to set arp ac override parameter: %d\n",  			    ret); +		goto err_core_stop; +	} +	ar->num_started_vdevs = 0;  	ath10k_regd_update(ar); -exit:  	mutex_unlock(&ar->conf_mutex);  	return 0; + +err_core_stop: +	ath10k_core_stop(ar); + +err_power_down: +	ath10k_hif_power_down(ar); + +err_off: +	ar->state = ATH10K_STATE_OFF; + +err: +	mutex_unlock(&ar->conf_mutex); +	return ret;  }  static void ath10k_stop(struct ieee80211_hw *hw)  {  	struct ath10k *ar = hw->priv; +	ath10k_drain_tx(ar); +  	mutex_lock(&ar->conf_mutex); -	if (ar->state == ATH10K_STATE_ON || -	    ar->state == ATH10K_STATE_RESTARTED || -	    ar->state == ATH10K_STATE_WEDGED) +	if (ar->state != ATH10K_STATE_OFF) {  		ath10k_halt(ar); - -	ar->state = ATH10K_STATE_OFF; +		ar->state = ATH10K_STATE_OFF; +	}  	mutex_unlock(&ar->conf_mutex); -	cancel_work_sync(&ar->offchan_tx_work);  	cancel_work_sync(&ar->restart_work);  } -static void ath10k_config_ps(struct ath10k *ar) +static int ath10k_config_ps(struct ath10k *ar)  { -	struct ath10k_generic_iter ar_iter; +	struct ath10k_vif *arvif; +	int ret = 0;  	lockdep_assert_held(&ar->conf_mutex); -	/* During HW reconfiguration mac80211 reports all interfaces that were -	 * running until reconfiguration was started. Since FW doesn't have any -	 * vdevs at this point we must not iterate over this interface list. -	 * This setting will be updated upon add_interface(). */ -	if (ar->state == ATH10K_STATE_RESTARTED) -		return; +	list_for_each_entry(arvif, &ar->arvifs, list) { +		ret = ath10k_mac_vif_setup_ps(arvif); +		if (ret) { +			ath10k_warn("failed to setup powersave: %d\n", ret); +			break; +		} +	} -	memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter)); -	ar_iter.ar = ar; +	return ret; +} -	ieee80211_iterate_active_interfaces_atomic( -		ar->hw, IEEE80211_IFACE_ITER_NORMAL, -		ath10k_ps_iter, &ar_iter); +static const char *chandef_get_width(enum nl80211_chan_width width) +{ +	switch (width) { +	case NL80211_CHAN_WIDTH_20_NOHT: +		return "20 (noht)"; +	case NL80211_CHAN_WIDTH_20: +		return "20"; +	case NL80211_CHAN_WIDTH_40: +		return "40"; +	case NL80211_CHAN_WIDTH_80: +		return "80"; +	case NL80211_CHAN_WIDTH_80P80: +		return "80+80"; +	case NL80211_CHAN_WIDTH_160: +		return "160"; +	case NL80211_CHAN_WIDTH_5: +		return "5"; +	case NL80211_CHAN_WIDTH_10: +		return "10"; +	} +	return "?"; +} -	if (ar_iter.ret) -		ath10k_warn("failed to set ps config (%d)\n", ar_iter.ret); +static void ath10k_config_chan(struct ath10k *ar) +{ +	struct ath10k_vif *arvif; +	int ret; + +	lockdep_assert_held(&ar->conf_mutex); + +	ath10k_dbg(ATH10K_DBG_MAC, +		   "mac config channel to %dMHz (cf1 %dMHz cf2 %dMHz width %s)\n", +		   ar->chandef.chan->center_freq, +		   ar->chandef.center_freq1, +		   ar->chandef.center_freq2, +		   chandef_get_width(ar->chandef.width)); + +	/* First stop monitor interface. Some FW versions crash if there's a +	 * lone monitor interface. */ +	if (ar->monitor_started) +		ath10k_monitor_vdev_stop(ar); + +	list_for_each_entry(arvif, &ar->arvifs, list) { +		if (!arvif->is_started) +			continue; + +		if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) +			continue; + +		ret = ath10k_vdev_stop(arvif); +		if (ret) { +			ath10k_warn("failed to stop vdev %d: %d\n", +				    arvif->vdev_id, ret); +			continue; +		} +	} + +	/* all vdevs are now stopped - now attempt to restart them */ + +	list_for_each_entry(arvif, &ar->arvifs, list) { +		if (!arvif->is_started) +			continue; + +		if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) +			continue; + +		ret = ath10k_vdev_start(arvif); +		if (ret) { +			ath10k_warn("failed to start vdev %d: %d\n", +				    arvif->vdev_id, ret); +			continue; +		} + +		if (!arvif->is_up) +			continue; + +		ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, +					 arvif->bssid); +		if (ret) { +			ath10k_warn("failed to bring vdev up %d: %d\n", +				    arvif->vdev_id, ret); +			continue; +		} +	} + +	if (ath10k_monitor_is_enabled(ar)) +		ath10k_monitor_vdev_start(ar, ar->monitor_vdev_id);  }  static int ath10k_config(struct ieee80211_hw *hw, u32 changed) @@ -1880,28 +2628,68 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)  	struct ath10k *ar = hw->priv;  	struct ieee80211_conf *conf = &hw->conf;  	int ret = 0; +	u32 param;  	mutex_lock(&ar->conf_mutex);  	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { -		ath10k_dbg(ATH10K_DBG_MAC, "Config channel %d mhz\n", -			   conf->chandef.chan->center_freq); +		ath10k_dbg(ATH10K_DBG_MAC, +			   "mac config channel %dMHz flags 0x%x radar %d\n", +			   conf->chandef.chan->center_freq, +			   conf->chandef.chan->flags, +			   conf->radar_enabled); +  		spin_lock_bh(&ar->data_lock);  		ar->rx_channel = conf->chandef.chan;  		spin_unlock_bh(&ar->data_lock); + +		ar->radar_enabled = conf->radar_enabled; +		ath10k_recalc_radar_detection(ar); + +		if (!cfg80211_chandef_identical(&ar->chandef, &conf->chandef)) { +			ar->chandef = conf->chandef; +			ath10k_config_chan(ar); +		} +	} + +	if (changed & IEEE80211_CONF_CHANGE_POWER) { +		ath10k_dbg(ATH10K_DBG_MAC, "mac config power %d\n", +			   hw->conf.power_level); + +		param = ar->wmi.pdev_param->txpower_limit2g; +		ret = ath10k_wmi_pdev_set_param(ar, param, +						hw->conf.power_level * 2); +		if (ret) +			ath10k_warn("failed to set 2g txpower %d: %d\n", +				    hw->conf.power_level, ret); + +		param = ar->wmi.pdev_param->txpower_limit5g; +		ret = ath10k_wmi_pdev_set_param(ar, param, +						hw->conf.power_level * 2); +		if (ret) +			ath10k_warn("failed to set 5g txpower %d: %d\n", +				    hw->conf.power_level, ret);  	}  	if (changed & IEEE80211_CONF_CHANGE_PS)  		ath10k_config_ps(ar);  	if (changed & IEEE80211_CONF_CHANGE_MONITOR) { -		if (conf->flags & IEEE80211_CONF_MONITOR) -			ret = ath10k_monitor_create(ar); -		else -			ret = ath10k_monitor_destroy(ar); +		if (conf->flags & IEEE80211_CONF_MONITOR && !ar->monitor) { +			ar->monitor = true; +			ret = ath10k_monitor_start(ar); +			if (ret) { +				ath10k_warn("failed to start monitor (config): %d\n", +					    ret); +				ar->monitor = false; +			} +		} else if (!(conf->flags & IEEE80211_CONF_MONITOR) && +			   ar->monitor) { +			ar->monitor = false; +			ath10k_monitor_stop(ar); +		}  	} -	ath10k_wmi_flush_tx(ar);  	mutex_unlock(&ar->conf_mutex);  	return ret;  } @@ -1922,6 +2710,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,  	int ret = 0;  	u32 value;  	int bit; +	u32 vdev_param;  	mutex_lock(&ar->conf_mutex); @@ -1930,21 +2719,17 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,  	arvif->ar = ar;  	arvif->vif = vif; -	if ((vif->type == NL80211_IFTYPE_MONITOR) && ar->monitor_present) { -		ath10k_warn("Only one monitor interface allowed\n"); -		ret = -EBUSY; -		goto exit; -	} +	INIT_WORK(&arvif->wep_key_work, ath10k_tx_wep_key_work); +	INIT_LIST_HEAD(&arvif->list);  	bit = ffs(ar->free_vdev_map);  	if (bit == 0) {  		ret = -EBUSY; -		goto exit; +		goto err;  	}  	arvif->vdev_id = bit - 1;  	arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE; -	ar->free_vdev_map &= ~(1 << arvif->vdev_id);  	if (ar->p2p)  		arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE; @@ -1973,32 +2758,52 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,  		break;  	} -	ath10k_dbg(ATH10K_DBG_MAC, "Add interface: id %d type %d subtype %d\n", +	ath10k_dbg(ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d\n",  		   arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype);  	ret = ath10k_wmi_vdev_create(ar, arvif->vdev_id, arvif->vdev_type,  				     arvif->vdev_subtype, vif->addr);  	if (ret) { -		ath10k_warn("WMI vdev create failed: ret %d\n", ret); -		goto exit; +		ath10k_warn("failed to create WMI vdev %i: %d\n", +			    arvif->vdev_id, ret); +		goto err;  	} -	ret = ath10k_wmi_vdev_set_param(ar, 0, WMI_VDEV_PARAM_DEF_KEYID, -					arvif->def_wep_key_index); -	if (ret) -		ath10k_warn("Failed to set default keyid: %d\n", ret); +	ar->free_vdev_map &= ~BIT(arvif->vdev_id); +	list_add(&arvif->list, &ar->arvifs); -	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, -					WMI_VDEV_PARAM_TX_ENCAP_TYPE, +	vdev_param = ar->wmi.vdev_param->def_keyid; +	ret = ath10k_wmi_vdev_set_param(ar, 0, vdev_param, +					arvif->def_wep_key_idx); +	if (ret) { +		ath10k_warn("failed to set vdev %i default key id: %d\n", +			    arvif->vdev_id, ret); +		goto err_vdev_delete; +	} + +	vdev_param = ar->wmi.vdev_param->tx_encap_type; +	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,  					ATH10K_HW_TXRX_NATIVE_WIFI); -	if (ret) -		ath10k_warn("Failed to set TX encap: %d\n", ret); +	/* 10.X firmware does not support this VDEV parameter. Do not warn */ +	if (ret && ret != -EOPNOTSUPP) { +		ath10k_warn("failed to set vdev %i TX encapsulation: %d\n", +			    arvif->vdev_id, ret); +		goto err_vdev_delete; +	}  	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {  		ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr);  		if (ret) { -			ath10k_warn("Failed to create peer for AP: %d\n", ret); -			goto exit; +			ath10k_warn("failed to create vdev %i peer for AP: %d\n", +				    arvif->vdev_id, ret); +			goto err_vdev_delete; +		} + +		ret = ath10k_mac_set_kickout(arvif); +		if (ret) { +			ath10k_warn("failed to set vdev %i kickout parameters: %d\n", +				    arvif->vdev_id, ret); +			goto err_peer_delete;  		}  	} @@ -2007,39 +2812,62 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,  		value = WMI_STA_PS_RX_WAKE_POLICY_WAKE;  		ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,  						  param, value); -		if (ret) -			ath10k_warn("Failed to set RX wake policy: %d\n", ret); +		if (ret) { +			ath10k_warn("failed to set vdev %i RX wake policy: %d\n", +				    arvif->vdev_id, ret); +			goto err_peer_delete; +		}  		param = WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD;  		value = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS;  		ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,  						  param, value); -		if (ret) -			ath10k_warn("Failed to set TX wake thresh: %d\n", ret); +		if (ret) { +			ath10k_warn("failed to set vdev %i TX wake thresh: %d\n", +				    arvif->vdev_id, ret); +			goto err_peer_delete; +		}  		param = WMI_STA_PS_PARAM_PSPOLL_COUNT;  		value = WMI_STA_PS_PSPOLL_COUNT_NO_MAX;  		ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,  						  param, value); -		if (ret) -			ath10k_warn("Failed to set PSPOLL count: %d\n", ret); +		if (ret) { +			ath10k_warn("failed to set vdev %i PSPOLL count: %d\n", +				    arvif->vdev_id, ret); +			goto err_peer_delete; +		}  	}  	ret = ath10k_mac_set_rts(arvif, ar->hw->wiphy->rts_threshold); -	if (ret) -		ath10k_warn("failed to set rts threshold for vdev %d (%d)\n", +	if (ret) { +		ath10k_warn("failed to set rts threshold for vdev %d: %d\n",  			    arvif->vdev_id, ret); +		goto err_peer_delete; +	}  	ret = ath10k_mac_set_frag(arvif, ar->hw->wiphy->frag_threshold); -	if (ret) -		ath10k_warn("failed to set frag threshold for vdev %d (%d)\n", +	if (ret) { +		ath10k_warn("failed to set frag threshold for vdev %d: %d\n",  			    arvif->vdev_id, ret); +		goto err_peer_delete; +	} -	if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) -		ar->monitor_present = true; +	mutex_unlock(&ar->conf_mutex); +	return 0; -exit: +err_peer_delete: +	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) +		ath10k_wmi_peer_delete(ar, arvif->vdev_id, vif->addr); + +err_vdev_delete: +	ath10k_wmi_vdev_delete(ar, arvif->vdev_id); +	ar->free_vdev_map &= ~BIT(arvif->vdev_id); +	list_del(&arvif->list); + +err:  	mutex_unlock(&ar->conf_mutex); +  	return ret;  } @@ -2052,24 +2880,37 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,  	mutex_lock(&ar->conf_mutex); -	ath10k_dbg(ATH10K_DBG_MAC, "Remove interface: id %d\n", arvif->vdev_id); +	cancel_work_sync(&arvif->wep_key_work); + +	spin_lock_bh(&ar->data_lock); +	if (arvif->beacon) { +		dma_unmap_single(arvif->ar->dev, +				 ATH10K_SKB_CB(arvif->beacon)->paddr, +				 arvif->beacon->len, DMA_TO_DEVICE); +		dev_kfree_skb_any(arvif->beacon); +		arvif->beacon = NULL; +	} +	spin_unlock_bh(&ar->data_lock);  	ar->free_vdev_map |= 1 << (arvif->vdev_id); +	list_del(&arvif->list);  	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {  		ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, vif->addr);  		if (ret) -			ath10k_warn("Failed to remove peer for AP: %d\n", ret); +			ath10k_warn("failed to remove peer for AP vdev %i: %d\n", +				    arvif->vdev_id, ret);  		kfree(arvif->u.ap.noa_data);  	} +	ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %i delete (remove interface)\n", +		   arvif->vdev_id); +  	ret = ath10k_wmi_vdev_delete(ar, arvif->vdev_id);  	if (ret) -		ath10k_warn("WMI vdev delete failed: %d\n", ret); - -	if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) -		ar->monitor_present = false; +		ath10k_warn("failed to delete WMI vdev %i: %d\n", +			    arvif->vdev_id, ret);  	ath10k_peer_cleanup(ar, arvif->vdev_id); @@ -2103,20 +2944,17 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw,  	*total_flags &= SUPPORTED_FILTERS;  	ar->filter_flags = *total_flags; -	if ((ar->filter_flags & FIF_PROMISC_IN_BSS) && -	    !ar->monitor_enabled) { -		ret = ath10k_monitor_start(ar, ar->monitor_vdev_id); -		if (ret) -			ath10k_warn("Unable to start monitor mode\n"); -		else -			ath10k_dbg(ATH10K_DBG_MAC, "Monitor mode started\n"); -	} else if (!(ar->filter_flags & FIF_PROMISC_IN_BSS) && -		   ar->monitor_enabled) { -		ret = ath10k_monitor_stop(ar); -		if (ret) -			ath10k_warn("Unable to stop monitor mode\n"); -		else -			ath10k_dbg(ATH10K_DBG_MAC, "Monitor mode stopped\n"); +	if (ar->filter_flags & FIF_PROMISC_IN_BSS && !ar->promisc) { +		ar->promisc = true; +		ret = ath10k_monitor_start(ar); +		if (ret) { +			ath10k_warn("failed to start monitor (promisc): %d\n", +				    ret); +			ar->promisc = false; +		} +	} else if (!(ar->filter_flags & FIF_PROMISC_IN_BSS) && ar->promisc) { +		ar->promisc = false; +		ath10k_monitor_stop(ar);  	}  	mutex_unlock(&ar->conf_mutex); @@ -2130,6 +2968,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,  	struct ath10k *ar = hw->priv;  	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);  	int ret = 0; +	u32 vdev_param, pdev_param;  	mutex_lock(&ar->conf_mutex); @@ -2138,44 +2977,44 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,  	if (changed & BSS_CHANGED_BEACON_INT) {  		arvif->beacon_interval = info->beacon_int; -		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, -						WMI_VDEV_PARAM_BEACON_INTERVAL, +		vdev_param = ar->wmi.vdev_param->beacon_interval; +		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,  						arvif->beacon_interval); +		ath10k_dbg(ATH10K_DBG_MAC, +			   "mac vdev %d beacon_interval %d\n", +			   arvif->vdev_id, arvif->beacon_interval); +  		if (ret) -			ath10k_warn("Failed to set beacon interval for VDEV: %d\n", -				    arvif->vdev_id); -		else -			ath10k_dbg(ATH10K_DBG_MAC, -				   "Beacon interval: %d set for VDEV: %d\n", -				   arvif->beacon_interval, arvif->vdev_id); +			ath10k_warn("failed to set beacon interval for vdev %d: %i\n", +				    arvif->vdev_id, ret);  	}  	if (changed & BSS_CHANGED_BEACON) { -		ret = ath10k_wmi_pdev_set_param(ar, -						WMI_PDEV_PARAM_BEACON_TX_MODE, +		ath10k_dbg(ATH10K_DBG_MAC, +			   "vdev %d set beacon tx mode to staggered\n", +			   arvif->vdev_id); + +		pdev_param = ar->wmi.pdev_param->beacon_tx_mode; +		ret = ath10k_wmi_pdev_set_param(ar, pdev_param,  						WMI_BEACON_STAGGERED_MODE);  		if (ret) -			ath10k_warn("Failed to set beacon mode for VDEV: %d\n", -				    arvif->vdev_id); -		else -			ath10k_dbg(ATH10K_DBG_MAC, -				   "Set staggered beacon mode for VDEV: %d\n", -				   arvif->vdev_id); +			ath10k_warn("failed to set beacon mode for vdev %d: %i\n", +				    arvif->vdev_id, ret);  	}  	if (changed & BSS_CHANGED_BEACON_INFO) {  		arvif->dtim_period = info->dtim_period; -		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, -						WMI_VDEV_PARAM_DTIM_PERIOD, +		ath10k_dbg(ATH10K_DBG_MAC, +			   "mac vdev %d dtim_period %d\n", +			   arvif->vdev_id, arvif->dtim_period); + +		vdev_param = ar->wmi.vdev_param->dtim_period; +		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,  						arvif->dtim_period);  		if (ret) -			ath10k_warn("Failed to set dtim period for VDEV: %d\n", -				    arvif->vdev_id); -		else -			ath10k_dbg(ATH10K_DBG_MAC, -				   "Set dtim period: %d for VDEV: %d\n", -				   arvif->dtim_period, arvif->vdev_id); +			ath10k_warn("failed to set dtim period for vdev %d: %i\n", +				    arvif->vdev_id, ret);  	}  	if (changed & BSS_CHANGED_SSID && @@ -2186,32 +3025,42 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,  		arvif->u.ap.hidden_ssid = info->hidden_ssid;  	} -	if (changed & BSS_CHANGED_BSSID) { +	/* +	 * Firmware manages AP self-peer internally so make sure to not create +	 * it in driver. Otherwise AP self-peer deletion may timeout later. +	 */ +	if (changed & BSS_CHANGED_BSSID && +	    vif->type != NL80211_IFTYPE_AP) {  		if (!is_zero_ether_addr(info->bssid)) { +			ath10k_dbg(ATH10K_DBG_MAC, +				   "mac vdev %d create peer %pM\n", +				   arvif->vdev_id, info->bssid); +  			ret = ath10k_peer_create(ar, arvif->vdev_id,  						 info->bssid);  			if (ret) -				ath10k_warn("Failed to add peer: %pM for VDEV: %d\n", -					    info->bssid, arvif->vdev_id); -			else -				ath10k_dbg(ATH10K_DBG_MAC, -					   "Added peer: %pM for VDEV: %d\n", -					   info->bssid, arvif->vdev_id); - +				ath10k_warn("failed to add peer %pM for vdev %d when changing bssid: %i\n", +					    info->bssid, arvif->vdev_id, ret);  			if (vif->type == NL80211_IFTYPE_STATION) {  				/*  				 * this is never erased as we it for crypto key  				 * clearing; this is FW requirement  				 */ -				memcpy(arvif->u.sta.bssid, info->bssid, -				       ETH_ALEN); +				memcpy(arvif->bssid, info->bssid, ETH_ALEN); + +				ath10k_dbg(ATH10K_DBG_MAC, +					   "mac vdev %d start %pM\n", +					   arvif->vdev_id, info->bssid);  				ret = ath10k_vdev_start(arvif); -				if (!ret) -					ath10k_dbg(ATH10K_DBG_MAC, -						   "VDEV: %d started with BSSID: %pM\n", -						   arvif->vdev_id, info->bssid); +				if (ret) { +					ath10k_warn("failed to start vdev %i: %d\n", +						    arvif->vdev_id, ret); +					goto exit; +				} + +				arvif->is_started = true;  			}  			/* @@ -2220,7 +3069,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,  			 * IBSS in order to remove BSSID peer.  			 */  			if (vif->type == NL80211_IFTYPE_ADHOC) -				memcpy(arvif->u.ibss.bssid, info->bssid, +				memcpy(arvif->bssid, info->bssid,  				       ETH_ALEN);  		}  	} @@ -2229,22 +3078,14 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,  		ath10k_control_beaconing(arvif, info);  	if (changed & BSS_CHANGED_ERP_CTS_PROT) { -		u32 cts_prot; -		if (info->use_cts_prot) -			cts_prot = 1; -		else -			cts_prot = 0; +		arvif->use_cts_prot = info->use_cts_prot; +		ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n", +			   arvif->vdev_id, info->use_cts_prot); -		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, -						WMI_VDEV_PARAM_ENABLE_RTSCTS, -						cts_prot); +		ret = ath10k_recalc_rtscts_prot(arvif);  		if (ret) -			ath10k_warn("Failed to set CTS prot for VDEV: %d\n", -				    arvif->vdev_id); -		else -			ath10k_dbg(ATH10K_DBG_MAC, -				   "Set CTS prot: %d for VDEV: %d\n", -				   cts_prot, arvif->vdev_id); +			ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n", +				    arvif->vdev_id, ret);  	}  	if (changed & BSS_CHANGED_ERP_SLOT) { @@ -2255,16 +3096,15 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,  		else  			slottime = WMI_VDEV_SLOT_TIME_LONG; /* 20us */ -		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, -						WMI_VDEV_PARAM_SLOT_TIME, +		ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d slot_time %d\n", +			   arvif->vdev_id, slottime); + +		vdev_param = ar->wmi.vdev_param->slot_time; +		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,  						slottime);  		if (ret) -			ath10k_warn("Failed to set erp slot for VDEV: %d\n", -				    arvif->vdev_id); -		else -			ath10k_dbg(ATH10K_DBG_MAC, -				   "Set slottime: %d for VDEV: %d\n", -				   slottime, arvif->vdev_id); +			ath10k_warn("failed to set erp slot for vdev %d: %i\n", +				    arvif->vdev_id, ret);  	}  	if (changed & BSS_CHANGED_ERP_PREAMBLE) { @@ -2274,16 +3114,16 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,  		else  			preamble = WMI_VDEV_PREAMBLE_LONG; -		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, -						WMI_VDEV_PARAM_PREAMBLE, +		ath10k_dbg(ATH10K_DBG_MAC, +			   "mac vdev %d preamble %dn", +			   arvif->vdev_id, preamble); + +		vdev_param = ar->wmi.vdev_param->preamble; +		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,  						preamble);  		if (ret) -			ath10k_warn("Failed to set preamble for VDEV: %d\n", -				    arvif->vdev_id); -		else -			ath10k_dbg(ATH10K_DBG_MAC, -				   "Set preamble: %d for VDEV: %d\n", -				   preamble, arvif->vdev_id); +			ath10k_warn("failed to set preamble for vdev %d: %i\n", +				    arvif->vdev_id, ret);  	}  	if (changed & BSS_CHANGED_ASSOC) { @@ -2291,6 +3131,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,  			ath10k_bss_assoc(hw, vif, info);  	} +exit:  	mutex_unlock(&ar->conf_mutex);  } @@ -2313,8 +3154,8 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw,  		goto exit;  	} -	INIT_COMPLETION(ar->scan.started); -	INIT_COMPLETION(ar->scan.completed); +	reinit_completion(&ar->scan.started); +	reinit_completion(&ar->scan.completed);  	ar->scan.in_progress = true;  	ar->scan.aborting = false;  	ar->scan.is_roc = false; @@ -2352,7 +3193,7 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw,  	ret = ath10k_start_scan(ar, &arg);  	if (ret) { -		ath10k_warn("could not start hw scan (%d)\n", ret); +		ath10k_warn("failed to start hw scan: %d\n", ret);  		spin_lock_bh(&ar->data_lock);  		ar->scan.in_progress = false;  		spin_unlock_bh(&ar->data_lock); @@ -2372,13 +3213,50 @@ static void ath10k_cancel_hw_scan(struct ieee80211_hw *hw,  	mutex_lock(&ar->conf_mutex);  	ret = ath10k_abort_scan(ar);  	if (ret) { -		ath10k_warn("couldn't abort scan (%d). forcefully sending scan completion to mac80211\n", -			    ret); +		ath10k_warn("failed to abort scan: %d\n", ret);  		ieee80211_scan_completed(hw, 1 /* aborted */);  	}  	mutex_unlock(&ar->conf_mutex);  } +static void ath10k_set_key_h_def_keyidx(struct ath10k *ar, +					struct ath10k_vif *arvif, +					enum set_key_cmd cmd, +					struct ieee80211_key_conf *key) +{ +	u32 vdev_param = arvif->ar->wmi.vdev_param->def_keyid; +	int ret; + +	/* 10.1 firmware branch requires default key index to be set to group +	 * key index after installing it. Otherwise FW/HW Txes corrupted +	 * frames with multi-vif APs. This is not required for main firmware +	 * branch (e.g. 636). +	 * +	 * FIXME: This has been tested only in AP. It remains unknown if this +	 * is required for multi-vif STA interfaces on 10.1 */ + +	if (arvif->vdev_type != WMI_VDEV_TYPE_AP) +		return; + +	if (key->cipher == WLAN_CIPHER_SUITE_WEP40) +		return; + +	if (key->cipher == WLAN_CIPHER_SUITE_WEP104) +		return; + +	if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) +		return; + +	if (cmd != SET_KEY) +		return; + +	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, +					key->keyidx); +	if (ret) +		ath10k_warn("failed to set vdev %i group key as default key: %d\n", +			    arvif->vdev_id, ret); +} +  static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,  			  struct ieee80211_vif *vif, struct ieee80211_sta *sta,  			  struct ieee80211_key_conf *key) @@ -2413,7 +3291,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,  	if (!peer) {  		if (cmd == SET_KEY) { -			ath10k_warn("cannot install key for non-existent peer %pM\n", +			ath10k_warn("failed to install key for non-existent peer %pM\n",  				    peer_addr);  			ret = -EOPNOTSUPP;  			goto exit; @@ -2436,10 +3314,13 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,  	ret = ath10k_install_key(arvif, key, cmd, peer_addr);  	if (ret) { -		ath10k_warn("ath10k_install_key failed (%d)\n", ret); +		ath10k_warn("failed to install key for vdev %i peer %pM: %d\n", +			    arvif->vdev_id, peer_addr, ret);  		goto exit;  	} +	ath10k_set_key_h_def_keyidx(ar, arvif, cmd, key); +  	spin_lock_bh(&ar->data_lock);  	peer = ath10k_peer_find(ar, arvif->vdev_id, peer_addr);  	if (peer && cmd == SET_KEY) @@ -2448,7 +3329,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,  		peer->keys[key->keyidx] = NULL;  	else if (peer == NULL)  		/* impossible unless FW goes crazy */ -		ath10k_warn("peer %pM disappeared!\n", peer_addr); +		ath10k_warn("Peer %pM disappeared!\n", peer_addr);  	spin_unlock_bh(&ar->data_lock);  exit: @@ -2456,6 +3337,79 @@ exit:  	return ret;  } +static void ath10k_sta_rc_update_wk(struct work_struct *wk) +{ +	struct ath10k *ar; +	struct ath10k_vif *arvif; +	struct ath10k_sta *arsta; +	struct ieee80211_sta *sta; +	u32 changed, bw, nss, smps; +	int err; + +	arsta = container_of(wk, struct ath10k_sta, update_wk); +	sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv); +	arvif = arsta->arvif; +	ar = arvif->ar; + +	spin_lock_bh(&ar->data_lock); + +	changed = arsta->changed; +	arsta->changed = 0; + +	bw = arsta->bw; +	nss = arsta->nss; +	smps = arsta->smps; + +	spin_unlock_bh(&ar->data_lock); + +	mutex_lock(&ar->conf_mutex); + +	if (changed & IEEE80211_RC_BW_CHANGED) { +		ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n", +			   sta->addr, bw); + +		err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, +						WMI_PEER_CHAN_WIDTH, bw); +		if (err) +			ath10k_warn("failed to update STA %pM peer bw %d: %d\n", +				    sta->addr, bw, err); +	} + +	if (changed & IEEE80211_RC_NSS_CHANGED) { +		ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM nss %d\n", +			   sta->addr, nss); + +		err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, +						WMI_PEER_NSS, nss); +		if (err) +			ath10k_warn("failed to update STA %pM nss %d: %d\n", +				    sta->addr, nss, err); +	} + +	if (changed & IEEE80211_RC_SMPS_CHANGED) { +		ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM smps %d\n", +			   sta->addr, smps); + +		err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, +						WMI_PEER_SMPS_STATE, smps); +		if (err) +			ath10k_warn("failed to update STA %pM smps %d: %d\n", +				    sta->addr, smps, err); +	} + +	if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { +		ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM supp rates\n", +			   sta->addr); + +		err = ath10k_station_assoc(ar, arvif, sta, true); +		if (err) +			ath10k_warn("failed to reassociate station: %pM\n", +				    sta->addr); +	} + +	mutex_unlock(&ar->conf_mutex); +} +  static int ath10k_sta_state(struct ieee80211_hw *hw,  			    struct ieee80211_vif *vif,  			    struct ieee80211_sta *sta, @@ -2464,8 +3418,22 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,  {  	struct ath10k *ar = hw->priv;  	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); +	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; +	int max_num_peers;  	int ret = 0; +	if (old_state == IEEE80211_STA_NOTEXIST && +	    new_state == IEEE80211_STA_NONE) { +		memset(arsta, 0, sizeof(*arsta)); +		arsta->arvif = arvif; +		INIT_WORK(&arsta->update_wk, ath10k_sta_rc_update_wk); +	} + +	/* cancel must be done outside the mutex to avoid deadlock */ +	if ((old_state == IEEE80211_STA_NONE && +	     new_state == IEEE80211_STA_NOTEXIST)) +		cancel_work_sync(&arsta->update_wk); +  	mutex_lock(&ar->conf_mutex);  	if (old_state == IEEE80211_STA_NOTEXIST && @@ -2474,27 +3442,38 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,  		/*  		 * New station addition.  		 */ +		if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) +			max_num_peers = TARGET_10X_NUM_PEERS_MAX - 1; +		else +			max_num_peers = TARGET_NUM_PEERS; + +		if (ar->num_peers >= max_num_peers) { +			ath10k_warn("number of peers exceeded: peers number %d (max peers %d)\n", +				    ar->num_peers, max_num_peers); +			ret = -ENOBUFS; +			goto exit; +		} + +		ath10k_dbg(ATH10K_DBG_MAC, +			   "mac vdev %d peer create %pM (new sta) num_peers %d\n", +			   arvif->vdev_id, sta->addr, ar->num_peers); +  		ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);  		if (ret) -			ath10k_warn("Failed to add peer: %pM for VDEV: %d\n", -				    sta->addr, arvif->vdev_id); -		else -			ath10k_dbg(ATH10K_DBG_MAC, -				   "Added peer: %pM for VDEV: %d\n", -				   sta->addr, arvif->vdev_id); +			ath10k_warn("failed to add peer %pM for vdev %d when adding a new sta: %i\n", +				    sta->addr, arvif->vdev_id, ret);  	} else if ((old_state == IEEE80211_STA_NONE &&  		    new_state == IEEE80211_STA_NOTEXIST)) {  		/*  		 * Existing station deletion.  		 */ +		ath10k_dbg(ATH10K_DBG_MAC, +			   "mac vdev %d peer delete %pM (sta gone)\n", +			   arvif->vdev_id, sta->addr);  		ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);  		if (ret) -			ath10k_warn("Failed to delete peer: %pM for VDEV: %d\n", -				    sta->addr, arvif->vdev_id); -		else -			ath10k_dbg(ATH10K_DBG_MAC, -				   "Removed peer: %pM for VDEV: %d\n", -				   sta->addr, arvif->vdev_id); +			ath10k_warn("failed to delete peer %pM for vdev %d: %i\n", +				    sta->addr, arvif->vdev_id, ret);  		if (vif->type == NL80211_IFTYPE_STATION)  			ath10k_bss_disassoc(hw, vif); @@ -2505,14 +3484,13 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,  		/*  		 * New association.  		 */ -		ret = ath10k_station_assoc(ar, arvif, sta); +		ath10k_dbg(ATH10K_DBG_MAC, "mac sta %pM associated\n", +			   sta->addr); + +		ret = ath10k_station_assoc(ar, arvif, sta, false);  		if (ret) -			ath10k_warn("Failed to associate station: %pM\n", -				    sta->addr); -		else -			ath10k_dbg(ATH10K_DBG_MAC, -				   "Station %pM moved to assoc state\n", -				   sta->addr); +			ath10k_warn("failed to associate station %pM for vdev %i: %i\n", +				    sta->addr, arvif->vdev_id, ret);  	} else if (old_state == IEEE80211_STA_ASSOC &&  		   new_state == IEEE80211_STA_AUTH &&  		   (vif->type == NL80211_IFTYPE_AP || @@ -2520,16 +3498,15 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,  		/*  		 * Disassociation.  		 */ +		ath10k_dbg(ATH10K_DBG_MAC, "mac sta %pM disassociated\n", +			   sta->addr); +  		ret = ath10k_station_disassoc(ar, arvif, sta);  		if (ret) -			ath10k_warn("Failed to disassociate station: %pM\n", -				    sta->addr); -		else -			ath10k_dbg(ATH10K_DBG_MAC, -				   "Station %pM moved to disassociated state\n", -				   sta->addr); +			ath10k_warn("failed to disassociate station: %pM vdev %i: %i\n", +				    sta->addr, arvif->vdev_id, ret);  	} - +exit:  	mutex_unlock(&ar->conf_mutex);  	return ret;  } @@ -2574,7 +3551,7 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif,  					  WMI_STA_PS_PARAM_UAPSD,  					  arvif->u.sta.uapsd);  	if (ret) { -		ath10k_warn("could not set uapsd params %d\n", ret); +		ath10k_warn("failed to set uapsd params: %d\n", ret);  		goto exit;  	} @@ -2587,7 +3564,7 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif,  					  WMI_STA_PS_PARAM_RX_WAKE_POLICY,  					  value);  	if (ret) -		ath10k_warn("could not set rx wake param %d\n", ret); +		ath10k_warn("failed to set rx wake param: %d\n", ret);  exit:  	return ret; @@ -2637,13 +3614,13 @@ static int ath10k_conf_tx(struct ieee80211_hw *hw,  	/* FIXME: FW accepts wmm params per hw, not per vif */  	ret = ath10k_wmi_pdev_set_wmm_params(ar, &ar->wmm_params);  	if (ret) { -		ath10k_warn("could not set wmm params %d\n", ret); +		ath10k_warn("failed to set wmm params: %d\n", ret);  		goto exit;  	}  	ret = ath10k_conf_tx_uapsd(ar, vif, ac, params->uapsd);  	if (ret) -		ath10k_warn("could not set sta uapsd %d\n", ret); +		ath10k_warn("failed to set sta uapsd: %d\n", ret);  exit:  	mutex_unlock(&ar->conf_mutex); @@ -2672,9 +3649,9 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,  		goto exit;  	} -	INIT_COMPLETION(ar->scan.started); -	INIT_COMPLETION(ar->scan.completed); -	INIT_COMPLETION(ar->scan.on_channel); +	reinit_completion(&ar->scan.started); +	reinit_completion(&ar->scan.completed); +	reinit_completion(&ar->scan.on_channel);  	ar->scan.in_progress = true;  	ar->scan.aborting = false;  	ar->scan.is_roc = true; @@ -2696,7 +3673,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,  	ret = ath10k_start_scan(ar, &arg);  	if (ret) { -		ath10k_warn("could not start roc scan (%d)\n", ret); +		ath10k_warn("failed to start roc scan: %d\n", ret);  		spin_lock_bh(&ar->data_lock);  		ar->scan.in_progress = false;  		spin_unlock_bh(&ar->data_lock); @@ -2705,7 +3682,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,  	ret = wait_for_completion_timeout(&ar->scan.on_channel, 3*HZ);  	if (ret == 0) { -		ath10k_warn("could not switch to channel for roc scan\n"); +		ath10k_warn("failed to switch to channel for roc scan\n");  		ath10k_abort_scan(ar);  		ret = -ETIMEDOUT;  		goto exit; @@ -2732,91 +3709,55 @@ static int ath10k_cancel_remain_on_channel(struct ieee80211_hw *hw)   * Both RTS and Fragmentation threshold are interface-specific   * in ath10k, but device-specific in mac80211.   */ -static void ath10k_set_rts_iter(void *data, u8 *mac, struct ieee80211_vif *vif) -{ -	struct ath10k_generic_iter *ar_iter = data; -	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); -	u32 rts = ar_iter->ar->hw->wiphy->rts_threshold; - -	lockdep_assert_held(&arvif->ar->conf_mutex); - -	/* During HW reconfiguration mac80211 reports all interfaces that were -	 * running until reconfiguration was started. Since FW doesn't have any -	 * vdevs at this point we must not iterate over this interface list. -	 * This setting will be updated upon add_interface(). */ -	if (ar_iter->ar->state == ATH10K_STATE_RESTARTED) -		return; - -	ar_iter->ret = ath10k_mac_set_rts(arvif, rts); -	if (ar_iter->ret) -		ath10k_warn("Failed to set RTS threshold for VDEV: %d\n", -			    arvif->vdev_id); -	else -		ath10k_dbg(ATH10K_DBG_MAC, -			   "Set RTS threshold: %d for VDEV: %d\n", -			   rts, arvif->vdev_id); -}  static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)  { -	struct ath10k_generic_iter ar_iter;  	struct ath10k *ar = hw->priv; - -	memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter)); -	ar_iter.ar = ar; +	struct ath10k_vif *arvif; +	int ret = 0;  	mutex_lock(&ar->conf_mutex); -	ieee80211_iterate_active_interfaces_atomic( -		hw, IEEE80211_IFACE_ITER_NORMAL, -		ath10k_set_rts_iter, &ar_iter); -	mutex_unlock(&ar->conf_mutex); - -	return ar_iter.ret; -} +	list_for_each_entry(arvif, &ar->arvifs, list) { +		ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d rts threshold %d\n", +			   arvif->vdev_id, value); -static void ath10k_set_frag_iter(void *data, u8 *mac, struct ieee80211_vif *vif) -{ -	struct ath10k_generic_iter *ar_iter = data; -	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); -	u32 frag = ar_iter->ar->hw->wiphy->frag_threshold; - -	lockdep_assert_held(&arvif->ar->conf_mutex); - -	/* During HW reconfiguration mac80211 reports all interfaces that were -	 * running until reconfiguration was started. Since FW doesn't have any -	 * vdevs at this point we must not iterate over this interface list. -	 * This setting will be updated upon add_interface(). */ -	if (ar_iter->ar->state == ATH10K_STATE_RESTARTED) -		return; +		ret = ath10k_mac_set_rts(arvif, value); +		if (ret) { +			ath10k_warn("failed to set rts threshold for vdev %d: %d\n", +				    arvif->vdev_id, ret); +			break; +		} +	} +	mutex_unlock(&ar->conf_mutex); -	ar_iter->ret = ath10k_mac_set_frag(arvif, frag); -	if (ar_iter->ret) -		ath10k_warn("Failed to set frag threshold for VDEV: %d\n", -			    arvif->vdev_id); -	else -		ath10k_dbg(ATH10K_DBG_MAC, -			   "Set frag threshold: %d for VDEV: %d\n", -			   frag, arvif->vdev_id); +	return ret;  }  static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value)  { -	struct ath10k_generic_iter ar_iter;  	struct ath10k *ar = hw->priv; - -	memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter)); -	ar_iter.ar = ar; +	struct ath10k_vif *arvif; +	int ret = 0;  	mutex_lock(&ar->conf_mutex); -	ieee80211_iterate_active_interfaces_atomic( -		hw, IEEE80211_IFACE_ITER_NORMAL, -		ath10k_set_frag_iter, &ar_iter); +	list_for_each_entry(arvif, &ar->arvifs, list) { +		ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n", +			   arvif->vdev_id, value); + +		ret = ath10k_mac_set_rts(arvif, value); +		if (ret) { +			ath10k_warn("failed to set fragmentation threshold for vdev %d: %d\n", +				    arvif->vdev_id, ret); +			break; +		} +	}  	mutex_unlock(&ar->conf_mutex); -	return ar_iter.ret; +	return ret;  } -static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +			 u32 queues, bool drop)  {  	struct ath10k *ar = hw->priv;  	bool skip; @@ -2836,8 +3777,7 @@ static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)  			bool empty;  			spin_lock_bh(&ar->htt.tx_lock); -			empty = bitmap_empty(ar->htt.used_msdu_ids, -					     ar->htt.max_num_pending_tx); +			empty = (ar->htt.num_pending_tx == 0);  			spin_unlock_bh(&ar->htt.tx_lock);  			skip = (ar->state == ATH10K_STATE_WEDGED); @@ -2846,7 +3786,8 @@ static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)  		}), ATH10K_FLUSH_TIMEOUT_HZ);  	if (ret <= 0 || skip) -		ath10k_warn("tx not flushed\n"); +		ath10k_warn("failed to flush transmit queue (skip %i ar-state %i): %i\n", +			    skip, ar->state, ret);  skip:  	mutex_unlock(&ar->conf_mutex); @@ -2868,37 +3809,33 @@ static int ath10k_suspend(struct ieee80211_hw *hw,  	struct ath10k *ar = hw->priv;  	int ret; -	ar->is_target_paused = false; +	mutex_lock(&ar->conf_mutex); -	ret = ath10k_wmi_pdev_suspend_target(ar); +	ret = ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND);  	if (ret) { -		ath10k_warn("could not suspend target (%d)\n", ret); -		return 1; -	} - -	ret = wait_event_interruptible_timeout(ar->event_queue, -					       ar->is_target_paused == true, -					       1 * HZ); -	if (ret < 0) { -		ath10k_warn("suspend interrupted (%d)\n", ret); -		goto resume; -	} else if (ret == 0) { -		ath10k_warn("suspend timed out - target pause event never came\n"); -		goto resume; +		if (ret == -ETIMEDOUT) +			goto resume; +		ret = 1; +		goto exit;  	}  	ret = ath10k_hif_suspend(ar);  	if (ret) { -		ath10k_warn("could not suspend hif (%d)\n", ret); +		ath10k_warn("failed to suspend hif: %d\n", ret);  		goto resume;  	} -	return 0; +	ret = 0; +	goto exit;  resume:  	ret = ath10k_wmi_pdev_resume_target(ar);  	if (ret) -		ath10k_warn("could not resume target (%d)\n", ret); -	return 1; +		ath10k_warn("failed to resume target: %d\n", ret); + +	ret = 1; +exit: +	mutex_unlock(&ar->conf_mutex); +	return ret;  }  static int ath10k_resume(struct ieee80211_hw *hw) @@ -2906,19 +3843,26 @@ static int ath10k_resume(struct ieee80211_hw *hw)  	struct ath10k *ar = hw->priv;  	int ret; +	mutex_lock(&ar->conf_mutex); +  	ret = ath10k_hif_resume(ar);  	if (ret) { -		ath10k_warn("could not resume hif (%d)\n", ret); -		return 1; +		ath10k_warn("failed to resume hif: %d\n", ret); +		ret = 1; +		goto exit;  	}  	ret = ath10k_wmi_pdev_resume_target(ar);  	if (ret) { -		ath10k_warn("could not resume target (%d)\n", ret); -		return 1; +		ath10k_warn("failed to resume target: %d\n", ret); +		ret = 1; +		goto exit;  	} -	return 0; +	ret = 0; +exit: +	mutex_unlock(&ar->conf_mutex); +	return ret;  }  #endif @@ -2973,6 +3917,419 @@ exit:  	return ret;  } +/* Helper table for legacy fixed_rate/bitrate_mask */ +static const u8 cck_ofdm_rate[] = { +	/* CCK */ +	3, /* 1Mbps */ +	2, /* 2Mbps */ +	1, /* 5.5Mbps */ +	0, /* 11Mbps */ +	/* OFDM */ +	3, /* 6Mbps */ +	7, /* 9Mbps */ +	2, /* 12Mbps */ +	6, /* 18Mbps */ +	1, /* 24Mbps */ +	5, /* 36Mbps */ +	0, /* 48Mbps */ +	4, /* 54Mbps */ +}; + +/* Check if only one bit set */ +static int ath10k_check_single_mask(u32 mask) +{ +	int bit; + +	bit = ffs(mask); +	if (!bit) +		return 0; + +	mask &= ~BIT(bit - 1); +	if (mask) +		return 2; + +	return 1; +} + +static bool +ath10k_default_bitrate_mask(struct ath10k *ar, +			    enum ieee80211_band band, +			    const struct cfg80211_bitrate_mask *mask) +{ +	u32 legacy = 0x00ff; +	u8 ht = 0xff, i; +	u16 vht = 0x3ff; + +	switch (band) { +	case IEEE80211_BAND_2GHZ: +		legacy = 0x00fff; +		vht = 0; +		break; +	case IEEE80211_BAND_5GHZ: +		break; +	default: +		return false; +	} + +	if (mask->control[band].legacy != legacy) +		return false; + +	for (i = 0; i < ar->num_rf_chains; i++) +		if (mask->control[band].ht_mcs[i] != ht) +			return false; + +	for (i = 0; i < ar->num_rf_chains; i++) +		if (mask->control[band].vht_mcs[i] != vht) +			return false; + +	return true; +} + +static bool +ath10k_bitrate_mask_nss(const struct cfg80211_bitrate_mask *mask, +			enum ieee80211_band band, +			u8 *fixed_nss) +{ +	int ht_nss = 0, vht_nss = 0, i; + +	/* check legacy */ +	if (ath10k_check_single_mask(mask->control[band].legacy)) +		return false; + +	/* check HT */ +	for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) { +		if (mask->control[band].ht_mcs[i] == 0xff) +			continue; +		else if (mask->control[band].ht_mcs[i] == 0x00) +			break; +		else +			return false; +	} + +	ht_nss = i; + +	/* check VHT */ +	for (i = 0; i < NL80211_VHT_NSS_MAX; i++) { +		if (mask->control[band].vht_mcs[i] == 0x03ff) +			continue; +		else if (mask->control[band].vht_mcs[i] == 0x0000) +			break; +		else +			return false; +	} + +	vht_nss = i; + +	if (ht_nss > 0 && vht_nss > 0) +		return false; + +	if (ht_nss) +		*fixed_nss = ht_nss; +	else if (vht_nss) +		*fixed_nss = vht_nss; +	else +		return false; + +	return true; +} + +static bool +ath10k_bitrate_mask_correct(const struct cfg80211_bitrate_mask *mask, +			    enum ieee80211_band band, +			    enum wmi_rate_preamble *preamble) +{ +	int legacy = 0, ht = 0, vht = 0, i; + +	*preamble = WMI_RATE_PREAMBLE_OFDM; + +	/* check legacy */ +	legacy = ath10k_check_single_mask(mask->control[band].legacy); +	if (legacy > 1) +		return false; + +	/* check HT */ +	for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) +		ht += ath10k_check_single_mask(mask->control[band].ht_mcs[i]); +	if (ht > 1) +		return false; + +	/* check VHT */ +	for (i = 0; i < NL80211_VHT_NSS_MAX; i++) +		vht += ath10k_check_single_mask(mask->control[band].vht_mcs[i]); +	if (vht > 1) +		return false; + +	/* Currently we support only one fixed_rate */ +	if ((legacy + ht + vht) != 1) +		return false; + +	if (ht) +		*preamble = WMI_RATE_PREAMBLE_HT; +	else if (vht) +		*preamble = WMI_RATE_PREAMBLE_VHT; + +	return true; +} + +static bool +ath10k_bitrate_mask_rate(const struct cfg80211_bitrate_mask *mask, +			 enum ieee80211_band band, +			 u8 *fixed_rate, +			 u8 *fixed_nss) +{ +	u8 rate = 0, pream = 0, nss = 0, i; +	enum wmi_rate_preamble preamble; + +	/* Check if single rate correct */ +	if (!ath10k_bitrate_mask_correct(mask, band, &preamble)) +		return false; + +	pream = preamble; + +	switch (preamble) { +	case WMI_RATE_PREAMBLE_CCK: +	case WMI_RATE_PREAMBLE_OFDM: +		i = ffs(mask->control[band].legacy) - 1; + +		if (band == IEEE80211_BAND_2GHZ && i < 4) +			pream = WMI_RATE_PREAMBLE_CCK; + +		if (band == IEEE80211_BAND_5GHZ) +			i += 4; + +		if (i >= ARRAY_SIZE(cck_ofdm_rate)) +			return false; + +		rate = cck_ofdm_rate[i]; +		break; +	case WMI_RATE_PREAMBLE_HT: +		for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) +			if (mask->control[band].ht_mcs[i]) +				break; + +		if (i == IEEE80211_HT_MCS_MASK_LEN) +			return false; + +		rate = ffs(mask->control[band].ht_mcs[i]) - 1; +		nss = i; +		break; +	case WMI_RATE_PREAMBLE_VHT: +		for (i = 0; i < NL80211_VHT_NSS_MAX; i++) +			if (mask->control[band].vht_mcs[i]) +				break; + +		if (i == NL80211_VHT_NSS_MAX) +			return false; + +		rate = ffs(mask->control[band].vht_mcs[i]) - 1; +		nss = i; +		break; +	} + +	*fixed_nss = nss + 1; +	nss <<= 4; +	pream <<= 6; + +	ath10k_dbg(ATH10K_DBG_MAC, "mac fixed rate pream 0x%02x nss 0x%02x rate 0x%02x\n", +		   pream, nss, rate); + +	*fixed_rate = pream | nss | rate; + +	return true; +} + +static bool ath10k_get_fixed_rate_nss(const struct cfg80211_bitrate_mask *mask, +				      enum ieee80211_band band, +				      u8 *fixed_rate, +				      u8 *fixed_nss) +{ +	/* First check full NSS mask, if we can simply limit NSS */ +	if (ath10k_bitrate_mask_nss(mask, band, fixed_nss)) +		return true; + +	/* Next Check single rate is set */ +	return ath10k_bitrate_mask_rate(mask, band, fixed_rate, fixed_nss); +} + +static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif, +				       u8 fixed_rate, +				       u8 fixed_nss, +				       u8 force_sgi) +{ +	struct ath10k *ar = arvif->ar; +	u32 vdev_param; +	int ret = 0; + +	mutex_lock(&ar->conf_mutex); + +	if (arvif->fixed_rate == fixed_rate && +	    arvif->fixed_nss == fixed_nss && +	    arvif->force_sgi == force_sgi) +		goto exit; + +	if (fixed_rate == WMI_FIXED_RATE_NONE) +		ath10k_dbg(ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n"); + +	if (force_sgi) +		ath10k_dbg(ATH10K_DBG_MAC, "mac force sgi\n"); + +	vdev_param = ar->wmi.vdev_param->fixed_rate; +	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, +					vdev_param, fixed_rate); +	if (ret) { +		ath10k_warn("failed to set fixed rate param 0x%02x: %d\n", +			    fixed_rate, ret); +		ret = -EINVAL; +		goto exit; +	} + +	arvif->fixed_rate = fixed_rate; + +	vdev_param = ar->wmi.vdev_param->nss; +	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, +					vdev_param, fixed_nss); + +	if (ret) { +		ath10k_warn("failed to set fixed nss param %d: %d\n", +			    fixed_nss, ret); +		ret = -EINVAL; +		goto exit; +	} + +	arvif->fixed_nss = fixed_nss; + +	vdev_param = ar->wmi.vdev_param->sgi; +	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, +					force_sgi); + +	if (ret) { +		ath10k_warn("failed to set sgi param %d: %d\n", +			    force_sgi, ret); +		ret = -EINVAL; +		goto exit; +	} + +	arvif->force_sgi = force_sgi; + +exit: +	mutex_unlock(&ar->conf_mutex); +	return ret; +} + +static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw, +				   struct ieee80211_vif *vif, +				   const struct cfg80211_bitrate_mask *mask) +{ +	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); +	struct ath10k *ar = arvif->ar; +	enum ieee80211_band band = ar->hw->conf.chandef.chan->band; +	u8 fixed_rate = WMI_FIXED_RATE_NONE; +	u8 fixed_nss = ar->num_rf_chains; +	u8 force_sgi; + +	force_sgi = mask->control[band].gi; +	if (force_sgi == NL80211_TXRATE_FORCE_LGI) +		return -EINVAL; + +	if (!ath10k_default_bitrate_mask(ar, band, mask)) { +		if (!ath10k_get_fixed_rate_nss(mask, band, +					       &fixed_rate, +					       &fixed_nss)) +			return -EINVAL; +	} + +	if (fixed_rate == WMI_FIXED_RATE_NONE && force_sgi) { +		ath10k_warn("failed to force SGI usage for default rate settings\n"); +		return -EINVAL; +	} + +	return ath10k_set_fixed_rate_param(arvif, fixed_rate, +					   fixed_nss, force_sgi); +} + +static void ath10k_sta_rc_update(struct ieee80211_hw *hw, +				 struct ieee80211_vif *vif, +				 struct ieee80211_sta *sta, +				 u32 changed) +{ +	struct ath10k *ar = hw->priv; +	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; +	u32 bw, smps; + +	spin_lock_bh(&ar->data_lock); + +	ath10k_dbg(ATH10K_DBG_MAC, +		   "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n", +		   sta->addr, changed, sta->bandwidth, sta->rx_nss, +		   sta->smps_mode); + +	if (changed & IEEE80211_RC_BW_CHANGED) { +		bw = WMI_PEER_CHWIDTH_20MHZ; + +		switch (sta->bandwidth) { +		case IEEE80211_STA_RX_BW_20: +			bw = WMI_PEER_CHWIDTH_20MHZ; +			break; +		case IEEE80211_STA_RX_BW_40: +			bw = WMI_PEER_CHWIDTH_40MHZ; +			break; +		case IEEE80211_STA_RX_BW_80: +			bw = WMI_PEER_CHWIDTH_80MHZ; +			break; +		case IEEE80211_STA_RX_BW_160: +			ath10k_warn("Invalid bandwith %d in rc update for %pM\n", +				    sta->bandwidth, sta->addr); +			bw = WMI_PEER_CHWIDTH_20MHZ; +			break; +		} + +		arsta->bw = bw; +	} + +	if (changed & IEEE80211_RC_NSS_CHANGED) +		arsta->nss = sta->rx_nss; + +	if (changed & IEEE80211_RC_SMPS_CHANGED) { +		smps = WMI_PEER_SMPS_PS_NONE; + +		switch (sta->smps_mode) { +		case IEEE80211_SMPS_AUTOMATIC: +		case IEEE80211_SMPS_OFF: +			smps = WMI_PEER_SMPS_PS_NONE; +			break; +		case IEEE80211_SMPS_STATIC: +			smps = WMI_PEER_SMPS_STATIC; +			break; +		case IEEE80211_SMPS_DYNAMIC: +			smps = WMI_PEER_SMPS_DYNAMIC; +			break; +		case IEEE80211_SMPS_NUM_MODES: +			ath10k_warn("Invalid smps %d in sta rc update for %pM\n", +				    sta->smps_mode, sta->addr); +			smps = WMI_PEER_SMPS_PS_NONE; +			break; +		} + +		arsta->smps = smps; +	} + +	arsta->changed |= changed; + +	spin_unlock_bh(&ar->data_lock); + +	ieee80211_queue_work(hw, &arsta->update_wk); +} + +static u64 ath10k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ +	/* +	 * FIXME: Return 0 for time being. Need to figure out whether FW +	 * has the API to fetch 64-bit local TSF +	 */ + +	return 0; +} +  static const struct ieee80211_ops ath10k_ops = {  	.tx				= ath10k_tx,  	.start				= ath10k_start, @@ -2993,8 +4350,13 @@ static const struct ieee80211_ops ath10k_ops = {  	.set_frag_threshold		= ath10k_set_frag_threshold,  	.flush				= ath10k_flush,  	.tx_last_beacon			= ath10k_tx_last_beacon, +	.set_antenna			= ath10k_set_antenna, +	.get_antenna			= ath10k_get_antenna,  	.restart_complete		= ath10k_restart_complete,  	.get_survey			= ath10k_get_survey, +	.set_bitrate_mask		= ath10k_set_bitrate_mask, +	.sta_rc_update			= ath10k_sta_rc_update, +	.get_tsf			= ath10k_get_tsf,  #ifdef CONFIG_PM  	.suspend			= ath10k_suspend,  	.resume				= ath10k_resume, @@ -3127,12 +4489,37 @@ static const struct ieee80211_iface_limit ath10k_if_limits[] = {  	},  }; -static const struct ieee80211_iface_combination ath10k_if_comb = { -	.limits = ath10k_if_limits, -	.n_limits = ARRAY_SIZE(ath10k_if_limits), -	.max_interfaces = 8, -	.num_different_channels = 1, -	.beacon_int_infra_match = true, +static const struct ieee80211_iface_limit ath10k_10x_if_limits[] = { +	{ +	.max	= 8, +	.types	= BIT(NL80211_IFTYPE_AP) +	}, +}; + +static const struct ieee80211_iface_combination ath10k_if_comb[] = { +	{ +		.limits = ath10k_if_limits, +		.n_limits = ARRAY_SIZE(ath10k_if_limits), +		.max_interfaces = 8, +		.num_different_channels = 1, +		.beacon_int_infra_match = true, +	}, +}; + +static const struct ieee80211_iface_combination ath10k_10x_if_comb[] = { +	{ +		.limits = ath10k_10x_if_limits, +		.n_limits = ARRAY_SIZE(ath10k_10x_if_limits), +		.max_interfaces = 8, +		.num_different_channels = 1, +		.beacon_int_infra_match = true, +#ifdef CONFIG_ATH10K_DFS_CERTIFIED +		.radar_detect_widths =	BIT(NL80211_CHAN_WIDTH_20_NOHT) | +					BIT(NL80211_CHAN_WIDTH_20) | +					BIT(NL80211_CHAN_WIDTH_40) | +					BIT(NL80211_CHAN_WIDTH_80), +#endif +	},  };  static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar) @@ -3246,7 +4633,7 @@ struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id)  						   ath10k_get_arvif_iter,  						   &arvif_iter);  	if (!arvif_iter.arvif) { -		ath10k_warn("No VIF found for VDEV: %d\n", vdev_id); +		ath10k_warn("No VIF found for vdev %d\n", vdev_id);  		return NULL;  	} @@ -3311,9 +4698,24 @@ int ath10k_mac_register(struct ath10k *ar)  	ar->hw->wiphy->interface_modes =  		BIT(NL80211_IFTYPE_STATION) |  		BIT(NL80211_IFTYPE_ADHOC) | -		BIT(NL80211_IFTYPE_AP) | -		BIT(NL80211_IFTYPE_P2P_CLIENT) | -		BIT(NL80211_IFTYPE_P2P_GO); +		BIT(NL80211_IFTYPE_AP); + +	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { +		/* TODO:  Have to deal with 2x2 chips if/when the come out. */ +		ar->supp_tx_chainmask = TARGET_10X_TX_CHAIN_MASK; +		ar->supp_rx_chainmask = TARGET_10X_RX_CHAIN_MASK; +	} else { +		ar->supp_tx_chainmask = TARGET_TX_CHAIN_MASK; +		ar->supp_rx_chainmask = TARGET_RX_CHAIN_MASK; +	} + +	ar->hw->wiphy->available_antennas_rx = ar->supp_rx_chainmask; +	ar->hw->wiphy->available_antennas_tx = ar->supp_tx_chainmask; + +	if (!test_bit(ATH10K_FW_FEATURE_NO_P2P, ar->fw_features)) +		ar->hw->wiphy->interface_modes |= +			BIT(NL80211_IFTYPE_P2P_CLIENT) | +			BIT(NL80211_IFTYPE_P2P_GO);  	ar->hw->flags = IEEE80211_HW_SIGNAL_DBM |  			IEEE80211_HW_SUPPORTS_PS | @@ -3323,8 +4725,12 @@ int ath10k_mac_register(struct ath10k *ar)  			IEEE80211_HW_REPORTS_TX_ACK_STATUS |  			IEEE80211_HW_HAS_RATE_CONTROL |  			IEEE80211_HW_SUPPORTS_STATIC_SMPS | -			IEEE80211_HW_WANT_MONITOR_VIF | -			IEEE80211_HW_AP_LINK_PS; +			IEEE80211_HW_AP_LINK_PS | +			IEEE80211_HW_SPECTRUM_MGMT; + +	/* MSDU can have HTT TX fragment pushed in front. The additional 4 +	 * bytes is used for padding/alignment if necessary. */ +	ar->hw->extra_tx_headroom += sizeof(struct htt_data_tx_desc_frag)*2 + 4;  	if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS)  		ar->hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS; @@ -3338,11 +4744,12 @@ int ath10k_mac_register(struct ath10k *ar)  	ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN;  	ar->hw->vif_data_size = sizeof(struct ath10k_vif); +	ar->hw->sta_data_size = sizeof(struct ath10k_sta); -	ar->hw->channel_change_time = 5000;  	ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL;  	ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; +	ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;  	ar->hw->wiphy->max_remain_on_channel_duration = 5000;  	ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; @@ -3352,21 +4759,38 @@ int ath10k_mac_register(struct ath10k *ar)  	 */  	ar->hw->queues = 4; -	ar->hw->wiphy->iface_combinations = &ath10k_if_comb; -	ar->hw->wiphy->n_iface_combinations = 1; +	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { +		ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb; +		ar->hw->wiphy->n_iface_combinations = +			ARRAY_SIZE(ath10k_10x_if_comb); +	} else { +		ar->hw->wiphy->iface_combinations = ath10k_if_comb; +		ar->hw->wiphy->n_iface_combinations = +			ARRAY_SIZE(ath10k_if_comb); +	}  	ar->hw->netdev_features = NETIF_F_HW_CSUM; +	if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) { +		/* Init ath dfs pattern detector */ +		ar->ath_common.debug_mask = ATH_DBG_DFS; +		ar->dfs_detector = dfs_pattern_detector_init(&ar->ath_common, +							     NL80211_DFS_UNSET); + +		if (!ar->dfs_detector) +			ath10k_warn("failed to initialise DFS pattern detector\n"); +	} +  	ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy,  			    ath10k_reg_notifier);  	if (ret) { -		ath10k_err("Regulatory initialization failed\n"); +		ath10k_err("failed to initialise regulatory: %i\n", ret);  		goto err_free;  	}  	ret = ieee80211_register_hw(ar->hw);  	if (ret) { -		ath10k_err("ieee80211 registration failed: %d\n", ret); +		ath10k_err("failed to register ieee80211: %d\n", ret);  		goto err_free;  	} @@ -3392,6 +4816,9 @@ void ath10k_mac_unregister(struct ath10k *ar)  {  	ieee80211_unregister_hw(ar->hw); +	if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) +		ar->dfs_detector->exit(ar->dfs_detector); +  	kfree(ar->mac.sbands[IEEE80211_BAND_2GHZ].channels);  	kfree(ar->mac.sbands[IEEE80211_BAND_5GHZ].channels); diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h index 6fce9bfb19a..ba1021997b8 100644 --- a/drivers/net/wireless/ath/ath10k/mac.h +++ b/drivers/net/wireless/ath/ath10k/mac.h @@ -34,6 +34,8 @@ 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); +void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar); +void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work);  void ath10k_halt(struct ath10k *ar);  static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index e2f9ef50b1b..d0004d59c97 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -19,6 +19,7 @@  #include <linux/module.h>  #include <linux/interrupt.h>  #include <linux/spinlock.h> +#include <linux/bitops.h>  #include "core.h"  #include "debug.h" @@ -32,15 +33,37 @@  #include "ce.h"  #include "pci.h" -static unsigned int ath10k_target_ps; -module_param(ath10k_target_ps, uint, 0644); -MODULE_PARM_DESC(ath10k_target_ps, "Enable ath10k Target (SoC) PS option"); +enum ath10k_pci_irq_mode { +	ATH10K_PCI_IRQ_AUTO = 0, +	ATH10K_PCI_IRQ_LEGACY = 1, +	ATH10K_PCI_IRQ_MSI = 2, +}; + +enum ath10k_pci_reset_mode { +	ATH10K_PCI_RESET_AUTO = 0, +	ATH10K_PCI_RESET_WARM_ONLY = 1, +}; + +static unsigned int ath10k_pci_target_ps; +static unsigned int ath10k_pci_irq_mode = ATH10K_PCI_IRQ_AUTO; +static unsigned int ath10k_pci_reset_mode = ATH10K_PCI_RESET_AUTO; + +module_param_named(target_ps, ath10k_pci_target_ps, uint, 0644); +MODULE_PARM_DESC(target_ps, "Enable ath10k Target (SoC) PS option"); + +module_param_named(irq_mode, ath10k_pci_irq_mode, uint, 0644); +MODULE_PARM_DESC(irq_mode, "0: auto, 1: legacy, 2: msi (default: 0)"); + +module_param_named(reset_mode, ath10k_pci_reset_mode, uint, 0644); +MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)"); + +/* how long wait to wait for target to initialise, in ms */ +#define ATH10K_PCI_TARGET_WAIT 3000 +#define ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS 3 -#define QCA988X_1_0_DEVICE_ID	(0xabcd)  #define QCA988X_2_0_DEVICE_ID	(0x003c)  static DEFINE_PCI_DEVICE_TABLE(ath10k_pci_id_table) = { -	{ PCI_VDEVICE(ATHEROS, QCA988X_1_0_DEVICE_ID) }, /* PCI-E QCA988X V1 */  	{ PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */  	{0}  }; @@ -48,58 +71,245 @@ static DEFINE_PCI_DEVICE_TABLE(ath10k_pci_id_table) = {  static int ath10k_pci_diag_read_access(struct ath10k *ar, u32 address,  				       u32 *data); -static void ath10k_pci_process_ce(struct ath10k *ar);  static int ath10k_pci_post_rx(struct ath10k *ar); -static int ath10k_pci_post_rx_pipe(struct hif_ce_pipe_info *pipe_info, +static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,  					     int num); -static void ath10k_pci_rx_pipe_cleanup(struct hif_ce_pipe_info *pipe_info); -static void ath10k_pci_stop_ce(struct ath10k *ar); -static void ath10k_pci_device_reset(struct ath10k *ar); -static int ath10k_pci_reset_target(struct ath10k *ar); -static int ath10k_pci_start_intr(struct ath10k *ar); -static void ath10k_pci_stop_intr(struct ath10k *ar); +static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info); +static int ath10k_pci_cold_reset(struct ath10k *ar); +static int ath10k_pci_warm_reset(struct ath10k *ar); +static int ath10k_pci_wait_for_target_init(struct ath10k *ar); +static int ath10k_pci_init_irq(struct ath10k *ar); +static int ath10k_pci_deinit_irq(struct ath10k *ar); +static int ath10k_pci_request_irq(struct ath10k *ar); +static void ath10k_pci_free_irq(struct ath10k *ar); +static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe, +			       struct ath10k_ce_pipe *rx_pipe, +			       struct bmi_xfer *xfer);  static const struct ce_attr host_ce_config_wlan[] = { -	/* host->target HTC control and raw streams */ -	{ /* CE0 */ CE_ATTR_FLAGS, 0, 16, 256, 0, NULL,}, -	/* could be moved to share CE3 */ -	/* target->host HTT + HTC control */ -	{ /* CE1 */ CE_ATTR_FLAGS, 0, 0, 512, 512, NULL,}, -	/* target->host WMI */ -	{ /* CE2 */ CE_ATTR_FLAGS, 0, 0, 2048, 32, NULL,}, -	/* host->target WMI */ -	{ /* CE3 */ CE_ATTR_FLAGS, 0, 32, 2048, 0, NULL,}, -	/* host->target HTT */ -	{ /* CE4 */ CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, 0, -		    CE_HTT_H2T_MSG_SRC_NENTRIES, 256, 0, NULL,}, -	/* unused */ -	{ /* CE5 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,}, -	/* Target autonomous hif_memcpy */ -	{ /* CE6 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,}, -	/* ce_diag, the Diagnostic Window */ -	{ /* CE7 */ CE_ATTR_FLAGS, 0, 2, DIAG_TRANSFER_LIMIT, 2, NULL,}, +	/* CE0: host->target HTC control and raw streams */ +	{ +		.flags = CE_ATTR_FLAGS, +		.src_nentries = 16, +		.src_sz_max = 256, +		.dest_nentries = 0, +	}, + +	/* CE1: target->host HTT + HTC control */ +	{ +		.flags = CE_ATTR_FLAGS, +		.src_nentries = 0, +		.src_sz_max = 512, +		.dest_nentries = 512, +	}, + +	/* CE2: target->host WMI */ +	{ +		.flags = CE_ATTR_FLAGS, +		.src_nentries = 0, +		.src_sz_max = 2048, +		.dest_nentries = 32, +	}, + +	/* CE3: host->target WMI */ +	{ +		.flags = CE_ATTR_FLAGS, +		.src_nentries = 32, +		.src_sz_max = 2048, +		.dest_nentries = 0, +	}, + +	/* CE4: host->target HTT */ +	{ +		.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, +		.src_nentries = CE_HTT_H2T_MSG_SRC_NENTRIES, +		.src_sz_max = 256, +		.dest_nentries = 0, +	}, + +	/* CE5: unused */ +	{ +		.flags = CE_ATTR_FLAGS, +		.src_nentries = 0, +		.src_sz_max = 0, +		.dest_nentries = 0, +	}, + +	/* CE6: target autonomous hif_memcpy */ +	{ +		.flags = CE_ATTR_FLAGS, +		.src_nentries = 0, +		.src_sz_max = 0, +		.dest_nentries = 0, +	}, + +	/* CE7: ce_diag, the Diagnostic Window */ +	{ +		.flags = CE_ATTR_FLAGS, +		.src_nentries = 2, +		.src_sz_max = DIAG_TRANSFER_LIMIT, +		.dest_nentries = 2, +	},  };  /* Target firmware's Copy Engine configuration. */  static const struct ce_pipe_config target_ce_config_wlan[] = { -	/* host->target HTC control and raw streams */ -	{ /* CE0 */ 0, PIPEDIR_OUT, 32, 256, CE_ATTR_FLAGS, 0,}, -	/* target->host HTT + HTC control */ -	{ /* CE1 */ 1, PIPEDIR_IN, 32, 512, CE_ATTR_FLAGS, 0,}, -	/* target->host WMI */ -	{ /* CE2 */ 2, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,}, -	/* host->target WMI */ -	{ /* CE3 */ 3, PIPEDIR_OUT, 32, 2048, CE_ATTR_FLAGS, 0,}, -	/* host->target HTT */ -	{ /* CE4 */ 4, PIPEDIR_OUT, 256, 256, CE_ATTR_FLAGS, 0,}, +	/* CE0: host->target HTC control and raw streams */ +	{ +		.pipenum = 0, +		.pipedir = PIPEDIR_OUT, +		.nentries = 32, +		.nbytes_max = 256, +		.flags = CE_ATTR_FLAGS, +		.reserved = 0, +	}, + +	/* CE1: target->host HTT + HTC control */ +	{ +		.pipenum = 1, +		.pipedir = PIPEDIR_IN, +		.nentries = 32, +		.nbytes_max = 512, +		.flags = CE_ATTR_FLAGS, +		.reserved = 0, +	}, + +	/* CE2: target->host WMI */ +	{ +		.pipenum = 2, +		.pipedir = PIPEDIR_IN, +		.nentries = 32, +		.nbytes_max = 2048, +		.flags = CE_ATTR_FLAGS, +		.reserved = 0, +	}, + +	/* CE3: host->target WMI */ +	{ +		.pipenum = 3, +		.pipedir = PIPEDIR_OUT, +		.nentries = 32, +		.nbytes_max = 2048, +		.flags = CE_ATTR_FLAGS, +		.reserved = 0, +	}, + +	/* CE4: host->target HTT */ +	{ +		.pipenum = 4, +		.pipedir = PIPEDIR_OUT, +		.nentries = 256, +		.nbytes_max = 256, +		.flags = CE_ATTR_FLAGS, +		.reserved = 0, +	}, +  	/* NB: 50% of src nentries, since tx has 2 frags */ -	/* unused */ -	{ /* CE5 */ 5, PIPEDIR_OUT, 32, 2048, CE_ATTR_FLAGS, 0,}, -	/* Reserved for target autonomous hif_memcpy */ -	{ /* CE6 */ 6, PIPEDIR_INOUT, 32, 4096, CE_ATTR_FLAGS, 0,}, + +	/* CE5: unused */ +	{ +		.pipenum = 5, +		.pipedir = PIPEDIR_OUT, +		.nentries = 32, +		.nbytes_max = 2048, +		.flags = CE_ATTR_FLAGS, +		.reserved = 0, +	}, + +	/* CE6: Reserved for target autonomous hif_memcpy */ +	{ +		.pipenum = 6, +		.pipedir = PIPEDIR_INOUT, +		.nentries = 32, +		.nbytes_max = 4096, +		.flags = CE_ATTR_FLAGS, +		.reserved = 0, +	}, +  	/* CE7 used only by Host */  }; +static bool ath10k_pci_irq_pending(struct ath10k *ar) +{ +	u32 cause; + +	/* Check if the shared legacy irq is for us */ +	cause = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + +				  PCIE_INTR_CAUSE_ADDRESS); +	if (cause & (PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL)) +		return true; + +	return false; +} + +static void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar) +{ +	/* IMPORTANT: INTR_CLR register has to be set after +	 * INTR_ENABLE is set to 0, otherwise interrupt can not be +	 * really cleared. */ +	ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS, +			   0); +	ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_CLR_ADDRESS, +			   PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL); + +	/* IMPORTANT: this extra read transaction is required to +	 * flush the posted write buffer. */ +	(void) ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + +				 PCIE_INTR_ENABLE_ADDRESS); +} + +static void ath10k_pci_enable_legacy_irq(struct ath10k *ar) +{ +	ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + +			   PCIE_INTR_ENABLE_ADDRESS, +			   PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL); + +	/* IMPORTANT: this extra read transaction is required to +	 * flush the posted write buffer. */ +	(void) ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + +				 PCIE_INTR_ENABLE_ADDRESS); +} + +static irqreturn_t ath10k_pci_early_irq_handler(int irq, void *arg) +{ +	struct ath10k *ar = arg; +	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + +	if (ar_pci->num_msi_intrs == 0) { +		if (!ath10k_pci_irq_pending(ar)) +			return IRQ_NONE; + +		ath10k_pci_disable_and_clear_legacy_irq(ar); +	} + +	tasklet_schedule(&ar_pci->early_irq_tasklet); + +	return IRQ_HANDLED; +} + +static int ath10k_pci_request_early_irq(struct ath10k *ar) +{ +	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); +	int ret; + +	/* Regardless whether MSI-X/MSI/legacy irqs have been set up the first +	 * interrupt from irq vector is triggered in all cases for FW +	 * indication/errors */ +	ret = request_irq(ar_pci->pdev->irq, ath10k_pci_early_irq_handler, +			  IRQF_SHARED, "ath10k_pci (early)", ar); +	if (ret) { +		ath10k_warn("failed to request early irq: %d\n", ret); +		return ret; +	} + +	return 0; +} + +static void ath10k_pci_free_early_irq(struct ath10k *ar) +{ +	free_irq(ath10k_pci_priv(ar)->pdev->irq, ar); +} +  /*   * Diagnostic read/write access is provided for startup/config/debug usage.   * Caller must guarantee proper alignment, when applicable, and single user @@ -114,7 +324,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,  	unsigned int completed_nbytes, orig_nbytes, remaining_bytes;  	unsigned int id;  	unsigned int flags; -	struct ce_state *ce_diag; +	struct ath10k_ce_pipe *ce_diag;  	/* Host buffer address in CE space */  	u32 ce_data;  	dma_addr_t ce_data_base = 0; @@ -149,9 +359,10 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,  	 *   2) Buffer in DMA-able space  	 */  	orig_nbytes = nbytes; -	data_buf = (unsigned char *)pci_alloc_consistent(ar_pci->pdev, -							 orig_nbytes, -							 &ce_data_base); +	data_buf = (unsigned char *)dma_alloc_coherent(ar->dev, +						       orig_nbytes, +						       &ce_data_base, +						       GFP_ATOMIC);  	if (!data_buf) {  		ret = -ENOMEM; @@ -245,12 +456,12 @@ done:  				__le32_to_cpu(((__le32 *)data_buf)[i]);  		}  	} else -		ath10k_dbg(ATH10K_DBG_PCI, "%s failure (0x%x)\n", -			   __func__, address); +		ath10k_warn("failed to read diag value at 0x%x: %d\n", +			    address, ret);  	if (data_buf) -		pci_free_consistent(ar_pci->pdev, orig_nbytes, -				    data_buf, ce_data_base); +		dma_free_coherent(ar->dev, orig_nbytes, data_buf, +				  ce_data_base);  	return ret;  } @@ -278,7 +489,7 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,  	unsigned int completed_nbytes, orig_nbytes, remaining_bytes;  	unsigned int id;  	unsigned int flags; -	struct ce_state *ce_diag; +	struct ath10k_ce_pipe *ce_diag;  	void *data_buf = NULL;  	u32 ce_data;	/* Host buffer address in CE space */  	dma_addr_t ce_data_base = 0; @@ -293,9 +504,10 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,  	 *   2) Buffer in DMA-able space  	 */  	orig_nbytes = nbytes; -	data_buf = (unsigned char *)pci_alloc_consistent(ar_pci->pdev, -							 orig_nbytes, -							 &ce_data_base); +	data_buf = (unsigned char *)dma_alloc_coherent(ar->dev, +						       orig_nbytes, +						       &ce_data_base, +						       GFP_ATOMIC);  	if (!data_buf) {  		ret = -ENOMEM;  		goto done; @@ -391,13 +603,13 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,  done:  	if (data_buf) { -		pci_free_consistent(ar_pci->pdev, orig_nbytes, data_buf, -				    ce_data_base); +		dma_free_coherent(ar->dev, orig_nbytes, data_buf, +				  ce_data_base);  	}  	if (ret != 0) -		ath10k_dbg(ATH10K_DBG_PCI, "%s failure (0x%x)\n", __func__, -			   address); +		ath10k_warn("failed to write diag value at 0x%x: %d\n", +			    address, ret);  	return ret;  } @@ -426,18 +638,7 @@ static bool ath10k_pci_target_is_awake(struct ath10k *ar)  	return (RTC_STATE_V_GET(val) == RTC_STATE_V_ON);  } -static void ath10k_pci_wait(struct ath10k *ar) -{ -	int n = 100; - -	while (n-- && !ath10k_pci_target_is_awake(ar)) -		msleep(10); - -	if (n < 0) -		ath10k_warn("Unable to wakeup target\n"); -} - -void ath10k_do_pci_wake(struct ath10k *ar) +int ath10k_do_pci_wake(struct ath10k *ar)  {  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);  	void __iomem *pci_addr = ar_pci->mem; @@ -453,18 +654,19 @@ void ath10k_do_pci_wake(struct ath10k *ar)  	atomic_inc(&ar_pci->keep_awake_count);  	if (ar_pci->verified_awake) -		return; +		return 0;  	for (;;) {  		if (ath10k_pci_target_is_awake(ar)) {  			ar_pci->verified_awake = true; -			break; +			return 0;  		}  		if (tot_delay > PCIE_WAKE_TIMEOUT) { -			ath10k_warn("target takes too long to wake up (awake count %d)\n", +			ath10k_warn("target took longer %d us to wake up (awake count %d)\n", +				    PCIE_WAKE_TIMEOUT,  				    atomic_read(&ar_pci->keep_awake_count)); -			break; +			return -ETIMEDOUT;  		}  		udelay(curr_delay); @@ -489,195 +691,146 @@ void ath10k_do_pci_sleep(struct ath10k *ar)  	}  } -/* - * FIXME: Handle OOM properly. - */ -static inline -struct ath10k_pci_compl *get_free_compl(struct hif_ce_pipe_info *pipe_info) -{ -	struct ath10k_pci_compl *compl = NULL; - -	spin_lock_bh(&pipe_info->pipe_lock); -	if (list_empty(&pipe_info->compl_free)) { -		ath10k_warn("Completion buffers are full\n"); -		goto exit; -	} -	compl = list_first_entry(&pipe_info->compl_free, -				 struct ath10k_pci_compl, list); -	list_del(&compl->list); -exit: -	spin_unlock_bh(&pipe_info->pipe_lock); -	return compl; -} -  /* Called by lower (CE) layer when a send to Target completes. */ -static void ath10k_pci_ce_send_done(struct ce_state *ce_state, -				    void *transfer_context, -				    u32 ce_data, -				    unsigned int nbytes, -				    unsigned int transfer_id) +static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state)  {  	struct ath10k *ar = ce_state->ar;  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	struct hif_ce_pipe_info *pipe_info =  &ar_pci->pipe_info[ce_state->id]; -	struct ath10k_pci_compl *compl; -	bool process = false; +	struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current; +	void *transfer_context; +	u32 ce_data; +	unsigned int nbytes; +	unsigned int transfer_id; -	do { -		/* -		 * For the send completion of an item in sendlist, just -		 * increment num_sends_allowed. The upper layer callback will -		 * be triggered when last fragment is done with send. -		 */ -		if (transfer_context == CE_SENDLIST_ITEM_CTXT) { -			spin_lock_bh(&pipe_info->pipe_lock); -			pipe_info->num_sends_allowed++; -			spin_unlock_bh(&pipe_info->pipe_lock); +	while (ath10k_ce_completed_send_next(ce_state, &transfer_context, +					     &ce_data, &nbytes, +					     &transfer_id) == 0) { +		/* no need to call tx completion for NULL pointers */ +		if (transfer_context == NULL)  			continue; -		} - -		compl = get_free_compl(pipe_info); -		if (!compl) -			break; - -		compl->send_or_recv = HIF_CE_COMPLETE_SEND; -		compl->ce_state = ce_state; -		compl->pipe_info = pipe_info; -		compl->transfer_context = transfer_context; -		compl->nbytes = nbytes; -		compl->transfer_id = transfer_id; -		compl->flags = 0; - -		/* -		 * Add the completion to the processing queue. -		 */ -		spin_lock_bh(&ar_pci->compl_lock); -		list_add_tail(&compl->list, &ar_pci->compl_process); -		spin_unlock_bh(&ar_pci->compl_lock); - -		process = true; -	} while (ath10k_ce_completed_send_next(ce_state, -							   &transfer_context, -							   &ce_data, &nbytes, -							   &transfer_id) == 0); -	/* -	 * If only some of the items within a sendlist have completed, -	 * don't invoke completion processing until the entire sendlist -	 * has been sent. -	 */ -	if (!process) -		return; - -	ath10k_pci_process_ce(ar); +		cb->tx_completion(ar, transfer_context, transfer_id); +	}  }  /* Called by lower (CE) layer when data is received from the Target. */ -static void ath10k_pci_ce_recv_data(struct ce_state *ce_state, -				    void *transfer_context, u32 ce_data, -				    unsigned int nbytes, -				    unsigned int transfer_id, -				    unsigned int flags) +static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)  {  	struct ath10k *ar = ce_state->ar;  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	struct hif_ce_pipe_info *pipe_info =  &ar_pci->pipe_info[ce_state->id]; -	struct ath10k_pci_compl *compl; +	struct ath10k_pci_pipe *pipe_info =  &ar_pci->pipe_info[ce_state->id]; +	struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current;  	struct sk_buff *skb; - -	do { -		compl = get_free_compl(pipe_info); -		if (!compl) -			break; - -		compl->send_or_recv = HIF_CE_COMPLETE_RECV; -		compl->ce_state = ce_state; -		compl->pipe_info = pipe_info; -		compl->transfer_context = transfer_context; -		compl->nbytes = nbytes; -		compl->transfer_id = transfer_id; -		compl->flags = flags; +	void *transfer_context; +	u32 ce_data; +	unsigned int nbytes, max_nbytes; +	unsigned int transfer_id; +	unsigned int flags; +	int err; + +	while (ath10k_ce_completed_recv_next(ce_state, &transfer_context, +					     &ce_data, &nbytes, &transfer_id, +					     &flags) == 0) { +		err = ath10k_pci_post_rx_pipe(pipe_info, 1); +		if (unlikely(err)) { +			/* FIXME: retry */ +			ath10k_warn("failed to replenish CE rx ring %d: %d\n", +				    pipe_info->pipe_num, err); +		}  		skb = transfer_context; +		max_nbytes = skb->len + skb_tailroom(skb);  		dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr, -				 skb->len + skb_tailroom(skb), -				 DMA_FROM_DEVICE); -		/* -		 * Add the completion to the processing queue. -		 */ -		spin_lock_bh(&ar_pci->compl_lock); -		list_add_tail(&compl->list, &ar_pci->compl_process); -		spin_unlock_bh(&ar_pci->compl_lock); +				 max_nbytes, DMA_FROM_DEVICE); -	} while (ath10k_ce_completed_recv_next(ce_state, -							   &transfer_context, -							   &ce_data, &nbytes, -							   &transfer_id, -							   &flags) == 0); +		if (unlikely(max_nbytes < nbytes)) { +			ath10k_warn("rxed more than expected (nbytes %d, max %d)", +				    nbytes, max_nbytes); +			dev_kfree_skb_any(skb); +			continue; +		} -	ath10k_pci_process_ce(ar); +		skb_put(skb, nbytes); +		cb->rx_completion(ar, skb, pipe_info->pipe_num); +	}  } -/* Send the first nbytes bytes of the buffer */ -static int ath10k_pci_hif_send_head(struct ath10k *ar, u8 pipe_id, -				    unsigned int transfer_id, -				    unsigned int bytes, struct sk_buff *nbuf) +static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, +				struct ath10k_hif_sg_item *items, int n_items)  { -	struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(nbuf);  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	struct hif_ce_pipe_info *pipe_info = &(ar_pci->pipe_info[pipe_id]); -	struct ce_state *ce_hdl = pipe_info->ce_hdl; -	struct ce_sendlist sendlist; -	unsigned int len; -	u32 flags = 0; -	int ret; - -	memset(&sendlist, 0, sizeof(struct ce_sendlist)); +	struct ath10k_pci_pipe *pci_pipe = &ar_pci->pipe_info[pipe_id]; +	struct ath10k_ce_pipe *ce_pipe = pci_pipe->ce_hdl; +	struct ath10k_ce_ring *src_ring = ce_pipe->src_ring; +	unsigned int nentries_mask; +	unsigned int sw_index; +	unsigned int write_index; +	int err, i = 0; + +	spin_lock_bh(&ar_pci->ce_lock); + +	nentries_mask = src_ring->nentries_mask; +	sw_index = src_ring->sw_index; +	write_index = src_ring->write_index; + +	if (unlikely(CE_RING_DELTA(nentries_mask, +				   write_index, sw_index - 1) < n_items)) { +		err = -ENOBUFS; +		goto err; +	} -	len = min(bytes, nbuf->len); -	bytes -= len; +	for (i = 0; i < n_items - 1; i++) { +		ath10k_dbg(ATH10K_DBG_PCI, +			   "pci tx item %d paddr 0x%08x len %d n_items %d\n", +			   i, items[i].paddr, items[i].len, n_items); +		ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, "item data: ", +				items[i].vaddr, items[i].len); + +		err = ath10k_ce_send_nolock(ce_pipe, +					    items[i].transfer_context, +					    items[i].paddr, +					    items[i].len, +					    items[i].transfer_id, +					    CE_SEND_FLAG_GATHER); +		if (err) +			goto err; +	} -	if (len & 3) -		ath10k_warn("skb not aligned to 4-byte boundary (%d)\n", len); +	/* `i` is equal to `n_items -1` after for() */  	ath10k_dbg(ATH10K_DBG_PCI, -		   "pci send data vaddr %p paddr 0x%llx len %d as %d bytes\n", -		   nbuf->data, (unsigned long long) skb_cb->paddr, -		   nbuf->len, len); -	ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, -			"ath10k tx: data: ", -			nbuf->data, nbuf->len); - -	ath10k_ce_sendlist_buf_add(&sendlist, skb_cb->paddr, len, flags); - -	/* Make sure we have resources to handle this request */ -	spin_lock_bh(&pipe_info->pipe_lock); -	if (!pipe_info->num_sends_allowed) { -		ath10k_warn("Pipe: %d is full\n", pipe_id); -		spin_unlock_bh(&pipe_info->pipe_lock); -		return -ENOSR; -	} -	pipe_info->num_sends_allowed--; -	spin_unlock_bh(&pipe_info->pipe_lock); - -	ret = ath10k_ce_sendlist_send(ce_hdl, nbuf, &sendlist, transfer_id); -	if (ret) -		ath10k_warn("CE send failed: %p\n", nbuf); +		   "pci tx item %d paddr 0x%08x len %d n_items %d\n", +		   i, items[i].paddr, items[i].len, n_items); +	ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, "item data: ", +			items[i].vaddr, items[i].len); + +	err = ath10k_ce_send_nolock(ce_pipe, +				    items[i].transfer_context, +				    items[i].paddr, +				    items[i].len, +				    items[i].transfer_id, +				    0); +	if (err) +		goto err; -	return ret; +	spin_unlock_bh(&ar_pci->ce_lock); +	return 0; + +err: +	for (; i > 0; i--) +		__ath10k_ce_send_revert(ce_pipe); + +	spin_unlock_bh(&ar_pci->ce_lock); +	return err;  }  static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)  {  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	struct hif_ce_pipe_info *pipe_info = &(ar_pci->pipe_info[pipe]); -	int ret; -	spin_lock_bh(&pipe_info->pipe_lock); -	ret = pipe_info->num_sends_allowed; -	spin_unlock_bh(&pipe_info->pipe_lock); +	ath10k_dbg(ATH10K_DBG_PCI, "pci hif get free queue number\n"); -	return ret; +	return ath10k_ce_num_free_src_entries(ar_pci->pipe_info[pipe].ce_hdl);  }  static void ath10k_pci_hif_dump_area(struct ath10k *ar) @@ -691,14 +844,13 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar)  	ath10k_err("firmware crashed!\n");  	ath10k_err("hardware name %s version 0x%x\n",  		   ar->hw_params.name, ar->target_version); -	ath10k_err("firmware version: %u.%u.%u.%u\n", ar->fw_version_major, -		   ar->fw_version_minor, ar->fw_version_release, -		   ar->fw_version_build); +	ath10k_err("firmware version: %s\n", ar->hw->wiphy->fw_version);  	host_addr = host_interest_item_address(HI_ITEM(hi_failure_state)); -	if (ath10k_pci_diag_read_mem(ar, host_addr, -				     ®_dump_area, sizeof(u32)) != 0) { -		ath10k_warn("could not read hi_failure_state\n"); +	ret = ath10k_pci_diag_read_mem(ar, host_addr, +				       ®_dump_area, sizeof(u32)); +	if (ret) { +		ath10k_err("failed to read FW dump area address: %d\n", ret);  		return;  	} @@ -708,7 +860,7 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar)  				       ®_dump_values[0],  				       REG_DUMP_COUNT_QCA988X * sizeof(u32));  	if (ret != 0) { -		ath10k_err("could not dump FW Dump Area\n"); +		ath10k_err("failed to read FW dump area: %d\n", ret);  		return;  	} @@ -723,12 +875,14 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar)  			   reg_dump_values[i + 2],  			   reg_dump_values[i + 3]); -	ieee80211_queue_work(ar->hw, &ar->restart_work); +	queue_work(ar->workqueue, &ar->restart_work);  }  static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,  					       int force)  { +	ath10k_dbg(ATH10K_DBG_PCI, "pci hif send complete check\n"); +  	if (!force) {  		int resources;  		/* @@ -755,211 +909,54 @@ static void ath10k_pci_hif_set_callbacks(struct ath10k *ar,  {  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__); +	ath10k_dbg(ATH10K_DBG_PCI, "pci hif set callbacks\n");  	memcpy(&ar_pci->msg_callbacks_current, callbacks,  	       sizeof(ar_pci->msg_callbacks_current));  } -static int ath10k_pci_start_ce(struct ath10k *ar) +static int ath10k_pci_setup_ce_irq(struct ath10k *ar)  {  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	struct ce_state *ce_diag = ar_pci->ce_diag;  	const struct ce_attr *attr; -	struct hif_ce_pipe_info *pipe_info; -	struct ath10k_pci_compl *compl; -	int i, pipe_num, completions, disable_interrupts; +	struct ath10k_pci_pipe *pipe_info; +	int pipe_num, disable_interrupts; -	spin_lock_init(&ar_pci->compl_lock); -	INIT_LIST_HEAD(&ar_pci->compl_process); - -	for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) { +	for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {  		pipe_info = &ar_pci->pipe_info[pipe_num]; -		spin_lock_init(&pipe_info->pipe_lock); -		INIT_LIST_HEAD(&pipe_info->compl_free); -  		/* Handle Diagnostic CE specially */ -		if (pipe_info->ce_hdl == ce_diag) +		if (pipe_info->ce_hdl == ar_pci->ce_diag)  			continue;  		attr = &host_ce_config_wlan[pipe_num]; -		completions = 0;  		if (attr->src_nentries) {  			disable_interrupts = attr->flags & CE_ATTR_DIS_INTR;  			ath10k_ce_send_cb_register(pipe_info->ce_hdl,  						   ath10k_pci_ce_send_done,  						   disable_interrupts); -			completions += attr->src_nentries; -			pipe_info->num_sends_allowed = attr->src_nentries - 1;  		} -		if (attr->dest_nentries) { +		if (attr->dest_nentries)  			ath10k_ce_recv_cb_register(pipe_info->ce_hdl,  						   ath10k_pci_ce_recv_data); -			completions += attr->dest_nentries; -		} - -		if (completions == 0) -			continue; - -		for (i = 0; i < completions; i++) { -			compl = kmalloc(sizeof(struct ath10k_pci_compl), -					GFP_KERNEL); -			if (!compl) { -				ath10k_warn("No memory for completion state\n"); -				ath10k_pci_stop_ce(ar); -				return -ENOMEM; -			} - -			compl->send_or_recv = HIF_CE_COMPLETE_FREE; -			list_add_tail(&compl->list, &pipe_info->compl_free); -		}  	}  	return 0;  } -static void ath10k_pci_stop_ce(struct ath10k *ar) +static void ath10k_pci_kill_tasklet(struct ath10k *ar)  {  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	struct ath10k_pci_compl *compl; -	struct sk_buff *skb;  	int i; -	ath10k_ce_disable_interrupts(ar); - -	/* Cancel the pending tasklet */  	tasklet_kill(&ar_pci->intr_tq); +	tasklet_kill(&ar_pci->msi_fw_err); +	tasklet_kill(&ar_pci->early_irq_tasklet);  	for (i = 0; i < CE_COUNT; i++)  		tasklet_kill(&ar_pci->pipe_info[i].intr); - -	/* Mark pending completions as aborted, so that upper layers free up -	 * their associated resources */ -	spin_lock_bh(&ar_pci->compl_lock); -	list_for_each_entry(compl, &ar_pci->compl_process, list) { -		skb = (struct sk_buff *)compl->transfer_context; -		ATH10K_SKB_CB(skb)->is_aborted = true; -	} -	spin_unlock_bh(&ar_pci->compl_lock); -} - -static void ath10k_pci_cleanup_ce(struct ath10k *ar) -{ -	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	struct ath10k_pci_compl *compl, *tmp; -	struct hif_ce_pipe_info *pipe_info; -	struct sk_buff *netbuf; -	int pipe_num; - -	/* Free pending completions. */ -	spin_lock_bh(&ar_pci->compl_lock); -	if (!list_empty(&ar_pci->compl_process)) -		ath10k_warn("pending completions still present! possible memory leaks.\n"); - -	list_for_each_entry_safe(compl, tmp, &ar_pci->compl_process, list) { -		list_del(&compl->list); -		netbuf = (struct sk_buff *)compl->transfer_context; -		dev_kfree_skb_any(netbuf); -		kfree(compl); -	} -	spin_unlock_bh(&ar_pci->compl_lock); - -	/* Free unused completions for each pipe. */ -	for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) { -		pipe_info = &ar_pci->pipe_info[pipe_num]; - -		spin_lock_bh(&pipe_info->pipe_lock); -		list_for_each_entry_safe(compl, tmp, -					 &pipe_info->compl_free, list) { -			list_del(&compl->list); -			kfree(compl); -		} -		spin_unlock_bh(&pipe_info->pipe_lock); -	} -} - -static void ath10k_pci_process_ce(struct ath10k *ar) -{ -	struct ath10k_pci *ar_pci = ar->hif.priv; -	struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current; -	struct ath10k_pci_compl *compl; -	struct sk_buff *skb; -	unsigned int nbytes; -	int ret, send_done = 0; - -	/* Upper layers aren't ready to handle tx/rx completions in parallel so -	 * we must serialize all completion processing. */ - -	spin_lock_bh(&ar_pci->compl_lock); -	if (ar_pci->compl_processing) { -		spin_unlock_bh(&ar_pci->compl_lock); -		return; -	} -	ar_pci->compl_processing = true; -	spin_unlock_bh(&ar_pci->compl_lock); - -	for (;;) { -		spin_lock_bh(&ar_pci->compl_lock); -		if (list_empty(&ar_pci->compl_process)) { -			spin_unlock_bh(&ar_pci->compl_lock); -			break; -		} -		compl = list_first_entry(&ar_pci->compl_process, -					 struct ath10k_pci_compl, list); -		list_del(&compl->list); -		spin_unlock_bh(&ar_pci->compl_lock); - -		if (compl->send_or_recv == HIF_CE_COMPLETE_SEND) { -			cb->tx_completion(ar, -					  compl->transfer_context, -					  compl->transfer_id); -			send_done = 1; -		} else { -			ret = ath10k_pci_post_rx_pipe(compl->pipe_info, 1); -			if (ret) { -				ath10k_warn("Unable to post recv buffer for pipe: %d\n", -					    compl->pipe_info->pipe_num); -				break; -			} - -			skb = (struct sk_buff *)compl->transfer_context; -			nbytes = compl->nbytes; - -			ath10k_dbg(ATH10K_DBG_PCI, -				   "ath10k_pci_ce_recv_data netbuf=%p  nbytes=%d\n", -				   skb, nbytes); -			ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, -					"ath10k rx: ", skb->data, nbytes); - -			if (skb->len + skb_tailroom(skb) >= nbytes) { -				skb_trim(skb, 0); -				skb_put(skb, nbytes); -				cb->rx_completion(ar, skb, -						  compl->pipe_info->pipe_num); -			} else { -				ath10k_warn("rxed more than expected (nbytes %d, max %d)", -					    nbytes, -					    skb->len + skb_tailroom(skb)); -			} -		} - -		compl->send_or_recv = HIF_CE_COMPLETE_FREE; - -		/* -		 * Add completion back to the pipe's free list. -		 */ -		spin_lock_bh(&compl->pipe_info->pipe_lock); -		list_add_tail(&compl->list, &compl->pipe_info->compl_free); -		compl->pipe_info->num_sends_allowed += send_done; -		spin_unlock_bh(&compl->pipe_info->pipe_lock); -	} - -	spin_lock_bh(&ar_pci->compl_lock); -	ar_pci->compl_processing = false; -	spin_unlock_bh(&ar_pci->compl_lock);  }  /* TODO - temporary mapping while we have too few CE's */ @@ -970,6 +967,8 @@ static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar,  {  	int ret = 0; +	ath10k_dbg(ATH10K_DBG_PCI, "pci hif map service\n"); +  	/* polling for received messages not supported */  	*dl_is_polled = 0; @@ -1029,6 +1028,8 @@ static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,  {  	int ul_is_polled, dl_is_polled; +	ath10k_dbg(ATH10K_DBG_PCI, "pci hif get default pipe\n"); +  	(void)ath10k_pci_hif_map_service_to_pipe(ar,  						 ATH10K_HTC_SVC_ID_RSVD_CTRL,  						 ul_pipe, @@ -1037,12 +1038,12 @@ static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,  						 &dl_is_polled);  } -static int ath10k_pci_post_rx_pipe(struct hif_ce_pipe_info *pipe_info, +static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,  				   int num)  {  	struct ath10k *ar = pipe_info->hif_ce_state;  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	struct ce_state *ce_state = pipe_info->ce_hdl; +	struct ath10k_ce_pipe *ce_state = pipe_info->ce_hdl;  	struct sk_buff *skb;  	dma_addr_t ce_data;  	int i, ret = 0; @@ -1053,7 +1054,7 @@ static int ath10k_pci_post_rx_pipe(struct hif_ce_pipe_info *pipe_info,  	for (i = 0; i < num; i++) {  		skb = dev_alloc_skb(pipe_info->buf_sz);  		if (!skb) { -			ath10k_warn("could not allocate skbuff for pipe %d\n", +			ath10k_warn("failed to allocate skbuff for pipe %d\n",  				    num);  			ret = -ENOMEM;  			goto err; @@ -1066,7 +1067,7 @@ static int ath10k_pci_post_rx_pipe(struct hif_ce_pipe_info *pipe_info,  					 DMA_FROM_DEVICE);  		if (unlikely(dma_mapping_error(ar->dev, ce_data))) { -			ath10k_warn("could not dma map skbuff\n"); +			ath10k_warn("failed to DMA map sk_buff\n");  			dev_kfree_skb_any(skb);  			ret = -EIO;  			goto err; @@ -1081,7 +1082,7 @@ static int ath10k_pci_post_rx_pipe(struct hif_ce_pipe_info *pipe_info,  		ret = ath10k_ce_recv_buf_enqueue(ce_state, (void *)skb,  						 ce_data);  		if (ret) { -			ath10k_warn("could not enqueue to pipe %d (%d)\n", +			ath10k_warn("failed to enqueue to pipe %d: %d\n",  				    num, ret);  			goto err;  		} @@ -1097,11 +1098,11 @@ err:  static int ath10k_pci_post_rx(struct ath10k *ar)  {  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	struct hif_ce_pipe_info *pipe_info; +	struct ath10k_pci_pipe *pipe_info;  	const struct ce_attr *attr;  	int pipe_num, ret = 0; -	for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) { +	for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {  		pipe_info = &ar_pci->pipe_info[pipe_num];  		attr = &host_ce_config_wlan[pipe_num]; @@ -1111,8 +1112,8 @@ static int ath10k_pci_post_rx(struct ath10k *ar)  		ret = ath10k_pci_post_rx_pipe(pipe_info,  					      attr->dest_nentries - 1);  		if (ret) { -			ath10k_warn("Unable to replenish recv buffers for pipe: %d\n", -				    pipe_num); +			ath10k_warn("failed to post RX buffer for pipe %d: %d\n", +				    pipe_num, ret);  			for (; pipe_num >= 0; pipe_num--) {  				pipe_info = &ar_pci->pipe_info[pipe_num]; @@ -1128,30 +1129,57 @@ static int ath10k_pci_post_rx(struct ath10k *ar)  static int ath10k_pci_hif_start(struct ath10k *ar)  {  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	int ret; +	int ret, ret_early; -	ret = ath10k_pci_start_ce(ar); +	ath10k_dbg(ATH10K_DBG_BOOT, "boot hif start\n"); + +	ath10k_pci_free_early_irq(ar); +	ath10k_pci_kill_tasklet(ar); + +	ret = ath10k_pci_request_irq(ar);  	if (ret) { -		ath10k_warn("could not start CE (%d)\n", ret); -		return ret; +		ath10k_warn("failed to post RX buffers for all pipes: %d\n", +			    ret); +		goto err_early_irq; +	} + +	ret = ath10k_pci_setup_ce_irq(ar); +	if (ret) { +		ath10k_warn("failed to setup CE interrupts: %d\n", ret); +		goto err_stop;  	}  	/* Post buffers once to start things off. */  	ret = ath10k_pci_post_rx(ar);  	if (ret) { -		ath10k_warn("could not post rx pipes (%d)\n", ret); -		return ret; +		ath10k_warn("failed to post RX buffers for all pipes: %d\n", +			    ret); +		goto err_stop;  	}  	ar_pci->started = 1;  	return 0; + +err_stop: +	ath10k_ce_disable_interrupts(ar); +	ath10k_pci_free_irq(ar); +	ath10k_pci_kill_tasklet(ar); +err_early_irq: +	/* Though there should be no interrupts (device was reset) +	 * power_down() expects the early IRQ to be installed as per the +	 * driver lifecycle. */ +	ret_early = ath10k_pci_request_early_irq(ar); +	if (ret_early) +		ath10k_warn("failed to re-enable early irq: %d\n", ret_early); + +	return ret;  } -static void ath10k_pci_rx_pipe_cleanup(struct hif_ce_pipe_info *pipe_info) +static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info)  {  	struct ath10k *ar;  	struct ath10k_pci *ar_pci; -	struct ce_state *ce_hdl; +	struct ath10k_ce_pipe *ce_hdl;  	u32 buf_sz;  	struct sk_buff *netbuf;  	u32 ce_data; @@ -1179,11 +1207,11 @@ static void ath10k_pci_rx_pipe_cleanup(struct hif_ce_pipe_info *pipe_info)  	}  } -static void ath10k_pci_tx_pipe_cleanup(struct hif_ce_pipe_info *pipe_info) +static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info)  {  	struct ath10k *ar;  	struct ath10k_pci *ar_pci; -	struct ce_state *ce_hdl; +	struct ath10k_ce_pipe *ce_hdl;  	struct sk_buff *netbuf;  	u32 ce_data;  	unsigned int nbytes; @@ -1206,15 +1234,13 @@ static void ath10k_pci_tx_pipe_cleanup(struct hif_ce_pipe_info *pipe_info)  	while (ath10k_ce_cancel_send_next(ce_hdl, (void **)&netbuf,  					  &ce_data, &nbytes, &id) == 0) { -		if (netbuf != CE_SENDLIST_ITEM_CTXT) -			/* -			 * Indicate the completion to higer layer to free -			 * the buffer -			 */ -			ATH10K_SKB_CB(netbuf)->is_aborted = true; -			ar_pci->msg_callbacks_current.tx_completion(ar, -								    netbuf, -								    id); +		/* no need to call tx completion for NULL pointers */ +		if (!netbuf) +			continue; + +		ar_pci->msg_callbacks_current.tx_completion(ar, +							    netbuf, +							    id);  	}  } @@ -1231,8 +1257,8 @@ static void ath10k_pci_buffer_cleanup(struct ath10k *ar)  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);  	int pipe_num; -	for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) { -		struct hif_ce_pipe_info *pipe_info; +	for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { +		struct ath10k_pci_pipe *pipe_info;  		pipe_info = &ar_pci->pipe_info[pipe_num];  		ath10k_pci_rx_pipe_cleanup(pipe_info); @@ -1242,49 +1268,46 @@ static void ath10k_pci_buffer_cleanup(struct ath10k *ar)  static void ath10k_pci_ce_deinit(struct ath10k *ar)  { -	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	struct hif_ce_pipe_info *pipe_info; -	int pipe_num; - -	for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) { -		pipe_info = &ar_pci->pipe_info[pipe_num]; -		if (pipe_info->ce_hdl) { -			ath10k_ce_deinit(pipe_info->ce_hdl); -			pipe_info->ce_hdl = NULL; -			pipe_info->buf_sz = 0; -		} -	} -} - -static void ath10k_pci_disable_irqs(struct ath10k *ar) -{ -	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);  	int i; -	for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++) -		disable_irq(ar_pci->pdev->irq + i); +	for (i = 0; i < CE_COUNT; i++) +		ath10k_ce_deinit_pipe(ar, i);  }  static void ath10k_pci_hif_stop(struct ath10k *ar)  {  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); +	int ret; -	ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__); +	ath10k_dbg(ATH10K_DBG_BOOT, "boot hif stop\n"); -	/* Irqs are never explicitly re-enabled. They are implicitly re-enabled -	 * by ath10k_pci_start_intr(). */ -	ath10k_pci_disable_irqs(ar); +	if (WARN_ON(!ar_pci->started)) +		return; -	ath10k_pci_stop_ce(ar); +	ret = ath10k_ce_disable_interrupts(ar); +	if (ret) +		ath10k_warn("failed to disable CE interrupts: %d\n", ret); + +	ath10k_pci_free_irq(ar); +	ath10k_pci_kill_tasklet(ar); + +	ret = ath10k_pci_request_early_irq(ar); +	if (ret) +		ath10k_warn("failed to re-enable early irq: %d\n", ret);  	/* At this point, asynchronous threads are stopped, the target should  	 * not DMA nor interrupt. We process the leftovers and then free  	 * everything else up. */ -	ath10k_pci_process_ce(ar); -	ath10k_pci_cleanup_ce(ar);  	ath10k_pci_buffer_cleanup(ar); +	/* Make the sure the device won't access any structures on the host by +	 * resetting it. The device was fed with PCI CE ringbuffer +	 * configuration during init. If ringbuffers are freed and the device +	 * were to access them this could lead to memory corruption on the +	 * host. */ +	ath10k_pci_warm_reset(ar); +  	ar_pci->started = 0;  } @@ -1293,14 +1316,18 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,  					   void *resp, u32 *resp_len)  {  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	struct ce_state *ce_tx = ar_pci->pipe_info[BMI_CE_NUM_TO_TARG].ce_hdl; -	struct ce_state *ce_rx = ar_pci->pipe_info[BMI_CE_NUM_TO_HOST].ce_hdl; +	struct ath10k_pci_pipe *pci_tx = &ar_pci->pipe_info[BMI_CE_NUM_TO_TARG]; +	struct ath10k_pci_pipe *pci_rx = &ar_pci->pipe_info[BMI_CE_NUM_TO_HOST]; +	struct ath10k_ce_pipe *ce_tx = pci_tx->ce_hdl; +	struct ath10k_ce_pipe *ce_rx = pci_rx->ce_hdl;  	dma_addr_t req_paddr = 0;  	dma_addr_t resp_paddr = 0;  	struct bmi_xfer xfer = {};  	void *treq, *tresp = NULL;  	int ret = 0; +	might_sleep(); +  	if (resp && !resp_len)  		return -EINVAL; @@ -1341,14 +1368,12 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,  	if (ret)  		goto err_resp; -	ret = wait_for_completion_timeout(&xfer.done, -					  BMI_COMMUNICATION_TIMEOUT_HZ); -	if (ret <= 0) { +	ret = ath10k_pci_bmi_wait(ce_tx, ce_rx, &xfer); +	if (ret) {  		u32 unused_buffer;  		unsigned int unused_nbytes;  		unsigned int unused_id; -		ret = -ETIMEDOUT;  		ath10k_ce_cancel_send_next(ce_tx, NULL, &unused_buffer,  					   &unused_nbytes, &unused_id);  	} else { @@ -1378,13 +1403,16 @@ err_dma:  	return ret;  } -static void ath10k_pci_bmi_send_done(struct ce_state *ce_state, -				     void *transfer_context, -				     u32 data, -				     unsigned int nbytes, -				     unsigned int transfer_id) +static void ath10k_pci_bmi_send_done(struct ath10k_ce_pipe *ce_state)  { -	struct bmi_xfer *xfer = transfer_context; +	struct bmi_xfer *xfer; +	u32 ce_data; +	unsigned int nbytes; +	unsigned int transfer_id; + +	if (ath10k_ce_completed_send_next(ce_state, (void **)&xfer, &ce_data, +					  &nbytes, &transfer_id)) +		return;  	if (xfer->wait_for_resp)  		return; @@ -1392,14 +1420,17 @@ static void ath10k_pci_bmi_send_done(struct ce_state *ce_state,  	complete(&xfer->done);  } -static void ath10k_pci_bmi_recv_data(struct ce_state *ce_state, -				     void *transfer_context, -				     u32 data, -				     unsigned int nbytes, -				     unsigned int transfer_id, -				     unsigned int flags) +static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state)  { -	struct bmi_xfer *xfer = transfer_context; +	struct bmi_xfer *xfer; +	u32 ce_data; +	unsigned int nbytes; +	unsigned int transfer_id; +	unsigned int flags; + +	if (ath10k_ce_completed_recv_next(ce_state, (void **)&xfer, &ce_data, +					  &nbytes, &transfer_id, &flags)) +		return;  	if (!xfer->wait_for_resp) {  		ath10k_warn("unexpected: BMI data received; ignoring\n"); @@ -1410,6 +1441,25 @@ static void ath10k_pci_bmi_recv_data(struct ce_state *ce_state,  	complete(&xfer->done);  } +static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe, +			       struct ath10k_ce_pipe *rx_pipe, +			       struct bmi_xfer *xfer) +{ +	unsigned long timeout = jiffies + BMI_COMMUNICATION_TIMEOUT_HZ; + +	while (time_before_eq(jiffies, timeout)) { +		ath10k_pci_bmi_send_done(tx_pipe); +		ath10k_pci_bmi_recv_data(rx_pipe); + +		if (completion_done(&xfer->done)) +			return 0; + +		schedule(); +	} + +	return -ETIMEDOUT; +} +  /*   * Map from service/endpoint to Copy Engine.   * This table is derived from the CE_PCI TABLE, above. @@ -1519,7 +1569,7 @@ static int ath10k_pci_wake_target_cpu(struct ath10k *ar)  					      CORE_CTRL_ADDRESS,  					  &core_ctrl);  	if (ret) { -		ath10k_warn("Unable to read core ctrl\n"); +		ath10k_warn("failed to read core_ctrl: %d\n", ret);  		return ret;  	} @@ -1529,10 +1579,13 @@ static int ath10k_pci_wake_target_cpu(struct ath10k *ar)  	ret = ath10k_pci_diag_write_access(ar, SOC_CORE_BASE_ADDRESS |  					       CORE_CTRL_ADDRESS,  					   core_ctrl); -	if (ret) -		ath10k_warn("Unable to set interrupt mask\n"); +	if (ret) { +		ath10k_warn("failed to set target CPU interrupt mask: %d\n", +			    ret); +		return ret; +	} -	return ret; +	return 0;  }  static int ath10k_pci_init_config(struct ath10k *ar) @@ -1674,73 +1727,78 @@ static int ath10k_pci_init_config(struct ath10k *ar)  	return 0;  } +static int ath10k_pci_alloc_ce(struct ath10k *ar) +{ +	int i, ret; +	for (i = 0; i < CE_COUNT; i++) { +		ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]); +		if (ret) { +			ath10k_err("failed to allocate copy engine pipe %d: %d\n", +				   i, ret); +			return ret; +		} +	} + +	return 0; +} + +static void ath10k_pci_free_ce(struct ath10k *ar) +{ +	int i; + +	for (i = 0; i < CE_COUNT; i++) +		ath10k_ce_free_pipe(ar, i); +}  static int ath10k_pci_ce_init(struct ath10k *ar)  {  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	struct hif_ce_pipe_info *pipe_info; +	struct ath10k_pci_pipe *pipe_info;  	const struct ce_attr *attr; -	int pipe_num; +	int pipe_num, ret; -	for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) { +	for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {  		pipe_info = &ar_pci->pipe_info[pipe_num]; +		pipe_info->ce_hdl = &ar_pci->ce_states[pipe_num];  		pipe_info->pipe_num = pipe_num;  		pipe_info->hif_ce_state = ar;  		attr = &host_ce_config_wlan[pipe_num]; -		pipe_info->ce_hdl = ath10k_ce_init(ar, pipe_num, attr); -		if (pipe_info->ce_hdl == NULL) { -			ath10k_err("Unable to initialize CE for pipe: %d\n", -				   pipe_num); - -			/* It is safe to call it here. It checks if ce_hdl is -			 * valid for each pipe */ -			ath10k_pci_ce_deinit(ar); -			return -1; +		ret = ath10k_ce_init_pipe(ar, pipe_num, attr); +		if (ret) { +			ath10k_err("failed to initialize copy engine pipe %d: %d\n", +				   pipe_num, ret); +			return ret;  		} -		if (pipe_num == ar_pci->ce_count - 1) { +		if (pipe_num == CE_COUNT - 1) {  			/*  			 * Reserve the ultimate CE for  			 * diagnostic Window support  			 */ -			ar_pci->ce_diag = -			ar_pci->pipe_info[ar_pci->ce_count - 1].ce_hdl; +			ar_pci->ce_diag = pipe_info->ce_hdl;  			continue;  		}  		pipe_info->buf_sz = (size_t) (attr->src_sz_max);  	} -	/* -	 * Initially, establish CE completion handlers for use with BMI. -	 * These are overwritten with generic handlers after we exit BMI phase. -	 */ -	pipe_info = &ar_pci->pipe_info[BMI_CE_NUM_TO_TARG]; -	ath10k_ce_send_cb_register(pipe_info->ce_hdl, -				   ath10k_pci_bmi_send_done, 0); - -	pipe_info = &ar_pci->pipe_info[BMI_CE_NUM_TO_HOST]; -	ath10k_ce_recv_cb_register(pipe_info->ce_hdl, -				   ath10k_pci_bmi_recv_data); -  	return 0;  }  static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar)  {  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	u32 fw_indicator_address, fw_indicator; +	u32 fw_indicator;  	ath10k_pci_wake(ar); -	fw_indicator_address = ar_pci->fw_indicator_address; -	fw_indicator = ath10k_pci_read32(ar, fw_indicator_address); +	fw_indicator = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);  	if (fw_indicator & FW_IND_EVENT_PENDING) {  		/* ACK: clear Target-side pending event */ -		ath10k_pci_write32(ar, fw_indicator_address, +		ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS,  				   fw_indicator & ~FW_IND_EVENT_PENDING);  		if (ar_pci->started) { @@ -1757,17 +1815,120 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar)  	ath10k_pci_sleep(ar);  } -static int ath10k_pci_hif_power_up(struct ath10k *ar) +/* this function effectively clears target memory controller assert line */ +static void ath10k_pci_warm_reset_si0(struct ath10k *ar)  { -	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	int ret; +	u32 val; + +	val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS); +	ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS, +			       val | SOC_RESET_CONTROL_SI0_RST_MASK); +	val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS); + +	msleep(10); + +	val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS); +	ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS, +			       val & ~SOC_RESET_CONTROL_SI0_RST_MASK); +	val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS); + +	msleep(10); +} + +static int ath10k_pci_warm_reset(struct ath10k *ar) +{ +	int ret = 0; +	u32 val; + +	ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset\n"); -	ret = ath10k_pci_start_intr(ar); +	ret = ath10k_do_pci_wake(ar);  	if (ret) { -		ath10k_err("could not start interrupt handling (%d)\n", ret); -		goto err; +		ath10k_err("failed to wake up target: %d\n", ret); +		return ret;  	} +	/* debug */ +	val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + +				PCIE_INTR_CAUSE_ADDRESS); +	ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val); + +	val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + +				CPU_INTR_ADDRESS); +	ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n", +		   val); + +	/* disable pending irqs */ +	ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + +			   PCIE_INTR_ENABLE_ADDRESS, 0); + +	ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + +			   PCIE_INTR_CLR_ADDRESS, ~0); + +	msleep(100); + +	/* clear fw indicator */ +	ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, 0); + +	/* clear target LF timer interrupts */ +	val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + +				SOC_LF_TIMER_CONTROL0_ADDRESS); +	ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + +			   SOC_LF_TIMER_CONTROL0_ADDRESS, +			   val & ~SOC_LF_TIMER_CONTROL0_ENABLE_MASK); + +	/* reset CE */ +	val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + +				SOC_RESET_CONTROL_ADDRESS); +	ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, +			   val | SOC_RESET_CONTROL_CE_RST_MASK); +	val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + +				SOC_RESET_CONTROL_ADDRESS); +	msleep(10); + +	/* unreset CE */ +	ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, +			   val & ~SOC_RESET_CONTROL_CE_RST_MASK); +	val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + +				SOC_RESET_CONTROL_ADDRESS); +	msleep(10); + +	ath10k_pci_warm_reset_si0(ar); + +	/* debug */ +	val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + +				PCIE_INTR_CAUSE_ADDRESS); +	ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val); + +	val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + +				CPU_INTR_ADDRESS); +	ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n", +		   val); + +	/* CPU warm reset */ +	val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + +				SOC_RESET_CONTROL_ADDRESS); +	ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, +			   val | SOC_RESET_CONTROL_CPU_WARM_RST_MASK); + +	val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + +				SOC_RESET_CONTROL_ADDRESS); +	ath10k_dbg(ATH10K_DBG_BOOT, "boot target reset state: 0x%08x\n", val); + +	msleep(100); + +	ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset complete\n"); + +	ath10k_do_pci_sleep(ar); +	return ret; +} + +static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset) +{ +	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); +	const char *irq_mode; +	int ret; +  	/*  	 * Bring the target up cleanly.  	 * @@ -1778,50 +1939,159 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)  	 * is in an unexpected state. We try to catch that here in order to  	 * reset the Target and retry the probe.  	 */ -	ath10k_pci_device_reset(ar); +	if (cold_reset) +		ret = ath10k_pci_cold_reset(ar); +	else +		ret = ath10k_pci_warm_reset(ar); -	ret = ath10k_pci_reset_target(ar); -	if (ret) -		goto err_irq; +	if (ret) { +		ath10k_err("failed to reset target: %d\n", ret); +		goto err; +	}  	if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))  		/* Force AWAKE forever */  		ath10k_do_pci_wake(ar);  	ret = ath10k_pci_ce_init(ar); -	if (ret) +	if (ret) { +		ath10k_err("failed to initialize CE: %d\n", ret);  		goto err_ps; +	} -	ret = ath10k_pci_init_config(ar); -	if (ret) +	ret = ath10k_ce_disable_interrupts(ar); +	if (ret) { +		ath10k_err("failed to disable CE interrupts: %d\n", ret);  		goto err_ce; +	} -	ret = ath10k_pci_wake_target_cpu(ar); +	ret = ath10k_pci_init_irq(ar);  	if (ret) { -		ath10k_err("could not wake up target CPU (%d)\n", ret); +		ath10k_err("failed to init irqs: %d\n", ret);  		goto err_ce;  	} +	ret = ath10k_pci_request_early_irq(ar); +	if (ret) { +		ath10k_err("failed to request early irq: %d\n", ret); +		goto err_deinit_irq; +	} + +	ret = ath10k_pci_wait_for_target_init(ar); +	if (ret) { +		ath10k_err("failed to wait for target to init: %d\n", ret); +		goto err_free_early_irq; +	} + +	ret = ath10k_pci_init_config(ar); +	if (ret) { +		ath10k_err("failed to setup init config: %d\n", ret); +		goto err_free_early_irq; +	} + +	ret = ath10k_pci_wake_target_cpu(ar); +	if (ret) { +		ath10k_err("could not wake up target CPU: %d\n", ret); +		goto err_free_early_irq; +	} + +	if (ar_pci->num_msi_intrs > 1) +		irq_mode = "MSI-X"; +	else if (ar_pci->num_msi_intrs == 1) +		irq_mode = "MSI"; +	else +		irq_mode = "legacy"; + +	if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) +		ath10k_info("pci irq %s irq_mode %d reset_mode %d\n", +			    irq_mode, ath10k_pci_irq_mode, +			    ath10k_pci_reset_mode); +  	return 0; +err_free_early_irq: +	ath10k_pci_free_early_irq(ar); +err_deinit_irq: +	ath10k_pci_deinit_irq(ar);  err_ce:  	ath10k_pci_ce_deinit(ar); +	ath10k_pci_warm_reset(ar);  err_ps:  	if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))  		ath10k_do_pci_sleep(ar); -err_irq: -	ath10k_pci_stop_intr(ar);  err:  	return ret;  } +static int ath10k_pci_hif_power_up_warm(struct ath10k *ar) +{ +	int i, ret; + +	/* +	 * Sometime warm reset succeeds after retries. +	 * +	 * FIXME: It might be possible to tune ath10k_pci_warm_reset() to work +	 * at first try. +	 */ +	for (i = 0; i < ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS; i++) { +		ret = __ath10k_pci_hif_power_up(ar, false); +		if (ret == 0) +			break; + +		ath10k_warn("failed to warm reset (attempt %d out of %d): %d\n", +			    i + 1, ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS, ret); +	} + +	return ret; +} + +static int ath10k_pci_hif_power_up(struct ath10k *ar) +{ +	int ret; + +	ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power up\n"); + +	/* +	 * Hardware CUS232 version 2 has some issues with cold reset and the +	 * preferred (and safer) way to perform a device reset is through a +	 * warm reset. +	 * +	 * Warm reset doesn't always work though so fall back to cold reset may +	 * be necessary. +	 */ +	ret = ath10k_pci_hif_power_up_warm(ar); +	if (ret) { +		ath10k_warn("failed to power up target using warm reset: %d\n", +			    ret); + +		if (ath10k_pci_reset_mode == ATH10K_PCI_RESET_WARM_ONLY) +			return ret; + +		ath10k_warn("trying cold reset\n"); + +		ret = __ath10k_pci_hif_power_up(ar, true); +		if (ret) { +			ath10k_err("failed to power up target using cold reset too (%d)\n", +				   ret); +			return ret; +		} +	} + +	return 0; +} +  static void ath10k_pci_hif_power_down(struct ath10k *ar)  {  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	ath10k_pci_stop_intr(ar); +	ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power down\n"); +	ath10k_pci_free_early_irq(ar); +	ath10k_pci_kill_tasklet(ar); +	ath10k_pci_deinit_irq(ar);  	ath10k_pci_ce_deinit(ar); +	ath10k_pci_warm_reset(ar); +  	if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))  		ath10k_do_pci_sleep(ar);  } @@ -1876,7 +2146,7 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)  #endif  static const struct ath10k_hif_ops ath10k_pci_hif_ops = { -	.send_head		= ath10k_pci_hif_send_head, +	.tx_sg			= ath10k_pci_hif_tx_sg,  	.exchange_bmi_msg	= ath10k_pci_hif_exchange_bmi_msg,  	.start			= ath10k_pci_hif_start,  	.stop			= ath10k_pci_hif_stop, @@ -1895,7 +2165,7 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = {  static void ath10k_pci_ce_tasklet(unsigned long ptr)  { -	struct hif_ce_pipe_info *pipe = (struct hif_ce_pipe_info *)ptr; +	struct ath10k_pci_pipe *pipe = (struct ath10k_pci_pipe *)ptr;  	struct ath10k_pci *ar_pci = pipe->ar_pci;  	ath10k_ce_per_engine_service(ar_pci->ar, pipe->pipe_num); @@ -1955,25 +2225,10 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);  	if (ar_pci->num_msi_intrs == 0) { -		/* -		 * IMPORTANT: INTR_CLR regiser has to be set after -		 * INTR_ENABLE is set to 0, otherwise interrupt can not be -		 * really cleared. -		 */ -		iowrite32(0, ar_pci->mem + -			  (SOC_CORE_BASE_ADDRESS | -			   PCIE_INTR_ENABLE_ADDRESS)); -		iowrite32(PCIE_INTR_FIRMWARE_MASK | -			  PCIE_INTR_CE_MASK_ALL, -			  ar_pci->mem + (SOC_CORE_BASE_ADDRESS | -					 PCIE_INTR_CLR_ADDRESS)); -		/* -		 * IMPORTANT: this extra read transaction is required to -		 * flush the posted write buffer. -		 */ -		(void) ioread32(ar_pci->mem + -				(SOC_CORE_BASE_ADDRESS | -				 PCIE_INTR_ENABLE_ADDRESS)); +		if (!ath10k_pci_irq_pending(ar)) +			return IRQ_NONE; + +		ath10k_pci_disable_and_clear_legacy_irq(ar);  	}  	tasklet_schedule(&ar_pci->intr_tq); @@ -1981,6 +2236,30 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)  	return IRQ_HANDLED;  } +static void ath10k_pci_early_irq_tasklet(unsigned long data) +{ +	struct ath10k *ar = (struct ath10k *)data; +	u32 fw_ind; +	int ret; + +	ret = ath10k_pci_wake(ar); +	if (ret) { +		ath10k_warn("failed to wake target in early irq tasklet: %d\n", +			    ret); +		return; +	} + +	fw_ind = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); +	if (fw_ind & FW_IND_EVENT_PENDING) { +		ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, +				   fw_ind & ~FW_IND_EVENT_PENDING); +		ath10k_pci_hif_dump_area(ar); +	} + +	ath10k_pci_sleep(ar); +	ath10k_pci_enable_legacy_irq(ar); +} +  static void ath10k_pci_tasklet(unsigned long data)  {  	struct ath10k *ar = (struct ath10k *)data; @@ -1989,40 +2268,22 @@ static void ath10k_pci_tasklet(unsigned long data)  	ath10k_pci_fw_interrupt_handler(ar); /* FIXME: Handle FW error */  	ath10k_ce_per_engine_service_any(ar); -	if (ar_pci->num_msi_intrs == 0) { -		/* Enable Legacy PCI line interrupts */ -		iowrite32(PCIE_INTR_FIRMWARE_MASK | -			  PCIE_INTR_CE_MASK_ALL, -			  ar_pci->mem + (SOC_CORE_BASE_ADDRESS | -					 PCIE_INTR_ENABLE_ADDRESS)); -		/* -		 * IMPORTANT: this extra read transaction is required to -		 * flush the posted write buffer -		 */ -		(void) ioread32(ar_pci->mem + -				(SOC_CORE_BASE_ADDRESS | -				 PCIE_INTR_ENABLE_ADDRESS)); -	} +	/* Re-enable legacy irq that was disabled in the irq handler */ +	if (ar_pci->num_msi_intrs == 0) +		ath10k_pci_enable_legacy_irq(ar);  } -static int ath10k_pci_start_intr_msix(struct ath10k *ar, int num) +static int ath10k_pci_request_irq_msix(struct ath10k *ar)  {  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	int ret; -	int i; - -	ret = pci_enable_msi_block(ar_pci->pdev, num); -	if (ret) -		return ret; +	int ret, i;  	ret = request_irq(ar_pci->pdev->irq + MSI_ASSIGN_FW,  			  ath10k_pci_msi_fw_handler,  			  IRQF_SHARED, "ath10k_pci", ar);  	if (ret) { -		ath10k_warn("request_irq(%d) failed %d\n", +		ath10k_warn("failed to request MSI-X fw irq %d: %d\n",  			    ar_pci->pdev->irq + MSI_ASSIGN_FW, ret); - -		pci_disable_msi(ar_pci->pdev);  		return ret;  	} @@ -2031,44 +2292,38 @@ static int ath10k_pci_start_intr_msix(struct ath10k *ar, int num)  				  ath10k_pci_per_engine_handler,  				  IRQF_SHARED, "ath10k_pci", ar);  		if (ret) { -			ath10k_warn("request_irq(%d) failed %d\n", +			ath10k_warn("failed to request MSI-X ce irq %d: %d\n",  				    ar_pci->pdev->irq + i, ret);  			for (i--; i >= MSI_ASSIGN_CE_INITIAL; i--)  				free_irq(ar_pci->pdev->irq + i, ar);  			free_irq(ar_pci->pdev->irq + MSI_ASSIGN_FW, ar); -			pci_disable_msi(ar_pci->pdev);  			return ret;  		}  	} -	ath10k_info("MSI-X interrupt handling (%d intrs)\n", num);  	return 0;  } -static int ath10k_pci_start_intr_msi(struct ath10k *ar) +static int ath10k_pci_request_irq_msi(struct ath10k *ar)  {  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);  	int ret; -	ret = pci_enable_msi(ar_pci->pdev); -	if (ret < 0) -		return ret; -  	ret = request_irq(ar_pci->pdev->irq,  			  ath10k_pci_interrupt_handler,  			  IRQF_SHARED, "ath10k_pci", ar); -	if (ret < 0) { -		pci_disable_msi(ar_pci->pdev); +	if (ret) { +		ath10k_warn("failed to request MSI irq %d: %d\n", +			    ar_pci->pdev->irq, ret);  		return ret;  	} -	ath10k_info("MSI interrupt handling\n");  	return 0;  } -static int ath10k_pci_start_intr_legacy(struct ath10k *ar) +static int ath10k_pci_request_irq_legacy(struct ath10k *ar)  {  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);  	int ret; @@ -2076,168 +2331,247 @@ static int ath10k_pci_start_intr_legacy(struct ath10k *ar)  	ret = request_irq(ar_pci->pdev->irq,  			  ath10k_pci_interrupt_handler,  			  IRQF_SHARED, "ath10k_pci", ar); -	if (ret < 0) +	if (ret) { +		ath10k_warn("failed to request legacy irq %d: %d\n", +			    ar_pci->pdev->irq, ret);  		return ret; +	} -	/* -	 * Make sure to wake the Target before enabling Legacy -	 * Interrupt. -	 */ -	iowrite32(PCIE_SOC_WAKE_V_MASK, -		  ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + -		  PCIE_SOC_WAKE_ADDRESS); +	return 0; +} -	ath10k_pci_wait(ar); +static int ath10k_pci_request_irq(struct ath10k *ar) +{ +	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	/* -	 * A potential race occurs here: The CORE_BASE write -	 * depends on target correctly decoding AXI address but -	 * host won't know when target writes BAR to CORE_CTRL. -	 * This write might get lost if target has NOT written BAR. -	 * For now, fix the race by repeating the write in below -	 * synchronization checking. -	 */ -	iowrite32(PCIE_INTR_FIRMWARE_MASK | -		  PCIE_INTR_CE_MASK_ALL, -		  ar_pci->mem + (SOC_CORE_BASE_ADDRESS | -				 PCIE_INTR_ENABLE_ADDRESS)); -	iowrite32(PCIE_SOC_WAKE_RESET, -		  ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + -		  PCIE_SOC_WAKE_ADDRESS); - -	ath10k_info("legacy interrupt handling\n"); -	return 0; +	switch (ar_pci->num_msi_intrs) { +	case 0: +		return ath10k_pci_request_irq_legacy(ar); +	case 1: +		return ath10k_pci_request_irq_msi(ar); +	case MSI_NUM_REQUEST: +		return ath10k_pci_request_irq_msix(ar); +	} + +	ath10k_warn("unknown irq configuration upon request\n"); +	return -EINVAL;  } -static int ath10k_pci_start_intr(struct ath10k *ar) +static void ath10k_pci_free_irq(struct ath10k *ar)  {  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	int num = MSI_NUM_REQUEST; -	int ret;  	int i; -	tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long) ar); +	/* There's at least one interrupt irregardless whether its legacy INTR +	 * or MSI or MSI-X */ +	for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++) +		free_irq(ar_pci->pdev->irq + i, ar); +} + +static void ath10k_pci_init_irq_tasklets(struct ath10k *ar) +{ +	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); +	int i; + +	tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar);  	tasklet_init(&ar_pci->msi_fw_err, ath10k_msi_err_tasklet, -		     (unsigned long) ar); +		     (unsigned long)ar); +	tasklet_init(&ar_pci->early_irq_tasklet, ath10k_pci_early_irq_tasklet, +		     (unsigned long)ar);  	for (i = 0; i < CE_COUNT; i++) {  		ar_pci->pipe_info[i].ar_pci = ar_pci; -		tasklet_init(&ar_pci->pipe_info[i].intr, -			     ath10k_pci_ce_tasklet, +		tasklet_init(&ar_pci->pipe_info[i].intr, ath10k_pci_ce_tasklet,  			     (unsigned long)&ar_pci->pipe_info[i]);  	} +} -	if (!test_bit(ATH10K_PCI_FEATURE_MSI_X, ar_pci->features)) -		num = 1; +static int ath10k_pci_init_irq(struct ath10k *ar) +{ +	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); +	bool msix_supported = test_bit(ATH10K_PCI_FEATURE_MSI_X, +				       ar_pci->features); +	int ret; -	if (num > 1) { -		ret = ath10k_pci_start_intr_msix(ar, num); -		if (ret == 0) -			goto exit; +	ath10k_pci_init_irq_tasklets(ar); + +	if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_AUTO && +	    !test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) +		ath10k_info("limiting irq mode to: %d\n", ath10k_pci_irq_mode); + +	/* Try MSI-X */ +	if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO && msix_supported) { +		ar_pci->num_msi_intrs = MSI_NUM_REQUEST; +		ret = pci_enable_msi_range(ar_pci->pdev, ar_pci->num_msi_intrs, +							 ar_pci->num_msi_intrs); +		if (ret > 0) +			return 0; -		ath10k_warn("MSI-X didn't succeed (%d), trying MSI\n", ret); -		num = 1; +		/* fall-through */  	} -	if (num == 1) { -		ret = ath10k_pci_start_intr_msi(ar); +	/* Try MSI */ +	if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_LEGACY) { +		ar_pci->num_msi_intrs = 1; +		ret = pci_enable_msi(ar_pci->pdev);  		if (ret == 0) -			goto exit; +			return 0; -		ath10k_warn("MSI didn't succeed (%d), trying legacy INTR\n", -			    ret); -		num = 0; +		/* fall-through */  	} -	ret = ath10k_pci_start_intr_legacy(ar); +	/* Try legacy irq +	 * +	 * A potential race occurs here: The CORE_BASE write +	 * depends on target correctly decoding AXI address but +	 * host won't know when target writes BAR to CORE_CTRL. +	 * This write might get lost if target has NOT written BAR. +	 * For now, fix the race by repeating the write in below +	 * synchronization checking. */ +	ar_pci->num_msi_intrs = 0; -exit: -	ar_pci->num_msi_intrs = num; -	ar_pci->ce_count = CE_COUNT; -	return ret; +	ret = ath10k_pci_wake(ar); +	if (ret) { +		ath10k_warn("failed to wake target: %d\n", ret); +		return ret; +	} + +	ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS, +			   PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL); +	ath10k_pci_sleep(ar); + +	return 0;  } -static void ath10k_pci_stop_intr(struct ath10k *ar) +static int ath10k_pci_deinit_irq_legacy(struct ath10k *ar)  { -	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	int i; +	int ret; -	/* There's at least one interrupt irregardless whether its legacy INTR -	 * or MSI or MSI-X */ -	for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++) -		free_irq(ar_pci->pdev->irq + i, ar); +	ret = ath10k_pci_wake(ar); +	if (ret) { +		ath10k_warn("failed to wake target: %d\n", ret); +		return ret; +	} + +	ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS, +			   0); +	ath10k_pci_sleep(ar); -	if (ar_pci->num_msi_intrs > 0) +	return 0; +} + +static int ath10k_pci_deinit_irq(struct ath10k *ar) +{ +	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + +	switch (ar_pci->num_msi_intrs) { +	case 0: +		return ath10k_pci_deinit_irq_legacy(ar); +	case 1: +		/* fall-through */ +	case MSI_NUM_REQUEST: +		pci_disable_msi(ar_pci->pdev); +		return 0; +	default:  		pci_disable_msi(ar_pci->pdev); +	} + +	ath10k_warn("unknown irq configuration upon deinit\n"); +	return -EINVAL;  } -static int ath10k_pci_reset_target(struct ath10k *ar) +static int ath10k_pci_wait_for_target_init(struct ath10k *ar)  {  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	int wait_limit = 300; /* 3 sec */ +	unsigned long timeout; +	int ret; +	u32 val; + +	ath10k_dbg(ATH10K_DBG_BOOT, "boot waiting target to initialise\n"); + +	ret = ath10k_pci_wake(ar); +	if (ret) { +		ath10k_err("failed to wake up target for init: %d\n", ret); +		return ret; +	} + +	timeout = jiffies + msecs_to_jiffies(ATH10K_PCI_TARGET_WAIT); -	/* Wait for Target to finish initialization before we proceed. */ -	iowrite32(PCIE_SOC_WAKE_V_MASK, -		  ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + -		  PCIE_SOC_WAKE_ADDRESS); +	do { +		val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); -	ath10k_pci_wait(ar); +		ath10k_dbg(ATH10K_DBG_BOOT, "boot target indicator %x\n", val); + +		/* target should never return this */ +		if (val == 0xffffffff) +			continue; + +		/* the device has crashed so don't bother trying anymore */ +		if (val & FW_IND_EVENT_PENDING) +			break; + +		if (val & FW_IND_INITIALIZED) +			break; -	while (wait_limit-- && -	       !(ioread32(ar_pci->mem + FW_INDICATOR_ADDRESS) & -		 FW_IND_INITIALIZED)) {  		if (ar_pci->num_msi_intrs == 0)  			/* Fix potential race by repeating CORE_BASE writes */ -			iowrite32(PCIE_INTR_FIRMWARE_MASK | -				  PCIE_INTR_CE_MASK_ALL, -				  ar_pci->mem + (SOC_CORE_BASE_ADDRESS | -						 PCIE_INTR_ENABLE_ADDRESS)); +			ath10k_pci_soc_write32(ar, PCIE_INTR_ENABLE_ADDRESS, +					       PCIE_INTR_FIRMWARE_MASK | +					       PCIE_INTR_CE_MASK_ALL); +  		mdelay(10); +	} while (time_before(jiffies, timeout)); + +	if (val == 0xffffffff) { +		ath10k_err("failed to read device register, device is gone\n"); +		ret = -EIO; +		goto out;  	} -	if (wait_limit < 0) { -		ath10k_err("Target stalled\n"); -		iowrite32(PCIE_SOC_WAKE_RESET, -			  ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + -			  PCIE_SOC_WAKE_ADDRESS); -		return -EIO; +	if (val & FW_IND_EVENT_PENDING) { +		ath10k_warn("device has crashed during init\n"); +		ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, +				   val & ~FW_IND_EVENT_PENDING); +		ath10k_pci_hif_dump_area(ar); +		ret = -ECOMM; +		goto out;  	} -	iowrite32(PCIE_SOC_WAKE_RESET, -		  ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + -		  PCIE_SOC_WAKE_ADDRESS); +	if (!(val & FW_IND_INITIALIZED)) { +		ath10k_err("failed to receive initialized event from target: %08x\n", +			   val); +		ret = -ETIMEDOUT; +		goto out; +	} -	return 0; +	ath10k_dbg(ATH10K_DBG_BOOT, "boot target initialised\n"); + +out: +	ath10k_pci_sleep(ar); +	return ret;  } -static void ath10k_pci_device_reset(struct ath10k *ar) +static int ath10k_pci_cold_reset(struct ath10k *ar)  { -	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -	void __iomem *mem = ar_pci->mem; -	int i; +	int i, ret;  	u32 val; -	if (!SOC_GLOBAL_RESET_ADDRESS) -		return; +	ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset\n"); -	if (!mem) -		return; - -	ath10k_pci_reg_write32(mem, PCIE_SOC_WAKE_ADDRESS, -			       PCIE_SOC_WAKE_V_MASK); -	for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) { -		if (ath10k_pci_target_is_awake(ar)) -			break; -		msleep(1); +	ret = ath10k_do_pci_wake(ar); +	if (ret) { +		ath10k_err("failed to wake up target: %d\n", +			   ret); +		return ret;  	}  	/* Put Target, including PCIe, into RESET. */ -	val = ath10k_pci_reg_read32(mem, SOC_GLOBAL_RESET_ADDRESS); +	val = ath10k_pci_reg_read32(ar, SOC_GLOBAL_RESET_ADDRESS);  	val |= 1; -	ath10k_pci_reg_write32(mem, SOC_GLOBAL_RESET_ADDRESS, val); +	ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val);  	for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) { -		if (ath10k_pci_reg_read32(mem, RTC_STATE_ADDRESS) & +		if (ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) &  					  RTC_STATE_COLD_RESET_MASK)  			break;  		msleep(1); @@ -2245,16 +2579,20 @@ static void ath10k_pci_device_reset(struct ath10k *ar)  	/* Pull Target, including PCIe, out of RESET. */  	val &= ~1; -	ath10k_pci_reg_write32(mem, SOC_GLOBAL_RESET_ADDRESS, val); +	ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val);  	for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) { -		if (!(ath10k_pci_reg_read32(mem, RTC_STATE_ADDRESS) & +		if (!(ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) &  					    RTC_STATE_COLD_RESET_MASK))  			break;  		msleep(1);  	} -	ath10k_pci_reg_write32(mem, PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_RESET); +	ath10k_do_pci_sleep(ar); + +	ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset complete\n"); + +	return 0;  }  static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci) @@ -2267,13 +2605,10 @@ static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci)  		switch (i) {  		case ATH10K_PCI_FEATURE_MSI_X: -			ath10k_dbg(ATH10K_DBG_PCI, "device supports MSI-X\n"); -			break; -		case ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND: -			ath10k_dbg(ATH10K_DBG_PCI, "QCA988X_1.0 workaround enabled\n"); +			ath10k_dbg(ATH10K_DBG_BOOT, "device supports MSI-X\n");  			break;  		case ATH10K_PCI_FEATURE_SOC_POWER_SAVE: -			ath10k_dbg(ATH10K_DBG_PCI, "QCA98XX SoC power save enabled\n"); +			ath10k_dbg(ATH10K_DBG_BOOT, "QCA98XX SoC power save enabled\n");  			break;  		}  	} @@ -2286,9 +2621,9 @@ static int ath10k_pci_probe(struct pci_dev *pdev,  	int ret = 0;  	struct ath10k *ar;  	struct ath10k_pci *ar_pci; -	u32 lcr_val; +	u32 lcr_val, chip_id; -	ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__); +	ath10k_dbg(ATH10K_DBG_PCI, "pci probe\n");  	ar_pci = kzalloc(sizeof(*ar_pci), GFP_KERNEL);  	if (ar_pci == NULL) @@ -2298,62 +2633,42 @@ static int ath10k_pci_probe(struct pci_dev *pdev,  	ar_pci->dev = &pdev->dev;  	switch (pci_dev->device) { -	case QCA988X_1_0_DEVICE_ID: -		set_bit(ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND, ar_pci->features); -		break;  	case QCA988X_2_0_DEVICE_ID:  		set_bit(ATH10K_PCI_FEATURE_MSI_X, ar_pci->features);  		break;  	default:  		ret = -ENODEV; -		ath10k_err("Unkown device ID: %d\n", pci_dev->device); +		ath10k_err("Unknown device ID: %d\n", pci_dev->device);  		goto err_ar_pci;  	} -	if (ath10k_target_ps) +	if (ath10k_pci_target_ps)  		set_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features);  	ath10k_pci_dump_features(ar_pci);  	ar = ath10k_core_create(ar_pci, ar_pci->dev, &ath10k_pci_hif_ops);  	if (!ar) { -		ath10k_err("ath10k_core_create failed!\n"); +		ath10k_err("failed to create driver core\n");  		ret = -EINVAL;  		goto err_ar_pci;  	} -	/* Enable QCA988X_1.0 HW workarounds */ -	if (test_bit(ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND, ar_pci->features)) -		spin_lock_init(&ar_pci->hw_v1_workaround_lock); -  	ar_pci->ar = ar; -	ar_pci->fw_indicator_address = FW_INDICATOR_ADDRESS;  	atomic_set(&ar_pci->keep_awake_count, 0);  	pci_set_drvdata(pdev, ar); -	/* -	 * Without any knowledge of the Host, the Target may have been reset or -	 * power cycled and its Config Space may no longer reflect the PCI -	 * address space that was assigned earlier by the PCI infrastructure. -	 * Refresh it now. -	 */ -	ret = pci_assign_resource(pdev, BAR_NUM); -	if (ret) { -		ath10k_err("cannot assign PCI space: %d\n", ret); -		goto err_ar; -	} -  	ret = pci_enable_device(pdev);  	if (ret) { -		ath10k_err("cannot enable PCI device: %d\n", ret); +		ath10k_err("failed to enable PCI device: %d\n", ret);  		goto err_ar;  	}  	/* Request MMIO resources */  	ret = pci_request_region(pdev, BAR_NUM, "ath");  	if (ret) { -		ath10k_err("PCI MMIO reservation error: %d\n", ret); +		ath10k_err("failed to request MMIO region: %d\n", ret);  		goto err_device;  	} @@ -2363,13 +2678,13 @@ static int ath10k_pci_probe(struct pci_dev *pdev,  	 */  	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));  	if (ret) { -		ath10k_err("32-bit DMA not available: %d\n", ret); +		ath10k_err("failed to set DMA mask to 32-bit: %d\n", ret);  		goto err_region;  	}  	ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));  	if (ret) { -		ath10k_err("cannot enable 32-bit consistent DMA\n"); +		ath10k_err("failed to set consistent DMA mask to 32-bit\n");  		goto err_region;  	} @@ -2386,7 +2701,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,  	/* Arrange for access to Target SoC registers. */  	mem = pci_iomap(pdev, BAR_NUM, 0);  	if (!mem) { -		ath10k_err("PCI iomap error\n"); +		ath10k_err("failed to perform IOMAP for BAR%d\n", BAR_NUM);  		ret = -EIO;  		goto err_master;  	} @@ -2395,16 +2710,34 @@ static int ath10k_pci_probe(struct pci_dev *pdev,  	spin_lock_init(&ar_pci->ce_lock); -	ar_pci->cacheline_sz = dma_get_cache_alignment(); +	ret = ath10k_do_pci_wake(ar); +	if (ret) { +		ath10k_err("Failed to get chip id: %d\n", ret); +		goto err_iomap; +	} -	ret = ath10k_core_register(ar); +	chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); + +	ath10k_do_pci_sleep(ar); + +	ret = ath10k_pci_alloc_ce(ar);  	if (ret) { -		ath10k_err("could not register driver core (%d)\n", ret); +		ath10k_err("failed to allocate copy engine pipes: %d\n", ret);  		goto err_iomap;  	} +	ath10k_dbg(ATH10K_DBG_BOOT, "boot pci_mem 0x%p\n", ar_pci->mem); + +	ret = ath10k_core_register(ar, chip_id); +	if (ret) { +		ath10k_err("failed to register driver core: %d\n", ret); +		goto err_free_ce; +	} +  	return 0; +err_free_ce: +	ath10k_pci_free_ce(ar);  err_iomap:  	pci_iounmap(pdev, mem);  err_master: @@ -2414,7 +2747,6 @@ err_region:  err_device:  	pci_disable_device(pdev);  err_ar: -	pci_set_drvdata(pdev, NULL);  	ath10k_core_destroy(ar);  err_ar_pci:  	/* call HIF PCI free here */ @@ -2428,7 +2760,7 @@ static void ath10k_pci_remove(struct pci_dev *pdev)  	struct ath10k *ar = pci_get_drvdata(pdev);  	struct ath10k_pci *ar_pci; -	ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__); +	ath10k_dbg(ATH10K_DBG_PCI, "pci remove\n");  	if (!ar)  		return; @@ -2438,11 +2770,9 @@ static void ath10k_pci_remove(struct pci_dev *pdev)  	if (!ar_pci)  		return; -	tasklet_kill(&ar_pci->msi_fw_err); -  	ath10k_core_unregister(ar); +	ath10k_pci_free_ce(ar); -	pci_set_drvdata(pdev, NULL);  	pci_iounmap(pdev, ar_pci->mem);  	pci_release_region(pdev, BAR_NUM);  	pci_clear_master(pdev); @@ -2467,7 +2797,7 @@ static int __init ath10k_pci_init(void)  	ret = pci_register_driver(&ath10k_pci_driver);  	if (ret) -		ath10k_err("pci_register_driver failed [%d]\n", ret); +		ath10k_err("failed to register PCI driver: %d\n", ret);  	return ret;  } @@ -2483,9 +2813,5 @@ module_exit(ath10k_pci_exit);  MODULE_AUTHOR("Qualcomm Atheros");  MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices");  MODULE_LICENSE("Dual BSD/GPL"); -MODULE_FIRMWARE(QCA988X_HW_1_0_FW_DIR "/" QCA988X_HW_1_0_FW_FILE); -MODULE_FIRMWARE(QCA988X_HW_1_0_FW_DIR "/" QCA988X_HW_1_0_OTP_FILE); -MODULE_FIRMWARE(QCA988X_HW_1_0_FW_DIR "/" QCA988X_HW_1_0_BOARD_DATA_FILE); -MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_FILE); -MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_OTP_FILE); +MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_2_FILE);  MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE); diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index 871bb339d56..dfdebb4157a 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -43,22 +43,6 @@ struct bmi_xfer {  	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   * @@ -152,17 +136,16 @@ struct service_to_pipe {  enum ath10k_pci_features {  	ATH10K_PCI_FEATURE_MSI_X		= 0, -	ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND	= 1, -	ATH10K_PCI_FEATURE_SOC_POWER_SAVE	= 2, +	ATH10K_PCI_FEATURE_SOC_POWER_SAVE	= 1,  	/* keep last */  	ATH10K_PCI_FEATURE_COUNT  };  /* Per-pipe state. */ -struct hif_ce_pipe_info { +struct ath10k_pci_pipe {  	/* Handle of underlying Copy Engine */ -	struct ce_state *ce_hdl; +	struct ath10k_ce_pipe *ce_hdl;  	/* Our pipe number; facilitiates use of pipe_info ptrs. */  	u8 pipe_num; @@ -175,12 +158,6 @@ struct hif_ce_pipe_info {  	/* 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;  }; @@ -190,7 +167,6 @@ struct ath10k_pci {  	struct device *dev;  	struct ath10k *ar;  	void __iomem *mem; -	int cacheline_sz;  	DECLARE_BITMAP(features, ATH10K_PCI_FEATURE_COUNT); @@ -202,41 +178,25 @@ struct ath10k_pci {  	struct tasklet_struct intr_tq;  	struct tasklet_struct msi_fw_err; - -	/* Number of Copy Engines supported */ -	unsigned int ce_count; +	struct tasklet_struct early_irq_tasklet;  	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_pci_pipe 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; +	struct ath10k_ce_pipe *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; +	struct ath10k_ce_pipe ce_states[CE_COUNT_MAX];  };  static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar) @@ -244,14 +204,18 @@ 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) +static inline u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr)  { -	return ioread32(mem + PCIE_LOCAL_BASE_ADDRESS + addr); +	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + +	return ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);  } -static inline void ath10k_pci_reg_write32(void __iomem *mem, u32 addr, u32 val) +static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)  { -	iowrite32(val, mem + PCIE_LOCAL_BASE_ADDRESS + addr); +	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + +	iowrite32(val, ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);  }  #define ATH_PCI_RESET_WAIT_MAX 10 /* ms */ @@ -310,23 +274,8 @@ 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_WORKAROUND, 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); -	} +	iowrite32(value, ar_pci->mem + offset);  }  static inline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset) @@ -336,15 +285,27 @@ static inline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)  	return ioread32(ar_pci->mem + offset);  } -void ath10k_do_pci_wake(struct ath10k *ar); +static inline u32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr) +{ +	return ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + addr); +} + +static inline void ath10k_pci_soc_write32(struct ath10k *ar, u32 addr, u32 val) +{ +	ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + addr, val); +} + +int ath10k_do_pci_wake(struct ath10k *ar);  void ath10k_do_pci_sleep(struct ath10k *ar); -static inline void ath10k_pci_wake(struct ath10k *ar) +static inline int ath10k_pci_wake(struct ath10k *ar)  {  	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);  	if (test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) -		ath10k_do_pci_wake(ar); +		return ath10k_do_pci_wake(ar); + +	return 0;  }  static inline void ath10k_pci_sleep(struct ath10k *ar) diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h index bfec6c8f2ec..1c584c4b019 100644 --- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++ b/drivers/net/wireless/ath/ath10k/rx_desc.h @@ -422,10 +422,30 @@ struct rx_mpdu_end {  #define RX_MSDU_START_INFO1_IP_FRAG             (1 << 14)  #define RX_MSDU_START_INFO1_TCP_ONLY_ACK        (1 << 15) +/* The decapped header (rx_hdr_status) contains the following: + *  a) 802.11 header + *  [padding to 4 bytes] + *  b) HW crypto parameter + *     - 0 bytes for no security + *     - 4 bytes for WEP + *     - 8 bytes for TKIP, AES + *  [padding to 4 bytes] + *  c) A-MSDU subframe header (14 bytes) if appliable + *  d) LLC/SNAP (RFC1042, 8 bytes) + * + * In case of A-MSDU only first frame in sequence contains (a) and (b). */  enum rx_msdu_decap_format { -	RX_MSDU_DECAP_RAW           = 0, -	RX_MSDU_DECAP_NATIVE_WIFI   = 1, +	RX_MSDU_DECAP_RAW = 0, + +	/* Note: QoS frames are reported as non-QoS. The rx_hdr_status in +	 * htt_rx_desc contains the original decapped 802.11 header. */ +	RX_MSDU_DECAP_NATIVE_WIFI = 1, + +	/* Payload contains an ethernet header (struct ethhdr). */  	RX_MSDU_DECAP_ETHERNET2_DIX = 2, + +	/* Payload contains two 48-bit addresses and 2-byte length (14 bytes +	 * total), followed by an RFC1042 header (8 bytes). */  	RX_MSDU_DECAP_8023_SNAP_LLC = 3  }; diff --git a/drivers/net/wireless/ath/ath10k/trace.h b/drivers/net/wireless/ath/ath10k/trace.h index 85e806bf725..4eb2ecbc06e 100644 --- a/drivers/net/wireless/ath/ath10k/trace.h +++ b/drivers/net/wireless/ath/ath10k/trace.h @@ -111,26 +111,29 @@ TRACE_EVENT(ath10k_log_dbg_dump,  );  TRACE_EVENT(ath10k_wmi_cmd, -	TP_PROTO(int id, void *buf, size_t buf_len), +	TP_PROTO(int id, void *buf, size_t buf_len, int ret), -	TP_ARGS(id, buf, buf_len), +	TP_ARGS(id, buf, buf_len, ret),  	TP_STRUCT__entry(  		__field(unsigned int, id)  		__field(size_t, buf_len)  		__dynamic_array(u8, buf, buf_len) +		__field(int, ret)  	),  	TP_fast_assign(  		__entry->id = id;  		__entry->buf_len = buf_len; +		__entry->ret = ret;  		memcpy(__get_dynamic_array(buf), buf, buf_len);  	),  	TP_printk( -		"id %d len %zu", +		"id %d len %zu ret %d",  		__entry->id, -		__entry->buf_len +		__entry->buf_len, +		__entry->ret  	)  ); @@ -158,6 +161,48 @@ TRACE_EVENT(ath10k_wmi_event,  	)  ); +TRACE_EVENT(ath10k_htt_stats, +	TP_PROTO(void *buf, size_t buf_len), + +	TP_ARGS(buf, buf_len), + +	TP_STRUCT__entry( +		__field(size_t, buf_len) +		__dynamic_array(u8, buf, buf_len) +	), + +	TP_fast_assign( +		__entry->buf_len = buf_len; +		memcpy(__get_dynamic_array(buf), buf, buf_len); +	), + +	TP_printk( +		"len %zu", +		__entry->buf_len +	) +); + +TRACE_EVENT(ath10k_wmi_dbglog, +	TP_PROTO(void *buf, size_t buf_len), + +	TP_ARGS(buf, buf_len), + +	TP_STRUCT__entry( +		__field(size_t, buf_len) +		__dynamic_array(u8, buf, buf_len) +	), + +	TP_fast_assign( +		__entry->buf_len = buf_len; +		memcpy(__get_dynamic_array(buf), buf, buf_len); +	), + +	TP_printk( +		"len %zu", +		__entry->buf_len +	) +); +  #endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/  /* we don't want to use include/trace/events */ diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 68b6faefd1d..82669a77e55 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -44,40 +44,41 @@ out:  	spin_unlock_bh(&ar->data_lock);  } -void ath10k_txrx_tx_unref(struct ath10k_htt *htt, struct sk_buff *txdesc) +void ath10k_txrx_tx_unref(struct ath10k_htt *htt, +			  const struct htt_tx_done *tx_done)  {  	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; +	struct ath10k_skb_cb *skb_cb; +	struct sk_buff *msdu; -	if (ATH10K_SKB_CB(txdesc)->htt.refcount == 0) -		return; +	lockdep_assert_held(&htt->tx_lock); -	ATH10K_SKB_CB(txdesc)->htt.refcount--; +	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 (ATH10K_SKB_CB(txdesc)->htt.refcount > 0) +	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; +	} -	if (txfrag) { -		ret = ath10k_skb_unmap(dev, txfrag); -		if (ret) -			ath10k_warn("txfrag unmap failed (%d)\n", ret); +	msdu = htt->pending_tx[tx_done->msdu_id]; +	skb_cb = ATH10K_SKB_CB(msdu); -		dev_kfree_skb_any(txfrag); -	} +	dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); -	ret = ath10k_skb_unmap(dev, msdu); -	if (ret) -		ath10k_warn("data skb unmap failed (%d)\n", ret); +	if (skb_cb->htt.txbuf) +		dma_pool_free(htt->tx_pool, +			      skb_cb->htt.txbuf, +			      skb_cb->htt.txbuf_paddr);  	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) { +	if (tx_done->discard) {  		ieee80211_free_txskb(htt->ar->hw, msdu);  		goto exit;  	} @@ -85,216 +86,18 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, struct sk_buff *txdesc)  	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))  		info->flags |= IEEE80211_TX_STAT_ACK; -	if (ATH10K_SKB_CB(txdesc)->htt.no_ack) +	if (tx_done->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); +	htt->pending_tx[tx_done->msdu_id] = NULL; +	ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id);  	__ath10k_htt_tx_dec_pending(htt); -	if (bitmap_empty(htt->used_msdu_ids, htt->max_num_pending_tx)) +	if (htt->num_pending_tx == 0)  		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, @@ -397,7 +200,8 @@ void ath10k_peer_unmap_event(struct ath10k_htt *htt,  	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); +		ath10k_warn("peer-unmap-event: unknown peer id %d\n", +			    ev->peer_id);  		goto exit;  	} diff --git a/drivers/net/wireless/ath/ath10k/txrx.h b/drivers/net/wireless/ath/ath10k/txrx.h index e78632a76df..aee3e20058f 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.h +++ b/drivers/net/wireless/ath/ath10k/txrx.h @@ -19,10 +19,8 @@  #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); +void ath10k_txrx_tx_unref(struct ath10k_htt *htt, +			  const struct htt_tx_done *tx_done);  struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id,  				     const u8 *addr); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 55f90c76186..4b7782a529a 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -16,6 +16,7 @@   */  #include <linux/skbuff.h> +#include <linux/ctype.h>  #include "core.h"  #include "htc.h" @@ -23,29 +24,468 @@  #include "wmi.h"  #include "mac.h" -void ath10k_wmi_flush_tx(struct ath10k *ar) -{ -	int ret; - -	lockdep_assert_held(&ar->conf_mutex); - -	if (ar->state == ATH10K_STATE_WEDGED) { -		ath10k_warn("wmi flush skipped - device is wedged anyway\n"); -		return; -	} - -	ret = wait_event_timeout(ar->wmi.wq, -				 atomic_read(&ar->wmi.pending_tx_count) == 0, -				 5*HZ); -	if (atomic_read(&ar->wmi.pending_tx_count) == 0) -		return; - -	if (ret == 0) -		ret = -ETIMEDOUT; - -	if (ret < 0) -		ath10k_warn("wmi flush failed (%d)\n", ret); -} +/* MAIN WMI cmd track */ +static struct wmi_cmd_map wmi_cmd_map = { +	.init_cmdid = WMI_INIT_CMDID, +	.start_scan_cmdid = WMI_START_SCAN_CMDID, +	.stop_scan_cmdid = WMI_STOP_SCAN_CMDID, +	.scan_chan_list_cmdid = WMI_SCAN_CHAN_LIST_CMDID, +	.scan_sch_prio_tbl_cmdid = WMI_SCAN_SCH_PRIO_TBL_CMDID, +	.pdev_set_regdomain_cmdid = WMI_PDEV_SET_REGDOMAIN_CMDID, +	.pdev_set_channel_cmdid = WMI_PDEV_SET_CHANNEL_CMDID, +	.pdev_set_param_cmdid = WMI_PDEV_SET_PARAM_CMDID, +	.pdev_pktlog_enable_cmdid = WMI_PDEV_PKTLOG_ENABLE_CMDID, +	.pdev_pktlog_disable_cmdid = WMI_PDEV_PKTLOG_DISABLE_CMDID, +	.pdev_set_wmm_params_cmdid = WMI_PDEV_SET_WMM_PARAMS_CMDID, +	.pdev_set_ht_cap_ie_cmdid = WMI_PDEV_SET_HT_CAP_IE_CMDID, +	.pdev_set_vht_cap_ie_cmdid = WMI_PDEV_SET_VHT_CAP_IE_CMDID, +	.pdev_set_dscp_tid_map_cmdid = WMI_PDEV_SET_DSCP_TID_MAP_CMDID, +	.pdev_set_quiet_mode_cmdid = WMI_PDEV_SET_QUIET_MODE_CMDID, +	.pdev_green_ap_ps_enable_cmdid = WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID, +	.pdev_get_tpc_config_cmdid = WMI_PDEV_GET_TPC_CONFIG_CMDID, +	.pdev_set_base_macaddr_cmdid = WMI_PDEV_SET_BASE_MACADDR_CMDID, +	.vdev_create_cmdid = WMI_VDEV_CREATE_CMDID, +	.vdev_delete_cmdid = WMI_VDEV_DELETE_CMDID, +	.vdev_start_request_cmdid = WMI_VDEV_START_REQUEST_CMDID, +	.vdev_restart_request_cmdid = WMI_VDEV_RESTART_REQUEST_CMDID, +	.vdev_up_cmdid = WMI_VDEV_UP_CMDID, +	.vdev_stop_cmdid = WMI_VDEV_STOP_CMDID, +	.vdev_down_cmdid = WMI_VDEV_DOWN_CMDID, +	.vdev_set_param_cmdid = WMI_VDEV_SET_PARAM_CMDID, +	.vdev_install_key_cmdid = WMI_VDEV_INSTALL_KEY_CMDID, +	.peer_create_cmdid = WMI_PEER_CREATE_CMDID, +	.peer_delete_cmdid = WMI_PEER_DELETE_CMDID, +	.peer_flush_tids_cmdid = WMI_PEER_FLUSH_TIDS_CMDID, +	.peer_set_param_cmdid = WMI_PEER_SET_PARAM_CMDID, +	.peer_assoc_cmdid = WMI_PEER_ASSOC_CMDID, +	.peer_add_wds_entry_cmdid = WMI_PEER_ADD_WDS_ENTRY_CMDID, +	.peer_remove_wds_entry_cmdid = WMI_PEER_REMOVE_WDS_ENTRY_CMDID, +	.peer_mcast_group_cmdid = WMI_PEER_MCAST_GROUP_CMDID, +	.bcn_tx_cmdid = WMI_BCN_TX_CMDID, +	.pdev_send_bcn_cmdid = WMI_PDEV_SEND_BCN_CMDID, +	.bcn_tmpl_cmdid = WMI_BCN_TMPL_CMDID, +	.bcn_filter_rx_cmdid = WMI_BCN_FILTER_RX_CMDID, +	.prb_req_filter_rx_cmdid = WMI_PRB_REQ_FILTER_RX_CMDID, +	.mgmt_tx_cmdid = WMI_MGMT_TX_CMDID, +	.prb_tmpl_cmdid = WMI_PRB_TMPL_CMDID, +	.addba_clear_resp_cmdid = WMI_ADDBA_CLEAR_RESP_CMDID, +	.addba_send_cmdid = WMI_ADDBA_SEND_CMDID, +	.addba_status_cmdid = WMI_ADDBA_STATUS_CMDID, +	.delba_send_cmdid = WMI_DELBA_SEND_CMDID, +	.addba_set_resp_cmdid = WMI_ADDBA_SET_RESP_CMDID, +	.send_singleamsdu_cmdid = WMI_SEND_SINGLEAMSDU_CMDID, +	.sta_powersave_mode_cmdid = WMI_STA_POWERSAVE_MODE_CMDID, +	.sta_powersave_param_cmdid = WMI_STA_POWERSAVE_PARAM_CMDID, +	.sta_mimo_ps_mode_cmdid = WMI_STA_MIMO_PS_MODE_CMDID, +	.pdev_dfs_enable_cmdid = WMI_PDEV_DFS_ENABLE_CMDID, +	.pdev_dfs_disable_cmdid = WMI_PDEV_DFS_DISABLE_CMDID, +	.roam_scan_mode = WMI_ROAM_SCAN_MODE, +	.roam_scan_rssi_threshold = WMI_ROAM_SCAN_RSSI_THRESHOLD, +	.roam_scan_period = WMI_ROAM_SCAN_PERIOD, +	.roam_scan_rssi_change_threshold = WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, +	.roam_ap_profile = WMI_ROAM_AP_PROFILE, +	.ofl_scan_add_ap_profile = WMI_ROAM_AP_PROFILE, +	.ofl_scan_remove_ap_profile = WMI_OFL_SCAN_REMOVE_AP_PROFILE, +	.ofl_scan_period = WMI_OFL_SCAN_PERIOD, +	.p2p_dev_set_device_info = WMI_P2P_DEV_SET_DEVICE_INFO, +	.p2p_dev_set_discoverability = WMI_P2P_DEV_SET_DISCOVERABILITY, +	.p2p_go_set_beacon_ie = WMI_P2P_GO_SET_BEACON_IE, +	.p2p_go_set_probe_resp_ie = WMI_P2P_GO_SET_PROBE_RESP_IE, +	.p2p_set_vendor_ie_data_cmdid = WMI_P2P_SET_VENDOR_IE_DATA_CMDID, +	.ap_ps_peer_param_cmdid = WMI_AP_PS_PEER_PARAM_CMDID, +	.ap_ps_peer_uapsd_coex_cmdid = WMI_AP_PS_PEER_UAPSD_COEX_CMDID, +	.peer_rate_retry_sched_cmdid = WMI_PEER_RATE_RETRY_SCHED_CMDID, +	.wlan_profile_trigger_cmdid = WMI_WLAN_PROFILE_TRIGGER_CMDID, +	.wlan_profile_set_hist_intvl_cmdid = +				WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID, +	.wlan_profile_get_profile_data_cmdid = +				WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, +	.wlan_profile_enable_profile_id_cmdid = +				WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, +	.wlan_profile_list_profile_id_cmdid = +				WMI_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, +	.pdev_suspend_cmdid = WMI_PDEV_SUSPEND_CMDID, +	.pdev_resume_cmdid = WMI_PDEV_RESUME_CMDID, +	.add_bcn_filter_cmdid = WMI_ADD_BCN_FILTER_CMDID, +	.rmv_bcn_filter_cmdid = WMI_RMV_BCN_FILTER_CMDID, +	.wow_add_wake_pattern_cmdid = WMI_WOW_ADD_WAKE_PATTERN_CMDID, +	.wow_del_wake_pattern_cmdid = WMI_WOW_DEL_WAKE_PATTERN_CMDID, +	.wow_enable_disable_wake_event_cmdid = +				WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, +	.wow_enable_cmdid = WMI_WOW_ENABLE_CMDID, +	.wow_hostwakeup_from_sleep_cmdid = WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, +	.rtt_measreq_cmdid = WMI_RTT_MEASREQ_CMDID, +	.rtt_tsf_cmdid = WMI_RTT_TSF_CMDID, +	.vdev_spectral_scan_configure_cmdid = +				WMI_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID, +	.vdev_spectral_scan_enable_cmdid = WMI_VDEV_SPECTRAL_SCAN_ENABLE_CMDID, +	.request_stats_cmdid = WMI_REQUEST_STATS_CMDID, +	.set_arp_ns_offload_cmdid = WMI_SET_ARP_NS_OFFLOAD_CMDID, +	.network_list_offload_config_cmdid = +				WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID, +	.gtk_offload_cmdid = WMI_GTK_OFFLOAD_CMDID, +	.csa_offload_enable_cmdid = WMI_CSA_OFFLOAD_ENABLE_CMDID, +	.csa_offload_chanswitch_cmdid = WMI_CSA_OFFLOAD_CHANSWITCH_CMDID, +	.chatter_set_mode_cmdid = WMI_CHATTER_SET_MODE_CMDID, +	.peer_tid_addba_cmdid = WMI_PEER_TID_ADDBA_CMDID, +	.peer_tid_delba_cmdid = WMI_PEER_TID_DELBA_CMDID, +	.sta_dtim_ps_method_cmdid = WMI_STA_DTIM_PS_METHOD_CMDID, +	.sta_uapsd_auto_trig_cmdid = WMI_STA_UAPSD_AUTO_TRIG_CMDID, +	.sta_keepalive_cmd = WMI_STA_KEEPALIVE_CMD, +	.echo_cmdid = WMI_ECHO_CMDID, +	.pdev_utf_cmdid = WMI_PDEV_UTF_CMDID, +	.dbglog_cfg_cmdid = WMI_DBGLOG_CFG_CMDID, +	.pdev_qvit_cmdid = WMI_PDEV_QVIT_CMDID, +	.pdev_ftm_intg_cmdid = WMI_PDEV_FTM_INTG_CMDID, +	.vdev_set_keepalive_cmdid = WMI_VDEV_SET_KEEPALIVE_CMDID, +	.vdev_get_keepalive_cmdid = WMI_VDEV_GET_KEEPALIVE_CMDID, +	.force_fw_hang_cmdid = WMI_FORCE_FW_HANG_CMDID, +	.gpio_config_cmdid = WMI_GPIO_CONFIG_CMDID, +	.gpio_output_cmdid = WMI_GPIO_OUTPUT_CMDID, +}; + +/* 10.X WMI cmd track */ +static struct wmi_cmd_map wmi_10x_cmd_map = { +	.init_cmdid = WMI_10X_INIT_CMDID, +	.start_scan_cmdid = WMI_10X_START_SCAN_CMDID, +	.stop_scan_cmdid = WMI_10X_STOP_SCAN_CMDID, +	.scan_chan_list_cmdid = WMI_10X_SCAN_CHAN_LIST_CMDID, +	.scan_sch_prio_tbl_cmdid = WMI_CMD_UNSUPPORTED, +	.pdev_set_regdomain_cmdid = WMI_10X_PDEV_SET_REGDOMAIN_CMDID, +	.pdev_set_channel_cmdid = WMI_10X_PDEV_SET_CHANNEL_CMDID, +	.pdev_set_param_cmdid = WMI_10X_PDEV_SET_PARAM_CMDID, +	.pdev_pktlog_enable_cmdid = WMI_10X_PDEV_PKTLOG_ENABLE_CMDID, +	.pdev_pktlog_disable_cmdid = WMI_10X_PDEV_PKTLOG_DISABLE_CMDID, +	.pdev_set_wmm_params_cmdid = WMI_10X_PDEV_SET_WMM_PARAMS_CMDID, +	.pdev_set_ht_cap_ie_cmdid = WMI_10X_PDEV_SET_HT_CAP_IE_CMDID, +	.pdev_set_vht_cap_ie_cmdid = WMI_10X_PDEV_SET_VHT_CAP_IE_CMDID, +	.pdev_set_dscp_tid_map_cmdid = WMI_10X_PDEV_SET_DSCP_TID_MAP_CMDID, +	.pdev_set_quiet_mode_cmdid = WMI_10X_PDEV_SET_QUIET_MODE_CMDID, +	.pdev_green_ap_ps_enable_cmdid = WMI_10X_PDEV_GREEN_AP_PS_ENABLE_CMDID, +	.pdev_get_tpc_config_cmdid = WMI_10X_PDEV_GET_TPC_CONFIG_CMDID, +	.pdev_set_base_macaddr_cmdid = WMI_10X_PDEV_SET_BASE_MACADDR_CMDID, +	.vdev_create_cmdid = WMI_10X_VDEV_CREATE_CMDID, +	.vdev_delete_cmdid = WMI_10X_VDEV_DELETE_CMDID, +	.vdev_start_request_cmdid = WMI_10X_VDEV_START_REQUEST_CMDID, +	.vdev_restart_request_cmdid = WMI_10X_VDEV_RESTART_REQUEST_CMDID, +	.vdev_up_cmdid = WMI_10X_VDEV_UP_CMDID, +	.vdev_stop_cmdid = WMI_10X_VDEV_STOP_CMDID, +	.vdev_down_cmdid = WMI_10X_VDEV_DOWN_CMDID, +	.vdev_set_param_cmdid = WMI_10X_VDEV_SET_PARAM_CMDID, +	.vdev_install_key_cmdid = WMI_10X_VDEV_INSTALL_KEY_CMDID, +	.peer_create_cmdid = WMI_10X_PEER_CREATE_CMDID, +	.peer_delete_cmdid = WMI_10X_PEER_DELETE_CMDID, +	.peer_flush_tids_cmdid = WMI_10X_PEER_FLUSH_TIDS_CMDID, +	.peer_set_param_cmdid = WMI_10X_PEER_SET_PARAM_CMDID, +	.peer_assoc_cmdid = WMI_10X_PEER_ASSOC_CMDID, +	.peer_add_wds_entry_cmdid = WMI_10X_PEER_ADD_WDS_ENTRY_CMDID, +	.peer_remove_wds_entry_cmdid = WMI_10X_PEER_REMOVE_WDS_ENTRY_CMDID, +	.peer_mcast_group_cmdid = WMI_10X_PEER_MCAST_GROUP_CMDID, +	.bcn_tx_cmdid = WMI_10X_BCN_TX_CMDID, +	.pdev_send_bcn_cmdid = WMI_10X_PDEV_SEND_BCN_CMDID, +	.bcn_tmpl_cmdid = WMI_CMD_UNSUPPORTED, +	.bcn_filter_rx_cmdid = WMI_10X_BCN_FILTER_RX_CMDID, +	.prb_req_filter_rx_cmdid = WMI_10X_PRB_REQ_FILTER_RX_CMDID, +	.mgmt_tx_cmdid = WMI_10X_MGMT_TX_CMDID, +	.prb_tmpl_cmdid = WMI_CMD_UNSUPPORTED, +	.addba_clear_resp_cmdid = WMI_10X_ADDBA_CLEAR_RESP_CMDID, +	.addba_send_cmdid = WMI_10X_ADDBA_SEND_CMDID, +	.addba_status_cmdid = WMI_10X_ADDBA_STATUS_CMDID, +	.delba_send_cmdid = WMI_10X_DELBA_SEND_CMDID, +	.addba_set_resp_cmdid = WMI_10X_ADDBA_SET_RESP_CMDID, +	.send_singleamsdu_cmdid = WMI_10X_SEND_SINGLEAMSDU_CMDID, +	.sta_powersave_mode_cmdid = WMI_10X_STA_POWERSAVE_MODE_CMDID, +	.sta_powersave_param_cmdid = WMI_10X_STA_POWERSAVE_PARAM_CMDID, +	.sta_mimo_ps_mode_cmdid = WMI_10X_STA_MIMO_PS_MODE_CMDID, +	.pdev_dfs_enable_cmdid = WMI_10X_PDEV_DFS_ENABLE_CMDID, +	.pdev_dfs_disable_cmdid = WMI_10X_PDEV_DFS_DISABLE_CMDID, +	.roam_scan_mode = WMI_10X_ROAM_SCAN_MODE, +	.roam_scan_rssi_threshold = WMI_10X_ROAM_SCAN_RSSI_THRESHOLD, +	.roam_scan_period = WMI_10X_ROAM_SCAN_PERIOD, +	.roam_scan_rssi_change_threshold = +				WMI_10X_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, +	.roam_ap_profile = WMI_10X_ROAM_AP_PROFILE, +	.ofl_scan_add_ap_profile = WMI_10X_OFL_SCAN_ADD_AP_PROFILE, +	.ofl_scan_remove_ap_profile = WMI_10X_OFL_SCAN_REMOVE_AP_PROFILE, +	.ofl_scan_period = WMI_10X_OFL_SCAN_PERIOD, +	.p2p_dev_set_device_info = WMI_10X_P2P_DEV_SET_DEVICE_INFO, +	.p2p_dev_set_discoverability = WMI_10X_P2P_DEV_SET_DISCOVERABILITY, +	.p2p_go_set_beacon_ie = WMI_10X_P2P_GO_SET_BEACON_IE, +	.p2p_go_set_probe_resp_ie = WMI_10X_P2P_GO_SET_PROBE_RESP_IE, +	.p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED, +	.ap_ps_peer_param_cmdid = WMI_10X_AP_PS_PEER_PARAM_CMDID, +	.ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_rate_retry_sched_cmdid = WMI_10X_PEER_RATE_RETRY_SCHED_CMDID, +	.wlan_profile_trigger_cmdid = WMI_10X_WLAN_PROFILE_TRIGGER_CMDID, +	.wlan_profile_set_hist_intvl_cmdid = +				WMI_10X_WLAN_PROFILE_SET_HIST_INTVL_CMDID, +	.wlan_profile_get_profile_data_cmdid = +				WMI_10X_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, +	.wlan_profile_enable_profile_id_cmdid = +				WMI_10X_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, +	.wlan_profile_list_profile_id_cmdid = +				WMI_10X_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, +	.pdev_suspend_cmdid = WMI_10X_PDEV_SUSPEND_CMDID, +	.pdev_resume_cmdid = WMI_10X_PDEV_RESUME_CMDID, +	.add_bcn_filter_cmdid = WMI_10X_ADD_BCN_FILTER_CMDID, +	.rmv_bcn_filter_cmdid = WMI_10X_RMV_BCN_FILTER_CMDID, +	.wow_add_wake_pattern_cmdid = WMI_10X_WOW_ADD_WAKE_PATTERN_CMDID, +	.wow_del_wake_pattern_cmdid = WMI_10X_WOW_DEL_WAKE_PATTERN_CMDID, +	.wow_enable_disable_wake_event_cmdid = +				WMI_10X_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, +	.wow_enable_cmdid = WMI_10X_WOW_ENABLE_CMDID, +	.wow_hostwakeup_from_sleep_cmdid = +				WMI_10X_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, +	.rtt_measreq_cmdid = WMI_10X_RTT_MEASREQ_CMDID, +	.rtt_tsf_cmdid = WMI_10X_RTT_TSF_CMDID, +	.vdev_spectral_scan_configure_cmdid = +				WMI_10X_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID, +	.vdev_spectral_scan_enable_cmdid = +				WMI_10X_VDEV_SPECTRAL_SCAN_ENABLE_CMDID, +	.request_stats_cmdid = WMI_10X_REQUEST_STATS_CMDID, +	.set_arp_ns_offload_cmdid = WMI_CMD_UNSUPPORTED, +	.network_list_offload_config_cmdid = WMI_CMD_UNSUPPORTED, +	.gtk_offload_cmdid = WMI_CMD_UNSUPPORTED, +	.csa_offload_enable_cmdid = WMI_CMD_UNSUPPORTED, +	.csa_offload_chanswitch_cmdid = WMI_CMD_UNSUPPORTED, +	.chatter_set_mode_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_tid_addba_cmdid = WMI_CMD_UNSUPPORTED, +	.peer_tid_delba_cmdid = WMI_CMD_UNSUPPORTED, +	.sta_dtim_ps_method_cmdid = WMI_CMD_UNSUPPORTED, +	.sta_uapsd_auto_trig_cmdid = WMI_CMD_UNSUPPORTED, +	.sta_keepalive_cmd = WMI_CMD_UNSUPPORTED, +	.echo_cmdid = WMI_10X_ECHO_CMDID, +	.pdev_utf_cmdid = WMI_10X_PDEV_UTF_CMDID, +	.dbglog_cfg_cmdid = WMI_10X_DBGLOG_CFG_CMDID, +	.pdev_qvit_cmdid = WMI_10X_PDEV_QVIT_CMDID, +	.pdev_ftm_intg_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_set_keepalive_cmdid = WMI_CMD_UNSUPPORTED, +	.vdev_get_keepalive_cmdid = WMI_CMD_UNSUPPORTED, +	.force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED, +	.gpio_config_cmdid = WMI_10X_GPIO_CONFIG_CMDID, +	.gpio_output_cmdid = WMI_10X_GPIO_OUTPUT_CMDID, +}; + +/* MAIN WMI VDEV param map */ +static struct wmi_vdev_param_map wmi_vdev_param_map = { +	.rts_threshold = WMI_VDEV_PARAM_RTS_THRESHOLD, +	.fragmentation_threshold = WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD, +	.beacon_interval = WMI_VDEV_PARAM_BEACON_INTERVAL, +	.listen_interval = WMI_VDEV_PARAM_LISTEN_INTERVAL, +	.multicast_rate = WMI_VDEV_PARAM_MULTICAST_RATE, +	.mgmt_tx_rate = WMI_VDEV_PARAM_MGMT_TX_RATE, +	.slot_time = WMI_VDEV_PARAM_SLOT_TIME, +	.preamble = WMI_VDEV_PARAM_PREAMBLE, +	.swba_time = WMI_VDEV_PARAM_SWBA_TIME, +	.wmi_vdev_stats_update_period = WMI_VDEV_STATS_UPDATE_PERIOD, +	.wmi_vdev_pwrsave_ageout_time = WMI_VDEV_PWRSAVE_AGEOUT_TIME, +	.wmi_vdev_host_swba_interval = WMI_VDEV_HOST_SWBA_INTERVAL, +	.dtim_period = WMI_VDEV_PARAM_DTIM_PERIOD, +	.wmi_vdev_oc_scheduler_air_time_limit = +					WMI_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT, +	.wds = WMI_VDEV_PARAM_WDS, +	.atim_window = WMI_VDEV_PARAM_ATIM_WINDOW, +	.bmiss_count_max = WMI_VDEV_PARAM_BMISS_COUNT_MAX, +	.bmiss_first_bcnt = WMI_VDEV_PARAM_BMISS_FIRST_BCNT, +	.bmiss_final_bcnt = WMI_VDEV_PARAM_BMISS_FINAL_BCNT, +	.feature_wmm = WMI_VDEV_PARAM_FEATURE_WMM, +	.chwidth = WMI_VDEV_PARAM_CHWIDTH, +	.chextoffset = WMI_VDEV_PARAM_CHEXTOFFSET, +	.disable_htprotection =	WMI_VDEV_PARAM_DISABLE_HTPROTECTION, +	.sta_quickkickout = WMI_VDEV_PARAM_STA_QUICKKICKOUT, +	.mgmt_rate = WMI_VDEV_PARAM_MGMT_RATE, +	.protection_mode = WMI_VDEV_PARAM_PROTECTION_MODE, +	.fixed_rate = WMI_VDEV_PARAM_FIXED_RATE, +	.sgi = WMI_VDEV_PARAM_SGI, +	.ldpc = WMI_VDEV_PARAM_LDPC, +	.tx_stbc = WMI_VDEV_PARAM_TX_STBC, +	.rx_stbc = WMI_VDEV_PARAM_RX_STBC, +	.intra_bss_fwd = WMI_VDEV_PARAM_INTRA_BSS_FWD, +	.def_keyid = WMI_VDEV_PARAM_DEF_KEYID, +	.nss = WMI_VDEV_PARAM_NSS, +	.bcast_data_rate = WMI_VDEV_PARAM_BCAST_DATA_RATE, +	.mcast_data_rate = WMI_VDEV_PARAM_MCAST_DATA_RATE, +	.mcast_indicate = WMI_VDEV_PARAM_MCAST_INDICATE, +	.dhcp_indicate = WMI_VDEV_PARAM_DHCP_INDICATE, +	.unknown_dest_indicate = WMI_VDEV_PARAM_UNKNOWN_DEST_INDICATE, +	.ap_keepalive_min_idle_inactive_time_secs = +			WMI_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, +	.ap_keepalive_max_idle_inactive_time_secs = +			WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, +	.ap_keepalive_max_unresponsive_time_secs = +			WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, +	.ap_enable_nawds = WMI_VDEV_PARAM_AP_ENABLE_NAWDS, +	.mcast2ucast_set = WMI_VDEV_PARAM_UNSUPPORTED, +	.enable_rtscts = WMI_VDEV_PARAM_ENABLE_RTSCTS, +	.txbf = WMI_VDEV_PARAM_TXBF, +	.packet_powersave = WMI_VDEV_PARAM_PACKET_POWERSAVE, +	.drop_unencry = WMI_VDEV_PARAM_DROP_UNENCRY, +	.tx_encap_type = WMI_VDEV_PARAM_TX_ENCAP_TYPE, +	.ap_detect_out_of_sync_sleeping_sta_time_secs = +					WMI_VDEV_PARAM_UNSUPPORTED, +}; + +/* 10.X WMI VDEV param map */ +static struct wmi_vdev_param_map wmi_10x_vdev_param_map = { +	.rts_threshold = WMI_10X_VDEV_PARAM_RTS_THRESHOLD, +	.fragmentation_threshold = WMI_10X_VDEV_PARAM_FRAGMENTATION_THRESHOLD, +	.beacon_interval = WMI_10X_VDEV_PARAM_BEACON_INTERVAL, +	.listen_interval = WMI_10X_VDEV_PARAM_LISTEN_INTERVAL, +	.multicast_rate = WMI_10X_VDEV_PARAM_MULTICAST_RATE, +	.mgmt_tx_rate = WMI_10X_VDEV_PARAM_MGMT_TX_RATE, +	.slot_time = WMI_10X_VDEV_PARAM_SLOT_TIME, +	.preamble = WMI_10X_VDEV_PARAM_PREAMBLE, +	.swba_time = WMI_10X_VDEV_PARAM_SWBA_TIME, +	.wmi_vdev_stats_update_period = WMI_10X_VDEV_STATS_UPDATE_PERIOD, +	.wmi_vdev_pwrsave_ageout_time = WMI_10X_VDEV_PWRSAVE_AGEOUT_TIME, +	.wmi_vdev_host_swba_interval = WMI_10X_VDEV_HOST_SWBA_INTERVAL, +	.dtim_period = WMI_10X_VDEV_PARAM_DTIM_PERIOD, +	.wmi_vdev_oc_scheduler_air_time_limit = +				WMI_10X_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT, +	.wds = WMI_10X_VDEV_PARAM_WDS, +	.atim_window = WMI_10X_VDEV_PARAM_ATIM_WINDOW, +	.bmiss_count_max = WMI_10X_VDEV_PARAM_BMISS_COUNT_MAX, +	.bmiss_first_bcnt = WMI_VDEV_PARAM_UNSUPPORTED, +	.bmiss_final_bcnt = WMI_VDEV_PARAM_UNSUPPORTED, +	.feature_wmm = WMI_10X_VDEV_PARAM_FEATURE_WMM, +	.chwidth = WMI_10X_VDEV_PARAM_CHWIDTH, +	.chextoffset = WMI_10X_VDEV_PARAM_CHEXTOFFSET, +	.disable_htprotection = WMI_10X_VDEV_PARAM_DISABLE_HTPROTECTION, +	.sta_quickkickout = WMI_10X_VDEV_PARAM_STA_QUICKKICKOUT, +	.mgmt_rate = WMI_10X_VDEV_PARAM_MGMT_RATE, +	.protection_mode = WMI_10X_VDEV_PARAM_PROTECTION_MODE, +	.fixed_rate = WMI_10X_VDEV_PARAM_FIXED_RATE, +	.sgi = WMI_10X_VDEV_PARAM_SGI, +	.ldpc = WMI_10X_VDEV_PARAM_LDPC, +	.tx_stbc = WMI_10X_VDEV_PARAM_TX_STBC, +	.rx_stbc = WMI_10X_VDEV_PARAM_RX_STBC, +	.intra_bss_fwd = WMI_10X_VDEV_PARAM_INTRA_BSS_FWD, +	.def_keyid = WMI_10X_VDEV_PARAM_DEF_KEYID, +	.nss = WMI_10X_VDEV_PARAM_NSS, +	.bcast_data_rate = WMI_10X_VDEV_PARAM_BCAST_DATA_RATE, +	.mcast_data_rate = WMI_10X_VDEV_PARAM_MCAST_DATA_RATE, +	.mcast_indicate = WMI_10X_VDEV_PARAM_MCAST_INDICATE, +	.dhcp_indicate = WMI_10X_VDEV_PARAM_DHCP_INDICATE, +	.unknown_dest_indicate = WMI_10X_VDEV_PARAM_UNKNOWN_DEST_INDICATE, +	.ap_keepalive_min_idle_inactive_time_secs = +		WMI_10X_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, +	.ap_keepalive_max_idle_inactive_time_secs = +		WMI_10X_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, +	.ap_keepalive_max_unresponsive_time_secs = +		WMI_10X_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, +	.ap_enable_nawds = WMI_10X_VDEV_PARAM_AP_ENABLE_NAWDS, +	.mcast2ucast_set = WMI_10X_VDEV_PARAM_MCAST2UCAST_SET, +	.enable_rtscts = WMI_10X_VDEV_PARAM_ENABLE_RTSCTS, +	.txbf = WMI_VDEV_PARAM_UNSUPPORTED, +	.packet_powersave = WMI_VDEV_PARAM_UNSUPPORTED, +	.drop_unencry = WMI_VDEV_PARAM_UNSUPPORTED, +	.tx_encap_type = WMI_VDEV_PARAM_UNSUPPORTED, +	.ap_detect_out_of_sync_sleeping_sta_time_secs = +		WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, +}; + +static struct wmi_pdev_param_map wmi_pdev_param_map = { +	.tx_chain_mask = WMI_PDEV_PARAM_TX_CHAIN_MASK, +	.rx_chain_mask = WMI_PDEV_PARAM_RX_CHAIN_MASK, +	.txpower_limit2g = WMI_PDEV_PARAM_TXPOWER_LIMIT2G, +	.txpower_limit5g = WMI_PDEV_PARAM_TXPOWER_LIMIT5G, +	.txpower_scale = WMI_PDEV_PARAM_TXPOWER_SCALE, +	.beacon_gen_mode = WMI_PDEV_PARAM_BEACON_GEN_MODE, +	.beacon_tx_mode = WMI_PDEV_PARAM_BEACON_TX_MODE, +	.resmgr_offchan_mode = WMI_PDEV_PARAM_RESMGR_OFFCHAN_MODE, +	.protection_mode = WMI_PDEV_PARAM_PROTECTION_MODE, +	.dynamic_bw = WMI_PDEV_PARAM_DYNAMIC_BW, +	.non_agg_sw_retry_th = WMI_PDEV_PARAM_NON_AGG_SW_RETRY_TH, +	.agg_sw_retry_th = WMI_PDEV_PARAM_AGG_SW_RETRY_TH, +	.sta_kickout_th = WMI_PDEV_PARAM_STA_KICKOUT_TH, +	.ac_aggrsize_scaling = WMI_PDEV_PARAM_AC_AGGRSIZE_SCALING, +	.ltr_enable = WMI_PDEV_PARAM_LTR_ENABLE, +	.ltr_ac_latency_be = WMI_PDEV_PARAM_LTR_AC_LATENCY_BE, +	.ltr_ac_latency_bk = WMI_PDEV_PARAM_LTR_AC_LATENCY_BK, +	.ltr_ac_latency_vi = WMI_PDEV_PARAM_LTR_AC_LATENCY_VI, +	.ltr_ac_latency_vo = WMI_PDEV_PARAM_LTR_AC_LATENCY_VO, +	.ltr_ac_latency_timeout = WMI_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT, +	.ltr_sleep_override = WMI_PDEV_PARAM_LTR_SLEEP_OVERRIDE, +	.ltr_rx_override = WMI_PDEV_PARAM_LTR_RX_OVERRIDE, +	.ltr_tx_activity_timeout = WMI_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT, +	.l1ss_enable = WMI_PDEV_PARAM_L1SS_ENABLE, +	.dsleep_enable = WMI_PDEV_PARAM_DSLEEP_ENABLE, +	.pcielp_txbuf_flush = WMI_PDEV_PARAM_PCIELP_TXBUF_FLUSH, +	.pcielp_txbuf_watermark = WMI_PDEV_PARAM_PCIELP_TXBUF_TMO_EN, +	.pcielp_txbuf_tmo_en = WMI_PDEV_PARAM_PCIELP_TXBUF_TMO_EN, +	.pcielp_txbuf_tmo_value = WMI_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE, +	.pdev_stats_update_period = WMI_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD, +	.vdev_stats_update_period = WMI_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD, +	.peer_stats_update_period = WMI_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD, +	.bcnflt_stats_update_period = WMI_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, +	.pmf_qos = WMI_PDEV_PARAM_PMF_QOS, +	.arp_ac_override = WMI_PDEV_PARAM_ARP_AC_OVERRIDE, +	.dcs = WMI_PDEV_PARAM_DCS, +	.ani_enable = WMI_PDEV_PARAM_ANI_ENABLE, +	.ani_poll_period = WMI_PDEV_PARAM_ANI_POLL_PERIOD, +	.ani_listen_period = WMI_PDEV_PARAM_ANI_LISTEN_PERIOD, +	.ani_ofdm_level = WMI_PDEV_PARAM_ANI_OFDM_LEVEL, +	.ani_cck_level = WMI_PDEV_PARAM_ANI_CCK_LEVEL, +	.dyntxchain = WMI_PDEV_PARAM_DYNTXCHAIN, +	.proxy_sta = WMI_PDEV_PARAM_PROXY_STA, +	.idle_ps_config = WMI_PDEV_PARAM_IDLE_PS_CONFIG, +	.power_gating_sleep = WMI_PDEV_PARAM_POWER_GATING_SLEEP, +	.fast_channel_reset = WMI_PDEV_PARAM_UNSUPPORTED, +	.burst_dur = WMI_PDEV_PARAM_UNSUPPORTED, +	.burst_enable = WMI_PDEV_PARAM_UNSUPPORTED, +}; + +static struct wmi_pdev_param_map wmi_10x_pdev_param_map = { +	.tx_chain_mask = WMI_10X_PDEV_PARAM_TX_CHAIN_MASK, +	.rx_chain_mask = WMI_10X_PDEV_PARAM_RX_CHAIN_MASK, +	.txpower_limit2g = WMI_10X_PDEV_PARAM_TXPOWER_LIMIT2G, +	.txpower_limit5g = WMI_10X_PDEV_PARAM_TXPOWER_LIMIT5G, +	.txpower_scale = WMI_10X_PDEV_PARAM_TXPOWER_SCALE, +	.beacon_gen_mode = WMI_10X_PDEV_PARAM_BEACON_GEN_MODE, +	.beacon_tx_mode = WMI_10X_PDEV_PARAM_BEACON_TX_MODE, +	.resmgr_offchan_mode = WMI_10X_PDEV_PARAM_RESMGR_OFFCHAN_MODE, +	.protection_mode = WMI_10X_PDEV_PARAM_PROTECTION_MODE, +	.dynamic_bw = WMI_10X_PDEV_PARAM_DYNAMIC_BW, +	.non_agg_sw_retry_th = WMI_10X_PDEV_PARAM_NON_AGG_SW_RETRY_TH, +	.agg_sw_retry_th = WMI_10X_PDEV_PARAM_AGG_SW_RETRY_TH, +	.sta_kickout_th = WMI_10X_PDEV_PARAM_STA_KICKOUT_TH, +	.ac_aggrsize_scaling = WMI_10X_PDEV_PARAM_AC_AGGRSIZE_SCALING, +	.ltr_enable = WMI_10X_PDEV_PARAM_LTR_ENABLE, +	.ltr_ac_latency_be = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_BE, +	.ltr_ac_latency_bk = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_BK, +	.ltr_ac_latency_vi = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_VI, +	.ltr_ac_latency_vo = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_VO, +	.ltr_ac_latency_timeout = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT, +	.ltr_sleep_override = WMI_10X_PDEV_PARAM_LTR_SLEEP_OVERRIDE, +	.ltr_rx_override = WMI_10X_PDEV_PARAM_LTR_RX_OVERRIDE, +	.ltr_tx_activity_timeout = WMI_10X_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT, +	.l1ss_enable = WMI_10X_PDEV_PARAM_L1SS_ENABLE, +	.dsleep_enable = WMI_10X_PDEV_PARAM_DSLEEP_ENABLE, +	.pcielp_txbuf_flush = WMI_PDEV_PARAM_UNSUPPORTED, +	.pcielp_txbuf_watermark = WMI_PDEV_PARAM_UNSUPPORTED, +	.pcielp_txbuf_tmo_en = WMI_PDEV_PARAM_UNSUPPORTED, +	.pcielp_txbuf_tmo_value = WMI_PDEV_PARAM_UNSUPPORTED, +	.pdev_stats_update_period = WMI_10X_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD, +	.vdev_stats_update_period = WMI_10X_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD, +	.peer_stats_update_period = WMI_10X_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD, +	.bcnflt_stats_update_period = +				WMI_10X_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, +	.pmf_qos = WMI_10X_PDEV_PARAM_PMF_QOS, +	.arp_ac_override = WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE, +	.dcs = WMI_10X_PDEV_PARAM_DCS, +	.ani_enable = WMI_10X_PDEV_PARAM_ANI_ENABLE, +	.ani_poll_period = WMI_10X_PDEV_PARAM_ANI_POLL_PERIOD, +	.ani_listen_period = WMI_10X_PDEV_PARAM_ANI_LISTEN_PERIOD, +	.ani_ofdm_level = WMI_10X_PDEV_PARAM_ANI_OFDM_LEVEL, +	.ani_cck_level = WMI_10X_PDEV_PARAM_ANI_CCK_LEVEL, +	.dyntxchain = WMI_10X_PDEV_PARAM_DYNTXCHAIN, +	.proxy_sta = WMI_PDEV_PARAM_UNSUPPORTED, +	.idle_ps_config = WMI_PDEV_PARAM_UNSUPPORTED, +	.power_gating_sleep = WMI_PDEV_PARAM_UNSUPPORTED, +	.fast_channel_reset = WMI_10X_PDEV_PARAM_FAST_CHANNEL_RESET, +	.burst_dur = WMI_10X_PDEV_PARAM_BURST_DUR, +	.burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE, +};  int ath10k_wmi_wait_for_service_ready(struct ath10k *ar)  { @@ -85,18 +525,14 @@ static struct sk_buff *ath10k_wmi_alloc_skb(u32 len)  static void ath10k_wmi_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)  {  	dev_kfree_skb(skb); - -	if (atomic_sub_return(1, &ar->wmi.pending_tx_count) == 0) -		wake_up(&ar->wmi.wq);  } -/* WMI command API */ -static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, -			       enum wmi_cmd_id cmd_id) +static int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb, +				      u32 cmd_id)  {  	struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);  	struct wmi_cmd_hdr *cmd_hdr; -	int status; +	int ret;  	u32 cmd = 0;  	if (skb_push(skb, sizeof(struct wmi_cmd_hdr)) == NULL) @@ -107,25 +543,151 @@ static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb,  	cmd_hdr = (struct wmi_cmd_hdr *)skb->data;  	cmd_hdr->cmd_id = __cpu_to_le32(cmd); -	if (atomic_add_return(1, &ar->wmi.pending_tx_count) > -	    WMI_MAX_PENDING_TX_COUNT) { -		/* avoid using up memory when FW hangs */ -		atomic_dec(&ar->wmi.pending_tx_count); -		return -EBUSY; +	memset(skb_cb, 0, sizeof(*skb_cb)); +	ret = ath10k_htc_send(&ar->htc, ar->wmi.eid, skb); +	trace_ath10k_wmi_cmd(cmd_id, skb->data, skb->len, ret); + +	if (ret) +		goto err_pull; + +	return 0; + +err_pull: +	skb_pull(skb, sizeof(struct wmi_cmd_hdr)); +	return ret; +} + +static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) +{ +	int ret; + +	lockdep_assert_held(&arvif->ar->data_lock); + +	if (arvif->beacon == NULL) +		return; + +	if (arvif->beacon_sent) +		return; + +	ret = ath10k_wmi_beacon_send_ref_nowait(arvif); +	if (ret) +		return; + +	/* We need to retain the arvif->beacon reference for DMA unmapping and +	 * freeing the skbuff later. */ +	arvif->beacon_sent = true; +} + +static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac, +				       struct ieee80211_vif *vif) +{ +	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); + +	ath10k_wmi_tx_beacon_nowait(arvif); +} + +static void ath10k_wmi_tx_beacons_nowait(struct ath10k *ar) +{ +	spin_lock_bh(&ar->data_lock); +	ieee80211_iterate_active_interfaces_atomic(ar->hw, +						   IEEE80211_IFACE_ITER_NORMAL, +						   ath10k_wmi_tx_beacons_iter, +						   NULL); +	spin_unlock_bh(&ar->data_lock); +} + +static void ath10k_wmi_op_ep_tx_credits(struct ath10k *ar) +{ +	/* try to send pending beacons first. they take priority */ +	ath10k_wmi_tx_beacons_nowait(ar); + +	wake_up(&ar->wmi.tx_credits_wq); +} + +static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, +			       u32 cmd_id) +{ +	int ret = -EOPNOTSUPP; + +	might_sleep(); + +	if (cmd_id == WMI_CMD_UNSUPPORTED) { +		ath10k_warn("wmi command %d is not supported by firmware\n", +			    cmd_id); +		return ret;  	} -	memset(skb_cb, 0, sizeof(*skb_cb)); +	wait_event_timeout(ar->wmi.tx_credits_wq, ({ +		/* try to send pending beacons first. they take priority */ +		ath10k_wmi_tx_beacons_nowait(ar); -	trace_ath10k_wmi_cmd(cmd_id, skb->data, skb->len); +		ret = ath10k_wmi_cmd_send_nowait(ar, skb, cmd_id); +		(ret != -EAGAIN); +	}), 3*HZ); -	status = ath10k_htc_send(&ar->htc, ar->wmi.eid, skb); -	if (status) { +	if (ret)  		dev_kfree_skb_any(skb); -		atomic_dec(&ar->wmi.pending_tx_count); -		return status; + +	return ret; +} + +int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb) +{ +	int ret = 0; +	struct wmi_mgmt_tx_cmd *cmd; +	struct ieee80211_hdr *hdr; +	struct sk_buff *wmi_skb; +	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); +	int len; +	u32 buf_len = skb->len; +	u16 fc; + +	hdr = (struct ieee80211_hdr *)skb->data; +	fc = le16_to_cpu(hdr->frame_control); + +	if (WARN_ON_ONCE(!ieee80211_is_mgmt(hdr->frame_control))) +		return -EINVAL; + +	len = sizeof(cmd->hdr) + skb->len; + +	if ((ieee80211_is_action(hdr->frame_control) || +	     ieee80211_is_deauth(hdr->frame_control) || +	     ieee80211_is_disassoc(hdr->frame_control)) && +	     ieee80211_has_protected(hdr->frame_control)) { +		len += IEEE80211_CCMP_MIC_LEN; +		buf_len += IEEE80211_CCMP_MIC_LEN;  	} -	return 0; +	len = round_up(len, 4); + +	wmi_skb = ath10k_wmi_alloc_skb(len); +	if (!wmi_skb) +		return -ENOMEM; + +	cmd = (struct wmi_mgmt_tx_cmd *)wmi_skb->data; + +	cmd->hdr.vdev_id = __cpu_to_le32(ATH10K_SKB_CB(skb)->vdev_id); +	cmd->hdr.tx_rate = 0; +	cmd->hdr.tx_power = 0; +	cmd->hdr.buf_len = __cpu_to_le32(buf_len); + +	memcpy(cmd->hdr.peer_macaddr.addr, ieee80211_get_DA(hdr), ETH_ALEN); +	memcpy(cmd->buf, skb->data, skb->len); + +	ath10k_dbg(ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n", +		   wmi_skb, wmi_skb->len, fc & IEEE80211_FCTL_FTYPE, +		   fc & IEEE80211_FCTL_STYPE); + +	/* Send the management frame buffer to the target */ +	ret = ath10k_wmi_cmd_send(ar, wmi_skb, ar->wmi.cmd->mgmt_tx_cmdid); +	if (ret) +		return ret; + +	/* TODO: report tx status to mac80211 - temporary just ACK */ +	info->flags |= IEEE80211_TX_STAT_ACK; +	ieee80211_tx_status_irqsafe(ar->hw, skb); + +	return ret;  }  static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) @@ -315,8 +877,11 @@ static inline u8 get_rate_idx(u32 rate, enum ieee80211_band band)  static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)  { -	struct wmi_mgmt_rx_event *event = (struct wmi_mgmt_rx_event *)skb->data; +	struct wmi_mgmt_rx_event_v1 *ev_v1; +	struct wmi_mgmt_rx_event_v2 *ev_v2; +	struct wmi_mgmt_rx_hdr_v1 *ev_hdr;  	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); +	struct ieee80211_channel *ch;  	struct ieee80211_hdr *hdr;  	u32 rx_status;  	u32 channel; @@ -325,19 +890,35 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)  	u32 rate;  	u32 buf_len;  	u16 fc; +	int pull_len; + +	if (test_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features)) { +		ev_v2 = (struct wmi_mgmt_rx_event_v2 *)skb->data; +		ev_hdr = &ev_v2->hdr.v1; +		pull_len = sizeof(*ev_v2); +	} else { +		ev_v1 = (struct wmi_mgmt_rx_event_v1 *)skb->data; +		ev_hdr = &ev_v1->hdr; +		pull_len = sizeof(*ev_v1); +	} -	channel   = __le32_to_cpu(event->hdr.channel); -	buf_len   = __le32_to_cpu(event->hdr.buf_len); -	rx_status = __le32_to_cpu(event->hdr.status); -	snr       = __le32_to_cpu(event->hdr.snr); -	phy_mode  = __le32_to_cpu(event->hdr.phy_mode); -	rate	  = __le32_to_cpu(event->hdr.rate); +	channel   = __le32_to_cpu(ev_hdr->channel); +	buf_len   = __le32_to_cpu(ev_hdr->buf_len); +	rx_status = __le32_to_cpu(ev_hdr->status); +	snr       = __le32_to_cpu(ev_hdr->snr); +	phy_mode  = __le32_to_cpu(ev_hdr->phy_mode); +	rate	  = __le32_to_cpu(ev_hdr->rate);  	memset(status, 0, sizeof(*status));  	ath10k_dbg(ATH10K_DBG_MGMT,  		   "event mgmt rx status %08x\n", rx_status); +	if (test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) { +		dev_kfree_skb(skb); +		return 0; +	} +  	if (rx_status & WMI_RX_STATUS_ERR_DECRYPT) {  		dev_kfree_skb(skb);  		return 0; @@ -353,21 +934,49 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)  	if (rx_status & WMI_RX_STATUS_ERR_MIC)  		status->flag |= RX_FLAG_MMIC_ERROR; -	status->band = phy_mode_to_band(phy_mode); +	/* HW can Rx CCK rates on 5GHz. In that case phy_mode is set to +	 * MODE_11B. This means phy_mode is not a reliable source for the band +	 * of mgmt rx. */ + +	ch = ar->scan_channel; +	if (!ch) +		ch = ar->rx_channel; + +	if (ch) { +		status->band = ch->band; + +		if (phy_mode == MODE_11B && +		    status->band == IEEE80211_BAND_5GHZ) +			ath10k_dbg(ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n"); +	} else { +		ath10k_warn("using (unreliable) phy_mode to extract band for mgmt rx\n"); +		status->band = phy_mode_to_band(phy_mode); +	} +  	status->freq = ieee80211_channel_to_frequency(channel, status->band);  	status->signal = snr + ATH10K_DEFAULT_NOISE_FLOOR;  	status->rate_idx = get_rate_idx(rate, status->band); -	skb_pull(skb, sizeof(event->hdr)); +	skb_pull(skb, pull_len);  	hdr = (struct ieee80211_hdr *)skb->data;  	fc = le16_to_cpu(hdr->frame_control); -	if (fc & IEEE80211_FCTL_PROTECTED) { -		status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED | -				RX_FLAG_MMIC_STRIPPED; -		hdr->frame_control = __cpu_to_le16(fc & +	/* FW delivers WEP Shared Auth frame with Protected Bit set and +	 * encrypted payload. However in case of PMF it delivers decrypted +	 * frames with Protected Bit set. */ +	if (ieee80211_has_protected(hdr->frame_control) && +	    !ieee80211_is_auth(hdr->frame_control)) { +		status->flag |= RX_FLAG_DECRYPTED; + +		if (!ieee80211_is_action(hdr->frame_control) && +		    !ieee80211_is_deauth(hdr->frame_control) && +		    !ieee80211_is_disassoc(hdr->frame_control)) { +			status->flag |= RX_FLAG_IV_STRIPPED | +					RX_FLAG_MMIC_STRIPPED; +			hdr->frame_control = __cpu_to_le16(fc &  					~IEEE80211_FCTL_PROTECTED); +		}  	}  	ath10k_dbg(ATH10K_DBG_MGMT, @@ -473,9 +1082,14 @@ static void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb)  	ath10k_dbg(ATH10K_DBG_WMI, "WMI_ECHO_EVENTID\n");  } -static void ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb) +static int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)  { -	ath10k_dbg(ATH10K_DBG_WMI, "WMI_DEBUG_MESG_EVENTID\n"); +	ath10k_dbg(ATH10K_DBG_WMI, "wmi event debug mesg len %d\n", +		   skb->len); + +	trace_ath10k_wmi_dbglog(skb->data, skb->len); + +	return 0;  }  static void ath10k_wmi_event_update_stats(struct ath10k *ar, @@ -513,7 +1127,27 @@ static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar,  static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar,  					      struct sk_buff *skb)  { -	ath10k_dbg(ATH10K_DBG_WMI, "WMI_PEER_STA_KICKOUT_EVENTID\n"); +	struct wmi_peer_sta_kickout_event *ev; +	struct ieee80211_sta *sta; + +	ev = (struct wmi_peer_sta_kickout_event *)skb->data; + +	ath10k_dbg(ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n", +		   ev->peer_macaddr.addr); + +	rcu_read_lock(); + +	sta = ieee80211_find_sta_by_ifaddr(ar->hw, ev->peer_macaddr.addr, NULL); +	if (!sta) { +		ath10k_warn("Spurious quick kickout for STA %pM\n", +			    ev->peer_macaddr.addr); +		goto exit; +	} + +	ieee80211_report_low_ack(sta, 10); + +exit: +	rcu_read_unlock();  }  /* @@ -614,6 +1248,13 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,  	tim->bitmap_ctrl = !!__le32_to_cpu(bcn_info->tim_info.tim_mcast);  	memcpy(tim->virtual_map, arvif->u.ap.tim_bitmap, pvm_len); +	if (tim->dtim_count == 0) { +		ATH10K_SKB_CB(bcn)->bcn.dtim_zero = true; + +		if (__le32_to_cpu(bcn_info->tim_info.tim_mcast) == 1) +			ATH10K_SKB_CB(bcn)->bcn.deliver_cab = true; +	} +  	ath10k_dbg(ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n",  		   tim->dtim_count, tim->dtim_period,  		   tim->bitmap_ctrl, pvm_len); @@ -734,18 +1375,13 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)  	int i = -1;  	struct wmi_bcn_info *bcn_info;  	struct ath10k_vif *arvif; -	struct wmi_bcn_tx_arg arg;  	struct sk_buff *bcn; -	int vdev_id = 0; -	int ret; - -	ath10k_dbg(ATH10K_DBG_MGMT, "WMI_HOST_SWBA_EVENTID\n"); +	int ret, vdev_id = 0;  	ev = (struct wmi_host_swba_event *)skb->data;  	map = __le32_to_cpu(ev->vdev_map); -	ath10k_dbg(ATH10K_DBG_MGMT, "host swba:\n" -		   "-vdev map 0x%x\n", +	ath10k_dbg(ATH10K_DBG_MGMT, "mgmt swba vdev_map 0x%x\n",  		   ev->vdev_map);  	for (; map; map >>= 1, vdev_id++) { @@ -762,12 +1398,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)  		bcn_info = &ev->bcn_info[i];  		ath10k_dbg(ATH10K_DBG_MGMT, -			   "-bcn_info[%d]:\n" -			   "--tim_len %d\n" -			   "--tim_mcast %d\n" -			   "--tim_changed %d\n" -			   "--tim_num_ps_pending %d\n" -			   "--tim_bitmap 0x%08x%08x%08x%08x\n", +			   "mgmt event bcn_info %d tim_len %d mcast %d changed %d num_ps_pending %d bitmap 0x%08x%08x%08x%08x\n",  			   i,  			   __le32_to_cpu(bcn_info->tim_info.tim_len),  			   __le32_to_cpu(bcn_info->tim_info.tim_mcast), @@ -784,6 +1415,17 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)  			continue;  		} +		/* There are no completions for beacons so wait for next SWBA +		 * before telling mac80211 to decrement CSA counter +		 * +		 * Once CSA counter is completed stop sending beacons until +		 * actual channel switch is done */ +		if (arvif->vif->csa_active && +		    ieee80211_csa_is_complete(arvif->vif)) { +			ieee80211_csa_finish(arvif->vif); +			continue; +		} +  		bcn = ieee80211_beacon_get(ar->hw, arvif->vif);  		if (!bcn) {  			ath10k_warn("could not get mac80211 beacon\n"); @@ -794,17 +1436,37 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)  		ath10k_wmi_update_tim(ar, arvif, bcn, bcn_info);  		ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info); -		arg.vdev_id = arvif->vdev_id; -		arg.tx_rate = 0; -		arg.tx_power = 0; -		arg.bcn = bcn->data; -		arg.bcn_len = bcn->len; +		spin_lock_bh(&ar->data_lock); -		ret = ath10k_wmi_beacon_send(ar, &arg); -		if (ret) -			ath10k_warn("could not send beacon (%d)\n", ret); +		if (arvif->beacon) { +			if (!arvif->beacon_sent) +				ath10k_warn("SWBA overrun on vdev %d\n", +					    arvif->vdev_id); -		dev_kfree_skb_any(bcn); +			dma_unmap_single(arvif->ar->dev, +					 ATH10K_SKB_CB(arvif->beacon)->paddr, +					 arvif->beacon->len, DMA_TO_DEVICE); +			dev_kfree_skb_any(arvif->beacon); +			arvif->beacon = NULL; +		} + +		ATH10K_SKB_CB(bcn)->paddr = dma_map_single(arvif->ar->dev, +							   bcn->data, bcn->len, +							   DMA_TO_DEVICE); +		ret = dma_mapping_error(arvif->ar->dev, +					ATH10K_SKB_CB(bcn)->paddr); +		if (ret) { +			ath10k_warn("failed to map beacon: %d\n", ret); +			dev_kfree_skb_any(bcn); +			goto skip; +		} + +		arvif->beacon = bcn; +		arvif->beacon_sent = false; + +		ath10k_wmi_tx_beacon_nowait(arvif); +skip: +		spin_unlock_bh(&ar->data_lock);  	}  } @@ -814,9 +1476,259 @@ static void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar,  	ath10k_dbg(ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n");  } +static void ath10k_dfs_radar_report(struct ath10k *ar, +				    struct wmi_single_phyerr_rx_event *event, +				    struct phyerr_radar_report *rr, +				    u64 tsf) +{ +	u32 reg0, reg1, tsf32l; +	struct pulse_event pe; +	u64 tsf64; +	u8 rssi, width; + +	reg0 = __le32_to_cpu(rr->reg0); +	reg1 = __le32_to_cpu(rr->reg1); + +	ath10k_dbg(ATH10K_DBG_REGULATORY, +		   "wmi phyerr radar report chirp %d max_width %d agc_total_gain %d pulse_delta_diff %d\n", +		   MS(reg0, RADAR_REPORT_REG0_PULSE_IS_CHIRP), +		   MS(reg0, RADAR_REPORT_REG0_PULSE_IS_MAX_WIDTH), +		   MS(reg0, RADAR_REPORT_REG0_AGC_TOTAL_GAIN), +		   MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_DIFF)); +	ath10k_dbg(ATH10K_DBG_REGULATORY, +		   "wmi phyerr radar report pulse_delta_pean %d pulse_sidx %d fft_valid %d agc_mb_gain %d subchan_mask %d\n", +		   MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_PEAK), +		   MS(reg0, RADAR_REPORT_REG0_PULSE_SIDX), +		   MS(reg1, RADAR_REPORT_REG1_PULSE_SRCH_FFT_VALID), +		   MS(reg1, RADAR_REPORT_REG1_PULSE_AGC_MB_GAIN), +		   MS(reg1, RADAR_REPORT_REG1_PULSE_SUBCHAN_MASK)); +	ath10k_dbg(ATH10K_DBG_REGULATORY, +		   "wmi phyerr radar report pulse_tsf_offset 0x%X pulse_dur: %d\n", +		   MS(reg1, RADAR_REPORT_REG1_PULSE_TSF_OFFSET), +		   MS(reg1, RADAR_REPORT_REG1_PULSE_DUR)); + +	if (!ar->dfs_detector) +		return; + +	/* report event to DFS pattern detector */ +	tsf32l = __le32_to_cpu(event->hdr.tsf_timestamp); +	tsf64 = tsf & (~0xFFFFFFFFULL); +	tsf64 |= tsf32l; + +	width = MS(reg1, RADAR_REPORT_REG1_PULSE_DUR); +	rssi = event->hdr.rssi_combined; + +	/* hardware store this as 8 bit signed value, +	 * set to zero if negative number +	 */ +	if (rssi & 0x80) +		rssi = 0; + +	pe.ts = tsf64; +	pe.freq = ar->hw->conf.chandef.chan->center_freq; +	pe.width = width; +	pe.rssi = rssi; + +	ath10k_dbg(ATH10K_DBG_REGULATORY, +		   "dfs add pulse freq: %d, width: %d, rssi %d, tsf: %llX\n", +		   pe.freq, pe.width, pe.rssi, pe.ts); + +	ATH10K_DFS_STAT_INC(ar, pulses_detected); + +	if (!ar->dfs_detector->add_pulse(ar->dfs_detector, &pe)) { +		ath10k_dbg(ATH10K_DBG_REGULATORY, +			   "dfs no pulse pattern detected, yet\n"); +		return; +	} + +	ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs radar detected\n"); +	ATH10K_DFS_STAT_INC(ar, radar_detected); + +	/* Control radar events reporting in debugfs file +	   dfs_block_radar_events */ +	if (ar->dfs_block_radar_events) { +		ath10k_info("DFS Radar detected, but ignored as requested\n"); +		return; +	} + +	ieee80211_radar_detected(ar->hw); +} + +static int ath10k_dfs_fft_report(struct ath10k *ar, +				 struct wmi_single_phyerr_rx_event *event, +				 struct phyerr_fft_report *fftr, +				 u64 tsf) +{ +	u32 reg0, reg1; +	u8 rssi, peak_mag; + +	reg0 = __le32_to_cpu(fftr->reg0); +	reg1 = __le32_to_cpu(fftr->reg1); +	rssi = event->hdr.rssi_combined; + +	ath10k_dbg(ATH10K_DBG_REGULATORY, +		   "wmi phyerr fft report total_gain_db %d base_pwr_db %d fft_chn_idx %d peak_sidx %d\n", +		   MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB), +		   MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB), +		   MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX), +		   MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX)); +	ath10k_dbg(ATH10K_DBG_REGULATORY, +		   "wmi phyerr fft report rel_pwr_db %d avgpwr_db %d peak_mag %d num_store_bin %d\n", +		   MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB), +		   MS(reg1, SEARCH_FFT_REPORT_REG1_AVGPWR_DB), +		   MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG), +		   MS(reg1, SEARCH_FFT_REPORT_REG1_NUM_STR_BINS_IB)); + +	peak_mag = MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG); + +	/* false event detection */ +	if (rssi == DFS_RSSI_POSSIBLY_FALSE && +	    peak_mag < 2 * DFS_PEAK_MAG_THOLD_POSSIBLY_FALSE) { +		ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs false pulse detected\n"); +		ATH10K_DFS_STAT_INC(ar, pulses_discarded); +		return -EINVAL; +	} + +	return 0; +} + +static void ath10k_wmi_event_dfs(struct ath10k *ar, +				 struct wmi_single_phyerr_rx_event *event, +				 u64 tsf) +{ +	int buf_len, tlv_len, res, i = 0; +	struct phyerr_tlv *tlv; +	struct phyerr_radar_report *rr; +	struct phyerr_fft_report *fftr; +	u8 *tlv_buf; + +	buf_len = __le32_to_cpu(event->hdr.buf_len); +	ath10k_dbg(ATH10K_DBG_REGULATORY, +		   "wmi event dfs err_code %d rssi %d tsfl 0x%X tsf64 0x%llX len %d\n", +		   event->hdr.phy_err_code, event->hdr.rssi_combined, +		   __le32_to_cpu(event->hdr.tsf_timestamp), tsf, buf_len); + +	/* Skip event if DFS disabled */ +	if (!config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) +		return; + +	ATH10K_DFS_STAT_INC(ar, pulses_total); + +	while (i < buf_len) { +		if (i + sizeof(*tlv) > buf_len) { +			ath10k_warn("too short buf for tlv header (%d)\n", i); +			return; +		} + +		tlv = (struct phyerr_tlv *)&event->bufp[i]; +		tlv_len = __le16_to_cpu(tlv->len); +		tlv_buf = &event->bufp[i + sizeof(*tlv)]; +		ath10k_dbg(ATH10K_DBG_REGULATORY, +			   "wmi event dfs tlv_len %d tlv_tag 0x%02X tlv_sig 0x%02X\n", +			   tlv_len, tlv->tag, tlv->sig); + +		switch (tlv->tag) { +		case PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY: +			if (i + sizeof(*tlv) + sizeof(*rr) > buf_len) { +				ath10k_warn("too short radar pulse summary (%d)\n", +					    i); +				return; +			} + +			rr = (struct phyerr_radar_report *)tlv_buf; +			ath10k_dfs_radar_report(ar, event, rr, tsf); +			break; +		case PHYERR_TLV_TAG_SEARCH_FFT_REPORT: +			if (i + sizeof(*tlv) + sizeof(*fftr) > buf_len) { +				ath10k_warn("too short fft report (%d)\n", i); +				return; +			} + +			fftr = (struct phyerr_fft_report *)tlv_buf; +			res = ath10k_dfs_fft_report(ar, event, fftr, tsf); +			if (res) +				return; +			break; +		} + +		i += sizeof(*tlv) + tlv_len; +	} +} + +static void ath10k_wmi_event_spectral_scan(struct ath10k *ar, +				struct wmi_single_phyerr_rx_event *event, +				u64 tsf) +{ +	ath10k_dbg(ATH10K_DBG_WMI, "wmi event spectral scan\n"); +} +  static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)  { -	ath10k_dbg(ATH10K_DBG_WMI, "WMI_PHYERR_EVENTID\n"); +	struct wmi_comb_phyerr_rx_event *comb_event; +	struct wmi_single_phyerr_rx_event *event; +	u32 count, i, buf_len, phy_err_code; +	u64 tsf; +	int left_len = skb->len; + +	ATH10K_DFS_STAT_INC(ar, phy_errors); + +	/* Check if combined event available */ +	if (left_len < sizeof(*comb_event)) { +		ath10k_warn("wmi phyerr combined event wrong len\n"); +		return; +	} + +	left_len -= sizeof(*comb_event); + +	/* Check number of included events */ +	comb_event = (struct wmi_comb_phyerr_rx_event *)skb->data; +	count = __le32_to_cpu(comb_event->hdr.num_phyerr_events); + +	tsf = __le32_to_cpu(comb_event->hdr.tsf_u32); +	tsf <<= 32; +	tsf |= __le32_to_cpu(comb_event->hdr.tsf_l32); + +	ath10k_dbg(ATH10K_DBG_WMI, +		   "wmi event phyerr count %d tsf64 0x%llX\n", +		   count, tsf); + +	event = (struct wmi_single_phyerr_rx_event *)comb_event->bufp; +	for (i = 0; i < count; i++) { +		/* Check if we can read event header */ +		if (left_len < sizeof(*event)) { +			ath10k_warn("single event (%d) wrong head len\n", i); +			return; +		} + +		left_len -= sizeof(*event); + +		buf_len = __le32_to_cpu(event->hdr.buf_len); +		phy_err_code = event->hdr.phy_err_code; + +		if (left_len < buf_len) { +			ath10k_warn("single event (%d) wrong buf len\n", i); +			return; +		} + +		left_len -= buf_len; + +		switch (phy_err_code) { +		case PHY_ERROR_RADAR: +			ath10k_wmi_event_dfs(ar, event, tsf); +			break; +		case PHY_ERROR_SPECTRAL_SCAN: +			ath10k_wmi_event_spectral_scan(ar, event, tsf); +			break; +		case PHY_ERROR_FALSE_RADAR_EXT: +			ath10k_wmi_event_dfs(ar, event, tsf); +			ath10k_wmi_event_spectral_scan(ar, event, tsf); +			break; +		default: +			break; +		} + +		event += sizeof(*event) + buf_len; +	}  }  static void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb) @@ -831,9 +1743,37 @@ static void ath10k_wmi_event_profile_match(struct ath10k *ar,  }  static void ath10k_wmi_event_debug_print(struct ath10k *ar, -				  struct sk_buff *skb) +					 struct sk_buff *skb)  { -	ath10k_dbg(ATH10K_DBG_WMI, "WMI_DEBUG_PRINT_EVENTID\n"); +	char buf[101], c; +	int i; + +	for (i = 0; i < sizeof(buf) - 1; i++) { +		if (i >= skb->len) +			break; + +		c = skb->data[i]; + +		if (c == '\0') +			break; + +		if (isascii(c) && isprint(c)) +			buf[i] = c; +		else +			buf[i] = '.'; +	} + +	if (i == sizeof(buf) - 1) +		ath10k_warn("wmi debug print truncated: %d\n", skb->len); + +	/* for some reason the debug prints end with \n, remove that */ +	if (skb->data[i - 1] == '\n') +		i--; + +	/* the last byte is always reserved for the null character */ +	buf[i] = '\0'; + +	ath10k_dbg(ATH10K_DBG_WMI, "wmi event debug print '%s'\n", buf);  }  static void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb) @@ -919,6 +1859,55 @@ static void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar,  	ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID\n");  } +static void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar, +					     struct sk_buff *skb) +{ +	ath10k_dbg(ATH10K_DBG_WMI, "WMI_INST_RSSI_STATS_EVENTID\n"); +} + +static void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar, +					      struct sk_buff *skb) +{ +	ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_STANDBY_REQ_EVENTID\n"); +} + +static void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, +					     struct sk_buff *skb) +{ +	ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n"); +} + +static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id, +				      u32 num_units, u32 unit_len) +{ +	dma_addr_t paddr; +	u32 pool_size; +	int idx = ar->wmi.num_mem_chunks; + +	pool_size = num_units * round_up(unit_len, 4); + +	if (!pool_size) +		return -EINVAL; + +	ar->wmi.mem_chunks[idx].vaddr = dma_alloc_coherent(ar->dev, +							   pool_size, +							   &paddr, +							   GFP_ATOMIC); +	if (!ar->wmi.mem_chunks[idx].vaddr) { +		ath10k_warn("failed to allocate memory chunk\n"); +		return -ENOMEM; +	} + +	memset(ar->wmi.mem_chunks[idx].vaddr, 0, pool_size); + +	ar->wmi.mem_chunks[idx].paddr = paddr; +	ar->wmi.mem_chunks[idx].len = pool_size; +	ar->wmi.mem_chunks[idx].req_id = req_id; +	ar->wmi.num_mem_chunks++; + +	return 0; +} +  static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,  					      struct sk_buff *skb)  { @@ -943,6 +1932,10 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,  	ar->phy_capability = __le32_to_cpu(ev->phy_capability);  	ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains); +	/* only manually set fw features when not using FW IE format */ +	if (ar->fw_api == 1 && ar->fw_version_build > 636) +		set_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features); +  	if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) {  		ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n",  			    ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM); @@ -987,6 +1980,108 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,  	complete(&ar->wmi.service_ready);  } +static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar, +						  struct sk_buff *skb) +{ +	u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i; +	int ret; +	struct wmi_service_ready_event_10x *ev = (void *)skb->data; + +	if (skb->len < sizeof(*ev)) { +		ath10k_warn("Service ready event was %d B but expected %zu B. Wrong firmware version?\n", +			    skb->len, sizeof(*ev)); +		return; +	} + +	ar->hw_min_tx_power = __le32_to_cpu(ev->hw_min_tx_power); +	ar->hw_max_tx_power = __le32_to_cpu(ev->hw_max_tx_power); +	ar->ht_cap_info = __le32_to_cpu(ev->ht_cap_info); +	ar->vht_cap_info = __le32_to_cpu(ev->vht_cap_info); +	ar->fw_version_major = +		(__le32_to_cpu(ev->sw_version) & 0xff000000) >> 24; +	ar->fw_version_minor = (__le32_to_cpu(ev->sw_version) & 0x00ffffff); +	ar->phy_capability = __le32_to_cpu(ev->phy_capability); +	ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains); + +	if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) { +		ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n", +			    ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM); +		ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM; +	} + +	ar->ath_common.regulatory.current_rd = +		__le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd); + +	ath10k_debug_read_service_map(ar, ev->wmi_service_bitmap, +				      sizeof(ev->wmi_service_bitmap)); + +	if (strlen(ar->hw->wiphy->fw_version) == 0) { +		snprintf(ar->hw->wiphy->fw_version, +			 sizeof(ar->hw->wiphy->fw_version), +			 "%u.%u", +			 ar->fw_version_major, +			 ar->fw_version_minor); +	} + +	num_mem_reqs = __le32_to_cpu(ev->num_mem_reqs); + +	if (num_mem_reqs > ATH10K_MAX_MEM_REQS) { +		ath10k_warn("requested memory chunks number (%d) exceeds the limit\n", +			    num_mem_reqs); +		return; +	} + +	if (!num_mem_reqs) +		goto exit; + +	ath10k_dbg(ATH10K_DBG_WMI, "firmware has requested %d memory chunks\n", +		   num_mem_reqs); + +	for (i = 0; i < num_mem_reqs; ++i) { +		req_id = __le32_to_cpu(ev->mem_reqs[i].req_id); +		num_units = __le32_to_cpu(ev->mem_reqs[i].num_units); +		unit_size = __le32_to_cpu(ev->mem_reqs[i].unit_size); +		num_unit_info = __le32_to_cpu(ev->mem_reqs[i].num_unit_info); + +		if (num_unit_info & NUM_UNITS_IS_NUM_PEERS) +			/* number of units to allocate is number of +			 * peers, 1 extra for self peer on target */ +			/* this needs to be tied, host and target +			 * can get out of sync */ +			num_units = TARGET_10X_NUM_PEERS + 1; +		else if (num_unit_info & NUM_UNITS_IS_NUM_VDEVS) +			num_units = TARGET_10X_NUM_VDEVS + 1; + +		ath10k_dbg(ATH10K_DBG_WMI, +			   "wmi mem_req_id %d num_units %d num_unit_info %d unit size %d actual units %d\n", +			   req_id, +			   __le32_to_cpu(ev->mem_reqs[i].num_units), +			   num_unit_info, +			   unit_size, +			   num_units); + +		ret = ath10k_wmi_alloc_host_mem(ar, req_id, num_units, +						unit_size); +		if (ret) +			return; +	} + +exit: +	ath10k_dbg(ATH10K_DBG_WMI, +		   "wmi event service ready sw_ver 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n", +		   __le32_to_cpu(ev->sw_version), +		   __le32_to_cpu(ev->abi_version), +		   __le32_to_cpu(ev->phy_capability), +		   __le32_to_cpu(ev->ht_cap_info), +		   __le32_to_cpu(ev->vht_cap_info), +		   __le32_to_cpu(ev->vht_supp_mcs), +		   __le32_to_cpu(ev->sys_cap_info), +		   __le32_to_cpu(ev->num_mem_reqs), +		   __le32_to_cpu(ev->num_rf_chains)); + +	complete(&ar->wmi.service_ready); +} +  static int ath10k_wmi_ready_event_rx(struct ath10k *ar, struct sk_buff *skb)  {  	struct wmi_ready_event *ev = (struct wmi_ready_event *)skb->data; @@ -997,17 +2092,17 @@ static int ath10k_wmi_ready_event_rx(struct ath10k *ar, struct sk_buff *skb)  	memcpy(ar->mac_addr, ev->mac_addr.addr, ETH_ALEN);  	ath10k_dbg(ATH10K_DBG_WMI, -		   "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d\n", +		   "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d skb->len %i ev-sz %zu\n",  		   __le32_to_cpu(ev->sw_version),  		   __le32_to_cpu(ev->abi_version),  		   ev->mac_addr.addr, -		   __le32_to_cpu(ev->status)); +		   __le32_to_cpu(ev->status), skb->len, sizeof(*ev));  	complete(&ar->wmi.unified_ready);  	return 0;  } -static void ath10k_wmi_event_process(struct ath10k *ar, struct sk_buff *skb) +static void ath10k_wmi_main_process_rx(struct ath10k *ar, struct sk_buff *skb)  {  	struct wmi_cmd_hdr *cmd_hdr;  	enum wmi_event_id id; @@ -1126,67 +2221,161 @@ static void ath10k_wmi_event_process(struct ath10k *ar, struct sk_buff *skb)  	dev_kfree_skb(skb);  } -static void ath10k_wmi_event_work(struct work_struct *work) +static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb)  { -	struct ath10k *ar = container_of(work, struct ath10k, -					 wmi.wmi_event_work); -	struct sk_buff *skb; +	struct wmi_cmd_hdr *cmd_hdr; +	enum wmi_10x_event_id id; +	u16 len; -	for (;;) { -		skb = skb_dequeue(&ar->wmi.wmi_event_list); -		if (!skb) -			break; +	cmd_hdr = (struct wmi_cmd_hdr *)skb->data; +	id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); -		ath10k_wmi_event_process(ar, skb); -	} -} +	if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) +		return; -static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb) -{ -	struct wmi_cmd_hdr *cmd_hdr = (struct wmi_cmd_hdr *)skb->data; -	enum wmi_event_id event_id; +	len = skb->len; -	event_id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); +	trace_ath10k_wmi_event(id, skb->data, skb->len); -	/* some events require to be handled ASAP -	 * thus can't be defered to a worker thread */ -	switch (event_id) { -	case WMI_HOST_SWBA_EVENTID: -	case WMI_MGMT_RX_EVENTID: -		ath10k_wmi_event_process(ar, skb); +	switch (id) { +	case WMI_10X_MGMT_RX_EVENTID: +		ath10k_wmi_event_mgmt_rx(ar, skb); +		/* mgmt_rx() owns the skb now! */  		return; +	case WMI_10X_SCAN_EVENTID: +		ath10k_wmi_event_scan(ar, skb); +		break; +	case WMI_10X_CHAN_INFO_EVENTID: +		ath10k_wmi_event_chan_info(ar, skb); +		break; +	case WMI_10X_ECHO_EVENTID: +		ath10k_wmi_event_echo(ar, skb); +		break; +	case WMI_10X_DEBUG_MESG_EVENTID: +		ath10k_wmi_event_debug_mesg(ar, skb); +		break; +	case WMI_10X_UPDATE_STATS_EVENTID: +		ath10k_wmi_event_update_stats(ar, skb); +		break; +	case WMI_10X_VDEV_START_RESP_EVENTID: +		ath10k_wmi_event_vdev_start_resp(ar, skb); +		break; +	case WMI_10X_VDEV_STOPPED_EVENTID: +		ath10k_wmi_event_vdev_stopped(ar, skb); +		break; +	case WMI_10X_PEER_STA_KICKOUT_EVENTID: +		ath10k_wmi_event_peer_sta_kickout(ar, skb); +		break; +	case WMI_10X_HOST_SWBA_EVENTID: +		ath10k_wmi_event_host_swba(ar, skb); +		break; +	case WMI_10X_TBTTOFFSET_UPDATE_EVENTID: +		ath10k_wmi_event_tbttoffset_update(ar, skb); +		break; +	case WMI_10X_PHYERR_EVENTID: +		ath10k_wmi_event_phyerr(ar, skb); +		break; +	case WMI_10X_ROAM_EVENTID: +		ath10k_wmi_event_roam(ar, skb); +		break; +	case WMI_10X_PROFILE_MATCH: +		ath10k_wmi_event_profile_match(ar, skb); +		break; +	case WMI_10X_DEBUG_PRINT_EVENTID: +		ath10k_wmi_event_debug_print(ar, skb); +		break; +	case WMI_10X_PDEV_QVIT_EVENTID: +		ath10k_wmi_event_pdev_qvit(ar, skb); +		break; +	case WMI_10X_WLAN_PROFILE_DATA_EVENTID: +		ath10k_wmi_event_wlan_profile_data(ar, skb); +		break; +	case WMI_10X_RTT_MEASUREMENT_REPORT_EVENTID: +		ath10k_wmi_event_rtt_measurement_report(ar, skb); +		break; +	case WMI_10X_TSF_MEASUREMENT_REPORT_EVENTID: +		ath10k_wmi_event_tsf_measurement_report(ar, skb); +		break; +	case WMI_10X_RTT_ERROR_REPORT_EVENTID: +		ath10k_wmi_event_rtt_error_report(ar, skb); +		break; +	case WMI_10X_WOW_WAKEUP_HOST_EVENTID: +		ath10k_wmi_event_wow_wakeup_host(ar, skb); +		break; +	case WMI_10X_DCS_INTERFERENCE_EVENTID: +		ath10k_wmi_event_dcs_interference(ar, skb); +		break; +	case WMI_10X_PDEV_TPC_CONFIG_EVENTID: +		ath10k_wmi_event_pdev_tpc_config(ar, skb); +		break; +	case WMI_10X_INST_RSSI_STATS_EVENTID: +		ath10k_wmi_event_inst_rssi_stats(ar, skb); +		break; +	case WMI_10X_VDEV_STANDBY_REQ_EVENTID: +		ath10k_wmi_event_vdev_standby_req(ar, skb); +		break; +	case WMI_10X_VDEV_RESUME_REQ_EVENTID: +		ath10k_wmi_event_vdev_resume_req(ar, skb); +		break; +	case WMI_10X_SERVICE_READY_EVENTID: +		ath10k_wmi_10x_service_ready_event_rx(ar, skb); +		break; +	case WMI_10X_READY_EVENTID: +		ath10k_wmi_ready_event_rx(ar, skb); +		break;  	default: +		ath10k_warn("Unknown eventid: %d\n", id);  		break;  	} -	skb_queue_tail(&ar->wmi.wmi_event_list, skb); -	queue_work(ar->workqueue, &ar->wmi.wmi_event_work); +	dev_kfree_skb(skb); +} + + +static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb) +{ +	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) +		ath10k_wmi_10x_process_rx(ar, skb); +	else +		ath10k_wmi_main_process_rx(ar, skb);  }  /* WMI Initialization functions */  int ath10k_wmi_attach(struct ath10k *ar)  { +	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { +		ar->wmi.cmd = &wmi_10x_cmd_map; +		ar->wmi.vdev_param = &wmi_10x_vdev_param_map; +		ar->wmi.pdev_param = &wmi_10x_pdev_param_map; +	} else { +		ar->wmi.cmd = &wmi_cmd_map; +		ar->wmi.vdev_param = &wmi_vdev_param_map; +		ar->wmi.pdev_param = &wmi_pdev_param_map; +	} +  	init_completion(&ar->wmi.service_ready);  	init_completion(&ar->wmi.unified_ready); -	init_waitqueue_head(&ar->wmi.wq); - -	skb_queue_head_init(&ar->wmi.wmi_event_list); -	INIT_WORK(&ar->wmi.wmi_event_work, ath10k_wmi_event_work); +	init_waitqueue_head(&ar->wmi.tx_credits_wq);  	return 0;  }  void ath10k_wmi_detach(struct ath10k *ar)  { -	/* HTC should've drained the packets already */ -	if (WARN_ON(atomic_read(&ar->wmi.pending_tx_count) > 0)) -		ath10k_warn("there are still pending packets\n"); +	int i; + +	/* free the host memory chunks requested by firmware */ +	for (i = 0; i < ar->wmi.num_mem_chunks; i++) { +		dma_free_coherent(ar->dev, +				  ar->wmi.mem_chunks[i].len, +				  ar->wmi.mem_chunks[i].vaddr, +				  ar->wmi.mem_chunks[i].paddr); +	} -	cancel_work_sync(&ar->wmi.wmi_event_work); -	skb_queue_purge(&ar->wmi.wmi_event_list); +	ar->wmi.num_mem_chunks = 0;  } -int ath10k_wmi_connect_htc_service(struct ath10k *ar) +int ath10k_wmi_connect(struct ath10k *ar)  {  	int status;  	struct ath10k_htc_svc_conn_req conn_req; @@ -1198,6 +2387,7 @@ int ath10k_wmi_connect_htc_service(struct ath10k *ar)  	/* these fields are the same for all service endpoints */  	conn_req.ep_ops.ep_tx_complete = ath10k_wmi_htc_tx_complete;  	conn_req.ep_ops.ep_rx_complete = ath10k_wmi_process_rx; +	conn_req.ep_ops.ep_tx_credits = ath10k_wmi_op_ep_tx_credits;  	/* connect to control service */  	conn_req.service_id = ATH10K_HTC_SVC_ID_WMI_CONTROL; @@ -1213,8 +2403,9 @@ int ath10k_wmi_connect_htc_service(struct ath10k *ar)  	return 0;  } -int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, -				  u16 rd5g, u16 ctl2g, u16 ctl5g) +static int ath10k_wmi_main_pdev_set_regdomain(struct ath10k *ar, u16 rd, +					      u16 rd2g, u16 rd5g, u16 ctl2g, +					      u16 ctl5g)  {  	struct wmi_pdev_set_regdomain_cmd *cmd;  	struct sk_buff *skb; @@ -1234,7 +2425,48 @@ int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,  		   "wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x\n",  		   rd, rd2g, rd5g, ctl2g, ctl5g); -	return ath10k_wmi_cmd_send(ar, skb, WMI_PDEV_SET_REGDOMAIN_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, +				   ar->wmi.cmd->pdev_set_regdomain_cmdid); +} + +static int ath10k_wmi_10x_pdev_set_regdomain(struct ath10k *ar, u16 rd, +					     u16 rd2g, u16 rd5g, +					     u16 ctl2g, u16 ctl5g, +					     enum wmi_dfs_region dfs_reg) +{ +	struct wmi_pdev_set_regdomain_cmd_10x *cmd; +	struct sk_buff *skb; + +	skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +	if (!skb) +		return -ENOMEM; + +	cmd = (struct wmi_pdev_set_regdomain_cmd_10x *)skb->data; +	cmd->reg_domain = __cpu_to_le32(rd); +	cmd->reg_domain_2G = __cpu_to_le32(rd2g); +	cmd->reg_domain_5G = __cpu_to_le32(rd5g); +	cmd->conformance_test_limit_2G = __cpu_to_le32(ctl2g); +	cmd->conformance_test_limit_5G = __cpu_to_le32(ctl5g); +	cmd->dfs_domain = __cpu_to_le32(dfs_reg); + +	ath10k_dbg(ATH10K_DBG_WMI, +		   "wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x dfs_region %x\n", +		   rd, rd2g, rd5g, ctl2g, ctl5g, dfs_reg); + +	return ath10k_wmi_cmd_send(ar, skb, +				   ar->wmi.cmd->pdev_set_regdomain_cmdid); +} + +int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, +				  u16 rd5g, u16 ctl2g, u16 ctl5g, +				  enum wmi_dfs_region dfs_reg) +{ +	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) +		return ath10k_wmi_10x_pdev_set_regdomain(ar, rd, rd2g, rd5g, +							ctl2g, ctl5g, dfs_reg); +	else +		return ath10k_wmi_main_pdev_set_regdomain(ar, rd, rd2g, rd5g, +							 ctl2g, ctl5g);  }  int ath10k_wmi_pdev_set_channel(struct ath10k *ar, @@ -1242,6 +2474,7 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar,  {  	struct wmi_set_channel_cmd *cmd;  	struct sk_buff *skb; +	u32 ch_flags = 0;  	if (arg->passive)  		return -EINVAL; @@ -1250,10 +2483,14 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar,  	if (!skb)  		return -ENOMEM; +	if (arg->chan_radar) +		ch_flags |= WMI_CHAN_FLAG_DFS; +  	cmd = (struct wmi_set_channel_cmd *)skb->data;  	cmd->chan.mhz               = __cpu_to_le32(arg->freq);  	cmd->chan.band_center_freq1 = __cpu_to_le32(arg->freq);  	cmd->chan.mode              = arg->mode; +	cmd->chan.flags		   |= __cpu_to_le32(ch_flags);  	cmd->chan.min_power         = arg->min_power;  	cmd->chan.max_power         = arg->max_power;  	cmd->chan.reg_power         = arg->max_reg_power; @@ -1264,10 +2501,11 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar,  		   "wmi set channel mode %d freq %d\n",  		   arg->mode, arg->freq); -	return ath10k_wmi_cmd_send(ar, skb, WMI_PDEV_SET_CHANNEL_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, +				   ar->wmi.cmd->pdev_set_channel_cmdid);  } -int ath10k_wmi_pdev_suspend_target(struct ath10k *ar) +int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt)  {  	struct wmi_pdev_suspend_cmd *cmd;  	struct sk_buff *skb; @@ -1277,9 +2515,9 @@ int ath10k_wmi_pdev_suspend_target(struct ath10k *ar)  		return -ENOMEM;  	cmd = (struct wmi_pdev_suspend_cmd *)skb->data; -	cmd->suspend_opt = WMI_PDEV_SUSPEND; +	cmd->suspend_opt = __cpu_to_le32(suspend_opt); -	return ath10k_wmi_cmd_send(ar, skb, WMI_PDEV_SUSPEND_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_suspend_cmdid);  }  int ath10k_wmi_pdev_resume_target(struct ath10k *ar) @@ -1290,15 +2528,19 @@ int ath10k_wmi_pdev_resume_target(struct ath10k *ar)  	if (skb == NULL)  		return -ENOMEM; -	return ath10k_wmi_cmd_send(ar, skb, WMI_PDEV_RESUME_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_resume_cmdid);  } -int ath10k_wmi_pdev_set_param(struct ath10k *ar, enum wmi_pdev_param id, -			      u32 value) +int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value)  {  	struct wmi_pdev_set_param_cmd *cmd;  	struct sk_buff *skb; +	if (id == WMI_PDEV_PARAM_UNSUPPORTED) { +		ath10k_warn("pdev param %d not supported by firmware\n", id); +		return -EOPNOTSUPP; +	} +  	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));  	if (!skb)  		return -ENOMEM; @@ -1309,15 +2551,16 @@ int ath10k_wmi_pdev_set_param(struct ath10k *ar, enum wmi_pdev_param id,  	ath10k_dbg(ATH10K_DBG_WMI, "wmi pdev set param %d value %d\n",  		   id, value); -	return ath10k_wmi_cmd_send(ar, skb, WMI_PDEV_SET_PARAM_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_set_param_cmdid);  } -int ath10k_wmi_cmd_init(struct ath10k *ar) +static int ath10k_wmi_main_cmd_init(struct ath10k *ar)  {  	struct wmi_init_cmd *cmd;  	struct sk_buff *buf;  	struct wmi_resource_config config = {}; -	u32 val; +	u32 len, val; +	int i;  	config.num_vdevs = __cpu_to_le32(TARGET_NUM_VDEVS);  	config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS + TARGET_NUM_VDEVS); @@ -1370,23 +2613,158 @@ int ath10k_wmi_cmd_init(struct ath10k *ar)  	config.num_msdu_desc = __cpu_to_le32(TARGET_NUM_MSDU_DESC);  	config.max_frag_entries = __cpu_to_le32(TARGET_MAX_FRAG_ENTRIES); -	buf = ath10k_wmi_alloc_skb(sizeof(*cmd)); +	len = sizeof(*cmd) + +	      (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks); + +	buf = ath10k_wmi_alloc_skb(len);  	if (!buf)  		return -ENOMEM;  	cmd = (struct wmi_init_cmd *)buf->data; -	cmd->num_host_mem_chunks = 0; + +	if (ar->wmi.num_mem_chunks == 0) { +		cmd->num_host_mem_chunks = 0; +		goto out; +	} + +	ath10k_dbg(ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n", +		   ar->wmi.num_mem_chunks); + +	cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks); + +	for (i = 0; i < ar->wmi.num_mem_chunks; i++) { +		cmd->host_mem_chunks[i].ptr = +			__cpu_to_le32(ar->wmi.mem_chunks[i].paddr); +		cmd->host_mem_chunks[i].size = +			__cpu_to_le32(ar->wmi.mem_chunks[i].len); +		cmd->host_mem_chunks[i].req_id = +			__cpu_to_le32(ar->wmi.mem_chunks[i].req_id); + +		ath10k_dbg(ATH10K_DBG_WMI, +			   "wmi chunk %d len %d requested, addr 0x%llx\n", +			   i, +			   ar->wmi.mem_chunks[i].len, +			   (unsigned long long)ar->wmi.mem_chunks[i].paddr); +	} +out:  	memcpy(&cmd->resource_config, &config, sizeof(config));  	ath10k_dbg(ATH10K_DBG_WMI, "wmi init\n"); -	return ath10k_wmi_cmd_send(ar, buf, WMI_INIT_CMDID); +	return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid); +} + +static int ath10k_wmi_10x_cmd_init(struct ath10k *ar) +{ +	struct wmi_init_cmd_10x *cmd; +	struct sk_buff *buf; +	struct wmi_resource_config_10x config = {}; +	u32 len, val; +	int i; + +	config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS); +	config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS); +	config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS); +	config.num_tids = __cpu_to_le32(TARGET_10X_NUM_TIDS); +	config.ast_skid_limit = __cpu_to_le32(TARGET_10X_AST_SKID_LIMIT); +	config.tx_chain_mask = __cpu_to_le32(TARGET_10X_TX_CHAIN_MASK); +	config.rx_chain_mask = __cpu_to_le32(TARGET_10X_RX_CHAIN_MASK); +	config.rx_timeout_pri_vo = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI); +	config.rx_timeout_pri_vi = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI); +	config.rx_timeout_pri_be = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI); +	config.rx_timeout_pri_bk = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_HI_PRI); +	config.rx_decap_mode = __cpu_to_le32(TARGET_10X_RX_DECAP_MODE); + +	config.scan_max_pending_reqs = +		__cpu_to_le32(TARGET_10X_SCAN_MAX_PENDING_REQS); + +	config.bmiss_offload_max_vdev = +		__cpu_to_le32(TARGET_10X_BMISS_OFFLOAD_MAX_VDEV); + +	config.roam_offload_max_vdev = +		__cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_VDEV); + +	config.roam_offload_max_ap_profiles = +		__cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_AP_PROFILES); + +	config.num_mcast_groups = __cpu_to_le32(TARGET_10X_NUM_MCAST_GROUPS); +	config.num_mcast_table_elems = +		__cpu_to_le32(TARGET_10X_NUM_MCAST_TABLE_ELEMS); + +	config.mcast2ucast_mode = __cpu_to_le32(TARGET_10X_MCAST2UCAST_MODE); +	config.tx_dbg_log_size = __cpu_to_le32(TARGET_10X_TX_DBG_LOG_SIZE); +	config.num_wds_entries = __cpu_to_le32(TARGET_10X_NUM_WDS_ENTRIES); +	config.dma_burst_size = __cpu_to_le32(TARGET_10X_DMA_BURST_SIZE); +	config.mac_aggr_delim = __cpu_to_le32(TARGET_10X_MAC_AGGR_DELIM); + +	val = TARGET_10X_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK; +	config.rx_skip_defrag_timeout_dup_detection_check = __cpu_to_le32(val); + +	config.vow_config = __cpu_to_le32(TARGET_10X_VOW_CONFIG); + +	config.num_msdu_desc = __cpu_to_le32(TARGET_10X_NUM_MSDU_DESC); +	config.max_frag_entries = __cpu_to_le32(TARGET_10X_MAX_FRAG_ENTRIES); + +	len = sizeof(*cmd) + +	      (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks); + +	buf = ath10k_wmi_alloc_skb(len); +	if (!buf) +		return -ENOMEM; + +	cmd = (struct wmi_init_cmd_10x *)buf->data; + +	if (ar->wmi.num_mem_chunks == 0) { +		cmd->num_host_mem_chunks = 0; +		goto out; +	} + +	ath10k_dbg(ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n", +		   ar->wmi.num_mem_chunks); + +	cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks); + +	for (i = 0; i < ar->wmi.num_mem_chunks; i++) { +		cmd->host_mem_chunks[i].ptr = +			__cpu_to_le32(ar->wmi.mem_chunks[i].paddr); +		cmd->host_mem_chunks[i].size = +			__cpu_to_le32(ar->wmi.mem_chunks[i].len); +		cmd->host_mem_chunks[i].req_id = +			__cpu_to_le32(ar->wmi.mem_chunks[i].req_id); + +		ath10k_dbg(ATH10K_DBG_WMI, +			   "wmi chunk %d len %d requested, addr 0x%llx\n", +			   i, +			   ar->wmi.mem_chunks[i].len, +			   (unsigned long long)ar->wmi.mem_chunks[i].paddr); +	} +out: +	memcpy(&cmd->resource_config, &config, sizeof(config)); + +	ath10k_dbg(ATH10K_DBG_WMI, "wmi init 10x\n"); +	return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);  } -static int ath10k_wmi_start_scan_calc_len(const struct wmi_start_scan_arg *arg) +int ath10k_wmi_cmd_init(struct ath10k *ar) +{ +	int ret; + +	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) +		ret = ath10k_wmi_10x_cmd_init(ar); +	else +		ret = ath10k_wmi_main_cmd_init(ar); + +	return ret; +} + +static int ath10k_wmi_start_scan_calc_len(struct ath10k *ar, +					  const struct wmi_start_scan_arg *arg)  {  	int len; -	len = sizeof(struct wmi_start_scan_cmd); +	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) +		len = sizeof(struct wmi_start_scan_cmd_10x); +	else +		len = sizeof(struct wmi_start_scan_cmd);  	if (arg->ie_len) {  		if (!arg->ie) @@ -1446,7 +2824,7 @@ int ath10k_wmi_start_scan(struct ath10k *ar,  	int len = 0;  	int i; -	len = ath10k_wmi_start_scan_calc_len(arg); +	len = ath10k_wmi_start_scan_calc_len(ar, arg);  	if (len < 0)  		return len; /* len contains error code here */ @@ -1478,7 +2856,14 @@ int ath10k_wmi_start_scan(struct ath10k *ar,  	cmd->scan_ctrl_flags    = __cpu_to_le32(arg->scan_ctrl_flags);  	/* TLV list starts after fields included in the struct */ -	off = sizeof(*cmd); +	/* There's just one filed that differes the two start_scan +	 * structures - burst_duration, which we are not using btw, +	   no point to make the split here, just shift the buffer to fit with +	   given FW */ +	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) +		off = sizeof(struct wmi_start_scan_cmd_10x); +	else +		off = sizeof(struct wmi_start_scan_cmd);  	if (arg->n_channels) {  		channels = (void *)skb->data + off; @@ -1540,7 +2925,7 @@ int ath10k_wmi_start_scan(struct ath10k *ar,  	}  	ath10k_dbg(ATH10K_DBG_WMI, "wmi start scan\n"); -	return ath10k_wmi_cmd_send(ar, skb, WMI_START_SCAN_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->start_scan_cmdid);  }  void ath10k_wmi_start_scan_init(struct ath10k *ar, @@ -1556,7 +2941,7 @@ void ath10k_wmi_start_scan_init(struct ath10k *ar,  	arg->repeat_probe_time = 0;  	arg->probe_spacing_time = 0;  	arg->idle_time = 0; -	arg->max_scan_time = 5000; +	arg->max_scan_time = 20000;  	arg->probe_delay = 5;  	arg->notify_scan_events = WMI_SCAN_EVENT_STARTED  		| WMI_SCAN_EVENT_COMPLETED @@ -1600,7 +2985,7 @@ int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg)  	ath10k_dbg(ATH10K_DBG_WMI,  		   "wmi stop scan reqid %d req_type %d vdev/scan_id %d\n",  		   arg->req_id, arg->req_type, arg->u.scan_id); -	return ath10k_wmi_cmd_send(ar, skb, WMI_STOP_SCAN_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->stop_scan_cmdid);  }  int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id, @@ -1625,7 +3010,7 @@ int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id,  		   "WMI vdev create: id %d type %d subtype %d macaddr %pM\n",  		   vdev_id, type, subtype, macaddr); -	return ath10k_wmi_cmd_send(ar, skb, WMI_VDEV_CREATE_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_create_cmdid);  }  int ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id) @@ -1643,20 +3028,21 @@ int ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id)  	ath10k_dbg(ATH10K_DBG_WMI,  		   "WMI vdev delete id %d\n", vdev_id); -	return ath10k_wmi_cmd_send(ar, skb, WMI_VDEV_DELETE_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_delete_cmdid);  }  static int ath10k_wmi_vdev_start_restart(struct ath10k *ar,  				const struct wmi_vdev_start_request_arg *arg, -				enum wmi_cmd_id cmd_id) +				u32 cmd_id)  {  	struct wmi_vdev_start_request_cmd *cmd;  	struct sk_buff *skb;  	const char *cmdname;  	u32 flags = 0; +	u32 ch_flags = 0; -	if (cmd_id != WMI_VDEV_START_REQUEST_CMDID && -	    cmd_id != WMI_VDEV_RESTART_REQUEST_CMDID) +	if (cmd_id != ar->wmi.cmd->vdev_start_request_cmdid && +	    cmd_id != ar->wmi.cmd->vdev_restart_request_cmdid)  		return -EINVAL;  	if (WARN_ON(arg->ssid && arg->ssid_len == 0))  		return -EINVAL; @@ -1665,9 +3051,9 @@ static int ath10k_wmi_vdev_start_restart(struct ath10k *ar,  	if (WARN_ON(arg->ssid_len > sizeof(cmd->ssid.ssid)))  		return -EINVAL; -	if (cmd_id == WMI_VDEV_START_REQUEST_CMDID) +	if (cmd_id == ar->wmi.cmd->vdev_start_request_cmdid)  		cmdname = "start"; -	else if (cmd_id == WMI_VDEV_RESTART_REQUEST_CMDID) +	else if (cmd_id == ar->wmi.cmd->vdev_restart_request_cmdid)  		cmdname = "restart";  	else  		return -EINVAL; /* should not happen, we already check cmd_id */ @@ -1680,6 +3066,8 @@ static int ath10k_wmi_vdev_start_restart(struct ath10k *ar,  		flags |= WMI_VDEV_START_HIDDEN_SSID;  	if (arg->pmf_enabled)  		flags |= WMI_VDEV_START_PMF_ENABLED; +	if (arg->channel.chan_radar) +		ch_flags |= WMI_CHAN_FLAG_DFS;  	cmd = (struct wmi_vdev_start_request_cmd *)skb->data;  	cmd->vdev_id         = __cpu_to_le32(arg->vdev_id); @@ -1701,6 +3089,7 @@ static int ath10k_wmi_vdev_start_restart(struct ath10k *ar,  		__cpu_to_le32(arg->channel.band_center_freq1);  	cmd->chan.mode = arg->channel.mode; +	cmd->chan.flags |= __cpu_to_le32(ch_flags);  	cmd->chan.min_power = arg->channel.min_power;  	cmd->chan.max_power = arg->channel.max_power;  	cmd->chan.reg_power = arg->channel.max_reg_power; @@ -1708,9 +3097,10 @@ static int ath10k_wmi_vdev_start_restart(struct ath10k *ar,  	cmd->chan.antenna_max = arg->channel.max_antenna_gain;  	ath10k_dbg(ATH10K_DBG_WMI, -		   "wmi vdev %s id 0x%x freq %d, mode %d, ch_flags: 0x%0X," -		   "max_power: %d\n", cmdname, arg->vdev_id, arg->channel.freq, -		   arg->channel.mode, flags, arg->channel.max_power); +		   "wmi vdev %s id 0x%x flags: 0x%0X, freq %d, mode %d, " +		   "ch_flags: 0x%0X, max_power: %d\n", cmdname, arg->vdev_id, +		   flags, arg->channel.freq, arg->channel.mode, +		   cmd->chan.flags, arg->channel.max_power);  	return ath10k_wmi_cmd_send(ar, skb, cmd_id);  } @@ -1718,15 +3108,17 @@ static int ath10k_wmi_vdev_start_restart(struct ath10k *ar,  int ath10k_wmi_vdev_start(struct ath10k *ar,  			  const struct wmi_vdev_start_request_arg *arg)  { -	return ath10k_wmi_vdev_start_restart(ar, arg, -					     WMI_VDEV_START_REQUEST_CMDID); +	u32 cmd_id = ar->wmi.cmd->vdev_start_request_cmdid; + +	return ath10k_wmi_vdev_start_restart(ar, arg, cmd_id);  }  int ath10k_wmi_vdev_restart(struct ath10k *ar,  		     const struct wmi_vdev_start_request_arg *arg)  { -	return ath10k_wmi_vdev_start_restart(ar, arg, -					     WMI_VDEV_RESTART_REQUEST_CMDID); +	u32 cmd_id = ar->wmi.cmd->vdev_restart_request_cmdid; + +	return ath10k_wmi_vdev_start_restart(ar, arg, cmd_id);  }  int ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id) @@ -1743,7 +3135,7 @@ int ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id)  	ath10k_dbg(ATH10K_DBG_WMI, "wmi vdev stop id 0x%x\n", vdev_id); -	return ath10k_wmi_cmd_send(ar, skb, WMI_VDEV_STOP_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_stop_cmdid);  }  int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid) @@ -1758,13 +3150,13 @@ int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid)  	cmd = (struct wmi_vdev_up_cmd *)skb->data;  	cmd->vdev_id       = __cpu_to_le32(vdev_id);  	cmd->vdev_assoc_id = __cpu_to_le32(aid); -	memcpy(&cmd->vdev_bssid.addr, bssid, 6); +	memcpy(&cmd->vdev_bssid.addr, bssid, ETH_ALEN);  	ath10k_dbg(ATH10K_DBG_WMI,  		   "wmi mgmt vdev up id 0x%x assoc id %d bssid %pM\n",  		   vdev_id, aid, bssid); -	return ath10k_wmi_cmd_send(ar, skb, WMI_VDEV_UP_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_up_cmdid);  }  int ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id) @@ -1782,15 +3174,22 @@ int ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id)  	ath10k_dbg(ATH10K_DBG_WMI,  		   "wmi mgmt vdev down id 0x%x\n", vdev_id); -	return ath10k_wmi_cmd_send(ar, skb, WMI_VDEV_DOWN_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_down_cmdid);  }  int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id, -			      enum wmi_vdev_param param_id, u32 param_value) +			      u32 param_id, u32 param_value)  {  	struct wmi_vdev_set_param_cmd *cmd;  	struct sk_buff *skb; +	if (param_id == WMI_VDEV_PARAM_UNSUPPORTED) { +		ath10k_dbg(ATH10K_DBG_WMI, +			   "vdev param %d not supported by firmware\n", +			    param_id); +		return -EOPNOTSUPP; +	} +  	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));  	if (!skb)  		return -ENOMEM; @@ -1804,7 +3203,7 @@ int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id,  		   "wmi vdev id 0x%x set param %d value %d\n",  		   vdev_id, param_id, param_value); -	return ath10k_wmi_cmd_send(ar, skb, WMI_VDEV_SET_PARAM_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_set_param_cmdid);  }  int ath10k_wmi_vdev_install_key(struct ath10k *ar, @@ -1839,7 +3238,8 @@ int ath10k_wmi_vdev_install_key(struct ath10k *ar,  	ath10k_dbg(ATH10K_DBG_WMI,  		   "wmi vdev install key idx %d cipher %d len %d\n",  		   arg->key_idx, arg->key_cipher, arg->key_len); -	return ath10k_wmi_cmd_send(ar, skb, WMI_VDEV_INSTALL_KEY_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, +				   ar->wmi.cmd->vdev_install_key_cmdid);  }  int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id, @@ -1859,7 +3259,7 @@ int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,  	ath10k_dbg(ATH10K_DBG_WMI,  		   "wmi peer create vdev_id %d peer_addr %pM\n",  		   vdev_id, peer_addr); -	return ath10k_wmi_cmd_send(ar, skb, WMI_PEER_CREATE_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_create_cmdid);  }  int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id, @@ -1879,7 +3279,7 @@ int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id,  	ath10k_dbg(ATH10K_DBG_WMI,  		   "wmi peer delete vdev_id %d peer_addr %pM\n",  		   vdev_id, peer_addr); -	return ath10k_wmi_cmd_send(ar, skb, WMI_PEER_DELETE_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_delete_cmdid);  }  int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id, @@ -1900,7 +3300,7 @@ int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id,  	ath10k_dbg(ATH10K_DBG_WMI,  		   "wmi peer flush vdev_id %d peer_addr %pM tids %08x\n",  		   vdev_id, peer_addr, tid_bitmap); -	return ath10k_wmi_cmd_send(ar, skb, WMI_PEER_FLUSH_TIDS_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_flush_tids_cmdid);  }  int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id, @@ -1918,13 +3318,13 @@ int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id,  	cmd->vdev_id     = __cpu_to_le32(vdev_id);  	cmd->param_id    = __cpu_to_le32(param_id);  	cmd->param_value = __cpu_to_le32(param_value); -	memcpy(&cmd->peer_macaddr.addr, peer_addr, 6); +	memcpy(&cmd->peer_macaddr.addr, peer_addr, ETH_ALEN);  	ath10k_dbg(ATH10K_DBG_WMI,  		   "wmi vdev %d peer 0x%pM set param %d value %d\n",  		   vdev_id, peer_addr, param_id, param_value); -	return ath10k_wmi_cmd_send(ar, skb, WMI_PEER_SET_PARAM_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_set_param_cmdid);  }  int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id, @@ -1945,7 +3345,8 @@ int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id,  		   "wmi set powersave id 0x%x mode %d\n",  		   vdev_id, psmode); -	return ath10k_wmi_cmd_send(ar, skb, WMI_STA_POWERSAVE_MODE_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, +				   ar->wmi.cmd->sta_powersave_mode_cmdid);  }  int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id, @@ -1967,7 +3368,8 @@ int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id,  	ath10k_dbg(ATH10K_DBG_WMI,  		   "wmi sta ps param vdev_id 0x%x param %d value %d\n",  		   vdev_id, param_id, value); -	return ath10k_wmi_cmd_send(ar, skb, WMI_STA_POWERSAVE_PARAM_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, +				   ar->wmi.cmd->sta_powersave_param_cmdid);  }  int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac, @@ -1993,7 +3395,8 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,  		   "wmi ap ps param vdev_id 0x%X param %d value %d mac_addr %pM\n",  		   vdev_id, param_id, value, mac); -	return ath10k_wmi_cmd_send(ar, skb, WMI_AP_PS_PEER_PARAM_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, +				   ar->wmi.cmd->ap_ps_peer_param_cmdid);  }  int ath10k_wmi_scan_chan_list(struct ath10k *ar, @@ -2031,6 +3434,8 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar,  			flags |= WMI_CHAN_FLAG_ALLOW_VHT;  		if (ch->ht40plus)  			flags |= WMI_CHAN_FLAG_HT40_PLUS; +		if (ch->chan_radar) +			flags |= WMI_CHAN_FLAG_DFS;  		ci->mhz               = __cpu_to_le32(ch->freq);  		ci->band_center_freq1 = __cpu_to_le32(ch->freq); @@ -2039,14 +3444,13 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar,  		ci->max_power         = ch->max_power;  		ci->reg_power         = ch->max_reg_power;  		ci->antenna_max       = ch->max_antenna_gain; -		ci->antenna_max       = 0;  		/* mode & flags share storage */  		ci->mode              = ch->mode;  		ci->flags            |= __cpu_to_le32(flags);  	} -	return ath10k_wmi_cmd_send(ar, skb, WMI_SCAN_CHAN_LIST_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid);  }  int ath10k_wmi_peer_assoc(struct ath10k *ar, @@ -2103,28 +3507,51 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar,  		__cpu_to_le32(arg->peer_vht_rates.tx_mcs_set);  	ath10k_dbg(ATH10K_DBG_WMI, -		   "wmi peer assoc vdev %d addr %pM\n", -		   arg->vdev_id, arg->addr); -	return ath10k_wmi_cmd_send(ar, skb, WMI_PEER_ASSOC_CMDID); +		   "wmi peer assoc vdev %d addr %pM (%s)\n", +		   arg->vdev_id, arg->addr, +		   arg->peer_reassoc ? "reassociate" : "new"); +	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid);  } -int ath10k_wmi_beacon_send(struct ath10k *ar, const struct wmi_bcn_tx_arg *arg) +/* This function assumes the beacon is already DMA mapped */ +int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif)  { -	struct wmi_bcn_tx_cmd *cmd; +	struct wmi_bcn_tx_ref_cmd *cmd;  	struct sk_buff *skb; +	struct sk_buff *beacon = arvif->beacon; +	struct ath10k *ar = arvif->ar; +	struct ieee80211_hdr *hdr; +	int ret; +	u16 fc; -	skb = ath10k_wmi_alloc_skb(sizeof(*cmd) + arg->bcn_len); +	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));  	if (!skb)  		return -ENOMEM; -	cmd = (struct wmi_bcn_tx_cmd *)skb->data; -	cmd->hdr.vdev_id  = __cpu_to_le32(arg->vdev_id); -	cmd->hdr.tx_rate  = __cpu_to_le32(arg->tx_rate); -	cmd->hdr.tx_power = __cpu_to_le32(arg->tx_power); -	cmd->hdr.bcn_len  = __cpu_to_le32(arg->bcn_len); -	memcpy(cmd->bcn, arg->bcn, arg->bcn_len); +	hdr = (struct ieee80211_hdr *)beacon->data; +	fc = le16_to_cpu(hdr->frame_control); -	return ath10k_wmi_cmd_send(ar, skb, WMI_BCN_TX_CMDID); +	cmd = (struct wmi_bcn_tx_ref_cmd *)skb->data; +	cmd->vdev_id = __cpu_to_le32(arvif->vdev_id); +	cmd->data_len = __cpu_to_le32(beacon->len); +	cmd->data_ptr = __cpu_to_le32(ATH10K_SKB_CB(beacon)->paddr); +	cmd->msdu_id = 0; +	cmd->frame_control = __cpu_to_le32(fc); +	cmd->flags = 0; + +	if (ATH10K_SKB_CB(beacon)->bcn.dtim_zero) +		cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO); + +	if (ATH10K_SKB_CB(beacon)->bcn.deliver_cab) +		cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DELIVER_CAB); + +	ret = ath10k_wmi_cmd_send_nowait(ar, skb, +					 ar->wmi.cmd->pdev_send_bcn_cmdid); + +	if (ret) +		dev_kfree_skb(skb); + +	return ret;  }  static void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params, @@ -2155,7 +3582,8 @@ int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,  	ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vo, &arg->ac_vo);  	ath10k_dbg(ATH10K_DBG_WMI, "wmi pdev set wmm params\n"); -	return ath10k_wmi_cmd_send(ar, skb, WMI_PDEV_SET_WMM_PARAMS_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, +				   ar->wmi.cmd->pdev_set_wmm_params_cmdid);  }  int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id) @@ -2171,7 +3599,7 @@ int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id)  	cmd->stats_id = __cpu_to_le32(stats_id);  	ath10k_dbg(ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id); -	return ath10k_wmi_cmd_send(ar, skb, WMI_REQUEST_STATS_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_stats_cmdid);  }  int ath10k_wmi_force_fw_hang(struct ath10k *ar, @@ -2190,5 +3618,42 @@ int ath10k_wmi_force_fw_hang(struct ath10k *ar,  	ath10k_dbg(ATH10K_DBG_WMI, "wmi force fw hang %d delay %d\n",  		   type, delay_ms); -	return ath10k_wmi_cmd_send(ar, skb, WMI_FORCE_FW_HANG_CMDID); +	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid); +} + +int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable) +{ +	struct wmi_dbglog_cfg_cmd *cmd; +	struct sk_buff *skb; +	u32 cfg; + +	skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); +	if (!skb) +		return -ENOMEM; + +	cmd = (struct wmi_dbglog_cfg_cmd *)skb->data; + +	if (module_enable) { +		cfg = SM(ATH10K_DBGLOG_LEVEL_VERBOSE, +			 ATH10K_DBGLOG_CFG_LOG_LVL); +	} else { +		/* set back defaults, all modules with WARN level */ +		cfg = SM(ATH10K_DBGLOG_LEVEL_WARN, +			 ATH10K_DBGLOG_CFG_LOG_LVL); +		module_enable = ~0; +	} + +	cmd->module_enable = __cpu_to_le32(module_enable); +	cmd->module_valid = __cpu_to_le32(~0); +	cmd->config_enable = __cpu_to_le32(cfg); +	cmd->config_valid = __cpu_to_le32(ATH10K_DBGLOG_CFG_LOG_LVL_MASK); + +	ath10k_dbg(ATH10K_DBG_WMI, +		   "wmi dbglog cfg modules %08x %08x config %08x %08x\n", +		   __le32_to_cpu(cmd->module_enable), +		   __le32_to_cpu(cmd->module_valid), +		   __le32_to_cpu(cmd->config_enable), +		   __le32_to_cpu(cmd->config_valid)); + +	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->dbglog_cfg_cmdid);  } diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 2c5a4f8daf2..e93df2c1041 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -198,15 +198,117 @@ struct wmi_mac_addr {  	} __packed;  } __packed; -/* macro to convert MAC address from WMI word format to char array */ -#define WMI_MAC_ADDR_TO_CHAR_ARRAY(pwmi_mac_addr, c_macaddr) do { \ -	(c_macaddr)[0] =  ((pwmi_mac_addr)->word0) & 0xff; \ -	(c_macaddr)[1] = (((pwmi_mac_addr)->word0) >> 8) & 0xff; \ -	(c_macaddr)[2] = (((pwmi_mac_addr)->word0) >> 16) & 0xff; \ -	(c_macaddr)[3] = (((pwmi_mac_addr)->word0) >> 24) & 0xff; \ -	(c_macaddr)[4] =  ((pwmi_mac_addr)->word1) & 0xff; \ -	(c_macaddr)[5] = (((pwmi_mac_addr)->word1) >> 8) & 0xff; \ -	} while (0) +struct wmi_cmd_map { +	u32 init_cmdid; +	u32 start_scan_cmdid; +	u32 stop_scan_cmdid; +	u32 scan_chan_list_cmdid; +	u32 scan_sch_prio_tbl_cmdid; +	u32 pdev_set_regdomain_cmdid; +	u32 pdev_set_channel_cmdid; +	u32 pdev_set_param_cmdid; +	u32 pdev_pktlog_enable_cmdid; +	u32 pdev_pktlog_disable_cmdid; +	u32 pdev_set_wmm_params_cmdid; +	u32 pdev_set_ht_cap_ie_cmdid; +	u32 pdev_set_vht_cap_ie_cmdid; +	u32 pdev_set_dscp_tid_map_cmdid; +	u32 pdev_set_quiet_mode_cmdid; +	u32 pdev_green_ap_ps_enable_cmdid; +	u32 pdev_get_tpc_config_cmdid; +	u32 pdev_set_base_macaddr_cmdid; +	u32 vdev_create_cmdid; +	u32 vdev_delete_cmdid; +	u32 vdev_start_request_cmdid; +	u32 vdev_restart_request_cmdid; +	u32 vdev_up_cmdid; +	u32 vdev_stop_cmdid; +	u32 vdev_down_cmdid; +	u32 vdev_set_param_cmdid; +	u32 vdev_install_key_cmdid; +	u32 peer_create_cmdid; +	u32 peer_delete_cmdid; +	u32 peer_flush_tids_cmdid; +	u32 peer_set_param_cmdid; +	u32 peer_assoc_cmdid; +	u32 peer_add_wds_entry_cmdid; +	u32 peer_remove_wds_entry_cmdid; +	u32 peer_mcast_group_cmdid; +	u32 bcn_tx_cmdid; +	u32 pdev_send_bcn_cmdid; +	u32 bcn_tmpl_cmdid; +	u32 bcn_filter_rx_cmdid; +	u32 prb_req_filter_rx_cmdid; +	u32 mgmt_tx_cmdid; +	u32 prb_tmpl_cmdid; +	u32 addba_clear_resp_cmdid; +	u32 addba_send_cmdid; +	u32 addba_status_cmdid; +	u32 delba_send_cmdid; +	u32 addba_set_resp_cmdid; +	u32 send_singleamsdu_cmdid; +	u32 sta_powersave_mode_cmdid; +	u32 sta_powersave_param_cmdid; +	u32 sta_mimo_ps_mode_cmdid; +	u32 pdev_dfs_enable_cmdid; +	u32 pdev_dfs_disable_cmdid; +	u32 roam_scan_mode; +	u32 roam_scan_rssi_threshold; +	u32 roam_scan_period; +	u32 roam_scan_rssi_change_threshold; +	u32 roam_ap_profile; +	u32 ofl_scan_add_ap_profile; +	u32 ofl_scan_remove_ap_profile; +	u32 ofl_scan_period; +	u32 p2p_dev_set_device_info; +	u32 p2p_dev_set_discoverability; +	u32 p2p_go_set_beacon_ie; +	u32 p2p_go_set_probe_resp_ie; +	u32 p2p_set_vendor_ie_data_cmdid; +	u32 ap_ps_peer_param_cmdid; +	u32 ap_ps_peer_uapsd_coex_cmdid; +	u32 peer_rate_retry_sched_cmdid; +	u32 wlan_profile_trigger_cmdid; +	u32 wlan_profile_set_hist_intvl_cmdid; +	u32 wlan_profile_get_profile_data_cmdid; +	u32 wlan_profile_enable_profile_id_cmdid; +	u32 wlan_profile_list_profile_id_cmdid; +	u32 pdev_suspend_cmdid; +	u32 pdev_resume_cmdid; +	u32 add_bcn_filter_cmdid; +	u32 rmv_bcn_filter_cmdid; +	u32 wow_add_wake_pattern_cmdid; +	u32 wow_del_wake_pattern_cmdid; +	u32 wow_enable_disable_wake_event_cmdid; +	u32 wow_enable_cmdid; +	u32 wow_hostwakeup_from_sleep_cmdid; +	u32 rtt_measreq_cmdid; +	u32 rtt_tsf_cmdid; +	u32 vdev_spectral_scan_configure_cmdid; +	u32 vdev_spectral_scan_enable_cmdid; +	u32 request_stats_cmdid; +	u32 set_arp_ns_offload_cmdid; +	u32 network_list_offload_config_cmdid; +	u32 gtk_offload_cmdid; +	u32 csa_offload_enable_cmdid; +	u32 csa_offload_chanswitch_cmdid; +	u32 chatter_set_mode_cmdid; +	u32 peer_tid_addba_cmdid; +	u32 peer_tid_delba_cmdid; +	u32 sta_dtim_ps_method_cmdid; +	u32 sta_uapsd_auto_trig_cmdid; +	u32 sta_keepalive_cmd; +	u32 echo_cmdid; +	u32 pdev_utf_cmdid; +	u32 dbglog_cfg_cmdid; +	u32 pdev_qvit_cmdid; +	u32 pdev_ftm_intg_cmdid; +	u32 vdev_set_keepalive_cmdid; +	u32 vdev_get_keepalive_cmdid; +	u32 force_fw_hang_cmdid; +	u32 gpio_config_cmdid; +	u32 gpio_output_cmdid; +};  /*   * wmi command groups. @@ -247,7 +349,9 @@ enum wmi_cmd_group {  #define WMI_CMD_GRP(grp_id) (((grp_id) << 12) | 0x1)  #define WMI_EVT_GRP_START_ID(grp_id) (((grp_id) << 12) | 0x1) -/* Command IDs and commande events. */ +#define WMI_CMD_UNSUPPORTED 0 + +/* Command IDs and command events for MAIN FW. */  enum wmi_cmd_id {  	WMI_INIT_CMDID = 0x1, @@ -488,6 +592,217 @@ enum wmi_event_id {  	WMI_GPIO_INPUT_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_GPIO),  }; +/* Command IDs and command events for 10.X firmware */ +enum wmi_10x_cmd_id { +	WMI_10X_START_CMDID = 0x9000, +	WMI_10X_END_CMDID = 0x9FFF, + +	/* initialize the wlan sub system */ +	WMI_10X_INIT_CMDID, + +	/* Scan specific commands */ + +	WMI_10X_START_SCAN_CMDID = WMI_10X_START_CMDID, +	WMI_10X_STOP_SCAN_CMDID, +	WMI_10X_SCAN_CHAN_LIST_CMDID, +	WMI_10X_ECHO_CMDID, + +	/* PDEV(physical device) specific commands */ +	WMI_10X_PDEV_SET_REGDOMAIN_CMDID, +	WMI_10X_PDEV_SET_CHANNEL_CMDID, +	WMI_10X_PDEV_SET_PARAM_CMDID, +	WMI_10X_PDEV_PKTLOG_ENABLE_CMDID, +	WMI_10X_PDEV_PKTLOG_DISABLE_CMDID, +	WMI_10X_PDEV_SET_WMM_PARAMS_CMDID, +	WMI_10X_PDEV_SET_HT_CAP_IE_CMDID, +	WMI_10X_PDEV_SET_VHT_CAP_IE_CMDID, +	WMI_10X_PDEV_SET_BASE_MACADDR_CMDID, +	WMI_10X_PDEV_SET_DSCP_TID_MAP_CMDID, +	WMI_10X_PDEV_SET_QUIET_MODE_CMDID, +	WMI_10X_PDEV_GREEN_AP_PS_ENABLE_CMDID, +	WMI_10X_PDEV_GET_TPC_CONFIG_CMDID, + +	/* VDEV(virtual device) specific commands */ +	WMI_10X_VDEV_CREATE_CMDID, +	WMI_10X_VDEV_DELETE_CMDID, +	WMI_10X_VDEV_START_REQUEST_CMDID, +	WMI_10X_VDEV_RESTART_REQUEST_CMDID, +	WMI_10X_VDEV_UP_CMDID, +	WMI_10X_VDEV_STOP_CMDID, +	WMI_10X_VDEV_DOWN_CMDID, +	WMI_10X_VDEV_STANDBY_RESPONSE_CMDID, +	WMI_10X_VDEV_RESUME_RESPONSE_CMDID, +	WMI_10X_VDEV_SET_PARAM_CMDID, +	WMI_10X_VDEV_INSTALL_KEY_CMDID, + +	/* peer specific commands */ +	WMI_10X_PEER_CREATE_CMDID, +	WMI_10X_PEER_DELETE_CMDID, +	WMI_10X_PEER_FLUSH_TIDS_CMDID, +	WMI_10X_PEER_SET_PARAM_CMDID, +	WMI_10X_PEER_ASSOC_CMDID, +	WMI_10X_PEER_ADD_WDS_ENTRY_CMDID, +	WMI_10X_PEER_REMOVE_WDS_ENTRY_CMDID, +	WMI_10X_PEER_MCAST_GROUP_CMDID, + +	/* beacon/management specific commands */ + +	WMI_10X_BCN_TX_CMDID, +	WMI_10X_BCN_PRB_TMPL_CMDID, +	WMI_10X_BCN_FILTER_RX_CMDID, +	WMI_10X_PRB_REQ_FILTER_RX_CMDID, +	WMI_10X_MGMT_TX_CMDID, + +	/* commands to directly control ba negotiation directly from host. */ +	WMI_10X_ADDBA_CLEAR_RESP_CMDID, +	WMI_10X_ADDBA_SEND_CMDID, +	WMI_10X_ADDBA_STATUS_CMDID, +	WMI_10X_DELBA_SEND_CMDID, +	WMI_10X_ADDBA_SET_RESP_CMDID, +	WMI_10X_SEND_SINGLEAMSDU_CMDID, + +	/* Station power save specific config */ +	WMI_10X_STA_POWERSAVE_MODE_CMDID, +	WMI_10X_STA_POWERSAVE_PARAM_CMDID, +	WMI_10X_STA_MIMO_PS_MODE_CMDID, + +	/* set debug log config */ +	WMI_10X_DBGLOG_CFG_CMDID, + +	/* DFS-specific commands */ +	WMI_10X_PDEV_DFS_ENABLE_CMDID, +	WMI_10X_PDEV_DFS_DISABLE_CMDID, + +	/* QVIT specific command id */ +	WMI_10X_PDEV_QVIT_CMDID, + +	/* Offload Scan and Roaming related  commands */ +	WMI_10X_ROAM_SCAN_MODE, +	WMI_10X_ROAM_SCAN_RSSI_THRESHOLD, +	WMI_10X_ROAM_SCAN_PERIOD, +	WMI_10X_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, +	WMI_10X_ROAM_AP_PROFILE, +	WMI_10X_OFL_SCAN_ADD_AP_PROFILE, +	WMI_10X_OFL_SCAN_REMOVE_AP_PROFILE, +	WMI_10X_OFL_SCAN_PERIOD, + +	/* P2P specific commands */ +	WMI_10X_P2P_DEV_SET_DEVICE_INFO, +	WMI_10X_P2P_DEV_SET_DISCOVERABILITY, +	WMI_10X_P2P_GO_SET_BEACON_IE, +	WMI_10X_P2P_GO_SET_PROBE_RESP_IE, + +	/* AP power save specific config */ +	WMI_10X_AP_PS_PEER_PARAM_CMDID, +	WMI_10X_AP_PS_PEER_UAPSD_COEX_CMDID, + +	/* Rate-control specific commands */ +	WMI_10X_PEER_RATE_RETRY_SCHED_CMDID, + +	/* WLAN Profiling commands. */ +	WMI_10X_WLAN_PROFILE_TRIGGER_CMDID, +	WMI_10X_WLAN_PROFILE_SET_HIST_INTVL_CMDID, +	WMI_10X_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, +	WMI_10X_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, +	WMI_10X_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, + +	/* Suspend resume command Ids */ +	WMI_10X_PDEV_SUSPEND_CMDID, +	WMI_10X_PDEV_RESUME_CMDID, + +	/* Beacon filter commands */ +	WMI_10X_ADD_BCN_FILTER_CMDID, +	WMI_10X_RMV_BCN_FILTER_CMDID, + +	/* WOW Specific WMI commands*/ +	WMI_10X_WOW_ADD_WAKE_PATTERN_CMDID, +	WMI_10X_WOW_DEL_WAKE_PATTERN_CMDID, +	WMI_10X_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, +	WMI_10X_WOW_ENABLE_CMDID, +	WMI_10X_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, + +	/* RTT measurement related cmd */ +	WMI_10X_RTT_MEASREQ_CMDID, +	WMI_10X_RTT_TSF_CMDID, + +	/* transmit beacon by value */ +	WMI_10X_PDEV_SEND_BCN_CMDID, + +	/* F/W stats */ +	WMI_10X_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID, +	WMI_10X_VDEV_SPECTRAL_SCAN_ENABLE_CMDID, +	WMI_10X_REQUEST_STATS_CMDID, + +	/* GPIO Configuration */ +	WMI_10X_GPIO_CONFIG_CMDID, +	WMI_10X_GPIO_OUTPUT_CMDID, + +	WMI_10X_PDEV_UTF_CMDID = WMI_10X_END_CMDID - 1, +}; + +enum wmi_10x_event_id { +	WMI_10X_SERVICE_READY_EVENTID = 0x8000, +	WMI_10X_READY_EVENTID, +	WMI_10X_START_EVENTID = 0x9000, +	WMI_10X_END_EVENTID = 0x9FFF, + +	/* Scan specific events */ +	WMI_10X_SCAN_EVENTID = WMI_10X_START_EVENTID, +	WMI_10X_ECHO_EVENTID, +	WMI_10X_DEBUG_MESG_EVENTID, +	WMI_10X_UPDATE_STATS_EVENTID, + +	/* Instantaneous RSSI event */ +	WMI_10X_INST_RSSI_STATS_EVENTID, + +	/* VDEV specific events */ +	WMI_10X_VDEV_START_RESP_EVENTID, +	WMI_10X_VDEV_STANDBY_REQ_EVENTID, +	WMI_10X_VDEV_RESUME_REQ_EVENTID, +	WMI_10X_VDEV_STOPPED_EVENTID, + +	/* peer  specific events */ +	WMI_10X_PEER_STA_KICKOUT_EVENTID, + +	/* beacon/mgmt specific events */ +	WMI_10X_HOST_SWBA_EVENTID, +	WMI_10X_TBTTOFFSET_UPDATE_EVENTID, +	WMI_10X_MGMT_RX_EVENTID, + +	/* Channel stats event */ +	WMI_10X_CHAN_INFO_EVENTID, + +	/* PHY Error specific WMI event */ +	WMI_10X_PHYERR_EVENTID, + +	/* Roam event to trigger roaming on host */ +	WMI_10X_ROAM_EVENTID, + +	/* matching AP found from list of profiles */ +	WMI_10X_PROFILE_MATCH, + +	/* debug print message used for tracing FW code while debugging */ +	WMI_10X_DEBUG_PRINT_EVENTID, +	/* VI spoecific event */ +	WMI_10X_PDEV_QVIT_EVENTID, +	/* FW code profile data in response to profile request */ +	WMI_10X_WLAN_PROFILE_DATA_EVENTID, + +	/*RTT related event ID*/ +	WMI_10X_RTT_MEASUREMENT_REPORT_EVENTID, +	WMI_10X_TSF_MEASUREMENT_REPORT_EVENTID, +	WMI_10X_RTT_ERROR_REPORT_EVENTID, + +	WMI_10X_WOW_WAKEUP_HOST_EVENTID, +	WMI_10X_DCS_INTERFERENCE_EVENTID, + +	/* TPC config for the current operating channel */ +	WMI_10X_PDEV_TPC_CONFIG_EVENTID, + +	WMI_10X_GPIO_INPUT_EVENTID, +	WMI_10X_PDEV_UTF_EVENTID = WMI_10X_END_EVENTID-1, +}; +  enum wmi_phy_mode {  	MODE_11A        = 0,   /* 11a Mode */  	MODE_11G        = 1,   /* 11b/g Mode */ @@ -508,6 +823,48 @@ enum wmi_phy_mode {  	MODE_MAX        = 14  }; +static inline const char *ath10k_wmi_phymode_str(enum wmi_phy_mode mode) +{ +	switch (mode) { +	case MODE_11A: +		return "11a"; +	case MODE_11G: +		return "11g"; +	case MODE_11B: +		return "11b"; +	case MODE_11GONLY: +		return "11gonly"; +	case MODE_11NA_HT20: +		return "11na-ht20"; +	case MODE_11NG_HT20: +		return "11ng-ht20"; +	case MODE_11NA_HT40: +		return "11na-ht40"; +	case MODE_11NG_HT40: +		return "11ng-ht40"; +	case MODE_11AC_VHT20: +		return "11ac-vht20"; +	case MODE_11AC_VHT40: +		return "11ac-vht40"; +	case MODE_11AC_VHT80: +		return "11ac-vht80"; +	case MODE_11AC_VHT20_2G: +		return "11ac-vht20-2g"; +	case MODE_11AC_VHT40_2G: +		return "11ac-vht40-2g"; +	case MODE_11AC_VHT80_2G: +		return "11ac-vht80-2g"; +	case MODE_UNKNOWN: +		/* skip */ +		break; + +		/* no default handler to allow compiler to check that the +		 * enum is fully handled */ +	}; + +	return "<unknown>"; +} +  #define WMI_CHAN_LIST_TAG	0x1  #define WMI_SSID_LIST_TAG	0x2  #define WMI_BSSID_LIST_TAG	0x3 @@ -526,6 +883,7 @@ struct wmi_channel {  	union {  		__le32 reginfo0;  		struct { +			/* note: power unit is 0.5 dBm */  			u8 min_power;  			u8 max_power;  			u8 reg_power; @@ -548,7 +906,8 @@ struct wmi_channel_arg {  	bool allow_ht;  	bool allow_vht;  	bool ht40plus; -	/* note: power unit is 1/4th of dBm */ +	bool chan_radar; +	/* note: power unit is 0.5 dBm */  	u32 min_power;  	u32 max_power;  	u32 max_reg_power; @@ -763,13 +1122,45 @@ struct wmi_service_ready_event {  	struct wlan_host_mem_req mem_reqs[1];  } __packed; -/* - * status consists of  upper 16 bits fo int status and lower 16 bits of - * module ID that retuned status - */ -#define WLAN_INIT_STATUS_SUCCESS   0x0 -#define WLAN_GET_INIT_STATUS_REASON(status)    ((status) & 0xffff) -#define WLAN_GET_INIT_STATUS_MODULE_ID(status) (((status) >> 16) & 0xffff) +/* This is the definition from 10.X firmware branch */ +struct wmi_service_ready_event_10x { +	__le32 sw_version; +	__le32 abi_version; + +	/* WMI_PHY_CAPABILITY */ +	__le32 phy_capability; + +	/* Maximum number of frag table entries that SW will populate less 1 */ +	__le32 max_frag_entry; +	__le32 wmi_service_bitmap[WMI_SERVICE_BM_SIZE]; +	__le32 num_rf_chains; + +	/* +	 * The following field is only valid for service type +	 * WMI_SERVICE_11AC +	 */ +	__le32 ht_cap_info; /* WMI HT Capability */ +	__le32 vht_cap_info; /* VHT capability info field of 802.11ac */ +	__le32 vht_supp_mcs; /* VHT Supported MCS Set field Rx/Tx same */ +	__le32 hw_min_tx_power; +	__le32 hw_max_tx_power; + +	struct hal_reg_capabilities hal_reg_capabilities; + +	__le32 sys_cap_info; +	__le32 min_pkt_size_enable; /* Enterprise mode short pkt enable */ + +	/* +	 * request to host to allocate a chuck of memory and pss it down to FW +	 * via WM_INIT. FW uses this as FW extesnsion memory for saving its +	 * data structures. Only valid for low latency interfaces like PCIE +	 * where FW can access this memory directly (or) by DMA. +	 */ +	__le32 num_mem_reqs; + +	struct wlan_host_mem_req mem_reqs[1]; +} __packed; +  #define WMI_SERVICE_READY_TIMEOUT_HZ (5*HZ)  #define WMI_UNIFIED_READY_TIMEOUT_HZ (5*HZ) @@ -864,7 +1255,7 @@ struct wmi_resource_config {  	 */  	__le32 rx_decap_mode; -	/* what is the maximum scan requests than can be queued */ +	/* what is the maximum number of scan requests that can be queued */  	__le32 scan_max_pending_reqs;  	/* maximum VDEV that could use BMISS offload */ @@ -978,6 +1369,192 @@ struct wmi_resource_config {  	__le32 max_frag_entries;  } __packed; +struct wmi_resource_config_10x { +	/* number of virtual devices (VAPs) to support */ +	__le32 num_vdevs; + +	/* number of peer nodes to support */ +	__le32 num_peers; + +	/* number of keys per peer */ +	__le32 num_peer_keys; + +	/* total number of TX/RX data TIDs */ +	__le32 num_tids; + +	/* +	 * max skid for resolving hash collisions +	 * +	 *   The address search table is sparse, so that if two MAC addresses +	 *   result in the same hash value, the second of these conflicting +	 *   entries can slide to the next index in the address search table, +	 *   and use it, if it is unoccupied.  This ast_skid_limit parameter +	 *   specifies the upper bound on how many subsequent indices to search +	 *   over to find an unoccupied space. +	 */ +	__le32 ast_skid_limit; + +	/* +	 * the nominal chain mask for transmit +	 * +	 *   The chain mask may be modified dynamically, e.g. to operate AP +	 *   tx with a reduced number of chains if no clients are associated. +	 *   This configuration parameter specifies the nominal chain-mask that +	 *   should be used when not operating with a reduced set of tx chains. +	 */ +	__le32 tx_chain_mask; + +	/* +	 * the nominal chain mask for receive +	 * +	 *   The chain mask may be modified dynamically, e.g. for a client +	 *   to use a reduced number of chains for receive if the traffic to +	 *   the client is low enough that it doesn't require downlink MIMO +	 *   or antenna diversity. +	 *   This configuration parameter specifies the nominal chain-mask that +	 *   should be used when not operating with a reduced set of rx chains. +	 */ +	__le32 rx_chain_mask; + +	/* +	 * what rx reorder timeout (ms) to use for the AC +	 * +	 *   Each WMM access class (voice, video, best-effort, background) will +	 *   have its own timeout value to dictate how long to wait for missing +	 *   rx MPDUs to arrive before flushing subsequent MPDUs that have +	 *   already been received. +	 *   This parameter specifies the timeout in milliseconds for each +	 *   class. +	 */ +	__le32 rx_timeout_pri_vi; +	__le32 rx_timeout_pri_vo; +	__le32 rx_timeout_pri_be; +	__le32 rx_timeout_pri_bk; + +	/* +	 * what mode the rx should decap packets to +	 * +	 *   MAC can decap to RAW (no decap), native wifi or Ethernet types +	 *   THis setting also determines the default TX behavior, however TX +	 *   behavior can be modified on a per VAP basis during VAP init +	 */ +	__le32 rx_decap_mode; + +	/* what is the maximum number of scan requests that can be queued */ +	__le32 scan_max_pending_reqs; + +	/* maximum VDEV that could use BMISS offload */ +	__le32 bmiss_offload_max_vdev; + +	/* maximum VDEV that could use offload roaming */ +	__le32 roam_offload_max_vdev; + +	/* maximum AP profiles that would push to offload roaming */ +	__le32 roam_offload_max_ap_profiles; + +	/* +	 * how many groups to use for mcast->ucast conversion +	 * +	 *   The target's WAL maintains a table to hold information regarding +	 *   which peers belong to a given multicast group, so that if +	 *   multicast->unicast conversion is enabled, the target can convert +	 *   multicast tx frames to a series of unicast tx frames, to each +	 *   peer within the multicast group. +	     This num_mcast_groups configuration parameter tells the target how +	 *   many multicast groups to provide storage for within its multicast +	 *   group membership table. +	 */ +	__le32 num_mcast_groups; + +	/* +	 * size to alloc for the mcast membership table +	 * +	 *   This num_mcast_table_elems configuration parameter tells the +	 *   target how many peer elements it needs to provide storage for in +	 *   its multicast group membership table. +	 *   These multicast group membership table elements are shared by the +	 *   multicast groups stored within the table. +	 */ +	__le32 num_mcast_table_elems; + +	/* +	 * whether/how to do multicast->unicast conversion +	 * +	 *   This configuration parameter specifies whether the target should +	 *   perform multicast --> unicast conversion on transmit, and if so, +	 *   what to do if it finds no entries in its multicast group +	 *   membership table for the multicast IP address in the tx frame. +	 *   Configuration value: +	 *   0 -> Do not perform multicast to unicast conversion. +	 *   1 -> Convert multicast frames to unicast, if the IP multicast +	 *        address from the tx frame is found in the multicast group +	 *        membership table.  If the IP multicast address is not found, +	 *        drop the frame. +	 *   2 -> Convert multicast frames to unicast, if the IP multicast +	 *        address from the tx frame is found in the multicast group +	 *        membership table.  If the IP multicast address is not found, +	 *        transmit the frame as multicast. +	 */ +	__le32 mcast2ucast_mode; + +	/* +	 * how much memory to allocate for a tx PPDU dbg log +	 * +	 *   This parameter controls how much memory the target will allocate +	 *   to store a log of tx PPDU meta-information (how large the PPDU +	 *   was, when it was sent, whether it was successful, etc.) +	 */ +	__le32 tx_dbg_log_size; + +	/* how many AST entries to be allocated for WDS */ +	__le32 num_wds_entries; + +	/* +	 * MAC DMA burst size, e.g., For target PCI limit can be +	 * 0 -default, 1 256B +	 */ +	__le32 dma_burst_size; + +	/* +	 * Fixed delimiters to be inserted after every MPDU to +	 * account for interface latency to avoid underrun. +	 */ +	__le32 mac_aggr_delim; + +	/* +	 *   determine whether target is responsible for detecting duplicate +	 *   non-aggregate MPDU and timing out stale fragments. +	 * +	 *   A-MPDU reordering is always performed on the target. +	 * +	 *   0: target responsible for frag timeout and dup checking +	 *   1: host responsible for frag timeout and dup checking +	 */ +	__le32 rx_skip_defrag_timeout_dup_detection_check; + +	/* +	 * Configuration for VoW : +	 * No of Video Nodes to be supported +	 * and Max no of descriptors for each Video link (node). +	 */ +	__le32 vow_config; + +	/* Number of msdu descriptors target should use */ +	__le32 num_msdu_desc; + +	/* +	 * Max. number of Tx fragments per MSDU +	 *  This parameter controls the max number of Tx fragments per MSDU. +	 *  This is sent by the target as part of the WMI_SERVICE_READY event +	 *  and is overriden by the OS shim as required. +	 */ +	__le32 max_frag_entries; +} __packed; + + +#define NUM_UNITS_IS_NUM_VDEVS   0x1 +#define NUM_UNITS_IS_NUM_PEERS   0x2 +  /* strucutre describing host memory chunk. */  struct host_memory_chunk {  	/* id of the request that is passed up in service ready */ @@ -999,6 +1576,18 @@ struct wmi_init_cmd {  	struct host_memory_chunk host_mem_chunks[1];  } __packed; +/* _10x stucture is from 10.X FW API */ +struct wmi_init_cmd_10x { +	struct wmi_resource_config_10x resource_config; +	__le32 num_host_mem_chunks; + +	/* +	 * variable number of host memory chunks. +	 * This should be the last element in the structure +	 */ +	struct host_memory_chunk host_mem_chunks[1]; +} __packed; +  /* TLV for channel list */  struct wmi_chan_list {  	__le32 tag; /* WMI_CHAN_LIST_TAG */ @@ -1118,6 +1707,88 @@ struct wmi_start_scan_cmd {  	 */  } __packed; +/* This is the definition from 10.X firmware branch */ +struct wmi_start_scan_cmd_10x { +	/* Scan ID */ +	__le32 scan_id; + +	/* Scan requestor ID */ +	__le32 scan_req_id; + +	/* VDEV id(interface) that is requesting scan */ +	__le32 vdev_id; + +	/* Scan Priority, input to scan scheduler */ +	__le32 scan_priority; + +	/* Scan events subscription */ +	__le32 notify_scan_events; + +	/* dwell time in msec on active channels */ +	__le32 dwell_time_active; + +	/* dwell time in msec on passive channels */ +	__le32 dwell_time_passive; + +	/* +	 * min time in msec on the BSS channel,only valid if atleast one +	 * VDEV is active +	 */ +	__le32 min_rest_time; + +	/* +	 * max rest time in msec on the BSS channel,only valid if at least +	 * one VDEV is active +	 */ +	/* +	 * the scanner will rest on the bss channel at least min_rest_time +	 * after min_rest_time the scanner will start checking for tx/rx +	 * activity on all VDEVs. if there is no activity the scanner will +	 * switch to off channel. if there is activity the scanner will let +	 * the radio on the bss channel until max_rest_time expires.at +	 * max_rest_time scanner will switch to off channel irrespective of +	 * activity. activity is determined by the idle_time parameter. +	 */ +	__le32 max_rest_time; + +	/* +	 * time before sending next set of probe requests. +	 * The scanner keeps repeating probe requests transmission with +	 * period specified by repeat_probe_time. +	 * The number of probe requests specified depends on the ssid_list +	 * and bssid_list +	 */ +	__le32 repeat_probe_time; + +	/* time in msec between 2 consequetive probe requests with in a set. */ +	__le32 probe_spacing_time; + +	/* +	 * data inactivity time in msec on bss channel that will be used by +	 * scanner for measuring the inactivity. +	 */ +	__le32 idle_time; + +	/* maximum time in msec allowed for scan  */ +	__le32 max_scan_time; + +	/* +	 * delay in msec before sending first probe request after switching +	 * to a channel +	 */ +	__le32 probe_delay; + +	/* Scan control flags */ +	__le32 scan_ctrl_flags; + +	/* +	 * TLV (tag length value )  paramerters follow the scan_cmd structure. +	 * TLV can contain channel list, bssid list, ssid list and +	 * ie. the TLV tags are defined above; +	 */ +} __packed; + +  struct wmi_ssid_arg {  	int len;  	const u8 *ssid; @@ -1268,7 +1939,7 @@ struct wmi_scan_event {   * good idea to pass all the fields in the RX status   * descriptor up to the host.   */ -struct wmi_mgmt_rx_hdr { +struct wmi_mgmt_rx_hdr_v1 {  	__le32 channel;  	__le32 snr;  	__le32 rate; @@ -1277,8 +1948,18 @@ struct wmi_mgmt_rx_hdr {  	__le32 status; /* %WMI_RX_STATUS_ */  } __packed; -struct wmi_mgmt_rx_event { -	struct wmi_mgmt_rx_hdr hdr; +struct wmi_mgmt_rx_hdr_v2 { +	struct wmi_mgmt_rx_hdr_v1 v1; +	__le32 rssi_ctl[4]; +} __packed; + +struct wmi_mgmt_rx_event_v1 { +	struct wmi_mgmt_rx_hdr_v1 hdr; +	u8 buf[0]; +} __packed; + +struct wmi_mgmt_rx_event_v2 { +	struct wmi_mgmt_rx_hdr_v2 hdr;  	u8 buf[0];  } __packed; @@ -1288,6 +1969,10 @@ struct wmi_mgmt_rx_event {  #define WMI_RX_STATUS_ERR_MIC			0x10  #define WMI_RX_STATUS_ERR_KEY_CACHE_MISS	0x20 +#define PHY_ERROR_SPECTRAL_SCAN		0x26 +#define PHY_ERROR_FALSE_RADAR_EXT		0x24 +#define PHY_ERROR_RADAR				0x05 +  struct wmi_single_phyerr_rx_hdr {  	/* TSF timestamp */  	__le32 tsf_timestamp; @@ -1379,6 +2064,87 @@ struct wmi_comb_phyerr_rx_event {  	u8 bufp[0];  } __packed; +#define PHYERR_TLV_SIG				0xBB +#define PHYERR_TLV_TAG_SEARCH_FFT_REPORT	0xFB +#define PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY	0xF8 + +struct phyerr_radar_report { +	__le32 reg0; /* RADAR_REPORT_REG0_* */ +	__le32 reg1; /* REDAR_REPORT_REG1_* */ +} __packed; + +#define RADAR_REPORT_REG0_PULSE_IS_CHIRP_MASK		0x80000000 +#define RADAR_REPORT_REG0_PULSE_IS_CHIRP_LSB		31 + +#define RADAR_REPORT_REG0_PULSE_IS_MAX_WIDTH_MASK	0x40000000 +#define RADAR_REPORT_REG0_PULSE_IS_MAX_WIDTH_LSB	30 + +#define RADAR_REPORT_REG0_AGC_TOTAL_GAIN_MASK		0x3FF00000 +#define RADAR_REPORT_REG0_AGC_TOTAL_GAIN_LSB		20 + +#define RADAR_REPORT_REG0_PULSE_DELTA_DIFF_MASK		0x000F0000 +#define RADAR_REPORT_REG0_PULSE_DELTA_DIFF_LSB		16 + +#define RADAR_REPORT_REG0_PULSE_DELTA_PEAK_MASK		0x0000FC00 +#define RADAR_REPORT_REG0_PULSE_DELTA_PEAK_LSB		10 + +#define RADAR_REPORT_REG0_PULSE_SIDX_MASK		0x000003FF +#define RADAR_REPORT_REG0_PULSE_SIDX_LSB		0 + +#define RADAR_REPORT_REG1_PULSE_SRCH_FFT_VALID_MASK	0x80000000 +#define RADAR_REPORT_REG1_PULSE_SRCH_FFT_VALID_LSB	31 + +#define RADAR_REPORT_REG1_PULSE_AGC_MB_GAIN_MASK	0x7F000000 +#define RADAR_REPORT_REG1_PULSE_AGC_MB_GAIN_LSB		24 + +#define RADAR_REPORT_REG1_PULSE_SUBCHAN_MASK_MASK	0x00FF0000 +#define RADAR_REPORT_REG1_PULSE_SUBCHAN_MASK_LSB	16 + +#define RADAR_REPORT_REG1_PULSE_TSF_OFFSET_MASK		0x0000FF00 +#define RADAR_REPORT_REG1_PULSE_TSF_OFFSET_LSB		8 + +#define RADAR_REPORT_REG1_PULSE_DUR_MASK		0x000000FF +#define RADAR_REPORT_REG1_PULSE_DUR_LSB			0 + +struct phyerr_fft_report { +	__le32 reg0; /* SEARCH_FFT_REPORT_REG0_ * */ +	__le32 reg1; /* SEARCH_FFT_REPORT_REG1_ * */ +} __packed; + +#define SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB_MASK	0xFF800000 +#define SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB_LSB	23 + +#define SEARCH_FFT_REPORT_REG0_BASE_PWR_DB_MASK		0x007FC000 +#define SEARCH_FFT_REPORT_REG0_BASE_PWR_DB_LSB		14 + +#define SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX_MASK		0x00003000 +#define SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX_LSB		12 + +#define SEARCH_FFT_REPORT_REG0_PEAK_SIDX_MASK		0x00000FFF +#define SEARCH_FFT_REPORT_REG0_PEAK_SIDX_LSB		0 + +#define SEARCH_FFT_REPORT_REG1_RELPWR_DB_MASK		0xFC000000 +#define SEARCH_FFT_REPORT_REG1_RELPWR_DB_LSB		26 + +#define SEARCH_FFT_REPORT_REG1_AVGPWR_DB_MASK		0x03FC0000 +#define SEARCH_FFT_REPORT_REG1_AVGPWR_DB_LSB		18 + +#define SEARCH_FFT_REPORT_REG1_PEAK_MAG_MASK		0x0003FF00 +#define SEARCH_FFT_REPORT_REG1_PEAK_MAG_LSB		8 + +#define SEARCH_FFT_REPORT_REG1_NUM_STR_BINS_IB_MASK	0x000000FF +#define SEARCH_FFT_REPORT_REG1_NUM_STR_BINS_IB_LSB	0 + + +struct phyerr_tlv { +	__le16 len; +	u8 tag; +	u8 sig; +} __packed; + +#define DFS_RSSI_POSSIBLY_FALSE			50 +#define DFS_PEAK_MAG_THOLD_POSSIBLY_FALSE	40 +  struct wmi_mgmt_tx_hdr {  	__le32 vdev_id;  	struct wmi_mac_addr peer_macaddr; @@ -1409,6 +2175,31 @@ struct wmi_pdev_set_regdomain_cmd {  	__le32 conformance_test_limit_5G;  } __packed; +enum wmi_dfs_region { +	/* Uninitialized dfs domain */ +	WMI_UNINIT_DFS_DOMAIN = 0, + +	/* FCC3 dfs domain */ +	WMI_FCC_DFS_DOMAIN = 1, + +	/* ETSI dfs domain */ +	WMI_ETSI_DFS_DOMAIN = 2, + +	/*Japan dfs domain */ +	WMI_MKK4_DFS_DOMAIN = 3, +}; + +struct wmi_pdev_set_regdomain_cmd_10x { +	__le32 reg_domain; +	__le32 reg_domain_2G; +	__le32 reg_domain_5G; +	__le32 conformance_test_limit_2G; +	__le32 conformance_test_limit_5G; + +	/* dfs domain from wmi_dfs_region */ +	__le32 dfs_domain; +} __packed; +  /* Command to set/unset chip in quiet mode */  struct wmi_pdev_set_quiet_cmd {  	/* period in TUs */ @@ -1434,6 +2225,19 @@ enum ath10k_protmode {  	ATH10K_PROT_RTSCTS   = 2,    /* RTS-CTS */  }; +enum wmi_rtscts_profile { +	WMI_RTSCTS_FOR_NO_RATESERIES = 0, +	WMI_RTSCTS_FOR_SECOND_RATESERIES, +	WMI_RTSCTS_ACROSS_SW_RETRIES +}; + +#define WMI_RTSCTS_ENABLED		1 +#define WMI_RTSCTS_SET_MASK		0x0f +#define WMI_RTSCTS_SET_LSB		0 + +#define WMI_RTSCTS_PROFILE_MASK		0xf0 +#define WMI_RTSCTS_PROFILE_LSB		4 +  enum wmi_beacon_gen_mode {  	WMI_BEACON_STAGGERED_MODE = 0,  	WMI_BEACON_BURST_MODE = 1 @@ -1465,10 +2269,63 @@ struct wmi_csa_event {  #define VDEV_DEFAULT_STATS_UPDATE_PERIOD    500  #define PEER_DEFAULT_STATS_UPDATE_PERIOD    500 +struct wmi_pdev_param_map { +	u32 tx_chain_mask; +	u32 rx_chain_mask; +	u32 txpower_limit2g; +	u32 txpower_limit5g; +	u32 txpower_scale; +	u32 beacon_gen_mode; +	u32 beacon_tx_mode; +	u32 resmgr_offchan_mode; +	u32 protection_mode; +	u32 dynamic_bw; +	u32 non_agg_sw_retry_th; +	u32 agg_sw_retry_th; +	u32 sta_kickout_th; +	u32 ac_aggrsize_scaling; +	u32 ltr_enable; +	u32 ltr_ac_latency_be; +	u32 ltr_ac_latency_bk; +	u32 ltr_ac_latency_vi; +	u32 ltr_ac_latency_vo; +	u32 ltr_ac_latency_timeout; +	u32 ltr_sleep_override; +	u32 ltr_rx_override; +	u32 ltr_tx_activity_timeout; +	u32 l1ss_enable; +	u32 dsleep_enable; +	u32 pcielp_txbuf_flush; +	u32 pcielp_txbuf_watermark; +	u32 pcielp_txbuf_tmo_en; +	u32 pcielp_txbuf_tmo_value; +	u32 pdev_stats_update_period; +	u32 vdev_stats_update_period; +	u32 peer_stats_update_period; +	u32 bcnflt_stats_update_period; +	u32 pmf_qos; +	u32 arp_ac_override; +	u32 dcs; +	u32 ani_enable; +	u32 ani_poll_period; +	u32 ani_listen_period; +	u32 ani_ofdm_level; +	u32 ani_cck_level; +	u32 dyntxchain; +	u32 proxy_sta; +	u32 idle_ps_config; +	u32 power_gating_sleep; +	u32 fast_channel_reset; +	u32 burst_dur; +	u32 burst_enable; +}; + +#define WMI_PDEV_PARAM_UNSUPPORTED 0 +  enum wmi_pdev_param { -	/* TX chian mask */ +	/* TX chain mask */  	WMI_PDEV_PARAM_TX_CHAIN_MASK = 0x1, -	/* RX chian mask */ +	/* RX chain mask */  	WMI_PDEV_PARAM_RX_CHAIN_MASK,  	/* TX power limit for 2G Radio */  	WMI_PDEV_PARAM_TXPOWER_LIMIT2G, @@ -1490,7 +2347,12 @@ enum wmi_pdev_param {  	 * 0: no protection 1:use CTS-to-self 2: use RTS/CTS  	 */  	WMI_PDEV_PARAM_PROTECTION_MODE, -	/* Dynamic bandwidth 0: disable 1: enable */ +	/* +	 * Dynamic bandwidth - 0: disable, 1: enable +	 * +	 * When enabled HW rate control tries different bandwidths when +	 * retransmitting frames. +	 */  	WMI_PDEV_PARAM_DYNAMIC_BW,  	/* Non aggregrate/ 11g sw retry threshold.0-disable */  	WMI_PDEV_PARAM_NON_AGG_SW_RETRY_TH, @@ -1564,6 +2426,97 @@ enum wmi_pdev_param {  	WMI_PDEV_PARAM_POWER_GATING_SLEEP,  }; +enum wmi_10x_pdev_param { +	/* TX chian mask */ +	WMI_10X_PDEV_PARAM_TX_CHAIN_MASK = 0x1, +	/* RX chian mask */ +	WMI_10X_PDEV_PARAM_RX_CHAIN_MASK, +	/* TX power limit for 2G Radio */ +	WMI_10X_PDEV_PARAM_TXPOWER_LIMIT2G, +	/* TX power limit for 5G Radio */ +	WMI_10X_PDEV_PARAM_TXPOWER_LIMIT5G, +	/* TX power scale */ +	WMI_10X_PDEV_PARAM_TXPOWER_SCALE, +	/* Beacon generation mode . 0: host, 1: target   */ +	WMI_10X_PDEV_PARAM_BEACON_GEN_MODE, +	/* Beacon generation mode . 0: staggered 1: bursted   */ +	WMI_10X_PDEV_PARAM_BEACON_TX_MODE, +	/* +	 * Resource manager off chan mode . +	 * 0: turn off off chan mode. 1: turn on offchan mode +	 */ +	WMI_10X_PDEV_PARAM_RESMGR_OFFCHAN_MODE, +	/* +	 * Protection mode: +	 * 0: no protection 1:use CTS-to-self 2: use RTS/CTS +	 */ +	WMI_10X_PDEV_PARAM_PROTECTION_MODE, +	/* Dynamic bandwidth 0: disable 1: enable */ +	WMI_10X_PDEV_PARAM_DYNAMIC_BW, +	/* Non aggregrate/ 11g sw retry threshold.0-disable */ +	WMI_10X_PDEV_PARAM_NON_AGG_SW_RETRY_TH, +	/* aggregrate sw retry threshold. 0-disable*/ +	WMI_10X_PDEV_PARAM_AGG_SW_RETRY_TH, +	/* Station kickout threshold (non of consecutive failures).0-disable */ +	WMI_10X_PDEV_PARAM_STA_KICKOUT_TH, +	/* Aggerate size scaling configuration per AC */ +	WMI_10X_PDEV_PARAM_AC_AGGRSIZE_SCALING, +	/* LTR enable */ +	WMI_10X_PDEV_PARAM_LTR_ENABLE, +	/* LTR latency for BE, in us */ +	WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_BE, +	/* LTR latency for BK, in us */ +	WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_BK, +	/* LTR latency for VI, in us */ +	WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_VI, +	/* LTR latency for VO, in us  */ +	WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_VO, +	/* LTR AC latency timeout, in ms */ +	WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT, +	/* LTR platform latency override, in us */ +	WMI_10X_PDEV_PARAM_LTR_SLEEP_OVERRIDE, +	/* LTR-RX override, in us */ +	WMI_10X_PDEV_PARAM_LTR_RX_OVERRIDE, +	/* Tx activity timeout for LTR, in us */ +	WMI_10X_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT, +	/* L1SS state machine enable */ +	WMI_10X_PDEV_PARAM_L1SS_ENABLE, +	/* Deep sleep state machine enable */ +	WMI_10X_PDEV_PARAM_DSLEEP_ENABLE, +	/* pdev level stats update period in ms */ +	WMI_10X_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD, +	/* vdev level stats update period in ms */ +	WMI_10X_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD, +	/* peer level stats update period in ms */ +	WMI_10X_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD, +	/* beacon filter status update period */ +	WMI_10X_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, +	/* QOS Mgmt frame protection MFP/PMF 0: disable, 1: enable */ +	WMI_10X_PDEV_PARAM_PMF_QOS, +	/* Access category on which ARP and DHCP frames are sent */ +	WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE, +	/* DCS configuration */ +	WMI_10X_PDEV_PARAM_DCS, +	/* Enable/Disable ANI on target */ +	WMI_10X_PDEV_PARAM_ANI_ENABLE, +	/* configure the ANI polling period */ +	WMI_10X_PDEV_PARAM_ANI_POLL_PERIOD, +	/* configure the ANI listening period */ +	WMI_10X_PDEV_PARAM_ANI_LISTEN_PERIOD, +	/* configure OFDM immunity level */ +	WMI_10X_PDEV_PARAM_ANI_OFDM_LEVEL, +	/* configure CCK immunity level */ +	WMI_10X_PDEV_PARAM_ANI_CCK_LEVEL, +	/* Enable/Disable CDD for 1x1 STAs in rate control module */ +	WMI_10X_PDEV_PARAM_DYNTXCHAIN, +	/* Enable/Disable Fast channel reset*/ +	WMI_10X_PDEV_PARAM_FAST_CHANNEL_RESET, +	/* Set Bursting DUR */ +	WMI_10X_PDEV_PARAM_BURST_DUR, +	/* Set Bursting Enable*/ +	WMI_10X_PDEV_PARAM_BURST_ENABLE, +}; +  struct wmi_pdev_set_param_cmd {  	__le32 param_id;  	__le32 param_value; @@ -1757,6 +2710,9 @@ struct wal_dbg_tx_stats {  	/* wal pdev resets  */  	__le32 pdev_resets; +	/* frames dropped due to non-availability of stateless TIDs */ +	__le32 stateless_tid_alloc_failure; +  	__le32 phy_underrun;  	/* MPDU is more than txop limit */ @@ -1813,13 +2769,21 @@ enum wmi_stats_id {  	WMI_REQUEST_AP_STAT	= 0x02  }; +struct wlan_inst_rssi_args { +	__le16 cfg_retry_count; +	__le16 retry_count; +}; +  struct wmi_request_stats_cmd {  	__le32 stats_id; -	/* -	 * Space to add parameters like -	 * peer mac addr -	 */ +	__le32 vdev_id; + +	/* peer MAC address */ +	struct wmi_mac_addr peer_macaddr; + +	/* Instantaneous RSSI arguments */ +	struct wlan_inst_rssi_args inst_rssi_args;  } __packed;  /* Suspend option */ @@ -1870,7 +2834,7 @@ struct wmi_stats_event {   * PDEV statistics   * TODO: add all PDEV stats here   */ -struct wmi_pdev_stats { +struct wmi_pdev_stats_old {  	__le32 chan_nf;        /* Channel noise floor */  	__le32 tx_frame_count; /* TX frame count */  	__le32 rx_frame_count; /* RX frame count */ @@ -1881,6 +2845,23 @@ struct wmi_pdev_stats {  	struct wal_dbg_stats wal; /* WAL dbg stats */  } __packed; +struct wmi_pdev_stats_10x { +	__le32 chan_nf;        /* Channel noise floor */ +	__le32 tx_frame_count; /* TX frame count */ +	__le32 rx_frame_count; /* RX frame count */ +	__le32 rx_clear_count; /* rx clear count */ +	__le32 cycle_count;    /* cycle count */ +	__le32 phy_err_count;  /* Phy error count */ +	__le32 chan_tx_pwr;    /* channel tx power */ +	struct wal_dbg_stats wal; /* WAL dbg stats */ +	__le32 ack_rx_bad; +	__le32 rts_bad; +	__le32 rts_good; +	__le32 fcs_bad; +	__le32 no_beacons; +	__le32 mib_int_count; +} __packed; +  /*   * VDEV statistics   * TODO: add all VDEV stats here @@ -1893,10 +2874,17 @@ struct wmi_vdev_stats {   * peer statistics.   * TODO: add more stats   */ -struct wmi_peer_stats { +struct wmi_peer_stats_old { +	struct wmi_mac_addr peer_macaddr; +	__le32 peer_rssi; +	__le32 peer_tx_rate; +} __packed; + +struct wmi_peer_stats_10x {  	struct wmi_mac_addr peer_macaddr;  	__le32 peer_rssi;  	__le32 peer_tx_rate; +	__le32 peer_rx_rate;  } __packed;  struct wmi_vdev_create_cmd { @@ -2077,6 +3065,18 @@ struct wmi_vdev_install_key_arg {  	const void *key_data;  }; +/* + * vdev fixed rate format: + * - preamble - b7:b6 - see WMI_RATE_PREMABLE_ + * - nss      - b5:b4 - ss number (0 mean 1ss) + * - rate_mcs - b3:b0 - as below + *    CCK:  0 - 11Mbps, 1 - 5,5Mbps, 2 - 2Mbps, 3 - 1Mbps, + *          4 - 11Mbps (s), 5 - 5,5Mbps (s), 6 - 2Mbps (s) + *    OFDM: 0 - 48Mbps, 1 - 24Mbps, 2 - 12Mbps, 3 - 6Mbps, + *          4 - 54Mbps, 5 - 36Mbps, 6 - 18Mbps, 7 - 9Mbps + *    HT/VHT: MCS index + */ +  /* Preamble types to be used with VDEV fixed rate configuration */  enum wmi_rate_preamble {  	WMI_RATE_PREAMBLE_OFDM, @@ -2088,6 +3088,61 @@ enum wmi_rate_preamble {  /* Value to disable fixed rate setting */  #define WMI_FIXED_RATE_NONE    (0xff) +struct wmi_vdev_param_map { +	u32 rts_threshold; +	u32 fragmentation_threshold; +	u32 beacon_interval; +	u32 listen_interval; +	u32 multicast_rate; +	u32 mgmt_tx_rate; +	u32 slot_time; +	u32 preamble; +	u32 swba_time; +	u32 wmi_vdev_stats_update_period; +	u32 wmi_vdev_pwrsave_ageout_time; +	u32 wmi_vdev_host_swba_interval; +	u32 dtim_period; +	u32 wmi_vdev_oc_scheduler_air_time_limit; +	u32 wds; +	u32 atim_window; +	u32 bmiss_count_max; +	u32 bmiss_first_bcnt; +	u32 bmiss_final_bcnt; +	u32 feature_wmm; +	u32 chwidth; +	u32 chextoffset; +	u32 disable_htprotection; +	u32 sta_quickkickout; +	u32 mgmt_rate; +	u32 protection_mode; +	u32 fixed_rate; +	u32 sgi; +	u32 ldpc; +	u32 tx_stbc; +	u32 rx_stbc; +	u32 intra_bss_fwd; +	u32 def_keyid; +	u32 nss; +	u32 bcast_data_rate; +	u32 mcast_data_rate; +	u32 mcast_indicate; +	u32 dhcp_indicate; +	u32 unknown_dest_indicate; +	u32 ap_keepalive_min_idle_inactive_time_secs; +	u32 ap_keepalive_max_idle_inactive_time_secs; +	u32 ap_keepalive_max_unresponsive_time_secs; +	u32 ap_enable_nawds; +	u32 mcast2ucast_set; +	u32 enable_rtscts; +	u32 txbf; +	u32 packet_powersave; +	u32 drop_unencry; +	u32 tx_encap_type; +	u32 ap_detect_out_of_sync_sleeping_sta_time_secs; +}; + +#define WMI_VDEV_PARAM_UNSUPPORTED 0 +  /* the definition of different VDEV parameters */  enum wmi_vdev_param {  	/* RTS Threshold */ @@ -2219,6 +3274,121 @@ enum wmi_vdev_param {  	WMI_VDEV_PARAM_TX_ENCAP_TYPE,  }; +/* the definition of different VDEV parameters */ +enum wmi_10x_vdev_param { +	/* RTS Threshold */ +	WMI_10X_VDEV_PARAM_RTS_THRESHOLD = 0x1, +	/* Fragmentation threshold */ +	WMI_10X_VDEV_PARAM_FRAGMENTATION_THRESHOLD, +	/* beacon interval in TUs */ +	WMI_10X_VDEV_PARAM_BEACON_INTERVAL, +	/* Listen interval in TUs */ +	WMI_10X_VDEV_PARAM_LISTEN_INTERVAL, +	/* muticast rate in Mbps */ +	WMI_10X_VDEV_PARAM_MULTICAST_RATE, +	/* management frame rate in Mbps */ +	WMI_10X_VDEV_PARAM_MGMT_TX_RATE, +	/* slot time (long vs short) */ +	WMI_10X_VDEV_PARAM_SLOT_TIME, +	/* preamble (long vs short) */ +	WMI_10X_VDEV_PARAM_PREAMBLE, +	/* SWBA time (time before tbtt in msec) */ +	WMI_10X_VDEV_PARAM_SWBA_TIME, +	/* time period for updating VDEV stats */ +	WMI_10X_VDEV_STATS_UPDATE_PERIOD, +	/* age out time in msec for frames queued for station in power save */ +	WMI_10X_VDEV_PWRSAVE_AGEOUT_TIME, +	/* +	 * Host SWBA interval (time in msec before tbtt for SWBA event +	 * generation). +	 */ +	WMI_10X_VDEV_HOST_SWBA_INTERVAL, +	/* DTIM period (specified in units of num beacon intervals) */ +	WMI_10X_VDEV_PARAM_DTIM_PERIOD, +	/* +	 * scheduler air time limit for this VDEV. used by off chan +	 * scheduler. +	 */ +	WMI_10X_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT, +	/* enable/dsiable WDS for this VDEV  */ +	WMI_10X_VDEV_PARAM_WDS, +	/* ATIM Window */ +	WMI_10X_VDEV_PARAM_ATIM_WINDOW, +	/* BMISS max */ +	WMI_10X_VDEV_PARAM_BMISS_COUNT_MAX, +	/* WMM enables/disabled */ +	WMI_10X_VDEV_PARAM_FEATURE_WMM, +	/* Channel width */ +	WMI_10X_VDEV_PARAM_CHWIDTH, +	/* Channel Offset */ +	WMI_10X_VDEV_PARAM_CHEXTOFFSET, +	/* Disable HT Protection */ +	WMI_10X_VDEV_PARAM_DISABLE_HTPROTECTION, +	/* Quick STA Kickout */ +	WMI_10X_VDEV_PARAM_STA_QUICKKICKOUT, +	/* Rate to be used with Management frames */ +	WMI_10X_VDEV_PARAM_MGMT_RATE, +	/* Protection Mode */ +	WMI_10X_VDEV_PARAM_PROTECTION_MODE, +	/* Fixed rate setting */ +	WMI_10X_VDEV_PARAM_FIXED_RATE, +	/* Short GI Enable/Disable */ +	WMI_10X_VDEV_PARAM_SGI, +	/* Enable LDPC */ +	WMI_10X_VDEV_PARAM_LDPC, +	/* Enable Tx STBC */ +	WMI_10X_VDEV_PARAM_TX_STBC, +	/* Enable Rx STBC */ +	WMI_10X_VDEV_PARAM_RX_STBC, +	/* Intra BSS forwarding  */ +	WMI_10X_VDEV_PARAM_INTRA_BSS_FWD, +	/* Setting Default xmit key for Vdev */ +	WMI_10X_VDEV_PARAM_DEF_KEYID, +	/* NSS width */ +	WMI_10X_VDEV_PARAM_NSS, +	/* Set the custom rate for the broadcast data frames */ +	WMI_10X_VDEV_PARAM_BCAST_DATA_RATE, +	/* Set the custom rate (rate-code) for multicast data frames */ +	WMI_10X_VDEV_PARAM_MCAST_DATA_RATE, +	/* Tx multicast packet indicate Enable/Disable */ +	WMI_10X_VDEV_PARAM_MCAST_INDICATE, +	/* Tx DHCP packet indicate Enable/Disable */ +	WMI_10X_VDEV_PARAM_DHCP_INDICATE, +	/* Enable host inspection of Tx unicast packet to unknown destination */ +	WMI_10X_VDEV_PARAM_UNKNOWN_DEST_INDICATE, + +	/* The minimum amount of time AP begins to consider STA inactive */ +	WMI_10X_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, + +	/* +	 * An associated STA is considered inactive when there is no recent +	 * TX/RX activity and no downlink frames are buffered for it. Once a +	 * STA exceeds the maximum idle inactive time, the AP will send an +	 * 802.11 data-null as a keep alive to verify the STA is still +	 * associated. If the STA does ACK the data-null, or if the data-null +	 * is buffered and the STA does not retrieve it, the STA will be +	 * considered unresponsive +	 * (see WMI_10X_VDEV_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS). +	 */ +	WMI_10X_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, + +	/* +	 * An associated STA is considered unresponsive if there is no recent +	 * TX/RX activity and downlink frames are buffered for it. Once a STA +	 * exceeds the maximum unresponsive time, the AP will send a +	 * WMI_10X_STA_KICKOUT event to the host so the STA can be deleted. */ +	WMI_10X_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, + +	/* Enable NAWDS : MCAST INSPECT Enable, NAWDS Flag set */ +	WMI_10X_VDEV_PARAM_AP_ENABLE_NAWDS, + +	WMI_10X_VDEV_PARAM_MCAST2UCAST_SET, +	/* Enable/Disable RTS-CTS */ +	WMI_10X_VDEV_PARAM_ENABLE_RTSCTS, + +	WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, +}; +  /* slot time long */  #define WMI_VDEV_SLOT_TIME_LONG		0x1  /* slot time short */ @@ -2295,6 +3465,24 @@ struct wmi_bcn_tx_arg {  	const void *bcn;  }; +enum wmi_bcn_tx_ref_flags { +	WMI_BCN_TX_REF_FLAG_DTIM_ZERO = 0x1, +	WMI_BCN_TX_REF_FLAG_DELIVER_CAB = 0x2, +}; + +struct wmi_bcn_tx_ref_cmd { +	__le32 vdev_id; +	__le32 data_len; +	/* physical address of the frame - dma pointer */ +	__le32 data_ptr; +	/* id for host to track */ +	__le32 msdu_id; +	/* frame ctrl to setup PPDU desc */ +	__le32 frame_control; +	/* to control CABQ traffic: WMI_BCN_TX_REF_FLAG_ */ +	__le32 flags; +} __packed; +  /* Beacon filter */  #define WMI_BCN_FILTER_ALL   0 /* Filter all beacons */  #define WMI_BCN_FILTER_NONE  1 /* Pass all beacons */ @@ -2751,6 +3939,12 @@ enum wmi_peer_smps_state {  	WMI_PEER_SMPS_DYNAMIC = 0x2  }; +enum wmi_peer_chwidth { +	WMI_PEER_CHWIDTH_20MHZ = 0, +	WMI_PEER_CHWIDTH_40MHZ = 1, +	WMI_PEER_CHWIDTH_80MHZ = 2, +}; +  enum wmi_peer_param {  	WMI_PEER_SMPS_STATE = 0x1, /* see %wmi_peer_smps_state */  	WMI_PEER_AMPDU      = 0x2, @@ -2931,6 +4125,10 @@ struct wmi_chan_info_event {  	__le32 cycle_count;  } __packed; +struct wmi_peer_sta_kickout_event { +	struct wmi_mac_addr peer_macaddr; +} __packed; +  #define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0)  /* FIXME: empirically extrapolated */ @@ -2994,13 +4192,60 @@ struct wmi_force_fw_hang_cmd {  	__le32 delay_ms;  } __packed; +enum ath10k_dbglog_level { +	ATH10K_DBGLOG_LEVEL_VERBOSE = 0, +	ATH10K_DBGLOG_LEVEL_INFO = 1, +	ATH10K_DBGLOG_LEVEL_WARN = 2, +	ATH10K_DBGLOG_LEVEL_ERR = 3, +}; + +/* VAP ids to enable dbglog */ +#define ATH10K_DBGLOG_CFG_VAP_LOG_LSB		0 +#define ATH10K_DBGLOG_CFG_VAP_LOG_MASK		0x0000ffff + +/* to enable dbglog in the firmware */ +#define ATH10K_DBGLOG_CFG_REPORTING_ENABLE_LSB	16 +#define ATH10K_DBGLOG_CFG_REPORTING_ENABLE_MASK	0x00010000 + +/* timestamp resolution */ +#define ATH10K_DBGLOG_CFG_RESOLUTION_LSB	17 +#define ATH10K_DBGLOG_CFG_RESOLUTION_MASK	0x000E0000 + +/* number of queued messages before sending them to the host */ +#define ATH10K_DBGLOG_CFG_REPORT_SIZE_LSB	20 +#define ATH10K_DBGLOG_CFG_REPORT_SIZE_MASK	0x0ff00000 + +/* + * Log levels to enable. This defines the minimum level to enable, this is + * not a bitmask. See enum ath10k_dbglog_level for the values. + */ +#define ATH10K_DBGLOG_CFG_LOG_LVL_LSB		28 +#define ATH10K_DBGLOG_CFG_LOG_LVL_MASK		0x70000000 + +/* + * Note: this is a cleaned up version of a struct firmware uses. For + * example, config_valid was hidden inside an array. + */ +struct wmi_dbglog_cfg_cmd { +	/* bitmask to hold mod id config*/ +	__le32 module_enable; + +	/* see ATH10K_DBGLOG_CFG_ */ +	__le32 config_enable; + +	/* mask of module id bits to be changed */ +	__le32 module_valid; + +	/* mask of config bits to be changed, see ATH10K_DBGLOG_CFG_ */ +	__le32 config_valid; +} __packed; +  #define ATH10K_RTS_MAX		2347  #define ATH10K_FRAGMT_THRESHOLD_MIN	540  #define ATH10K_FRAGMT_THRESHOLD_MAX	2346  #define WMI_MAX_EVENT 0x1000  /* Maximum number of pending TXed WMI packets */ -#define WMI_MAX_PENDING_TX_COUNT 128  #define WMI_SKB_HEADROOM sizeof(struct wmi_cmd_hdr)  /* By default disable power save for IBSS */ @@ -3013,17 +4258,16 @@ int ath10k_wmi_attach(struct ath10k *ar);  void ath10k_wmi_detach(struct ath10k *ar);  int ath10k_wmi_wait_for_service_ready(struct ath10k *ar);  int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar); -void ath10k_wmi_flush_tx(struct ath10k *ar); -int ath10k_wmi_connect_htc_service(struct ath10k *ar); +int ath10k_wmi_connect(struct ath10k *ar);  int ath10k_wmi_pdev_set_channel(struct ath10k *ar,  				const struct wmi_channel_arg *); -int ath10k_wmi_pdev_suspend_target(struct ath10k *ar); +int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt);  int ath10k_wmi_pdev_resume_target(struct ath10k *ar);  int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, -				  u16 rd5g, u16 ctl2g, u16 ctl5g); -int ath10k_wmi_pdev_set_param(struct ath10k *ar, enum wmi_pdev_param id, -			      u32 value); +				  u16 rd5g, u16 ctl2g, u16 ctl5g, +				  enum wmi_dfs_region dfs_reg); +int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value);  int ath10k_wmi_cmd_init(struct ath10k *ar);  int ath10k_wmi_start_scan(struct ath10k *ar, const struct wmi_start_scan_arg *);  void ath10k_wmi_start_scan_init(struct ath10k *ar, struct wmi_start_scan_arg *); @@ -3043,7 +4287,7 @@ int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid,  		       const u8 *bssid);  int ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id);  int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id, -			      enum wmi_vdev_param param_id, u32 param_value); +			      u32 param_id, u32 param_value);  int ath10k_wmi_vdev_install_key(struct ath10k *ar,  				const struct wmi_vdev_install_key_arg *arg);  int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id, @@ -3066,11 +4310,13 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,  			       enum wmi_ap_ps_peer_param param_id, u32 value);  int ath10k_wmi_scan_chan_list(struct ath10k *ar,  			      const struct wmi_scan_chan_list_arg *arg); -int ath10k_wmi_beacon_send(struct ath10k *ar, const struct wmi_bcn_tx_arg *arg); +int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif);  int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,  			const struct wmi_pdev_set_wmm_params_arg *arg);  int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id);  int ath10k_wmi_force_fw_hang(struct ath10k *ar,  			     enum wmi_force_fw_hang_type type, u32 delay_ms); +int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb); +int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable);  #endif /* _WMI_H_ */ diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index e9bc9e616b6..79bffe165ca 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -37,12 +37,9 @@ ath5k_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)  {  	struct ath5k_hw *ah = common->priv;  	struct platform_device *pdev = to_platform_device(ah->dev); -	struct ar231x_board_config *bcfg = pdev->dev.platform_data; +	struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);  	u16 *eeprom, *eeprom_end; - - -	bcfg = pdev->dev.platform_data;  	eeprom = (u16 *) bcfg->radio;  	eeprom_end = ((void *) bcfg->config) + BOARD_CONFIG_BUFSZ; @@ -57,7 +54,7 @@ ath5k_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)  int ath5k_hw_read_srev(struct ath5k_hw *ah)  {  	struct platform_device *pdev = to_platform_device(ah->dev); -	struct ar231x_board_config *bcfg = pdev->dev.platform_data; +	struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);  	ah->ah_mac_srev = bcfg->devid;  	return 0;  } @@ -65,7 +62,7 @@ int ath5k_hw_read_srev(struct ath5k_hw *ah)  static int ath5k_ahb_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)  {  	struct platform_device *pdev = to_platform_device(ah->dev); -	struct ar231x_board_config *bcfg = pdev->dev.platform_data; +	struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);  	u8 *cfg_mac;  	if (to_platform_device(ah->dev)->id == 0) @@ -87,7 +84,7 @@ static const struct ath_bus_ops ath_ahb_bus_ops = {  /*Initialization*/  static int ath_ahb_probe(struct platform_device *pdev)  { -	struct ar231x_board_config *bcfg = pdev->dev.platform_data; +	struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);  	struct ath5k_hw *ah;  	struct ieee80211_hw *hw;  	struct resource *res; @@ -96,7 +93,7 @@ static int ath_ahb_probe(struct platform_device *pdev)  	int ret = 0;  	u32 reg; -	if (!pdev->dev.platform_data) { +	if (!dev_get_platdata(&pdev->dev)) {  		dev_err(&pdev->dev, "no platform data specified\n");  		ret = -EINVAL;  		goto err_out; @@ -193,7 +190,7 @@ static int ath_ahb_probe(struct platform_device *pdev)  static int ath_ahb_remove(struct platform_device *pdev)  { -	struct ar231x_board_config *bcfg = pdev->dev.platform_data; +	struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);  	struct ieee80211_hw *hw = platform_get_drvdata(pdev);  	struct ath5k_hw *ah;  	u32 reg; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 48161edec8d..4b18434ba69 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -751,6 +751,9 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf,  	bf->skbaddr = dma_map_single(ah->dev, skb->data, skb->len,  			DMA_TO_DEVICE); +	if (dma_mapping_error(ah->dev, bf->skbaddr)) +		return -ENOSPC; +  	ieee80211_get_tx_rates(info->control.vif, (control) ? control->sta : NULL, skb, bf->rates,  			       ARRAY_SIZE(bf->rates)); @@ -1238,14 +1241,11 @@ static void  ath5k_check_ibss_tsf(struct ath5k_hw *ah, struct sk_buff *skb,  		     struct ieee80211_rx_status *rxs)  { -	struct ath_common *common = ath5k_hw_common(ah);  	u64 tsf, bc_tstamp;  	u32 hw_tu;  	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; -	if (ieee80211_is_beacon(mgmt->frame_control) && -	    le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS && -	    ether_addr_equal(mgmt->bssid, common->curbssid)) { +	if (le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS) {  		/*  		 * Received an IBSS beacon with the same BSSID. Hardware *must*  		 * have updated the local TSF. We have to work around various @@ -1301,23 +1301,6 @@ ath5k_check_ibss_tsf(struct ath5k_hw *ah, struct sk_buff *skb,  	}  } -static void -ath5k_update_beacon_rssi(struct ath5k_hw *ah, struct sk_buff *skb, int rssi) -{ -	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; -	struct ath_common *common = ath5k_hw_common(ah); - -	/* only beacons from our BSSID */ -	if (!ieee80211_is_beacon(mgmt->frame_control) || -	    !ether_addr_equal(mgmt->bssid, common->curbssid)) -		return; - -	ewma_add(&ah->ah_beacon_rssi_avg, rssi); - -	/* in IBSS mode we should keep RSSI statistics per neighbour */ -	/* le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS */ -} -  /*   * Compute padding position. skb must contain an IEEE 802.11 frame   */ @@ -1390,6 +1373,7 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb,  		    struct ath5k_rx_status *rs)  {  	struct ieee80211_rx_status *rxs; +	struct ath_common *common = ath5k_hw_common(ah);  	ath5k_remove_padding(skb); @@ -1442,11 +1426,13 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb,  	trace_ath5k_rx(ah, skb); -	ath5k_update_beacon_rssi(ah, skb, rs->rs_rssi); +	if (ath_is_mybeacon(common, (struct ieee80211_hdr *)skb->data)) { +		ewma_add(&ah->ah_beacon_rssi_avg, rs->rs_rssi); -	/* check beacons in IBSS mode */ -	if (ah->opmode == NL80211_IFTYPE_ADHOC) -		ath5k_check_ibss_tsf(ah, skb, rxs); +		/* check beacons in IBSS mode */ +		if (ah->opmode == NL80211_IFTYPE_ADHOC) +			ath5k_check_ibss_tsf(ah, skb, rxs); +	}  	ieee80211_rx(ah->hw, skb);  } @@ -1663,15 +1649,15 @@ ath5k_tx_frame_completed(struct ath5k_hw *ah, struct sk_buff *skb,  	ah->stats.tx_bytes_count += skb->len;  	info = IEEE80211_SKB_CB(skb); +	size = min_t(int, sizeof(info->status.rates), sizeof(bf->rates)); +	memcpy(info->status.rates, bf->rates, size); +  	tries[0] = info->status.rates[0].count;  	tries[1] = info->status.rates[1].count;  	tries[2] = info->status.rates[2].count;  	ieee80211_tx_info_clear_status(info); -	size = min_t(int, sizeof(info->status.rates), sizeof(bf->rates)); -	memcpy(info->status.rates, bf->rates, size); -  	for (i = 0; i < ts->ts_final_idx; i++) {  		struct ieee80211_tx_rate *r =  			&info->status.rates[i]; @@ -2549,7 +2535,6 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops)  	hw->wiphy->available_antennas_rx = 0x3;  	hw->extra_tx_headroom = 2; -	hw->channel_change_time = 5000;  	/*  	 * Mark the device as detached to avoid processing diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c index ce86f158423..e6c52f7c26e 100644 --- a/drivers/net/wireless/ath/ath5k/dma.c +++ b/drivers/net/wireless/ath/ath5k/dma.c @@ -616,7 +616,16 @@ ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)  		 * SISRs will also clear PISR so no need to worry here.  		 */ -		pisr_clear = pisr & ~AR5K_ISR_BITS_FROM_SISRS; +		/* XXX: There seems to be  an issue on some cards +		 *	with tx interrupt flags not being updated +		 *	on PISR despite that all Tx interrupt bits +		 * 	are cleared on SISRs. Since we handle all +		 *	Tx queues all together it shouldn't be an +		 *	issue if we clear Tx interrupt flags also +		 * 	on PISR to avoid that. +		 */ +		pisr_clear = (pisr & ~AR5K_ISR_BITS_FROM_SISRS) | +					(pisr & AR5K_INT_TX_ALL);  		/*  		 * Write to clear them... @@ -661,7 +670,7 @@ ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)  			ah->ah_txq_isr_txok_all |= AR5K_REG_MS(sisr1,  						AR5K_SISR1_QCU_TXEOL); -		/* Currently this is not much usefull since we treat +		/* Currently this is not much useful since we treat  		 * all queues the same way if we get a TXURN (update  		 * tx trigger level) but we might need it later on*/  		if (pisr & AR5K_ISR_TXURN) diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 4ee01f65423..afb23b3cc7b 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -681,6 +681,7 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)  	survey->channel = conf->chandef.chan;  	survey->noise = ah->ah_noise_floor;  	survey->filled = SURVEY_INFO_NOISE_DBM | +			SURVEY_INFO_IN_USE |  			SURVEY_INFO_CHANNEL_TIME |  			SURVEY_INFO_CHANNEL_TIME_BUSY |  			SURVEY_INFO_CHANNEL_TIME_RX | diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index d6bc7cb61bf..0fce1c76638 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -110,7 +110,7 @@ ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band)  		ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20));  	if (ah->ah_version == AR5K_AR5210) { -		srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf; +		srev = (ath5k_hw_reg_read(ah, AR5K_PHY(256)) >> 28) & 0xf;  		ret = (u16)ath5k_hw_bitswap(srev, 4) + 1;  	} else {  		srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff; @@ -3709,8 +3709,8 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,  			AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CHIRP),  			AR5K_TPC);  	} else { -		ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX | -			AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX); +		ath5k_hw_reg_write(ah, AR5K_TUNE_MAX_TXPOWER, +			AR5K_PHY_TXPOWER_RATE_MAX);  	}  	return 0; diff --git a/drivers/net/wireless/ath/ath6kl/Kconfig b/drivers/net/wireless/ath/ath6kl/Kconfig index e39e5860a2e..9c125ff083f 100644 --- a/drivers/net/wireless/ath/ath6kl/Kconfig +++ b/drivers/net/wireless/ath/ath6kl/Kconfig @@ -1,11 +1,19 @@  config ATH6KL  	tristate "Atheros mobile chipsets support" +	depends on CFG80211 +        ---help--- +	  This module adds core support for wireless adapters based on +	  Atheros AR6003 and AR6004 chipsets. You still need separate +	  bus drivers for USB and SDIO to be able to use real devices. + +	  If you choose to build it as a module, it will be called +	  ath6kl_core. Please note that AR6002 and AR6001 are not +	  supported by this driver.  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 and AR6004 chipsets running over SDIO. If you @@ -17,25 +25,31 @@ config ATH6KL_USB  	tristate "Atheros ath6kl USB support"  	depends on ATH6KL  	depends on USB -	depends on CFG80211  	---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. +	  Atheros AR6004 chipset and chipsets based on it running over +	  USB. If you choose to build it as a module, it will be +	  called ath6kl_usb.  config ATH6KL_DEBUG  	bool "Atheros ath6kl debugging"  	depends on ATH6KL  	---help--- -	  Enables debug support +	  Enables ath6kl debug support, including debug messages +	  enabled with debug_mask module parameter and debugfs +	  interface. + +	  If unsure, say Y to make it easier to debug problems.  config ATH6KL_TRACING  	bool "Atheros ath6kl tracing support"  	depends on ATH6KL  	depends on EVENT_TRACING  	---help--- -	  Select this to ath6kl use tracing infrastructure. +	  Select this to ath6kl use tracing infrastructure which, for +	  example, can be enabled with help of trace-cmd. All debug +	  messages and commands are delivered to using individually +	  enablable trace points.  	  If unsure, say Y to make it easier to debug problems. @@ -47,3 +61,5 @@ config ATH6KL_REGDOMAIN  	  Enabling this makes it possible to change the regdomain in  	  the firmware. This can be only enabled if regulatory requirements  	  are taken into account. + +	  If unsure, say N. diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 2437ad26949..0e26f4a34fd 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -724,8 +724,9 @@ ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,  			ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,  				   "added bss %pM to cfg80211\n", bssid);  		kfree(ie); -	} else +	} else {  		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss\n"); +	}  	return bss;  } @@ -790,7 +791,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,  	if (nw_type & ADHOC_NETWORK) {  		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",  			   nw_type & ADHOC_CREATOR ? "creator" : "joiner"); -		cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL); +		cfg80211_ibss_joined(vif->ndev, bssid, chan, GFP_KERNEL);  		cfg80211_put_bss(ar->wiphy, bss);  		return;  	} @@ -861,13 +862,9 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,  	}  	if (vif->nw_type & ADHOC_NETWORK) { -		if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) { +		if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC)  			ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,  				   "%s: ath6k not in ibss mode\n", __func__); -			return; -		} -		memset(bssid, 0, ETH_ALEN); -		cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);  		return;  	} @@ -974,7 +971,6 @@ static int ath6kl_set_probed_ssids(struct ath6kl *ar,  					  ssid_list[i].flag,  					  ssid_list[i].ssid.ssid_len,  					  ssid_list[i].ssid.ssid); -  	}  	/* Make sure no old entries are left behind */ @@ -1109,7 +1105,9 @@ void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,  				(mode == WMI_11G_HT20) ?  					NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT); +	mutex_lock(&vif->wdev.mtx);  	cfg80211_ch_switch_notify(vif->ndev, &chandef); +	mutex_unlock(&vif->wdev.mtx);  }  static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, @@ -1761,7 +1759,7 @@ static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi)  }  static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev, -			      u8 *mac, struct station_info *sinfo) +			      const u8 *mac, struct station_info *sinfo)  {  	struct ath6kl *ar = ath6kl_priv(dev);  	struct ath6kl_vif *vif = netdev_priv(dev); @@ -1899,7 +1897,6 @@ static int ath6kl_wow_usr(struct ath6kl *ar, struct ath6kl_vif *vif,  	/* Configure the patterns that we received from the user. */  	for (i = 0; i < wow->n_patterns; i++) { -  		/*  		 * Convert given nl80211 specific mask value to equivalent  		 * driver specific mask value and send it to the chip along @@ -2852,8 +2849,9 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,  	if (p.prwise_crypto_type == 0) {  		p.prwise_crypto_type = NONE_CRYPT;  		ath6kl_set_cipher(vif, 0, true); -	} else if (info->crypto.n_ciphers_pairwise == 1) +	} else if (info->crypto.n_ciphers_pairwise == 1) {  		ath6kl_set_cipher(vif, info->crypto.ciphers_pairwise[0], true); +	}  	switch (info->crypto.cipher_group) {  	case WLAN_CIPHER_SUITE_WEP40: @@ -2899,7 +2897,6 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,  	}  	if (info->inactivity_timeout) { -  		inactivity_timeout = info->inactivity_timeout;  		if (ar->hw.flags & ATH6KL_HW_AP_INACTIVITY_MINS) @@ -2977,7 +2974,7 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev)  static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };  static int ath6kl_del_station(struct wiphy *wiphy, struct net_device *dev, -			      u8 *mac) +			      const u8 *mac)  {  	struct ath6kl *ar = ath6kl_priv(dev);  	struct ath6kl_vif *vif = netdev_priv(dev); @@ -2988,7 +2985,8 @@ static int ath6kl_del_station(struct wiphy *wiphy, struct net_device *dev,  }  static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev, -				 u8 *mac, struct station_parameters *params) +				 const u8 *mac, +				 struct station_parameters *params)  {  	struct ath6kl *ar = ath6kl_priv(dev);  	struct ath6kl_vif *vif = netdev_priv(dev); @@ -3169,12 +3167,15 @@ static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len)  }  static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, -			  struct ieee80211_channel *chan, bool offchan, -			  unsigned int wait, const u8 *buf, size_t len, -			  bool no_cck, bool dont_wait_for_ack, u64 *cookie) +			  struct cfg80211_mgmt_tx_params *params, u64 *cookie)  {  	struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);  	struct ath6kl *ar = ath6kl_priv(vif->ndev); +	struct ieee80211_channel *chan = params->chan; +	const u8 *buf = params->buf; +	size_t len = params->len; +	unsigned int wait = params->wait; +	bool no_cck = params->no_cck;  	u32 id, freq;  	const struct ieee80211_mgmt *mgmt;  	bool more_data, queued; @@ -3251,6 +3252,15 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,  	struct ath6kl_vif *vif = netdev_priv(dev);  	u16 interval;  	int ret, rssi_thold; +	int n_match_sets = request->n_match_sets; + +	/* +	 * If there's a matchset w/o an SSID, then assume it's just for +	 * the RSSI (nothing else is currently supported) and ignore it. +	 * The device only supports a global RSSI filter that we set below. +	 */ +	if (n_match_sets == 1 && !request->match_sets[0].ssid.ssid_len) +		n_match_sets = 0;  	if (ar->state != ATH6KL_STATE_ON)  		return -EIO; @@ -3263,11 +3273,11 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,  	ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,  				      request->n_ssids,  				      request->match_sets, -				      request->n_match_sets); +				      n_match_sets);  	if (ret < 0)  		return ret; -	if (!request->n_match_sets) { +	if (!n_match_sets) {  		ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,  					       ALL_BSS_FILTER, 0);  		if (ret < 0) @@ -3281,12 +3291,12 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,  	if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD,  		     ar->fw_capabilities)) { -		if (request->rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF) +		if (request->min_rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF)  			rssi_thold = 0; -		else if (request->rssi_thold < -127) +		else if (request->min_rssi_thold < -127)  			rssi_thold = -127;  		else -			rssi_thold = request->rssi_thold; +			rssi_thold = request->min_rssi_thold;  		ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx,  						     rssi_thold); diff --git a/drivers/net/wireless/ath/ath6kl/common.h b/drivers/net/wireless/ath/ath6kl/common.h index 98a886154d9..05debf700a8 100644 --- a/drivers/net/wireless/ath/ath6kl/common.h +++ b/drivers/net/wireless/ath/ath6kl/common.h @@ -22,8 +22,7 @@  #define ATH6KL_MAX_IE			256 -extern __printf(2, 3) -int ath6kl_printk(const char *level, const char *fmt, ...); +__printf(2, 3) int ath6kl_printk(const char *level, const char *fmt, ...);  /*   * Reflects the version of binary interface exposed by ATH6KL target diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index 4b46adbe8c9..b0b65204276 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -45,9 +45,9 @@ module_param(testmode, uint, 0644);  module_param(recovery_enable, uint, 0644);  module_param(heart_beat_poll, uint, 0644);  MODULE_PARM_DESC(recovery_enable, "Enable recovery from firmware error"); -MODULE_PARM_DESC(heart_beat_poll, "Enable fw error detection periodic"   \ -		 "polling. This also specifies the polling interval in"  \ -		 "msecs. Set reocvery_enable for this to be effective"); +MODULE_PARM_DESC(heart_beat_poll, +		 "Enable fw error detection periodic polling in msecs - Also set recovery_enable for this to be effective"); +  void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb)  { diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index dbfd17d0a5f..55c4064dd50 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c @@ -172,7 +172,6 @@ void ath6kl_dump_registers(struct ath6kl_device *dev,  			   struct ath6kl_irq_proc_registers *irq_proc_reg,  			   struct ath6kl_irq_enable_reg *irq_enable_reg)  { -  	ath6kl_dbg(ATH6KL_DBG_IRQ, ("<------- Register Table -------->\n"));  	if (irq_proc_reg != NULL) { @@ -219,7 +218,6 @@ void ath6kl_dump_registers(struct ath6kl_device *dev,  				   "GMBOX lookahead alias 1:   0x%x\n",  				   irq_proc_reg->rx_gmbox_lkahd_alias[1]);  		} -  	}  	if (irq_enable_reg != NULL) { @@ -1396,7 +1394,6 @@ static ssize_t ath6kl_create_qos_write(struct file *file,  						const char __user *user_buf,  						size_t count, loff_t *ppos)  { -  	struct ath6kl *ar = file->private_data;  	struct ath6kl_vif *vif;  	char buf[200]; @@ -1575,7 +1572,6 @@ static ssize_t ath6kl_delete_qos_write(struct file *file,  				const char __user *user_buf,  				size_t count, loff_t *ppos)  { -  	struct ath6kl *ar = file->private_data;  	struct ath6kl_vif *vif;  	char buf[100]; diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h index 74369de00fb..e194c10d9f0 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.h +++ b/drivers/net/wireless/ath/ath6kl/debug.h @@ -50,11 +50,10 @@ enum ATH6K_DEBUG_MASK {  };  extern unsigned int debug_mask; -extern __printf(2, 3) -int ath6kl_printk(const char *level, const char *fmt, ...); -extern __printf(1, 2) int ath6kl_info(const char *fmt, ...); -extern __printf(1, 2) int ath6kl_err(const char *fmt, ...); -extern __printf(1, 2) int ath6kl_warn(const char *fmt, ...); +__printf(2, 3) int ath6kl_printk(const char *level, const char *fmt, ...); +__printf(1, 2) int ath6kl_info(const char *fmt, ...); +__printf(1, 2) int ath6kl_err(const char *fmt, ...); +__printf(1, 2) int ath6kl_warn(const char *fmt, ...);  enum ath6kl_war {  	ATH6KL_WAR_INVALID_RATE, @@ -98,8 +97,8 @@ static inline void ath6kl_dump_registers(struct ath6kl_device *dev,  		struct ath6kl_irq_proc_registers *irq_proc_reg,  		struct ath6kl_irq_enable_reg *irq_en_reg)  { -  } +  static inline void dump_cred_dist_stats(struct htc_target *target)  {  } diff --git a/drivers/net/wireless/ath/ath6kl/hif.c b/drivers/net/wireless/ath/ath6kl/hif.c index fea7709b5dd..18c070850a0 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.c +++ b/drivers/net/wireless/ath/ath6kl/hif.c @@ -37,7 +37,6 @@ static int ath6kl_hif_cp_scat_dma_buf(struct hif_scatter_req *req,  	buf = req->virt_dma_buf;  	for (i = 0; i < req->scat_entries; i++) { -  		if (from_dma)  			memcpy(req->scat_list[i].buf, buf,  			       req->scat_list[i].len); @@ -116,7 +115,6 @@ static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar)  			    le32_to_cpu(regdump_val[i + 2]),  			    le32_to_cpu(regdump_val[i + 3]));  	} -  }  static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev) @@ -701,5 +699,4 @@ int ath6kl_hif_setup(struct ath6kl_device *dev)  fail_setup:  	return status; -  } diff --git a/drivers/net/wireless/ath/ath6kl/hif.h b/drivers/net/wireless/ath/ath6kl/hif.h index 61f6b21fb0a..dc6bd8cd9b8 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.h +++ b/drivers/net/wireless/ath/ath6kl/hif.h @@ -197,9 +197,9 @@ struct hif_scatter_req {  	/* bounce buffer for upper layers to copy to/from */  	u8 *virt_dma_buf; -	struct hif_scatter_item scat_list[1]; -  	u32 scat_q_depth; + +	struct hif_scatter_item scat_list[0];  };  struct ath6kl_irq_proc_registers { diff --git a/drivers/net/wireless/ath/ath6kl/htc.h b/drivers/net/wireless/ath/ath6kl/htc.h index a2c8ff80979..14cab1403dd 100644 --- a/drivers/net/wireless/ath/ath6kl/htc.h +++ b/drivers/net/wireless/ath/ath6kl/htc.h @@ -60,7 +60,7 @@  /* disable credit flow control on a specific service */  #define HTC_CONN_FLGS_DISABLE_CRED_FLOW_CTRL          (1 << 3)  #define HTC_CONN_FLGS_SET_RECV_ALLOC_SHIFT    8 -#define HTC_CONN_FLGS_SET_RECV_ALLOC_MASK     0xFF00 +#define HTC_CONN_FLGS_SET_RECV_ALLOC_MASK     0xFF00U  /* connect response status codes */  #define HTC_SERVICE_SUCCESS      0 diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c index 65e5b719093..e481f14b987 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c +++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c @@ -112,9 +112,9 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info,  		if (cur_ep_dist->endpoint == ENDPOINT_0)  			continue; -		if (cur_ep_dist->svc_id == WMI_CONTROL_SVC) +		if (cur_ep_dist->svc_id == WMI_CONTROL_SVC) {  			cur_ep_dist->cred_norm = cur_ep_dist->cred_per_msg; -		else { +		} else {  			/*  			 * For the remaining data endpoints, we assume that  			 * each cred_per_msg are the same. We use a simple @@ -129,7 +129,6 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info,  			count = (count * 3) >> 2;  			count = max(count, cur_ep_dist->cred_per_msg);  			cur_ep_dist->cred_norm = count; -  		}  		ath6kl_dbg(ATH6KL_DBG_CREDIT, @@ -549,7 +548,6 @@ static int htc_check_credits(struct htc_target *target,  			     enum htc_endpoint_id eid, unsigned int len,  			     int *req_cred)  { -  	*req_cred = (len > target->tgt_cred_sz) ?  		     DIV_ROUND_UP(len, target->tgt_cred_sz) : 1; @@ -608,7 +606,6 @@ static void ath6kl_htc_tx_pkts_get(struct htc_target *target,  	unsigned int len;  	while (true) { -  		flags = 0;  		if (list_empty(&endpoint->txq)) @@ -889,7 +886,6 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target,  		ac = target->dev->ar->ep2ac_map[endpoint->eid];  	while (true) { -  		if (list_empty(&endpoint->txq))  			break; @@ -1190,7 +1186,6 @@ static void ath6kl_htc_mbox_flush_txep(struct htc_target *target,  		list_add_tail(&packet->list, &container);  		htc_tx_complete(endpoint, &container);  	} -  }  static void ath6kl_htc_flush_txep_all(struct htc_target *target) @@ -1394,7 +1389,6 @@ static int ath6kl_htc_rx_setup(struct htc_target *target,  	ep_cb = ep->ep_cb;  	for (j = 0; j < n_msg; j++) { -  		/*  		 * Reset flag, any packets allocated using the  		 * rx_alloc() API cannot be recycled on @@ -1424,9 +1418,9 @@ static int ath6kl_htc_rx_setup(struct htc_target *target,  				}  			} -			if (list_empty(&ep->rx_bufq)) +			if (list_empty(&ep->rx_bufq)) {  				packet = NULL; -			else { +			} else {  				packet = list_first_entry(&ep->rx_bufq,  						struct htc_packet, list);  				list_del(&packet->list); @@ -1487,7 +1481,6 @@ static int ath6kl_htc_rx_alloc(struct htc_target *target,  	spin_lock_bh(&target->rx_lock);  	for (i = 0; i < msg; i++) { -  		htc_hdr = (struct htc_frame_hdr *)&lk_ahds[i];  		if (htc_hdr->eid >= ENDPOINT_MAX) { @@ -1708,7 +1701,6 @@ static int htc_parse_trailer(struct htc_target *target,  		lk_ahd = (struct htc_lookahead_report *) record_buf;  		if ((lk_ahd->pre_valid == ((~lk_ahd->post_valid) & 0xFF)) &&  		    next_lk_ahds) { -  			ath6kl_dbg(ATH6KL_DBG_HTC,  				   "htc rx lk_ahd found pre_valid 0x%x post_valid 0x%x\n",  				   lk_ahd->pre_valid, lk_ahd->post_valid); @@ -1755,7 +1747,6 @@ static int htc_parse_trailer(struct htc_target *target,  	}  	return 0; -  }  static int htc_proc_trailer(struct htc_target *target, @@ -1776,7 +1767,6 @@ static int htc_proc_trailer(struct htc_target *target,  	status = 0;  	while (len > 0) { -  		if (len < sizeof(struct htc_record_hdr)) {  			status = -ENOMEM;  			break; @@ -2098,7 +2088,6 @@ static int ath6kl_htc_rx_fetch(struct htc_target *target,  		}  		if (!fetched_pkts) { -  			packet = list_first_entry(rx_pktq, struct htc_packet,  						   list); @@ -2173,7 +2162,6 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,  	look_aheads[0] = msg_look_ahead;  	while (true) { -  		/*  		 * First lookahead sets the expected endpoint IDs for all  		 * packets in a bundle. @@ -2825,8 +2813,9 @@ static int ath6kl_htc_reset(struct htc_target *target)  			packet->buf = packet->buf_start;  			packet->endpoint = ENDPOINT_0;  			list_add_tail(&packet->list, &target->free_ctrl_rxbuf); -		} else +		} else {  			list_add_tail(&packet->list, &target->free_ctrl_txbuf); +		}  	}  	return 0; diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c index 67aa924ed8b..756fe52a12c 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c +++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c @@ -137,7 +137,6 @@ static void get_htc_packet_credit_based(struct htc_target *target,  			credits_required = 0;  		} else { -  			if (ep->cred_dist.credits < credits_required)  				break; @@ -169,7 +168,6 @@ static void get_htc_packet_credit_based(struct htc_target *target,  		/* queue this packet into the caller's queue */  		list_add_tail(&packet->list, queue);  	} -  }  static void get_htc_packet(struct htc_target *target, @@ -279,7 +277,6 @@ static int htc_issue_packets(struct htc_target *target,  			list_add(&packet->list, pkt_queue);  			break;  		} -  	}  	if (status != 0) { @@ -385,7 +382,6 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target,  			 */  			list_for_each_entry_safe(packet, tmp_pkt,  						 txq, list) { -  				ath6kl_dbg(ATH6KL_DBG_HTC,  					   "%s: Indicat overflowed TX pkts: %p\n",  					   __func__, packet); @@ -403,7 +399,6 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target,  					list_move_tail(&packet->list,  						       &send_queue);  				} -  			}  			if (list_empty(&send_queue)) { @@ -454,7 +449,6 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target,  	 * enough transmit resources.  	 */  	while (true) { -  		if (get_queue_depth(&ep->txq) == 0)  			break; @@ -495,8 +489,8 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target,  		}  		spin_lock_bh(&target->tx_lock); -  	} +  	/* done with this endpoint, we can clear the count */  	ep->tx_proc_cnt = 0;  	spin_unlock_bh(&target->tx_lock); @@ -1106,7 +1100,6 @@ free_skb:  	dev_kfree_skb(skb);  	return status; -  }  static void htc_flush_rx_queue(struct htc_target *target, @@ -1258,7 +1251,6 @@ static int ath6kl_htc_pipe_conn_service(struct htc_target *target,  		tx_alloc = 0;  	} else { -  		tx_alloc = htc_get_credit_alloc(target, conn_req->svc_id);  		if (tx_alloc == 0) {  			status = -ENOMEM; diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 4f316bdcbab..d5ef211f261 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1192,7 +1192,6 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)  	if (board_ext_address &&  	    ar->fw_board_len == (board_data_size + board_ext_data_size)) { -  		/* write extended board data */  		ath6kl_dbg(ATH6KL_DBG_BOOT,  			   "writing extended board data to 0x%x (%d B)\n", diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index 5839fc23bdc..d56554674da 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -571,7 +571,6 @@ void ath6kl_scan_complete_evt(struct ath6kl_vif *vif, int status)  static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel)  { -  	struct ath6kl *ar = vif->ar;  	vif->profile.ch = cpu_to_le16(channel); @@ -600,7 +599,6 @@ static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel)  static void ath6kl_check_ch_switch(struct ath6kl *ar, u16 channel)  { -  	struct ath6kl_vif *vif;  	int res = 0; @@ -692,9 +690,9 @@ void ath6kl_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid, bool ismcast)  		cfg80211_michael_mic_failure(vif->ndev, sta->mac,  					     NL80211_KEYTYPE_PAIRWISE, keyid,  					     tsc, GFP_KERNEL); -	} else +	} else {  		ath6kl_cfg80211_tkip_micerr_event(vif, keyid, ismcast); - +	}  }  static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len) @@ -1093,8 +1091,9 @@ static int ath6kl_open(struct net_device *dev)  	if (test_bit(CONNECTED, &vif->flags)) {  		netif_carrier_on(dev);  		netif_wake_queue(dev); -	} else +	} else {  		netif_carrier_off(dev); +	}  	return 0;  } @@ -1146,7 +1145,6 @@ static int ath6kl_set_features(struct net_device *dev,  			dev->features = features | NETIF_F_RXCSUM;  			return err;  		} -  	}  	return err; diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 7126bdd4236..339d89f14d3 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -348,7 +348,7 @@ static int ath6kl_sdio_alloc_prep_scat_req(struct ath6kl_sdio *ar_sdio,  	int i, scat_req_sz, scat_list_sz, size;  	u8 *virt_buf; -	scat_list_sz = (n_scat_entry - 1) * sizeof(struct hif_scatter_item); +	scat_list_sz = n_scat_entry * sizeof(struct hif_scatter_item);  	scat_req_sz = sizeof(*s_req) + scat_list_sz;  	if (!virt_scat) @@ -425,8 +425,9 @@ static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf,  			memcpy(tbuf, buf, len);  		bounced = true; -	} else +	} else {  		tbuf = buf; +	}  	ret = ath6kl_sdio_io(ar_sdio->func, request, addr, tbuf, len);  	if ((request & HIF_READ) && bounced) @@ -441,9 +442,9 @@ static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf,  static void __ath6kl_sdio_write_async(struct ath6kl_sdio *ar_sdio,  				      struct bus_request *req)  { -	if (req->scat_req) +	if (req->scat_req) {  		ath6kl_sdio_scat_rw(ar_sdio, req); -	else { +	} else {  		void *context;  		int status; @@ -656,7 +657,6 @@ static void ath6kl_sdio_scatter_req_add(struct ath6kl *ar,  	list_add_tail(&s_req->list, &ar_sdio->scat_req);  	spin_unlock_bh(&ar_sdio->scat_lock); -  }  /* scatter gather read write request */ @@ -674,9 +674,9 @@ static int ath6kl_sdio_async_rw_scatter(struct ath6kl *ar,  		   "hif-scatter: total len: %d scatter entries: %d\n",  		   scat_req->len, scat_req->scat_entries); -	if (request & HIF_SYNCHRONOUS) +	if (request & HIF_SYNCHRONOUS) {  		status = ath6kl_sdio_scat_rw(ar_sdio, scat_req->busrequest); -	else { +	} else {  		spin_lock_bh(&ar_sdio->wr_async_lock);  		list_add_tail(&scat_req->busrequest->list, &ar_sdio->wr_asyncq);  		spin_unlock_bh(&ar_sdio->wr_async_lock); @@ -856,7 +856,6 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)  	if (ar->suspend_mode == WLAN_POWER_STATE_WOW ||  	    (!ar->suspend_mode && wow)) { -  		ret = ath6kl_set_sdio_pm_caps(ar);  		if (ret)  			goto cut_pwr; @@ -878,7 +877,6 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)  	if (ar->suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP ||  	    !ar->suspend_mode || try_deepsleep) { -  		flags = sdio_get_host_pm_caps(func);  		if (!(flags & MMC_PM_KEEP_POWER))  			goto cut_pwr; @@ -1061,7 +1059,6 @@ static int ath6kl_sdio_bmi_credits(struct ath6kl *ar)  	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 diff --git a/drivers/net/wireless/ath/ath6kl/target.h b/drivers/net/wireless/ath/ath6kl/target.h index a580a629a0d..d5eeeae7711 100644 --- a/drivers/net/wireless/ath/ath6kl/target.h +++ b/drivers/net/wireless/ath/ath6kl/target.h @@ -289,7 +289,7 @@ struct host_interest {  	u32 hi_hp_rx_traffic_ratio;                    /* 0xd8 */  	/* test applications flags */ -	u32 hi_test_apps_related    ;                  /* 0xdc */ +	u32 hi_test_apps_related;                      /* 0xdc */  	/* location of test script */  	u32 hi_ota_testscript;                         /* 0xe0 */  	/* location of CAL data */ diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index ebb24045a8a..40432fe7a5d 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -125,8 +125,9 @@ static bool ath6kl_process_uapsdq(struct ath6kl_sta *conn,  		*flags |= WMI_DATA_HDR_FLAGS_UAPSD;  		spin_unlock_bh(&conn->psq_lock);  		return false; -	} else if (!conn->apsd_info) +	} else if (!conn->apsd_info) {  		return false; +	}  	if (test_bit(WMM_ENABLED, &vif->flags)) {  		ether_type = be16_to_cpu(datap->h_proto); @@ -316,8 +317,9 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb,  		cookie = NULL;  		ath6kl_err("wmi ctrl ep full, dropping pkt : 0x%p, len:%d\n",  			   skb, skb->len); -	} else +	} else {  		cookie = ath6kl_alloc_cookie(ar); +	}  	if (cookie == NULL) {  		spin_unlock_bh(&ar->lock); @@ -359,7 +361,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)  	struct ath6kl_vif *vif = netdev_priv(dev);  	u32 map_no = 0;  	u16 htc_tag = ATH6KL_DATA_PKT_TAG; -	u8 ac = 99 ; /* initialize to unmapped ac */ +	u8 ac = 99; /* initialize to unmapped ac */  	bool chk_adhoc_ps_mapping = false;  	int ret;  	struct wmi_tx_meta_v2 meta_v2; @@ -449,8 +451,9 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)  			if (ret)  				goto fail_tx;  		} -	} else +	} else {  		goto fail_tx; +	}  	spin_lock_bh(&ar->lock); @@ -702,7 +705,6 @@ void ath6kl_tx_complete(struct htc_target *target,  	/* reap completed packets */  	while (!list_empty(packet_queue)) { -  		packet = list_first_entry(packet_queue, struct htc_packet,  					  list);  		list_del(&packet->list); @@ -1089,8 +1091,9 @@ static void aggr_deque_frms(struct aggr_info_conn *agg_conn, u8 tid,  			else  				skb_queue_tail(&rxtid->q, node->skb);  			node->skb = NULL; -		} else +		} else {  			stats->num_hole++; +		}  		rxtid->seq_next = ATH6KL_NEXT_SEQ_NO(rxtid->seq_next);  		idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz); @@ -1211,7 +1214,7 @@ static bool aggr_process_recv_frm(struct aggr_info_conn *agg_conn, u8 tid,  		return is_queued;  	spin_lock_bh(&rxtid->lock); -	for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) { +	for (idx = 0; idx < rxtid->hold_q_sz; idx++) {  		if (rxtid->hold_q[idx].skb) {  			/*  			 * There is a frame in the queue and no @@ -1265,7 +1268,6 @@ static void ath6kl_uapsd_trigger_frame_rx(struct ath6kl_vif *vif,  	is_apsdq_empty_at_start = is_apsdq_empty;  	while ((!is_apsdq_empty) && (num_frames_to_deliver)) { -  		spin_lock_bh(&conn->psq_lock);  		skb = skb_dequeue(&conn->apsdq);  		is_apsdq_empty = skb_queue_empty(&conn->apsdq); @@ -1606,16 +1608,18 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)  			if (!conn)  				return;  			aggr_conn = conn->aggr_conn; -		} else +		} else {  			aggr_conn = vif->aggr_cntxt->aggr_conn; +		}  		if (aggr_process_recv_frm(aggr_conn, tid, seq_no,  					  is_amsdu, skb)) {  			/* aggregation code will handle the skb */  			return;  		} -	} else if (!is_broadcast_ether_addr(datap->h_dest)) +	} else if (!is_broadcast_ether_addr(datap->h_dest)) {  		vif->net_stats.multicast++; +	}  	ath6kl_deliver_frames_to_nw_stack(vif->ndev, skb);  } @@ -1710,8 +1714,9 @@ void aggr_recv_addba_req_evt(struct ath6kl_vif *vif, u8 tid_mux, u16 seq_no,  		sta = ath6kl_find_sta_by_aid(vif->ar, aid);  		if (sta)  			aggr_conn = sta->aggr_conn; -	} else +	} else {  		aggr_conn = vif->aggr_cntxt->aggr_conn; +	}  	if (!aggr_conn)  		return; @@ -1766,7 +1771,6 @@ void aggr_conn_init(struct ath6kl_vif *vif, struct aggr_info *aggr_info,  		skb_queue_head_init(&rxtid->q);  		spin_lock_init(&rxtid->lock);  	} -  }  struct aggr_info *aggr_init(struct ath6kl_vif *vif) @@ -1806,8 +1810,9 @@ void aggr_recv_delba_req_evt(struct ath6kl_vif *vif, u8 tid_mux)  		sta = ath6kl_find_sta_by_aid(vif->ar, aid);  		if (sta)  			aggr_conn = sta->aggr_conn; -	} else +	} else {  		aggr_conn = vif->aggr_cntxt->aggr_conn; +	}  	if (!aggr_conn)  		return; diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index f38ff6a6255..3afc5a463d0 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -24,7 +24,7 @@  /* constants */  #define TX_URB_COUNT            32  #define RX_URB_COUNT            32 -#define ATH6KL_USB_RX_BUFFER_SIZE  1700 +#define ATH6KL_USB_RX_BUFFER_SIZE  4096  /* tx/rx pipes for usb */  enum ATH6KL_USB_PIPE_ID { @@ -236,7 +236,6 @@ static void ath6kl_usb_free_pipe_resources(struct ath6kl_usb_pipe *pipe)  			break;  		kfree(urb_context);  	} -  }  static void ath6kl_usb_cleanup_pipe_resources(struct ath6kl_usb *ar_usb) @@ -245,7 +244,6 @@ static void ath6kl_usb_cleanup_pipe_resources(struct ath6kl_usb *ar_usb)  	for (i = 0; i < ATH6KL_USB_PIPE_MAX; i++)  		ath6kl_usb_free_pipe_resources(&ar_usb->pipes[i]); -  }  static u8 ath6kl_usb_get_logical_pipe_num(struct ath6kl_usb *ar_usb, @@ -481,8 +479,8 @@ static void ath6kl_usb_start_recv_pipes(struct ath6kl_usb *ar_usb)  	 *		ATH6KL_USB_RX_BUFFER_SIZE);  	 */ -	ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_cnt_thresh = -	    ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_alloc / 2; +	ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_cnt_thresh = 1; +  	ath6kl_usb_post_recv_transfers(&ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA],  				       ATH6KL_USB_RX_BUFFER_SIZE);  } diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 546d5da0b89..4d7f9e4712e 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -289,8 +289,9 @@ int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, u8 if_idx,  			   ath6kl_wmi_determine_user_priority(((u8 *) llc_hdr) +  					sizeof(struct ath6kl_llc_snap_hdr),  					layer2_priority); -		} else +		} else {  			usr_pri = layer2_priority & 0x7; +		}  		/*  		 * Queue the EAPOL frames in the same WMM_AC_VO queue @@ -359,8 +360,9 @@ int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb)  		hdr_size = roundup(sizeof(struct ieee80211_qos_hdr),  				   sizeof(u32));  		skb_pull(skb, hdr_size); -	} else if (sub_type == cpu_to_le16(IEEE80211_STYPE_DATA)) +	} else if (sub_type == cpu_to_le16(IEEE80211_STYPE_DATA)) {  		skb_pull(skb, sizeof(struct ieee80211_hdr_3addr)); +	}  	datap = skb->data;  	llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap); @@ -914,7 +916,7 @@ ath6kl_get_regpair(u16 regdmn)  		return NULL;  	for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) { -		if (regDomainPairs[i].regDmnEnum == regdmn) +		if (regDomainPairs[i].reg_domain == regdmn)  			return ®DomainPairs[i];  	} @@ -936,7 +938,6 @@ ath6kl_regd_find_country_by_rd(u16 regdmn)  static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len)  { -  	struct ath6kl_wmi_regdomain *ev;  	struct country_code_to_enum_rd *country = NULL;  	struct reg_dmn_pair_mapping *regpair = NULL; @@ -946,15 +947,14 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len)  	ev = (struct ath6kl_wmi_regdomain *) datap;  	reg_code = le32_to_cpu(ev->reg_code); -	if ((reg_code >> ATH6KL_COUNTRY_RD_SHIFT) & COUNTRY_ERD_FLAG) +	if ((reg_code >> ATH6KL_COUNTRY_RD_SHIFT) & COUNTRY_ERD_FLAG) {  		country = ath6kl_regd_find_country((u16) reg_code); -	else if (!(((u16) reg_code & WORLD_SKU_MASK) == WORLD_SKU_PREFIX)) { - +	} else if (!(((u16) reg_code & WORLD_SKU_MASK) == WORLD_SKU_PREFIX)) {  		regpair = ath6kl_get_regpair((u16) reg_code);  		country = ath6kl_regd_find_country_by_rd((u16) reg_code);  		if (regpair)  			ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n", -				   regpair->regDmnEnum); +				   regpair->reg_domain);  		else  			ath6kl_warn("Regpair not found reg_code 0x%0x\n",  				    reg_code); @@ -1499,7 +1499,6 @@ static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len,  	if ((reply->cac_indication == CAC_INDICATION_ADMISSION_RESP) &&  	    (reply->status_code != IEEE80211_TSPEC_STATUS_ADMISS_ACCEPTED)) { -  		ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion);  		tsinfo = le16_to_cpu(ts->tsinfo);  		tsid = (tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) & @@ -1530,7 +1529,6 @@ static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len,  	 * for delete qos stream from AP  	 */  	else if (reply->cac_indication == CAC_INDICATION_DELETE) { -  		ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion);  		tsinfo = le16_to_cpu(ts->tsinfo);  		ts_id = ((tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) & @@ -2322,7 +2320,7 @@ int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 if_idx, u8 key_index,  	return ret;  } -int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 if_idx, u8 *krk) +int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 if_idx, const u8 *krk)  {  	struct sk_buff *skb;  	struct wmi_add_krk_cmd *cmd; @@ -2479,7 +2477,6 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx)  		goto free_data_skb;  	for (index = 0; index < num_pri_streams; index++) { -  		if (WARN_ON(!data_sync_bufs[index].skb))  			goto free_data_skb; @@ -2704,7 +2701,6 @@ static void ath6kl_wmi_relinquish_implicit_pstream_credits(struct wmi *wmi)  	for (i = 0; i < WMM_NUM_AC; i++) {  		if (stream_exist & (1 << i)) { -  			/*  			 * FIXME: Is this lock & unlock inside  			 * for loop correct? may need rework. @@ -2754,9 +2750,9 @@ static int ath6kl_set_bitrate_mask64(struct wmi *wmi, u8 if_idx,  				mask->control[band].legacy << 4;  		/* copy mcs rate mask */ -		mcsrate = mask->control[band].mcs[1]; +		mcsrate = mask->control[band].ht_mcs[1];  		mcsrate <<= 8; -		mcsrate |= mask->control[band].mcs[0]; +		mcsrate |= mask->control[band].ht_mcs[0];  		ratemask[band] |= mcsrate << 12;  		ratemask[band] |= mcsrate << 28;  	} @@ -2806,7 +2802,7 @@ static int ath6kl_set_bitrate_mask32(struct wmi *wmi, u8 if_idx,  				mask->control[band].legacy << 4;  		/* copy mcs rate mask */ -		mcsrate = mask->control[band].mcs[0]; +		mcsrate = mask->control[band].ht_mcs[0];  		ratemask[band] |= mcsrate << 12;  		ratemask[band] |= mcsrate << 20;  	} @@ -2870,8 +2866,9 @@ int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx,  	if (host_mode == ATH6KL_HOST_MODE_ASLEEP) {  		ath6kl_wmi_relinquish_implicit_pstream_credits(wmi);  		cmd->asleep = cpu_to_le32(1); -	} else +	} else {  		cmd->awake = cpu_to_le32(1); +	}  	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,  				  WMI_SET_HOST_SLEEP_MODE_CMDID, diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index b5f226503ba..bb23fc00111 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -898,7 +898,6 @@ struct wmi_start_scan_cmd {   *  flags here   */  enum wmi_scan_ctrl_flags_bits { -  	/* set if can scan in the connect cmd */  	CONNECT_SCAN_CTRL_FLAGS = 0x01, @@ -1068,7 +1067,7 @@ struct wmi_power_mode_cmd {  } __packed;  /* - * Policy to determnine whether power save failure event should be sent to + * Policy to determine whether power save failure event should be sent to   * host during scanning   */  enum power_save_fail_event_policy { @@ -2617,7 +2616,7 @@ int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 if_idx, u8 key_index,  			  u8 *key_material,  			  u8 key_op_ctrl, u8 *mac_addr,  			  enum wmi_sync_flag sync_flag); -int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 if_idx, u8 *krk); +int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 if_idx, const u8 *krk);  int ath6kl_wmi_deletekey_cmd(struct wmi *wmi, u8 if_idx, u8 key_index);  int ath6kl_wmi_setpmkid_cmd(struct wmi *wmi, u8 if_idx, const u8 *bssid,  			    const u8 *pmkid, bool set); diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 7944c25c9a4..8fcc029a76a 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -65,6 +65,14 @@ config ATH9K_DEBUGFS  	  Also required for changing debug message flags at run time. +config ATH9K_STATION_STATISTICS +	bool "Detailed station statistics" +	depends on ATH9K && ATH9K_DEBUGFS && DEBUG_FS +	select MAC80211_DEBUGFS +	default n +	---help--- +	  This option enables detailed statistics for association stations. +  config ATH9K_DFS_CERTIFIED  	bool "Atheros DFS support for certified platforms"  	depends on ATH9K && CFG80211_CERTIFICATION_ONUS @@ -84,17 +92,33 @@ config ATH9K_DFS_CERTIFIED  	  developed. At this point enabling this option won't do anything  	  except increase code size. -config ATH9K_LEGACY_RATE_CONTROL -	bool "Atheros ath9k rate control" -	depends on ATH9K +config ATH9K_TX99 +	bool "Atheros ath9k TX99 testing support" +	depends on ATH9K_DEBUGFS && CFG80211_CERTIFICATION_ONUS +	default n +	---help--- +	  Say N. This should only be enabled on systems undergoing +	  certification testing and evaluation in a controlled environment. +	  Enabling this will only enable TX99 support, all other modes of +	  operation will be disabled. + +	  TX99 support enables Specific Absorption Rate (SAR) testing. +	  SAR is the unit of measurement for the amount of radio frequency(RF) +	  absorbed by the body when using a wireless device. The RF exposure +	  limits used are expressed in the terms of SAR, which is a measure +	  of the electric and magnetic field strength and power density for +	  transmitters operating at frequencies from 300 kHz to 100 GHz. +	  Regulatory bodies around the world require that wireless device +	  be evaluated to meet the RF exposure limits set forth in the +	  governmental SAR regulations. + +config ATH9K_WOW +	bool "Wake on Wireless LAN support (EXPERIMENTAL)" +	depends on ATH9K && PM  	default n  	---help--- -	  Say Y, if you want to use the ath9k specific rate control -	  module instead of minstrel_ht. Be warned that there are various -	  issues with the ath9k RC and minstrel is a more robust algorithm. -	  Note that even if this option is selected, "ath9k_rate_control" -	  has to be passed to mac80211 using the module parameter, -	  ieee80211_default_rc_algo. +	  This option enables Wake on Wireless LAN support for certain cards. +	  Currently, AR9462 is supported.  config ATH9K_RFKILL  	bool "Atheros ath9k rfkill support" if EXPERT diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 75ee9e7704c..8fcd586d1c3 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -8,16 +8,17 @@ ath9k-y +=	beacon.o \  		antenna.o  ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o -ath9k-$(CONFIG_ATH9K_LEGACY_RATE_CONTROL) += rc.o  ath9k-$(CONFIG_ATH9K_PCI) += pci.o  ath9k-$(CONFIG_ATH9K_AHB) += ahb.o -ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o  ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o -ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += \ -		dfs.o \ -		dfs_pattern_detector.o \ -		dfs_pri_detector.o -ath9k-$(CONFIG_PM_SLEEP) += wow.o +ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o +ath9k-$(CONFIG_ATH9K_TX99) += tx99.o +ath9k-$(CONFIG_ATH9K_WOW) += wow.o + +ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o \ +				 spectral.o + +ath9k-$(CONFIG_ATH9K_STATION_STATISTICS) += debug_sta.o  obj-$(CONFIG_ATH9K) += ath9k.o @@ -43,12 +44,17 @@ ath9k_hw-y:=	\  		ar9003_eeprom.o \  		ar9003_paprd.o +ath9k_hw-$(CONFIG_ATH9K_WOW) += ar9003_wow.o +  ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \  					   ar9003_mci.o  obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o  obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o -ath9k_common-y:=	common.o +ath9k_common-y:=	common.o \ +			common-init.o \ +			common-beacon.o \ +			common-debug.o  ath9k_htc-y +=	htc_hst.o \  		hif_usb.o \ diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 072e4b53106..be3eb2a8d60 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -39,6 +39,10 @@ static const struct platform_device_id ath9k_platform_id_table[] = {  		.name = "qca955x_wmac",  		.driver_data = AR9300_DEVID_QCA955X,  	}, +	{ +		.name = "qca953x_wmac", +		.driver_data = AR9300_DEVID_AR953X, +	},  	{},  }; @@ -54,7 +58,7 @@ static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)  	struct platform_device *pdev = to_platform_device(sc->dev);  	struct ath9k_platform_data *pdata; -	pdata = (struct ath9k_platform_data *) pdev->dev.platform_data; +	pdata = dev_get_platdata(&pdev->dev);  	if (off >= (ARRAY_SIZE(pdata->eeprom_data))) {  		ath_err(common,  			"%s: flash read failed, offset %08x is out of range\n", @@ -84,7 +88,7 @@ static int ath_ahb_probe(struct platform_device *pdev)  	struct ath_hw *ah;  	char hw_name[64]; -	if (!pdev->dev.platform_data) { +	if (!dev_get_platdata(&pdev->dev)) {  		dev_err(&pdev->dev, "no platform data specified\n");  		return -EINVAL;  	} @@ -124,9 +128,6 @@ static int ath_ahb_probe(struct platform_device *pdev)  	sc->mem = mem;  	sc->irq = irq; -	/* Will be cleared in ath9k_start() */ -	set_bit(SC_OP_INVALID, &sc->sc_flags); -  	ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc);  	if (ret) {  		dev_err(&pdev->dev, "request_irq failed\n"); diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index be466b0ef7a..ba502a2d199 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -155,6 +155,9 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel,  		ATH9K_ANI_RSSI_THR_LOW,  		ATH9K_ANI_RSSI_THR_HIGH); +	if (AR_SREV_9100(ah) && immunityLevel < ATH9K_ANI_OFDM_DEF_LEVEL) +		immunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL; +  	if (!scan)  		aniState->ofdmNoiseImmunityLevel = immunityLevel; @@ -176,16 +179,26 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel,  	if (ah->opmode == NL80211_IFTYPE_STATION &&  	    BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_HIGH)  		weak_sig = true; -  	/* -	 * OFDM Weak signal detection is always enabled for AP mode. +	 * Newer chipsets are better at dealing with high PHY error counts - +	 * keep weak signal detection enabled when no RSSI threshold is +	 * available to determine if it is needed (mode != STA)  	 */ -	if (ah->opmode != NL80211_IFTYPE_AP && -	    aniState->ofdmWeakSigDetect != weak_sig) { -		ath9k_hw_ani_control(ah, -				     ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, -				     entry_ofdm->ofdm_weak_signal_on); -	} +	else if (AR_SREV_9300_20_OR_LATER(ah) && +		 ah->opmode != NL80211_IFTYPE_STATION) +		weak_sig = true; + +	/* Older chipsets are more sensitive to high PHY error counts */ +	else if (!AR_SREV_9300_20_OR_LATER(ah) && +		 aniState->ofdmNoiseImmunityLevel >= 8) +		weak_sig = false; + +	if (aniState->ofdmWeakSigDetect != weak_sig) +		ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, +				     weak_sig); + +	if (!AR_SREV_9300_20_OR_LATER(ah)) +		return;  	if (aniState->ofdmNoiseImmunityLevel >= ATH9K_ANI_OFDM_DEF_LEVEL) {  		ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; @@ -225,6 +238,9 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel,  		BEACON_RSSI(ah), ATH9K_ANI_RSSI_THR_LOW,  		ATH9K_ANI_RSSI_THR_HIGH); +	if (AR_SREV_9100(ah) && immunityLevel < ATH9K_ANI_CCK_DEF_LEVEL) +		immunityLevel = ATH9K_ANI_CCK_DEF_LEVEL; +  	if (ah->opmode == NL80211_IFTYPE_STATION &&  	    BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_LOW &&  	    immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI) @@ -308,17 +324,6 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)  	BUG_ON(aniState == NULL);  	ah->stats.ast_ani_reset++; -	/* only allow a subset of functions in AP mode */ -	if (ah->opmode == NL80211_IFTYPE_AP) { -		if (IS_CHAN_2GHZ(chan)) { -			ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | -					    ATH9K_ANI_FIRSTEP_LEVEL); -			if (AR_SREV_9300_20_OR_LATER(ah)) -				ah->ani_function |= ATH9K_ANI_MRC_CCK; -		} else -			ah->ani_function = 0; -	} -  	ofdm_nil = max_t(int, ATH9K_ANI_OFDM_DEF_LEVEL,  			 aniState->ofdmNoiseImmunityLevel);  	cck_nil = max_t(int, ATH9K_ANI_CCK_DEF_LEVEL, @@ -338,10 +343,9 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)  		    aniState->cckNoiseImmunityLevel !=  		    ATH9K_ANI_CCK_DEF_LEVEL) {  			ath_dbg(common, ANI, -				"Restore defaults: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n", +				"Restore defaults: opmode %u chan %d Mhz is_scanning=%d ofdm:%d cck:%d\n",  				ah->opmode,  				chan->channel, -				chan->channelFlags,  				is_scanning,  				aniState->ofdmNoiseImmunityLevel,  				aniState->cckNoiseImmunityLevel); @@ -354,10 +358,9 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)  		 * restore historical levels for this channel  		 */  		ath_dbg(common, ANI, -			"Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n", +			"Restore history: opmode %u chan %d Mhz is_scanning=%d ofdm:%d cck:%d\n",  			ah->opmode,  			chan->channel, -			chan->channelFlags,  			is_scanning,  			aniState->ofdmNoiseImmunityLevel,  			aniState->cckNoiseImmunityLevel); @@ -485,10 +488,17 @@ void ath9k_hw_ani_init(struct ath_hw *ah)  	ath_dbg(common, ANI, "Initialize ANI\n"); -	ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; -	ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW; -	ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH; -	ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW; +	if (AR_SREV_9300_20_OR_LATER(ah)) { +		ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; +		ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW; +		ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH; +		ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW; +	} else { +		ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD; +		ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD; +		ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD; +		ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD; +	}  	ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;  	ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index 21e7b83c3f6..c40965b4c1e 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -22,12 +22,16 @@  /* units are errors per second */  #define ATH9K_ANI_OFDM_TRIG_HIGH           3500  #define ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI 1000 +#define ATH9K_ANI_OFDM_TRIG_HIGH_OLD       500  #define ATH9K_ANI_OFDM_TRIG_LOW           400  #define ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI 900 +#define ATH9K_ANI_OFDM_TRIG_LOW_OLD       200  #define ATH9K_ANI_CCK_TRIG_HIGH           600 +#define ATH9K_ANI_CCK_TRIG_HIGH_OLD       200  #define ATH9K_ANI_CCK_TRIG_LOW            300 +#define ATH9K_ANI_CCK_TRIG_LOW_OLD        100  #define ATH9K_ANI_SPUR_IMMUNE_LVL         3  #define ATH9K_ANI_FIRSTEP_LVL             2 diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c index dd1cc73d794..a3668433dc0 100644 --- a/drivers/net/wireless/ath/ath9k/antenna.c +++ b/drivers/net/wireless/ath/ath9k/antenna.c @@ -332,7 +332,7 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,  		}  		if (antcomb->rssi_lna2 > antcomb->rssi_lna1 + -		    ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA) +		    div_ant_conf->lna1_lna2_switch_delta)  			div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;  		else  			div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; @@ -554,42 +554,22 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,  			ant_conf->fast_div_bias = 0x1;  			break;  		case 0x10: /* LNA2 A-B */ -			if ((antcomb->scan == 0) && -			    (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { -				ant_conf->fast_div_bias = 0x3f; -			} else { -				ant_conf->fast_div_bias = 0x1; -			} +			ant_conf->fast_div_bias = 0x2;  			break;  		case 0x12: /* LNA2 LNA1 */ -			ant_conf->fast_div_bias = 0x39; +			ant_conf->fast_div_bias = 0x3f;  			break;  		case 0x13: /* LNA2 A+B */ -			if ((antcomb->scan == 0) && -			    (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { -				ant_conf->fast_div_bias = 0x3f; -			} else { -				ant_conf->fast_div_bias = 0x1; -			} +			ant_conf->fast_div_bias = 0x2;  			break;  		case 0x20: /* LNA1 A-B */ -			if ((antcomb->scan == 0) && -			    (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { -				ant_conf->fast_div_bias = 0x3f; -			} else { -				ant_conf->fast_div_bias = 0x4; -			} +			ant_conf->fast_div_bias = 0x3;  			break;  		case 0x21: /* LNA1 LNA2 */ -			ant_conf->fast_div_bias = 0x6; +			ant_conf->fast_div_bias = 0x3;  			break;  		case 0x23: /* LNA1 A+B */ -			if ((antcomb->scan == 0) && -			    (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { -				ant_conf->fast_div_bias = 0x3f; -			} else { -				ant_conf->fast_div_bias = 0x6; -			} +			ant_conf->fast_div_bias = 0x3;  			break;  		case 0x30: /* A+B A-B */  			ant_conf->fast_div_bias = 0x1; @@ -638,7 +618,7 @@ static void ath_ant_try_scan(struct ath_ant_comb *antcomb,  		antcomb->rssi_sub = alt_rssi_avg;  		antcomb->scan = false;  		if (antcomb->rssi_lna2 > -		    (antcomb->rssi_lna1 + ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) { +		    (antcomb->rssi_lna1 + conf->lna1_lna2_switch_delta)) {  			/* use LNA2 as main LNA */  			if ((antcomb->rssi_add > antcomb->rssi_lna1) &&  			    (antcomb->rssi_add > antcomb->rssi_sub)) { @@ -744,14 +724,14 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)  	struct ath_ant_comb *antcomb = &sc->ant_comb;  	int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;  	int curr_main_set; -	int main_rssi = rs->rs_rssi_ctl0; -	int alt_rssi = rs->rs_rssi_ctl1; +	int main_rssi = rs->rs_rssi_ctl[0]; +	int alt_rssi = rs->rs_rssi_ctl[1];  	int rx_ant_conf,  main_ant_conf;  	bool short_scan = false, ret; -	rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) & +	rx_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_CURRENT_SHIFT) &  		       ATH_ANT_RX_MASK; -	main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) & +	main_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_MAIN_SHIFT) &  			 ATH_ANT_RX_MASK;  	if (alt_rssi >= antcomb->low_rssi_thresh) { diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 08656473c63..00fb8badbac 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -26,10 +26,6 @@ static const int firstep_table[] =  /* level:  0   1   2   3   4   5   6   7   8  */  	{ -4, -2,  0,  2,  4,  6,  8, 10, 12 }; /* lvl 0-8, default 2 */ -static const int cycpwrThr1_table[] = -/* level:  0   1   2   3   4   5   6   7   8  */ -	{ -6, -4, -2,  0,  2,  4,  6,  8 };     /* lvl 0-7, default 3 */ -  /*   * register values to turn OFDM weak signal detection OFF   */ @@ -626,12 +622,11 @@ static void ar5008_hw_override_ini(struct ath_hw *ah,  		if (AR_SREV_9287_11_OR_LATER(ah))  			val = val & (~AR_PCU_MISC_MODE2_HWWAR2); +		val |= AR_PCU_MISC_MODE2_CFP_IGNORE; +  		REG_WRITE(ah, AR_PCU_MISC_MODE2, val);  	} -	REG_SET_BIT(ah, AR_PHY_CCK_DETECT, -		    AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); -  	if (AR_SREV_9280_20_OR_LATER(ah))  		return;  	/* @@ -667,14 +662,13 @@ static void ar5008_hw_set_channel_regs(struct ath_hw *ah,  	if (IS_CHAN_HT40(chan)) {  		phymode |= AR_PHY_FC_DYN2040_EN; -		if ((chan->chanmode == CHANNEL_A_HT40PLUS) || -		    (chan->chanmode == CHANNEL_G_HT40PLUS)) +		if (IS_CHAN_HT40PLUS(chan))  			phymode |= AR_PHY_FC_DYN2040_PRI_CH;  	}  	REG_WRITE(ah, AR_PHY_TURBO, phymode); -	ath9k_hw_set11nmac2040(ah); +	ath9k_hw_set11nmac2040(ah, chan);  	ENABLE_REGWRITE_BUFFER(ah); @@ -692,31 +686,12 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,  	int i, regWrites = 0;  	u32 modesIndex, freqIndex; -	switch (chan->chanmode) { -	case CHANNEL_A: -	case CHANNEL_A_HT20: -		modesIndex = 1; +	if (IS_CHAN_5GHZ(chan)) {  		freqIndex = 1; -		break; -	case CHANNEL_A_HT40PLUS: -	case CHANNEL_A_HT40MINUS: -		modesIndex = 2; -		freqIndex = 1; -		break; -	case CHANNEL_G: -	case CHANNEL_G_HT20: -	case CHANNEL_B: -		modesIndex = 4; -		freqIndex = 2; -		break; -	case CHANNEL_G_HT40PLUS: -	case CHANNEL_G_HT40MINUS: -		modesIndex = 3; +		modesIndex = IS_CHAN_HT40(chan) ? 2 : 1; +	} else {  		freqIndex = 2; -		break; - -	default: -		return -EINVAL; +		modesIndex = IS_CHAN_HT40(chan) ? 3 : 4;  	}  	/* @@ -815,8 +790,10 @@ static void ar5008_hw_set_rfmode(struct ath_hw *ah, struct ath9k_channel *chan)  	if (chan == NULL)  		return; -	rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan)) -		? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM; +	if (IS_CHAN_2GHZ(chan)) +		rfMode |= AR_PHY_MODE_DYNAMIC; +	else +		rfMode |= AR_PHY_MODE_OFDM;  	if (!AR_SREV_9280_20_OR_LATER(ah))  		rfMode |= (IS_CHAN_5GHZ(chan)) ? @@ -940,7 +917,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,  	struct ath_common *common = ath9k_hw_common(ah);  	struct ath9k_channel *chan = ah->curchan;  	struct ar5416AniState *aniState = &ah->ani; -	s32 value, value2; +	s32 value;  	switch (cmd & ah->ani_function) {  	case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{ @@ -1027,42 +1004,9 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,  	case ATH9K_ANI_FIRSTEP_LEVEL:{  		u32 level = param; -		if (level >= ARRAY_SIZE(firstep_table)) { -			ath_dbg(common, ANI, -				"ATH9K_ANI_FIRSTEP_LEVEL: level out of range (%u > %zu)\n", -				level, ARRAY_SIZE(firstep_table)); -			return false; -		} - -		/* -		 * make register setting relative to default -		 * from INI file & cap value -		 */ -		value = firstep_table[level] - -			firstep_table[ATH9K_ANI_FIRSTEP_LVL] + -			aniState->iniDef.firstep; -		if (value < ATH9K_SIG_FIRSTEP_SETTING_MIN) -			value = ATH9K_SIG_FIRSTEP_SETTING_MIN; -		if (value > ATH9K_SIG_FIRSTEP_SETTING_MAX) -			value = ATH9K_SIG_FIRSTEP_SETTING_MAX; +		value = level;  		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, -			      AR_PHY_FIND_SIG_FIRSTEP, -			      value); -		/* -		 * we need to set first step low register too -		 * make register setting relative to default -		 * from INI file & cap value -		 */ -		value2 = firstep_table[level] - -			 firstep_table[ATH9K_ANI_FIRSTEP_LVL] + -			 aniState->iniDef.firstepLow; -		if (value2 < ATH9K_SIG_FIRSTEP_SETTING_MIN) -			value2 = ATH9K_SIG_FIRSTEP_SETTING_MIN; -		if (value2 > ATH9K_SIG_FIRSTEP_SETTING_MAX) -			value2 = ATH9K_SIG_FIRSTEP_SETTING_MAX; - -		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW, -			      AR_PHY_FIND_SIG_FIRSTEP_LOW, value2); +			      AR_PHY_FIND_SIG_FIRSTEP, value);  		if (level != aniState->firstepLevel) {  			ath_dbg(common, ANI, @@ -1079,7 +1023,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,  				aniState->firstepLevel,  				level,  				ATH9K_ANI_FIRSTEP_LVL, -				value2, +				value,  				aniState->iniDef.firstepLow);  			if (level > aniState->firstepLevel)  				ah->stats.ast_ani_stepup++; @@ -1092,41 +1036,13 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,  	case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{  		u32 level = param; -		if (level >= ARRAY_SIZE(cycpwrThr1_table)) { -			ath_dbg(common, ANI, -				"ATH9K_ANI_SPUR_IMMUNITY_LEVEL: level out of range (%u > %zu)\n", -				level, ARRAY_SIZE(cycpwrThr1_table)); -			return false; -		} -		/* -		 * make register setting relative to default -		 * from INI file & cap value -		 */ -		value = cycpwrThr1_table[level] - -			cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] + -			aniState->iniDef.cycpwrThr1; -		if (value < ATH9K_SIG_SPUR_IMM_SETTING_MIN) -			value = ATH9K_SIG_SPUR_IMM_SETTING_MIN; -		if (value > ATH9K_SIG_SPUR_IMM_SETTING_MAX) -			value = ATH9K_SIG_SPUR_IMM_SETTING_MAX; +		value = (level + 1) * 2;  		REG_RMW_FIELD(ah, AR_PHY_TIMING5, -			      AR_PHY_TIMING5_CYCPWR_THR1, -			      value); +			      AR_PHY_TIMING5_CYCPWR_THR1, value); -		/* -		 * set AR_PHY_EXT_CCA for extension channel -		 * make register setting relative to default -		 * from INI file & cap value -		 */ -		value2 = cycpwrThr1_table[level] - -			 cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] + -			 aniState->iniDef.cycpwrThr1Ext; -		if (value2 < ATH9K_SIG_SPUR_IMM_SETTING_MIN) -			value2 = ATH9K_SIG_SPUR_IMM_SETTING_MIN; -		if (value2 > ATH9K_SIG_SPUR_IMM_SETTING_MAX) -			value2 = ATH9K_SIG_SPUR_IMM_SETTING_MAX; -		REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, -			      AR_PHY_EXT_TIMING5_CYCPWR_THR1, value2); +		if (IS_CHAN_HT40(ah->curchan)) +			REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, +				      AR_PHY_EXT_TIMING5_CYCPWR_THR1, value);  		if (level != aniState->spurImmunityLevel) {  			ath_dbg(common, ANI, @@ -1143,7 +1059,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,  				aniState->spurImmunityLevel,  				level,  				ATH9K_ANI_SPUR_IMMUNE_LVL, -				value2, +				value,  				aniState->iniDef.cycpwrThr1Ext);  			if (level > aniState->spurImmunityLevel)  				ah->stats.ast_ani_spurup++; @@ -1219,12 +1135,11 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah)  	iniDef = &aniState->iniDef; -	ath_dbg(common, ANI, "ver %d.%d opmode %u chan %d Mhz/0x%x\n", +	ath_dbg(common, ANI, "ver %d.%d opmode %u chan %d Mhz\n",  		ah->hw_version.macVersion,  		ah->hw_version.macRev,  		ah->opmode, -		chan->channel, -		chan->channelFlags); +		chan->channel);  	val = REG_READ(ah, AR_PHY_SFCORR);  	iniDef->m1Thresh = MS(val, AR_PHY_SFCORR_M1_THRESH); diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index 9f589744a9f..cdc74005650 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -33,15 +33,12 @@ static bool ar9002_hw_is_cal_supported(struct ath_hw *ah,  	bool supported = false;  	switch (ah->supp_cals & cal_type) {  	case IQ_MISMATCH_CAL: -		/* Run IQ Mismatch for non-CCK only */ -		if (!IS_CHAN_B(chan)) -			supported = true; +		supported = true;  		break;  	case ADC_GAIN_CAL:  	case ADC_DC_CAL:  		/* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */ -		if (!IS_CHAN_B(chan) && -		    !((IS_CHAN_2GHZ(chan) || IS_CHAN_A_FAST_CLOCK(ah, chan)) && +		if (!((IS_CHAN_2GHZ(chan) || IS_CHAN_A_FAST_CLOCK(ah, chan)) &&  		      IS_CHAN_HT20(chan)))  			supported = true;  		break; @@ -671,7 +668,7 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah,  	nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF);  	if (ah->caldata) -		nfcal_pending = ah->caldata->nfcal_pending; +		nfcal_pending = test_bit(NFCAL_PENDING, &ah->caldata->cal_flags);  	if (currCal && !nfcal &&  	    (currCal->calState == CAL_RUNNING || @@ -861,7 +858,7 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)  	ar9002_hw_pa_cal(ah, true);  	if (ah->caldata) -		ah->caldata->nfcal_pending = true; +		set_bit(NFCAL_PENDING, &ah->caldata->cal_flags);  	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c index fb61b081d17..d480d2f3e18 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c @@ -32,12 +32,8 @@ static int ar9002_hw_init_mode_regs(struct ath_hw *ah)  		return 0;  	} -	if (ah->config.pcie_clock_req) -		INIT_INI_ARRAY(&ah->iniPcieSerdes, -			   ar9280PciePhy_clkreq_off_L1_9280); -	else -		INIT_INI_ARRAY(&ah->iniPcieSerdes, -			   ar9280PciePhy_clkreq_always_on_L1_9280); +	INIT_INI_ARRAY(&ah->iniPcieSerdes, +		       ar9280PciePhy_clkreq_always_on_L1_9280);  	if (AR_SREV_9287_11_OR_LATER(ah)) {  		INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1); @@ -387,6 +383,20 @@ void ar9002_hw_enable_async_fifo(struct ath_hw *ah)  	}  } +static void ar9002_hw_init_hang_checks(struct ath_hw *ah) +{ +	if (AR_SREV_9100(ah) || AR_SREV_9160(ah)) { +		ah->config.hw_hang_checks |= HW_BB_RIFS_HANG; +		ah->config.hw_hang_checks |= HW_BB_DFS_HANG; +	} + +	if (AR_SREV_9280(ah)) +		ah->config.hw_hang_checks |= HW_BB_RX_CLEAR_STUCK_HANG; + +	if (AR_SREV_5416(ah) || AR_SREV_9100(ah) || AR_SREV_9160(ah)) +		ah->config.hw_hang_checks |= HW_MAC_HANG; +} +  /* Sets up the AR5008/AR9001/AR9002 hardware familiy callbacks */  int ar9002_hw_attach_ops(struct ath_hw *ah)  { @@ -399,6 +409,7 @@ int ar9002_hw_attach_ops(struct ath_hw *ah)  		return ret;  	priv_ops->init_mode_gain_regs = ar9002_hw_init_mode_gain_regs; +	priv_ops->init_hang_checks = ar9002_hw_init_hang_checks;  	ops->config_pci_powersave = ar9002_hw_configpcipowersave; @@ -419,28 +430,10 @@ void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan)  	u32 modesIndex;  	int i; -	switch (chan->chanmode) { -	case CHANNEL_A: -	case CHANNEL_A_HT20: -		modesIndex = 1; -		break; -	case CHANNEL_A_HT40PLUS: -	case CHANNEL_A_HT40MINUS: -		modesIndex = 2; -		break; -	case CHANNEL_G: -	case CHANNEL_G_HT20: -	case CHANNEL_B: -		modesIndex = 4; -		break; -	case CHANNEL_G_HT40PLUS: -	case CHANNEL_G_HT40MINUS: -		modesIndex = 3; -		break; - -	default: -		return; -	} +	if (IS_CHAN_5GHZ(chan)) +		modesIndex = IS_CHAN_HT40(chan) ? 2 : 1; +	else +		modesIndex = IS_CHAN_HT40(chan) ? 3 : 4;  	ENABLE_REGWRITE_BUFFER(ah); diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index 8d78253c26c..741b38ddcb3 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -29,7 +29,8 @@ static void ar9002_hw_set_desc_link(void *ds, u32 ds_link)  	((struct ath_desc*) ds)->ds_link = ds_link;  } -static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) +static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked, +			      u32 *sync_cause_p)  {  	u32 isr = 0;  	u32 mask2 = 0; @@ -76,9 +77,16 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)  				mask2 |= ATH9K_INT_CST;  			if (isr2 & AR_ISR_S2_TSFOOR)  				mask2 |= ATH9K_INT_TSFOOR; + +			if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) { +				REG_WRITE(ah, AR_ISR_S2, isr2); +				isr &= ~AR_ISR_BCNMISC; +			}  		} -		isr = REG_READ(ah, AR_ISR_RAC); +		if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED) +			isr = REG_READ(ah, AR_ISR_RAC); +  		if (isr == 0xffffffff) {  			*masked = 0;  			return false; @@ -97,11 +105,23 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)  			*masked |= ATH9K_INT_TX; -			s0_s = REG_READ(ah, AR_ISR_S0_S); +			if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED) { +				s0_s = REG_READ(ah, AR_ISR_S0_S); +				s1_s = REG_READ(ah, AR_ISR_S1_S); +			} else { +				s0_s = REG_READ(ah, AR_ISR_S0); +				REG_WRITE(ah, AR_ISR_S0, s0_s); +				s1_s = REG_READ(ah, AR_ISR_S1); +				REG_WRITE(ah, AR_ISR_S1, s1_s); + +				isr &= ~(AR_ISR_TXOK | +					 AR_ISR_TXDESC | +					 AR_ISR_TXERR | +					 AR_ISR_TXEOL); +			} +  			ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXOK);  			ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC); - -			s1_s = REG_READ(ah, AR_ISR_S1_S);  			ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR);  			ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL);  		} @@ -114,13 +134,15 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)  		*masked |= mask2;  	} -	if (AR_SREV_9100(ah)) -		return true; - -	if (isr & AR_ISR_GENTMR) { +	if (!AR_SREV_9100(ah) && (isr & AR_ISR_GENTMR)) {  		u32 s5_s; -		s5_s = REG_READ(ah, AR_ISR_S5_S); +		if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED) { +			s5_s = REG_READ(ah, AR_ISR_S5_S); +		} else { +			s5_s = REG_READ(ah, AR_ISR_S5); +		} +  		ah->intr_gen_timer_trigger =  				MS(s5_s, AR_ISR_S5_GENTIMER_TRIG); @@ -133,10 +155,24 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)  		if ((s5_s & AR_ISR_S5_TIM_TIMER) &&  		    !(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))  			*masked |= ATH9K_INT_TIM_TIMER; + +		if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) { +			REG_WRITE(ah, AR_ISR_S5, s5_s); +			isr &= ~AR_ISR_GENTMR; +		}  	} +	if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) { +		REG_WRITE(ah, AR_ISR, isr); +		REG_READ(ah, AR_ISR); +	} + +	if (AR_SREV_9100(ah)) +		return true; +  	if (sync_cause) { -		ath9k_debug_sync_cause(common, sync_cause); +		if (sync_cause_p) +			*sync_cause_p = sync_cause;  		fatal_int =  			(sync_cause &  			 (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR)) diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c index 1fc1fa955d4..9a2afa2c690 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c @@ -201,7 +201,6 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah,  	ath9k_hw_get_channel_centers(ah, chan, ¢ers);  	freq = centers.synth_center; -	ah->config.spurmode = SPUR_ENABLE_EEPROM;  	for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {  		cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz); @@ -485,7 +484,7 @@ static void ar9002_hw_do_getnf(struct ath_hw *ah,  	if (IS_CHAN_HT40(ah->curchan))  		nfarray[3] = sign_extend32(nf, 8); -	if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) +	if (!(ah->rxchainmask & BIT(1)))  		return;  	nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), AR9280_PHY_CH1_MINCCA_PWR); @@ -532,6 +531,7 @@ static void ar9002_hw_antdiv_comb_conf_get(struct ath_hw *ah,  				 AR_PHY_9285_ANT_DIV_ALT_LNACONF_S;  	antconf->fast_div_bias = (regval & AR_PHY_9285_FAST_DIV_BIAS) >>  				  AR_PHY_9285_FAST_DIV_BIAS_S; +	antconf->lna1_lna2_switch_delta = -1;  	antconf->lna1_lna2_delta = -3;  	antconf->div_group = 0;  } @@ -679,6 +679,26 @@ static void ar9002_hw_spectral_scan_wait(struct ath_hw *ah)  	}  } +static void ar9002_hw_tx99_start(struct ath_hw *ah, u32 qnum) +{ +	REG_SET_BIT(ah, 0x9864, 0x7f000); +	REG_SET_BIT(ah, 0x9924, 0x7f00fe); +	REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); +	REG_WRITE(ah, AR_CR, AR_CR_RXD); +	REG_WRITE(ah, AR_DLCL_IFS(qnum), 0); +	REG_WRITE(ah, AR_D_GBL_IFS_SIFS, 20); +	REG_WRITE(ah, AR_D_GBL_IFS_EIFS, 20); +	REG_WRITE(ah, AR_D_FPCTL, 0x10|qnum); +	REG_WRITE(ah, AR_TIME_OUT, 0x00000400); +	REG_WRITE(ah, AR_DRETRY_LIMIT(qnum), 0xffffffff); +	REG_SET_BIT(ah, AR_QMISC(qnum), AR_Q_MISC_DCU_EARLY_TERM_REQ); +} + +static void ar9002_hw_tx99_stop(struct ath_hw *ah) +{ +	REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); +} +  void ar9002_hw_attach_phy_ops(struct ath_hw *ah)  {  	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); @@ -700,6 +720,8 @@ void ar9002_hw_attach_phy_ops(struct ath_hw *ah)  #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT  	ops->set_bt_ant_diversity = ar9002_hw_set_bt_ant_diversity;  #endif +	ops->tx99_start = ar9002_hw_tx99_start; +	ops->tx99_stop = ar9002_hw_tx99_stop;  	ar9002_hw_set_nf_limits(ah);  } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index 7546b9a7dcb..c38399bc9aa 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -303,7 +303,7 @@ static const u32 ar9300_2p2_mac_postamble[][5] = {  	{0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38},  	{0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},  	{0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, -	{0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, +	{0x00008120, 0x18f04800, 0x18f04800, 0x18f04810, 0x18f04810},  	{0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a},  	{0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},  }; @@ -352,7 +352,7 @@ static const u32 ar9300_2p2_baseband_postamble[][5] = {  	{0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},  	{0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},  	{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, -	{0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982}, +	{0x0000a2d0, 0x00041983, 0x00041983, 0x00041981, 0x00041982},  	{0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},  	{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},  	{0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, @@ -378,9 +378,9 @@ static const u32 ar9300_2p2_baseband_core[][2] = {  	{0x00009814, 0x9280c00a},  	{0x00009818, 0x00000000},  	{0x0000981c, 0x00020028}, -	{0x00009834, 0x6400a290}, +	{0x00009834, 0x6400a190},  	{0x00009838, 0x0108ecff}, -	{0x0000983c, 0x0d000600}, +	{0x0000983c, 0x14000600},  	{0x00009880, 0x201fff00},  	{0x00009884, 0x00001042},  	{0x000098a4, 0x00200400}, @@ -401,7 +401,7 @@ static const u32 ar9300_2p2_baseband_core[][2] = {  	{0x00009d04, 0x40206c10},  	{0x00009d08, 0x009c4060},  	{0x00009d0c, 0x9883800a}, -	{0x00009d10, 0x01834061}, +	{0x00009d10, 0x01884061},  	{0x00009d14, 0x00c0040b},  	{0x00009d18, 0x00000000},  	{0x00009e08, 0x0038230c}, @@ -410,7 +410,7 @@ static const u32 ar9300_2p2_baseband_core[][2] = {  	{0x00009e30, 0x06336f77},  	{0x00009e34, 0x6af6532f},  	{0x00009e38, 0x0cc80c00}, -	{0x00009e40, 0x0d261820}, +	{0x00009e40, 0x0d261800},  	{0x00009e4c, 0x00001004},  	{0x00009e50, 0x00ff03f1},  	{0x00009e54, 0x00000000}, @@ -459,7 +459,7 @@ static const u32 ar9300_2p2_baseband_core[][2] = {  	{0x0000a3e8, 0x20202020},  	{0x0000a3ec, 0x20202020},  	{0x0000a3f0, 0x00000000}, -	{0x0000a3f4, 0x00000246}, +	{0x0000a3f4, 0x00000000},  	{0x0000a3f8, 0x0c9bd380},  	{0x0000a3fc, 0x000f0f01},  	{0x0000a400, 0x8fa91f01}, @@ -534,107 +534,107 @@ static const u32 ar9300_2p2_baseband_core[][2] = {  static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {  	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ -	{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, -	{0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, -	{0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, +	{0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, +	{0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, +	{0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},  	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, -	{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, -	{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, -	{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, -	{0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, -	{0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, -	{0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, -	{0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, -	{0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, -	{0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, -	{0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, -	{0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, -	{0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, -	{0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, -	{0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, -	{0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, -	{0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, -	{0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, -	{0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, -	{0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, -	{0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, -	{0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83}, -	{0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, -	{0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, -	{0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, -	{0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, -	{0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, -	{0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, -	{0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, -	{0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, -	{0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, -	{0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, -	{0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, -	{0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, -	{0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, -	{0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, -	{0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, -	{0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, -	{0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, -	{0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, -	{0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, -	{0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, -	{0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, -	{0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, -	{0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, -	{0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, -	{0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, -	{0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, -	{0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, -	{0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, -	{0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, -	{0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, -	{0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, -	{0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, -	{0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, -	{0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, -	{0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, -	{0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, -	{0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, -	{0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, -	{0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, -	{0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, -	{0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, -	{0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, -	{0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, -	{0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, +	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, +	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, +	{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, +	{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, +	{0x0000a510, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202}, +	{0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400}, +	{0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402}, +	{0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404}, +	{0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603}, +	{0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02}, +	{0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04}, +	{0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20}, +	{0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20}, +	{0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22}, +	{0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24}, +	{0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640}, +	{0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660}, +	{0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861}, +	{0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81}, +	{0x0000a54c, 0x5e08442e, 0x5e08442e, 0x47001a83, 0x47001a83}, +	{0x0000a550, 0x620a4431, 0x620a4431, 0x4a001c84, 0x4a001c84}, +	{0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3}, +	{0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5}, +	{0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9}, +	{0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb}, +	{0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, +	{0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, +	{0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, +	{0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, +	{0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, +	{0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, +	{0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, +	{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, +	{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, +	{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, +	{0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, +	{0x0000a590, 0x15800028, 0x15800028, 0x0f800202, 0x0f800202}, +	{0x0000a594, 0x1b80002b, 0x1b80002b, 0x12800400, 0x12800400}, +	{0x0000a598, 0x1f820028, 0x1f820028, 0x16800402, 0x16800402}, +	{0x0000a59c, 0x2582002b, 0x2582002b, 0x19800404, 0x19800404}, +	{0x0000a5a0, 0x2a84002a, 0x2a84002a, 0x1c800603, 0x1c800603}, +	{0x0000a5a4, 0x2e86002a, 0x2e86002a, 0x21800a02, 0x21800a02}, +	{0x0000a5a8, 0x3382202d, 0x3382202d, 0x25800a04, 0x25800a04}, +	{0x0000a5ac, 0x3884202c, 0x3884202c, 0x28800a20, 0x28800a20}, +	{0x0000a5b0, 0x3c86202c, 0x3c86202c, 0x2c800e20, 0x2c800e20}, +	{0x0000a5b4, 0x4188202d, 0x4188202d, 0x30800e22, 0x30800e22}, +	{0x0000a5b8, 0x4586402d, 0x4586402d, 0x34800e24, 0x34800e24}, +	{0x0000a5bc, 0x4986222d, 0x4986222d, 0x38801640, 0x38801640}, +	{0x0000a5c0, 0x4d862231, 0x4d862231, 0x3c801660, 0x3c801660}, +	{0x0000a5c4, 0x50882231, 0x50882231, 0x3f801861, 0x3f801861}, +	{0x0000a5c8, 0x5688422e, 0x5688422e, 0x43801a81, 0x43801a81}, +	{0x0000a5cc, 0x5e88442e, 0x5e88442e, 0x47801a83, 0x47801a83}, +	{0x0000a5d0, 0x628a4431, 0x628a4431, 0x4a801c84, 0x4a801c84}, +	{0x0000a5d4, 0x648a4432, 0x648a4432, 0x4e801ce3, 0x4e801ce3}, +	{0x0000a5d8, 0x688a4434, 0x688a4434, 0x52801ce5, 0x52801ce5}, +	{0x0000a5dc, 0x6c8a6434, 0x6c8a6434, 0x56801ce9, 0x56801ce9}, +	{0x0000a5e0, 0x6f8a6633, 0x6f8a6633, 0x5a801ceb, 0x5a801ceb}, +	{0x0000a5e4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, +	{0x0000a5e8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, +	{0x0000a5ec, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, +	{0x0000a5f0, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, +	{0x0000a5f4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, +	{0x0000a5f8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, +	{0x0000a5fc, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},  	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},  	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, -	{0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, -	{0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, -	{0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, -	{0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, -	{0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, -	{0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, -	{0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, -	{0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, -	{0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, -	{0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, -	{0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, -	{0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, -	{0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, -	{0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, +	{0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, +	{0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, +	{0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, +	{0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000}, +	{0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501}, +	{0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501}, +	{0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03}, +	{0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, +	{0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04}, +	{0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, +	{0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, +	{0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, +	{0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, +	{0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, +	{0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, +	{0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, +	{0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},  	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, -	{0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, -	{0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, -	{0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, +	{0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, +	{0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, +	{0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},  	{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},  	{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, -	{0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, +	{0x00016048, 0x61200001, 0x61200001, 0x66480001, 0x66480001},  	{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},  	{0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, -	{0x00016448, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, +	{0x00016448, 0x61200001, 0x61200001, 0x66480001, 0x66480001},  	{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},  	{0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, -	{0x00016848, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, +	{0x00016848, 0x61200001, 0x61200001, 0x66480001, 0x66480001},  	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},  }; @@ -644,7 +644,7 @@ static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {  	{0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},  	{0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},  	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, -	{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, +	{0x0000a410, 0x000050d4, 0x000050d4, 0x000050d9, 0x000050d9},  	{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},  	{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},  	{0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, @@ -1086,8 +1086,8 @@ static const u32 ar9300Common_rx_gain_table_2p2[][2] = {  	{0x0000b074, 0x00000000},  	{0x0000b078, 0x00000000},  	{0x0000b07c, 0x00000000}, -	{0x0000b080, 0x2a2d2f32}, -	{0x0000b084, 0x21232328}, +	{0x0000b080, 0x23232323}, +	{0x0000b084, 0x21232323},  	{0x0000b088, 0x19191c1e},  	{0x0000b08c, 0x12141417},  	{0x0000b090, 0x07070e0e}, @@ -1385,9 +1385,9 @@ static const u32 ar9300_2p2_mac_core[][2] = {  	{0x000081f8, 0x00000000},  	{0x000081fc, 0x00000000},  	{0x00008240, 0x00100000}, -	{0x00008244, 0x0010f424}, +	{0x00008244, 0x0010f400},  	{0x00008248, 0x00000800}, -	{0x0000824c, 0x0001e848}, +	{0x0000824c, 0x0001e800},  	{0x00008250, 0x00000000},  	{0x00008254, 0x00000000},  	{0x00008258, 0x00000000}, @@ -1726,16 +1726,30 @@ static const u32 ar9300PciePhy_pll_on_clkreq_disable_L1_2p2[][2] = {  static const u32 ar9300PciePhy_clkreq_enable_L1_2p2[][2] = {  	/* Addr      allmodes  */ -	{0x00004040, 0x08253e5e}, +	{0x00004040, 0x0825365e},  	{0x00004040, 0x0008003b},  	{0x00004044, 0x00000000},  };  static const u32 ar9300PciePhy_clkreq_disable_L1_2p2[][2] = {  	/* Addr      allmodes  */ -	{0x00004040, 0x08213e5e}, +	{0x00004040, 0x0821365e},  	{0x00004040, 0x0008003b},  	{0x00004044, 0x00000000},  }; +static const u32 ar9300_2p2_baseband_core_txfir_coeff_japan_2484[][2] = { +	/* Addr      allmodes  */ +	{0x0000a398, 0x00000000}, +	{0x0000a39c, 0x6f7f0301}, +	{0x0000a3a0, 0xca9228ee}, +}; + +static const u32 ar9300_2p2_baseband_postamble_dfs_channel[][3] = { +	/* Addr      5G          2G        */ +	{0x00009824, 0x5ac668d0, 0x5ac668d0}, +	{0x00009e0c, 0x6d4000e2, 0x6d4000e2}, +	{0x00009e14, 0x37b9625e, 0x37b9625e}, +}; +  #endif /* INITVALS_9003_2P2_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_buffalo_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_buffalo_initvals.h new file mode 100644 index 00000000000..59cf738f70d --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_buffalo_initvals.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 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 INITVALS_9003_BUFFALO_H +#define INITVALS_9003_BUFFALO_H + +static const u32 ar9300Modes_high_power_tx_gain_table_buffalo[][5] = { +	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ +	{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, +	{0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, +	{0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, +	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, +	{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, +	{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, +	{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, +	{0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, +	{0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, +	{0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, +	{0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, +	{0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, +	{0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, +	{0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, +	{0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, +	{0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, +	{0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, +	{0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, +	{0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, +	{0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, +	{0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, +	{0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, +	{0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, +	{0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, +	{0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83}, +	{0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, +	{0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, +	{0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, +	{0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, +	{0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, +	{0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, +	{0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, +	{0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, +	{0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, +	{0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, +	{0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, +	{0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, +	{0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, +	{0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, +	{0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, +	{0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, +	{0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, +	{0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, +	{0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, +	{0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, +	{0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, +	{0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, +	{0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, +	{0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, +	{0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, +	{0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, +	{0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, +	{0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, +	{0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, +	{0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, +	{0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, +	{0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, +	{0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, +	{0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, +	{0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, +	{0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, +	{0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, +	{0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, +	{0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, +	{0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, +	{0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, +	{0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, +	{0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, +	{0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, +	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, +	{0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, +	{0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, +	{0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, +	{0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, +	{0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, +	{0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, +	{0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, +	{0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, +	{0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, +	{0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, +	{0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, +	{0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, +	{0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, +	{0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, +	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, +	{0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, +	{0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, +	{0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, +	{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, +	{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, +	{0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, +	{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, +	{0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, +	{0x00016448, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, +	{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, +	{0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, +	{0x00016848, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, +	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, +}; + +#endif /* INITVALS_9003_BUFFALO_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 6988e1d081f..ac8301ef524 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -23,10 +23,11 @@  #define MAX_MEASUREMENT	MAX_IQCAL_MEASUREMENT  #define MAX_MAG_DELTA	11  #define MAX_PHS_DELTA	10 +#define MAXIQCAL        3  struct coeff { -	int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; -	int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; +	int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL]; +	int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL];  	int iqc_coeff[2];  }; @@ -326,6 +327,224 @@ static void ar9003_hw_init_cal_settings(struct ath_hw *ah)  	ah->supp_cals = IQ_MISMATCH_CAL;  } +#define OFF_UPPER_LT 24 +#define OFF_LOWER_LT 7 + +static bool ar9003_hw_dynamic_osdac_selection(struct ath_hw *ah, +					      bool txiqcal_done) +{ +	struct ath_common *common = ath9k_hw_common(ah); +	int ch0_done, osdac_ch0, dc_off_ch0_i1, dc_off_ch0_q1, dc_off_ch0_i2, +		dc_off_ch0_q2, dc_off_ch0_i3, dc_off_ch0_q3; +	int ch1_done, osdac_ch1, dc_off_ch1_i1, dc_off_ch1_q1, dc_off_ch1_i2, +		dc_off_ch1_q2, dc_off_ch1_i3, dc_off_ch1_q3; +	int ch2_done, osdac_ch2, dc_off_ch2_i1, dc_off_ch2_q1, dc_off_ch2_i2, +		dc_off_ch2_q2, dc_off_ch2_i3, dc_off_ch2_q3; +	bool status; +	u32 temp, val; + +	/* +	 * Clear offset and IQ calibration, run AGC cal. +	 */ +	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, +		    AR_PHY_AGC_CONTROL_OFFSET_CAL); +	REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0, +		    AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); +	REG_WRITE(ah, AR_PHY_AGC_CONTROL, +		  REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL); + +	status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, +			       AR_PHY_AGC_CONTROL_CAL, +			       0, AH_WAIT_TIMEOUT); +	if (!status) { +		ath_dbg(common, CALIBRATE, +			"AGC cal without offset cal failed to complete in 1ms"); +		return false; +	} + +	/* +	 * Allow only offset calibration and disable the others +	 * (Carrier Leak calibration, TX Filter calibration and +	 *  Peak Detector offset calibration). +	 */ +	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, +		    AR_PHY_AGC_CONTROL_OFFSET_CAL); +	REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, +		    AR_PHY_CL_CAL_ENABLE); +	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, +		    AR_PHY_AGC_CONTROL_FLTR_CAL); +	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, +		    AR_PHY_AGC_CONTROL_PKDET_CAL); + +	ch0_done = 0; +	ch1_done = 0; +	ch2_done = 0; + +	while ((ch0_done == 0) || (ch1_done == 0) || (ch2_done == 0)) { +		osdac_ch0 = (REG_READ(ah, AR_PHY_65NM_CH0_BB1) >> 30) & 0x3; +		osdac_ch1 = (REG_READ(ah, AR_PHY_65NM_CH1_BB1) >> 30) & 0x3; +		osdac_ch2 = (REG_READ(ah, AR_PHY_65NM_CH2_BB1) >> 30) & 0x3; + +		REG_SET_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + +		REG_WRITE(ah, AR_PHY_AGC_CONTROL, +			  REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL); + +		status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, +				       AR_PHY_AGC_CONTROL_CAL, +				       0, AH_WAIT_TIMEOUT); +		if (!status) { +			ath_dbg(common, CALIBRATE, +				"DC offset cal failed to complete in 1ms"); +			return false; +		} + +		REG_CLR_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + +		/* +		 * High gain. +		 */ +		REG_WRITE(ah, AR_PHY_65NM_CH0_BB3, +			  ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (1 << 8))); +		REG_WRITE(ah, AR_PHY_65NM_CH1_BB3, +			  ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (1 << 8))); +		REG_WRITE(ah, AR_PHY_65NM_CH2_BB3, +			  ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (1 << 8))); + +		temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3); +		dc_off_ch0_i1 = (temp >> 26) & 0x1f; +		dc_off_ch0_q1 = (temp >> 21) & 0x1f; + +		temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3); +		dc_off_ch1_i1 = (temp >> 26) & 0x1f; +		dc_off_ch1_q1 = (temp >> 21) & 0x1f; + +		temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3); +		dc_off_ch2_i1 = (temp >> 26) & 0x1f; +		dc_off_ch2_q1 = (temp >> 21) & 0x1f; + +		/* +		 * Low gain. +		 */ +		REG_WRITE(ah, AR_PHY_65NM_CH0_BB3, +			  ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (2 << 8))); +		REG_WRITE(ah, AR_PHY_65NM_CH1_BB3, +			  ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (2 << 8))); +		REG_WRITE(ah, AR_PHY_65NM_CH2_BB3, +			  ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (2 << 8))); + +		temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3); +		dc_off_ch0_i2 = (temp >> 26) & 0x1f; +		dc_off_ch0_q2 = (temp >> 21) & 0x1f; + +		temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3); +		dc_off_ch1_i2 = (temp >> 26) & 0x1f; +		dc_off_ch1_q2 = (temp >> 21) & 0x1f; + +		temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3); +		dc_off_ch2_i2 = (temp >> 26) & 0x1f; +		dc_off_ch2_q2 = (temp >> 21) & 0x1f; + +		/* +		 * Loopback. +		 */ +		REG_WRITE(ah, AR_PHY_65NM_CH0_BB3, +			  ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (3 << 8))); +		REG_WRITE(ah, AR_PHY_65NM_CH1_BB3, +			  ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (3 << 8))); +		REG_WRITE(ah, AR_PHY_65NM_CH2_BB3, +			  ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (3 << 8))); + +		temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3); +		dc_off_ch0_i3 = (temp >> 26) & 0x1f; +		dc_off_ch0_q3 = (temp >> 21) & 0x1f; + +		temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3); +		dc_off_ch1_i3 = (temp >> 26) & 0x1f; +		dc_off_ch1_q3 = (temp >> 21) & 0x1f; + +		temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3); +		dc_off_ch2_i3 = (temp >> 26) & 0x1f; +		dc_off_ch2_q3 = (temp >> 21) & 0x1f; + +		if ((dc_off_ch0_i1 > OFF_UPPER_LT) || (dc_off_ch0_i1 < OFF_LOWER_LT) || +		    (dc_off_ch0_i2 > OFF_UPPER_LT) || (dc_off_ch0_i2 < OFF_LOWER_LT) || +		    (dc_off_ch0_i3 > OFF_UPPER_LT) || (dc_off_ch0_i3 < OFF_LOWER_LT) || +		    (dc_off_ch0_q1 > OFF_UPPER_LT) || (dc_off_ch0_q1 < OFF_LOWER_LT) || +		    (dc_off_ch0_q2 > OFF_UPPER_LT) || (dc_off_ch0_q2 < OFF_LOWER_LT) || +		    (dc_off_ch0_q3 > OFF_UPPER_LT) || (dc_off_ch0_q3 < OFF_LOWER_LT)) { +			if (osdac_ch0 == 3) { +				ch0_done = 1; +			} else { +				osdac_ch0++; + +				val = REG_READ(ah, AR_PHY_65NM_CH0_BB1) & 0x3fffffff; +				val |= (osdac_ch0 << 30); +				REG_WRITE(ah, AR_PHY_65NM_CH0_BB1, val); + +				ch0_done = 0; +			} +		} else { +			ch0_done = 1; +		} + +		if ((dc_off_ch1_i1 > OFF_UPPER_LT) || (dc_off_ch1_i1 < OFF_LOWER_LT) || +		    (dc_off_ch1_i2 > OFF_UPPER_LT) || (dc_off_ch1_i2 < OFF_LOWER_LT) || +		    (dc_off_ch1_i3 > OFF_UPPER_LT) || (dc_off_ch1_i3 < OFF_LOWER_LT) || +		    (dc_off_ch1_q1 > OFF_UPPER_LT) || (dc_off_ch1_q1 < OFF_LOWER_LT) || +		    (dc_off_ch1_q2 > OFF_UPPER_LT) || (dc_off_ch1_q2 < OFF_LOWER_LT) || +		    (dc_off_ch1_q3 > OFF_UPPER_LT) || (dc_off_ch1_q3 < OFF_LOWER_LT)) { +			if (osdac_ch1 == 3) { +				ch1_done = 1; +			} else { +				osdac_ch1++; + +				val = REG_READ(ah, AR_PHY_65NM_CH1_BB1) & 0x3fffffff; +				val |= (osdac_ch1 << 30); +				REG_WRITE(ah, AR_PHY_65NM_CH1_BB1, val); + +				ch1_done = 0; +			} +		} else { +			ch1_done = 1; +		} + +		if ((dc_off_ch2_i1 > OFF_UPPER_LT) || (dc_off_ch2_i1 < OFF_LOWER_LT) || +		    (dc_off_ch2_i2 > OFF_UPPER_LT) || (dc_off_ch2_i2 < OFF_LOWER_LT) || +		    (dc_off_ch2_i3 > OFF_UPPER_LT) || (dc_off_ch2_i3 < OFF_LOWER_LT) || +		    (dc_off_ch2_q1 > OFF_UPPER_LT) || (dc_off_ch2_q1 < OFF_LOWER_LT) || +		    (dc_off_ch2_q2 > OFF_UPPER_LT) || (dc_off_ch2_q2 < OFF_LOWER_LT) || +		    (dc_off_ch2_q3 > OFF_UPPER_LT) || (dc_off_ch2_q3 < OFF_LOWER_LT)) { +			if (osdac_ch2 == 3) { +				ch2_done = 1; +			} else { +				osdac_ch2++; + +				val = REG_READ(ah, AR_PHY_65NM_CH2_BB1) & 0x3fffffff; +				val |= (osdac_ch2 << 30); +				REG_WRITE(ah, AR_PHY_65NM_CH2_BB1, val); + +				ch2_done = 0; +			} +		} else { +			ch2_done = 1; +		} +	} + +	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, +		    AR_PHY_AGC_CONTROL_OFFSET_CAL); +	REG_SET_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + +	/* +	 * We don't need to check txiqcal_done here since it is always +	 * set for AR9550. +	 */ +	REG_SET_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0, +		    AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); + +	return true; +} +  /*   * solve 4x4 linear equation used in loopback iq cal.   */ @@ -347,7 +566,7 @@ static bool ar9003_hw_solve_iq_cal(struct ath_hw *ah,  	const s32 result_shift = 1 << 15;  	struct ath_common *common = ath9k_hw_common(ah); -	f2 = (f1 * f1 + f3 * f3) / result_shift; +	f2 = ((f1 >> 3) * (f1 >> 3) + (f3 >> 3) * (f3 >> 3)) >> 9;  	if (!f2) {  		ath_dbg(common, CALIBRATE, "Divide by 0\n"); @@ -437,9 +656,6 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,  	if (i2_m_q2_a0_d1 > 0x800)  		i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1); -	if (i2_p_q2_a0_d1 > 0x800) -		i2_p_q2_a0_d1 = -((0xfff - i2_p_q2_a0_d1) + 1); -  	if (iq_corr_a0_d1 > 0x800)  		iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1); @@ -482,6 +698,19 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,  		return false;  	} +	if ((i2_p_q2_a0_d0 < 1024) || (i2_p_q2_a0_d0 > 2047) || +            (i2_p_q2_a1_d0 < 0) || (i2_p_q2_a1_d1 < 0) || +            (i2_p_q2_a0_d0 <= i2_m_q2_a0_d0) || +            (i2_p_q2_a0_d0 <= iq_corr_a0_d0) || +            (i2_p_q2_a0_d1 <= i2_m_q2_a0_d1) || +            (i2_p_q2_a0_d1 <= iq_corr_a0_d1) || +            (i2_p_q2_a1_d0 <= i2_m_q2_a1_d0) || +            (i2_p_q2_a1_d0 <= iq_corr_a1_d0) || +            (i2_p_q2_a1_d1 <= i2_m_q2_a1_d1) || +            (i2_p_q2_a1_d1 <= iq_corr_a1_d1)) { +		return false; +	} +  	mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0;  	phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0; @@ -569,7 +798,7 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,  	if (q_q_coff > 63)  		q_q_coff = 63; -	iqc_coeff[0] = (q_q_coff * 128) + q_i_coff; +	iqc_coeff[0] = (q_q_coff * 128) + (0x7f & q_i_coff);  	ath_dbg(common, CALIBRATE, "tx chain %d: iq corr coeff=%x\n",  		chain_idx, iqc_coeff[0]); @@ -600,7 +829,7 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,  	if (q_q_coff > 63)  		q_q_coff = 63; -	iqc_coeff[1] = (q_q_coff * 128) + q_i_coff; +	iqc_coeff[1] = (q_q_coff * 128) + (0x7f & q_i_coff);  	ath_dbg(common, CALIBRATE, "rx chain %d: iq corr coeff=%x\n",  		chain_idx, iqc_coeff[1]); @@ -608,7 +837,8 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,  	return true;  } -static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, +static void ar9003_hw_detect_outlier(int mp_coeff[][MAXIQCAL], +				     int nmeasurement,  				     int max_delta)  {  	int mp_max = -64, max_idx = 0; @@ -617,20 +847,20 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,  	/* find min/max mismatch across all calibrated gains */  	for (i = 0; i < nmeasurement; i++) { -		if (mp_coeff[i] > mp_max) { -			mp_max = mp_coeff[i]; +		if (mp_coeff[i][0] > mp_max) { +			mp_max = mp_coeff[i][0];  			max_idx = i; -		} else if (mp_coeff[i] < mp_min) { -			mp_min = mp_coeff[i]; +		} else if (mp_coeff[i][0] < mp_min) { +			mp_min = mp_coeff[i][0];  			min_idx = i;  		}  	}  	/* find average (exclude max abs value) */  	for (i = 0; i < nmeasurement; i++) { -		if ((abs(mp_coeff[i]) < abs(mp_max)) || -		    (abs(mp_coeff[i]) < abs(mp_min))) { -			mp_avg += mp_coeff[i]; +		if ((abs(mp_coeff[i][0]) < abs(mp_max)) || +		    (abs(mp_coeff[i][0]) < abs(mp_min))) { +			mp_avg += mp_coeff[i][0];  			mp_count++;  		}  	} @@ -642,7 +872,7 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,  	if (mp_count)  		mp_avg /= mp_count;  	else -		mp_avg = mp_coeff[nmeasurement - 1]; +		mp_avg = mp_coeff[nmeasurement - 1][0];  	/* detect outlier */  	if (abs(mp_max - mp_min) > max_delta) { @@ -651,15 +881,16 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,  		else  			outlier_idx = min_idx; -		mp_coeff[outlier_idx] = mp_avg; +		mp_coeff[outlier_idx][0] = mp_avg;  	}  } -static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, -						 struct coeff *coeff, -						 bool is_reusable) +static void ar9003_hw_tx_iq_cal_outlier_detection(struct ath_hw *ah, +						  struct coeff *coeff, +						  bool is_reusable)  {  	int i, im, nmeasurement; +	int magnitude, phase;  	u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS];  	struct ath9k_hw_cal_data *caldata = ah->caldata; @@ -689,21 +920,30 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,  		if (nmeasurement > MAX_MEASUREMENT)  			nmeasurement = MAX_MEASUREMENT; -		/* detect outlier only if nmeasurement > 1 */ -		if (nmeasurement > 1) { -			/* Detect magnitude outlier */ -			ar9003_hw_detect_outlier(coeff->mag_coeff[i], -					nmeasurement, MAX_MAG_DELTA); - -			/* Detect phase outlier */ -			ar9003_hw_detect_outlier(coeff->phs_coeff[i], -					nmeasurement, MAX_PHS_DELTA); +		/* +		 * Skip normal outlier detection for AR9550. +		 */ +		if (!AR_SREV_9550(ah)) { +			/* detect outlier only if nmeasurement > 1 */ +			if (nmeasurement > 1) { +				/* Detect magnitude outlier */ +				ar9003_hw_detect_outlier(coeff->mag_coeff[i], +							 nmeasurement, +							 MAX_MAG_DELTA); + +				/* Detect phase outlier */ +				ar9003_hw_detect_outlier(coeff->phs_coeff[i], +							 nmeasurement, +							 MAX_PHS_DELTA); +			}  		}  		for (im = 0; im < nmeasurement; im++) { +			magnitude = coeff->mag_coeff[i][im][0]; +			phase = coeff->phs_coeff[i][im][0]; -			coeff->iqc_coeff[0] = (coeff->mag_coeff[i][im] & 0x7f) | -				((coeff->phs_coeff[i][im] & 0x7f) << 7); +			coeff->iqc_coeff[0] = +				(phase & 0x7f) | ((magnitude & 0x7f) << 7);  			if ((im % 2) == 0)  				REG_RMW_FIELD(ah, tx_corr_coeff[im][i], @@ -727,8 +967,12 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,  	REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,  		      AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1); -	if (caldata) -		caldata->done_txiqcal_once = is_reusable; +	if (caldata) { +		if (is_reusable) +			set_bit(TXIQCAL_DONE, &caldata->cal_flags); +		else +			clear_bit(TXIQCAL_DONE, &caldata->cal_flags); +	}  	return;  } @@ -756,7 +1000,63 @@ static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)  	return true;  } -static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable) +static void __ar955x_tx_iq_cal_sort(struct ath_hw *ah, +				    struct coeff *coeff, +				    int i, int nmeasurement) +{ +	struct ath_common *common = ath9k_hw_common(ah); +	int im, ix, iy, temp; + +	for (im = 0; im < nmeasurement; im++) { +		for (ix = 0; ix < MAXIQCAL - 1; ix++) { +			for (iy = ix + 1; iy <= MAXIQCAL - 1; iy++) { +				if (coeff->mag_coeff[i][im][iy] < +				    coeff->mag_coeff[i][im][ix]) { +					temp = coeff->mag_coeff[i][im][ix]; +					coeff->mag_coeff[i][im][ix] = +						coeff->mag_coeff[i][im][iy]; +					coeff->mag_coeff[i][im][iy] = temp; +				} +				if (coeff->phs_coeff[i][im][iy] < +				    coeff->phs_coeff[i][im][ix]) { +					temp = coeff->phs_coeff[i][im][ix]; +					coeff->phs_coeff[i][im][ix] = +						coeff->phs_coeff[i][im][iy]; +					coeff->phs_coeff[i][im][iy] = temp; +				} +			} +		} +		coeff->mag_coeff[i][im][0] = coeff->mag_coeff[i][im][MAXIQCAL / 2]; +		coeff->phs_coeff[i][im][0] = coeff->phs_coeff[i][im][MAXIQCAL / 2]; + +		ath_dbg(common, CALIBRATE, +			"IQCAL: Median [ch%d][gain%d]: mag = %d phase = %d\n", +			i, im, +			coeff->mag_coeff[i][im][0], +			coeff->phs_coeff[i][im][0]); +	} +} + +static bool ar955x_tx_iq_cal_median(struct ath_hw *ah, +				    struct coeff *coeff, +				    int iqcal_idx, +				    int nmeasurement) +{ +	int i; + +	if ((iqcal_idx + 1) != MAXIQCAL) +		return false; + +	for (i = 0; i < AR9300_MAX_CHAINS; i++) { +		__ar955x_tx_iq_cal_sort(ah, coeff, i, nmeasurement); +	} + +	return true; +} + +static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, +					  int iqcal_idx, +					  bool is_reusable)  {  	struct ath_common *common = ath9k_hw_common(ah);  	const u32 txiqcal_status[AR9300_MAX_CHAINS] = { @@ -769,10 +1069,11 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)  		AR_PHY_CHAN_INFO_TAB_1,  		AR_PHY_CHAN_INFO_TAB_2,  	}; -	struct coeff coeff; +	static struct coeff coeff;  	s32 iq_res[6];  	int i, im, j; -	int nmeasurement; +	int nmeasurement = 0; +	bool outlier_detect = true;  	for (i = 0; i < AR9300_MAX_CHAINS; i++) {  		if (!(ah->txchainmask & (1 << i))) @@ -830,17 +1131,23 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)  				goto tx_iqcal_fail;  			} -			coeff.mag_coeff[i][im] = coeff.iqc_coeff[0] & 0x7f; -			coeff.phs_coeff[i][im] = +			coeff.phs_coeff[i][im][iqcal_idx] = +				coeff.iqc_coeff[0] & 0x7f; +			coeff.mag_coeff[i][im][iqcal_idx] =  				(coeff.iqc_coeff[0] >> 7) & 0x7f; -			if (coeff.mag_coeff[i][im] > 63) -				coeff.mag_coeff[i][im] -= 128; -			if (coeff.phs_coeff[i][im] > 63) -				coeff.phs_coeff[i][im] -= 128; +			if (coeff.mag_coeff[i][im][iqcal_idx] > 63) +				coeff.mag_coeff[i][im][iqcal_idx] -= 128; +			if (coeff.phs_coeff[i][im][iqcal_idx] > 63) +				coeff.phs_coeff[i][im][iqcal_idx] -= 128;  		}  	} -	ar9003_hw_tx_iqcal_load_avg_2_passes(ah, &coeff, is_reusable); + +	if (AR_SREV_9550(ah)) +		outlier_detect = ar955x_tx_iq_cal_median(ah, &coeff, +							 iqcal_idx, nmeasurement); +	if (outlier_detect) +		ar9003_hw_tx_iq_cal_outlier_detection(ah, &coeff, is_reusable);  	return; @@ -894,7 +1201,7 @@ static void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah)  static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g)  { -	int offset[8], total = 0, test; +	int offset[8] = {0}, total = 0, test;  	int agc_out, i;  	REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), @@ -919,12 +1226,18 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g)  		      AR_PHY_65NM_RXRF_AGC_AGC_ON_OVR, 0x1);  	REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),  		      AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0x1); -	if (is_2g) -		REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), -			      AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR, 0x0); -	else + +	if (AR_SREV_9330_11(ah)) {  		REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), -			      AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR, 0x0); +			      AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, 0x0); +	} else { +		if (is_2g) +			REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), +				      AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR, 0x0); +		else +			REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), +				      AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR, 0x0); +	}  	for (i = 6; i > 0; i--) {  		offset[i] = BIT(i - 1); @@ -960,19 +1273,45 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g)  		      AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0);  } -static void ar9003_hw_do_manual_peak_cal(struct ath_hw *ah, -					 struct ath9k_channel *chan) +static void ar9003_hw_do_pcoem_manual_peak_cal(struct ath_hw *ah, +					       struct ath9k_channel *chan, +					       bool run_rtt_cal)  { +	struct ath9k_hw_cal_data *caldata = ah->caldata;  	int i;  	if (!AR_SREV_9462(ah) && !AR_SREV_9565(ah) && !AR_SREV_9485(ah))  		return; +	if ((ah->caps.hw_caps & ATH9K_HW_CAP_RTT) && !run_rtt_cal) +		return; +  	for (i = 0; i < AR9300_MAX_CHAINS; i++) {  		if (!(ah->rxchainmask & (1 << i)))  			continue;  		ar9003_hw_manual_peak_cal(ah, i, IS_CHAN_2GHZ(chan));  	} + +	if (caldata) +		set_bit(SW_PKDET_DONE, &caldata->cal_flags); + +	if ((ah->caps.hw_caps & ATH9K_HW_CAP_RTT) && caldata) { +		if (IS_CHAN_2GHZ(chan)){ +			caldata->caldac[0] = REG_READ_FIELD(ah, +						    AR_PHY_65NM_RXRF_AGC(0), +						    AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR); +			caldata->caldac[1] = REG_READ_FIELD(ah, +						    AR_PHY_65NM_RXRF_AGC(1), +						    AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR); +		} else { +			caldata->caldac[0] = REG_READ_FIELD(ah, +						    AR_PHY_65NM_RXRF_AGC(0), +						    AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR); +			caldata->caldac[1] = REG_READ_FIELD(ah, +						    AR_PHY_65NM_RXRF_AGC(1), +						    AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR); +		} +	}  }  static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable) @@ -990,7 +1329,7 @@ static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable)  	txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) &  			  AR_PHY_AGC_CONTROL_CLC_SUCCESS); -	if (caldata->done_txclcal_once) { +	if (test_bit(TXCLCAL_DONE, &caldata->cal_flags)) {  		for (i = 0; i < AR9300_MAX_CHAINS; i++) {  			if (!(ah->txchainmask & (1 << i)))  				continue; @@ -1006,19 +1345,20 @@ static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable)  				caldata->tx_clcal[i][j] =  					REG_READ(ah, CL_TAB_ENTRY(cl_idx[i]));  		} -		caldata->done_txclcal_once = true; +		set_bit(TXCLCAL_DONE, &caldata->cal_flags);  	}  } -static bool ar9003_hw_init_cal(struct ath_hw *ah, -			       struct ath9k_channel *chan) +static bool ar9003_hw_init_cal_pcoem(struct ath_hw *ah, +				     struct ath9k_channel *chan)  {  	struct ath_common *common = ath9k_hw_common(ah);  	struct ath9k_hw_cal_data *caldata = ah->caldata;  	bool txiqcal_done = false;  	bool is_reusable = true, status = true; -	bool run_rtt_cal = false, run_agc_cal, sep_iq_cal = false; +	bool run_rtt_cal = false, run_agc_cal;  	bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT); +	u32 rx_delay = 0;  	u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |  					  AR_PHY_AGC_CONTROL_FLTR_CAL   |  					  AR_PHY_AGC_CONTROL_PKDET_CAL; @@ -1042,17 +1382,22 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,  		ar9003_hw_rtt_clear_hist(ah);  	} -	if (rtt && !run_rtt_cal) { -		agc_ctrl = REG_READ(ah, AR_PHY_AGC_CONTROL); -		agc_supp_cals &= agc_ctrl; -		agc_ctrl &= ~(AR_PHY_AGC_CONTROL_OFFSET_CAL | -			     AR_PHY_AGC_CONTROL_FLTR_CAL | -			     AR_PHY_AGC_CONTROL_PKDET_CAL); -		REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl); +	if (rtt) { +		if (!run_rtt_cal) { +			agc_ctrl = REG_READ(ah, AR_PHY_AGC_CONTROL); +			agc_supp_cals &= agc_ctrl; +			agc_ctrl &= ~(AR_PHY_AGC_CONTROL_OFFSET_CAL | +				      AR_PHY_AGC_CONTROL_FLTR_CAL | +				      AR_PHY_AGC_CONTROL_PKDET_CAL); +			REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl); +		} else { +			if (ah->ah_flags & AH_FASTCC) +				run_agc_cal = true; +		}  	}  	if (ah->enabled_cals & TX_CL_CAL) { -		if (caldata && caldata->done_txclcal_once) +		if (caldata && test_bit(TXCLCAL_DONE, &caldata->cal_flags))  			REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL,  				    AR_PHY_CL_CAL_ENABLE);  		else { @@ -1076,26 +1421,25 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,  	 * AGC calibration  	 */  	if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) { -		if (caldata && !caldata->done_txiqcal_once) +		if (caldata && !test_bit(TXIQCAL_DONE, &caldata->cal_flags))  			REG_SET_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,  				    AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);  		else  			REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,  				    AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);  		txiqcal_done = run_agc_cal = true; -	} else if (caldata && !caldata->done_txiqcal_once) { -		run_agc_cal = true; -		sep_iq_cal = true;  	}  skip_tx_iqcal:  	if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)  		ar9003_mci_init_cal_req(ah, &is_reusable); -	if (sep_iq_cal) { -		txiqcal_done = ar9003_hw_tx_iq_cal_run(ah); +	if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) { +		rx_delay = REG_READ(ah, AR_PHY_RX_DELAY); +		/* Disable BB_active */  		REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);  		udelay(5); +		REG_WRITE(ah, AR_PHY_RX_DELAY, AR_PHY_RX_DELAY_DELAY);  		REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);  	} @@ -1110,7 +1454,12 @@ skip_tx_iqcal:  				       AR_PHY_AGC_CONTROL_CAL,  				       0, AH_WAIT_TIMEOUT); -		ar9003_hw_do_manual_peak_cal(ah, chan); +		ar9003_hw_do_pcoem_manual_peak_cal(ah, chan, run_rtt_cal); +	} + +	if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) { +		REG_WRITE(ah, AR_PHY_RX_DELAY, rx_delay); +		udelay(5);  	}  	if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal) @@ -1132,20 +1481,24 @@ skip_tx_iqcal:  	}  	if (txiqcal_done) -		ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable); -	else if (caldata && caldata->done_txiqcal_once) +		ar9003_hw_tx_iq_cal_post_proc(ah, 0, is_reusable); +	else if (caldata && test_bit(TXIQCAL_DONE, &caldata->cal_flags))  		ar9003_hw_tx_iq_cal_reload(ah);  	ar9003_hw_cl_cal_post_proc(ah, is_reusable);  	if (run_rtt_cal && caldata) {  		if (is_reusable) { -			if (!ath9k_hw_rfbus_req(ah)) +			if (!ath9k_hw_rfbus_req(ah)) {  				ath_err(ath9k_hw_common(ah),  					"Could not stop baseband\n"); -			else +			} else {  				ar9003_hw_rtt_fill_hist(ah); +				if (test_bit(SW_PKDET_DONE, &caldata->cal_flags)) +					ar9003_hw_rtt_load_hist(ah); +			} +  			ath9k_hw_rfbus_done(ah);  		} @@ -1174,13 +1527,156 @@ skip_tx_iqcal:  	return true;  } +static bool do_ar9003_agc_cal(struct ath_hw *ah) +{ +	struct ath_common *common = ath9k_hw_common(ah); +	bool status; + +	REG_WRITE(ah, AR_PHY_AGC_CONTROL, +		  REG_READ(ah, AR_PHY_AGC_CONTROL) | +		  AR_PHY_AGC_CONTROL_CAL); + +	status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, +			       AR_PHY_AGC_CONTROL_CAL, +			       0, AH_WAIT_TIMEOUT); +	if (!status) { +		ath_dbg(common, CALIBRATE, +			"offset calibration failed to complete in %d ms," +			"noisy environment?\n", +			AH_WAIT_TIMEOUT / 1000); +		return false; +	} + +	return true; +} + +static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, +				   struct ath9k_channel *chan) +{ +	struct ath_common *common = ath9k_hw_common(ah); +	struct ath9k_hw_cal_data *caldata = ah->caldata; +	bool txiqcal_done = false; +	bool status = true; +	bool run_agc_cal = false, sep_iq_cal = false; +	int i = 0; + +	/* Use chip chainmask only for calibration */ +	ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask); + +	if (ah->enabled_cals & TX_CL_CAL) { +		REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); +		run_agc_cal = true; +	} + +	if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) +		goto skip_tx_iqcal; + +	/* Do Tx IQ Calibration */ +	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1, +		      AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, +		      DELPT); + +	/* +	 * For AR9485 or later chips, TxIQ cal runs as part of +	 * AGC calibration. Specifically, AR9550 in SoC chips. +	 */ +	if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) { +		if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0, +				   AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)) { +				txiqcal_done = true; +		} else { +			txiqcal_done = false; +		} +		run_agc_cal = true; +	} else { +		sep_iq_cal = true; +		run_agc_cal = true; +	} + +	/* +	 * In the SoC family, this will run for AR9300, AR9331 and AR9340. +	 */ +	if (sep_iq_cal) { +		txiqcal_done = ar9003_hw_tx_iq_cal_run(ah); +		REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); +		udelay(5); +		REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); +	} + +	if (AR_SREV_9550(ah) && IS_CHAN_2GHZ(chan)) { +		if (!ar9003_hw_dynamic_osdac_selection(ah, txiqcal_done)) +			return false; +	} + +skip_tx_iqcal: +	if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) { +		if (AR_SREV_9330_11(ah)) +			ar9003_hw_manual_peak_cal(ah, 0, IS_CHAN_2GHZ(chan)); + +		/* +		 * For non-AR9550 chips, we just trigger AGC calibration +		 * in the HW, poll for completion and then process +		 * the results. +		 * +		 * For AR955x, we run it multiple times and use +		 * median IQ correction. +		 */ +		if (!AR_SREV_9550(ah)) { +			status = do_ar9003_agc_cal(ah); +			if (!status) +				return false; + +			if (txiqcal_done) +				ar9003_hw_tx_iq_cal_post_proc(ah, 0, false); +		} else { +			if (!txiqcal_done) { +				status = do_ar9003_agc_cal(ah); +				if (!status) +					return false; +			} else { +				for (i = 0; i < MAXIQCAL; i++) { +					status = do_ar9003_agc_cal(ah); +					if (!status) +						return false; +					ar9003_hw_tx_iq_cal_post_proc(ah, i, false); +				} +			} +		} +	} + +	/* Revert chainmask to runtime parameters */ +	ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); + +	/* Initialize list pointers */ +	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; + +	INIT_CAL(&ah->iq_caldata); +	INSERT_CAL(ah, &ah->iq_caldata); +	ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n"); + +	/* Initialize current pointer to first element in list */ +	ah->cal_list_curr = ah->cal_list; + +	if (ah->cal_list_curr) +		ath9k_hw_reset_calibration(ah, ah->cal_list_curr); + +	if (caldata) +		caldata->CalValid = 0; + +	return true; +} +  void ar9003_hw_attach_calib_ops(struct ath_hw *ah)  {  	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);  	struct ath_hw_ops *ops = ath9k_hw_ops(ah); +	if (AR_SREV_9485(ah) || AR_SREV_9462(ah) || AR_SREV_9565(ah)) +		priv_ops->init_cal = ar9003_hw_init_cal_pcoem; +	else +		priv_ops->init_cal = ar9003_hw_init_cal_soc; +  	priv_ops->init_cal_settings = ar9003_hw_init_cal_settings; -	priv_ops->init_cal = ar9003_hw_init_cal;  	priv_ops->setup_calibration = ar9003_hw_setup_calibration;  	ops->calibrate = ar9003_hw_calibrate; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index f4864807e15..235053ba773 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -23,8 +23,8 @@  #define COMP_HDR_LEN 4  #define COMP_CKSUM_LEN 2 -#define LE16(x) __constant_cpu_to_le16(x) -#define LE32(x) __constant_cpu_to_le32(x) +#define LE16(x) cpu_to_le16(x) +#define LE32(x) cpu_to_le32(x)  /* Local defines to distinguish between extension and control CTL's */  #define EXT_ADDITIVE (0x8000) @@ -131,6 +131,7 @@ static const struct ar9300_eeprom ar9300_default = {  		.thresh62 = 28,  		.papdRateMaskHt20 = LE32(0x0cf0e0e0),  		.papdRateMaskHt40 = LE32(0x6cf0e0e0), +		.switchcomspdt = 0,  		.xlna_bias_strength = 0,  		.futureModal = {  			0, 0, 0, 0, 0, 0, 0, @@ -138,7 +139,7 @@ static const struct ar9300_eeprom ar9300_default = {  	 },  	.base_ext1 = {  		.ant_div_control = 0, -		.future = {0, 0, 0}, +		.future = {0, 0},  		.tempslopextension = {0, 0, 0, 0, 0, 0, 0, 0}  	},  	.calFreqPier2G = { @@ -333,6 +334,7 @@ static const struct ar9300_eeprom ar9300_default = {  		.thresh62 = 28,  		.papdRateMaskHt20 = LE32(0x0c80c080),  		.papdRateMaskHt40 = LE32(0x0080c080), +		.switchcomspdt = 0,  		.xlna_bias_strength = 0,  		.futureModal = {  			0, 0, 0, 0, 0, 0, 0, @@ -707,6 +709,7 @@ static const struct ar9300_eeprom ar9300_x113 = {  		.thresh62 = 28,  		.papdRateMaskHt20 = LE32(0x0c80c080),  		.papdRateMaskHt40 = LE32(0x0080c080), +		.switchcomspdt = 0,  		.xlna_bias_strength = 0,  		.futureModal = {  			0, 0, 0, 0, 0, 0, 0, @@ -714,7 +717,7 @@ static const struct ar9300_eeprom ar9300_x113 = {  	 },  	 .base_ext1 = {  		.ant_div_control = 0, -		.future = {0, 0, 0}, +		.future = {0, 0},  		.tempslopextension = {0, 0, 0, 0, 0, 0, 0, 0}  	 },  	.calFreqPier2G = { @@ -909,6 +912,7 @@ static const struct ar9300_eeprom ar9300_x113 = {  		.thresh62 = 28,  		.papdRateMaskHt20 = LE32(0x0cf0e0e0),  		.papdRateMaskHt40 = LE32(0x6cf0e0e0), +		.switchcomspdt = 0,  		.xlna_bias_strength = 0,  		.futureModal = {  			0, 0, 0, 0, 0, 0, 0, @@ -1284,6 +1288,7 @@ static const struct ar9300_eeprom ar9300_h112 = {  		.thresh62 = 28,  		.papdRateMaskHt20 = LE32(0x0c80c080),  		.papdRateMaskHt40 = LE32(0x0080c080), +		.switchcomspdt = 0,  		.xlna_bias_strength = 0,  		.futureModal = {  			0, 0, 0, 0, 0, 0, 0, @@ -1291,7 +1296,7 @@ static const struct ar9300_eeprom ar9300_h112 = {  	},  	.base_ext1 = {  		.ant_div_control = 0, -		.future = {0, 0, 0}, +		.future = {0, 0},  		.tempslopextension = {0, 0, 0, 0, 0, 0, 0, 0}  	},  	.calFreqPier2G = { @@ -1486,6 +1491,7 @@ static const struct ar9300_eeprom ar9300_h112 = {  		.thresh62 = 28,  		.papdRateMaskHt20 = LE32(0x0cf0e0e0),  		.papdRateMaskHt40 = LE32(0x6cf0e0e0), +		.switchcomspdt = 0,  		.xlna_bias_strength = 0,  		.futureModal = {  			0, 0, 0, 0, 0, 0, 0, @@ -1861,6 +1867,7 @@ static const struct ar9300_eeprom ar9300_x112 = {  		.thresh62 = 28,  		.papdRateMaskHt20 = LE32(0x0c80c080),  		.papdRateMaskHt40 = LE32(0x0080c080), +		.switchcomspdt = 0,  		.xlna_bias_strength = 0,  		.futureModal = {  			0, 0, 0, 0, 0, 0, 0, @@ -1868,7 +1875,7 @@ static const struct ar9300_eeprom ar9300_x112 = {  	},  	.base_ext1 = {  		.ant_div_control = 0, -		.future = {0, 0, 0}, +		.future = {0, 0},  		.tempslopextension = {0, 0, 0, 0, 0, 0, 0, 0}  	},  	.calFreqPier2G = { @@ -2063,6 +2070,7 @@ static const struct ar9300_eeprom ar9300_x112 = {  		.thresh62 = 28,  		.papdRateMaskHt20 = LE32(0x0cf0e0e0),  		.papdRateMaskHt40 = LE32(0x6cf0e0e0), +		.switchcomspdt = 0,  		.xlna_bias_strength = 0,  		.futureModal = {  			0, 0, 0, 0, 0, 0, 0, @@ -2437,6 +2445,7 @@ static const struct ar9300_eeprom ar9300_h116 = {  		.thresh62 = 28,  		.papdRateMaskHt20 = LE32(0x0c80C080),  		.papdRateMaskHt40 = LE32(0x0080C080), +		.switchcomspdt = 0,  		.xlna_bias_strength = 0,  		.futureModal = {  			0, 0, 0, 0, 0, 0, 0, @@ -2444,7 +2453,7 @@ static const struct ar9300_eeprom ar9300_h116 = {  	 },  	 .base_ext1 = {  		.ant_div_control = 0, -		.future = {0, 0, 0}, +		.future = {0, 0},  		.tempslopextension = {0, 0, 0, 0, 0, 0, 0, 0}  	 },  	.calFreqPier2G = { @@ -2639,6 +2648,7 @@ static const struct ar9300_eeprom ar9300_h116 = {  		.thresh62 = 28,  		.papdRateMaskHt20 = LE32(0x0cf0e0e0),  		.papdRateMaskHt40 = LE32(0x6cf0e0e0), +		.switchcomspdt = 0,  		.xlna_bias_strength = 0,  		.futureModal = {  			0, 0, 0, 0, 0, 0, 0, @@ -2991,7 +3001,10 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah,  	case EEP_CHAIN_MASK_REDUCE:  		return (pBase->miscConfiguration >> 0x3) & 0x1;  	case EEP_ANT_DIV_CTL1: -		return eep->base_ext1.ant_div_control; +		if (AR_SREV_9565(ah)) +			return AR9300_EEP_ANTDIV_CONTROL_DEFAULT_VALUE; +		else +			return eep->base_ext1.ant_div_control;  	case EEP_ANTENNA_GAIN_5G:  		return eep->modalHeader5G.antennaGain;  	case EEP_ANTENNA_GAIN_2G: @@ -3424,12 +3437,12 @@ static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,  	struct ar9300_base_eep_hdr *pBase;  	if (!dump_base_hdr) { -		len += snprintf(buf + len, size - len, -				"%20s :\n", "2GHz modal Header"); +		len += scnprintf(buf + len, size - len, +				 "%20s :\n", "2GHz modal Header");  		len = ar9003_dump_modal_eeprom(buf, len, size,  						&eep->modalHeader2G); -		len += snprintf(buf + len, size - len, -				"%20s :\n", "5GHz modal Header"); +		len += scnprintf(buf + len, size - len, +				 "%20s :\n", "5GHz modal Header");  		len = ar9003_dump_modal_eeprom(buf, len, size,  						&eep->modalHeader5G);  		goto out; @@ -3479,8 +3492,8 @@ static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,  	PR_EEP("Rx Gain", pBase->txrxgain & 0xf);  	PR_EEP("SW Reg", le32_to_cpu(pBase->swreg)); -	len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", -			ah->eeprom.ar9300_eep.macAddr); +	len += scnprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", +			 ah->eeprom.ar9300_eep.macAddr);  out:  	if (len > size)  		len = size; @@ -3585,7 +3598,7 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)  	if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {  		REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,  				AR_SWITCH_TABLE_COM_AR9462_ALL, value); -	} else if (AR_SREV_9550(ah)) { +	} else if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) {  		REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,  				AR_SWITCH_TABLE_COM_AR9550_ALL, value);  	} else @@ -3656,9 +3669,23 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)  		if (AR_SREV_9565(ah)) {  			if (common->bt_ant_diversity) {  				regval |= (1 << AR_PHY_ANT_SW_RX_PROT_S); + +				REG_SET_BIT(ah, AR_PHY_RESTART, +					    AR_PHY_RESTART_ENABLE_DIV_M2FLAG); + +				/* Force WLAN LNA diversity ON */ +				REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, +					    AR_BTCOEX_WL_LNADIV_FORCE_ON);  			} else {  				regval &= ~(1 << AR_PHY_ANT_DIV_LNADIV_S);  				regval &= ~(1 << AR_PHY_ANT_SW_RX_PROT_S); + +				REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, +					    (1 << AR_PHY_ANT_SW_RX_PROT_S)); + +				/* Force WLAN LNA diversity OFF */ +				REG_CLR_BIT(ah, AR_BTCOEX_WL_LNADIV, +					    AR_BTCOEX_WL_LNADIV_FORCE_ON);  			}  		} @@ -3669,7 +3696,8 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)  		regval &= (~AR_FAST_DIV_ENABLE);  		regval |= ((value >> 7) & 0x1) << AR_FAST_DIV_ENABLE_S; -		if (AR_SREV_9485(ah) && common->bt_ant_diversity) +		if ((AR_SREV_9485(ah) || AR_SREV_9565(ah)) +		    && common->bt_ant_diversity)  			regval |= AR_FAST_DIV_ENABLE;  		REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); @@ -3947,7 +3975,7 @@ static void ar9003_hw_apply_tuning_caps(struct ath_hw *ah)  	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;  	u8 tuning_caps_param = eep->baseEepHeader.params_for_tuning_caps[0]; -	if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah)) +	if (AR_SREV_9340(ah) || AR_SREV_9531(ah))  		return;  	if (eep->baseEepHeader.featureEnable & 0x40) { @@ -3966,18 +3994,20 @@ static void ar9003_hw_quick_drop_apply(struct ath_hw *ah, u16 freq)  	int quick_drop;  	s32 t[3], f[3] = {5180, 5500, 5785}; -	if (!(pBase->miscConfiguration & BIT(1))) +	if (!(pBase->miscConfiguration & BIT(4)))  		return; -	if (freq < 4000) -		quick_drop = eep->modalHeader2G.quick_drop; -	else { -		t[0] = eep->base_ext1.quick_drop_low; -		t[1] = eep->modalHeader5G.quick_drop; -		t[2] = eep->base_ext1.quick_drop_high; -		quick_drop = ar9003_hw_power_interpolate(freq, f, t, 3); +	if (AR_SREV_9300(ah) || AR_SREV_9580(ah) || AR_SREV_9340(ah)) { +		if (freq < 4000) { +			quick_drop = eep->modalHeader2G.quick_drop; +		} else { +			t[0] = eep->base_ext1.quick_drop_low; +			t[1] = eep->modalHeader5G.quick_drop; +			t[2] = eep->base_ext1.quick_drop_high; +			quick_drop = ar9003_hw_power_interpolate(freq, f, t, 3); +		} +		REG_RMW_FIELD(ah, AR_PHY_AGC, AR_PHY_AGC_QUICK_DROP, quick_drop);  	} -	REG_RMW_FIELD(ah, AR_PHY_AGC, AR_PHY_AGC_QUICK_DROP, quick_drop);  }  static void ar9003_hw_txend_to_xpa_off_apply(struct ath_hw *ah, bool is2ghz) @@ -4000,7 +4030,10 @@ static void ar9003_hw_xpa_timing_control_apply(struct ath_hw *ah, bool is2ghz)  	if (!(eep->baseEepHeader.featureEnable & 0x80))  		return; -	if (!AR_SREV_9300(ah) && !AR_SREV_9340(ah) && !AR_SREV_9580(ah)) +	if (!AR_SREV_9300(ah) && +	    !AR_SREV_9340(ah) && +	    !AR_SREV_9580(ah) && +	    !AR_SREV_9531(ah))  		return;  	xpa_ctl = ar9003_modal_header(ah, is2ghz)->txFrameToXpaOn; @@ -4017,7 +4050,7 @@ static void ar9003_hw_xlna_bias_strength_apply(struct ath_hw *ah, bool is2ghz)  	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;  	u8 bias; -	if (!(eep->baseEepHeader.featureEnable & 0x40)) +	if (!(eep->baseEepHeader.miscConfiguration & 0x40))  		return;  	if (!AR_SREV_9300(ah)) @@ -4091,6 +4124,37 @@ static void ar9003_hw_thermo_cal_apply(struct ath_hw *ah)  	}  } +static void ar9003_hw_apply_minccapwr_thresh(struct ath_hw *ah, +					     bool is2ghz) +{ +	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; +	const u_int32_t cca_ctrl[AR9300_MAX_CHAINS] = { +		AR_PHY_CCA_CTRL_0, +		AR_PHY_CCA_CTRL_1, +		AR_PHY_CCA_CTRL_2, +	}; +	int chain; +	u32 val; + +	if (is2ghz) { +		if (!(eep->base_ext1.misc_enable & BIT(2))) +			return; +	} else { +		if (!(eep->base_ext1.misc_enable & BIT(3))) +			return; +	} + +	for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { +		if (!(ah->caps.tx_chainmask & BIT(chain))) +			continue; + +		val = ar9003_modal_header(ah, is2ghz)->noiseFloorThreshCh[chain]; +		REG_RMW_FIELD(ah, cca_ctrl[chain], +			      AR_PHY_EXT_CCA0_THRESH62_1, val); +	} + +} +  static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah,  					     struct ath9k_channel *chan)  { @@ -4102,9 +4166,10 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah,  	ar9003_hw_xlna_bias_strength_apply(ah, is2ghz);  	ar9003_hw_atten_apply(ah, chan);  	ar9003_hw_quick_drop_apply(ah, chan->channel); -	if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah) && !AR_SREV_9550(ah)) +	if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah) && !AR_SREV_9531(ah))  		ar9003_hw_internal_regulator_apply(ah);  	ar9003_hw_apply_tuning_caps(ah); +	ar9003_hw_apply_minccapwr_thresh(ah, chan);  	ar9003_hw_txend_to_xpa_off_apply(ah, is2ghz);  	ar9003_hw_thermometer_apply(ah);  	ar9003_hw_thermo_cal_apply(ah); @@ -4726,44 +4791,55 @@ static void ar9003_hw_power_control_override(struct ath_hw *ah,  	}  tempslope: -	if (AR_SREV_9550(ah)) { +	if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) { +		u8 txmask = (eep->baseEepHeader.txrxMask & 0xf0) >> 4; +  		/*  		 * AR955x has tempSlope register for each chain.  		 * Check whether temp_compensation feature is enabled or not.  		 */  		if (eep->baseEepHeader.featureEnable & 0x1) {  			if (frequency < 4000) { -				REG_RMW_FIELD(ah, AR_PHY_TPC_19, -					      AR_PHY_TPC_19_ALPHA_THERM, -					      eep->base_ext2.tempSlopeLow); -				REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, -					      AR_PHY_TPC_19_ALPHA_THERM, -					      temp_slope); -				REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, -					      AR_PHY_TPC_19_ALPHA_THERM, -					      eep->base_ext2.tempSlopeHigh); +				if (txmask & BIT(0)) +					REG_RMW_FIELD(ah, AR_PHY_TPC_19, +						      AR_PHY_TPC_19_ALPHA_THERM, +						      eep->base_ext2.tempSlopeLow); +				if (txmask & BIT(1)) +					REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, +						      AR_PHY_TPC_19_ALPHA_THERM, +						      temp_slope); +				if (txmask & BIT(2)) +					REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, +						      AR_PHY_TPC_19_ALPHA_THERM, +						      eep->base_ext2.tempSlopeHigh);  			} else { -				REG_RMW_FIELD(ah, AR_PHY_TPC_19, -					      AR_PHY_TPC_19_ALPHA_THERM, -					      temp_slope); -				REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, -					      AR_PHY_TPC_19_ALPHA_THERM, -					      temp_slope1); -				REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, -					      AR_PHY_TPC_19_ALPHA_THERM, -					      temp_slope2); +				if (txmask & BIT(0)) +					REG_RMW_FIELD(ah, AR_PHY_TPC_19, +						      AR_PHY_TPC_19_ALPHA_THERM, +						      temp_slope); +				if (txmask & BIT(1)) +					REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, +						      AR_PHY_TPC_19_ALPHA_THERM, +						      temp_slope1); +				if (txmask & BIT(2)) +					REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, +						      AR_PHY_TPC_19_ALPHA_THERM, +						      temp_slope2);  			}  		} else {  			/*  			 * If temp compensation is not enabled,  			 * set all registers to 0.  			 */ -			REG_RMW_FIELD(ah, AR_PHY_TPC_19, -				      AR_PHY_TPC_19_ALPHA_THERM, 0); -			REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, -				      AR_PHY_TPC_19_ALPHA_THERM, 0); -			REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, -				      AR_PHY_TPC_19_ALPHA_THERM, 0); +			if (txmask & BIT(0)) +				REG_RMW_FIELD(ah, AR_PHY_TPC_19, +					      AR_PHY_TPC_19_ALPHA_THERM, 0); +			if (txmask & BIT(1)) +				REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, +					      AR_PHY_TPC_19_ALPHA_THERM, 0); +			if (txmask & BIT(2)) +				REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, +					      AR_PHY_TPC_19_ALPHA_THERM, 0);  		}  	} else {  		REG_RMW_FIELD(ah, AR_PHY_TPC_19, @@ -5000,6 +5076,10 @@ static u16 ar9003_hw_get_max_edge_power(struct ar9300_eeprom *eep,  			break;  		}  	} + +	if (is2GHz && !twiceMaxEdgePower) +		twiceMaxEdgePower = 60; +  	return twiceMaxEdgePower;  } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h index 75d4fb41962..694ca2e680e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h @@ -52,6 +52,8 @@  #define AR9300_PAPRD_SCALE_2		0x70000000  #define AR9300_PAPRD_SCALE_2_S		28 +#define AR9300_EEP_ANTDIV_CONTROL_DEFAULT_VALUE 0xc9 +  /* Delta from which to start power to pdadc table */  /* This offset is used in both open loop and closed loop power control   * schemes. In open loop power control, it is not really needed, but for @@ -268,10 +270,20 @@ struct cal_ctl_data_5g {  	u8 ctlEdges[AR9300_NUM_BAND_EDGES_5G];  } __packed; +#define MAX_BASE_EXTENSION_FUTURE 2 +  struct ar9300_BaseExtension_1 {  	u8 ant_div_control; -	u8 future[3]; -	u8 tempslopextension[8]; +	u8 future[MAX_BASE_EXTENSION_FUTURE]; +	/* +	 * misc_enable: +	 * +	 * BIT 0   - TX Gain Cap enable. +	 * BIT 1   - Uncompressed Checksum enable. +	 * BIT 2/3 - MinCCApwr enable 2g/5g. +	 */ +	u8 misc_enable; +	int8_t tempslopextension[8];  	int8_t quick_drop_low;  	int8_t quick_drop_high;  } __packed; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 608bb4824e2..ec1da0cc25f 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -17,6 +17,7 @@  #include "hw.h"  #include "ar9003_mac.h"  #include "ar9003_2p2_initvals.h" +#include "ar9003_buffalo_initvals.h"  #include "ar9485_initvals.h"  #include "ar9340_initvals.h"  #include "ar9330_1p1_initvals.h" @@ -26,6 +27,8 @@  #include "ar9462_2p0_initvals.h"  #include "ar9462_2p1_initvals.h"  #include "ar9565_1p0_initvals.h" +#include "ar9565_1p1_initvals.h" +#include "ar953x_initvals.h"  /* General hardware code for the AR9003 hadware family */ @@ -148,7 +151,11 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)  				ar9340Modes_high_ob_db_tx_gain_table_1p0);  		INIT_INI_ARRAY(&ah->iniModesFastClock, -				ar9340Modes_fast_clock_1p0); +			       ar9340Modes_fast_clock_1p0); +		INIT_INI_ARRAY(&ah->iniCckfirJapan2484, +			       ar9340_1p0_baseband_core_txfir_coeff_japan_2484); +		INIT_INI_ARRAY(&ah->ini_dfs, +			       ar9340_1p0_baseband_postamble_dfs_channel);  		if (!ah->is_clk_25mhz)  			INIT_INI_ARRAY(&ah->iniAdditional, @@ -187,17 +194,17 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)  		INIT_INI_ARRAY(&ah->iniCckfirJapan2484,  			       ar9485_1_1_baseband_core_txfir_coeff_japan_2484); -		/* Load PCIE SERDES settings from INI */ - -		/* Awake Setting */ - -		INIT_INI_ARRAY(&ah->iniPcieSerdes, -				ar9485_1_1_pcie_phy_clkreq_disable_L1); - -		/* Sleep Setting */ - -		INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, -				ar9485_1_1_pcie_phy_clkreq_disable_L1); +		if (ah->config.no_pll_pwrsave) { +			INIT_INI_ARRAY(&ah->iniPcieSerdes, +				       ar9485_1_1_pcie_phy_clkreq_disable_L1); +			INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, +				       ar9485_1_1_pcie_phy_clkreq_disable_L1); +		} else { +			INIT_INI_ARRAY(&ah->iniPcieSerdes, +				       ar9485_1_1_pll_on_cdr_on_clkreq_disable_L1); +			INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, +				       ar9485_1_1_pll_on_cdr_on_clkreq_disable_L1); +		}  	} else if (AR_SREV_9462_21(ah)) {  		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],  			       ar9462_2p1_mac_core); @@ -223,6 +230,10 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)  			       ar9462_2p1_modes_fast_clock);  		INIT_INI_ARRAY(&ah->iniCckfirJapan2484,  			       ar9462_2p1_baseband_core_txfir_coeff_japan_2484); +		INIT_INI_ARRAY(&ah->iniPcieSerdes, +			       ar9462_2p1_pciephy_clkreq_disable_L1); +		INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, +			       ar9462_2p1_pciephy_clkreq_disable_L1);  	} else if (AR_SREV_9462_20(ah)) {  		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], ar9462_2p0_mac_core); @@ -247,18 +258,18 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)  				ar9462_2p0_soc_postamble);  		INIT_INI_ARRAY(&ah->iniModesRxGain, -				ar9462_common_rx_gain_table_2p0); +				ar9462_2p0_common_rx_gain);  		/* Awake -> Sleep Setting */  		INIT_INI_ARRAY(&ah->iniPcieSerdes, -			       ar9462_pciephy_clkreq_disable_L1_2p0); +			       ar9462_2p0_pciephy_clkreq_disable_L1);  		/* Sleep -> Awake Setting */  		INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, -			       ar9462_pciephy_clkreq_disable_L1_2p0); +			       ar9462_2p0_pciephy_clkreq_disable_L1);  		/* Fast clock modal settings */  		INIT_INI_ARRAY(&ah->iniModesFastClock, -				ar9462_modes_fast_clock_2p0); +				ar9462_2p0_modes_fast_clock);  		INIT_INI_ARRAY(&ah->iniCckfirJapan2484,  			       ar9462_2p0_baseband_core_txfir_coeff_japan_2484); @@ -298,6 +309,31 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)  		/* Fast clock modal settings */  		INIT_INI_ARRAY(&ah->iniModesFastClock,  				ar955x_1p0_modes_fast_clock); +	} else if (AR_SREV_9531(ah)) { +		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], +			       qca953x_1p0_mac_core); +		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], +			       qca953x_1p0_mac_postamble); +		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], +			       qca953x_1p0_baseband_core); +		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], +			       qca953x_1p0_baseband_postamble); +		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], +			       qca953x_1p0_radio_core); +		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], +			       qca953x_1p0_radio_postamble); +		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], +			       qca953x_1p0_soc_preamble); +		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], +			       qca953x_1p0_soc_postamble); +		INIT_INI_ARRAY(&ah->iniModesRxGain, +			       qca953x_1p0_common_wo_xlna_rx_gain_table); +		INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, +			       qca953x_1p0_common_wo_xlna_rx_gain_bounds); +		INIT_INI_ARRAY(&ah->iniModesTxGain, +			       qca953x_1p0_modes_no_xpa_tx_gain_table); +		INIT_INI_ARRAY(&ah->iniModesFastClock, +			       qca953x_1p0_modes_fast_clock);  	} else if (AR_SREV_9580(ah)) {  		/* mac */  		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], @@ -330,7 +366,46 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)  				ar9580_1p0_low_ob_db_tx_gain_table);  		INIT_INI_ARRAY(&ah->iniModesFastClock, -				ar9580_1p0_modes_fast_clock); +			       ar9580_1p0_modes_fast_clock); +		INIT_INI_ARRAY(&ah->iniCckfirJapan2484, +			       ar9580_1p0_baseband_core_txfir_coeff_japan_2484); +		INIT_INI_ARRAY(&ah->ini_dfs, +			       ar9580_1p0_baseband_postamble_dfs_channel); +	} else if (AR_SREV_9565_11_OR_LATER(ah)) { +		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], +			       ar9565_1p1_mac_core); +		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], +			       ar9565_1p1_mac_postamble); + +		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], +			       ar9565_1p1_baseband_core); +		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], +			       ar9565_1p1_baseband_postamble); + +		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], +			       ar9565_1p1_radio_core); +		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], +			       ar9565_1p1_radio_postamble); + +		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], +			       ar9565_1p1_soc_preamble); +		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], +			       ar9565_1p1_soc_postamble); + +		INIT_INI_ARRAY(&ah->iniModesRxGain, +			       ar9565_1p1_Common_rx_gain_table); +		INIT_INI_ARRAY(&ah->iniModesTxGain, +			       ar9565_1p1_Modes_lowest_ob_db_tx_gain_table); + +		INIT_INI_ARRAY(&ah->iniPcieSerdes, +			       ar9565_1p1_pciephy_clkreq_disable_L1); +		INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, +			       ar9565_1p1_pciephy_clkreq_disable_L1); + +		INIT_INI_ARRAY(&ah->iniModesFastClock, +				ar9565_1p1_modes_fast_clock); +		INIT_INI_ARRAY(&ah->iniCckfirJapan2484, +			       ar9565_1p1_baseband_core_txfir_coeff_japan_2484);  	} else if (AR_SREV_9565(ah)) {  		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],  			       ar9565_1p0_mac_core); @@ -364,6 +439,8 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)  		INIT_INI_ARRAY(&ah->iniModesFastClock,  				ar9565_1p0_modes_fast_clock); +		INIT_INI_ARRAY(&ah->iniCckfirJapan2484, +			       ar9565_1p0_baseband_core_txfir_coeff_japan_2484);  	} else {  		/* mac */  		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], @@ -409,7 +486,11 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)  		/* Fast clock modal settings */  		INIT_INI_ARRAY(&ah->iniModesFastClock, -				ar9300Modes_fast_clock_2p2); +			       ar9300Modes_fast_clock_2p2); +		INIT_INI_ARRAY(&ah->iniCckfirJapan2484, +			       ar9300_2p2_baseband_core_txfir_coeff_japan_2484); +		INIT_INI_ARRAY(&ah->ini_dfs, +			       ar9300_2p2_baseband_postamble_dfs_channel);  	}  } @@ -430,6 +511,9 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah)  	else if (AR_SREV_9550(ah))  		INIT_INI_ARRAY(&ah->iniModesTxGain,  			ar955x_1p0_modes_xpa_tx_gain_table); +	else if (AR_SREV_9531(ah)) +		INIT_INI_ARRAY(&ah->iniModesTxGain, +			qca953x_1p0_modes_xpa_tx_gain_table);  	else if (AR_SREV_9580(ah))  		INIT_INI_ARRAY(&ah->iniModesTxGain,  			ar9580_1p0_lowest_ob_db_tx_gain_table); @@ -438,7 +522,10 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah)  			ar9462_2p1_modes_low_ob_db_tx_gain);  	else if (AR_SREV_9462_20(ah))  		INIT_INI_ARRAY(&ah->iniModesTxGain, -			ar9462_modes_low_ob_db_tx_gain_table_2p0); +			ar9462_2p0_modes_low_ob_db_tx_gain); +	else if (AR_SREV_9565_11(ah)) +		INIT_INI_ARRAY(&ah->iniModesTxGain, +			       ar9565_1p1_modes_low_ob_db_tx_gain_table);  	else if (AR_SREV_9565(ah))  		INIT_INI_ARRAY(&ah->iniModesTxGain,  			       ar9565_1p0_modes_low_ob_db_tx_gain_table); @@ -467,12 +554,22 @@ static void ar9003_tx_gain_table_mode1(struct ath_hw *ah)  	else if (AR_SREV_9550(ah))  		INIT_INI_ARRAY(&ah->iniModesTxGain,  			ar955x_1p0_modes_no_xpa_tx_gain_table); -	else if (AR_SREV_9462_21(ah)) +	else if (AR_SREV_9531(ah)) { +		if (AR_SREV_9531_11(ah)) +			INIT_INI_ARRAY(&ah->iniModesTxGain, +				       qca953x_1p1_modes_no_xpa_tx_gain_table); +		else +			INIT_INI_ARRAY(&ah->iniModesTxGain, +				       qca953x_1p0_modes_no_xpa_tx_gain_table); +	} else if (AR_SREV_9462_21(ah))  		INIT_INI_ARRAY(&ah->iniModesTxGain,  			ar9462_2p1_modes_high_ob_db_tx_gain);  	else if (AR_SREV_9462_20(ah))  		INIT_INI_ARRAY(&ah->iniModesTxGain, -			ar9462_modes_high_ob_db_tx_gain_table_2p0); +			ar9462_2p0_modes_high_ob_db_tx_gain); +	else if (AR_SREV_9565_11(ah)) +		INIT_INI_ARRAY(&ah->iniModesTxGain, +			       ar9565_1p1_modes_high_ob_db_tx_gain_table);  	else if (AR_SREV_9565(ah))  		INIT_INI_ARRAY(&ah->iniModesTxGain,  			       ar9565_1p0_modes_high_ob_db_tx_gain_table); @@ -498,6 +595,9 @@ static void ar9003_tx_gain_table_mode2(struct ath_hw *ah)  	else if (AR_SREV_9580(ah))  		INIT_INI_ARRAY(&ah->iniModesTxGain,  			ar9580_1p0_low_ob_db_tx_gain_table); +	else if (AR_SREV_9565_11(ah)) +		INIT_INI_ARRAY(&ah->iniModesTxGain, +			       ar9565_1p1_modes_low_ob_db_tx_gain_table);  	else if (AR_SREV_9565(ah))  		INIT_INI_ARRAY(&ah->iniModesTxGain,  			       ar9565_1p0_modes_low_ob_db_tx_gain_table); @@ -523,12 +623,20 @@ static void ar9003_tx_gain_table_mode3(struct ath_hw *ah)  	else if (AR_SREV_9580(ah))  		INIT_INI_ARRAY(&ah->iniModesTxGain,  			ar9580_1p0_high_power_tx_gain_table); +	else if (AR_SREV_9565_11(ah)) +		INIT_INI_ARRAY(&ah->iniModesTxGain, +			       ar9565_1p1_modes_high_power_tx_gain_table);  	else if (AR_SREV_9565(ah))  		INIT_INI_ARRAY(&ah->iniModesTxGain,  			       ar9565_1p0_modes_high_power_tx_gain_table); -	else -		INIT_INI_ARRAY(&ah->iniModesTxGain, -			ar9300Modes_high_power_tx_gain_table_2p2); +	else { +		if (ah->config.tx_gain_buffalo) +			INIT_INI_ARRAY(&ah->iniModesTxGain, +				       ar9300Modes_high_power_tx_gain_table_buffalo); +		else +			INIT_INI_ARRAY(&ah->iniModesTxGain, +				       ar9300Modes_high_power_tx_gain_table_2p2); +	}  }  static void ar9003_tx_gain_table_mode4(struct ath_hw *ah) @@ -544,7 +652,7 @@ static void ar9003_tx_gain_table_mode4(struct ath_hw *ah)  		       ar9462_2p1_modes_mix_ob_db_tx_gain);  	else if (AR_SREV_9462_20(ah))  		INIT_INI_ARRAY(&ah->iniModesTxGain, -		       ar9462_modes_mix_ob_db_tx_gain_table_2p0); +		       ar9462_2p0_modes_mix_ob_db_tx_gain);  	else  		INIT_INI_ARRAY(&ah->iniModesTxGain,  			ar9300Modes_mixed_ob_db_tx_gain_table_2p2); @@ -579,6 +687,13 @@ static void ar9003_tx_gain_table_mode6(struct ath_hw *ah)  			ar9580_1p0_type6_tx_gain_table);  } +static void ar9003_tx_gain_table_mode7(struct ath_hw *ah) +{ +	if (AR_SREV_9340(ah)) +		INIT_INI_ARRAY(&ah->iniModesTxGain, +			       ar9340_cus227_tx_gain_table_1p0); +} +  typedef void (*ath_txgain_tab)(struct ath_hw *ah);  static void ar9003_tx_gain_table_apply(struct ath_hw *ah) @@ -591,6 +706,7 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah)  		ar9003_tx_gain_table_mode4,  		ar9003_tx_gain_table_mode5,  		ar9003_tx_gain_table_mode6, +		ar9003_tx_gain_table_mode7,  	};  	int idx = ar9003_hw_get_tx_gain_idx(ah); @@ -619,6 +735,11 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah)  				ar955x_1p0_common_rx_gain_table);  		INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,  				ar955x_1p0_common_rx_gain_bounds); +	} else if (AR_SREV_9531(ah)) { +		INIT_INI_ARRAY(&ah->iniModesRxGain, +			       qca953x_1p0_common_rx_gain_table); +		INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, +			       qca953x_1p0_common_rx_gain_bounds);  	} else if (AR_SREV_9580(ah))  		INIT_INI_ARRAY(&ah->iniModesRxGain,  				ar9580_1p0_rx_gain_table); @@ -627,7 +748,13 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah)  				ar9462_2p1_common_rx_gain);  	else if (AR_SREV_9462_20(ah))  		INIT_INI_ARRAY(&ah->iniModesRxGain, -				ar9462_common_rx_gain_table_2p0); +				ar9462_2p0_common_rx_gain); +	else if (AR_SREV_9565_11(ah)) +		INIT_INI_ARRAY(&ah->iniModesRxGain, +			       ar9565_1p1_Common_rx_gain_table); +	else if (AR_SREV_9565(ah)) +		INIT_INI_ARRAY(&ah->iniModesRxGain, +			       ar9565_1p0_Common_rx_gain_table);  	else  		INIT_INI_ARRAY(&ah->iniModesRxGain,  				ar9300Common_rx_gain_table_2p2); @@ -652,15 +779,23 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah)  			ar9462_2p1_common_wo_xlna_rx_gain);  	else if (AR_SREV_9462_20(ah))  		INIT_INI_ARRAY(&ah->iniModesRxGain, -			ar9462_common_wo_xlna_rx_gain_table_2p0); +			ar9462_2p0_common_wo_xlna_rx_gain);  	else if (AR_SREV_9550(ah)) {  		INIT_INI_ARRAY(&ah->iniModesRxGain,  			ar955x_1p0_common_wo_xlna_rx_gain_table);  		INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,  			ar955x_1p0_common_wo_xlna_rx_gain_bounds); +	} else if (AR_SREV_9531(ah)) { +		INIT_INI_ARRAY(&ah->iniModesRxGain, +			       qca953x_1p0_common_wo_xlna_rx_gain_table); +		INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, +			       qca953x_1p0_common_wo_xlna_rx_gain_bounds);  	} else if (AR_SREV_9580(ah))  		INIT_INI_ARRAY(&ah->iniModesRxGain,  			ar9580_1p0_wo_xlna_rx_gain_table); +	else if (AR_SREV_9565_11(ah)) +		INIT_INI_ARRAY(&ah->iniModesRxGain, +			       ar9565_1p1_common_wo_xlna_rx_gain_table);  	else if (AR_SREV_9565(ah))  		INIT_INI_ARRAY(&ah->iniModesRxGain,  			       ar9565_1p0_common_wo_xlna_rx_gain_table); @@ -682,7 +817,7 @@ static void ar9003_rx_gain_table_mode2(struct ath_hw *ah)  			       ar9462_2p1_baseband_postamble_5g_xlna);  	} else if (AR_SREV_9462_20(ah)) {  		INIT_INI_ARRAY(&ah->iniModesRxGain, -			       ar9462_common_mixed_rx_gain_table_2p0); +			       ar9462_2p0_common_mixed_rx_gain);  		INIT_INI_ARRAY(&ah->ini_modes_rxgain_bb_core,  			       ar9462_2p0_baseband_core_mix_rxgain);  		INIT_INI_ARRAY(&ah->ini_modes_rxgain_bb_postamble, @@ -696,12 +831,12 @@ static void ar9003_rx_gain_table_mode3(struct ath_hw *ah)  {  	if (AR_SREV_9462_21(ah)) {  		INIT_INI_ARRAY(&ah->iniModesRxGain, -			       ar9462_2p1_common_5g_xlna_only_rx_gain); +			       ar9462_2p1_common_5g_xlna_only_rxgain);  		INIT_INI_ARRAY(&ah->ini_modes_rxgain_5g_xlna,  			       ar9462_2p1_baseband_postamble_5g_xlna);  	} else if (AR_SREV_9462_20(ah)) {  		INIT_INI_ARRAY(&ah->iniModesRxGain, -			       ar9462_2p0_5g_xlna_only_rxgain); +			       ar9462_2p0_common_5g_xlna_only_rxgain);  		INIT_INI_ARRAY(&ah->ini_modes_rxgain_5g_xlna,  			       ar9462_2p0_baseband_postamble_5g_xlna);  	} @@ -745,6 +880,9 @@ static void ar9003_hw_init_mode_gain_regs(struct ath_hw *ah)  static void ar9003_hw_configpcipowersave(struct ath_hw *ah,  					 bool power_off)  { +	unsigned int i; +	struct ar5416IniArray *array; +  	/*  	 * Increase L1 Entry Latency. Some WB222 boards don't have  	 * this change in eeprom/OTP. @@ -770,19 +908,125 @@ static void ar9003_hw_configpcipowersave(struct ath_hw *ah,  	 * Configire PCIE after Ini init. SERDES values now come from ini file  	 * This enables PCIe low power mode.  	 */ -	if (ah->config.pcieSerDesWrite) { -		unsigned int i; -		struct ar5416IniArray *array; +	array = power_off ? &ah->iniPcieSerdes : +		&ah->iniPcieSerdesLowPower; + +	for (i = 0; i < array->ia_rows; i++) { +		REG_WRITE(ah, +			  INI_RA(array, i, 0), +			  INI_RA(array, i, 1)); +	} +} + +static void ar9003_hw_init_hang_checks(struct ath_hw *ah) +{ +	/* +	 * All chips support detection of BB/MAC hangs. +	 */ +	ah->config.hw_hang_checks |= HW_BB_WATCHDOG; +	ah->config.hw_hang_checks |= HW_MAC_HANG; + +	/* +	 * This is not required for AR9580 1.0 +	 */ +	if (AR_SREV_9300_22(ah)) +		ah->config.hw_hang_checks |= HW_PHYRESTART_CLC_WAR; -		array = power_off ? &ah->iniPcieSerdes : -				    &ah->iniPcieSerdesLowPower; +	if (AR_SREV_9330(ah)) +		ah->bb_watchdog_timeout_ms = 85; +	else +		ah->bb_watchdog_timeout_ms = 25; +} + +/* + * MAC HW hang check + * ================= + * + * Signature: dcu_chain_state is 0x6 and dcu_complete_state is 0x1. + * + * The state of each DCU chain (mapped to TX queues) is available from these + * DMA debug registers: + * + * Chain 0 state : Bits 4:0   of AR_DMADBG_4 + * Chain 1 state : Bits 9:5   of AR_DMADBG_4 + * Chain 2 state : Bits 14:10 of AR_DMADBG_4 + * Chain 3 state : Bits 19:15 of AR_DMADBG_4 + * Chain 4 state : Bits 24:20 of AR_DMADBG_4 + * Chain 5 state : Bits 29:25 of AR_DMADBG_4 + * Chain 6 state : Bits 4:0   of AR_DMADBG_5 + * Chain 7 state : Bits 9:5   of AR_DMADBG_5 + * Chain 8 state : Bits 14:10 of AR_DMADBG_5 + * Chain 9 state : Bits 19:15 of AR_DMADBG_5 + * + * The DCU chain state "0x6" means "WAIT_FRDONE" - wait for TX frame to be done. + */ + +#define NUM_STATUS_READS 50 + +static bool ath9k_hw_verify_hang(struct ath_hw *ah, unsigned int queue) +{ +	u32 dma_dbg_chain, dma_dbg_complete; +	u8 dcu_chain_state, dcu_complete_state; +	int i; + +	for (i = 0; i < NUM_STATUS_READS; i++) { +		if (queue < 6) +			dma_dbg_chain = REG_READ(ah, AR_DMADBG_4); +		else +			dma_dbg_chain = REG_READ(ah, AR_DMADBG_5); + +		dma_dbg_complete = REG_READ(ah, AR_DMADBG_6); + +		dcu_chain_state = (dma_dbg_chain >> (5 * queue)) & 0x1f; +		dcu_complete_state = dma_dbg_complete & 0x3; + +		if ((dcu_chain_state != 0x6) || (dcu_complete_state != 0x1)) +			return false; +	} + +	ath_dbg(ath9k_hw_common(ah), RESET, +		"MAC Hang signature found for queue: %d\n", queue); + +	return true; +} + +static bool ar9003_hw_detect_mac_hang(struct ath_hw *ah) +{ +	u32 dma_dbg_4, dma_dbg_5, dma_dbg_6, chk_dbg; +	u8 dcu_chain_state, dcu_complete_state; +	bool dcu_wait_frdone = false; +	unsigned long chk_dcu = 0; +	unsigned int i = 0; + +	dma_dbg_4 = REG_READ(ah, AR_DMADBG_4); +	dma_dbg_5 = REG_READ(ah, AR_DMADBG_5); +	dma_dbg_6 = REG_READ(ah, AR_DMADBG_6); + +	dcu_complete_state = dma_dbg_6 & 0x3; +	if (dcu_complete_state != 0x1) +		goto exit; + +	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { +		if (i < 6) +			chk_dbg = dma_dbg_4; +		else +			chk_dbg = dma_dbg_5; + +		dcu_chain_state = (chk_dbg >> (5 * i)) & 0x1f; +		if (dcu_chain_state == 0x6) { +			dcu_wait_frdone = true; +			chk_dcu |= BIT(i); +		} +	} -		for (i = 0; i < array->ia_rows; i++) { -			REG_WRITE(ah, -				  INI_RA(array, i, 0), -				  INI_RA(array, i, 1)); +	if ((dcu_complete_state == 0x1) && dcu_wait_frdone) { +		for_each_set_bit(i, &chk_dcu, ATH9K_NUM_TX_QUEUES) { +			if (ath9k_hw_verify_hang(ah, i)) +				return true;  		}  	} +exit: +	return false;  }  /* Sets up the AR9003 hardware familiy callbacks */ @@ -793,6 +1037,8 @@ void ar9003_hw_attach_ops(struct ath_hw *ah)  	ar9003_hw_init_mode_regs(ah);  	priv_ops->init_mode_gain_regs = ar9003_hw_init_mode_gain_regs; +	priv_ops->init_hang_checks = ar9003_hw_init_hang_checks; +	priv_ops->detect_mac_hang = ar9003_hw_detect_mac_hang;  	ops->config_pci_powersave = ar9003_hw_configpcipowersave; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index f6c5c1b5047..729ffbf0734 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -175,7 +175,8 @@ static void ar9003_hw_set_desc_link(void *ds, u32 ds_link)  	ads->ctl10 |= ar9003_calc_ptr_chksum(ads);  } -static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) +static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked, +			      u32 *sync_cause_p)  {  	u32 isr = 0;  	u32 mask2 = 0; @@ -310,7 +311,8 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)  		ar9003_mci_get_isr(ah, masked);  	if (sync_cause) { -		ath9k_debug_sync_cause(common, sync_cause); +		if (sync_cause_p) +			*sync_cause_p = sync_cause;  		fatal_int =  			(sync_cause &  			 (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR)) @@ -476,12 +478,12 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,  	/* XXX: Keycache */  	rxs->rs_rssi = MS(rxsp->status5, AR_RxRSSICombined); -	rxs->rs_rssi_ctl0 = MS(rxsp->status1, AR_RxRSSIAnt00); -	rxs->rs_rssi_ctl1 = MS(rxsp->status1, AR_RxRSSIAnt01); -	rxs->rs_rssi_ctl2 = MS(rxsp->status1, AR_RxRSSIAnt02); -	rxs->rs_rssi_ext0 = MS(rxsp->status5, AR_RxRSSIAnt10); -	rxs->rs_rssi_ext1 = MS(rxsp->status5, AR_RxRSSIAnt11); -	rxs->rs_rssi_ext2 = MS(rxsp->status5, AR_RxRSSIAnt12); +	rxs->rs_rssi_ctl[0] = MS(rxsp->status1, AR_RxRSSIAnt00); +	rxs->rs_rssi_ctl[1] = MS(rxsp->status1, AR_RxRSSIAnt01); +	rxs->rs_rssi_ctl[2] = MS(rxsp->status1, AR_RxRSSIAnt02); +	rxs->rs_rssi_ext[0] = MS(rxsp->status5, AR_RxRSSIAnt10); +	rxs->rs_rssi_ext[1] = MS(rxsp->status5, AR_RxRSSIAnt11); +	rxs->rs_rssi_ext[2] = MS(rxsp->status5, AR_RxRSSIAnt12);  	if (rxsp->status11 & AR_RxKeyIdxValid)  		rxs->rs_keyix = MS(rxsp->status11, AR_KeyIdx); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index 8dd069259e7..7b94a6c7db3 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -753,9 +753,9 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,  		    1 << AR_PHY_TIMING_CONTROL4_DO_GAIN_DC_IQ_CAL_SHIFT);  	if (caldata) { -		caldata->done_txiqcal_once = false; -		caldata->done_txclcal_once = false; -		caldata->rtt_done = false; +		clear_bit(TXIQCAL_DONE, &caldata->cal_flags); +		clear_bit(TXCLCAL_DONE, &caldata->cal_flags); +		clear_bit(RTT_DONE, &caldata->cal_flags);  	}  	if (!ath9k_hw_init_cal(ah, chan)) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index e897648d323..8927fc34d84 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -103,7 +103,7 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)  			} else {  				channelSel = CHANSEL_2G(freq) >> 1;  			} -		} else if (AR_SREV_9550(ah)) { +		} else if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) {  			if (ah->is_clk_25mhz)  				div = 75;  			else @@ -118,7 +118,7 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)  		/* Set to 2G mode */  		bMode = 1;  	} else { -		if ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) && +		if ((AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) &&  		    ah->is_clk_25mhz) {  			channelSel = freq / 75;  			chan_frac = ((freq % 75) * 0x20000) / 75; @@ -551,8 +551,7 @@ static void ar9003_hw_set_channel_regs(struct ath_hw *ah,  	if (IS_CHAN_HT40(chan)) {  		phymode |= AR_PHY_GC_DYN2040_EN;  		/* Configure control (primary) channel at +-10MHz */ -		if ((chan->chanmode == CHANNEL_A_HT40PLUS) || -		    (chan->chanmode == CHANNEL_G_HT40PLUS)) +		if (IS_CHAN_HT40PLUS(chan))  			phymode |= AR_PHY_GC_DYN2040_PRI_CH;  	} @@ -565,7 +564,7 @@ static void ar9003_hw_set_channel_regs(struct ath_hw *ah,  	REG_WRITE(ah, AR_PHY_GEN_CTRL, phymode);  	/* Configure MAC for 20/40 operation */ -	ath9k_hw_set11nmac2040(ah); +	ath9k_hw_set11nmac2040(ah, chan);  	/* global transmit timeout (25 TUs default)*/  	REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S); @@ -627,11 +626,10 @@ static void ar9003_hw_override_ini(struct ath_hw *ah)  	 * MAC addr only will fail.  	 */  	val = REG_READ(ah, AR_PCU_MISC_MODE2) & (~AR_ADHOC_MCAST_KEYID_ENABLE); -	REG_WRITE(ah, AR_PCU_MISC_MODE2, -		  val | AR_AGG_WEP_ENABLE_FIX | AR_AGG_WEP_ENABLE); - -	REG_SET_BIT(ah, AR_PHY_CCK_DETECT, -		    AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); +	val |= AR_AGG_WEP_ENABLE_FIX | +	       AR_AGG_WEP_ENABLE | +	       AR_PCU_MISC_MODE2_CFP_IGNORE; +	REG_WRITE(ah, AR_PCU_MISC_MODE2, val);  	if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {  		REG_WRITE(ah, AR_GLB_SWREG_DISCONT_MODE, @@ -643,11 +641,12 @@ static void ar9003_hw_override_ini(struct ath_hw *ah)  		else  			ah->enabled_cals &= ~TX_IQ_CAL; -		if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) -			ah->enabled_cals |= TX_CL_CAL; -		else -			ah->enabled_cals &= ~TX_CL_CAL;  	} + +	if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) +		ah->enabled_cals |= TX_CL_CAL; +	else +		ah->enabled_cals &= ~TX_CL_CAL;  }  static void ar9003_hw_prog_ini(struct ath_hw *ah, @@ -683,43 +682,72 @@ static int ar9550_hw_get_modes_txgain_index(struct ath_hw *ah,  {  	int ret; -	switch (chan->chanmode) { -	case CHANNEL_A: -	case CHANNEL_A_HT20: -		if (chan->channel <= 5350) -			ret = 1; -		else if ((chan->channel > 5350) && (chan->channel <= 5600)) -			ret = 3; +	if (IS_CHAN_2GHZ(chan)) { +		if (IS_CHAN_HT40(chan)) +			return 7;  		else -			ret = 5; -		break; +			return 8; +	} -	case CHANNEL_A_HT40PLUS: -	case CHANNEL_A_HT40MINUS: -		if (chan->channel <= 5350) -			ret = 2; -		else if ((chan->channel > 5350) && (chan->channel <= 5600)) -			ret = 4; -		else -			ret = 6; -		break; +	if (chan->channel <= 5350) +		ret = 1; +	else if ((chan->channel > 5350) && (chan->channel <= 5600)) +		ret = 3; +	else +		ret = 5; -	case CHANNEL_G: -	case CHANNEL_G_HT20: -	case CHANNEL_B: -		ret = 8; -		break; +	if (IS_CHAN_HT40(chan)) +		ret++; -	case CHANNEL_G_HT40PLUS: -	case CHANNEL_G_HT40MINUS: -		ret = 7; -		break; +	return ret; +} -	default: -		ret = -EINVAL; +static void ar9003_doubler_fix(struct ath_hw *ah) +{ +	if (AR_SREV_9300(ah) || AR_SREV_9580(ah) || AR_SREV_9550(ah)) { +		REG_RMW(ah, AR_PHY_65NM_CH0_RXTX2, +			1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | +			1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); +		REG_RMW(ah, AR_PHY_65NM_CH1_RXTX2, +			1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | +			1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); +		REG_RMW(ah, AR_PHY_65NM_CH2_RXTX2, +			1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | +			1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); + +		udelay(200); + +		REG_CLR_BIT(ah, AR_PHY_65NM_CH0_RXTX2, +			    AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); +		REG_CLR_BIT(ah, AR_PHY_65NM_CH1_RXTX2, +			    AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); +		REG_CLR_BIT(ah, AR_PHY_65NM_CH2_RXTX2, +			    AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); + +		udelay(1); + +		REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_RXTX2, +			      AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); +		REG_RMW_FIELD(ah, AR_PHY_65NM_CH1_RXTX2, +			      AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); +		REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX2, +			      AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); + +		udelay(200); + +		REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_SYNTH12, +			      AR_PHY_65NM_CH0_SYNTH12_VREFMUL3, 0xf); + +		REG_RMW(ah, AR_PHY_65NM_CH0_RXTX2, 0, +			1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | +			1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); +		REG_RMW(ah, AR_PHY_65NM_CH1_RXTX2, 0, +			1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | +			1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); +		REG_RMW(ah, AR_PHY_65NM_CH2_RXTX2, 0, +			1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | +			1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S);  	} - -	return ret;  }  static int ar9003_hw_process_ini(struct ath_hw *ah, @@ -728,28 +756,10 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,  	unsigned int regWrites = 0, i;  	u32 modesIndex; -	switch (chan->chanmode) { -	case CHANNEL_A: -	case CHANNEL_A_HT20: -		modesIndex = 1; -		break; -	case CHANNEL_A_HT40PLUS: -	case CHANNEL_A_HT40MINUS: -		modesIndex = 2; -		break; -	case CHANNEL_G: -	case CHANNEL_G_HT20: -	case CHANNEL_B: -		modesIndex = 4; -		break; -	case CHANNEL_G_HT40PLUS: -	case CHANNEL_G_HT40MINUS: -		modesIndex = 3; -		break; - -	default: -		return -EINVAL; -	} +	if (IS_CHAN_5GHZ(chan)) +		modesIndex = IS_CHAN_HT40(chan) ? 2 : 1; +	else +		modesIndex = IS_CHAN_HT40(chan) ? 3 : 4;  	/*  	 * SOC, MAC, BB, RADIO initvals. @@ -765,6 +775,8 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,  					   modesIndex);  	} +	ar9003_doubler_fix(ah); +  	/*  	 * RXGAIN initvals.  	 */ @@ -798,10 +810,12 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,  	/*  	 * TXGAIN initvals.  	 */ -	if (AR_SREV_9550(ah)) { -		int modes_txgain_index; +	if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) { +		int modes_txgain_index = 1; + +		if (AR_SREV_9550(ah)) +			modes_txgain_index = ar9550_hw_get_modes_txgain_index(ah, chan); -		modes_txgain_index = ar9550_hw_get_modes_txgain_index(ah, chan);  		if (modes_txgain_index < 0)  			return -EINVAL; @@ -847,15 +861,13 @@ static void ar9003_hw_set_rfmode(struct ath_hw *ah,  	if (chan == NULL)  		return; -	rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan)) -		? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM; +	if (IS_CHAN_2GHZ(chan)) +		rfMode |= AR_PHY_MODE_DYNAMIC; +	else +		rfMode |= AR_PHY_MODE_OFDM;  	if (IS_CHAN_A_FAST_CLOCK(ah, chan))  		rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); -	if (IS_CHAN_QUARTER_RATE(chan)) -		rfMode |= AR_PHY_MODE_QUARTER; -	if (IS_CHAN_HALF_RATE(chan)) -		rfMode |= AR_PHY_MODE_HALF;  	if (rfMode & (AR_PHY_MODE_QUARTER | AR_PHY_MODE_HALF))  		REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, @@ -1274,12 +1286,11 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)  	aniState = &ah->ani;  	iniDef = &aniState->iniDef; -	ath_dbg(common, ANI, "ver %d.%d opmode %u chan %d Mhz/0x%x\n", +	ath_dbg(common, ANI, "ver %d.%d opmode %u chan %d Mhz\n",  		ah->hw_version.macVersion,  		ah->hw_version.macRev,  		ah->opmode, -		chan->channel, -		chan->channelFlags); +		chan->channel);  	val = REG_READ(ah, AR_PHY_SFCORR);  	iniDef->m1Thresh = MS(val, AR_PHY_SFCORR_M1_THRESH); @@ -1319,6 +1330,7 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)  static void ar9003_hw_set_radar_params(struct ath_hw *ah,  				       struct ath_hw_radar_conf *conf)  { +	unsigned int regWrites = 0;  	u32 radar_0 = 0, radar_1 = 0;  	if (!conf) { @@ -1345,6 +1357,11 @@ static void ar9003_hw_set_radar_params(struct ath_hw *ah,  		REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);  	else  		REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA); + +	if (AR_SREV_9300(ah) || AR_SREV_9340(ah) || AR_SREV_9580(ah)) { +		REG_WRITE_ARRAY(&ah->ini_dfs, +				IS_CHAN_HT40(ah->curchan) ? 2 : 1, regWrites); +	}  }  static void ar9003_hw_set_radar_conf(struct ath_hw *ah) @@ -1375,15 +1392,19 @@ static void ar9003_hw_antdiv_comb_conf_get(struct ath_hw *ah,  				  AR_PHY_ANT_FAST_DIV_BIAS_S;  	if (AR_SREV_9330_11(ah)) { +		antconf->lna1_lna2_switch_delta = -1;  		antconf->lna1_lna2_delta = -9;  		antconf->div_group = 1;  	} else if (AR_SREV_9485(ah)) { +		antconf->lna1_lna2_switch_delta = -1;  		antconf->lna1_lna2_delta = -9;  		antconf->div_group = 2;  	} else if (AR_SREV_9565(ah)) { -		antconf->lna1_lna2_delta = -3; +		antconf->lna1_lna2_switch_delta = 3; +		antconf->lna1_lna2_delta = -9;  		antconf->div_group = 3;  	} else { +		antconf->lna1_lna2_switch_delta = -1;  		antconf->lna1_lna2_delta = -3;  		antconf->div_group = 0;  	} @@ -1489,17 +1510,24 @@ static void ar9003_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable)  	} else if (AR_SREV_9565(ah)) {  		if (enable) {  			REG_SET_BIT(ah, AR_PHY_MC_GAIN_CTRL, +				    AR_ANT_DIV_ENABLE); +			REG_SET_BIT(ah, AR_PHY_MC_GAIN_CTRL,  				    (1 << AR_PHY_ANT_SW_RX_PROT_S)); -			if (ah->curchan && IS_CHAN_2GHZ(ah->curchan)) -				REG_SET_BIT(ah, AR_PHY_RESTART, -					    AR_PHY_RESTART_ENABLE_DIV_M2FLAG); +			REG_SET_BIT(ah, AR_PHY_CCK_DETECT, +				    AR_FAST_DIV_ENABLE); +			REG_SET_BIT(ah, AR_PHY_RESTART, +				    AR_PHY_RESTART_ENABLE_DIV_M2FLAG);  			REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV,  				    AR_BTCOEX_WL_LNADIV_FORCE_ON);  		} else { -			REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, AR_ANT_DIV_ENABLE); +			REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, +				    AR_ANT_DIV_ENABLE);  			REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL,  				    (1 << AR_PHY_ANT_SW_RX_PROT_S)); -			REG_CLR_BIT(ah, AR_PHY_CCK_DETECT, AR_FAST_DIV_ENABLE); +			REG_CLR_BIT(ah, AR_PHY_CCK_DETECT, +				    AR_FAST_DIV_ENABLE); +			REG_CLR_BIT(ah, AR_PHY_RESTART, +				    AR_PHY_RESTART_ENABLE_DIV_M2FLAG);  			REG_CLR_BIT(ah, AR_BTCOEX_WL_LNADIV,  				    AR_BTCOEX_WL_LNADIV_FORCE_ON); @@ -1526,28 +1554,10 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah,  	unsigned int regWrites = 0;  	u32 modesIndex; -	switch (chan->chanmode) { -	case CHANNEL_A: -	case CHANNEL_A_HT20: -		modesIndex = 1; -		break; -	case CHANNEL_A_HT40PLUS: -	case CHANNEL_A_HT40MINUS: -		modesIndex = 2; -		break; -	case CHANNEL_G: -	case CHANNEL_G_HT20: -	case CHANNEL_B: -		modesIndex = 4; -		break; -	case CHANNEL_G_HT40PLUS: -	case CHANNEL_G_HT40MINUS: -		modesIndex = 3; -		break; - -	default: -		return -EINVAL; -	} +	if (IS_CHAN_5GHZ(chan)) +		modesIndex = IS_CHAN_HT40(chan) ? 2 : 1; +	else +		modesIndex = IS_CHAN_HT40(chan) ? 3 : 4;  	if (modesIndex == ah->modes_index) {  		*ini_reloaded = false; @@ -1662,6 +1672,98 @@ static void ar9003_hw_spectral_scan_wait(struct ath_hw *ah)  	}  } +static void ar9003_hw_tx99_start(struct ath_hw *ah, u32 qnum) +{ +	REG_SET_BIT(ah, AR_PHY_TEST, PHY_AGC_CLR); +	REG_SET_BIT(ah, 0x9864, 0x7f000); +	REG_SET_BIT(ah, 0x9924, 0x7f00fe); +	REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); +	REG_WRITE(ah, AR_CR, AR_CR_RXD); +	REG_WRITE(ah, AR_DLCL_IFS(qnum), 0); +	REG_WRITE(ah, AR_D_GBL_IFS_SIFS, 20); /* 50 OK */ +	REG_WRITE(ah, AR_D_GBL_IFS_EIFS, 20); +	REG_WRITE(ah, AR_TIME_OUT, 0x00000400); +	REG_WRITE(ah, AR_DRETRY_LIMIT(qnum), 0xffffffff); +	REG_SET_BIT(ah, AR_QMISC(qnum), AR_Q_MISC_DCU_EARLY_TERM_REQ); +} + +static void ar9003_hw_tx99_stop(struct ath_hw *ah) +{ +	REG_CLR_BIT(ah, AR_PHY_TEST, PHY_AGC_CLR); +	REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); +} + +static void ar9003_hw_tx99_set_txpower(struct ath_hw *ah, u8 txpower) +{ +	static s16 p_pwr_array[ar9300RateSize] = { 0 }; +	unsigned int i; + +	if (txpower <= MAX_RATE_POWER) { +		for (i = 0; i < ar9300RateSize; i++) +			p_pwr_array[i] = txpower; +	} else { +		for (i = 0; i < ar9300RateSize; i++) +			p_pwr_array[i] = MAX_RATE_POWER; +	} + +	REG_WRITE(ah, 0xa458, 0); + +	REG_WRITE(ah, 0xa3c0, +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 24) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 16) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24],  8) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24],  0)); +	REG_WRITE(ah, 0xa3c4, +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_54],  24) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_48],  16) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_36],   8) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 0)); +	REG_WRITE(ah, 0xa3c8, +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 24) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 16) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L],  0)); +	REG_WRITE(ah, 0xa3cc, +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_11S],   24) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_11L],   16) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_5S],     8) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L],  0)); +	REG_WRITE(ah, 0xa3d0, +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_5],  24) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_4],  16) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_1_3_9_11_17_19], 8)| +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_0_8_16], 0)); +	REG_WRITE(ah, 0xa3d4, +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_13], 24) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_12], 16) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_7],   8) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_6],   0)); +	REG_WRITE(ah, 0xa3e4, +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_21], 24) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_20], 16) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_15],  8) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_14],  0)); +	REG_WRITE(ah, 0xa3e8, +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_23], 24) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_22], 16) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_23],  8) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_22],  0)); +	REG_WRITE(ah, 0xa3d8, +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_5], 24) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_4], 16) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_1_3_9_11_17_19], 8) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_0_8_16], 0)); +	REG_WRITE(ah, 0xa3dc, +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_13], 24) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_12], 16) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_7],   8) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_6],   0)); +	REG_WRITE(ah, 0xa3ec, +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_21], 24) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_20], 16) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_15],  8) | +		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_14],  0)); +} +  void ar9003_hw_attach_phy_ops(struct ath_hw *ah)  {  	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); @@ -1701,12 +1803,77 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)  #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT  	ops->set_bt_ant_diversity = ar9003_hw_set_bt_ant_diversity;  #endif +	ops->tx99_start = ar9003_hw_tx99_start; +	ops->tx99_stop = ar9003_hw_tx99_stop; +	ops->tx99_set_txpower = ar9003_hw_tx99_set_txpower;  	ar9003_hw_set_nf_limits(ah);  	ar9003_hw_set_radar_conf(ah);  	memcpy(ah->nf_regs, ar9300_cca_regs, sizeof(ah->nf_regs));  } +/* + * Baseband Watchdog signatures: + * + * 0x04000539: BB hang when operating in HT40 DFS Channel. + *             Full chip reset is not required, but a recovery + *             mechanism is needed. + * + * 0x1300000a: Related to CAC deafness. + *             Chip reset is not required. + * + * 0x0400000a: Related to CAC deafness. + *             Full chip reset is required. + * + * 0x04000b09: RX state machine gets into an illegal state + *             when a packet with unsupported rate is received. + *             Full chip reset is required and PHY_RESTART has + *             to be disabled. + * + * 0x04000409: Packet stuck on receive. + *             Full chip reset is required for all chips except AR9340. + */ + +/* + * ar9003_hw_bb_watchdog_check(): Returns true if a chip reset is required. + */ +bool ar9003_hw_bb_watchdog_check(struct ath_hw *ah) +{ +	u32 val; + +	switch(ah->bb_watchdog_last_status) { +	case 0x04000539: +		val = REG_READ(ah, AR_PHY_RADAR_0); +		val &= (~AR_PHY_RADAR_0_FIRPWR); +		val |= SM(0x7f, AR_PHY_RADAR_0_FIRPWR); +		REG_WRITE(ah, AR_PHY_RADAR_0, val); +		udelay(1); +		val = REG_READ(ah, AR_PHY_RADAR_0); +		val &= ~AR_PHY_RADAR_0_FIRPWR; +		val |= SM(AR9300_DFS_FIRPWR, AR_PHY_RADAR_0_FIRPWR); +		REG_WRITE(ah, AR_PHY_RADAR_0, val); + +		return false; +	case 0x1300000a: +		return false; +	case 0x0400000a: +	case 0x04000b09: +		return true; +	case 0x04000409: +		if (AR_SREV_9340(ah) || AR_SREV_9531(ah)) +			return false; +		else +			return true; +	default: +		/* +		 * For any other unknown signatures, do a +		 * full chip reset. +		 */ +		return true; +	} +} +EXPORT_SYMBOL(ar9003_hw_bb_watchdog_check); +  void ar9003_hw_bb_watchdog_config(struct ath_hw *ah)  {  	struct ath_common *common = ath9k_hw_common(ah); @@ -1823,6 +1990,7 @@ EXPORT_SYMBOL(ar9003_hw_bb_watchdog_dbg_info);  void ar9003_hw_disable_phy_restart(struct ath_hw *ah)  { +	u8 result;  	u32 val;  	/* While receiving unsupported rate frame rx state machine @@ -1830,15 +1998,13 @@ void ar9003_hw_disable_phy_restart(struct ath_hw *ah)  	 * state, BB would go hang. If RXSM is in 0xb state after  	 * first bb panic, ensure to disable the phy_restart.  	 */ -	if (!((MS(ah->bb_watchdog_last_status, -		  AR_PHY_WATCHDOG_RX_OFDM_SM) == 0xb) || -	    ah->bb_hang_rx_ofdm)) -		return; +	result = MS(ah->bb_watchdog_last_status, AR_PHY_WATCHDOG_RX_OFDM_SM); -	ah->bb_hang_rx_ofdm = true; -	val = REG_READ(ah, AR_PHY_RESTART); -	val &= ~AR_PHY_RESTART_ENA; - -	REG_WRITE(ah, AR_PHY_RESTART, val); +	if ((result == 0xb) || ah->bb_hang_rx_ofdm) { +		ah->bb_hang_rx_ofdm = true; +		val = REG_READ(ah, AR_PHY_RESTART); +		val &= ~AR_PHY_RESTART_ENA; +		REG_WRITE(ah, AR_PHY_RESTART, val); +	}  }  EXPORT_SYMBOL(ar9003_hw_disable_phy_restart); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 6fd752321e3..fd090b1f2d0 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -270,7 +270,7 @@  #define AR_PHY_AGC              (AR_AGC_BASE + 0x14)  #define AR_PHY_EXT_ATTEN_CTL_0  (AR_AGC_BASE + 0x18)  #define AR_PHY_CCA_0            (AR_AGC_BASE + 0x1c) -#define AR_PHY_EXT_CCA0         (AR_AGC_BASE + 0x20) +#define AR_PHY_CCA_CTRL_0       (AR_AGC_BASE + 0x20)  #define AR_PHY_RESTART          (AR_AGC_BASE + 0x24)  /* @@ -338,13 +338,17 @@  #define AR_PHY_CCA_NOM_VAL_9300_5GHZ          -115  #define AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ     -125  #define AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ     -125 -#define AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ     -95 -#define AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ     -100 +#define AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ     -60 +#define AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ     -60 +#define AR_PHY_CCA_MAX_GOOD_VAL_9300_FCC_2GHZ -95 +#define AR_PHY_CCA_MAX_GOOD_VAL_9300_FCC_5GHZ -100  #define AR_PHY_CCA_NOM_VAL_9462_2GHZ          -127  #define AR_PHY_CCA_MIN_GOOD_VAL_9462_2GHZ     -127 +#define AR_PHY_CCA_MAX_GOOD_VAL_9462_2GHZ     -60  #define AR_PHY_CCA_NOM_VAL_9462_5GHZ          -127  #define AR_PHY_CCA_MIN_GOOD_VAL_9462_5GHZ     -127 +#define AR_PHY_CCA_MAX_GOOD_VAL_9462_5GHZ     -60  #define AR_PHY_CCA_NOM_VAL_9330_2GHZ          -118 @@ -393,6 +397,8 @@  #define AR9280_PHY_CCA_THRESH62_S   12  #define AR_PHY_EXT_CCA0_THRESH62    0x000000FF  #define AR_PHY_EXT_CCA0_THRESH62_S  0 +#define AR_PHY_EXT_CCA0_THRESH62_1    0x000001FF +#define AR_PHY_EXT_CCA0_THRESH62_1_S  0  #define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK          0x0000003F  #define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK_S        0  #define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME           0x00001FC0 @@ -652,13 +658,34 @@  #define AR_PHY_SYNTH4_LONG_SHIFT_SELECT   ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x00000001 : 0x00000002)  #define AR_PHY_SYNTH4_LONG_SHIFT_SELECT_S ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0 : 1)  #define AR_PHY_65NM_CH0_SYNTH7      0x16098 +#define AR_PHY_65NM_CH0_SYNTH12     0x160ac  #define AR_PHY_65NM_CH0_BIAS1       0x160c0  #define AR_PHY_65NM_CH0_BIAS2       0x160c4  #define AR_PHY_65NM_CH0_BIAS4       0x160cc +#define AR_PHY_65NM_CH0_RXTX2       0x16104 +#define AR_PHY_65NM_CH1_RXTX2       0x16504 +#define AR_PHY_65NM_CH2_RXTX2       0x16904  #define AR_PHY_65NM_CH0_RXTX4       0x1610c  #define AR_PHY_65NM_CH1_RXTX4       0x1650c  #define AR_PHY_65NM_CH2_RXTX4       0x1690c +#define AR_PHY_65NM_CH0_BB1         0x16140 +#define AR_PHY_65NM_CH0_BB2         0x16144 +#define AR_PHY_65NM_CH0_BB3         0x16148 +#define AR_PHY_65NM_CH1_BB1         0x16540 +#define AR_PHY_65NM_CH1_BB2         0x16544 +#define AR_PHY_65NM_CH1_BB3         0x16548 +#define AR_PHY_65NM_CH2_BB1         0x16940 +#define AR_PHY_65NM_CH2_BB2         0x16944 +#define AR_PHY_65NM_CH2_BB3         0x16948 + +#define AR_PHY_65NM_CH0_SYNTH12_VREFMUL3           0x00780000 +#define AR_PHY_65NM_CH0_SYNTH12_VREFMUL3_S         19 +#define AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK         0x00000004 +#define AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S       2 +#define AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK        0x00000008 +#define AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S      3 +  #define AR_CH0_TOP	(AR_SREV_9300(ah) ? 0x16288 : \  			 (((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x1628c : 0x16280)))  #define AR_CH0_TOP_XPABIASLVL (AR_SREV_9550(ah) ? 0x3c0 : 0x300) @@ -1316,4 +1343,6 @@  #define AR_PHY_65NM_RXRF_AGC_AGC_OUT                   0x00000004  #define AR_PHY_65NM_RXRF_AGC_AGC_OUT_S                 2 +#define AR9300_DFS_FIRPWR -28 +  #endif  /* AR9003_PHY_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_rtt.c b/drivers/net/wireless/ath/ath9k/ar9003_rtt.c index 74de3539c2c..934418872e8 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_rtt.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_rtt.c @@ -118,6 +118,27 @@ void ar9003_hw_rtt_load_hist(struct ath_hw *ah)  	}  } +static void ar9003_hw_patch_rtt(struct ath_hw *ah, int index, int chain) +{ +	int agc, caldac; + +	if (!test_bit(SW_PKDET_DONE, &ah->caldata->cal_flags)) +		return; + +	if ((index != 5) || (chain >= 2)) +		return; + +	agc = REG_READ_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), +			     AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE); +	if (!agc) +		return; + +	caldac = ah->caldata->caldac[chain]; +	ah->caldata->rtt_table[chain][index] &= 0xFFFF05FF; +	caldac = (caldac & 0x20) | ((caldac & 0x1F) << 7); +	ah->caldata->rtt_table[chain][index] |= (caldac << 4); +} +  static int ar9003_hw_rtt_fill_hist_entry(struct ath_hw *ah, u8 chain, u32 index)  {  	u32 val; @@ -155,13 +176,16 @@ void ar9003_hw_rtt_fill_hist(struct ath_hw *ah)  		for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) {  			ah->caldata->rtt_table[chain][i] =  				ar9003_hw_rtt_fill_hist_entry(ah, chain, i); + +			ar9003_hw_patch_rtt(ah, i, chain); +  			ath_dbg(ath9k_hw_common(ah), CALIBRATE,  				"RTT value at idx %d, chain %d is: 0x%x\n",  				i, chain, ah->caldata->rtt_table[chain][i]);  		}  	} -	ah->caldata->rtt_done = true; +	set_bit(RTT_DONE, &ah->caldata->cal_flags);  }  void ar9003_hw_rtt_clear_hist(struct ath_hw *ah) @@ -176,7 +200,7 @@ void ar9003_hw_rtt_clear_hist(struct ath_hw *ah)  	}  	if (ah->caldata) -		ah->caldata->rtt_done = false; +		clear_bit(RTT_DONE, &ah->caldata->cal_flags);  }  bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan) @@ -186,11 +210,37 @@ bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan)  	if (!ah->caldata)  		return false; -	if (!ah->caldata->rtt_done) +	if (test_bit(SW_PKDET_DONE, &ah->caldata->cal_flags)) { +		if (IS_CHAN_2GHZ(chan)){ +			REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(0), +				      AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, +				      ah->caldata->caldac[0]); +			REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(1), +				      AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, +				      ah->caldata->caldac[1]); +		} else { +			REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(0), +				      AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR, +				      ah->caldata->caldac[0]); +			REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(1), +				      AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR, +				      ah->caldata->caldac[1]); +		} +		REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(1), +			      AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1); +		REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(0), +			      AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1); +	} + +	if (!test_bit(RTT_DONE, &ah->caldata->cal_flags))  		return false;  	ar9003_hw_rtt_enable(ah); -	ar9003_hw_rtt_set_mask(ah, 0x10); + +	if (test_bit(SW_PKDET_DONE, &ah->caldata->cal_flags)) +		ar9003_hw_rtt_set_mask(ah, 0x30); +	else +		ar9003_hw_rtt_set_mask(ah, 0x10);  	if (!ath9k_hw_rfbus_req(ah)) {  		ath_err(ath9k_hw_common(ah), "Could not stop baseband\n"); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_wow.c b/drivers/net/wireless/ath/ath9k/ar9003_wow.c new file mode 100644 index 00000000000..81c88dd606d --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_wow.c @@ -0,0 +1,422 @@ +/* + * 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/export.h> +#include "ath9k.h" +#include "reg.h" +#include "hw-ops.h" + +const char *ath9k_hw_wow_event_to_string(u32 wow_event) +{ +	if (wow_event & AH_WOW_MAGIC_PATTERN_EN) +		return "Magic pattern"; +	if (wow_event & AH_WOW_USER_PATTERN_EN) +		return "User pattern"; +	if (wow_event & AH_WOW_LINK_CHANGE) +		return "Link change"; +	if (wow_event & AH_WOW_BEACON_MISS) +		return "Beacon miss"; + +	return  "unknown reason"; +} +EXPORT_SYMBOL(ath9k_hw_wow_event_to_string); + +static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah) +{ +	struct ath_common *common = ath9k_hw_common(ah); + +	REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + +	/* set rx disable bit */ +	REG_WRITE(ah, AR_CR, AR_CR_RXD); + +	if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0, AH_WAIT_TIMEOUT)) { +		ath_err(common, "Failed to stop Rx DMA in 10ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n", +			REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW)); +		return; +	} + +	REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT); +} + +static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah) +{ +	struct ath_common *common = ath9k_hw_common(ah); +	u8 sta_mac_addr[ETH_ALEN], ap_mac_addr[ETH_ALEN]; +	u32 ctl[13] = {0}; +	u32 data_word[KAL_NUM_DATA_WORDS]; +	u8 i; +	u32 wow_ka_data_word0; + +	memcpy(sta_mac_addr, common->macaddr, ETH_ALEN); +	memcpy(ap_mac_addr, common->curbssid, ETH_ALEN); + +	/* set the transmit buffer */ +	ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16)); +	ctl[1] = 0; +	ctl[3] = 0xb;	/* OFDM_6M hardware value for this rate */ +	ctl[4] = 0; +	ctl[7] = (ah->txchainmask) << 2; +	ctl[2] = 0xf << 16; /* tx_tries 0 */ + +	for (i = 0; i < KAL_NUM_DESC_WORDS; i++) +		REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); + +	REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); + +	data_word[0] = (KAL_FRAME_TYPE << 2) | (KAL_FRAME_SUB_TYPE << 4) | +		       (KAL_TO_DS << 8) | (KAL_DURATION_ID << 16); +	data_word[1] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) | +		       (ap_mac_addr[1] << 8) | (ap_mac_addr[0]); +	data_word[2] = (sta_mac_addr[1] << 24) | (sta_mac_addr[0] << 16) | +		       (ap_mac_addr[5] << 8) | (ap_mac_addr[4]); +	data_word[3] = (sta_mac_addr[5] << 24) | (sta_mac_addr[4] << 16) | +		       (sta_mac_addr[3] << 8) | (sta_mac_addr[2]); +	data_word[4] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) | +		       (ap_mac_addr[1] << 8) | (ap_mac_addr[0]); +	data_word[5] = (ap_mac_addr[5] << 8) | (ap_mac_addr[4]); + +	if (AR_SREV_9462_20(ah)) { +		/* AR9462 2.0 has an extra descriptor word (time based +		 * discard) compared to other chips */ +		REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + (12 * 4)), 0); +		wow_ka_data_word0 = AR_WOW_TXBUF(13); +	} else { +		wow_ka_data_word0 = AR_WOW_TXBUF(12); +	} + +	for (i = 0; i < KAL_NUM_DATA_WORDS; i++) +		REG_WRITE(ah, (wow_ka_data_word0 + i*4), data_word[i]); + +} + +void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, +				u8 *user_mask, int pattern_count, +				int pattern_len) +{ +	int i; +	u32 pattern_val, mask_val; +	u32 set, clr; + +	/* FIXME: should check count by querying the hardware capability */ +	if (pattern_count >= MAX_NUM_PATTERN) +		return; + +	REG_SET_BIT(ah, AR_WOW_PATTERN, BIT(pattern_count)); + +	/* set the registers for pattern */ +	for (i = 0; i < MAX_PATTERN_SIZE; i += 4) { +		memcpy(&pattern_val, user_pattern, 4); +		REG_WRITE(ah, (AR_WOW_TB_PATTERN(pattern_count) + i), +			  pattern_val); +		user_pattern += 4; +	} + +	/* set the registers for mask */ +	for (i = 0; i < MAX_PATTERN_MASK_SIZE; i += 4) { +		memcpy(&mask_val, user_mask, 4); +		REG_WRITE(ah, (AR_WOW_TB_MASK(pattern_count) + i), mask_val); +		user_mask += 4; +	} + +	/* set the pattern length to be matched +	 * +	 * AR_WOW_LENGTH1_REG1 +	 * bit 31:24 pattern 0 length +	 * bit 23:16 pattern 1 length +	 * bit 15:8 pattern 2 length +	 * bit 7:0 pattern 3 length +	 * +	 * AR_WOW_LENGTH1_REG2 +	 * bit 31:24 pattern 4 length +	 * bit 23:16 pattern 5 length +	 * bit 15:8 pattern 6 length +	 * bit 7:0 pattern 7 length +	 * +	 * the below logic writes out the new +	 * pattern length for the corresponding +	 * pattern_count, while masking out the +	 * other fields +	 */ + +	ah->wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT); + +	if (pattern_count < 4) { +		/* Pattern 0-3 uses AR_WOW_LENGTH1 register */ +		set = (pattern_len & AR_WOW_LENGTH_MAX) << +		       AR_WOW_LEN1_SHIFT(pattern_count); +		clr = AR_WOW_LENGTH1_MASK(pattern_count); +		REG_RMW(ah, AR_WOW_LENGTH1, set, clr); +	} else { +		/* Pattern 4-7 uses AR_WOW_LENGTH2 register */ +		set = (pattern_len & AR_WOW_LENGTH_MAX) << +		       AR_WOW_LEN2_SHIFT(pattern_count); +		clr = AR_WOW_LENGTH2_MASK(pattern_count); +		REG_RMW(ah, AR_WOW_LENGTH2, set, clr); +	} + +} +EXPORT_SYMBOL(ath9k_hw_wow_apply_pattern); + +u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) +{ +	u32 wow_status = 0; +	u32 val = 0, rval; + +	/* +	 * read the WoW status register to know +	 * the wakeup reason +	 */ +	rval = REG_READ(ah, AR_WOW_PATTERN); +	val = AR_WOW_STATUS(rval); + +	/* +	 * mask only the WoW events that we have enabled. Sometimes +	 * we have spurious WoW events from the AR_WOW_PATTERN +	 * register. This mask will clean it up. +	 */ + +	val &= ah->wow_event_mask; + +	if (val) { +		if (val & AR_WOW_MAGIC_PAT_FOUND) +			wow_status |= AH_WOW_MAGIC_PATTERN_EN; +		if (AR_WOW_PATTERN_FOUND(val)) +			wow_status |= AH_WOW_USER_PATTERN_EN; +		if (val & AR_WOW_KEEP_ALIVE_FAIL) +			wow_status |= AH_WOW_LINK_CHANGE; +		if (val & AR_WOW_BEACON_FAIL) +			wow_status |= AH_WOW_BEACON_MISS; +	} + +	/* +	 * set and clear WOW_PME_CLEAR registers for the chip to +	 * generate next wow signal. +	 * disable D3 before accessing other registers ? +	 */ + +	/* do we need to check the bit value 0x01000000 (7-10) ?? */ +	REG_RMW(ah, AR_PCIE_PM_CTRL, AR_PMCTRL_WOW_PME_CLR, +		AR_PMCTRL_PWR_STATE_D1D3); + +	/* +	 * clear all events +	 */ +	REG_WRITE(ah, AR_WOW_PATTERN, +		  AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN))); + +	/* +	 * restore the beacon threshold to init value +	 */ +	REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR); + +	/* +	 * Restore the way the PCI-E reset, Power-On-Reset, external +	 * PCIE_POR_SHORT pins are tied to its original value. +	 * Previously just before WoW sleep, we untie the PCI-E +	 * reset to our Chip's Power On Reset so that any PCI-E +	 * reset from the bus will not reset our chip +	 */ +	if (ah->is_pciexpress) +		ath9k_hw_configpcipowersave(ah, false); + +	ah->wow_event_mask = 0; + +	return wow_status; +} +EXPORT_SYMBOL(ath9k_hw_wow_wakeup); + +void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) +{ +	u32 wow_event_mask; +	u32 set, clr; + +	/* +	 * wow_event_mask is a mask to the AR_WOW_PATTERN register to +	 * indicate which WoW events we have enabled. The WoW events +	 * are from the 'pattern_enable' in this function and +	 * 'pattern_count' of ath9k_hw_wow_apply_pattern() +	 */ +	wow_event_mask = ah->wow_event_mask; + +	/* +	 * Untie Power-on-Reset from the PCI-E-Reset. When we are in +	 * WOW sleep, we do want the Reset from the PCI-E to disturb +	 * our hw state +	 */ +	if (ah->is_pciexpress) { +		/* +		 * we need to untie the internal POR (power-on-reset) +		 * to the external PCI-E reset. We also need to tie +		 * the PCI-E Phy reset to the PCI-E reset. +		 */ +		set = AR_WA_RESET_EN | AR_WA_POR_SHORT; +		clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE; +		REG_RMW(ah, AR_WA, set, clr); +	} + +	/* +	 * set the power states appropriately and enable PME +	 */ +	set = AR_PMCTRL_HOST_PME_EN | AR_PMCTRL_PWR_PM_CTRL_ENA | +	      AR_PMCTRL_AUX_PWR_DET | AR_PMCTRL_WOW_PME_CLR; + +	/* +	 * set and clear WOW_PME_CLEAR registers for the chip +	 * to generate next wow signal. +	 */ +	REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set); +	clr = AR_PMCTRL_WOW_PME_CLR; +	REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr); + +	/* +	 * Setup for: +	 *	- beacon misses +	 *	- magic pattern +	 *	- keep alive timeout +	 *	- pattern matching +	 */ + +	/* +	 * Program default values for pattern backoff, aifs/slot/KAL count, +	 * beacon miss timeout, KAL timeout, etc. +	 */ +	set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF); +	REG_SET_BIT(ah, AR_WOW_PATTERN, set); + +	set = AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) | +	      AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) | +	      AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT); +	REG_SET_BIT(ah, AR_WOW_COUNT, set); + +	if (pattern_enable & AH_WOW_BEACON_MISS) +		set = AR_WOW_BEACON_TIMO; +	/* We are not using beacon miss, program a large value */ +	else +		set = AR_WOW_BEACON_TIMO_MAX; + +	REG_WRITE(ah, AR_WOW_BCN_TIMO, set); + +	/* +	 * Keep alive timo in ms except AR9280 +	 */ +	if (!pattern_enable) +		set = AR_WOW_KEEP_ALIVE_NEVER; +	else +		set = KAL_TIMEOUT * 32; + +	REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, set); + +	/* +	 * Keep alive delay in us. based on 'power on clock', +	 * therefore in usec +	 */ +	set = KAL_DELAY * 1000; +	REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY, set); + +	/* +	 * Create keep alive pattern to respond to beacons +	 */ +	ath9k_wow_create_keep_alive_pattern(ah); + +	/* +	 * Configure MAC WoW Registers +	 */ +	set = 0; +	/* Send keep alive timeouts anyway */ +	clr = AR_WOW_KEEP_ALIVE_AUTO_DIS; + +	if (pattern_enable & AH_WOW_LINK_CHANGE) +		wow_event_mask |= AR_WOW_KEEP_ALIVE_FAIL; +	else +		set = AR_WOW_KEEP_ALIVE_FAIL_DIS; + +	set = AR_WOW_KEEP_ALIVE_FAIL_DIS; +	REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr); + +	/* +	 * we are relying on a bmiss failure. ensure we have +	 * enough threshold to prevent false positives +	 */ +	REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, +		      AR_WOW_BMISSTHRESHOLD); + +	set = 0; +	clr = 0; + +	if (pattern_enable & AH_WOW_BEACON_MISS) { +		set = AR_WOW_BEACON_FAIL_EN; +		wow_event_mask |= AR_WOW_BEACON_FAIL; +	} else { +		clr = AR_WOW_BEACON_FAIL_EN; +	} + +	REG_RMW(ah, AR_WOW_BCN_EN, set, clr); + +	set = 0; +	clr = 0; +	/* +	 * Enable the magic packet registers +	 */ +	if (pattern_enable & AH_WOW_MAGIC_PATTERN_EN) { +		set = AR_WOW_MAGIC_EN; +		wow_event_mask |= AR_WOW_MAGIC_PAT_FOUND; +	} else { +		clr = AR_WOW_MAGIC_EN; +	} +	set |= AR_WOW_MAC_INTR_EN; +	REG_RMW(ah, AR_WOW_PATTERN, set, clr); + +	REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B, +		  AR_WOW_PATTERN_SUPPORTED); + +	/* +	 * Set the power states appropriately and enable PME +	 */ +	clr = 0; +	set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN | +	      AR_PMCTRL_PWR_PM_CTRL_ENA; + +	clr = AR_PCIE_PM_CTRL_ENA; +	REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr); + +	/* +	 * this is needed to prevent the chip waking up +	 * the host within 3-4 seconds with certain +	 * platform/BIOS. The fix is to enable +	 * D1 & D3 to match original definition and +	 * also match the OTP value. Anyway this +	 * is more related to SW WOW. +	 */ +	clr = AR_PMCTRL_PWR_STATE_D1D3; +	REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr); + +	set = AR_PMCTRL_PWR_STATE_D1D3_REAL; +	REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set); + +	REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM); + +	/* to bring down WOW power low margin */ +	set = BIT(13); +	REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set); +	/* HW WoW */ +	clr = BIT(5); +	REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr); + +	ath9k_hw_set_powermode_wow_sleep(ah); +	ah->wow_event_mask = wow_event_mask; +} +EXPORT_SYMBOL(ath9k_hw_wow_enable); diff --git a/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h b/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h index 6e1756bc383..2c42ff05efa 100644 --- a/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h @@ -18,6 +18,10 @@  #ifndef INITVALS_9330_1P1_H  #define INITVALS_9330_1P1_H +#define ar9331_1p1_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484 + +#define ar9331_modes_high_power_tx_gain_1p1 ar9331_modes_lowest_ob_db_tx_gain_1p1 +  static const u32 ar9331_1p1_baseband_postamble[][5] = {  	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */  	{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005}, @@ -55,7 +59,7 @@ static const u32 ar9331_1p1_baseband_postamble[][5] = {  	{0x0000a284, 0x00000000, 0x00000000, 0x00000000, 0x00000000},  	{0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000},  	{0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, +	{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00058d18, 0x00058d18},  	{0x0000a2d0, 0x00071982, 0x00071982, 0x00071982, 0x00071982},  	{0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},  	{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, @@ -252,7 +256,7 @@ static const u32 ar9331_modes_low_ob_db_tx_gain_1p1[][5] = {  	{0x0000a2e0, 0xffffcc84, 0xffffcc84, 0xffffcc84, 0xffffcc84},  	{0x0000a2e4, 0xfffff000, 0xfffff000, 0xfffff000, 0xfffff000},  	{0x0000a2e8, 0xfffe0000, 0xfffe0000, 0xfffe0000, 0xfffe0000}, -	{0x0000a410, 0x000050d7, 0x000050d7, 0x000050d0, 0x000050d0}, +	{0x0000a410, 0x000050d7, 0x000050d7, 0x000050d4, 0x000050d4},  	{0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},  	{0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},  	{0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, @@ -337,8 +341,6 @@ static const u32 ar9331_modes_low_ob_db_tx_gain_1p1[][5] = {  	{0x00016284, 0x14d3f000, 0x14d3f000, 0x14d3f000, 0x14d3f000},  }; -#define ar9331_1p1_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484 -  static const u32 ar9331_1p1_xtal_25M[][2] = {  	/* Addr      allmodes  */  	{0x00007038, 0x000002f8}, @@ -373,17 +375,17 @@ static const u32 ar9331_1p1_radio_core[][2] = {  	{0x000160b4, 0x92480040},  	{0x000160c0, 0x006db6db},  	{0x000160c4, 0x0186db60}, -	{0x000160c8, 0x6db4db6c}, +	{0x000160c8, 0x6db6db6c},  	{0x000160cc, 0x6de6c300},  	{0x000160d0, 0x14500820},  	{0x00016100, 0x04cb0001},  	{0x00016104, 0xfff80015},  	{0x00016108, 0x00080010},  	{0x0001610c, 0x00170000}, -	{0x00016140, 0x10800000}, +	{0x00016140, 0x50804000},  	{0x00016144, 0x01884080},  	{0x00016148, 0x000080c0}, -	{0x00016280, 0x01000015}, +	{0x00016280, 0x01001015},  	{0x00016284, 0x14d20000},  	{0x00016288, 0x00318000},  	{0x0001628c, 0x50000000}, @@ -590,7 +592,7 @@ static const u32 ar9331_1p1_baseband_core[][2] = {  	{0x00009e30, 0x06336f77},  	{0x00009e34, 0x6af6532f},  	{0x00009e38, 0x0cc80c00}, -	{0x00009e40, 0x0d261820}, +	{0x00009e40, 0x0d261800},  	{0x00009e4c, 0x00001004},  	{0x00009e50, 0x00ff03f1},  	{0x00009fc0, 0x803e4788}, @@ -622,12 +624,12 @@ static const u32 ar9331_1p1_baseband_core[][2] = {  	{0x0000a370, 0x00000000},  	{0x0000a390, 0x00000001},  	{0x0000a394, 0x00000444}, -	{0x0000a398, 0x001f0e0f}, -	{0x0000a39c, 0x0075393f}, -	{0x0000a3a0, 0xb79f6427}, -	{0x0000a3a4, 0x00000000}, -	{0x0000a3a8, 0xaaaaaaaa}, -	{0x0000a3ac, 0x3c466478}, +	{0x0000a398, 0x00000000}, +	{0x0000a39c, 0x210d0401}, +	{0x0000a3a0, 0xab9a7144}, +	{0x0000a3a4, 0x00000011}, +	{0x0000a3a8, 0x3c3c003d}, +	{0x0000a3ac, 0x30310030},  	{0x0000a3c0, 0x20202020},  	{0x0000a3c4, 0x22222220},  	{0x0000a3c8, 0x20200020}, @@ -686,100 +688,18 @@ static const u32 ar9331_1p1_baseband_core[][2] = {  	{0x0000a7dc, 0x00000001},  }; -static const u32 ar9331_modes_high_power_tx_gain_1p1[][5] = { +static const u32 ar9331_1p1_mac_postamble[][5] = {  	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ -	{0x0000a2d8, 0x7999a83a, 0x7999a83a, 0x7999a83a, 0x7999a83a}, -	{0x0000a2dc, 0xffff2a52, 0xffff2a52, 0xffff2a52, 0xffff2a52}, -	{0x0000a2e0, 0xffffcc84, 0xffffcc84, 0xffffcc84, 0xffffcc84}, -	{0x0000a2e4, 0xfffff000, 0xfffff000, 0xfffff000, 0xfffff000}, -	{0x0000a2e8, 0xfffe0000, 0xfffe0000, 0xfffe0000, 0xfffe0000}, -	{0x0000a410, 0x000050d7, 0x000050d7, 0x000050d0, 0x000050d0}, -	{0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, -	{0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, -	{0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, -	{0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, -	{0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, -	{0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, -	{0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, -	{0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, -	{0x0000a520, 0x2f001f04, 0x2f001f04, 0x23000a00, 0x23000a00}, -	{0x0000a524, 0x35001fc4, 0x35001fc4, 0x27000a02, 0x27000a02}, -	{0x0000a528, 0x3c022f04, 0x3c022f04, 0x2b000a04, 0x2b000a04}, -	{0x0000a52c, 0x41023e85, 0x41023e85, 0x2d000a20, 0x2d000a20}, -	{0x0000a530, 0x48023ec6, 0x48023ec6, 0x31000a22, 0x31000a22}, -	{0x0000a534, 0x4d023f01, 0x4d023f01, 0x35000a24, 0x35000a24}, -	{0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000a43, 0x38000a43}, -	{0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3b000e42, 0x3b000e42}, -	{0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x3f000e44, 0x3f000e44}, -	{0x0000a544, 0x6502feca, 0x6502feca, 0x42000e64, 0x42000e64}, -	{0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46000e66, 0x46000e66}, -	{0x0000a54c, 0x7203feca, 0x7203feca, 0x4a000ea6, 0x4a000ea6}, -	{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4a000ea6, 0x4a000ea6}, -	{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4a000ea6, 0x4a000ea6}, -	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x4a000ea6, 0x4a000ea6}, -	{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x4a000ea6, 0x4a000ea6}, -	{0x0000a560, 0x900fff0b, 0x900fff0b, 0x4a000ea6, 0x4a000ea6}, -	{0x0000a564, 0x960fffcb, 0x960fffcb, 0x4a000ea6, 0x4a000ea6}, -	{0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x4a000ea6, 0x4a000ea6}, -	{0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x4a000ea6, 0x4a000ea6}, -	{0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x4a000ea6, 0x4a000ea6}, -	{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x4a000ea6, 0x4a000ea6}, -	{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x4a000ea6, 0x4a000ea6}, -	{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x4a000ea6, 0x4a000ea6}, -	{0x0000a580, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, -	{0x0000a584, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, -	{0x0000a588, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, -	{0x0000a58c, 0x11062202, 0x11062202, 0x0b000200, 0x0b000200}, -	{0x0000a590, 0x17022e00, 0x17022e00, 0x0f000202, 0x0f000202}, -	{0x0000a594, 0x1d000ec2, 0x1d000ec2, 0x11000400, 0x11000400}, -	{0x0000a598, 0x25020ec0, 0x25020ec0, 0x15000402, 0x15000402}, -	{0x0000a59c, 0x2b020ec3, 0x2b020ec3, 0x19000404, 0x19000404}, -	{0x0000a5a0, 0x2f001f04, 0x2f001f04, 0x1b000603, 0x1b000603}, -	{0x0000a5a4, 0x35001fc4, 0x35001fc4, 0x1f000a02, 0x1f000a02}, -	{0x0000a5a8, 0x3c022f04, 0x3c022f04, 0x23000a04, 0x23000a04}, -	{0x0000a5ac, 0x41023e85, 0x41023e85, 0x26000a20, 0x26000a20}, -	{0x0000a5b0, 0x48023ec6, 0x48023ec6, 0x2a000e20, 0x2a000e20}, -	{0x0000a5b4, 0x4d023f01, 0x4d023f01, 0x2e000e22, 0x2e000e22}, -	{0x0000a5b8, 0x53023f4b, 0x53023f4b, 0x31000e24, 0x31000e24}, -	{0x0000a5bc, 0x5a027f09, 0x5a027f09, 0x34001640, 0x34001640}, -	{0x0000a5c0, 0x5f027fc9, 0x5f027fc9, 0x38001660, 0x38001660}, -	{0x0000a5c4, 0x6502feca, 0x6502feca, 0x3b001861, 0x3b001861}, -	{0x0000a5c8, 0x6b02ff4a, 0x6b02ff4a, 0x3e001a81, 0x3e001a81}, -	{0x0000a5cc, 0x7203feca, 0x7203feca, 0x42001a83, 0x42001a83}, -	{0x0000a5d0, 0x7703ff0b, 0x7703ff0b, 0x44001c84, 0x44001c84}, -	{0x0000a5d4, 0x7d06ffcb, 0x7d06ffcb, 0x48001ce3, 0x48001ce3}, -	{0x0000a5d8, 0x8407ff0b, 0x8407ff0b, 0x4c001ce5, 0x4c001ce5}, -	{0x0000a5dc, 0x8907ffcb, 0x8907ffcb, 0x50001ce9, 0x50001ce9}, -	{0x0000a5e0, 0x900fff0b, 0x900fff0b, 0x54001ceb, 0x54001ceb}, -	{0x0000a5e4, 0x960fffcb, 0x960fffcb, 0x56001eec, 0x56001eec}, -	{0x0000a5e8, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, -	{0x0000a5ec, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, -	{0x0000a5f0, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, -	{0x0000a5f4, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, -	{0x0000a5f8, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, -	{0x0000a5fc, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, -	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, -	{0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, -	{0x0000a61c, 0x02008802, 0x02008802, 0x02008802, 0x02008802}, -	{0x0000a620, 0x0280c802, 0x0280c802, 0x0280c802, 0x0280c802}, -	{0x0000a624, 0x03010a03, 0x03010a03, 0x03010a03, 0x03010a03}, -	{0x0000a628, 0x03010c04, 0x03010c04, 0x03010c04, 0x03010c04}, -	{0x0000a62c, 0x03010c04, 0x03010c04, 0x03010c04, 0x03010c04}, -	{0x0000a630, 0x03010c04, 0x03010c04, 0x03010c04, 0x03010c04}, -	{0x0000a634, 0x03010c04, 0x03010c04, 0x03010c04, 0x03010c04}, -	{0x0000a638, 0x03010c04, 0x03010c04, 0x03010c04, 0x03010c04}, -	{0x0000a63c, 0x03010c04, 0x03010c04, 0x03010c04, 0x03010c04}, -	{0x00016044, 0x034922db, 0x034922db, 0x034922db, 0x034922db}, -	{0x00016284, 0x14d3f000, 0x14d3f000, 0x14d3f000, 0x14d3f000}, +	{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, +	{0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, +	{0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, +	{0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, +	{0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, +	{0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, +	{0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, +	{0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},  }; -#define ar9331_1p1_mac_postamble ar9300_2p2_mac_postamble -  static const u32 ar9331_1p1_soc_preamble[][2] = {  	/* Addr      allmodes  */  	{0x00007020, 0x00000000}, diff --git a/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h index 57ed8a11217..2154efcd390 100644 --- a/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h @@ -18,6 +18,28 @@  #ifndef INITVALS_9330_1P2_H  #define INITVALS_9330_1P2_H +#define ar9331_modes_high_power_tx_gain_1p2 ar9331_modes_high_ob_db_tx_gain_1p2 + +#define ar9331_modes_low_ob_db_tx_gain_1p2 ar9331_modes_high_ob_db_tx_gain_1p2 + +#define ar9331_modes_lowest_ob_db_tx_gain_1p2 ar9331_modes_high_ob_db_tx_gain_1p2 + +#define ar9331_1p2_baseband_core_txfir_coeff_japan_2484 ar9331_1p1_baseband_core_txfir_coeff_japan_2484 + +#define ar9331_1p2_xtal_25M ar9331_1p1_xtal_25M + +#define ar9331_1p2_xtal_40M ar9331_1p1_xtal_40M + +#define ar9331_1p2_soc_postamble ar9331_1p1_soc_postamble + +#define ar9331_1p2_mac_postamble ar9331_1p1_mac_postamble + +#define ar9331_1p2_soc_preamble ar9331_1p1_soc_preamble + +#define ar9331_1p2_mac_core ar9331_1p1_mac_core + +#define ar9331_common_wo_xlna_rx_gain_1p2 ar9331_common_wo_xlna_rx_gain_1p1 +  static const u32 ar9331_modes_high_ob_db_tx_gain_1p2[][5] = {  	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */  	{0x0000a410, 0x000050d7, 0x000050d7, 0x000050d7, 0x000050d7}, @@ -103,57 +125,6 @@ static const u32 ar9331_modes_high_ob_db_tx_gain_1p2[][5] = {  	{0x0000a63c, 0x04011004, 0x04011004, 0x04011004, 0x04011004},  }; -#define ar9331_modes_high_power_tx_gain_1p2 ar9331_modes_high_ob_db_tx_gain_1p2 - -#define ar9331_modes_low_ob_db_tx_gain_1p2 ar9331_modes_high_power_tx_gain_1p2 - -#define ar9331_modes_lowest_ob_db_tx_gain_1p2 ar9331_modes_low_ob_db_tx_gain_1p2 - -static const u32 ar9331_1p2_baseband_postamble[][5] = { -	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ -	{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005}, -	{0x00009820, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e}, -	{0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, -	{0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, -	{0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, -	{0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c}, -	{0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044}, -	{0x00009e00, 0x0372161e, 0x0372161e, 0x037216a4, 0x037216a4}, -	{0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020}, -	{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, -	{0x00009e10, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e}, -	{0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, -	{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, -	{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, -	{0x00009e2c, 0x0000001c, 0x0000001c, 0x00003221, 0x00003221}, -	{0x00009e3c, 0xcf946222, 0xcf946222, 0xcf946222, 0xcf946222}, -	{0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324}, -	{0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010}, -	{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, -	{0x0000a204, 0x00003fc0, 0x00003fc4, 0x00003fc4, 0x00003fc0}, -	{0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, -	{0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, -	{0x0000a234, 0x00000fff, 0x00000fff, 0x10000fff, 0x00000fff}, -	{0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018}, -	{0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, -	{0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, -	{0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, -	{0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, -	{0x0000a260, 0x3a021501, 0x3a021501, 0x3a021501, 0x3a021501}, -	{0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, -	{0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, -	{0x0000a284, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, -	{0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071981}, -	{0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, -	{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000ae04, 0x00802020, 0x00802020, 0x00802020, 0x00802020}, -	{0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -}; -  static const u32 ar9331_1p2_radio_core[][2] = {  	/* Addr      allmodes  */  	{0x00016000, 0x36db6db6}, @@ -219,24 +190,318 @@ static const u32 ar9331_1p2_radio_core[][2] = {  	{0x000163d4, 0x00000000},  }; -#define ar9331_1p2_baseband_core_txfir_coeff_japan_2484 ar9331_1p1_baseband_core_txfir_coeff_japan_2484 - -#define ar9331_1p2_xtal_25M ar9331_1p1_xtal_25M - -#define ar9331_1p2_xtal_40M ar9331_1p1_xtal_40M - -#define ar9331_1p2_baseband_core ar9331_1p1_baseband_core - -#define ar9331_1p2_soc_postamble ar9331_1p1_soc_postamble - -#define ar9331_1p2_mac_postamble ar9331_1p1_mac_postamble - -#define ar9331_1p2_soc_preamble ar9331_1p1_soc_preamble - -#define ar9331_1p2_mac_core ar9331_1p1_mac_core +static const u32 ar9331_1p2_baseband_core[][2] = { +	/* Addr      allmodes  */ +	{0x00009800, 0xafe68e30}, +	{0x00009804, 0xfd14e000}, +	{0x00009808, 0x9c0a8f6b}, +	{0x0000980c, 0x04800000}, +	{0x00009814, 0x9280c00a}, +	{0x00009818, 0x00000000}, +	{0x0000981c, 0x00020028}, +	{0x00009834, 0x5f3ca3de}, +	{0x00009838, 0x0108ecff}, +	{0x0000983c, 0x14750600}, +	{0x00009880, 0x201fff00}, +	{0x00009884, 0x00001042}, +	{0x000098a4, 0x00200400}, +	{0x000098b0, 0x32840bbe}, +	{0x000098d0, 0x004b6a8e}, +	{0x000098d4, 0x00000820}, +	{0x000098dc, 0x00000000}, +	{0x000098f0, 0x00000000}, +	{0x000098f4, 0x00000000}, +	{0x00009c04, 0x00000000}, +	{0x00009c08, 0x03200000}, +	{0x00009c0c, 0x00000000}, +	{0x00009c10, 0x00000000}, +	{0x00009c14, 0x00046384}, +	{0x00009c18, 0x05b6b440}, +	{0x00009c1c, 0x00b6b440}, +	{0x00009d00, 0xc080a333}, +	{0x00009d04, 0x40206c10}, +	{0x00009d08, 0x009c4060}, +	{0x00009d0c, 0x1883800a}, +	{0x00009d10, 0x01834061}, +	{0x00009d14, 0x00c00400}, +	{0x00009d18, 0x00000000}, +	{0x00009e08, 0x0038233c}, +	{0x00009e24, 0x9927b515}, +	{0x00009e28, 0x12ef0200}, +	{0x00009e30, 0x06336f77}, +	{0x00009e34, 0x6af6532f}, +	{0x00009e38, 0x0cc80c00}, +	{0x00009e40, 0x0d261800}, +	{0x00009e4c, 0x00001004}, +	{0x00009e50, 0x00ff03f1}, +	{0x00009fc0, 0x803e4788}, +	{0x00009fc4, 0x0001efb5}, +	{0x00009fcc, 0x40000014}, +	{0x0000a20c, 0x00000000}, +	{0x0000a220, 0x00000000}, +	{0x0000a224, 0x00000000}, +	{0x0000a228, 0x10002310}, +	{0x0000a23c, 0x00000000}, +	{0x0000a244, 0x0c000000}, +	{0x0000a2a0, 0x00000001}, +	{0x0000a2c0, 0x00000001}, +	{0x0000a2c8, 0x00000000}, +	{0x0000a2cc, 0x18c43433}, +	{0x0000a2d4, 0x00000000}, +	{0x0000a2dc, 0x00000000}, +	{0x0000a2e0, 0x00000000}, +	{0x0000a2e4, 0x00000000}, +	{0x0000a2e8, 0x00000000}, +	{0x0000a2ec, 0x00000000}, +	{0x0000a2f0, 0x00000000}, +	{0x0000a2f4, 0x00000000}, +	{0x0000a2f8, 0x00000000}, +	{0x0000a344, 0x00000000}, +	{0x0000a34c, 0x00000000}, +	{0x0000a350, 0x0000a000}, +	{0x0000a364, 0x00000000}, +	{0x0000a370, 0x00000000}, +	{0x0000a390, 0x00000001}, +	{0x0000a394, 0x00000444}, +	{0x0000a398, 0x001f0e0f}, +	{0x0000a39c, 0x0075393f}, +	{0x0000a3a0, 0xb79f6427}, +	{0x0000a3a4, 0x00000000}, +	{0x0000a3a8, 0xaaaaaaaa}, +	{0x0000a3ac, 0x3c466478}, +	{0x0000a3c0, 0x20202020}, +	{0x0000a3c4, 0x22222220}, +	{0x0000a3c8, 0x20200020}, +	{0x0000a3cc, 0x20202020}, +	{0x0000a3d0, 0x20202020}, +	{0x0000a3d4, 0x20202020}, +	{0x0000a3d8, 0x20202020}, +	{0x0000a3dc, 0x20202020}, +	{0x0000a3e0, 0x20202020}, +	{0x0000a3e4, 0x20202020}, +	{0x0000a3e8, 0x20202020}, +	{0x0000a3ec, 0x20202020}, +	{0x0000a3f0, 0x00000000}, +	{0x0000a3f4, 0x00000006}, +	{0x0000a3f8, 0x0cdbd380}, +	{0x0000a3fc, 0x000f0f01}, +	{0x0000a400, 0x8fa91f01}, +	{0x0000a404, 0x00000000}, +	{0x0000a408, 0x0e79e5c6}, +	{0x0000a40c, 0x00820820}, +	{0x0000a414, 0x1ce739ce}, +	{0x0000a418, 0x2d001dce}, +	{0x0000a41c, 0x1ce739ce}, +	{0x0000a420, 0x000001ce}, +	{0x0000a424, 0x1ce739ce}, +	{0x0000a428, 0x000001ce}, +	{0x0000a42c, 0x1ce739ce}, +	{0x0000a430, 0x1ce739ce}, +	{0x0000a434, 0x00000000}, +	{0x0000a438, 0x00001801}, +	{0x0000a43c, 0x00000000}, +	{0x0000a440, 0x00000000}, +	{0x0000a444, 0x00000000}, +	{0x0000a448, 0x04000000}, +	{0x0000a44c, 0x00000001}, +	{0x0000a450, 0x00010000}, +	{0x0000a458, 0x00000000}, +	{0x0000a640, 0x00000000}, +	{0x0000a644, 0x3fad9d74}, +	{0x0000a648, 0x0048060a}, +	{0x0000a64c, 0x00003c37}, +	{0x0000a670, 0x03020100}, +	{0x0000a674, 0x09080504}, +	{0x0000a678, 0x0d0c0b0a}, +	{0x0000a67c, 0x13121110}, +	{0x0000a680, 0x31301514}, +	{0x0000a684, 0x35343332}, +	{0x0000a688, 0x00000036}, +	{0x0000a690, 0x00000838}, +	{0x0000a7c0, 0x00000000}, +	{0x0000a7c4, 0xfffffffc}, +	{0x0000a7c8, 0x00000000}, +	{0x0000a7cc, 0x00000000}, +	{0x0000a7d0, 0x00000000}, +	{0x0000a7d4, 0x00000004}, +	{0x0000a7dc, 0x00000001}, +}; -#define ar9331_common_wo_xlna_rx_gain_1p2 ar9331_common_wo_xlna_rx_gain_1p1 +static const u32 ar9331_1p2_baseband_postamble[][5] = { +	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ +	{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005}, +	{0x00009820, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e}, +	{0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, +	{0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, +	{0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, +	{0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c}, +	{0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044}, +	{0x00009e00, 0x0372161e, 0x0372161e, 0x037216a4, 0x037216a4}, +	{0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020}, +	{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, +	{0x00009e10, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e}, +	{0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, +	{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, +	{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, +	{0x00009e2c, 0x0000001c, 0x0000001c, 0x00003221, 0x00003221}, +	{0x00009e3c, 0xcf946222, 0xcf946222, 0xcf946222, 0xcf946222}, +	{0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324}, +	{0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010}, +	{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, +	{0x0000a204, 0x00003fc0, 0x00003fc4, 0x00003fc4, 0x00003fc0}, +	{0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, +	{0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, +	{0x0000a234, 0x00000fff, 0x00000fff, 0x10000fff, 0x00000fff}, +	{0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018}, +	{0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, +	{0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, +	{0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, +	{0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, +	{0x0000a260, 0x3a021501, 0x3a021501, 0x3a021501, 0x3a021501}, +	{0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, +	{0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, +	{0x0000a284, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, +	{0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071981}, +	{0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, +	{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000ae04, 0x00802020, 0x00802020, 0x00802020, 0x00802020}, +	{0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +}; -#define ar9331_common_rx_gain_1p2 ar9485_common_rx_gain_1_1 +static const u32 ar9331_common_rx_gain_1p2[][2] = { +	/* Addr      allmodes  */ +	{0x0000a000, 0x00010000}, +	{0x0000a004, 0x00030002}, +	{0x0000a008, 0x00050004}, +	{0x0000a00c, 0x00810080}, +	{0x0000a010, 0x01800082}, +	{0x0000a014, 0x01820181}, +	{0x0000a018, 0x01840183}, +	{0x0000a01c, 0x01880185}, +	{0x0000a020, 0x018a0189}, +	{0x0000a024, 0x02850284}, +	{0x0000a028, 0x02890288}, +	{0x0000a02c, 0x03850384}, +	{0x0000a030, 0x03890388}, +	{0x0000a034, 0x038b038a}, +	{0x0000a038, 0x038d038c}, +	{0x0000a03c, 0x03910390}, +	{0x0000a040, 0x03930392}, +	{0x0000a044, 0x03950394}, +	{0x0000a048, 0x00000396}, +	{0x0000a04c, 0x00000000}, +	{0x0000a050, 0x00000000}, +	{0x0000a054, 0x00000000}, +	{0x0000a058, 0x00000000}, +	{0x0000a05c, 0x00000000}, +	{0x0000a060, 0x00000000}, +	{0x0000a064, 0x00000000}, +	{0x0000a068, 0x00000000}, +	{0x0000a06c, 0x00000000}, +	{0x0000a070, 0x00000000}, +	{0x0000a074, 0x00000000}, +	{0x0000a078, 0x00000000}, +	{0x0000a07c, 0x00000000}, +	{0x0000a080, 0x28282828}, +	{0x0000a084, 0x28282828}, +	{0x0000a088, 0x28282828}, +	{0x0000a08c, 0x28282828}, +	{0x0000a090, 0x28282828}, +	{0x0000a094, 0x21212128}, +	{0x0000a098, 0x171c1c1c}, +	{0x0000a09c, 0x02020212}, +	{0x0000a0a0, 0x00000202}, +	{0x0000a0a4, 0x00000000}, +	{0x0000a0a8, 0x00000000}, +	{0x0000a0ac, 0x00000000}, +	{0x0000a0b0, 0x00000000}, +	{0x0000a0b4, 0x00000000}, +	{0x0000a0b8, 0x00000000}, +	{0x0000a0bc, 0x00000000}, +	{0x0000a0c0, 0x001f0000}, +	{0x0000a0c4, 0x111f1100}, +	{0x0000a0c8, 0x111d111e}, +	{0x0000a0cc, 0x111b111c}, +	{0x0000a0d0, 0x22032204}, +	{0x0000a0d4, 0x22012202}, +	{0x0000a0d8, 0x221f2200}, +	{0x0000a0dc, 0x221d221e}, +	{0x0000a0e0, 0x33013302}, +	{0x0000a0e4, 0x331f3300}, +	{0x0000a0e8, 0x4402331e}, +	{0x0000a0ec, 0x44004401}, +	{0x0000a0f0, 0x441e441f}, +	{0x0000a0f4, 0x55015502}, +	{0x0000a0f8, 0x551f5500}, +	{0x0000a0fc, 0x6602551e}, +	{0x0000a100, 0x66006601}, +	{0x0000a104, 0x661e661f}, +	{0x0000a108, 0x7703661d}, +	{0x0000a10c, 0x77017702}, +	{0x0000a110, 0x00007700}, +	{0x0000a114, 0x00000000}, +	{0x0000a118, 0x00000000}, +	{0x0000a11c, 0x00000000}, +	{0x0000a120, 0x00000000}, +	{0x0000a124, 0x00000000}, +	{0x0000a128, 0x00000000}, +	{0x0000a12c, 0x00000000}, +	{0x0000a130, 0x00000000}, +	{0x0000a134, 0x00000000}, +	{0x0000a138, 0x00000000}, +	{0x0000a13c, 0x00000000}, +	{0x0000a140, 0x001f0000}, +	{0x0000a144, 0x111f1100}, +	{0x0000a148, 0x111d111e}, +	{0x0000a14c, 0x111b111c}, +	{0x0000a150, 0x22032204}, +	{0x0000a154, 0x22012202}, +	{0x0000a158, 0x221f2200}, +	{0x0000a15c, 0x221d221e}, +	{0x0000a160, 0x33013302}, +	{0x0000a164, 0x331f3300}, +	{0x0000a168, 0x4402331e}, +	{0x0000a16c, 0x44004401}, +	{0x0000a170, 0x441e441f}, +	{0x0000a174, 0x55015502}, +	{0x0000a178, 0x551f5500}, +	{0x0000a17c, 0x6602551e}, +	{0x0000a180, 0x66006601}, +	{0x0000a184, 0x661e661f}, +	{0x0000a188, 0x7703661d}, +	{0x0000a18c, 0x77017702}, +	{0x0000a190, 0x00007700}, +	{0x0000a194, 0x00000000}, +	{0x0000a198, 0x00000000}, +	{0x0000a19c, 0x00000000}, +	{0x0000a1a0, 0x00000000}, +	{0x0000a1a4, 0x00000000}, +	{0x0000a1a8, 0x00000000}, +	{0x0000a1ac, 0x00000000}, +	{0x0000a1b0, 0x00000000}, +	{0x0000a1b4, 0x00000000}, +	{0x0000a1b8, 0x00000000}, +	{0x0000a1bc, 0x00000000}, +	{0x0000a1c0, 0x00000000}, +	{0x0000a1c4, 0x00000000}, +	{0x0000a1c8, 0x00000000}, +	{0x0000a1cc, 0x00000000}, +	{0x0000a1d0, 0x00000000}, +	{0x0000a1d4, 0x00000000}, +	{0x0000a1d8, 0x00000000}, +	{0x0000a1dc, 0x00000000}, +	{0x0000a1e0, 0x00000000}, +	{0x0000a1e4, 0x00000000}, +	{0x0000a1e8, 0x00000000}, +	{0x0000a1ec, 0x00000000}, +	{0x0000a1f0, 0x00000396}, +	{0x0000a1f4, 0x00000396}, +	{0x0000a1f8, 0x00000396}, +	{0x0000a1fc, 0x00000296}, +};  #endif /* INITVALS_9330_1P2_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h index 25db9215985..b995ffe88b3 100644 --- a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h @@ -18,6 +18,20 @@  #ifndef INITVALS_9340_H  #define INITVALS_9340_H +#define ar9340_1p0_mac_postamble ar9300_2p2_mac_postamble + +#define ar9340_1p0_soc_postamble ar9300_2p2_soc_postamble + +#define ar9340Modes_fast_clock_1p0 ar9300Modes_fast_clock_2p2 + +#define ar9340Common_rx_gain_table_1p0 ar9300Common_rx_gain_table_2p2 + +#define ar9340Common_wo_xlna_rx_gain_table_1p0 ar9300Common_wo_xlna_rx_gain_table_2p2 + +#define ar9340_1p0_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484 + +#define ar9340_1p0_baseband_postamble_dfs_channel ar9300_2p2_baseband_postamble_dfs_channel +  static const u32 ar9340_1p0_radio_postamble[][5] = {  	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */  	{0x000160ac, 0xa4646800, 0xa4646800, 0xa4646800, 0xa4646800}, @@ -100,8 +114,6 @@ static const u32 ar9340Modes_lowest_ob_db_tx_gain_table_1p0[][5] = {  	{0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266},  }; -#define ar9340Modes_fast_clock_1p0 ar9300Modes_fast_clock_2p2 -  static const u32 ar9340_1p0_radio_core[][2] = {  	/* Addr      allmodes  */  	{0x00016000, 0x36db6db6}, @@ -215,16 +227,12 @@ static const u32 ar9340_1p0_radio_core_40M[][2] = {  	{0x0000824c, 0x0001e800},  }; -#define ar9340_1p0_mac_postamble ar9300_2p2_mac_postamble - -#define ar9340_1p0_soc_postamble ar9300_2p2_soc_postamble -  static const u32 ar9340_1p0_baseband_postamble[][5] = {  	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */  	{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},  	{0x00009820, 0x206a022e, 0x206a022e, 0x206a022e, 0x206a022e},  	{0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, -	{0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, +	{0x00009828, 0x06903081, 0x06903081, 0x09103881, 0x09103881},  	{0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},  	{0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},  	{0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4}, @@ -310,7 +318,7 @@ static const u32 ar9340_1p0_baseband_core[][2] = {  	{0x00009e30, 0x06336f77},  	{0x00009e34, 0x6af6532f},  	{0x00009e38, 0x0cc80c00}, -	{0x00009e40, 0x0d261820}, +	{0x00009e40, 0x0d261800},  	{0x00009e4c, 0x00001004},  	{0x00009e50, 0x00ff03f1},  	{0x00009e54, 0x00000000}, @@ -714,266 +722,6 @@ static const u32 ar9340Modes_ub124_tx_gain_table_1p0[][5] = {  	{0x0000b2e8, 0xfffe0000, 0xfffe0000, 0xfffc0000, 0xfffc0000},  }; -static const u32 ar9340Common_rx_gain_table_1p0[][2] = { -	/* Addr      allmodes  */ -	{0x0000a000, 0x00010000}, -	{0x0000a004, 0x00030002}, -	{0x0000a008, 0x00050004}, -	{0x0000a00c, 0x00810080}, -	{0x0000a010, 0x00830082}, -	{0x0000a014, 0x01810180}, -	{0x0000a018, 0x01830182}, -	{0x0000a01c, 0x01850184}, -	{0x0000a020, 0x01890188}, -	{0x0000a024, 0x018b018a}, -	{0x0000a028, 0x018d018c}, -	{0x0000a02c, 0x01910190}, -	{0x0000a030, 0x01930192}, -	{0x0000a034, 0x01950194}, -	{0x0000a038, 0x038a0196}, -	{0x0000a03c, 0x038c038b}, -	{0x0000a040, 0x0390038d}, -	{0x0000a044, 0x03920391}, -	{0x0000a048, 0x03940393}, -	{0x0000a04c, 0x03960395}, -	{0x0000a050, 0x00000000}, -	{0x0000a054, 0x00000000}, -	{0x0000a058, 0x00000000}, -	{0x0000a05c, 0x00000000}, -	{0x0000a060, 0x00000000}, -	{0x0000a064, 0x00000000}, -	{0x0000a068, 0x00000000}, -	{0x0000a06c, 0x00000000}, -	{0x0000a070, 0x00000000}, -	{0x0000a074, 0x00000000}, -	{0x0000a078, 0x00000000}, -	{0x0000a07c, 0x00000000}, -	{0x0000a080, 0x22222229}, -	{0x0000a084, 0x1d1d1d1d}, -	{0x0000a088, 0x1d1d1d1d}, -	{0x0000a08c, 0x1d1d1d1d}, -	{0x0000a090, 0x171d1d1d}, -	{0x0000a094, 0x11111717}, -	{0x0000a098, 0x00030311}, -	{0x0000a09c, 0x00000000}, -	{0x0000a0a0, 0x00000000}, -	{0x0000a0a4, 0x00000000}, -	{0x0000a0a8, 0x00000000}, -	{0x0000a0ac, 0x00000000}, -	{0x0000a0b0, 0x00000000}, -	{0x0000a0b4, 0x00000000}, -	{0x0000a0b8, 0x00000000}, -	{0x0000a0bc, 0x00000000}, -	{0x0000a0c0, 0x001f0000}, -	{0x0000a0c4, 0x01000101}, -	{0x0000a0c8, 0x011e011f}, -	{0x0000a0cc, 0x011c011d}, -	{0x0000a0d0, 0x02030204}, -	{0x0000a0d4, 0x02010202}, -	{0x0000a0d8, 0x021f0200}, -	{0x0000a0dc, 0x0302021e}, -	{0x0000a0e0, 0x03000301}, -	{0x0000a0e4, 0x031e031f}, -	{0x0000a0e8, 0x0402031d}, -	{0x0000a0ec, 0x04000401}, -	{0x0000a0f0, 0x041e041f}, -	{0x0000a0f4, 0x0502041d}, -	{0x0000a0f8, 0x05000501}, -	{0x0000a0fc, 0x051e051f}, -	{0x0000a100, 0x06010602}, -	{0x0000a104, 0x061f0600}, -	{0x0000a108, 0x061d061e}, -	{0x0000a10c, 0x07020703}, -	{0x0000a110, 0x07000701}, -	{0x0000a114, 0x00000000}, -	{0x0000a118, 0x00000000}, -	{0x0000a11c, 0x00000000}, -	{0x0000a120, 0x00000000}, -	{0x0000a124, 0x00000000}, -	{0x0000a128, 0x00000000}, -	{0x0000a12c, 0x00000000}, -	{0x0000a130, 0x00000000}, -	{0x0000a134, 0x00000000}, -	{0x0000a138, 0x00000000}, -	{0x0000a13c, 0x00000000}, -	{0x0000a140, 0x001f0000}, -	{0x0000a144, 0x01000101}, -	{0x0000a148, 0x011e011f}, -	{0x0000a14c, 0x011c011d}, -	{0x0000a150, 0x02030204}, -	{0x0000a154, 0x02010202}, -	{0x0000a158, 0x021f0200}, -	{0x0000a15c, 0x0302021e}, -	{0x0000a160, 0x03000301}, -	{0x0000a164, 0x031e031f}, -	{0x0000a168, 0x0402031d}, -	{0x0000a16c, 0x04000401}, -	{0x0000a170, 0x041e041f}, -	{0x0000a174, 0x0502041d}, -	{0x0000a178, 0x05000501}, -	{0x0000a17c, 0x051e051f}, -	{0x0000a180, 0x06010602}, -	{0x0000a184, 0x061f0600}, -	{0x0000a188, 0x061d061e}, -	{0x0000a18c, 0x07020703}, -	{0x0000a190, 0x07000701}, -	{0x0000a194, 0x00000000}, -	{0x0000a198, 0x00000000}, -	{0x0000a19c, 0x00000000}, -	{0x0000a1a0, 0x00000000}, -	{0x0000a1a4, 0x00000000}, -	{0x0000a1a8, 0x00000000}, -	{0x0000a1ac, 0x00000000}, -	{0x0000a1b0, 0x00000000}, -	{0x0000a1b4, 0x00000000}, -	{0x0000a1b8, 0x00000000}, -	{0x0000a1bc, 0x00000000}, -	{0x0000a1c0, 0x00000000}, -	{0x0000a1c4, 0x00000000}, -	{0x0000a1c8, 0x00000000}, -	{0x0000a1cc, 0x00000000}, -	{0x0000a1d0, 0x00000000}, -	{0x0000a1d4, 0x00000000}, -	{0x0000a1d8, 0x00000000}, -	{0x0000a1dc, 0x00000000}, -	{0x0000a1e0, 0x00000000}, -	{0x0000a1e4, 0x00000000}, -	{0x0000a1e8, 0x00000000}, -	{0x0000a1ec, 0x00000000}, -	{0x0000a1f0, 0x00000396}, -	{0x0000a1f4, 0x00000396}, -	{0x0000a1f8, 0x00000396}, -	{0x0000a1fc, 0x00000196}, -	{0x0000b000, 0x00010000}, -	{0x0000b004, 0x00030002}, -	{0x0000b008, 0x00050004}, -	{0x0000b00c, 0x00810080}, -	{0x0000b010, 0x00830082}, -	{0x0000b014, 0x01810180}, -	{0x0000b018, 0x01830182}, -	{0x0000b01c, 0x01850184}, -	{0x0000b020, 0x02810280}, -	{0x0000b024, 0x02830282}, -	{0x0000b028, 0x02850284}, -	{0x0000b02c, 0x02890288}, -	{0x0000b030, 0x028b028a}, -	{0x0000b034, 0x0388028c}, -	{0x0000b038, 0x038a0389}, -	{0x0000b03c, 0x038c038b}, -	{0x0000b040, 0x0390038d}, -	{0x0000b044, 0x03920391}, -	{0x0000b048, 0x03940393}, -	{0x0000b04c, 0x03960395}, -	{0x0000b050, 0x00000000}, -	{0x0000b054, 0x00000000}, -	{0x0000b058, 0x00000000}, -	{0x0000b05c, 0x00000000}, -	{0x0000b060, 0x00000000}, -	{0x0000b064, 0x00000000}, -	{0x0000b068, 0x00000000}, -	{0x0000b06c, 0x00000000}, -	{0x0000b070, 0x00000000}, -	{0x0000b074, 0x00000000}, -	{0x0000b078, 0x00000000}, -	{0x0000b07c, 0x00000000}, -	{0x0000b080, 0x23232323}, -	{0x0000b084, 0x21232323}, -	{0x0000b088, 0x19191c1e}, -	{0x0000b08c, 0x12141417}, -	{0x0000b090, 0x07070e0e}, -	{0x0000b094, 0x03030305}, -	{0x0000b098, 0x00000003}, -	{0x0000b09c, 0x00000000}, -	{0x0000b0a0, 0x00000000}, -	{0x0000b0a4, 0x00000000}, -	{0x0000b0a8, 0x00000000}, -	{0x0000b0ac, 0x00000000}, -	{0x0000b0b0, 0x00000000}, -	{0x0000b0b4, 0x00000000}, -	{0x0000b0b8, 0x00000000}, -	{0x0000b0bc, 0x00000000}, -	{0x0000b0c0, 0x003f0020}, -	{0x0000b0c4, 0x00400041}, -	{0x0000b0c8, 0x0140005f}, -	{0x0000b0cc, 0x0160015f}, -	{0x0000b0d0, 0x017e017f}, -	{0x0000b0d4, 0x02410242}, -	{0x0000b0d8, 0x025f0240}, -	{0x0000b0dc, 0x027f0260}, -	{0x0000b0e0, 0x0341027e}, -	{0x0000b0e4, 0x035f0340}, -	{0x0000b0e8, 0x037f0360}, -	{0x0000b0ec, 0x04400441}, -	{0x0000b0f0, 0x0460045f}, -	{0x0000b0f4, 0x0541047f}, -	{0x0000b0f8, 0x055f0540}, -	{0x0000b0fc, 0x057f0560}, -	{0x0000b100, 0x06400641}, -	{0x0000b104, 0x0660065f}, -	{0x0000b108, 0x067e067f}, -	{0x0000b10c, 0x07410742}, -	{0x0000b110, 0x075f0740}, -	{0x0000b114, 0x077f0760}, -	{0x0000b118, 0x07800781}, -	{0x0000b11c, 0x07a0079f}, -	{0x0000b120, 0x07c107bf}, -	{0x0000b124, 0x000007c0}, -	{0x0000b128, 0x00000000}, -	{0x0000b12c, 0x00000000}, -	{0x0000b130, 0x00000000}, -	{0x0000b134, 0x00000000}, -	{0x0000b138, 0x00000000}, -	{0x0000b13c, 0x00000000}, -	{0x0000b140, 0x003f0020}, -	{0x0000b144, 0x00400041}, -	{0x0000b148, 0x0140005f}, -	{0x0000b14c, 0x0160015f}, -	{0x0000b150, 0x017e017f}, -	{0x0000b154, 0x02410242}, -	{0x0000b158, 0x025f0240}, -	{0x0000b15c, 0x027f0260}, -	{0x0000b160, 0x0341027e}, -	{0x0000b164, 0x035f0340}, -	{0x0000b168, 0x037f0360}, -	{0x0000b16c, 0x04400441}, -	{0x0000b170, 0x0460045f}, -	{0x0000b174, 0x0541047f}, -	{0x0000b178, 0x055f0540}, -	{0x0000b17c, 0x057f0560}, -	{0x0000b180, 0x06400641}, -	{0x0000b184, 0x0660065f}, -	{0x0000b188, 0x067e067f}, -	{0x0000b18c, 0x07410742}, -	{0x0000b190, 0x075f0740}, -	{0x0000b194, 0x077f0760}, -	{0x0000b198, 0x07800781}, -	{0x0000b19c, 0x07a0079f}, -	{0x0000b1a0, 0x07c107bf}, -	{0x0000b1a4, 0x000007c0}, -	{0x0000b1a8, 0x00000000}, -	{0x0000b1ac, 0x00000000}, -	{0x0000b1b0, 0x00000000}, -	{0x0000b1b4, 0x00000000}, -	{0x0000b1b8, 0x00000000}, -	{0x0000b1bc, 0x00000000}, -	{0x0000b1c0, 0x00000000}, -	{0x0000b1c4, 0x00000000}, -	{0x0000b1c8, 0x00000000}, -	{0x0000b1cc, 0x00000000}, -	{0x0000b1d0, 0x00000000}, -	{0x0000b1d4, 0x00000000}, -	{0x0000b1d8, 0x00000000}, -	{0x0000b1dc, 0x00000000}, -	{0x0000b1e0, 0x00000000}, -	{0x0000b1e4, 0x00000000}, -	{0x0000b1e8, 0x00000000}, -	{0x0000b1ec, 0x00000000}, -	{0x0000b1f0, 0x00000396}, -	{0x0000b1f4, 0x00000396}, -	{0x0000b1f8, 0x00000396}, -	{0x0000b1fc, 0x00000196}, -}; -  static const u32 ar9340Modes_low_ob_db_tx_gain_table_1p0[][5] = {  	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */  	{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, @@ -1437,8 +1185,6 @@ static const u32 ar9340_1p0_mac_core[][2] = {  	{0x000083d0, 0x000101ff},  }; -#define ar9340Common_wo_xlna_rx_gain_table_1p0 ar9300Common_wo_xlna_rx_gain_table_2p2 -  static const u32 ar9340_1p0_soc_preamble[][2] = {  	/* Addr      allmodes  */  	{0x00007008, 0x00000000}, @@ -1447,4 +1193,106 @@ static const u32 ar9340_1p0_soc_preamble[][2] = {  	{0x00007038, 0x000004c2},  }; +static const u32 ar9340_cus227_tx_gain_table_1p0[][5] = { +	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ +	{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, +	{0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, +	{0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, +	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, +	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, +	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, +	{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, +	{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, +	{0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, +	{0x0000a514, 0x1c000223, 0x1c000223, 0x11000400, 0x11000400}, +	{0x0000a518, 0x21002220, 0x21002220, 0x15000402, 0x15000402}, +	{0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404}, +	{0x0000a520, 0x2c022220, 0x2c022220, 0x1b000603, 0x1b000603}, +	{0x0000a524, 0x30022222, 0x30022222, 0x1f000a02, 0x1f000a02}, +	{0x0000a528, 0x35022225, 0x35022225, 0x23000a04, 0x23000a04}, +	{0x0000a52c, 0x3b02222a, 0x3b02222a, 0x26000a20, 0x26000a20}, +	{0x0000a530, 0x3f02222c, 0x3f02222c, 0x2a000e20, 0x2a000e20}, +	{0x0000a534, 0x4202242a, 0x4202242a, 0x2e000e22, 0x2e000e22}, +	{0x0000a538, 0x4702244a, 0x4702244a, 0x31000e24, 0x31000e24}, +	{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x34001640, 0x34001640}, +	{0x0000a540, 0x4e02246c, 0x4e02246c, 0x38001660, 0x38001660}, +	{0x0000a544, 0x5302266c, 0x5302266c, 0x3b001861, 0x3b001861}, +	{0x0000a548, 0x5702286c, 0x5702286c, 0x3e001a81, 0x3e001a81}, +	{0x0000a54c, 0x5c02486b, 0x5c02486b, 0x42001a83, 0x42001a83}, +	{0x0000a550, 0x61024a6c, 0x61024a6c, 0x44001c84, 0x44001c84}, +	{0x0000a554, 0x66026a6c, 0x66026a6c, 0x48001ce3, 0x48001ce3}, +	{0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x4c001ce5, 0x4c001ce5}, +	{0x0000a55c, 0x7002708c, 0x7002708c, 0x50001ce9, 0x50001ce9}, +	{0x0000a560, 0x7302b08a, 0x7302b08a, 0x54001ceb, 0x54001ceb}, +	{0x0000a564, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, +	{0x0000a568, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, +	{0x0000a56c, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, +	{0x0000a570, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, +	{0x0000a574, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, +	{0x0000a578, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, +	{0x0000a57c, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, +	{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, +	{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, +	{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, +	{0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, +	{0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, +	{0x0000a594, 0x1c800223, 0x1c800223, 0x11800400, 0x11800400}, +	{0x0000a598, 0x21820220, 0x21820220, 0x15800402, 0x15800402}, +	{0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404}, +	{0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800603, 0x1b800603}, +	{0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800a02, 0x1f800a02}, +	{0x0000a5a8, 0x34822225, 0x34822225, 0x23800a04, 0x23800a04}, +	{0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x26800a20, 0x26800a20}, +	{0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2a800e20, 0x2a800e20}, +	{0x0000a5b4, 0x4282242a, 0x4282242a, 0x2e800e22, 0x2e800e22}, +	{0x0000a5b8, 0x4782244a, 0x4782244a, 0x31800e24, 0x31800e24}, +	{0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x34801640, 0x34801640}, +	{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38801660, 0x38801660}, +	{0x0000a5c4, 0x5382266c, 0x5382266c, 0x3b801861, 0x3b801861}, +	{0x0000a5c8, 0x5782286c, 0x5782286c, 0x3e801a81, 0x3e801a81}, +	{0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x42801a83, 0x42801a83}, +	{0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x44801c84, 0x44801c84}, +	{0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x48801ce3, 0x48801ce3}, +	{0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x4c801ce5, 0x4c801ce5}, +	{0x0000a5dc, 0x7086308c, 0x7086308c, 0x50801ce9, 0x50801ce9}, +	{0x0000a5e0, 0x738a308a, 0x738a308a, 0x54801ceb, 0x54801ceb}, +	{0x0000a5e4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, +	{0x0000a5e8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, +	{0x0000a5ec, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, +	{0x0000a5f0, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, +	{0x0000a5f4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, +	{0x0000a5f8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, +	{0x0000a5fc, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, +	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, +	{0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, +	{0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501}, +	{0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03}, +	{0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, +	{0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04}, +	{0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005}, +	{0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, +	{0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, +	{0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, +	{0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, +	{0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, +	{0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, +	{0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, +	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, +	{0x00016044, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4}, +	{0x00016048, 0x24925666, 0x24925666, 0x8e481266, 0x8e481266}, +	{0x00016280, 0x01000015, 0x01000015, 0x01001015, 0x01001015}, +	{0x00016288, 0x30318000, 0x30318000, 0x00318000, 0x00318000}, +	{0x00016444, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4}, +	{0x00016448, 0x24925666, 0x24925666, 0x8e481266, 0x8e481266}, +	{0x0000a3a4, 0x00000011, 0x00000011, 0x00000011, 0x00000011}, +	{0x0000a3a8, 0x3c3c3c3c, 0x3c3c3c3c, 0x3c3c3c3c, 0x3c3c3c3c}, +	{0x0000a3ac, 0x30303030, 0x30303030, 0x30303030, 0x30303030}, +}; +  #endif /* INITVALS_9340_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h index 092b9d412e7..1b6b4d0cfa9 100644 --- a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h @@ -20,7 +20,15 @@  /* AR9462 2.0 */ -static const u32 ar9462_modes_fast_clock_2p0[][3] = { +#define ar9462_2p0_mac_postamble ar9331_1p1_mac_postamble + +#define ar9462_2p0_common_wo_xlna_rx_gain ar9300Common_wo_xlna_rx_gain_table_2p2 + +#define ar9462_2p0_common_5g_xlna_only_rxgain ar9462_2p0_common_mixed_rx_gain + +#define ar9462_2p0_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484 + +static const u32 ar9462_2p0_modes_fast_clock[][3] = {  	/* Addr      5G_HT20     5G_HT40   */  	{0x00001030, 0x00000268, 0x000004d0},  	{0x00001070, 0x0000018c, 0x00000318}, @@ -33,13 +41,6 @@ static const u32 ar9462_modes_fast_clock_2p0[][3] = {  	{0x0000a254, 0x00000898, 0x00001130},  }; -static const u32 ar9462_pciephy_clkreq_enable_L1_2p0[][2] = { -	/* Addr      allmodes  */ -	{0x00018c00, 0x18253ede}, -	{0x00018c04, 0x000801d8}, -	{0x00018c08, 0x0003780c}, -}; -  static const u32 ar9462_2p0_baseband_postamble[][5] = {  	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */  	{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a800d}, @@ -56,7 +57,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {  	{0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3236605e, 0x32365a5e},  	{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},  	{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, -	{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, +	{0x00009e20, 0x000003a5, 0x000003a5, 0x000003a5, 0x000003a5},  	{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},  	{0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282},  	{0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27}, @@ -95,11 +96,11 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {  	{0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000},  	{0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},  	{0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, -	{0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, +	{0x0000ae20, 0x000001a6, 0x000001a6, 0x000001aa, 0x000001aa},  	{0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550},  }; -static const u32 ar9462_common_rx_gain_table_2p0[][2] = { +static const u32 ar9462_2p0_common_rx_gain[][2] = {  	/* Addr      allmodes  */  	{0x0000a000, 0x00010000},  	{0x0000a004, 0x00030002}, @@ -359,20 +360,13 @@ static const u32 ar9462_common_rx_gain_table_2p0[][2] = {  	{0x0000b1fc, 0x00000196},  }; -static const u32 ar9462_pciephy_clkreq_disable_L1_2p0[][2] = { +static const u32 ar9462_2p0_pciephy_clkreq_disable_L1[][2] = {  	/* Addr      allmodes  */  	{0x00018c00, 0x18213ede},  	{0x00018c04, 0x000801d8},  	{0x00018c08, 0x0003780c},  }; -static const u32 ar9462_pciephy_pll_on_clkreq_disable_L1_2p0[][2] = { -	/* Addr      allmodes  */ -	{0x00018c00, 0x18212ede}, -	{0x00018c04, 0x000801d8}, -	{0x00018c08, 0x0003780c}, -}; -  static const u32 ar9462_2p0_radio_postamble_sys2ant[][5] = {  	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */  	{0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808}, @@ -380,274 +374,7 @@ static const u32 ar9462_2p0_radio_postamble_sys2ant[][5] = {  	{0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},  }; -static const u32 ar9462_common_wo_xlna_rx_gain_table_2p0[][2] = { -	/* Addr      allmodes  */ -	{0x0000a000, 0x00010000}, -	{0x0000a004, 0x00030002}, -	{0x0000a008, 0x00050004}, -	{0x0000a00c, 0x00810080}, -	{0x0000a010, 0x00830082}, -	{0x0000a014, 0x01810180}, -	{0x0000a018, 0x01830182}, -	{0x0000a01c, 0x01850184}, -	{0x0000a020, 0x01890188}, -	{0x0000a024, 0x018b018a}, -	{0x0000a028, 0x018d018c}, -	{0x0000a02c, 0x03820190}, -	{0x0000a030, 0x03840383}, -	{0x0000a034, 0x03880385}, -	{0x0000a038, 0x038a0389}, -	{0x0000a03c, 0x038c038b}, -	{0x0000a040, 0x0390038d}, -	{0x0000a044, 0x03920391}, -	{0x0000a048, 0x03940393}, -	{0x0000a04c, 0x03960395}, -	{0x0000a050, 0x00000000}, -	{0x0000a054, 0x00000000}, -	{0x0000a058, 0x00000000}, -	{0x0000a05c, 0x00000000}, -	{0x0000a060, 0x00000000}, -	{0x0000a064, 0x00000000}, -	{0x0000a068, 0x00000000}, -	{0x0000a06c, 0x00000000}, -	{0x0000a070, 0x00000000}, -	{0x0000a074, 0x00000000}, -	{0x0000a078, 0x00000000}, -	{0x0000a07c, 0x00000000}, -	{0x0000a080, 0x29292929}, -	{0x0000a084, 0x29292929}, -	{0x0000a088, 0x29292929}, -	{0x0000a08c, 0x29292929}, -	{0x0000a090, 0x22292929}, -	{0x0000a094, 0x1d1d2222}, -	{0x0000a098, 0x0c111117}, -	{0x0000a09c, 0x00030303}, -	{0x0000a0a0, 0x00000000}, -	{0x0000a0a4, 0x00000000}, -	{0x0000a0a8, 0x00000000}, -	{0x0000a0ac, 0x00000000}, -	{0x0000a0b0, 0x00000000}, -	{0x0000a0b4, 0x00000000}, -	{0x0000a0b8, 0x00000000}, -	{0x0000a0bc, 0x00000000}, -	{0x0000a0c0, 0x001f0000}, -	{0x0000a0c4, 0x01000101}, -	{0x0000a0c8, 0x011e011f}, -	{0x0000a0cc, 0x011c011d}, -	{0x0000a0d0, 0x02030204}, -	{0x0000a0d4, 0x02010202}, -	{0x0000a0d8, 0x021f0200}, -	{0x0000a0dc, 0x0302021e}, -	{0x0000a0e0, 0x03000301}, -	{0x0000a0e4, 0x031e031f}, -	{0x0000a0e8, 0x0402031d}, -	{0x0000a0ec, 0x04000401}, -	{0x0000a0f0, 0x041e041f}, -	{0x0000a0f4, 0x0502041d}, -	{0x0000a0f8, 0x05000501}, -	{0x0000a0fc, 0x051e051f}, -	{0x0000a100, 0x06010602}, -	{0x0000a104, 0x061f0600}, -	{0x0000a108, 0x061d061e}, -	{0x0000a10c, 0x07020703}, -	{0x0000a110, 0x07000701}, -	{0x0000a114, 0x00000000}, -	{0x0000a118, 0x00000000}, -	{0x0000a11c, 0x00000000}, -	{0x0000a120, 0x00000000}, -	{0x0000a124, 0x00000000}, -	{0x0000a128, 0x00000000}, -	{0x0000a12c, 0x00000000}, -	{0x0000a130, 0x00000000}, -	{0x0000a134, 0x00000000}, -	{0x0000a138, 0x00000000}, -	{0x0000a13c, 0x00000000}, -	{0x0000a140, 0x001f0000}, -	{0x0000a144, 0x01000101}, -	{0x0000a148, 0x011e011f}, -	{0x0000a14c, 0x011c011d}, -	{0x0000a150, 0x02030204}, -	{0x0000a154, 0x02010202}, -	{0x0000a158, 0x021f0200}, -	{0x0000a15c, 0x0302021e}, -	{0x0000a160, 0x03000301}, -	{0x0000a164, 0x031e031f}, -	{0x0000a168, 0x0402031d}, -	{0x0000a16c, 0x04000401}, -	{0x0000a170, 0x041e041f}, -	{0x0000a174, 0x0502041d}, -	{0x0000a178, 0x05000501}, -	{0x0000a17c, 0x051e051f}, -	{0x0000a180, 0x06010602}, -	{0x0000a184, 0x061f0600}, -	{0x0000a188, 0x061d061e}, -	{0x0000a18c, 0x07020703}, -	{0x0000a190, 0x07000701}, -	{0x0000a194, 0x00000000}, -	{0x0000a198, 0x00000000}, -	{0x0000a19c, 0x00000000}, -	{0x0000a1a0, 0x00000000}, -	{0x0000a1a4, 0x00000000}, -	{0x0000a1a8, 0x00000000}, -	{0x0000a1ac, 0x00000000}, -	{0x0000a1b0, 0x00000000}, -	{0x0000a1b4, 0x00000000}, -	{0x0000a1b8, 0x00000000}, -	{0x0000a1bc, 0x00000000}, -	{0x0000a1c0, 0x00000000}, -	{0x0000a1c4, 0x00000000}, -	{0x0000a1c8, 0x00000000}, -	{0x0000a1cc, 0x00000000}, -	{0x0000a1d0, 0x00000000}, -	{0x0000a1d4, 0x00000000}, -	{0x0000a1d8, 0x00000000}, -	{0x0000a1dc, 0x00000000}, -	{0x0000a1e0, 0x00000000}, -	{0x0000a1e4, 0x00000000}, -	{0x0000a1e8, 0x00000000}, -	{0x0000a1ec, 0x00000000}, -	{0x0000a1f0, 0x00000396}, -	{0x0000a1f4, 0x00000396}, -	{0x0000a1f8, 0x00000396}, -	{0x0000a1fc, 0x00000196}, -	{0x0000b000, 0x00010000}, -	{0x0000b004, 0x00030002}, -	{0x0000b008, 0x00050004}, -	{0x0000b00c, 0x00810080}, -	{0x0000b010, 0x00830082}, -	{0x0000b014, 0x01810180}, -	{0x0000b018, 0x01830182}, -	{0x0000b01c, 0x01850184}, -	{0x0000b020, 0x02810280}, -	{0x0000b024, 0x02830282}, -	{0x0000b028, 0x02850284}, -	{0x0000b02c, 0x02890288}, -	{0x0000b030, 0x028b028a}, -	{0x0000b034, 0x0388028c}, -	{0x0000b038, 0x038a0389}, -	{0x0000b03c, 0x038c038b}, -	{0x0000b040, 0x0390038d}, -	{0x0000b044, 0x03920391}, -	{0x0000b048, 0x03940393}, -	{0x0000b04c, 0x03960395}, -	{0x0000b050, 0x00000000}, -	{0x0000b054, 0x00000000}, -	{0x0000b058, 0x00000000}, -	{0x0000b05c, 0x00000000}, -	{0x0000b060, 0x00000000}, -	{0x0000b064, 0x00000000}, -	{0x0000b068, 0x00000000}, -	{0x0000b06c, 0x00000000}, -	{0x0000b070, 0x00000000}, -	{0x0000b074, 0x00000000}, -	{0x0000b078, 0x00000000}, -	{0x0000b07c, 0x00000000}, -	{0x0000b080, 0x32323232}, -	{0x0000b084, 0x2f2f3232}, -	{0x0000b088, 0x23282a2d}, -	{0x0000b08c, 0x1c1e2123}, -	{0x0000b090, 0x14171919}, -	{0x0000b094, 0x0e0e1214}, -	{0x0000b098, 0x03050707}, -	{0x0000b09c, 0x00030303}, -	{0x0000b0a0, 0x00000000}, -	{0x0000b0a4, 0x00000000}, -	{0x0000b0a8, 0x00000000}, -	{0x0000b0ac, 0x00000000}, -	{0x0000b0b0, 0x00000000}, -	{0x0000b0b4, 0x00000000}, -	{0x0000b0b8, 0x00000000}, -	{0x0000b0bc, 0x00000000}, -	{0x0000b0c0, 0x003f0020}, -	{0x0000b0c4, 0x00400041}, -	{0x0000b0c8, 0x0140005f}, -	{0x0000b0cc, 0x0160015f}, -	{0x0000b0d0, 0x017e017f}, -	{0x0000b0d4, 0x02410242}, -	{0x0000b0d8, 0x025f0240}, -	{0x0000b0dc, 0x027f0260}, -	{0x0000b0e0, 0x0341027e}, -	{0x0000b0e4, 0x035f0340}, -	{0x0000b0e8, 0x037f0360}, -	{0x0000b0ec, 0x04400441}, -	{0x0000b0f0, 0x0460045f}, -	{0x0000b0f4, 0x0541047f}, -	{0x0000b0f8, 0x055f0540}, -	{0x0000b0fc, 0x057f0560}, -	{0x0000b100, 0x06400641}, -	{0x0000b104, 0x0660065f}, -	{0x0000b108, 0x067e067f}, -	{0x0000b10c, 0x07410742}, -	{0x0000b110, 0x075f0740}, -	{0x0000b114, 0x077f0760}, -	{0x0000b118, 0x07800781}, -	{0x0000b11c, 0x07a0079f}, -	{0x0000b120, 0x07c107bf}, -	{0x0000b124, 0x000007c0}, -	{0x0000b128, 0x00000000}, -	{0x0000b12c, 0x00000000}, -	{0x0000b130, 0x00000000}, -	{0x0000b134, 0x00000000}, -	{0x0000b138, 0x00000000}, -	{0x0000b13c, 0x00000000}, -	{0x0000b140, 0x003f0020}, -	{0x0000b144, 0x00400041}, -	{0x0000b148, 0x0140005f}, -	{0x0000b14c, 0x0160015f}, -	{0x0000b150, 0x017e017f}, -	{0x0000b154, 0x02410242}, -	{0x0000b158, 0x025f0240}, -	{0x0000b15c, 0x027f0260}, -	{0x0000b160, 0x0341027e}, -	{0x0000b164, 0x035f0340}, -	{0x0000b168, 0x037f0360}, -	{0x0000b16c, 0x04400441}, -	{0x0000b170, 0x0460045f}, -	{0x0000b174, 0x0541047f}, -	{0x0000b178, 0x055f0540}, -	{0x0000b17c, 0x057f0560}, -	{0x0000b180, 0x06400641}, -	{0x0000b184, 0x0660065f}, -	{0x0000b188, 0x067e067f}, -	{0x0000b18c, 0x07410742}, -	{0x0000b190, 0x075f0740}, -	{0x0000b194, 0x077f0760}, -	{0x0000b198, 0x07800781}, -	{0x0000b19c, 0x07a0079f}, -	{0x0000b1a0, 0x07c107bf}, -	{0x0000b1a4, 0x000007c0}, -	{0x0000b1a8, 0x00000000}, -	{0x0000b1ac, 0x00000000}, -	{0x0000b1b0, 0x00000000}, -	{0x0000b1b4, 0x00000000}, -	{0x0000b1b8, 0x00000000}, -	{0x0000b1bc, 0x00000000}, -	{0x0000b1c0, 0x00000000}, -	{0x0000b1c4, 0x00000000}, -	{0x0000b1c8, 0x00000000}, -	{0x0000b1cc, 0x00000000}, -	{0x0000b1d0, 0x00000000}, -	{0x0000b1d4, 0x00000000}, -	{0x0000b1d8, 0x00000000}, -	{0x0000b1dc, 0x00000000}, -	{0x0000b1e0, 0x00000000}, -	{0x0000b1e4, 0x00000000}, -	{0x0000b1e8, 0x00000000}, -	{0x0000b1ec, 0x00000000}, -	{0x0000b1f0, 0x00000396}, -	{0x0000b1f4, 0x00000396}, -	{0x0000b1f8, 0x00000396}, -	{0x0000b1fc, 0x00000196}, -}; - -static const u32 ar9462_2p0_baseband_core_txfir_coeff_japan_2484[][2] = { -	/* Addr      allmodes  */ -	{0x0000a398, 0x00000000}, -	{0x0000a39c, 0x6f7f0301}, -	{0x0000a3a0, 0xca9228ee}, -}; - -static const u32 ar9462_modes_low_ob_db_tx_gain_table_2p0[][5] = { +static const u32 ar9462_2p0_modes_low_ob_db_tx_gain[][5] = {  	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */  	{0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},  	{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, @@ -879,7 +606,7 @@ static const u32 ar9462_2p0_radio_postamble[][5] = {  	{0x0001650c, 0x48000000, 0x40000000, 0x40000000, 0x40000000},  }; -static const u32 ar9462_modes_mix_ob_db_tx_gain_table_2p0[][5] = { +static const u32 ar9462_2p0_modes_mix_ob_db_tx_gain[][5] = {  	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */  	{0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},  	{0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, @@ -942,7 +669,7 @@ static const u32 ar9462_modes_mix_ob_db_tx_gain_table_2p0[][5] = {  	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},  }; -static const u32 ar9462_modes_high_ob_db_tx_gain_table_2p0[][5] = { +static const u32 ar9462_2p0_modes_high_ob_db_tx_gain[][5] = {  	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */  	{0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},  	{0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, @@ -1240,19 +967,7 @@ static const u32 ar9462_2p0_mac_core[][2] = {  	{0x000083d0, 0x000301ff},  }; -static const u32 ar9462_2p0_mac_postamble[][5] = { -	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ -	{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, -	{0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, -	{0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, -	{0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, -	{0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, -	{0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, -	{0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, -	{0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, -}; - -static const u32 ar9462_common_mixed_rx_gain_table_2p0[][2] = { +static const u32 ar9462_2p0_common_mixed_rx_gain[][2] = {  	/* Addr      allmodes  */  	{0x0000a000, 0x00010000},  	{0x0000a004, 0x00030002}, @@ -1517,266 +1232,6 @@ static const u32 ar9462_2p0_baseband_postamble_5g_xlna[][5] = {  	{0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282},  }; -static const u32 ar9462_2p0_5g_xlna_only_rxgain[][2] = { -	/* Addr      allmodes  */ -	{0x0000a000, 0x00010000}, -	{0x0000a004, 0x00030002}, -	{0x0000a008, 0x00050004}, -	{0x0000a00c, 0x00810080}, -	{0x0000a010, 0x00830082}, -	{0x0000a014, 0x01810180}, -	{0x0000a018, 0x01830182}, -	{0x0000a01c, 0x01850184}, -	{0x0000a020, 0x01890188}, -	{0x0000a024, 0x018b018a}, -	{0x0000a028, 0x018d018c}, -	{0x0000a02c, 0x03820190}, -	{0x0000a030, 0x03840383}, -	{0x0000a034, 0x03880385}, -	{0x0000a038, 0x038a0389}, -	{0x0000a03c, 0x038c038b}, -	{0x0000a040, 0x0390038d}, -	{0x0000a044, 0x03920391}, -	{0x0000a048, 0x03940393}, -	{0x0000a04c, 0x03960395}, -	{0x0000a050, 0x00000000}, -	{0x0000a054, 0x00000000}, -	{0x0000a058, 0x00000000}, -	{0x0000a05c, 0x00000000}, -	{0x0000a060, 0x00000000}, -	{0x0000a064, 0x00000000}, -	{0x0000a068, 0x00000000}, -	{0x0000a06c, 0x00000000}, -	{0x0000a070, 0x00000000}, -	{0x0000a074, 0x00000000}, -	{0x0000a078, 0x00000000}, -	{0x0000a07c, 0x00000000}, -	{0x0000a080, 0x29292929}, -	{0x0000a084, 0x29292929}, -	{0x0000a088, 0x29292929}, -	{0x0000a08c, 0x29292929}, -	{0x0000a090, 0x22292929}, -	{0x0000a094, 0x1d1d2222}, -	{0x0000a098, 0x0c111117}, -	{0x0000a09c, 0x00030303}, -	{0x0000a0a0, 0x00000000}, -	{0x0000a0a4, 0x00000000}, -	{0x0000a0a8, 0x00000000}, -	{0x0000a0ac, 0x00000000}, -	{0x0000a0b0, 0x00000000}, -	{0x0000a0b4, 0x00000000}, -	{0x0000a0b8, 0x00000000}, -	{0x0000a0bc, 0x00000000}, -	{0x0000a0c0, 0x001f0000}, -	{0x0000a0c4, 0x01000101}, -	{0x0000a0c8, 0x011e011f}, -	{0x0000a0cc, 0x011c011d}, -	{0x0000a0d0, 0x02030204}, -	{0x0000a0d4, 0x02010202}, -	{0x0000a0d8, 0x021f0200}, -	{0x0000a0dc, 0x0302021e}, -	{0x0000a0e0, 0x03000301}, -	{0x0000a0e4, 0x031e031f}, -	{0x0000a0e8, 0x0402031d}, -	{0x0000a0ec, 0x04000401}, -	{0x0000a0f0, 0x041e041f}, -	{0x0000a0f4, 0x0502041d}, -	{0x0000a0f8, 0x05000501}, -	{0x0000a0fc, 0x051e051f}, -	{0x0000a100, 0x06010602}, -	{0x0000a104, 0x061f0600}, -	{0x0000a108, 0x061d061e}, -	{0x0000a10c, 0x07020703}, -	{0x0000a110, 0x07000701}, -	{0x0000a114, 0x00000000}, -	{0x0000a118, 0x00000000}, -	{0x0000a11c, 0x00000000}, -	{0x0000a120, 0x00000000}, -	{0x0000a124, 0x00000000}, -	{0x0000a128, 0x00000000}, -	{0x0000a12c, 0x00000000}, -	{0x0000a130, 0x00000000}, -	{0x0000a134, 0x00000000}, -	{0x0000a138, 0x00000000}, -	{0x0000a13c, 0x00000000}, -	{0x0000a140, 0x001f0000}, -	{0x0000a144, 0x01000101}, -	{0x0000a148, 0x011e011f}, -	{0x0000a14c, 0x011c011d}, -	{0x0000a150, 0x02030204}, -	{0x0000a154, 0x02010202}, -	{0x0000a158, 0x021f0200}, -	{0x0000a15c, 0x0302021e}, -	{0x0000a160, 0x03000301}, -	{0x0000a164, 0x031e031f}, -	{0x0000a168, 0x0402031d}, -	{0x0000a16c, 0x04000401}, -	{0x0000a170, 0x041e041f}, -	{0x0000a174, 0x0502041d}, -	{0x0000a178, 0x05000501}, -	{0x0000a17c, 0x051e051f}, -	{0x0000a180, 0x06010602}, -	{0x0000a184, 0x061f0600}, -	{0x0000a188, 0x061d061e}, -	{0x0000a18c, 0x07020703}, -	{0x0000a190, 0x07000701}, -	{0x0000a194, 0x00000000}, -	{0x0000a198, 0x00000000}, -	{0x0000a19c, 0x00000000}, -	{0x0000a1a0, 0x00000000}, -	{0x0000a1a4, 0x00000000}, -	{0x0000a1a8, 0x00000000}, -	{0x0000a1ac, 0x00000000}, -	{0x0000a1b0, 0x00000000}, -	{0x0000a1b4, 0x00000000}, -	{0x0000a1b8, 0x00000000}, -	{0x0000a1bc, 0x00000000}, -	{0x0000a1c0, 0x00000000}, -	{0x0000a1c4, 0x00000000}, -	{0x0000a1c8, 0x00000000}, -	{0x0000a1cc, 0x00000000}, -	{0x0000a1d0, 0x00000000}, -	{0x0000a1d4, 0x00000000}, -	{0x0000a1d8, 0x00000000}, -	{0x0000a1dc, 0x00000000}, -	{0x0000a1e0, 0x00000000}, -	{0x0000a1e4, 0x00000000}, -	{0x0000a1e8, 0x00000000}, -	{0x0000a1ec, 0x00000000}, -	{0x0000a1f0, 0x00000396}, -	{0x0000a1f4, 0x00000396}, -	{0x0000a1f8, 0x00000396}, -	{0x0000a1fc, 0x00000196}, -	{0x0000b000, 0x00010000}, -	{0x0000b004, 0x00030002}, -	{0x0000b008, 0x00050004}, -	{0x0000b00c, 0x00810080}, -	{0x0000b010, 0x00830082}, -	{0x0000b014, 0x01810180}, -	{0x0000b018, 0x01830182}, -	{0x0000b01c, 0x01850184}, -	{0x0000b020, 0x02810280}, -	{0x0000b024, 0x02830282}, -	{0x0000b028, 0x02850284}, -	{0x0000b02c, 0x02890288}, -	{0x0000b030, 0x028b028a}, -	{0x0000b034, 0x0388028c}, -	{0x0000b038, 0x038a0389}, -	{0x0000b03c, 0x038c038b}, -	{0x0000b040, 0x0390038d}, -	{0x0000b044, 0x03920391}, -	{0x0000b048, 0x03940393}, -	{0x0000b04c, 0x03960395}, -	{0x0000b050, 0x00000000}, -	{0x0000b054, 0x00000000}, -	{0x0000b058, 0x00000000}, -	{0x0000b05c, 0x00000000}, -	{0x0000b060, 0x00000000}, -	{0x0000b064, 0x00000000}, -	{0x0000b068, 0x00000000}, -	{0x0000b06c, 0x00000000}, -	{0x0000b070, 0x00000000}, -	{0x0000b074, 0x00000000}, -	{0x0000b078, 0x00000000}, -	{0x0000b07c, 0x00000000}, -	{0x0000b080, 0x2a2d2f32}, -	{0x0000b084, 0x21232328}, -	{0x0000b088, 0x19191c1e}, -	{0x0000b08c, 0x12141417}, -	{0x0000b090, 0x07070e0e}, -	{0x0000b094, 0x03030305}, -	{0x0000b098, 0x00000003}, -	{0x0000b09c, 0x00000000}, -	{0x0000b0a0, 0x00000000}, -	{0x0000b0a4, 0x00000000}, -	{0x0000b0a8, 0x00000000}, -	{0x0000b0ac, 0x00000000}, -	{0x0000b0b0, 0x00000000}, -	{0x0000b0b4, 0x00000000}, -	{0x0000b0b8, 0x00000000}, -	{0x0000b0bc, 0x00000000}, -	{0x0000b0c0, 0x003f0020}, -	{0x0000b0c4, 0x00400041}, -	{0x0000b0c8, 0x0140005f}, -	{0x0000b0cc, 0x0160015f}, -	{0x0000b0d0, 0x017e017f}, -	{0x0000b0d4, 0x02410242}, -	{0x0000b0d8, 0x025f0240}, -	{0x0000b0dc, 0x027f0260}, -	{0x0000b0e0, 0x0341027e}, -	{0x0000b0e4, 0x035f0340}, -	{0x0000b0e8, 0x037f0360}, -	{0x0000b0ec, 0x04400441}, -	{0x0000b0f0, 0x0460045f}, -	{0x0000b0f4, 0x0541047f}, -	{0x0000b0f8, 0x055f0540}, -	{0x0000b0fc, 0x057f0560}, -	{0x0000b100, 0x06400641}, -	{0x0000b104, 0x0660065f}, -	{0x0000b108, 0x067e067f}, -	{0x0000b10c, 0x07410742}, -	{0x0000b110, 0x075f0740}, -	{0x0000b114, 0x077f0760}, -	{0x0000b118, 0x07800781}, -	{0x0000b11c, 0x07a0079f}, -	{0x0000b120, 0x07c107bf}, -	{0x0000b124, 0x000007c0}, -	{0x0000b128, 0x00000000}, -	{0x0000b12c, 0x00000000}, -	{0x0000b130, 0x00000000}, -	{0x0000b134, 0x00000000}, -	{0x0000b138, 0x00000000}, -	{0x0000b13c, 0x00000000}, -	{0x0000b140, 0x003f0020}, -	{0x0000b144, 0x00400041}, -	{0x0000b148, 0x0140005f}, -	{0x0000b14c, 0x0160015f}, -	{0x0000b150, 0x017e017f}, -	{0x0000b154, 0x02410242}, -	{0x0000b158, 0x025f0240}, -	{0x0000b15c, 0x027f0260}, -	{0x0000b160, 0x0341027e}, -	{0x0000b164, 0x035f0340}, -	{0x0000b168, 0x037f0360}, -	{0x0000b16c, 0x04400441}, -	{0x0000b170, 0x0460045f}, -	{0x0000b174, 0x0541047f}, -	{0x0000b178, 0x055f0540}, -	{0x0000b17c, 0x057f0560}, -	{0x0000b180, 0x06400641}, -	{0x0000b184, 0x0660065f}, -	{0x0000b188, 0x067e067f}, -	{0x0000b18c, 0x07410742}, -	{0x0000b190, 0x075f0740}, -	{0x0000b194, 0x077f0760}, -	{0x0000b198, 0x07800781}, -	{0x0000b19c, 0x07a0079f}, -	{0x0000b1a0, 0x07c107bf}, -	{0x0000b1a4, 0x000007c0}, -	{0x0000b1a8, 0x00000000}, -	{0x0000b1ac, 0x00000000}, -	{0x0000b1b0, 0x00000000}, -	{0x0000b1b4, 0x00000000}, -	{0x0000b1b8, 0x00000000}, -	{0x0000b1bc, 0x00000000}, -	{0x0000b1c0, 0x00000000}, -	{0x0000b1c4, 0x00000000}, -	{0x0000b1c8, 0x00000000}, -	{0x0000b1cc, 0x00000000}, -	{0x0000b1d0, 0x00000000}, -	{0x0000b1d4, 0x00000000}, -	{0x0000b1d8, 0x00000000}, -	{0x0000b1dc, 0x00000000}, -	{0x0000b1e0, 0x00000000}, -	{0x0000b1e4, 0x00000000}, -	{0x0000b1e8, 0x00000000}, -	{0x0000b1ec, 0x00000000}, -	{0x0000b1f0, 0x00000396}, -	{0x0000b1f4, 0x00000396}, -	{0x0000b1f8, 0x00000396}, -	{0x0000b1fc, 0x00000196}, -}; -  static const u32 ar9462_2p0_baseband_core_mix_rxgain[][2] = {  	/* Addr      allmodes  */  	{0x00009fd0, 0x0a2d6b93}, diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p1_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p1_initvals.h index 4dbc294df7e..dc3adda46e8 100644 --- a/drivers/net/wireless/ath/ath9k/ar9462_2p1_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9462_2p1_initvals.h @@ -20,6 +20,44 @@  /* AR9462 2.1 */ +#define ar9462_2p1_mac_postamble ar9462_2p0_mac_postamble + +#define ar9462_2p1_baseband_core ar9462_2p0_baseband_core + +#define ar9462_2p1_radio_core ar9462_2p0_radio_core + +#define ar9462_2p1_radio_postamble ar9462_2p0_radio_postamble + +#define ar9462_2p1_soc_postamble ar9462_2p0_soc_postamble + +#define ar9462_2p1_radio_postamble_sys2ant ar9462_2p0_radio_postamble_sys2ant + +#define ar9462_2p1_common_rx_gain ar9462_2p0_common_rx_gain + +#define ar9462_2p1_common_mixed_rx_gain ar9462_2p0_common_mixed_rx_gain + +#define ar9462_2p1_common_5g_xlna_only_rxgain ar9462_2p0_common_5g_xlna_only_rxgain + +#define ar9462_2p1_baseband_core_mix_rxgain ar9462_2p0_baseband_core_mix_rxgain + +#define ar9462_2p1_baseband_postamble_mix_rxgain ar9462_2p0_baseband_postamble_mix_rxgain + +#define ar9462_2p1_baseband_postamble_5g_xlna ar9462_2p0_baseband_postamble_5g_xlna + +#define ar9462_2p1_common_wo_xlna_rx_gain ar9462_2p0_common_wo_xlna_rx_gain + +#define ar9462_2p1_modes_low_ob_db_tx_gain ar9462_2p0_modes_low_ob_db_tx_gain + +#define ar9462_2p1_modes_high_ob_db_tx_gain ar9462_2p0_modes_high_ob_db_tx_gain + +#define ar9462_2p1_modes_mix_ob_db_tx_gain ar9462_2p0_modes_mix_ob_db_tx_gain + +#define ar9462_2p1_modes_fast_clock ar9462_2p0_modes_fast_clock + +#define ar9462_2p1_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484 + +#define ar9462_2p1_pciephy_clkreq_disable_L1 ar9462_2p0_pciephy_clkreq_disable_L1 +  static const u32 ar9462_2p1_mac_core[][2] = {  	/* Addr      allmodes  */  	{0x00000008, 0x00000000}, @@ -183,168 +221,6 @@ static const u32 ar9462_2p1_mac_core[][2] = {  	{0x000083d0, 0x000301ff},  }; -static const u32 ar9462_2p1_mac_postamble[][5] = { -	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ -	{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, -	{0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, -	{0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, -	{0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, -	{0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, -	{0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, -	{0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, -	{0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, -}; - -static const u32 ar9462_2p1_baseband_core[][2] = { -	/* Addr      allmodes  */ -	{0x00009800, 0xafe68e30}, -	{0x00009804, 0xfd14e000}, -	{0x00009808, 0x9c0a9f6b}, -	{0x0000980c, 0x04900000}, -	{0x00009814, 0x9280c00a}, -	{0x00009818, 0x00000000}, -	{0x0000981c, 0x00020028}, -	{0x00009834, 0x6400a290}, -	{0x00009838, 0x0108ecff}, -	{0x0000983c, 0x0d000600}, -	{0x00009880, 0x201fff00}, -	{0x00009884, 0x00001042}, -	{0x000098a4, 0x00200400}, -	{0x000098b0, 0x32440bbe}, -	{0x000098d0, 0x004b6a8e}, -	{0x000098d4, 0x00000820}, -	{0x000098dc, 0x00000000}, -	{0x000098e4, 0x01ffffff}, -	{0x000098e8, 0x01ffffff}, -	{0x000098ec, 0x01ffffff}, -	{0x000098f0, 0x00000000}, -	{0x000098f4, 0x00000000}, -	{0x00009bf0, 0x80000000}, -	{0x00009c04, 0xff55ff55}, -	{0x00009c08, 0x0320ff55}, -	{0x00009c0c, 0x00000000}, -	{0x00009c10, 0x00000000}, -	{0x00009c14, 0x00046384}, -	{0x00009c18, 0x05b6b440}, -	{0x00009c1c, 0x00b6b440}, -	{0x00009d00, 0xc080a333}, -	{0x00009d04, 0x40206c10}, -	{0x00009d08, 0x009c4060}, -	{0x00009d0c, 0x9883800a}, -	{0x00009d10, 0x01834061}, -	{0x00009d14, 0x00c0040b}, -	{0x00009d18, 0x00000000}, -	{0x00009e08, 0x0038230c}, -	{0x00009e24, 0x990bb515}, -	{0x00009e28, 0x0c6f0000}, -	{0x00009e30, 0x06336f77}, -	{0x00009e34, 0x6af6532f}, -	{0x00009e38, 0x0cc80c00}, -	{0x00009e40, 0x15262820}, -	{0x00009e4c, 0x00001004}, -	{0x00009e50, 0x00ff03f1}, -	{0x00009e54, 0xe4c555c2}, -	{0x00009e58, 0xfd857722}, -	{0x00009e5c, 0xe9198724}, -	{0x00009fc0, 0x803e4788}, -	{0x00009fc4, 0x0001efb5}, -	{0x00009fcc, 0x40000014}, -	{0x00009fd0, 0x0a193b93}, -	{0x0000a20c, 0x00000000}, -	{0x0000a220, 0x00000000}, -	{0x0000a224, 0x00000000}, -	{0x0000a228, 0x10002310}, -	{0x0000a23c, 0x00000000}, -	{0x0000a244, 0x0c000000}, -	{0x0000a2a0, 0x00000001}, -	{0x0000a2c0, 0x00000001}, -	{0x0000a2c8, 0x00000000}, -	{0x0000a2cc, 0x18c43433}, -	{0x0000a2d4, 0x00000000}, -	{0x0000a2ec, 0x00000000}, -	{0x0000a2f0, 0x00000000}, -	{0x0000a2f4, 0x00000000}, -	{0x0000a2f8, 0x00000000}, -	{0x0000a344, 0x00000000}, -	{0x0000a34c, 0x00000000}, -	{0x0000a350, 0x0000a000}, -	{0x0000a364, 0x00000000}, -	{0x0000a370, 0x00000000}, -	{0x0000a390, 0x00000001}, -	{0x0000a394, 0x00000444}, -	{0x0000a398, 0x001f0e0f}, -	{0x0000a39c, 0x0075393f}, -	{0x0000a3a0, 0xb79f6427}, -	{0x0000a3c0, 0x20202020}, -	{0x0000a3c4, 0x22222220}, -	{0x0000a3c8, 0x20200020}, -	{0x0000a3cc, 0x20202020}, -	{0x0000a3d0, 0x20202020}, -	{0x0000a3d4, 0x20202020}, -	{0x0000a3d8, 0x20202020}, -	{0x0000a3dc, 0x20202020}, -	{0x0000a3e0, 0x20202020}, -	{0x0000a3e4, 0x20202020}, -	{0x0000a3e8, 0x20202020}, -	{0x0000a3ec, 0x20202020}, -	{0x0000a3f0, 0x00000000}, -	{0x0000a3f4, 0x00000006}, -	{0x0000a3f8, 0x0c9bd380}, -	{0x0000a3fc, 0x000f0f01}, -	{0x0000a400, 0x8fa91f01}, -	{0x0000a404, 0x00000000}, -	{0x0000a408, 0x0e79e5c6}, -	{0x0000a40c, 0x00820820}, -	{0x0000a414, 0x1ce739ce}, -	{0x0000a418, 0x2d001dce}, -	{0x0000a434, 0x00000000}, -	{0x0000a438, 0x00001801}, -	{0x0000a43c, 0x00100000}, -	{0x0000a444, 0x00000000}, -	{0x0000a448, 0x05000080}, -	{0x0000a44c, 0x00000001}, -	{0x0000a450, 0x00010000}, -	{0x0000a454, 0x07000000}, -	{0x0000a644, 0xbfad9d74}, -	{0x0000a648, 0x0048060a}, -	{0x0000a64c, 0x00002037}, -	{0x0000a670, 0x03020100}, -	{0x0000a674, 0x09080504}, -	{0x0000a678, 0x0d0c0b0a}, -	{0x0000a67c, 0x13121110}, -	{0x0000a680, 0x31301514}, -	{0x0000a684, 0x35343332}, -	{0x0000a688, 0x00000036}, -	{0x0000a690, 0x00000838}, -	{0x0000a6b0, 0x0000000a}, -	{0x0000a6b4, 0x00512c01}, -	{0x0000a7c0, 0x00000000}, -	{0x0000a7c4, 0xfffffffc}, -	{0x0000a7c8, 0x00000000}, -	{0x0000a7cc, 0x00000000}, -	{0x0000a7d0, 0x00000000}, -	{0x0000a7d4, 0x00000004}, -	{0x0000a7dc, 0x00000000}, -	{0x0000a7f0, 0x80000000}, -	{0x0000a8d0, 0x004b6a8e}, -	{0x0000a8d4, 0x00000820}, -	{0x0000a8dc, 0x00000000}, -	{0x0000a8f0, 0x00000000}, -	{0x0000a8f4, 0x00000000}, -	{0x0000abf0, 0x80000000}, -	{0x0000b2d0, 0x00000080}, -	{0x0000b2d4, 0x00000000}, -	{0x0000b2ec, 0x00000000}, -	{0x0000b2f0, 0x00000000}, -	{0x0000b2f4, 0x00000000}, -	{0x0000b2f8, 0x00000000}, -	{0x0000b408, 0x0e79e5c0}, -	{0x0000b40c, 0x00820820}, -	{0x0000b420, 0x00000000}, -	{0x0000b6b0, 0x0000000a}, -	{0x0000b6b4, 0x00000001}, -}; -  static const u32 ar9462_2p1_baseband_postamble[][5] = {  	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */  	{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a800d}, @@ -361,7 +237,7 @@ static const u32 ar9462_2p1_baseband_postamble[][5] = {  	{0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3236605e, 0x32365a5e},  	{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},  	{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, -	{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, +	{0x00009e20, 0x000003a5, 0x000003a5, 0x000003a5, 0x000003a5},  	{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},  	{0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282},  	{0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27}, @@ -400,1375 +276,16 @@ static const u32 ar9462_2p1_baseband_postamble[][5] = {  	{0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000},  	{0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},  	{0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, -	{0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, +	{0x0000ae20, 0x000001a6, 0x000001a6, 0x000001aa, 0x000001aa},  	{0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550},  }; -static const u32 ar9462_2p1_radio_core[][2] = { -	/* Addr      allmodes  */ -	{0x00016000, 0x36db6db6}, -	{0x00016004, 0x6db6db40}, -	{0x00016008, 0x73f00000}, -	{0x0001600c, 0x00000000}, -	{0x00016010, 0x6d820001}, -	{0x00016040, 0x7f80fff8}, -	{0x0001604c, 0x2699e04f}, -	{0x00016050, 0x6db6db6c}, -	{0x00016058, 0x6c200000}, -	{0x00016080, 0x000c0000}, -	{0x00016084, 0x9a68048c}, -	{0x00016088, 0x54214514}, -	{0x0001608c, 0x1203040b}, -	{0x00016090, 0x24926490}, -	{0x00016098, 0xd2888888}, -	{0x000160a0, 0x0a108ffe}, -	{0x000160a4, 0x812fc491}, -	{0x000160a8, 0x423c8000}, -	{0x000160b4, 0x92000000}, -	{0x000160b8, 0x0285dddc}, -	{0x000160bc, 0x02908888}, -	{0x000160c0, 0x00adb6d0}, -	{0x000160c4, 0x6db6db60}, -	{0x000160c8, 0x6db6db6c}, -	{0x000160cc, 0x0de6c1b0}, -	{0x00016100, 0x3fffbe04}, -	{0x00016104, 0xfff80000}, -	{0x00016108, 0x00200400}, -	{0x00016110, 0x00000000}, -	{0x00016144, 0x02084080}, -	{0x00016148, 0x000080c0}, -	{0x00016280, 0x050a0001}, -	{0x00016284, 0x3d841418}, -	{0x00016288, 0x00000000}, -	{0x0001628c, 0xe3000000}, -	{0x00016290, 0xa1005080}, -	{0x00016294, 0x00000020}, -	{0x00016298, 0x54a82900}, -	{0x00016340, 0x121e4276}, -	{0x00016344, 0x00300000}, -	{0x00016400, 0x36db6db6}, -	{0x00016404, 0x6db6db40}, -	{0x00016408, 0x73f00000}, -	{0x0001640c, 0x00000000}, -	{0x00016410, 0x6c800001}, -	{0x00016440, 0x7f80fff8}, -	{0x0001644c, 0x4699e04f}, -	{0x00016450, 0x6db6db6c}, -	{0x00016500, 0x3fffbe04}, -	{0x00016504, 0xfff80000}, -	{0x00016508, 0x00200400}, -	{0x00016510, 0x00000000}, -	{0x00016544, 0x02084080}, -	{0x00016548, 0x000080c0}, -}; - -static const u32 ar9462_2p1_radio_postamble[][5] = { -	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ -	{0x0001609c, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524}, -	{0x000160b0, 0x01d67f70, 0x01d67f70, 0x01d67f70, 0x01d67f70}, -	{0x0001610c, 0x48000000, 0x40000000, 0x40000000, 0x40000000}, -	{0x0001650c, 0x48000000, 0x40000000, 0x40000000, 0x40000000}, -}; -  static const u32 ar9462_2p1_soc_preamble[][2] = {  	/* Addr      allmodes  */ -	{0x000040a4, 0x00a0c1c9}, +	{0x000040a4, 0x00a0c9c9},  	{0x00007020, 0x00000000},  	{0x00007034, 0x00000002},  	{0x00007038, 0x000004c2},  }; -static const u32 ar9462_2p1_soc_postamble[][5] = { -	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ -	{0x00007010, 0x00000033, 0x00000033, 0x00000033, 0x00000033}, -}; - -static const u32 ar9462_2p1_radio_postamble_sys2ant[][5] = { -	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ -	{0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808}, -	{0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, -	{0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, -}; - -static const u32 ar9462_2p1_common_rx_gain[][2] = { -	/* Addr      allmodes  */ -	{0x0000a000, 0x00010000}, -	{0x0000a004, 0x00030002}, -	{0x0000a008, 0x00050004}, -	{0x0000a00c, 0x00810080}, -	{0x0000a010, 0x00830082}, -	{0x0000a014, 0x01810180}, -	{0x0000a018, 0x01830182}, -	{0x0000a01c, 0x01850184}, -	{0x0000a020, 0x01890188}, -	{0x0000a024, 0x018b018a}, -	{0x0000a028, 0x018d018c}, -	{0x0000a02c, 0x01910190}, -	{0x0000a030, 0x01930192}, -	{0x0000a034, 0x01950194}, -	{0x0000a038, 0x038a0196}, -	{0x0000a03c, 0x038c038b}, -	{0x0000a040, 0x0390038d}, -	{0x0000a044, 0x03920391}, -	{0x0000a048, 0x03940393}, -	{0x0000a04c, 0x03960395}, -	{0x0000a050, 0x00000000}, -	{0x0000a054, 0x00000000}, -	{0x0000a058, 0x00000000}, -	{0x0000a05c, 0x00000000}, -	{0x0000a060, 0x00000000}, -	{0x0000a064, 0x00000000}, -	{0x0000a068, 0x00000000}, -	{0x0000a06c, 0x00000000}, -	{0x0000a070, 0x00000000}, -	{0x0000a074, 0x00000000}, -	{0x0000a078, 0x00000000}, -	{0x0000a07c, 0x00000000}, -	{0x0000a080, 0x22222229}, -	{0x0000a084, 0x1d1d1d1d}, -	{0x0000a088, 0x1d1d1d1d}, -	{0x0000a08c, 0x1d1d1d1d}, -	{0x0000a090, 0x171d1d1d}, -	{0x0000a094, 0x11111717}, -	{0x0000a098, 0x00030311}, -	{0x0000a09c, 0x00000000}, -	{0x0000a0a0, 0x00000000}, -	{0x0000a0a4, 0x00000000}, -	{0x0000a0a8, 0x00000000}, -	{0x0000a0ac, 0x00000000}, -	{0x0000a0b0, 0x00000000}, -	{0x0000a0b4, 0x00000000}, -	{0x0000a0b8, 0x00000000}, -	{0x0000a0bc, 0x00000000}, -	{0x0000a0c0, 0x001f0000}, -	{0x0000a0c4, 0x01000101}, -	{0x0000a0c8, 0x011e011f}, -	{0x0000a0cc, 0x011c011d}, -	{0x0000a0d0, 0x02030204}, -	{0x0000a0d4, 0x02010202}, -	{0x0000a0d8, 0x021f0200}, -	{0x0000a0dc, 0x0302021e}, -	{0x0000a0e0, 0x03000301}, -	{0x0000a0e4, 0x031e031f}, -	{0x0000a0e8, 0x0402031d}, -	{0x0000a0ec, 0x04000401}, -	{0x0000a0f0, 0x041e041f}, -	{0x0000a0f4, 0x0502041d}, -	{0x0000a0f8, 0x05000501}, -	{0x0000a0fc, 0x051e051f}, -	{0x0000a100, 0x06010602}, -	{0x0000a104, 0x061f0600}, -	{0x0000a108, 0x061d061e}, -	{0x0000a10c, 0x07020703}, -	{0x0000a110, 0x07000701}, -	{0x0000a114, 0x00000000}, -	{0x0000a118, 0x00000000}, -	{0x0000a11c, 0x00000000}, -	{0x0000a120, 0x00000000}, -	{0x0000a124, 0x00000000}, -	{0x0000a128, 0x00000000}, -	{0x0000a12c, 0x00000000}, -	{0x0000a130, 0x00000000}, -	{0x0000a134, 0x00000000}, -	{0x0000a138, 0x00000000}, -	{0x0000a13c, 0x00000000}, -	{0x0000a140, 0x001f0000}, -	{0x0000a144, 0x01000101}, -	{0x0000a148, 0x011e011f}, -	{0x0000a14c, 0x011c011d}, -	{0x0000a150, 0x02030204}, -	{0x0000a154, 0x02010202}, -	{0x0000a158, 0x021f0200}, -	{0x0000a15c, 0x0302021e}, -	{0x0000a160, 0x03000301}, -	{0x0000a164, 0x031e031f}, -	{0x0000a168, 0x0402031d}, -	{0x0000a16c, 0x04000401}, -	{0x0000a170, 0x041e041f}, -	{0x0000a174, 0x0502041d}, -	{0x0000a178, 0x05000501}, -	{0x0000a17c, 0x051e051f}, -	{0x0000a180, 0x06010602}, -	{0x0000a184, 0x061f0600}, -	{0x0000a188, 0x061d061e}, -	{0x0000a18c, 0x07020703}, -	{0x0000a190, 0x07000701}, -	{0x0000a194, 0x00000000}, -	{0x0000a198, 0x00000000}, -	{0x0000a19c, 0x00000000}, -	{0x0000a1a0, 0x00000000}, -	{0x0000a1a4, 0x00000000}, -	{0x0000a1a8, 0x00000000}, -	{0x0000a1ac, 0x00000000}, -	{0x0000a1b0, 0x00000000}, -	{0x0000a1b4, 0x00000000}, -	{0x0000a1b8, 0x00000000}, -	{0x0000a1bc, 0x00000000}, -	{0x0000a1c0, 0x00000000}, -	{0x0000a1c4, 0x00000000}, -	{0x0000a1c8, 0x00000000}, -	{0x0000a1cc, 0x00000000}, -	{0x0000a1d0, 0x00000000}, -	{0x0000a1d4, 0x00000000}, -	{0x0000a1d8, 0x00000000}, -	{0x0000a1dc, 0x00000000}, -	{0x0000a1e0, 0x00000000}, -	{0x0000a1e4, 0x00000000}, -	{0x0000a1e8, 0x00000000}, -	{0x0000a1ec, 0x00000000}, -	{0x0000a1f0, 0x00000396}, -	{0x0000a1f4, 0x00000396}, -	{0x0000a1f8, 0x00000396}, -	{0x0000a1fc, 0x00000196}, -	{0x0000b000, 0x00010000}, -	{0x0000b004, 0x00030002}, -	{0x0000b008, 0x00050004}, -	{0x0000b00c, 0x00810080}, -	{0x0000b010, 0x00830082}, -	{0x0000b014, 0x01810180}, -	{0x0000b018, 0x01830182}, -	{0x0000b01c, 0x01850184}, -	{0x0000b020, 0x02810280}, -	{0x0000b024, 0x02830282}, -	{0x0000b028, 0x02850284}, -	{0x0000b02c, 0x02890288}, -	{0x0000b030, 0x028b028a}, -	{0x0000b034, 0x0388028c}, -	{0x0000b038, 0x038a0389}, -	{0x0000b03c, 0x038c038b}, -	{0x0000b040, 0x0390038d}, -	{0x0000b044, 0x03920391}, -	{0x0000b048, 0x03940393}, -	{0x0000b04c, 0x03960395}, -	{0x0000b050, 0x00000000}, -	{0x0000b054, 0x00000000}, -	{0x0000b058, 0x00000000}, -	{0x0000b05c, 0x00000000}, -	{0x0000b060, 0x00000000}, -	{0x0000b064, 0x00000000}, -	{0x0000b068, 0x00000000}, -	{0x0000b06c, 0x00000000}, -	{0x0000b070, 0x00000000}, -	{0x0000b074, 0x00000000}, -	{0x0000b078, 0x00000000}, -	{0x0000b07c, 0x00000000}, -	{0x0000b080, 0x2a2d2f32}, -	{0x0000b084, 0x21232328}, -	{0x0000b088, 0x19191c1e}, -	{0x0000b08c, 0x12141417}, -	{0x0000b090, 0x07070e0e}, -	{0x0000b094, 0x03030305}, -	{0x0000b098, 0x00000003}, -	{0x0000b09c, 0x00000000}, -	{0x0000b0a0, 0x00000000}, -	{0x0000b0a4, 0x00000000}, -	{0x0000b0a8, 0x00000000}, -	{0x0000b0ac, 0x00000000}, -	{0x0000b0b0, 0x00000000}, -	{0x0000b0b4, 0x00000000}, -	{0x0000b0b8, 0x00000000}, -	{0x0000b0bc, 0x00000000}, -	{0x0000b0c0, 0x003f0020}, -	{0x0000b0c4, 0x00400041}, -	{0x0000b0c8, 0x0140005f}, -	{0x0000b0cc, 0x0160015f}, -	{0x0000b0d0, 0x017e017f}, -	{0x0000b0d4, 0x02410242}, -	{0x0000b0d8, 0x025f0240}, -	{0x0000b0dc, 0x027f0260}, -	{0x0000b0e0, 0x0341027e}, -	{0x0000b0e4, 0x035f0340}, -	{0x0000b0e8, 0x037f0360}, -	{0x0000b0ec, 0x04400441}, -	{0x0000b0f0, 0x0460045f}, -	{0x0000b0f4, 0x0541047f}, -	{0x0000b0f8, 0x055f0540}, -	{0x0000b0fc, 0x057f0560}, -	{0x0000b100, 0x06400641}, -	{0x0000b104, 0x0660065f}, -	{0x0000b108, 0x067e067f}, -	{0x0000b10c, 0x07410742}, -	{0x0000b110, 0x075f0740}, -	{0x0000b114, 0x077f0760}, -	{0x0000b118, 0x07800781}, -	{0x0000b11c, 0x07a0079f}, -	{0x0000b120, 0x07c107bf}, -	{0x0000b124, 0x000007c0}, -	{0x0000b128, 0x00000000}, -	{0x0000b12c, 0x00000000}, -	{0x0000b130, 0x00000000}, -	{0x0000b134, 0x00000000}, -	{0x0000b138, 0x00000000}, -	{0x0000b13c, 0x00000000}, -	{0x0000b140, 0x003f0020}, -	{0x0000b144, 0x00400041}, -	{0x0000b148, 0x0140005f}, -	{0x0000b14c, 0x0160015f}, -	{0x0000b150, 0x017e017f}, -	{0x0000b154, 0x02410242}, -	{0x0000b158, 0x025f0240}, -	{0x0000b15c, 0x027f0260}, -	{0x0000b160, 0x0341027e}, -	{0x0000b164, 0x035f0340}, -	{0x0000b168, 0x037f0360}, -	{0x0000b16c, 0x04400441}, -	{0x0000b170, 0x0460045f}, -	{0x0000b174, 0x0541047f}, -	{0x0000b178, 0x055f0540}, -	{0x0000b17c, 0x057f0560}, -	{0x0000b180, 0x06400641}, -	{0x0000b184, 0x0660065f}, -	{0x0000b188, 0x067e067f}, -	{0x0000b18c, 0x07410742}, -	{0x0000b190, 0x075f0740}, -	{0x0000b194, 0x077f0760}, -	{0x0000b198, 0x07800781}, -	{0x0000b19c, 0x07a0079f}, -	{0x0000b1a0, 0x07c107bf}, -	{0x0000b1a4, 0x000007c0}, -	{0x0000b1a8, 0x00000000}, -	{0x0000b1ac, 0x00000000}, -	{0x0000b1b0, 0x00000000}, -	{0x0000b1b4, 0x00000000}, -	{0x0000b1b8, 0x00000000}, -	{0x0000b1bc, 0x00000000}, -	{0x0000b1c0, 0x00000000}, -	{0x0000b1c4, 0x00000000}, -	{0x0000b1c8, 0x00000000}, -	{0x0000b1cc, 0x00000000}, -	{0x0000b1d0, 0x00000000}, -	{0x0000b1d4, 0x00000000}, -	{0x0000b1d8, 0x00000000}, -	{0x0000b1dc, 0x00000000}, -	{0x0000b1e0, 0x00000000}, -	{0x0000b1e4, 0x00000000}, -	{0x0000b1e8, 0x00000000}, -	{0x0000b1ec, 0x00000000}, -	{0x0000b1f0, 0x00000396}, -	{0x0000b1f4, 0x00000396}, -	{0x0000b1f8, 0x00000396}, -	{0x0000b1fc, 0x00000196}, -}; - -static const u32 ar9462_2p1_common_mixed_rx_gain[][2] = { -	/* Addr      allmodes  */ -	{0x0000a000, 0x00010000}, -	{0x0000a004, 0x00030002}, -	{0x0000a008, 0x00050004}, -	{0x0000a00c, 0x00810080}, -	{0x0000a010, 0x00830082}, -	{0x0000a014, 0x01810180}, -	{0x0000a018, 0x01830182}, -	{0x0000a01c, 0x01850184}, -	{0x0000a020, 0x01890188}, -	{0x0000a024, 0x018b018a}, -	{0x0000a028, 0x018d018c}, -	{0x0000a02c, 0x03820190}, -	{0x0000a030, 0x03840383}, -	{0x0000a034, 0x03880385}, -	{0x0000a038, 0x038a0389}, -	{0x0000a03c, 0x038c038b}, -	{0x0000a040, 0x0390038d}, -	{0x0000a044, 0x03920391}, -	{0x0000a048, 0x03940393}, -	{0x0000a04c, 0x03960395}, -	{0x0000a050, 0x00000000}, -	{0x0000a054, 0x00000000}, -	{0x0000a058, 0x00000000}, -	{0x0000a05c, 0x00000000}, -	{0x0000a060, 0x00000000}, -	{0x0000a064, 0x00000000}, -	{0x0000a068, 0x00000000}, -	{0x0000a06c, 0x00000000}, -	{0x0000a070, 0x00000000}, -	{0x0000a074, 0x00000000}, -	{0x0000a078, 0x00000000}, -	{0x0000a07c, 0x00000000}, -	{0x0000a080, 0x29292929}, -	{0x0000a084, 0x29292929}, -	{0x0000a088, 0x29292929}, -	{0x0000a08c, 0x29292929}, -	{0x0000a090, 0x22292929}, -	{0x0000a094, 0x1d1d2222}, -	{0x0000a098, 0x0c111117}, -	{0x0000a09c, 0x00030303}, -	{0x0000a0a0, 0x00000000}, -	{0x0000a0a4, 0x00000000}, -	{0x0000a0a8, 0x00000000}, -	{0x0000a0ac, 0x00000000}, -	{0x0000a0b0, 0x00000000}, -	{0x0000a0b4, 0x00000000}, -	{0x0000a0b8, 0x00000000}, -	{0x0000a0bc, 0x00000000}, -	{0x0000a0c0, 0x001f0000}, -	{0x0000a0c4, 0x01000101}, -	{0x0000a0c8, 0x011e011f}, -	{0x0000a0cc, 0x011c011d}, -	{0x0000a0d0, 0x02030204}, -	{0x0000a0d4, 0x02010202}, -	{0x0000a0d8, 0x021f0200}, -	{0x0000a0dc, 0x0302021e}, -	{0x0000a0e0, 0x03000301}, -	{0x0000a0e4, 0x031e031f}, -	{0x0000a0e8, 0x0402031d}, -	{0x0000a0ec, 0x04000401}, -	{0x0000a0f0, 0x041e041f}, -	{0x0000a0f4, 0x0502041d}, -	{0x0000a0f8, 0x05000501}, -	{0x0000a0fc, 0x051e051f}, -	{0x0000a100, 0x06010602}, -	{0x0000a104, 0x061f0600}, -	{0x0000a108, 0x061d061e}, -	{0x0000a10c, 0x07020703}, -	{0x0000a110, 0x07000701}, -	{0x0000a114, 0x00000000}, -	{0x0000a118, 0x00000000}, -	{0x0000a11c, 0x00000000}, -	{0x0000a120, 0x00000000}, -	{0x0000a124, 0x00000000}, -	{0x0000a128, 0x00000000}, -	{0x0000a12c, 0x00000000}, -	{0x0000a130, 0x00000000}, -	{0x0000a134, 0x00000000}, -	{0x0000a138, 0x00000000}, -	{0x0000a13c, 0x00000000}, -	{0x0000a140, 0x001f0000}, -	{0x0000a144, 0x01000101}, -	{0x0000a148, 0x011e011f}, -	{0x0000a14c, 0x011c011d}, -	{0x0000a150, 0x02030204}, -	{0x0000a154, 0x02010202}, -	{0x0000a158, 0x021f0200}, -	{0x0000a15c, 0x0302021e}, -	{0x0000a160, 0x03000301}, -	{0x0000a164, 0x031e031f}, -	{0x0000a168, 0x0402031d}, -	{0x0000a16c, 0x04000401}, -	{0x0000a170, 0x041e041f}, -	{0x0000a174, 0x0502041d}, -	{0x0000a178, 0x05000501}, -	{0x0000a17c, 0x051e051f}, -	{0x0000a180, 0x06010602}, -	{0x0000a184, 0x061f0600}, -	{0x0000a188, 0x061d061e}, -	{0x0000a18c, 0x07020703}, -	{0x0000a190, 0x07000701}, -	{0x0000a194, 0x00000000}, -	{0x0000a198, 0x00000000}, -	{0x0000a19c, 0x00000000}, -	{0x0000a1a0, 0x00000000}, -	{0x0000a1a4, 0x00000000}, -	{0x0000a1a8, 0x00000000}, -	{0x0000a1ac, 0x00000000}, -	{0x0000a1b0, 0x00000000}, -	{0x0000a1b4, 0x00000000}, -	{0x0000a1b8, 0x00000000}, -	{0x0000a1bc, 0x00000000}, -	{0x0000a1c0, 0x00000000}, -	{0x0000a1c4, 0x00000000}, -	{0x0000a1c8, 0x00000000}, -	{0x0000a1cc, 0x00000000}, -	{0x0000a1d0, 0x00000000}, -	{0x0000a1d4, 0x00000000}, -	{0x0000a1d8, 0x00000000}, -	{0x0000a1dc, 0x00000000}, -	{0x0000a1e0, 0x00000000}, -	{0x0000a1e4, 0x00000000}, -	{0x0000a1e8, 0x00000000}, -	{0x0000a1ec, 0x00000000}, -	{0x0000a1f0, 0x00000396}, -	{0x0000a1f4, 0x00000396}, -	{0x0000a1f8, 0x00000396}, -	{0x0000a1fc, 0x00000196}, -	{0x0000b000, 0x00010000}, -	{0x0000b004, 0x00030002}, -	{0x0000b008, 0x00050004}, -	{0x0000b00c, 0x00810080}, -	{0x0000b010, 0x00830082}, -	{0x0000b014, 0x01810180}, -	{0x0000b018, 0x01830182}, -	{0x0000b01c, 0x01850184}, -	{0x0000b020, 0x02810280}, -	{0x0000b024, 0x02830282}, -	{0x0000b028, 0x02850284}, -	{0x0000b02c, 0x02890288}, -	{0x0000b030, 0x028b028a}, -	{0x0000b034, 0x0388028c}, -	{0x0000b038, 0x038a0389}, -	{0x0000b03c, 0x038c038b}, -	{0x0000b040, 0x0390038d}, -	{0x0000b044, 0x03920391}, -	{0x0000b048, 0x03940393}, -	{0x0000b04c, 0x03960395}, -	{0x0000b050, 0x00000000}, -	{0x0000b054, 0x00000000}, -	{0x0000b058, 0x00000000}, -	{0x0000b05c, 0x00000000}, -	{0x0000b060, 0x00000000}, -	{0x0000b064, 0x00000000}, -	{0x0000b068, 0x00000000}, -	{0x0000b06c, 0x00000000}, -	{0x0000b070, 0x00000000}, -	{0x0000b074, 0x00000000}, -	{0x0000b078, 0x00000000}, -	{0x0000b07c, 0x00000000}, -	{0x0000b080, 0x2a2d2f32}, -	{0x0000b084, 0x21232328}, -	{0x0000b088, 0x19191c1e}, -	{0x0000b08c, 0x12141417}, -	{0x0000b090, 0x07070e0e}, -	{0x0000b094, 0x03030305}, -	{0x0000b098, 0x00000003}, -	{0x0000b09c, 0x00000000}, -	{0x0000b0a0, 0x00000000}, -	{0x0000b0a4, 0x00000000}, -	{0x0000b0a8, 0x00000000}, -	{0x0000b0ac, 0x00000000}, -	{0x0000b0b0, 0x00000000}, -	{0x0000b0b4, 0x00000000}, -	{0x0000b0b8, 0x00000000}, -	{0x0000b0bc, 0x00000000}, -	{0x0000b0c0, 0x003f0020}, -	{0x0000b0c4, 0x00400041}, -	{0x0000b0c8, 0x0140005f}, -	{0x0000b0cc, 0x0160015f}, -	{0x0000b0d0, 0x017e017f}, -	{0x0000b0d4, 0x02410242}, -	{0x0000b0d8, 0x025f0240}, -	{0x0000b0dc, 0x027f0260}, -	{0x0000b0e0, 0x0341027e}, -	{0x0000b0e4, 0x035f0340}, -	{0x0000b0e8, 0x037f0360}, -	{0x0000b0ec, 0x04400441}, -	{0x0000b0f0, 0x0460045f}, -	{0x0000b0f4, 0x0541047f}, -	{0x0000b0f8, 0x055f0540}, -	{0x0000b0fc, 0x057f0560}, -	{0x0000b100, 0x06400641}, -	{0x0000b104, 0x0660065f}, -	{0x0000b108, 0x067e067f}, -	{0x0000b10c, 0x07410742}, -	{0x0000b110, 0x075f0740}, -	{0x0000b114, 0x077f0760}, -	{0x0000b118, 0x07800781}, -	{0x0000b11c, 0x07a0079f}, -	{0x0000b120, 0x07c107bf}, -	{0x0000b124, 0x000007c0}, -	{0x0000b128, 0x00000000}, -	{0x0000b12c, 0x00000000}, -	{0x0000b130, 0x00000000}, -	{0x0000b134, 0x00000000}, -	{0x0000b138, 0x00000000}, -	{0x0000b13c, 0x00000000}, -	{0x0000b140, 0x003f0020}, -	{0x0000b144, 0x00400041}, -	{0x0000b148, 0x0140005f}, -	{0x0000b14c, 0x0160015f}, -	{0x0000b150, 0x017e017f}, -	{0x0000b154, 0x02410242}, -	{0x0000b158, 0x025f0240}, -	{0x0000b15c, 0x027f0260}, -	{0x0000b160, 0x0341027e}, -	{0x0000b164, 0x035f0340}, -	{0x0000b168, 0x037f0360}, -	{0x0000b16c, 0x04400441}, -	{0x0000b170, 0x0460045f}, -	{0x0000b174, 0x0541047f}, -	{0x0000b178, 0x055f0540}, -	{0x0000b17c, 0x057f0560}, -	{0x0000b180, 0x06400641}, -	{0x0000b184, 0x0660065f}, -	{0x0000b188, 0x067e067f}, -	{0x0000b18c, 0x07410742}, -	{0x0000b190, 0x075f0740}, -	{0x0000b194, 0x077f0760}, -	{0x0000b198, 0x07800781}, -	{0x0000b19c, 0x07a0079f}, -	{0x0000b1a0, 0x07c107bf}, -	{0x0000b1a4, 0x000007c0}, -	{0x0000b1a8, 0x00000000}, -	{0x0000b1ac, 0x00000000}, -	{0x0000b1b0, 0x00000000}, -	{0x0000b1b4, 0x00000000}, -	{0x0000b1b8, 0x00000000}, -	{0x0000b1bc, 0x00000000}, -	{0x0000b1c0, 0x00000000}, -	{0x0000b1c4, 0x00000000}, -	{0x0000b1c8, 0x00000000}, -	{0x0000b1cc, 0x00000000}, -	{0x0000b1d0, 0x00000000}, -	{0x0000b1d4, 0x00000000}, -	{0x0000b1d8, 0x00000000}, -	{0x0000b1dc, 0x00000000}, -	{0x0000b1e0, 0x00000000}, -	{0x0000b1e4, 0x00000000}, -	{0x0000b1e8, 0x00000000}, -	{0x0000b1ec, 0x00000000}, -	{0x0000b1f0, 0x00000396}, -	{0x0000b1f4, 0x00000396}, -	{0x0000b1f8, 0x00000396}, -	{0x0000b1fc, 0x00000196}, -}; - -static const u32 ar9462_2p1_baseband_core_mix_rxgain[][2] = { -	/* Addr      allmodes  */ -	{0x00009fd0, 0x0a2d6b93}, -}; - -static const u32 ar9462_2p1_baseband_postamble_mix_rxgain[][5] = { -	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ -	{0x00009820, 0x206a022e, 0x206a022e, 0x206a01ae, 0x206a01ae}, -	{0x00009824, 0x63c640de, 0x5ac640d0, 0x63c640da, 0x63c640da}, -	{0x00009828, 0x0796be89, 0x0696b081, 0x0916be81, 0x0916be81}, -	{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000d8, 0x6c4000d8}, -	{0x00009e10, 0x92c88d2e, 0x7ec88d2e, 0x7ec86d2e, 0x7ec86d2e}, -	{0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3236605e, 0x32395c5e}, -}; - -static const u32 ar9462_2p1_baseband_postamble_5g_xlna[][5] = { -	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ -	{0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282}, -}; - -static const u32 ar9462_2p1_common_wo_xlna_rx_gain[][2] = { -	/* Addr      allmodes  */ -	{0x0000a000, 0x00010000}, -	{0x0000a004, 0x00030002}, -	{0x0000a008, 0x00050004}, -	{0x0000a00c, 0x00810080}, -	{0x0000a010, 0x00830082}, -	{0x0000a014, 0x01810180}, -	{0x0000a018, 0x01830182}, -	{0x0000a01c, 0x01850184}, -	{0x0000a020, 0x01890188}, -	{0x0000a024, 0x018b018a}, -	{0x0000a028, 0x018d018c}, -	{0x0000a02c, 0x03820190}, -	{0x0000a030, 0x03840383}, -	{0x0000a034, 0x03880385}, -	{0x0000a038, 0x038a0389}, -	{0x0000a03c, 0x038c038b}, -	{0x0000a040, 0x0390038d}, -	{0x0000a044, 0x03920391}, -	{0x0000a048, 0x03940393}, -	{0x0000a04c, 0x03960395}, -	{0x0000a050, 0x00000000}, -	{0x0000a054, 0x00000000}, -	{0x0000a058, 0x00000000}, -	{0x0000a05c, 0x00000000}, -	{0x0000a060, 0x00000000}, -	{0x0000a064, 0x00000000}, -	{0x0000a068, 0x00000000}, -	{0x0000a06c, 0x00000000}, -	{0x0000a070, 0x00000000}, -	{0x0000a074, 0x00000000}, -	{0x0000a078, 0x00000000}, -	{0x0000a07c, 0x00000000}, -	{0x0000a080, 0x29292929}, -	{0x0000a084, 0x29292929}, -	{0x0000a088, 0x29292929}, -	{0x0000a08c, 0x29292929}, -	{0x0000a090, 0x22292929}, -	{0x0000a094, 0x1d1d2222}, -	{0x0000a098, 0x0c111117}, -	{0x0000a09c, 0x00030303}, -	{0x0000a0a0, 0x00000000}, -	{0x0000a0a4, 0x00000000}, -	{0x0000a0a8, 0x00000000}, -	{0x0000a0ac, 0x00000000}, -	{0x0000a0b0, 0x00000000}, -	{0x0000a0b4, 0x00000000}, -	{0x0000a0b8, 0x00000000}, -	{0x0000a0bc, 0x00000000}, -	{0x0000a0c0, 0x001f0000}, -	{0x0000a0c4, 0x01000101}, -	{0x0000a0c8, 0x011e011f}, -	{0x0000a0cc, 0x011c011d}, -	{0x0000a0d0, 0x02030204}, -	{0x0000a0d4, 0x02010202}, -	{0x0000a0d8, 0x021f0200}, -	{0x0000a0dc, 0x0302021e}, -	{0x0000a0e0, 0x03000301}, -	{0x0000a0e4, 0x031e031f}, -	{0x0000a0e8, 0x0402031d}, -	{0x0000a0ec, 0x04000401}, -	{0x0000a0f0, 0x041e041f}, -	{0x0000a0f4, 0x0502041d}, -	{0x0000a0f8, 0x05000501}, -	{0x0000a0fc, 0x051e051f}, -	{0x0000a100, 0x06010602}, -	{0x0000a104, 0x061f0600}, -	{0x0000a108, 0x061d061e}, -	{0x0000a10c, 0x07020703}, -	{0x0000a110, 0x07000701}, -	{0x0000a114, 0x00000000}, -	{0x0000a118, 0x00000000}, -	{0x0000a11c, 0x00000000}, -	{0x0000a120, 0x00000000}, -	{0x0000a124, 0x00000000}, -	{0x0000a128, 0x00000000}, -	{0x0000a12c, 0x00000000}, -	{0x0000a130, 0x00000000}, -	{0x0000a134, 0x00000000}, -	{0x0000a138, 0x00000000}, -	{0x0000a13c, 0x00000000}, -	{0x0000a140, 0x001f0000}, -	{0x0000a144, 0x01000101}, -	{0x0000a148, 0x011e011f}, -	{0x0000a14c, 0x011c011d}, -	{0x0000a150, 0x02030204}, -	{0x0000a154, 0x02010202}, -	{0x0000a158, 0x021f0200}, -	{0x0000a15c, 0x0302021e}, -	{0x0000a160, 0x03000301}, -	{0x0000a164, 0x031e031f}, -	{0x0000a168, 0x0402031d}, -	{0x0000a16c, 0x04000401}, -	{0x0000a170, 0x041e041f}, -	{0x0000a174, 0x0502041d}, -	{0x0000a178, 0x05000501}, -	{0x0000a17c, 0x051e051f}, -	{0x0000a180, 0x06010602}, -	{0x0000a184, 0x061f0600}, -	{0x0000a188, 0x061d061e}, -	{0x0000a18c, 0x07020703}, -	{0x0000a190, 0x07000701}, -	{0x0000a194, 0x00000000}, -	{0x0000a198, 0x00000000}, -	{0x0000a19c, 0x00000000}, -	{0x0000a1a0, 0x00000000}, -	{0x0000a1a4, 0x00000000}, -	{0x0000a1a8, 0x00000000}, -	{0x0000a1ac, 0x00000000}, -	{0x0000a1b0, 0x00000000}, -	{0x0000a1b4, 0x00000000}, -	{0x0000a1b8, 0x00000000}, -	{0x0000a1bc, 0x00000000}, -	{0x0000a1c0, 0x00000000}, -	{0x0000a1c4, 0x00000000}, -	{0x0000a1c8, 0x00000000}, -	{0x0000a1cc, 0x00000000}, -	{0x0000a1d0, 0x00000000}, -	{0x0000a1d4, 0x00000000}, -	{0x0000a1d8, 0x00000000}, -	{0x0000a1dc, 0x00000000}, -	{0x0000a1e0, 0x00000000}, -	{0x0000a1e4, 0x00000000}, -	{0x0000a1e8, 0x00000000}, -	{0x0000a1ec, 0x00000000}, -	{0x0000a1f0, 0x00000396}, -	{0x0000a1f4, 0x00000396}, -	{0x0000a1f8, 0x00000396}, -	{0x0000a1fc, 0x00000196}, -	{0x0000b000, 0x00010000}, -	{0x0000b004, 0x00030002}, -	{0x0000b008, 0x00050004}, -	{0x0000b00c, 0x00810080}, -	{0x0000b010, 0x00830082}, -	{0x0000b014, 0x01810180}, -	{0x0000b018, 0x01830182}, -	{0x0000b01c, 0x01850184}, -	{0x0000b020, 0x02810280}, -	{0x0000b024, 0x02830282}, -	{0x0000b028, 0x02850284}, -	{0x0000b02c, 0x02890288}, -	{0x0000b030, 0x028b028a}, -	{0x0000b034, 0x0388028c}, -	{0x0000b038, 0x038a0389}, -	{0x0000b03c, 0x038c038b}, -	{0x0000b040, 0x0390038d}, -	{0x0000b044, 0x03920391}, -	{0x0000b048, 0x03940393}, -	{0x0000b04c, 0x03960395}, -	{0x0000b050, 0x00000000}, -	{0x0000b054, 0x00000000}, -	{0x0000b058, 0x00000000}, -	{0x0000b05c, 0x00000000}, -	{0x0000b060, 0x00000000}, -	{0x0000b064, 0x00000000}, -	{0x0000b068, 0x00000000}, -	{0x0000b06c, 0x00000000}, -	{0x0000b070, 0x00000000}, -	{0x0000b074, 0x00000000}, -	{0x0000b078, 0x00000000}, -	{0x0000b07c, 0x00000000}, -	{0x0000b080, 0x32323232}, -	{0x0000b084, 0x2f2f3232}, -	{0x0000b088, 0x23282a2d}, -	{0x0000b08c, 0x1c1e2123}, -	{0x0000b090, 0x14171919}, -	{0x0000b094, 0x0e0e1214}, -	{0x0000b098, 0x03050707}, -	{0x0000b09c, 0x00030303}, -	{0x0000b0a0, 0x00000000}, -	{0x0000b0a4, 0x00000000}, -	{0x0000b0a8, 0x00000000}, -	{0x0000b0ac, 0x00000000}, -	{0x0000b0b0, 0x00000000}, -	{0x0000b0b4, 0x00000000}, -	{0x0000b0b8, 0x00000000}, -	{0x0000b0bc, 0x00000000}, -	{0x0000b0c0, 0x003f0020}, -	{0x0000b0c4, 0x00400041}, -	{0x0000b0c8, 0x0140005f}, -	{0x0000b0cc, 0x0160015f}, -	{0x0000b0d0, 0x017e017f}, -	{0x0000b0d4, 0x02410242}, -	{0x0000b0d8, 0x025f0240}, -	{0x0000b0dc, 0x027f0260}, -	{0x0000b0e0, 0x0341027e}, -	{0x0000b0e4, 0x035f0340}, -	{0x0000b0e8, 0x037f0360}, -	{0x0000b0ec, 0x04400441}, -	{0x0000b0f0, 0x0460045f}, -	{0x0000b0f4, 0x0541047f}, -	{0x0000b0f8, 0x055f0540}, -	{0x0000b0fc, 0x057f0560}, -	{0x0000b100, 0x06400641}, -	{0x0000b104, 0x0660065f}, -	{0x0000b108, 0x067e067f}, -	{0x0000b10c, 0x07410742}, -	{0x0000b110, 0x075f0740}, -	{0x0000b114, 0x077f0760}, -	{0x0000b118, 0x07800781}, -	{0x0000b11c, 0x07a0079f}, -	{0x0000b120, 0x07c107bf}, -	{0x0000b124, 0x000007c0}, -	{0x0000b128, 0x00000000}, -	{0x0000b12c, 0x00000000}, -	{0x0000b130, 0x00000000}, -	{0x0000b134, 0x00000000}, -	{0x0000b138, 0x00000000}, -	{0x0000b13c, 0x00000000}, -	{0x0000b140, 0x003f0020}, -	{0x0000b144, 0x00400041}, -	{0x0000b148, 0x0140005f}, -	{0x0000b14c, 0x0160015f}, -	{0x0000b150, 0x017e017f}, -	{0x0000b154, 0x02410242}, -	{0x0000b158, 0x025f0240}, -	{0x0000b15c, 0x027f0260}, -	{0x0000b160, 0x0341027e}, -	{0x0000b164, 0x035f0340}, -	{0x0000b168, 0x037f0360}, -	{0x0000b16c, 0x04400441}, -	{0x0000b170, 0x0460045f}, -	{0x0000b174, 0x0541047f}, -	{0x0000b178, 0x055f0540}, -	{0x0000b17c, 0x057f0560}, -	{0x0000b180, 0x06400641}, -	{0x0000b184, 0x0660065f}, -	{0x0000b188, 0x067e067f}, -	{0x0000b18c, 0x07410742}, -	{0x0000b190, 0x075f0740}, -	{0x0000b194, 0x077f0760}, -	{0x0000b198, 0x07800781}, -	{0x0000b19c, 0x07a0079f}, -	{0x0000b1a0, 0x07c107bf}, -	{0x0000b1a4, 0x000007c0}, -	{0x0000b1a8, 0x00000000}, -	{0x0000b1ac, 0x00000000}, -	{0x0000b1b0, 0x00000000}, -	{0x0000b1b4, 0x00000000}, -	{0x0000b1b8, 0x00000000}, -	{0x0000b1bc, 0x00000000}, -	{0x0000b1c0, 0x00000000}, -	{0x0000b1c4, 0x00000000}, -	{0x0000b1c8, 0x00000000}, -	{0x0000b1cc, 0x00000000}, -	{0x0000b1d0, 0x00000000}, -	{0x0000b1d4, 0x00000000}, -	{0x0000b1d8, 0x00000000}, -	{0x0000b1dc, 0x00000000}, -	{0x0000b1e0, 0x00000000}, -	{0x0000b1e4, 0x00000000}, -	{0x0000b1e8, 0x00000000}, -	{0x0000b1ec, 0x00000000}, -	{0x0000b1f0, 0x00000396}, -	{0x0000b1f4, 0x00000396}, -	{0x0000b1f8, 0x00000396}, -	{0x0000b1fc, 0x00000196}, -}; - -static const u32 ar9462_2p1_common_5g_xlna_only_rx_gain[][2] = { -	/* Addr      allmodes  */ -	{0x0000a000, 0x00010000}, -	{0x0000a004, 0x00030002}, -	{0x0000a008, 0x00050004}, -	{0x0000a00c, 0x00810080}, -	{0x0000a010, 0x00830082}, -	{0x0000a014, 0x01810180}, -	{0x0000a018, 0x01830182}, -	{0x0000a01c, 0x01850184}, -	{0x0000a020, 0x01890188}, -	{0x0000a024, 0x018b018a}, -	{0x0000a028, 0x018d018c}, -	{0x0000a02c, 0x03820190}, -	{0x0000a030, 0x03840383}, -	{0x0000a034, 0x03880385}, -	{0x0000a038, 0x038a0389}, -	{0x0000a03c, 0x038c038b}, -	{0x0000a040, 0x0390038d}, -	{0x0000a044, 0x03920391}, -	{0x0000a048, 0x03940393}, -	{0x0000a04c, 0x03960395}, -	{0x0000a050, 0x00000000}, -	{0x0000a054, 0x00000000}, -	{0x0000a058, 0x00000000}, -	{0x0000a05c, 0x00000000}, -	{0x0000a060, 0x00000000}, -	{0x0000a064, 0x00000000}, -	{0x0000a068, 0x00000000}, -	{0x0000a06c, 0x00000000}, -	{0x0000a070, 0x00000000}, -	{0x0000a074, 0x00000000}, -	{0x0000a078, 0x00000000}, -	{0x0000a07c, 0x00000000}, -	{0x0000a080, 0x29292929}, -	{0x0000a084, 0x29292929}, -	{0x0000a088, 0x29292929}, -	{0x0000a08c, 0x29292929}, -	{0x0000a090, 0x22292929}, -	{0x0000a094, 0x1d1d2222}, -	{0x0000a098, 0x0c111117}, -	{0x0000a09c, 0x00030303}, -	{0x0000a0a0, 0x00000000}, -	{0x0000a0a4, 0x00000000}, -	{0x0000a0a8, 0x00000000}, -	{0x0000a0ac, 0x00000000}, -	{0x0000a0b0, 0x00000000}, -	{0x0000a0b4, 0x00000000}, -	{0x0000a0b8, 0x00000000}, -	{0x0000a0bc, 0x00000000}, -	{0x0000a0c0, 0x001f0000}, -	{0x0000a0c4, 0x01000101}, -	{0x0000a0c8, 0x011e011f}, -	{0x0000a0cc, 0x011c011d}, -	{0x0000a0d0, 0x02030204}, -	{0x0000a0d4, 0x02010202}, -	{0x0000a0d8, 0x021f0200}, -	{0x0000a0dc, 0x0302021e}, -	{0x0000a0e0, 0x03000301}, -	{0x0000a0e4, 0x031e031f}, -	{0x0000a0e8, 0x0402031d}, -	{0x0000a0ec, 0x04000401}, -	{0x0000a0f0, 0x041e041f}, -	{0x0000a0f4, 0x0502041d}, -	{0x0000a0f8, 0x05000501}, -	{0x0000a0fc, 0x051e051f}, -	{0x0000a100, 0x06010602}, -	{0x0000a104, 0x061f0600}, -	{0x0000a108, 0x061d061e}, -	{0x0000a10c, 0x07020703}, -	{0x0000a110, 0x07000701}, -	{0x0000a114, 0x00000000}, -	{0x0000a118, 0x00000000}, -	{0x0000a11c, 0x00000000}, -	{0x0000a120, 0x00000000}, -	{0x0000a124, 0x00000000}, -	{0x0000a128, 0x00000000}, -	{0x0000a12c, 0x00000000}, -	{0x0000a130, 0x00000000}, -	{0x0000a134, 0x00000000}, -	{0x0000a138, 0x00000000}, -	{0x0000a13c, 0x00000000}, -	{0x0000a140, 0x001f0000}, -	{0x0000a144, 0x01000101}, -	{0x0000a148, 0x011e011f}, -	{0x0000a14c, 0x011c011d}, -	{0x0000a150, 0x02030204}, -	{0x0000a154, 0x02010202}, -	{0x0000a158, 0x021f0200}, -	{0x0000a15c, 0x0302021e}, -	{0x0000a160, 0x03000301}, -	{0x0000a164, 0x031e031f}, -	{0x0000a168, 0x0402031d}, -	{0x0000a16c, 0x04000401}, -	{0x0000a170, 0x041e041f}, -	{0x0000a174, 0x0502041d}, -	{0x0000a178, 0x05000501}, -	{0x0000a17c, 0x051e051f}, -	{0x0000a180, 0x06010602}, -	{0x0000a184, 0x061f0600}, -	{0x0000a188, 0x061d061e}, -	{0x0000a18c, 0x07020703}, -	{0x0000a190, 0x07000701}, -	{0x0000a194, 0x00000000}, -	{0x0000a198, 0x00000000}, -	{0x0000a19c, 0x00000000}, -	{0x0000a1a0, 0x00000000}, -	{0x0000a1a4, 0x00000000}, -	{0x0000a1a8, 0x00000000}, -	{0x0000a1ac, 0x00000000}, -	{0x0000a1b0, 0x00000000}, -	{0x0000a1b4, 0x00000000}, -	{0x0000a1b8, 0x00000000}, -	{0x0000a1bc, 0x00000000}, -	{0x0000a1c0, 0x00000000}, -	{0x0000a1c4, 0x00000000}, -	{0x0000a1c8, 0x00000000}, -	{0x0000a1cc, 0x00000000}, -	{0x0000a1d0, 0x00000000}, -	{0x0000a1d4, 0x00000000}, -	{0x0000a1d8, 0x00000000}, -	{0x0000a1dc, 0x00000000}, -	{0x0000a1e0, 0x00000000}, -	{0x0000a1e4, 0x00000000}, -	{0x0000a1e8, 0x00000000}, -	{0x0000a1ec, 0x00000000}, -	{0x0000a1f0, 0x00000396}, -	{0x0000a1f4, 0x00000396}, -	{0x0000a1f8, 0x00000396}, -	{0x0000a1fc, 0x00000196}, -	{0x0000b000, 0x00010000}, -	{0x0000b004, 0x00030002}, -	{0x0000b008, 0x00050004}, -	{0x0000b00c, 0x00810080}, -	{0x0000b010, 0x00830082}, -	{0x0000b014, 0x01810180}, -	{0x0000b018, 0x01830182}, -	{0x0000b01c, 0x01850184}, -	{0x0000b020, 0x02810280}, -	{0x0000b024, 0x02830282}, -	{0x0000b028, 0x02850284}, -	{0x0000b02c, 0x02890288}, -	{0x0000b030, 0x028b028a}, -	{0x0000b034, 0x0388028c}, -	{0x0000b038, 0x038a0389}, -	{0x0000b03c, 0x038c038b}, -	{0x0000b040, 0x0390038d}, -	{0x0000b044, 0x03920391}, -	{0x0000b048, 0x03940393}, -	{0x0000b04c, 0x03960395}, -	{0x0000b050, 0x00000000}, -	{0x0000b054, 0x00000000}, -	{0x0000b058, 0x00000000}, -	{0x0000b05c, 0x00000000}, -	{0x0000b060, 0x00000000}, -	{0x0000b064, 0x00000000}, -	{0x0000b068, 0x00000000}, -	{0x0000b06c, 0x00000000}, -	{0x0000b070, 0x00000000}, -	{0x0000b074, 0x00000000}, -	{0x0000b078, 0x00000000}, -	{0x0000b07c, 0x00000000}, -	{0x0000b080, 0x2a2d2f32}, -	{0x0000b084, 0x21232328}, -	{0x0000b088, 0x19191c1e}, -	{0x0000b08c, 0x12141417}, -	{0x0000b090, 0x07070e0e}, -	{0x0000b094, 0x03030305}, -	{0x0000b098, 0x00000003}, -	{0x0000b09c, 0x00000000}, -	{0x0000b0a0, 0x00000000}, -	{0x0000b0a4, 0x00000000}, -	{0x0000b0a8, 0x00000000}, -	{0x0000b0ac, 0x00000000}, -	{0x0000b0b0, 0x00000000}, -	{0x0000b0b4, 0x00000000}, -	{0x0000b0b8, 0x00000000}, -	{0x0000b0bc, 0x00000000}, -	{0x0000b0c0, 0x003f0020}, -	{0x0000b0c4, 0x00400041}, -	{0x0000b0c8, 0x0140005f}, -	{0x0000b0cc, 0x0160015f}, -	{0x0000b0d0, 0x017e017f}, -	{0x0000b0d4, 0x02410242}, -	{0x0000b0d8, 0x025f0240}, -	{0x0000b0dc, 0x027f0260}, -	{0x0000b0e0, 0x0341027e}, -	{0x0000b0e4, 0x035f0340}, -	{0x0000b0e8, 0x037f0360}, -	{0x0000b0ec, 0x04400441}, -	{0x0000b0f0, 0x0460045f}, -	{0x0000b0f4, 0x0541047f}, -	{0x0000b0f8, 0x055f0540}, -	{0x0000b0fc, 0x057f0560}, -	{0x0000b100, 0x06400641}, -	{0x0000b104, 0x0660065f}, -	{0x0000b108, 0x067e067f}, -	{0x0000b10c, 0x07410742}, -	{0x0000b110, 0x075f0740}, -	{0x0000b114, 0x077f0760}, -	{0x0000b118, 0x07800781}, -	{0x0000b11c, 0x07a0079f}, -	{0x0000b120, 0x07c107bf}, -	{0x0000b124, 0x000007c0}, -	{0x0000b128, 0x00000000}, -	{0x0000b12c, 0x00000000}, -	{0x0000b130, 0x00000000}, -	{0x0000b134, 0x00000000}, -	{0x0000b138, 0x00000000}, -	{0x0000b13c, 0x00000000}, -	{0x0000b140, 0x003f0020}, -	{0x0000b144, 0x00400041}, -	{0x0000b148, 0x0140005f}, -	{0x0000b14c, 0x0160015f}, -	{0x0000b150, 0x017e017f}, -	{0x0000b154, 0x02410242}, -	{0x0000b158, 0x025f0240}, -	{0x0000b15c, 0x027f0260}, -	{0x0000b160, 0x0341027e}, -	{0x0000b164, 0x035f0340}, -	{0x0000b168, 0x037f0360}, -	{0x0000b16c, 0x04400441}, -	{0x0000b170, 0x0460045f}, -	{0x0000b174, 0x0541047f}, -	{0x0000b178, 0x055f0540}, -	{0x0000b17c, 0x057f0560}, -	{0x0000b180, 0x06400641}, -	{0x0000b184, 0x0660065f}, -	{0x0000b188, 0x067e067f}, -	{0x0000b18c, 0x07410742}, -	{0x0000b190, 0x075f0740}, -	{0x0000b194, 0x077f0760}, -	{0x0000b198, 0x07800781}, -	{0x0000b19c, 0x07a0079f}, -	{0x0000b1a0, 0x07c107bf}, -	{0x0000b1a4, 0x000007c0}, -	{0x0000b1a8, 0x00000000}, -	{0x0000b1ac, 0x00000000}, -	{0x0000b1b0, 0x00000000}, -	{0x0000b1b4, 0x00000000}, -	{0x0000b1b8, 0x00000000}, -	{0x0000b1bc, 0x00000000}, -	{0x0000b1c0, 0x00000000}, -	{0x0000b1c4, 0x00000000}, -	{0x0000b1c8, 0x00000000}, -	{0x0000b1cc, 0x00000000}, -	{0x0000b1d0, 0x00000000}, -	{0x0000b1d4, 0x00000000}, -	{0x0000b1d8, 0x00000000}, -	{0x0000b1dc, 0x00000000}, -	{0x0000b1e0, 0x00000000}, -	{0x0000b1e4, 0x00000000}, -	{0x0000b1e8, 0x00000000}, -	{0x0000b1ec, 0x00000000}, -	{0x0000b1f0, 0x00000396}, -	{0x0000b1f4, 0x00000396}, -	{0x0000b1f8, 0x00000396}, -	{0x0000b1fc, 0x00000196}, -}; - -static const u32 ar9462_2p1_modes_low_ob_db_tx_gain[][5] = { -	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ -	{0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, -	{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, -	{0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, -	{0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, -	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, -	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, -	{0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, -	{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, -	{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, -	{0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, -	{0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, -	{0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402}, -	{0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, -	{0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, -	{0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, -	{0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, -	{0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, -	{0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, -	{0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, -	{0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, -	{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, -	{0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, -	{0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, -	{0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, -	{0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83}, -	{0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84}, -	{0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3}, -	{0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5}, -	{0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9}, -	{0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb}, -	{0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, -	{0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, -	{0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, -	{0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, -	{0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, -	{0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, -	{0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, -	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, -	{0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, -	{0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501}, -	{0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03}, -	{0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, -	{0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04}, -	{0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005}, -	{0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, -	{0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, -	{0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, -	{0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, -	{0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, -	{0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, -	{0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, -	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, -	{0x00016044, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4}, -	{0x00016048, 0x64992060, 0x64992060, 0x64992060, 0x64992060}, -	{0x00016054, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000}, -	{0x00016444, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4}, -	{0x00016448, 0x64992000, 0x64992000, 0x64992000, 0x64992000}, -	{0x00016454, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000}, -}; - -static const u32 ar9462_2p1_modes_high_ob_db_tx_gain[][5] = { -	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ -	{0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, -	{0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, -	{0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, -	{0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, -	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, -	{0x0000a410, 0x000050da, 0x000050da, 0x000050de, 0x000050de}, -	{0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, -	{0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002}, -	{0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004}, -	{0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200}, -	{0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202}, -	{0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400}, -	{0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402}, -	{0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404}, -	{0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603}, -	{0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02}, -	{0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04}, -	{0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20}, -	{0x0000a530, 0x34025643, 0x34025643, 0x2a000e20, 0x2a000e20}, -	{0x0000a534, 0x38025a44, 0x38025a44, 0x2e000e22, 0x2e000e22}, -	{0x0000a538, 0x3b025e45, 0x3b025e45, 0x31000e24, 0x31000e24}, -	{0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640}, -	{0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660}, -	{0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861}, -	{0x0000a548, 0x55025eb3, 0x55025eb3, 0x3e001a81, 0x3e001a81}, -	{0x0000a54c, 0x58025ef3, 0x58025ef3, 0x42001a83, 0x42001a83}, -	{0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x44001a84, 0x44001a84}, -	{0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3}, -	{0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5}, -	{0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9}, -	{0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb}, -	{0x0000a564, 0x751ffff6, 0x751ffff6, 0x56001eec, 0x56001eec}, -	{0x0000a568, 0x751ffff6, 0x751ffff6, 0x58001ef0, 0x58001ef0}, -	{0x0000a56c, 0x751ffff6, 0x751ffff6, 0x5a001ef4, 0x5a001ef4}, -	{0x0000a570, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6}, -	{0x0000a574, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6}, -	{0x0000a578, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6}, -	{0x0000a57c, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6}, -	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, -	{0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, -	{0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, -	{0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, -	{0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, -	{0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, -	{0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, -	{0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, -	{0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, -	{0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, -	{0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, -	{0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, -	{0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, -	{0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, -	{0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, -	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, -	{0x00016044, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4}, -	{0x00016048, 0x8db49060, 0x8db49060, 0x8db49060, 0x8db49060}, -	{0x00016054, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000}, -	{0x00016444, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4}, -	{0x00016448, 0x8db49000, 0x8db49000, 0x8db49000, 0x8db49000}, -	{0x00016454, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000}, -}; - -static const u32 ar9462_2p1_modes_mix_ob_db_tx_gain[][5] = { -	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ -	{0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, -	{0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, -	{0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, -	{0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, -	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, -	{0x0000a410, 0x0000d0da, 0x0000d0da, 0x0000d0de, 0x0000d0de}, -	{0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, -	{0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002}, -	{0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004}, -	{0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200}, -	{0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202}, -	{0x0000a514, 0x18022622, 0x18022622, 0x12000400, 0x12000400}, -	{0x0000a518, 0x1b022822, 0x1b022822, 0x16000402, 0x16000402}, -	{0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404}, -	{0x0000a520, 0x22022c41, 0x22022c41, 0x1c000603, 0x1c000603}, -	{0x0000a524, 0x28023042, 0x28023042, 0x21000a02, 0x21000a02}, -	{0x0000a528, 0x2c023044, 0x2c023044, 0x25000a04, 0x25000a04}, -	{0x0000a52c, 0x2f023644, 0x2f023644, 0x28000a20, 0x28000a20}, -	{0x0000a530, 0x34025643, 0x34025643, 0x2c000e20, 0x2c000e20}, -	{0x0000a534, 0x38025a44, 0x38025a44, 0x30000e22, 0x30000e22}, -	{0x0000a538, 0x3b025e45, 0x3b025e45, 0x34000e24, 0x34000e24}, -	{0x0000a53c, 0x41025e4a, 0x41025e4a, 0x38001640, 0x38001640}, -	{0x0000a540, 0x48025e6c, 0x48025e6c, 0x3c001660, 0x3c001660}, -	{0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3f001861, 0x3f001861}, -	{0x0000a548, 0x55025eb3, 0x55025eb3, 0x43001a81, 0x43001a81}, -	{0x0000a54c, 0x58025ef3, 0x58025ef3, 0x47001a83, 0x47001a83}, -	{0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x4a001c84, 0x4a001c84}, -	{0x0000a554, 0x62025f56, 0x62025f56, 0x4e001ce3, 0x4e001ce3}, -	{0x0000a558, 0x66027f56, 0x66027f56, 0x52001ce5, 0x52001ce5}, -	{0x0000a55c, 0x6a029f56, 0x6a029f56, 0x56001ce9, 0x56001ce9}, -	{0x0000a560, 0x70049f56, 0x70049f56, 0x5a001ceb, 0x5a001ceb}, -	{0x0000a564, 0x751ffff6, 0x751ffff6, 0x5c001eec, 0x5c001eec}, -	{0x0000a568, 0x751ffff6, 0x751ffff6, 0x5e001ef0, 0x5e001ef0}, -	{0x0000a56c, 0x751ffff6, 0x751ffff6, 0x60001ef4, 0x60001ef4}, -	{0x0000a570, 0x751ffff6, 0x751ffff6, 0x62001ff6, 0x62001ff6}, -	{0x0000a574, 0x751ffff6, 0x751ffff6, 0x62001ff6, 0x62001ff6}, -	{0x0000a578, 0x751ffff6, 0x751ffff6, 0x62001ff6, 0x62001ff6}, -	{0x0000a57c, 0x751ffff6, 0x751ffff6, 0x62001ff6, 0x62001ff6}, -	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, -	{0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, -	{0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, -	{0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, -	{0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, -	{0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, -	{0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, -	{0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, -	{0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, -	{0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, -	{0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, -	{0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, -	{0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, -	{0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, -	{0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, -	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, -}; - -static const u32 ar9462_2p1_modes_fast_clock[][3] = { -	/* Addr      5G_HT20     5G_HT40   */ -	{0x00001030, 0x00000268, 0x000004d0}, -	{0x00001070, 0x0000018c, 0x00000318}, -	{0x000010b0, 0x00000fd0, 0x00001fa0}, -	{0x00008014, 0x044c044c, 0x08980898}, -	{0x0000801c, 0x148ec02b, 0x148ec057}, -	{0x00008318, 0x000044c0, 0x00008980}, -	{0x00009e00, 0x0372131c, 0x0372131c}, -	{0x0000a230, 0x0000400b, 0x00004016}, -	{0x0000a254, 0x00000898, 0x00001130}, -}; - -static const u32 ar9462_2p1_baseband_core_txfir_coeff_japan_2484[][2] = { -	/* Addr      allmodes  */ -	{0x0000a398, 0x00000000}, -	{0x0000a39c, 0x6f7f0301}, -	{0x0000a3a0, 0xca9228ee}, -}; -  #endif /* INITVALS_9462_2P1_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h index 88ff1d7b53a..ce83ce47a1c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h @@ -20,20 +20,18 @@  /* AR9485 1.1 */ -#define ar9485_1_1_mac_postamble ar9300_2p2_mac_postamble +#define ar9485_modes_lowest_ob_db_tx_gain_1_1 ar9485Modes_low_ob_db_tx_gain_1_1 -static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_disable_L1[][2] = { -	/* Addr      allmodes  */ -	{0x00018c00, 0x18012e5e}, -	{0x00018c04, 0x000801d8}, -	{0x00018c08, 0x0000080c}, -}; +#define ar9485_1_1_mac_postamble ar9331_1p1_mac_postamble + +#define ar9485_1_1_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484  static const u32 ar9485Common_wo_xlna_rx_gain_1_1[][2] = {  	/* Addr      allmodes  */  	{0x00009e00, 0x037216a0},  	{0x00009e04, 0x00182020},  	{0x00009e18, 0x00000000}, +	{0x00009e20, 0x000003a8},  	{0x00009e2c, 0x00004121},  	{0x00009e44, 0x02282324},  	{0x0000a000, 0x00060005}, @@ -174,7 +172,7 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = {  	{0x0000a2e0, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},  	{0x0000a2e4, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},  	{0x0000a2e8, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, -	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, +	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050da, 0x000050da},  	{0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},  	{0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},  	{0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, @@ -200,14 +198,14 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = {  	{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},  	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},  	{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, -	{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, -	{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, -	{0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, -	{0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, -	{0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, -	{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, -	{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, -	{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, +	{0x0000a560, 0x900fff0b, 0x900fff0b, 0x62001eee, 0x62001eee}, +	{0x0000a564, 0x960fffcb, 0x960fffcb, 0x66001ff6, 0x66001ff6}, +	{0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6}, +	{0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6}, +	{0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6}, +	{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6}, +	{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6}, +	{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6},  	{0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000},  	{0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000},  	{0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, @@ -263,6 +261,11 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = {  static const u32 ar9485Modes_green_ob_db_tx_gain_1_1[][5] = {  	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */  	{0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003}, +	{0x0000a2d8, 0xf999a83a, 0xf999a83a, 0x7999a83a, 0x7999a83a}, +	{0x0000a2dc, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, +	{0x0000a2e0, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, +	{0x0000a2e4, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, +	{0x0000a2e8, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},  	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},  	{0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000},  	{0x0000a500, 0x00022200, 0x00022200, 0x00000006, 0x00000006}, @@ -297,6 +300,22 @@ static const u32 ar9485Modes_green_ob_db_tx_gain_1_1[][5] = {  	{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},  	{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},  	{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, +	{0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a58c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a590, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a594, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a598, 0x00000000, 0x00000000, 0x01404501, 0x01404501}, +	{0x0000a59c, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02}, +	{0x0000a5a0, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02}, +	{0x0000a5a4, 0x00000000, 0x00000000, 0x02808803, 0x02808803}, +	{0x0000a5a8, 0x00000000, 0x00000000, 0x04c14b04, 0x04c14b04}, +	{0x0000a5ac, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, +	{0x0000a5b0, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, +	{0x0000a5b4, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, +	{0x0000a5b8, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, +	{0x0000a5bc, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},  	{0x0000b500, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},  	{0x0000b504, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},  	{0x0000b508, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, @@ -341,7 +360,7 @@ static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = {  	{0x0000a2e0, 0x00000000, 0x00000000, 0xffc63a84, 0xffc63a84},  	{0x0000a2e4, 0x00000000, 0x00000000, 0xfe0fc000, 0xfe0fc000},  	{0x0000a2e8, 0x00000000, 0x00000000, 0xfff00000, 0xfff00000}, -	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, +	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050da, 0x000050da},  	{0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},  	{0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},  	{0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, @@ -367,14 +386,14 @@ static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = {  	{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},  	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},  	{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, -	{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, -	{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, -	{0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, -	{0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, -	{0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, -	{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, -	{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, -	{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, +	{0x0000a560, 0x900fff0b, 0x900fff0b, 0x62001eee, 0x62001eee}, +	{0x0000a564, 0x960fffcb, 0x960fffcb, 0x66001ff6, 0x66001ff6}, +	{0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6}, +	{0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6}, +	{0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6}, +	{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6}, +	{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6}, +	{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6},  	{0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000},  	{0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000},  	{0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, @@ -521,12 +540,15 @@ static const u32 ar9485Modes_low_ob_db_tx_gain_1_1[][5] = {  	{0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},  }; -#define ar9485_modes_lowest_ob_db_tx_gain_1_1 ar9485Modes_low_ob_db_tx_gain_1_1 -  static const u32 ar9485Modes_green_spur_ob_db_tx_gain_1_1[][5] = {  	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */  	{0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003}, -	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, +	{0x0000a2d8, 0xf999a83a, 0xf999a83a, 0x7999a83a, 0x7999a83a}, +	{0x0000a2dc, 0x00000000, 0x00000000, 0xffad452a, 0xffad452a}, +	{0x0000a2e0, 0x00000000, 0x00000000, 0xffc98634, 0xffc98634}, +	{0x0000a2e4, 0x00000000, 0x00000000, 0xfff60780, 0xfff60780}, +	{0x0000a2e8, 0x00000000, 0x00000000, 0xfffff800, 0xfffff800}, +	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},  	{0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000},  	{0x0000a500, 0x00022200, 0x00022200, 0x00000006, 0x00000006},  	{0x0000a504, 0x05062002, 0x05062002, 0x03000201, 0x03000201}, @@ -543,23 +565,39 @@ static const u32 ar9485Modes_green_spur_ob_db_tx_gain_1_1[][5] = {  	{0x0000a530, 0x48023ec6, 0x48023ec6, 0x310006e0, 0x310006e0},  	{0x0000a534, 0x4d023f01, 0x4d023f01, 0x330006e0, 0x330006e0},  	{0x0000a538, 0x53023f4b, 0x53023f4b, 0x3e0008e3, 0x3e0008e3}, -	{0x0000a53c, 0x5a027f09, 0x5a027f09, 0x410008e5, 0x410008e5}, -	{0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x430008e6, 0x430008e6}, -	{0x0000a544, 0x6502feca, 0x6502feca, 0x4a0008ec, 0x4a0008ec}, -	{0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4e0008f1, 0x4e0008f1}, -	{0x0000a54c, 0x7203feca, 0x7203feca, 0x520008f3, 0x520008f3}, -	{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x54000eed, 0x54000eed}, -	{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x58000ef1, 0x58000ef1}, -	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5c000ef3, 0x5c000ef3}, -	{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x60000ef5, 0x60000ef5}, -	{0x0000a560, 0x900fff0b, 0x900fff0b, 0x62000ef6, 0x62000ef6}, -	{0x0000a564, 0x960fffcb, 0x960fffcb, 0x62000ef6, 0x62000ef6}, -	{0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, -	{0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, -	{0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, -	{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, -	{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, -	{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, +	{0x0000a53c, 0x5a027f09, 0x5a027f09, 0x430008e6, 0x430008e6}, +	{0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x4a0008ec, 0x4a0008ec}, +	{0x0000a544, 0x6502feca, 0x6502feca, 0x4e0008f1, 0x4e0008f1}, +	{0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x520008f3, 0x520008f3}, +	{0x0000a54c, 0x7203feca, 0x7203feca, 0x54000eed, 0x54000eed}, +	{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x58000ef1, 0x58000ef1}, +	{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x5c000ef3, 0x5c000ef3}, +	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x62000ef6, 0x62000ef6}, +	{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x66001ff0, 0x66001ff0}, +	{0x0000a560, 0x900fff0b, 0x900fff0b, 0x68001ff6, 0x68001ff6}, +	{0x0000a564, 0x960fffcb, 0x960fffcb, 0x68001ff6, 0x68001ff6}, +	{0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x68001ff6, 0x68001ff6}, +	{0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x68001ff6, 0x68001ff6}, +	{0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x68001ff6, 0x68001ff6}, +	{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x68001ff6, 0x68001ff6}, +	{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x68001ff6, 0x68001ff6}, +	{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x68001ff6, 0x68001ff6}, +	{0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a58c, 0x00000000, 0x00000000, 0x01804000, 0x01804000}, +	{0x0000a590, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02}, +	{0x0000a594, 0x00000000, 0x00000000, 0x0340ca02, 0x0340ca02}, +	{0x0000a598, 0x00000000, 0x00000000, 0x0340cd03, 0x0340cd03}, +	{0x0000a59c, 0x00000000, 0x00000000, 0x0340cd03, 0x0340cd03}, +	{0x0000a5a0, 0x00000000, 0x00000000, 0x06415304, 0x06415304}, +	{0x0000a5a4, 0x00000000, 0x00000000, 0x04c11905, 0x04c11905}, +	{0x0000a5a8, 0x00000000, 0x00000000, 0x06415905, 0x06415905}, +	{0x0000a5ac, 0x00000000, 0x00000000, 0x06415905, 0x06415905}, +	{0x0000a5b0, 0x00000000, 0x00000000, 0x06415905, 0x06415905}, +	{0x0000a5b4, 0x00000000, 0x00000000, 0x06415905, 0x06415905}, +	{0x0000a5b8, 0x00000000, 0x00000000, 0x06415905, 0x06415905}, +	{0x0000a5bc, 0x00000000, 0x00000000, 0x06415905, 0x06415905},  	{0x0000b500, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},  	{0x0000b504, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},  	{0x0000b508, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, @@ -823,6 +861,7 @@ static const u32 ar9485_common_rx_gain_1_1[][2] = {  	{0x00009e00, 0x03721b20},  	{0x00009e04, 0x00082020},  	{0x00009e18, 0x0300501e}, +	{0x00009e20, 0x000003ba},  	{0x00009e2c, 0x00002e21},  	{0x00009e44, 0x02182324},  	{0x0000a000, 0x00060005}, @@ -955,20 +994,6 @@ static const u32 ar9485_common_rx_gain_1_1[][2] = {  	{0x0000a1fc, 0x00000296},  }; -static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_enable_L1[][2] = { -	/* Addr      allmodes  */ -	{0x00018c00, 0x18052e5e}, -	{0x00018c04, 0x000801d8}, -	{0x00018c08, 0x0000080c}, -}; - -static const u32 ar9485_1_1_pcie_phy_clkreq_enable_L1[][2] = { -	/* Addr      allmodes  */ -	{0x00018c00, 0x18053e5e}, -	{0x00018c04, 0x000801d8}, -	{0x00018c08, 0x0000080c}, -}; -  static const u32 ar9485_1_1_soc_preamble[][2] = {  	/* Addr      allmodes  */  	{0x00004014, 0xba280400}, @@ -1001,7 +1026,6 @@ static const u32 ar9485_1_1_baseband_postamble[][5] = {  	{0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec80d2e, 0x7ec80d2e},  	{0x00009e14, 0x31395d53, 0x31396053, 0x312e6053, 0x312e5d53},  	{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, -	{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},  	{0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222},  	{0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010},  	{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, @@ -1020,7 +1044,7 @@ static const u32 ar9485_1_1_baseband_postamble[][5] = {  	{0x0000a284, 0x00000000, 0x00000000, 0x000002a0, 0x000002a0},  	{0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000},  	{0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00058d18, 0x00058d18}, +	{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},  	{0x0000a2d0, 0x00071981, 0x00071981, 0x00071982, 0x00071982},  	{0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},  	{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, @@ -1028,13 +1052,6 @@ static const u32 ar9485_1_1_baseband_postamble[][5] = {  	{0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},  }; -static const u32 ar9485_1_1_pcie_phy_clkreq_disable_L1[][2] = { -	/* Addr      allmodes  */ -	{0x00018c00, 0x18013e5e}, -	{0x00018c04, 0x000801d8}, -	{0x00018c08, 0x0000080c}, -}; -  static const u32 ar9485_1_1_radio_postamble[][2] = {  	/* Addr      allmodes  */  	{0x0001609c, 0x0b283f31}, @@ -1206,6 +1223,18 @@ static const u32 ar9485_1_1_mac_core[][2] = {  	{0x000083d0, 0x000301ff},  }; -#define ar9485_1_1_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484 +static const u32 ar9485_1_1_pcie_phy_clkreq_disable_L1[][2] = { +	/* Addr      allmodes  */ +	{0x00018c00, 0x18013e5e}, +	{0x00018c04, 0x000801d8}, +	{0x00018c08, 0x0000080c}, +}; + +static const u32 ar9485_1_1_pll_on_cdr_on_clkreq_disable_L1[][2] = { +	/* Addr      allmodes  */ +	{0x00018c00, 0x1801265e}, +	{0x00018c04, 0x000801d8}, +	{0x00018c08, 0x0000080c}, +};  #endif /* INITVALS_9485_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h new file mode 100644 index 00000000000..8e5c3b9786e --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h @@ -0,0 +1,718 @@ +/* + * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011-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. + */ + +#ifndef INITVALS_953X_H +#define INITVALS_953X_H + +#define qca953x_1p0_mac_postamble ar9300_2p2_mac_postamble + +#define qca953x_1p0_soc_postamble ar9300_2p2_soc_postamble + +#define qca953x_1p0_common_rx_gain_table ar9300Common_rx_gain_table_2p2 + +#define qca953x_1p0_common_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2 + +#define qca953x_1p0_modes_fast_clock ar9300Modes_fast_clock_2p2 + +static const u32 qca953x_1p0_mac_core[][2] = { +	/* Addr      allmodes  */ +	{0x00000008, 0x00000000}, +	{0x00000030, 0x00020085}, +	{0x00000034, 0x00000005}, +	{0x00000040, 0x00000000}, +	{0x00000044, 0x00000000}, +	{0x00000048, 0x00000008}, +	{0x0000004c, 0x00000010}, +	{0x00000050, 0x00000000}, +	{0x00001040, 0x002ffc0f}, +	{0x00001044, 0x002ffc0f}, +	{0x00001048, 0x002ffc0f}, +	{0x0000104c, 0x002ffc0f}, +	{0x00001050, 0x002ffc0f}, +	{0x00001054, 0x002ffc0f}, +	{0x00001058, 0x002ffc0f}, +	{0x0000105c, 0x002ffc0f}, +	{0x00001060, 0x002ffc0f}, +	{0x00001064, 0x002ffc0f}, +	{0x000010f0, 0x00000100}, +	{0x00001270, 0x00000000}, +	{0x000012b0, 0x00000000}, +	{0x000012f0, 0x00000000}, +	{0x0000143c, 0x00000000}, +	{0x0000147c, 0x00000000}, +	{0x00008000, 0x00000000}, +	{0x00008004, 0x00000000}, +	{0x00008008, 0x00000000}, +	{0x0000800c, 0x00000000}, +	{0x00008018, 0x00000000}, +	{0x00008020, 0x00000000}, +	{0x00008038, 0x00000000}, +	{0x0000803c, 0x00000000}, +	{0x00008040, 0x00000000}, +	{0x00008044, 0x00000000}, +	{0x00008048, 0x00000000}, +	{0x0000804c, 0xffffffff}, +	{0x00008054, 0x00000000}, +	{0x00008058, 0x00000000}, +	{0x0000805c, 0x000fc78f}, +	{0x00008060, 0x0000000f}, +	{0x00008064, 0x00000000}, +	{0x00008070, 0x00000310}, +	{0x00008074, 0x00000020}, +	{0x00008078, 0x00000000}, +	{0x0000809c, 0x0000000f}, +	{0x000080a0, 0x00000000}, +	{0x000080a4, 0x02ff0000}, +	{0x000080a8, 0x0e070605}, +	{0x000080ac, 0x0000000d}, +	{0x000080b0, 0x00000000}, +	{0x000080b4, 0x00000000}, +	{0x000080b8, 0x00000000}, +	{0x000080bc, 0x00000000}, +	{0x000080c0, 0x2a800000}, +	{0x000080c4, 0x06900168}, +	{0x000080c8, 0x13881c22}, +	{0x000080cc, 0x01f40000}, +	{0x000080d0, 0x00252500}, +	{0x000080d4, 0x00a00000}, +	{0x000080d8, 0x00400000}, +	{0x000080dc, 0x00000000}, +	{0x000080e0, 0xffffffff}, +	{0x000080e4, 0x0000ffff}, +	{0x000080e8, 0x3f3f3f3f}, +	{0x000080ec, 0x00000000}, +	{0x000080f0, 0x00000000}, +	{0x000080f4, 0x00000000}, +	{0x000080fc, 0x00020000}, +	{0x00008100, 0x00000000}, +	{0x00008108, 0x00000052}, +	{0x0000810c, 0x00000000}, +	{0x00008110, 0x00000000}, +	{0x00008114, 0x000007ff}, +	{0x00008118, 0x000000aa}, +	{0x0000811c, 0x00003210}, +	{0x00008124, 0x00000000}, +	{0x00008128, 0x00000000}, +	{0x0000812c, 0x00000000}, +	{0x00008130, 0x00000000}, +	{0x00008134, 0x00000000}, +	{0x00008138, 0x00000000}, +	{0x0000813c, 0x0000ffff}, +	{0x00008140, 0x000000fe}, +	{0x00008144, 0xffffffff}, +	{0x00008168, 0x00000000}, +	{0x0000816c, 0x00000000}, +	{0x000081c0, 0x00000000}, +	{0x000081c4, 0x33332210}, +	{0x000081ec, 0x00000000}, +	{0x000081f0, 0x00000000}, +	{0x000081f4, 0x00000000}, +	{0x000081f8, 0x00000000}, +	{0x000081fc, 0x00000000}, +	{0x00008240, 0x00100000}, +	{0x00008244, 0x0010f3d7}, +	{0x00008248, 0x00000852}, +	{0x0000824c, 0x0001e7ae}, +	{0x00008250, 0x00000000}, +	{0x00008254, 0x00000000}, +	{0x00008258, 0x00000000}, +	{0x0000825c, 0x40000000}, +	{0x00008260, 0x00080922}, +	{0x00008264, 0x9d400010}, +	{0x00008268, 0xffffffff}, +	{0x0000826c, 0x0000ffff}, +	{0x00008270, 0x00000000}, +	{0x00008274, 0x40000000}, +	{0x00008278, 0x003e4180}, +	{0x0000827c, 0x00000004}, +	{0x00008284, 0x0000002c}, +	{0x00008288, 0x0000002c}, +	{0x0000828c, 0x000000ff}, +	{0x00008294, 0x00000000}, +	{0x00008298, 0x00000000}, +	{0x0000829c, 0x00000000}, +	{0x00008300, 0x00001d40}, +	{0x00008314, 0x00000000}, +	{0x0000831c, 0x0000010d}, +	{0x00008328, 0x00000000}, +	{0x0000832c, 0x0000001f}, +	{0x00008330, 0x00000302}, +	{0x00008334, 0x00000700}, +	{0x00008338, 0xffff0000}, +	{0x0000833c, 0x02400000}, +	{0x00008340, 0x000107ff}, +	{0x00008344, 0xaa48107b}, +	{0x00008348, 0x008f0000}, +	{0x0000835c, 0x00000000}, +	{0x00008360, 0xffffffff}, +	{0x00008364, 0xffffffff}, +	{0x00008368, 0x00000000}, +	{0x00008370, 0x00000000}, +	{0x00008374, 0x000000ff}, +	{0x00008378, 0x00000000}, +	{0x0000837c, 0x00000000}, +	{0x00008380, 0xffffffff}, +	{0x00008384, 0xffffffff}, +	{0x00008390, 0xffffffff}, +	{0x00008394, 0xffffffff}, +	{0x00008398, 0x00000000}, +	{0x0000839c, 0x00000000}, +	{0x000083a0, 0x00000000}, +	{0x000083a4, 0x0000fa14}, +	{0x000083a8, 0x000f0c00}, +	{0x000083ac, 0x33332210}, +	{0x000083b0, 0x33332210}, +	{0x000083b4, 0x33332210}, +	{0x000083b8, 0x33332210}, +	{0x000083bc, 0x00000000}, +	{0x000083c0, 0x00000000}, +	{0x000083c4, 0x00000000}, +	{0x000083c8, 0x00000000}, +	{0x000083cc, 0x00000200}, +	{0x000083d0, 0x8c7901ff}, +}; + +static const u32 qca953x_1p0_baseband_core[][2] = { +	/* Addr      allmodes  */ +	{0x00009800, 0xafe68e30}, +	{0x00009804, 0xfd14e000}, +	{0x00009808, 0x9c0a9f6b}, +	{0x0000980c, 0x04900000}, +	{0x00009814, 0x0280c00a}, +	{0x00009818, 0x00000000}, +	{0x0000981c, 0x00020028}, +	{0x00009834, 0x6400a190}, +	{0x00009838, 0x0108ecff}, +	{0x0000983c, 0x14000600}, +	{0x00009880, 0x201fff00}, +	{0x00009884, 0x00001042}, +	{0x000098a4, 0x00200400}, +	{0x000098b0, 0x32840bbe}, +	{0x000098bc, 0x00000002}, +	{0x000098d0, 0x004b6a8e}, +	{0x000098d4, 0x00000820}, +	{0x000098dc, 0x00000000}, +	{0x000098f0, 0x00000000}, +	{0x000098f4, 0x00000000}, +	{0x00009c04, 0xff55ff55}, +	{0x00009c08, 0x0320ff55}, +	{0x00009c0c, 0x00000000}, +	{0x00009c10, 0x00000000}, +	{0x00009c14, 0x00046384}, +	{0x00009c18, 0x05b6b440}, +	{0x00009c1c, 0x00b6b440}, +	{0x00009d00, 0xc080a333}, +	{0x00009d04, 0x40206c10}, +	{0x00009d08, 0x009c4060}, +	{0x00009d0c, 0x9883800a}, +	{0x00009d10, 0x01884061}, +	{0x00009d14, 0x00c0040b}, +	{0x00009d18, 0x00000000}, +	{0x00009e08, 0x0038230c}, +	{0x00009e24, 0x990bb515}, +	{0x00009e28, 0x0c6f0000}, +	{0x00009e30, 0x06336f77}, +	{0x00009e34, 0x6af6532f}, +	{0x00009e38, 0x0cc80c00}, +	{0x00009e40, 0x0d261820}, +	{0x00009e4c, 0x00001004}, +	{0x00009e50, 0x00ff03f1}, +	{0x00009fc0, 0x813e4788}, +	{0x00009fc4, 0x0001efb5}, +	{0x00009fcc, 0x40000014}, +	{0x00009fd0, 0x01193b91}, +	{0x0000a20c, 0x00000000}, +	{0x0000a220, 0x00000000}, +	{0x0000a224, 0x00000000}, +	{0x0000a228, 0x10002310}, +	{0x0000a23c, 0x00000000}, +	{0x0000a244, 0x0c000000}, +	{0x0000a248, 0x00000140}, +	{0x0000a2a0, 0x00000007}, +	{0x0000a2c0, 0x00000007}, +	{0x0000a2c8, 0x00000000}, +	{0x0000a2d4, 0x00000000}, +	{0x0000a2ec, 0x00000000}, +	{0x0000a2f0, 0x00000000}, +	{0x0000a2f4, 0x00000000}, +	{0x0000a2f8, 0x00000000}, +	{0x0000a344, 0x00000000}, +	{0x0000a34c, 0x00000000}, +	{0x0000a350, 0x0000a000}, +	{0x0000a364, 0x00000000}, +	{0x0000a370, 0x00000000}, +	{0x0000a390, 0x00000001}, +	{0x0000a394, 0x00000444}, +	{0x0000a398, 0x001f0e0f}, +	{0x0000a39c, 0x0075393f}, +	{0x0000a3a0, 0xb79f6427}, +	{0x0000a3a4, 0x000000ff}, +	{0x0000a3a8, 0x6a6a6a6a}, +	{0x0000a3ac, 0x6a6a6a6a}, +	{0x0000a3b0, 0x00c8641a}, +	{0x0000a3b4, 0x0000001a}, +	{0x0000a3b8, 0x0088642a}, +	{0x0000a3bc, 0x000001fa}, +	{0x0000a3c0, 0x20202020}, +	{0x0000a3c4, 0x22222220}, +	{0x0000a3c8, 0x20200020}, +	{0x0000a3cc, 0x20202020}, +	{0x0000a3d0, 0x20202020}, +	{0x0000a3d4, 0x20202020}, +	{0x0000a3d8, 0x20202020}, +	{0x0000a3dc, 0x20202020}, +	{0x0000a3e0, 0x20202020}, +	{0x0000a3e4, 0x20202020}, +	{0x0000a3e8, 0x20202020}, +	{0x0000a3ec, 0x20202020}, +	{0x0000a3f0, 0x00000000}, +	{0x0000a3f4, 0x00000000}, +	{0x0000a3f8, 0x0c9bd380}, +	{0x0000a3fc, 0x000f0f01}, +	{0x0000a400, 0x8fa91f01}, +	{0x0000a404, 0x00000000}, +	{0x0000a408, 0x0e79e5c6}, +	{0x0000a40c, 0x00820820}, +	{0x0000a414, 0x1ce42108}, +	{0x0000a418, 0x2d001dce}, +	{0x0000a41c, 0x1ce73908}, +	{0x0000a420, 0x000001ce}, +	{0x0000a424, 0x1ce738e7}, +	{0x0000a428, 0x000001ce}, +	{0x0000a42c, 0x1ce739ce}, +	{0x0000a430, 0x1ce739ce}, +	{0x0000a434, 0x00000000}, +	{0x0000a438, 0x00001801}, +	{0x0000a43c, 0x00100000}, +	{0x0000a444, 0x00000000}, +	{0x0000a448, 0x05000080}, +	{0x0000a44c, 0x00000001}, +	{0x0000a450, 0x00010000}, +	{0x0000a458, 0x00000000}, +	{0x0000a644, 0xbfad9d74}, +	{0x0000a648, 0x0048060a}, +	{0x0000a64c, 0x00003c37}, +	{0x0000a670, 0x03020100}, +	{0x0000a674, 0x09080504}, +	{0x0000a678, 0x0d0c0b0a}, +	{0x0000a67c, 0x13121110}, +	{0x0000a680, 0x31301514}, +	{0x0000a684, 0x35343332}, +	{0x0000a688, 0x00000036}, +	{0x0000a690, 0x08000838}, +	{0x0000a7cc, 0x00000000}, +	{0x0000a7d0, 0x00000000}, +	{0x0000a7d4, 0x00000004}, +	{0x0000a7dc, 0x00000000}, +	{0x0000a8d0, 0x004b6a8e}, +	{0x0000a8d4, 0x00000820}, +	{0x0000a8dc, 0x00000000}, +	{0x0000a8f0, 0x00000000}, +	{0x0000a8f4, 0x00000000}, +	{0x0000b2d0, 0x00000080}, +	{0x0000b2d4, 0x00000000}, +	{0x0000b2ec, 0x00000000}, +	{0x0000b2f0, 0x00000000}, +	{0x0000b2f4, 0x00000000}, +	{0x0000b2f8, 0x00000000}, +	{0x0000b408, 0x0e79e5c0}, +	{0x0000b40c, 0x00820820}, +	{0x0000b420, 0x00000000}, +}; + +static const u32 qca953x_1p0_baseband_postamble[][5] = { +	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ +	{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, +	{0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e}, +	{0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, +	{0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, +	{0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, +	{0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, +	{0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4}, +	{0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0}, +	{0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020}, +	{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, +	{0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e}, +	{0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e}, +	{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, +	{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, +	{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, +	{0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10822, 0xcfa10822}, +	{0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, +	{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, +	{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, +	{0x0000a204, 0x005c0ec0, 0x005c0ec4, 0x005c0ec4, 0x005c0ec0}, +	{0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, +	{0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f}, +	{0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, +	{0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff}, +	{0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018}, +	{0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, +	{0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, +	{0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, +	{0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01010e0e, 0x01010e0e}, +	{0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, +	{0x0000a264, 0x00000e0e, 0x00000e0e, 0x01000e0e, 0x01000e0e}, +	{0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, +	{0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, +	{0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, +	{0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, +	{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, +	{0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33}, +	{0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982}, +	{0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, +	{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, +	{0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000}, +	{0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, +	{0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, +	{0x0000b284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, +}; + +static const u32 qca953x_1p0_radio_core[][2] = { +	/* Addr      allmodes  */ +	{0x00016000, 0x36db6db6}, +	{0x00016004, 0x6db6db40}, +	{0x00016008, 0x73f00000}, +	{0x0001600c, 0x00000000}, +	{0x00016040, 0x3f80fff8}, +	{0x0001604c, 0x000f0278}, +	{0x00016050, 0x8036db6c}, +	{0x00016054, 0x6db60000}, +	{0x00016080, 0x00080000}, +	{0x00016084, 0x0e48048c}, +	{0x00016088, 0x14214514}, +	{0x0001608c, 0x119f080a}, +	{0x00016090, 0x24926490}, +	{0x00016094, 0x00000000}, +	{0x000160a0, 0xc2108ffe}, +	{0x000160a4, 0x812fc370}, +	{0x000160a8, 0x423c8000}, +	{0x000160b4, 0x92480080}, +	{0x000160c0, 0x006db6d8}, +	{0x000160c4, 0x24b6db6c}, +	{0x000160c8, 0x6db6db6c}, +	{0x000160cc, 0x6db6fb7c}, +	{0x000160d0, 0x6db6da44}, +	{0x00016100, 0x07ff8001}, +	{0x00016108, 0x00080010}, +	{0x00016144, 0x01884080}, +	{0x00016148, 0x000080d8}, +	{0x00016280, 0x01000901}, +	{0x00016284, 0x15d30000}, +	{0x00016288, 0x00318000}, +	{0x0001628c, 0x50000000}, +	{0x00016380, 0x00000000}, +	{0x00016384, 0x00000000}, +	{0x00016388, 0x00800700}, +	{0x0001638c, 0x00800700}, +	{0x00016390, 0x00800700}, +	{0x00016394, 0x00000000}, +	{0x00016398, 0x00000000}, +	{0x0001639c, 0x00000000}, +	{0x000163a0, 0x00000001}, +	{0x000163a4, 0x00000001}, +	{0x000163a8, 0x00000000}, +	{0x000163ac, 0x00000000}, +	{0x000163b0, 0x00000000}, +	{0x000163b4, 0x00000000}, +	{0x000163b8, 0x00000000}, +	{0x000163bc, 0x00000000}, +	{0x000163c0, 0x000000a0}, +	{0x000163c4, 0x000c0000}, +	{0x000163c8, 0x14021402}, +	{0x000163cc, 0x00001402}, +	{0x000163d0, 0x00000000}, +	{0x000163d4, 0x00000000}, +	{0x00016400, 0x36db6db6}, +	{0x00016404, 0x6db6db40}, +	{0x00016408, 0x73f00000}, +	{0x0001640c, 0x00000000}, +	{0x00016440, 0x3f80fff8}, +	{0x0001644c, 0x000f0278}, +	{0x00016450, 0x8036db6c}, +	{0x00016454, 0x6db60000}, +	{0x00016500, 0x07ff8001}, +	{0x00016508, 0x00080010}, +	{0x00016544, 0x01884080}, +	{0x00016548, 0x000080d8}, +	{0x00016780, 0x00000000}, +	{0x00016784, 0x00000000}, +	{0x00016788, 0x00800700}, +	{0x0001678c, 0x00800700}, +	{0x00016790, 0x00800700}, +	{0x00016794, 0x00000000}, +	{0x00016798, 0x00000000}, +	{0x0001679c, 0x00000000}, +	{0x000167a0, 0x00000001}, +	{0x000167a4, 0x00000001}, +	{0x000167a8, 0x00000000}, +	{0x000167ac, 0x00000000}, +	{0x000167b0, 0x00000000}, +	{0x000167b4, 0x00000000}, +	{0x000167b8, 0x00000000}, +	{0x000167bc, 0x00000000}, +	{0x000167c0, 0x000000a0}, +	{0x000167c4, 0x000c0000}, +	{0x000167c8, 0x14021402}, +	{0x000167cc, 0x00001402}, +	{0x000167d0, 0x00000000}, +	{0x000167d4, 0x00000000}, +}; + +static const u32 qca953x_1p0_radio_postamble[][5] = { +	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ +	{0x00016098, 0xd2dd5554, 0xd2dd5554, 0xc4128f5c, 0xc4128f5c}, +	{0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x0fd08f25, 0x0fd08f25}, +	{0x000160ac, 0xa4647c00, 0xa4647c00, 0x24646800, 0x24646800}, +	{0x000160b0, 0x01885f52, 0x01885f52, 0x00fe7f46, 0x00fe7f46}, +	{0x00016104, 0xb7a00001, 0xb7a00001, 0xfff80005, 0xfff80005}, +	{0x0001610c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000}, +	{0x00016140, 0x10804008, 0x10804008, 0x50804000, 0x50804000}, +	{0x00016504, 0xb7a00001, 0xb7a00001, 0xfff80001, 0xfff80001}, +	{0x0001650c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000}, +	{0x00016540, 0x10804008, 0x10804008, 0x50804000, 0x50804000}, +}; + +static const u32 qca953x_1p0_soc_preamble[][2] = { +	/* Addr      allmodes  */ +	{0x00007000, 0x00000000}, +	{0x00007004, 0x00000000}, +	{0x00007008, 0x00000000}, +	{0x0000700c, 0x00000000}, +	{0x0000701c, 0x00000000}, +	{0x00007020, 0x00000000}, +	{0x00007024, 0x00000000}, +	{0x00007028, 0x00000000}, +	{0x0000702c, 0x00000000}, +	{0x00007030, 0x00000000}, +	{0x00007034, 0x00000002}, +	{0x00007038, 0x000004c2}, +	{0x00007048, 0x00000000}, +}; + +static const u32 qca953x_1p0_common_rx_gain_bounds[][5] = { +	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ +	{0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, +	{0x00009e48, 0x5030201a, 0x5030201a, 0x50302018, 0x50302018}, +}; + +static const u32 qca953x_1p0_common_wo_xlna_rx_gain_bounds[][5] = { +	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ +	{0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, +	{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, +}; + +static const u32 qca953x_1p0_modes_xpa_tx_gain_table[][2] = { +	/* Addr      allmodes  */ +	{0x0000a2dc, 0xfffd5aaa}, +	{0x0000a2e0, 0xfffe9ccc}, +	{0x0000a2e4, 0xffffe0f0}, +	{0x0000a2e8, 0xfffcff00}, +	{0x0000a410, 0x000050da}, +	{0x0000a500, 0x00000000}, +	{0x0000a504, 0x04000002}, +	{0x0000a508, 0x08000004}, +	{0x0000a50c, 0x0c000006}, +	{0x0000a510, 0x0f00000a}, +	{0x0000a514, 0x1300000c}, +	{0x0000a518, 0x1700000e}, +	{0x0000a51c, 0x1b000064}, +	{0x0000a520, 0x1f000242}, +	{0x0000a524, 0x23000229}, +	{0x0000a528, 0x270002a2}, +	{0x0000a52c, 0x2c001203}, +	{0x0000a530, 0x30001803}, +	{0x0000a534, 0x33000881}, +	{0x0000a538, 0x38001809}, +	{0x0000a53c, 0x3a000814}, +	{0x0000a540, 0x3f001a0c}, +	{0x0000a544, 0x43001a0e}, +	{0x0000a548, 0x46001812}, +	{0x0000a54c, 0x49001884}, +	{0x0000a550, 0x4d001e84}, +	{0x0000a554, 0x50001e69}, +	{0x0000a558, 0x550006f4}, +	{0x0000a55c, 0x59000ad3}, +	{0x0000a560, 0x5e000ad5}, +	{0x0000a564, 0x61001ced}, +	{0x0000a568, 0x660018d4}, +	{0x0000a56c, 0x660018d4}, +	{0x0000a570, 0x660018d4}, +	{0x0000a574, 0x660018d4}, +	{0x0000a578, 0x660018d4}, +	{0x0000a57c, 0x660018d4}, +	{0x0000a600, 0x00000000}, +	{0x0000a604, 0x00000000}, +	{0x0000a608, 0x00000000}, +	{0x0000a60c, 0x03804000}, +	{0x0000a610, 0x0300ca02}, +	{0x0000a614, 0x00000e04}, +	{0x0000a618, 0x03014000}, +	{0x0000a61c, 0x00000000}, +	{0x0000a620, 0x00000000}, +	{0x0000a624, 0x03014000}, +	{0x0000a628, 0x03804c05}, +	{0x0000a62c, 0x0701de06}, +	{0x0000a630, 0x07819c07}, +	{0x0000a634, 0x0701dc07}, +	{0x0000a638, 0x0701dc07}, +	{0x0000a63c, 0x0701dc07}, +	{0x0000b2dc, 0xfffd5aaa}, +	{0x0000b2e0, 0xfffe9ccc}, +	{0x0000b2e4, 0xffffe0f0}, +	{0x0000b2e8, 0xfffcff00}, +	{0x00016044, 0x010002d4}, +	{0x00016048, 0x66482400}, +	{0x00016280, 0x01000015}, +	{0x00016444, 0x010002d4}, +	{0x00016448, 0x66482400}, +}; + +static const u32 qca953x_1p0_modes_no_xpa_tx_gain_table[][2] = { +	/* Addr      allmodes  */ +	{0x0000a2dc, 0xffd5f552}, +	{0x0000a2e0, 0xffe60664}, +	{0x0000a2e4, 0xfff80780}, +	{0x0000a2e8, 0xfffff800}, +	{0x0000a410, 0x000050d6}, +	{0x0000a500, 0x00060020}, +	{0x0000a504, 0x04060060}, +	{0x0000a508, 0x080600a0}, +	{0x0000a50c, 0x0c068020}, +	{0x0000a510, 0x10068060}, +	{0x0000a514, 0x140680a0}, +	{0x0000a518, 0x18090040}, +	{0x0000a51c, 0x1b090080}, +	{0x0000a520, 0x1f0900c0}, +	{0x0000a524, 0x240c0041}, +	{0x0000a528, 0x280d0021}, +	{0x0000a52c, 0x2d0f0061}, +	{0x0000a530, 0x310f00a1}, +	{0x0000a534, 0x350e00a2}, +	{0x0000a538, 0x360e80a2}, +	{0x0000a53c, 0x380f00a2}, +	{0x0000a540, 0x3b0e00a3}, +	{0x0000a544, 0x3d110083}, +	{0x0000a548, 0x3e1100a3}, +	{0x0000a54c, 0x401100e3}, +	{0x0000a550, 0x421380e3}, +	{0x0000a554, 0x431780e3}, +	{0x0000a558, 0x461f80e3}, +	{0x0000a55c, 0x461f80e3}, +	{0x0000a560, 0x461f80e3}, +	{0x0000a564, 0x461f80e3}, +	{0x0000a568, 0x461f80e3}, +	{0x0000a56c, 0x461f80e3}, +	{0x0000a570, 0x461f80e3}, +	{0x0000a574, 0x461f80e3}, +	{0x0000a578, 0x461f80e3}, +	{0x0000a57c, 0x461f80e3}, +	{0x0000a600, 0x00000000}, +	{0x0000a604, 0x00000000}, +	{0x0000a608, 0x00000000}, +	{0x0000a60c, 0x00804201}, +	{0x0000a610, 0x01008201}, +	{0x0000a614, 0x0180c402}, +	{0x0000a618, 0x0180c603}, +	{0x0000a61c, 0x0180c603}, +	{0x0000a620, 0x01c10603}, +	{0x0000a624, 0x01c10704}, +	{0x0000a628, 0x02c18b05}, +	{0x0000a62c, 0x0301cc07}, +	{0x0000a630, 0x0301cc07}, +	{0x0000a634, 0x0301cc07}, +	{0x0000a638, 0x0301cc07}, +	{0x0000a63c, 0x0301cc07}, +	{0x0000b2dc, 0xffd5f552}, +	{0x0000b2e0, 0xffe60664}, +	{0x0000b2e4, 0xfff80780}, +	{0x0000b2e8, 0xfffff800}, +	{0x00016044, 0x049242db}, +	{0x00016048, 0x6c927a70}, +	{0x00016444, 0x049242db}, +	{0x00016448, 0x6c927a70}, +}; + +static const u32 qca953x_1p1_modes_no_xpa_tx_gain_table[][2] = { +	/* Addr      allmodes  */ +	{0x0000a2dc, 0xffd5f552}, +	{0x0000a2e0, 0xffe60664}, +	{0x0000a2e4, 0xfff80780}, +	{0x0000a2e8, 0xfffff800}, +	{0x0000a410, 0x000050de}, +	{0x0000a500, 0x00000061}, +	{0x0000a504, 0x04000063}, +	{0x0000a508, 0x08000065}, +	{0x0000a50c, 0x0c000261}, +	{0x0000a510, 0x10000263}, +	{0x0000a514, 0x14000265}, +	{0x0000a518, 0x18000482}, +	{0x0000a51c, 0x1b000484}, +	{0x0000a520, 0x1f000486}, +	{0x0000a524, 0x240008c2}, +	{0x0000a528, 0x28000cc1}, +	{0x0000a52c, 0x2d000ce3}, +	{0x0000a530, 0x31000ce5}, +	{0x0000a534, 0x350010e5}, +	{0x0000a538, 0x360012e5}, +	{0x0000a53c, 0x380014e5}, +	{0x0000a540, 0x3b0018e5}, +	{0x0000a544, 0x3d001d04}, +	{0x0000a548, 0x3e001d05}, +	{0x0000a54c, 0x40001d07}, +	{0x0000a550, 0x42001f27}, +	{0x0000a554, 0x43001f67}, +	{0x0000a558, 0x46001fe7}, +	{0x0000a55c, 0x47001f2b}, +	{0x0000a560, 0x49001f0d}, +	{0x0000a564, 0x4b001ed2}, +	{0x0000a568, 0x4c001ed4}, +	{0x0000a56c, 0x4e001f15}, +	{0x0000a570, 0x4f001ff6}, +	{0x0000a574, 0x4f001ff6}, +	{0x0000a578, 0x4f001ff6}, +	{0x0000a57c, 0x4f001ff6}, +	{0x0000a600, 0x00000000}, +	{0x0000a604, 0x00000000}, +	{0x0000a608, 0x00000000}, +	{0x0000a60c, 0x00804201}, +	{0x0000a610, 0x01008201}, +	{0x0000a614, 0x0180c402}, +	{0x0000a618, 0x0180c603}, +	{0x0000a61c, 0x0180c603}, +	{0x0000a620, 0x01c10603}, +	{0x0000a624, 0x01c10704}, +	{0x0000a628, 0x02c18b05}, +	{0x0000a62c, 0x02c14c07}, +	{0x0000a630, 0x01008704}, +	{0x0000a634, 0x01c10402}, +	{0x0000a638, 0x0301cc07}, +	{0x0000a63c, 0x0301cc07}, +	{0x0000b2dc, 0xffd5f552}, +	{0x0000b2e0, 0xffe60664}, +	{0x0000b2e4, 0xfff80780}, +	{0x0000b2e8, 0xfffff800}, +	{0x00016044, 0x049242db}, +	{0x00016048, 0x6c927a70}, +	{0x00016444, 0x049242db}, +	{0x00016448, 0x6c927a70}, +}; + +#endif /* INITVALS_953X_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h index ccc5b6c99ad..74d8bc05b31 100644 --- a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h @@ -20,6 +20,14 @@  /* AR955X 1.0 */ +#define ar955x_1p0_soc_postamble ar9300_2p2_soc_postamble + +#define ar955x_1p0_common_rx_gain_table ar9300Common_rx_gain_table_2p2 + +#define ar955x_1p0_common_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2 + +#define ar955x_1p0_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484 +  static const u32 ar955x_1p0_radio_postamble[][5] = {  	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */  	{0x00016098, 0xd2dd5554, 0xd2dd5554, 0xd28b3330, 0xd28b3330}, @@ -37,13 +45,6 @@ static const u32 ar955x_1p0_radio_postamble[][5] = {  	{0x00016940, 0x10804008, 0x10804008, 0x10804008, 0x10804008},  }; -static const u32 ar955x_1p0_baseband_core_txfir_coeff_japan_2484[][2] = { -	/* Addr      allmodes  */ -	{0x0000a398, 0x00000000}, -	{0x0000a39c, 0x6f7f0301}, -	{0x0000a3a0, 0xca9228ee}, -}; -  static const u32 ar955x_1p0_baseband_postamble[][5] = {  	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */  	{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, @@ -473,266 +474,6 @@ static const u32 ar955x_1p0_mac_core[][2] = {  	{0x000083d0, 0x8c7901ff},  }; -static const u32 ar955x_1p0_common_rx_gain_table[][2] = { -	/* Addr      allmodes  */ -	{0x0000a000, 0x00010000}, -	{0x0000a004, 0x00030002}, -	{0x0000a008, 0x00050004}, -	{0x0000a00c, 0x00810080}, -	{0x0000a010, 0x00830082}, -	{0x0000a014, 0x01810180}, -	{0x0000a018, 0x01830182}, -	{0x0000a01c, 0x01850184}, -	{0x0000a020, 0x01890188}, -	{0x0000a024, 0x018b018a}, -	{0x0000a028, 0x018d018c}, -	{0x0000a02c, 0x01910190}, -	{0x0000a030, 0x01930192}, -	{0x0000a034, 0x01950194}, -	{0x0000a038, 0x038a0196}, -	{0x0000a03c, 0x038c038b}, -	{0x0000a040, 0x0390038d}, -	{0x0000a044, 0x03920391}, -	{0x0000a048, 0x03940393}, -	{0x0000a04c, 0x03960395}, -	{0x0000a050, 0x00000000}, -	{0x0000a054, 0x00000000}, -	{0x0000a058, 0x00000000}, -	{0x0000a05c, 0x00000000}, -	{0x0000a060, 0x00000000}, -	{0x0000a064, 0x00000000}, -	{0x0000a068, 0x00000000}, -	{0x0000a06c, 0x00000000}, -	{0x0000a070, 0x00000000}, -	{0x0000a074, 0x00000000}, -	{0x0000a078, 0x00000000}, -	{0x0000a07c, 0x00000000}, -	{0x0000a080, 0x22222229}, -	{0x0000a084, 0x1d1d1d1d}, -	{0x0000a088, 0x1d1d1d1d}, -	{0x0000a08c, 0x1d1d1d1d}, -	{0x0000a090, 0x171d1d1d}, -	{0x0000a094, 0x11111717}, -	{0x0000a098, 0x00030311}, -	{0x0000a09c, 0x00000000}, -	{0x0000a0a0, 0x00000000}, -	{0x0000a0a4, 0x00000000}, -	{0x0000a0a8, 0x00000000}, -	{0x0000a0ac, 0x00000000}, -	{0x0000a0b0, 0x00000000}, -	{0x0000a0b4, 0x00000000}, -	{0x0000a0b8, 0x00000000}, -	{0x0000a0bc, 0x00000000}, -	{0x0000a0c0, 0x001f0000}, -	{0x0000a0c4, 0x01000101}, -	{0x0000a0c8, 0x011e011f}, -	{0x0000a0cc, 0x011c011d}, -	{0x0000a0d0, 0x02030204}, -	{0x0000a0d4, 0x02010202}, -	{0x0000a0d8, 0x021f0200}, -	{0x0000a0dc, 0x0302021e}, -	{0x0000a0e0, 0x03000301}, -	{0x0000a0e4, 0x031e031f}, -	{0x0000a0e8, 0x0402031d}, -	{0x0000a0ec, 0x04000401}, -	{0x0000a0f0, 0x041e041f}, -	{0x0000a0f4, 0x0502041d}, -	{0x0000a0f8, 0x05000501}, -	{0x0000a0fc, 0x051e051f}, -	{0x0000a100, 0x06010602}, -	{0x0000a104, 0x061f0600}, -	{0x0000a108, 0x061d061e}, -	{0x0000a10c, 0x07020703}, -	{0x0000a110, 0x07000701}, -	{0x0000a114, 0x00000000}, -	{0x0000a118, 0x00000000}, -	{0x0000a11c, 0x00000000}, -	{0x0000a120, 0x00000000}, -	{0x0000a124, 0x00000000}, -	{0x0000a128, 0x00000000}, -	{0x0000a12c, 0x00000000}, -	{0x0000a130, 0x00000000}, -	{0x0000a134, 0x00000000}, -	{0x0000a138, 0x00000000}, -	{0x0000a13c, 0x00000000}, -	{0x0000a140, 0x001f0000}, -	{0x0000a144, 0x01000101}, -	{0x0000a148, 0x011e011f}, -	{0x0000a14c, 0x011c011d}, -	{0x0000a150, 0x02030204}, -	{0x0000a154, 0x02010202}, -	{0x0000a158, 0x021f0200}, -	{0x0000a15c, 0x0302021e}, -	{0x0000a160, 0x03000301}, -	{0x0000a164, 0x031e031f}, -	{0x0000a168, 0x0402031d}, -	{0x0000a16c, 0x04000401}, -	{0x0000a170, 0x041e041f}, -	{0x0000a174, 0x0502041d}, -	{0x0000a178, 0x05000501}, -	{0x0000a17c, 0x051e051f}, -	{0x0000a180, 0x06010602}, -	{0x0000a184, 0x061f0600}, -	{0x0000a188, 0x061d061e}, -	{0x0000a18c, 0x07020703}, -	{0x0000a190, 0x07000701}, -	{0x0000a194, 0x00000000}, -	{0x0000a198, 0x00000000}, -	{0x0000a19c, 0x00000000}, -	{0x0000a1a0, 0x00000000}, -	{0x0000a1a4, 0x00000000}, -	{0x0000a1a8, 0x00000000}, -	{0x0000a1ac, 0x00000000}, -	{0x0000a1b0, 0x00000000}, -	{0x0000a1b4, 0x00000000}, -	{0x0000a1b8, 0x00000000}, -	{0x0000a1bc, 0x00000000}, -	{0x0000a1c0, 0x00000000}, -	{0x0000a1c4, 0x00000000}, -	{0x0000a1c8, 0x00000000}, -	{0x0000a1cc, 0x00000000}, -	{0x0000a1d0, 0x00000000}, -	{0x0000a1d4, 0x00000000}, -	{0x0000a1d8, 0x00000000}, -	{0x0000a1dc, 0x00000000}, -	{0x0000a1e0, 0x00000000}, -	{0x0000a1e4, 0x00000000}, -	{0x0000a1e8, 0x00000000}, -	{0x0000a1ec, 0x00000000}, -	{0x0000a1f0, 0x00000396}, -	{0x0000a1f4, 0x00000396}, -	{0x0000a1f8, 0x00000396}, -	{0x0000a1fc, 0x00000196}, -	{0x0000b000, 0x00010000}, -	{0x0000b004, 0x00030002}, -	{0x0000b008, 0x00050004}, -	{0x0000b00c, 0x00810080}, -	{0x0000b010, 0x00830082}, -	{0x0000b014, 0x01810180}, -	{0x0000b018, 0x01830182}, -	{0x0000b01c, 0x01850184}, -	{0x0000b020, 0x02810280}, -	{0x0000b024, 0x02830282}, -	{0x0000b028, 0x02850284}, -	{0x0000b02c, 0x02890288}, -	{0x0000b030, 0x028b028a}, -	{0x0000b034, 0x0388028c}, -	{0x0000b038, 0x038a0389}, -	{0x0000b03c, 0x038c038b}, -	{0x0000b040, 0x0390038d}, -	{0x0000b044, 0x03920391}, -	{0x0000b048, 0x03940393}, -	{0x0000b04c, 0x03960395}, -	{0x0000b050, 0x00000000}, -	{0x0000b054, 0x00000000}, -	{0x0000b058, 0x00000000}, -	{0x0000b05c, 0x00000000}, -	{0x0000b060, 0x00000000}, -	{0x0000b064, 0x00000000}, -	{0x0000b068, 0x00000000}, -	{0x0000b06c, 0x00000000}, -	{0x0000b070, 0x00000000}, -	{0x0000b074, 0x00000000}, -	{0x0000b078, 0x00000000}, -	{0x0000b07c, 0x00000000}, -	{0x0000b080, 0x23232323}, -	{0x0000b084, 0x21232323}, -	{0x0000b088, 0x19191c1e}, -	{0x0000b08c, 0x12141417}, -	{0x0000b090, 0x07070e0e}, -	{0x0000b094, 0x03030305}, -	{0x0000b098, 0x00000003}, -	{0x0000b09c, 0x00000000}, -	{0x0000b0a0, 0x00000000}, -	{0x0000b0a4, 0x00000000}, -	{0x0000b0a8, 0x00000000}, -	{0x0000b0ac, 0x00000000}, -	{0x0000b0b0, 0x00000000}, -	{0x0000b0b4, 0x00000000}, -	{0x0000b0b8, 0x00000000}, -	{0x0000b0bc, 0x00000000}, -	{0x0000b0c0, 0x003f0020}, -	{0x0000b0c4, 0x00400041}, -	{0x0000b0c8, 0x0140005f}, -	{0x0000b0cc, 0x0160015f}, -	{0x0000b0d0, 0x017e017f}, -	{0x0000b0d4, 0x02410242}, -	{0x0000b0d8, 0x025f0240}, -	{0x0000b0dc, 0x027f0260}, -	{0x0000b0e0, 0x0341027e}, -	{0x0000b0e4, 0x035f0340}, -	{0x0000b0e8, 0x037f0360}, -	{0x0000b0ec, 0x04400441}, -	{0x0000b0f0, 0x0460045f}, -	{0x0000b0f4, 0x0541047f}, -	{0x0000b0f8, 0x055f0540}, -	{0x0000b0fc, 0x057f0560}, -	{0x0000b100, 0x06400641}, -	{0x0000b104, 0x0660065f}, -	{0x0000b108, 0x067e067f}, -	{0x0000b10c, 0x07410742}, -	{0x0000b110, 0x075f0740}, -	{0x0000b114, 0x077f0760}, -	{0x0000b118, 0x07800781}, -	{0x0000b11c, 0x07a0079f}, -	{0x0000b120, 0x07c107bf}, -	{0x0000b124, 0x000007c0}, -	{0x0000b128, 0x00000000}, -	{0x0000b12c, 0x00000000}, -	{0x0000b130, 0x00000000}, -	{0x0000b134, 0x00000000}, -	{0x0000b138, 0x00000000}, -	{0x0000b13c, 0x00000000}, -	{0x0000b140, 0x003f0020}, -	{0x0000b144, 0x00400041}, -	{0x0000b148, 0x0140005f}, -	{0x0000b14c, 0x0160015f}, -	{0x0000b150, 0x017e017f}, -	{0x0000b154, 0x02410242}, -	{0x0000b158, 0x025f0240}, -	{0x0000b15c, 0x027f0260}, -	{0x0000b160, 0x0341027e}, -	{0x0000b164, 0x035f0340}, -	{0x0000b168, 0x037f0360}, -	{0x0000b16c, 0x04400441}, -	{0x0000b170, 0x0460045f}, -	{0x0000b174, 0x0541047f}, -	{0x0000b178, 0x055f0540}, -	{0x0000b17c, 0x057f0560}, -	{0x0000b180, 0x06400641}, -	{0x0000b184, 0x0660065f}, -	{0x0000b188, 0x067e067f}, -	{0x0000b18c, 0x07410742}, -	{0x0000b190, 0x075f0740}, -	{0x0000b194, 0x077f0760}, -	{0x0000b198, 0x07800781}, -	{0x0000b19c, 0x07a0079f}, -	{0x0000b1a0, 0x07c107bf}, -	{0x0000b1a4, 0x000007c0}, -	{0x0000b1a8, 0x00000000}, -	{0x0000b1ac, 0x00000000}, -	{0x0000b1b0, 0x00000000}, -	{0x0000b1b4, 0x00000000}, -	{0x0000b1b8, 0x00000000}, -	{0x0000b1bc, 0x00000000}, -	{0x0000b1c0, 0x00000000}, -	{0x0000b1c4, 0x00000000}, -	{0x0000b1c8, 0x00000000}, -	{0x0000b1cc, 0x00000000}, -	{0x0000b1d0, 0x00000000}, -	{0x0000b1d4, 0x00000000}, -	{0x0000b1d8, 0x00000000}, -	{0x0000b1dc, 0x00000000}, -	{0x0000b1e0, 0x00000000}, -	{0x0000b1e4, 0x00000000}, -	{0x0000b1e8, 0x00000000}, -	{0x0000b1ec, 0x00000000}, -	{0x0000b1f0, 0x00000396}, -	{0x0000b1f4, 0x00000396}, -	{0x0000b1f8, 0x00000396}, -	{0x0000b1fc, 0x00000196}, -}; -  static const u32 ar955x_1p0_baseband_core[][2] = {  	/* Addr      allmodes  */  	{0x00009800, 0xafe68e30}, @@ -891,266 +632,6 @@ static const u32 ar955x_1p0_baseband_core[][2] = {  	{0x0000c420, 0x00000000},  }; -static const u32 ar955x_1p0_common_wo_xlna_rx_gain_table[][2] = { -	/* Addr      allmodes  */ -	{0x0000a000, 0x00010000}, -	{0x0000a004, 0x00030002}, -	{0x0000a008, 0x00050004}, -	{0x0000a00c, 0x00810080}, -	{0x0000a010, 0x00830082}, -	{0x0000a014, 0x01810180}, -	{0x0000a018, 0x01830182}, -	{0x0000a01c, 0x01850184}, -	{0x0000a020, 0x01890188}, -	{0x0000a024, 0x018b018a}, -	{0x0000a028, 0x018d018c}, -	{0x0000a02c, 0x03820190}, -	{0x0000a030, 0x03840383}, -	{0x0000a034, 0x03880385}, -	{0x0000a038, 0x038a0389}, -	{0x0000a03c, 0x038c038b}, -	{0x0000a040, 0x0390038d}, -	{0x0000a044, 0x03920391}, -	{0x0000a048, 0x03940393}, -	{0x0000a04c, 0x03960395}, -	{0x0000a050, 0x00000000}, -	{0x0000a054, 0x00000000}, -	{0x0000a058, 0x00000000}, -	{0x0000a05c, 0x00000000}, -	{0x0000a060, 0x00000000}, -	{0x0000a064, 0x00000000}, -	{0x0000a068, 0x00000000}, -	{0x0000a06c, 0x00000000}, -	{0x0000a070, 0x00000000}, -	{0x0000a074, 0x00000000}, -	{0x0000a078, 0x00000000}, -	{0x0000a07c, 0x00000000}, -	{0x0000a080, 0x29292929}, -	{0x0000a084, 0x29292929}, -	{0x0000a088, 0x29292929}, -	{0x0000a08c, 0x29292929}, -	{0x0000a090, 0x22292929}, -	{0x0000a094, 0x1d1d2222}, -	{0x0000a098, 0x0c111117}, -	{0x0000a09c, 0x00030303}, -	{0x0000a0a0, 0x00000000}, -	{0x0000a0a4, 0x00000000}, -	{0x0000a0a8, 0x00000000}, -	{0x0000a0ac, 0x00000000}, -	{0x0000a0b0, 0x00000000}, -	{0x0000a0b4, 0x00000000}, -	{0x0000a0b8, 0x00000000}, -	{0x0000a0bc, 0x00000000}, -	{0x0000a0c0, 0x001f0000}, -	{0x0000a0c4, 0x01000101}, -	{0x0000a0c8, 0x011e011f}, -	{0x0000a0cc, 0x011c011d}, -	{0x0000a0d0, 0x02030204}, -	{0x0000a0d4, 0x02010202}, -	{0x0000a0d8, 0x021f0200}, -	{0x0000a0dc, 0x0302021e}, -	{0x0000a0e0, 0x03000301}, -	{0x0000a0e4, 0x031e031f}, -	{0x0000a0e8, 0x0402031d}, -	{0x0000a0ec, 0x04000401}, -	{0x0000a0f0, 0x041e041f}, -	{0x0000a0f4, 0x0502041d}, -	{0x0000a0f8, 0x05000501}, -	{0x0000a0fc, 0x051e051f}, -	{0x0000a100, 0x06010602}, -	{0x0000a104, 0x061f0600}, -	{0x0000a108, 0x061d061e}, -	{0x0000a10c, 0x07020703}, -	{0x0000a110, 0x07000701}, -	{0x0000a114, 0x00000000}, -	{0x0000a118, 0x00000000}, -	{0x0000a11c, 0x00000000}, -	{0x0000a120, 0x00000000}, -	{0x0000a124, 0x00000000}, -	{0x0000a128, 0x00000000}, -	{0x0000a12c, 0x00000000}, -	{0x0000a130, 0x00000000}, -	{0x0000a134, 0x00000000}, -	{0x0000a138, 0x00000000}, -	{0x0000a13c, 0x00000000}, -	{0x0000a140, 0x001f0000}, -	{0x0000a144, 0x01000101}, -	{0x0000a148, 0x011e011f}, -	{0x0000a14c, 0x011c011d}, -	{0x0000a150, 0x02030204}, -	{0x0000a154, 0x02010202}, -	{0x0000a158, 0x021f0200}, -	{0x0000a15c, 0x0302021e}, -	{0x0000a160, 0x03000301}, -	{0x0000a164, 0x031e031f}, -	{0x0000a168, 0x0402031d}, -	{0x0000a16c, 0x04000401}, -	{0x0000a170, 0x041e041f}, -	{0x0000a174, 0x0502041d}, -	{0x0000a178, 0x05000501}, -	{0x0000a17c, 0x051e051f}, -	{0x0000a180, 0x06010602}, -	{0x0000a184, 0x061f0600}, -	{0x0000a188, 0x061d061e}, -	{0x0000a18c, 0x07020703}, -	{0x0000a190, 0x07000701}, -	{0x0000a194, 0x00000000}, -	{0x0000a198, 0x00000000}, -	{0x0000a19c, 0x00000000}, -	{0x0000a1a0, 0x00000000}, -	{0x0000a1a4, 0x00000000}, -	{0x0000a1a8, 0x00000000}, -	{0x0000a1ac, 0x00000000}, -	{0x0000a1b0, 0x00000000}, -	{0x0000a1b4, 0x00000000}, -	{0x0000a1b8, 0x00000000}, -	{0x0000a1bc, 0x00000000}, -	{0x0000a1c0, 0x00000000}, -	{0x0000a1c4, 0x00000000}, -	{0x0000a1c8, 0x00000000}, -	{0x0000a1cc, 0x00000000}, -	{0x0000a1d0, 0x00000000}, -	{0x0000a1d4, 0x00000000}, -	{0x0000a1d8, 0x00000000}, -	{0x0000a1dc, 0x00000000}, -	{0x0000a1e0, 0x00000000}, -	{0x0000a1e4, 0x00000000}, -	{0x0000a1e8, 0x00000000}, -	{0x0000a1ec, 0x00000000}, -	{0x0000a1f0, 0x00000396}, -	{0x0000a1f4, 0x00000396}, -	{0x0000a1f8, 0x00000396}, -	{0x0000a1fc, 0x00000196}, -	{0x0000b000, 0x00010000}, -	{0x0000b004, 0x00030002}, -	{0x0000b008, 0x00050004}, -	{0x0000b00c, 0x00810080}, -	{0x0000b010, 0x00830082}, -	{0x0000b014, 0x01810180}, -	{0x0000b018, 0x01830182}, -	{0x0000b01c, 0x01850184}, -	{0x0000b020, 0x02810280}, -	{0x0000b024, 0x02830282}, -	{0x0000b028, 0x02850284}, -	{0x0000b02c, 0x02890288}, -	{0x0000b030, 0x028b028a}, -	{0x0000b034, 0x0388028c}, -	{0x0000b038, 0x038a0389}, -	{0x0000b03c, 0x038c038b}, -	{0x0000b040, 0x0390038d}, -	{0x0000b044, 0x03920391}, -	{0x0000b048, 0x03940393}, -	{0x0000b04c, 0x03960395}, -	{0x0000b050, 0x00000000}, -	{0x0000b054, 0x00000000}, -	{0x0000b058, 0x00000000}, -	{0x0000b05c, 0x00000000}, -	{0x0000b060, 0x00000000}, -	{0x0000b064, 0x00000000}, -	{0x0000b068, 0x00000000}, -	{0x0000b06c, 0x00000000}, -	{0x0000b070, 0x00000000}, -	{0x0000b074, 0x00000000}, -	{0x0000b078, 0x00000000}, -	{0x0000b07c, 0x00000000}, -	{0x0000b080, 0x32323232}, -	{0x0000b084, 0x2f2f3232}, -	{0x0000b088, 0x23282a2d}, -	{0x0000b08c, 0x1c1e2123}, -	{0x0000b090, 0x14171919}, -	{0x0000b094, 0x0e0e1214}, -	{0x0000b098, 0x03050707}, -	{0x0000b09c, 0x00030303}, -	{0x0000b0a0, 0x00000000}, -	{0x0000b0a4, 0x00000000}, -	{0x0000b0a8, 0x00000000}, -	{0x0000b0ac, 0x00000000}, -	{0x0000b0b0, 0x00000000}, -	{0x0000b0b4, 0x00000000}, -	{0x0000b0b8, 0x00000000}, -	{0x0000b0bc, 0x00000000}, -	{0x0000b0c0, 0x003f0020}, -	{0x0000b0c4, 0x00400041}, -	{0x0000b0c8, 0x0140005f}, -	{0x0000b0cc, 0x0160015f}, -	{0x0000b0d0, 0x017e017f}, -	{0x0000b0d4, 0x02410242}, -	{0x0000b0d8, 0x025f0240}, -	{0x0000b0dc, 0x027f0260}, -	{0x0000b0e0, 0x0341027e}, -	{0x0000b0e4, 0x035f0340}, -	{0x0000b0e8, 0x037f0360}, -	{0x0000b0ec, 0x04400441}, -	{0x0000b0f0, 0x0460045f}, -	{0x0000b0f4, 0x0541047f}, -	{0x0000b0f8, 0x055f0540}, -	{0x0000b0fc, 0x057f0560}, -	{0x0000b100, 0x06400641}, -	{0x0000b104, 0x0660065f}, -	{0x0000b108, 0x067e067f}, -	{0x0000b10c, 0x07410742}, -	{0x0000b110, 0x075f0740}, -	{0x0000b114, 0x077f0760}, -	{0x0000b118, 0x07800781}, -	{0x0000b11c, 0x07a0079f}, -	{0x0000b120, 0x07c107bf}, -	{0x0000b124, 0x000007c0}, -	{0x0000b128, 0x00000000}, -	{0x0000b12c, 0x00000000}, -	{0x0000b130, 0x00000000}, -	{0x0000b134, 0x00000000}, -	{0x0000b138, 0x00000000}, -	{0x0000b13c, 0x00000000}, -	{0x0000b140, 0x003f0020}, -	{0x0000b144, 0x00400041}, -	{0x0000b148, 0x0140005f}, -	{0x0000b14c, 0x0160015f}, -	{0x0000b150, 0x017e017f}, -	{0x0000b154, 0x02410242}, -	{0x0000b158, 0x025f0240}, -	{0x0000b15c, 0x027f0260}, -	{0x0000b160, 0x0341027e}, -	{0x0000b164, 0x035f0340}, -	{0x0000b168, 0x037f0360}, -	{0x0000b16c, 0x04400441}, -	{0x0000b170, 0x0460045f}, -	{0x0000b174, 0x0541047f}, -	{0x0000b178, 0x055f0540}, -	{0x0000b17c, 0x057f0560}, -	{0x0000b180, 0x06400641}, -	{0x0000b184, 0x0660065f}, -	{0x0000b188, 0x067e067f}, -	{0x0000b18c, 0x07410742}, -	{0x0000b190, 0x075f0740}, -	{0x0000b194, 0x077f0760}, -	{0x0000b198, 0x07800781}, -	{0x0000b19c, 0x07a0079f}, -	{0x0000b1a0, 0x07c107bf}, -	{0x0000b1a4, 0x000007c0}, -	{0x0000b1a8, 0x00000000}, -	{0x0000b1ac, 0x00000000}, -	{0x0000b1b0, 0x00000000}, -	{0x0000b1b4, 0x00000000}, -	{0x0000b1b8, 0x00000000}, -	{0x0000b1bc, 0x00000000}, -	{0x0000b1c0, 0x00000000}, -	{0x0000b1c4, 0x00000000}, -	{0x0000b1c8, 0x00000000}, -	{0x0000b1cc, 0x00000000}, -	{0x0000b1d0, 0x00000000}, -	{0x0000b1d4, 0x00000000}, -	{0x0000b1d8, 0x00000000}, -	{0x0000b1dc, 0x00000000}, -	{0x0000b1e0, 0x00000000}, -	{0x0000b1e4, 0x00000000}, -	{0x0000b1e8, 0x00000000}, -	{0x0000b1ec, 0x00000000}, -	{0x0000b1f0, 0x00000396}, -	{0x0000b1f4, 0x00000396}, -	{0x0000b1f8, 0x00000396}, -	{0x0000b1fc, 0x00000196}, -}; -  static const u32 ar955x_1p0_soc_preamble[][2] = {  	/* Addr      allmodes  */  	{0x00007000, 0x00000000}, @@ -1263,11 +744,6 @@ static const u32 ar955x_1p0_modes_no_xpa_tx_gain_table[][9] = {  	{0x00016848, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401},  }; -static const u32 ar955x_1p0_soc_postamble[][5] = { -	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ -	{0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023}, -}; -  static const u32 ar955x_1p0_modes_fast_clock[][3] = {  	/* Addr      5G_HT20     5G_HT40   */  	{0x00001030, 0x00000268, 0x000004d0}, diff --git a/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h index e85a8b076c2..10d4a6cb1c3 100644 --- a/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h @@ -20,6 +20,12 @@  /* AR9565 1.0 */ +#define ar9565_1p0_mac_postamble ar9331_1p1_mac_postamble + +#define ar9565_1p0_Modes_lowest_ob_db_tx_gain_table ar9565_1p0_modes_low_ob_db_tx_gain_table + +#define ar9565_1p0_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484 +  static const u32 ar9565_1p0_mac_core[][2] = {  	/* Addr      allmodes  */  	{0x00000008, 0x00000000}, @@ -182,18 +188,6 @@ static const u32 ar9565_1p0_mac_core[][2] = {  	{0x000083d0, 0x800301ff},  }; -static const u32 ar9565_1p0_mac_postamble[][5] = { -	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ -	{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, -	{0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, -	{0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, -	{0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, -	{0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, -	{0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, -	{0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, -	{0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, -}; -  static const u32 ar9565_1p0_baseband_core[][2] = {  	/* Addr      allmodes  */  	{0x00009800, 0xafe68e30}, @@ -272,9 +266,9 @@ static const u32 ar9565_1p0_baseband_core[][2] = {  	{0x0000a398, 0x001f0e0f},  	{0x0000a39c, 0x0075393f},  	{0x0000a3a0, 0xb79f6427}, -	{0x0000a3a4, 0x00000000}, -	{0x0000a3a8, 0xaaaaaaaa}, -	{0x0000a3ac, 0x3c466478}, +	{0x0000a3a4, 0x00000011}, +	{0x0000a3a8, 0xaaaaaa6e}, +	{0x0000a3ac, 0x3c466455},  	{0x0000a3c0, 0x20202020},  	{0x0000a3c4, 0x22222220},  	{0x0000a3c8, 0x20200020}, @@ -295,11 +289,11 @@ static const u32 ar9565_1p0_baseband_core[][2] = {  	{0x0000a404, 0x00000000},  	{0x0000a408, 0x0e79e5c6},  	{0x0000a40c, 0x00820820}, -	{0x0000a414, 0x1ce739ce}, +	{0x0000a414, 0x1ce739c5},  	{0x0000a418, 0x2d001dce}, -	{0x0000a41c, 0x1ce739ce}, +	{0x0000a41c, 0x1ce739c5},  	{0x0000a420, 0x000001ce}, -	{0x0000a424, 0x1ce739ce}, +	{0x0000a424, 0x1ce739c5},  	{0x0000a428, 0x000001ce},  	{0x0000a42c, 0x1ce739ce},  	{0x0000a430, 0x1ce739ce}, @@ -351,9 +345,9 @@ static const u32 ar9565_1p0_baseband_postamble[][5] = {  	{0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e},  	{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},  	{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, -	{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, +	{0x00009e20, 0x000003b5, 0x000003b5, 0x000003a4, 0x000003a4},  	{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, -	{0x00009e3c, 0xcf946222, 0xcf946222, 0xcf946222, 0xcf946222}, +	{0x00009e3c, 0xcf946222, 0xcf946222, 0xcf946220, 0xcf946220},  	{0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27},  	{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},  	{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, @@ -452,6 +446,7 @@ static const u32 ar9565_1p0_Common_rx_gain_table[][2] = {  	/* Addr      allmodes  */  	{0x00004050, 0x00300300},  	{0x0000406c, 0x00100000}, +	{0x00009e20, 0x000003b6},  	{0x0000a000, 0x00010000},  	{0x0000a004, 0x00030002},  	{0x0000a008, 0x00050004}, @@ -710,66 +705,6 @@ static const u32 ar9565_1p0_Common_rx_gain_table[][2] = {  	{0x0000b1fc, 0x00000196},  }; -static const u32 ar9565_1p0_Modes_lowest_ob_db_tx_gain_table[][5] = { -	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ -	{0x0000a2dc, 0xfc0a9380, 0xfc0a9380, 0xfdab5b52, 0xfdab5b52}, -	{0x0000a2e0, 0xffecec00, 0xffecec00, 0xfd339c84, 0xfd339c84}, -	{0x0000a2e4, 0xfc0f0000, 0xfc0f0000, 0xfec3e000, 0xfec3e000}, -	{0x0000a2e8, 0xfc100000, 0xfc100000, 0xfffc0000, 0xfffc0000}, -	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, -	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, -	{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, -	{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, -	{0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, -	{0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, -	{0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402}, -	{0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, -	{0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, -	{0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, -	{0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, -	{0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, -	{0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, -	{0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, -	{0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, -	{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, -	{0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, -	{0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, -	{0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, -	{0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83}, -	{0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84}, -	{0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3}, -	{0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5}, -	{0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9}, -	{0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb}, -	{0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, -	{0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, -	{0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, -	{0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, -	{0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, -	{0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, -	{0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, -	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a614, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a618, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a61c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a620, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a624, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a628, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a62c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a630, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a634, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a638, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x0000a63c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x00016044, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4}, -	{0x00016048, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -	{0x00016054, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -}; -  static const u32 ar9565_1p0_pciephy_clkreq_disable_L1[][2] = {  	/* Addr      allmodes  */  	{0x00018c00, 0x18212ede}, diff --git a/drivers/net/wireless/ath/ath9k/ar9565_1p1_initvals.h b/drivers/net/wireless/ath/ath9k/ar9565_1p1_initvals.h new file mode 100644 index 00000000000..56810539971 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9565_1p1_initvals.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011-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. + */ + +#ifndef INITVALS_9565_1P1_H +#define INITVALS_9565_1P1_H + +/* AR9565 1.1 */ + +#define ar9565_1p1_mac_core ar9565_1p0_mac_core + +#define ar9565_1p1_mac_postamble ar9565_1p0_mac_postamble + +#define ar9565_1p1_baseband_core ar9565_1p0_baseband_core + +#define ar9565_1p1_baseband_postamble ar9565_1p0_baseband_postamble + +#define ar9565_1p1_radio_core ar9565_1p0_radio_core + +#define ar9565_1p1_soc_preamble ar9565_1p0_soc_preamble + +#define ar9565_1p1_soc_postamble ar9565_1p0_soc_postamble + +#define ar9565_1p1_Common_rx_gain_table ar9565_1p0_Common_rx_gain_table + +#define ar9565_1p1_Modes_lowest_ob_db_tx_gain_table ar9565_1p0_Modes_lowest_ob_db_tx_gain_table + +#define ar9565_1p1_pciephy_clkreq_disable_L1 ar9565_1p0_pciephy_clkreq_disable_L1 + +#define ar9565_1p1_modes_fast_clock ar9565_1p0_modes_fast_clock + +#define ar9565_1p1_common_wo_xlna_rx_gain_table ar9565_1p0_common_wo_xlna_rx_gain_table + +#define ar9565_1p1_modes_low_ob_db_tx_gain_table ar9565_1p0_modes_low_ob_db_tx_gain_table + +#define ar9565_1p1_modes_high_ob_db_tx_gain_table ar9565_1p0_modes_high_ob_db_tx_gain_table + +#define ar9565_1p1_modes_high_power_tx_gain_table ar9565_1p0_modes_high_power_tx_gain_table + +#define ar9565_1p1_baseband_core_txfir_coeff_japan_2484 ar9565_1p0_baseband_core_txfir_coeff_japan_2484 + +static const u32 ar9565_1p1_radio_postamble[][5] = { +	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ +	{0x0001609c, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524}, +	{0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808}, +	{0x000160b0, 0x01d67f70, 0x01d67f70, 0x01d67f70, 0x01d67f70}, +	{0x0001610c, 0x40000000, 0x40000000, 0x40000000, 0x40000000}, +	{0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, +}; + +#endif /* INITVALS_9565_1P1_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h index bdee2ed6721..a5ca65240af 100644 --- a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h @@ -20,18 +20,34 @@  /* AR9580 1.0 */ +#define ar9580_1p0_soc_preamble ar9300_2p2_soc_preamble + +#define ar9580_1p0_soc_postamble ar9300_2p2_soc_postamble + +#define ar9580_1p0_radio_core ar9300_2p2_radio_core + +#define ar9580_1p0_mac_postamble ar9300_2p2_mac_postamble + +#define ar9580_1p0_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2 + +#define ar9580_1p0_type5_tx_gain_table ar9300Modes_type5_tx_gain_table_2p2 + +#define ar9580_1p0_high_ob_db_tx_gain_table ar9300Modes_high_ob_db_tx_gain_table_2p2 +  #define ar9580_1p0_modes_fast_clock ar9300Modes_fast_clock_2p2 +#define ar9580_1p0_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484 +  static const u32 ar9580_1p0_radio_postamble[][5] = {  	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */  	{0x0001609c, 0x0dd08f29, 0x0dd08f29, 0x0b283f31, 0x0b283f31},  	{0x000160ac, 0xa4653c00, 0xa4653c00, 0x24652800, 0x24652800},  	{0x000160b0, 0x03284f3e, 0x03284f3e, 0x05d08f20, 0x05d08f20}, -	{0x0001610c, 0x08000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0001610c, 0xc8000000, 0xc0000000, 0xc0000000, 0xc0000000},  	{0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, -	{0x0001650c, 0x08000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0001650c, 0xc8000000, 0xc0000000, 0xc0000000, 0xc0000000},  	{0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, -	{0x0001690c, 0x08000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0001690c, 0xc8000000, 0xc0000000, 0xc0000000, 0xc0000000},  	{0x00016940, 0x10804008, 0x10804008, 0x50804008, 0x50804008},  }; @@ -41,12 +57,10 @@ static const u32 ar9580_1p0_baseband_core[][2] = {  	{0x00009804, 0xfd14e000},  	{0x00009808, 0x9c0a9f6b},  	{0x0000980c, 0x04900000}, -	{0x00009814, 0x3280c00a}, -	{0x00009818, 0x00000000},  	{0x0000981c, 0x00020028}, -	{0x00009834, 0x6400a290}, +	{0x00009834, 0x6400a190},  	{0x00009838, 0x0108ecff}, -	{0x0000983c, 0x0d000600}, +	{0x0000983c, 0x14000600},  	{0x00009880, 0x201fff00},  	{0x00009884, 0x00001042},  	{0x000098a4, 0x00200400}, @@ -67,7 +81,7 @@ static const u32 ar9580_1p0_baseband_core[][2] = {  	{0x00009d04, 0x40206c10},  	{0x00009d08, 0x009c4060},  	{0x00009d0c, 0x9883800a}, -	{0x00009d10, 0x01834061}, +	{0x00009d10, 0x01884061},  	{0x00009d14, 0x00c0040b},  	{0x00009d18, 0x00000000},  	{0x00009e08, 0x0038230c}, @@ -76,7 +90,7 @@ static const u32 ar9580_1p0_baseband_core[][2] = {  	{0x00009e30, 0x06336f77},  	{0x00009e34, 0x6af6532f},  	{0x00009e38, 0x0cc80c00}, -	{0x00009e40, 0x0d261820}, +	{0x00009e40, 0x0d261800},  	{0x00009e4c, 0x00001004},  	{0x00009e50, 0x00ff03f1},  	{0x00009e54, 0x00000000}, @@ -198,8 +212,6 @@ static const u32 ar9580_1p0_baseband_core[][2] = {  	{0x0000c420, 0x00000000},  }; -#define ar9580_1p0_mac_postamble ar9300_2p2_mac_postamble -  static const u32 ar9580_1p0_low_ob_db_tx_gain_table[][5] = {  	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */  	{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, @@ -306,7 +318,112 @@ static const u32 ar9580_1p0_low_ob_db_tx_gain_table[][5] = {  	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},  }; -#define ar9580_1p0_high_power_tx_gain_table ar9580_1p0_low_ob_db_tx_gain_table +static const u32 ar9580_1p0_high_power_tx_gain_table[][5] = { +	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ +	{0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, +	{0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, +	{0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, +	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, +	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, +	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, +	{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, +	{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, +	{0x0000a510, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202}, +	{0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400}, +	{0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402}, +	{0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404}, +	{0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603}, +	{0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02}, +	{0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04}, +	{0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20}, +	{0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20}, +	{0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22}, +	{0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24}, +	{0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640}, +	{0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660}, +	{0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861}, +	{0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81}, +	{0x0000a54c, 0x5e08442e, 0x5e08442e, 0x47001a83, 0x47001a83}, +	{0x0000a550, 0x620a4431, 0x620a4431, 0x4a001c84, 0x4a001c84}, +	{0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3}, +	{0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5}, +	{0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9}, +	{0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb}, +	{0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, +	{0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, +	{0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, +	{0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, +	{0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, +	{0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, +	{0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, +	{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, +	{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, +	{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, +	{0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, +	{0x0000a590, 0x15800028, 0x15800028, 0x0f800202, 0x0f800202}, +	{0x0000a594, 0x1b80002b, 0x1b80002b, 0x12800400, 0x12800400}, +	{0x0000a598, 0x1f820028, 0x1f820028, 0x16800402, 0x16800402}, +	{0x0000a59c, 0x2582002b, 0x2582002b, 0x19800404, 0x19800404}, +	{0x0000a5a0, 0x2a84002a, 0x2a84002a, 0x1c800603, 0x1c800603}, +	{0x0000a5a4, 0x2e86002a, 0x2e86002a, 0x21800a02, 0x21800a02}, +	{0x0000a5a8, 0x3382202d, 0x3382202d, 0x25800a04, 0x25800a04}, +	{0x0000a5ac, 0x3884202c, 0x3884202c, 0x28800a20, 0x28800a20}, +	{0x0000a5b0, 0x3c86202c, 0x3c86202c, 0x2c800e20, 0x2c800e20}, +	{0x0000a5b4, 0x4188202d, 0x4188202d, 0x30800e22, 0x30800e22}, +	{0x0000a5b8, 0x4586402d, 0x4586402d, 0x34800e24, 0x34800e24}, +	{0x0000a5bc, 0x4986222d, 0x4986222d, 0x38801640, 0x38801640}, +	{0x0000a5c0, 0x4d862231, 0x4d862231, 0x3c801660, 0x3c801660}, +	{0x0000a5c4, 0x50882231, 0x50882231, 0x3f801861, 0x3f801861}, +	{0x0000a5c8, 0x5688422e, 0x5688422e, 0x43801a81, 0x43801a81}, +	{0x0000a5cc, 0x5a88442e, 0x5a88442e, 0x47801a83, 0x47801a83}, +	{0x0000a5d0, 0x5e8a4431, 0x5e8a4431, 0x4a801c84, 0x4a801c84}, +	{0x0000a5d4, 0x648a4432, 0x648a4432, 0x4e801ce3, 0x4e801ce3}, +	{0x0000a5d8, 0x688a4434, 0x688a4434, 0x52801ce5, 0x52801ce5}, +	{0x0000a5dc, 0x6c8a6434, 0x6c8a6434, 0x56801ce9, 0x56801ce9}, +	{0x0000a5e0, 0x6f8a6633, 0x6f8a6633, 0x5a801ceb, 0x5a801ceb}, +	{0x0000a5e4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, +	{0x0000a5e8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, +	{0x0000a5ec, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, +	{0x0000a5f0, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, +	{0x0000a5f4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, +	{0x0000a5f8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, +	{0x0000a5fc, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, +	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +	{0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, +	{0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, +	{0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, +	{0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000}, +	{0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501}, +	{0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501}, +	{0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03}, +	{0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, +	{0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04}, +	{0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, +	{0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, +	{0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, +	{0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, +	{0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, +	{0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, +	{0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, +	{0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, +	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, +	{0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, +	{0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, +	{0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, +	{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, +	{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, +	{0x00016048, 0x65240001, 0x65240001, 0x66480001, 0x66480001}, +	{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, +	{0x00016288, 0x05a2040a, 0x05a2040a, 0x05a20408, 0x05a20408}, +	{0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, +	{0x00016448, 0x65240001, 0x65240001, 0x66480001, 0x66480001}, +	{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, +	{0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, +	{0x00016848, 0x65240001, 0x65240001, 0x66480001, 0x66480001}, +	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, +};  static const u32 ar9580_1p0_lowest_ob_db_tx_gain_table[][5] = {  	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */ @@ -414,8 +531,6 @@ static const u32 ar9580_1p0_lowest_ob_db_tx_gain_table[][5] = {  	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},  }; -#define ar9580_1p0_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484 -  static const u32 ar9580_1p0_mac_core[][2] = {  	/* Addr      allmodes  */  	{0x00000008, 0x00000000}, @@ -679,14 +794,6 @@ static const u32 ar9580_1p0_mixed_ob_db_tx_gain_table[][5] = {  	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},  }; -#define ar9580_1p0_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2 - -#define ar9580_1p0_soc_postamble ar9300_2p2_soc_postamble - -#define ar9580_1p0_high_ob_db_tx_gain_table ar9300Modes_high_ob_db_tx_gain_table_2p2 - -#define ar9580_1p0_type5_tx_gain_table ar9300Modes_type5_tx_gain_table_2p2 -  static const u32 ar9580_1p0_type6_tx_gain_table[][5] = {  	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */  	{0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, @@ -761,165 +868,271 @@ static const u32 ar9580_1p0_type6_tx_gain_table[][5] = {  	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},  }; -static const u32 ar9580_1p0_soc_preamble[][2] = { +static const u32 ar9580_1p0_rx_gain_table[][2] = {  	/* Addr      allmodes  */ -	{0x000040a4, 0x00a0c1c9}, -	{0x00007008, 0x00000000}, -	{0x00007020, 0x00000000}, -	{0x00007034, 0x00000002}, -	{0x00007038, 0x000004c2}, -	{0x00007048, 0x00000008}, -}; - -#define ar9580_1p0_rx_gain_table ar9462_common_rx_gain_table_2p0 - -static const u32 ar9580_1p0_radio_core[][2] = { -	/* Addr      allmodes  */ -	{0x00016000, 0x36db6db6}, -	{0x00016004, 0x6db6db40}, -	{0x00016008, 0x73f00000}, -	{0x0001600c, 0x00000000}, -	{0x00016040, 0x7f80fff8}, -	{0x0001604c, 0x76d005b5}, -	{0x00016050, 0x556cf031}, -	{0x00016054, 0x13449440}, -	{0x00016058, 0x0c51c92c}, -	{0x0001605c, 0x3db7fffc}, -	{0x00016060, 0xfffffffc}, -	{0x00016064, 0x000f0278}, -	{0x0001606c, 0x6db60000}, -	{0x00016080, 0x00000000}, -	{0x00016084, 0x0e48048c}, -	{0x00016088, 0x54214514}, -	{0x0001608c, 0x119f481e}, -	{0x00016090, 0x24926490}, -	{0x00016098, 0xd2888888}, -	{0x000160a0, 0x0a108ffe}, -	{0x000160a4, 0x812fc370}, -	{0x000160a8, 0x423c8000}, -	{0x000160b4, 0x92480080}, -	{0x000160c0, 0x00adb6d0}, -	{0x000160c4, 0x6db6db60}, -	{0x000160c8, 0x6db6db6c}, -	{0x000160cc, 0x01e6c000}, -	{0x00016100, 0x3fffbe01}, -	{0x00016104, 0xfff80000}, -	{0x00016108, 0x00080010}, -	{0x00016144, 0x02084080}, -	{0x00016148, 0x00000000}, -	{0x00016280, 0x058a0001}, -	{0x00016284, 0x3d840208}, -	{0x00016288, 0x05a20408}, -	{0x0001628c, 0x00038c07}, -	{0x00016290, 0x00000004}, -	{0x00016294, 0x458aa14f}, -	{0x00016380, 0x00000000}, -	{0x00016384, 0x00000000}, -	{0x00016388, 0x00800700}, -	{0x0001638c, 0x00800700}, -	{0x00016390, 0x00800700}, -	{0x00016394, 0x00000000}, -	{0x00016398, 0x00000000}, -	{0x0001639c, 0x00000000}, -	{0x000163a0, 0x00000001}, -	{0x000163a4, 0x00000001}, -	{0x000163a8, 0x00000000}, -	{0x000163ac, 0x00000000}, -	{0x000163b0, 0x00000000}, -	{0x000163b4, 0x00000000}, -	{0x000163b8, 0x00000000}, -	{0x000163bc, 0x00000000}, -	{0x000163c0, 0x000000a0}, -	{0x000163c4, 0x000c0000}, -	{0x000163c8, 0x14021402}, -	{0x000163cc, 0x00001402}, -	{0x000163d0, 0x00000000}, -	{0x000163d4, 0x00000000}, -	{0x00016400, 0x36db6db6}, -	{0x00016404, 0x6db6db40}, -	{0x00016408, 0x73f00000}, -	{0x0001640c, 0x00000000}, -	{0x00016440, 0x7f80fff8}, -	{0x0001644c, 0x76d005b5}, -	{0x00016450, 0x556cf031}, -	{0x00016454, 0x13449440}, -	{0x00016458, 0x0c51c92c}, -	{0x0001645c, 0x3db7fffc}, -	{0x00016460, 0xfffffffc}, -	{0x00016464, 0x000f0278}, -	{0x0001646c, 0x6db60000}, -	{0x00016500, 0x3fffbe01}, -	{0x00016504, 0xfff80000}, -	{0x00016508, 0x00080010}, -	{0x00016544, 0x02084080}, -	{0x00016548, 0x00000000}, -	{0x00016780, 0x00000000}, -	{0x00016784, 0x00000000}, -	{0x00016788, 0x00800700}, -	{0x0001678c, 0x00800700}, -	{0x00016790, 0x00800700}, -	{0x00016794, 0x00000000}, -	{0x00016798, 0x00000000}, -	{0x0001679c, 0x00000000}, -	{0x000167a0, 0x00000001}, -	{0x000167a4, 0x00000001}, -	{0x000167a8, 0x00000000}, -	{0x000167ac, 0x00000000}, -	{0x000167b0, 0x00000000}, -	{0x000167b4, 0x00000000}, -	{0x000167b8, 0x00000000}, -	{0x000167bc, 0x00000000}, -	{0x000167c0, 0x000000a0}, -	{0x000167c4, 0x000c0000}, -	{0x000167c8, 0x14021402}, -	{0x000167cc, 0x00001402}, -	{0x000167d0, 0x00000000}, -	{0x000167d4, 0x00000000}, -	{0x00016800, 0x36db6db6}, -	{0x00016804, 0x6db6db40}, -	{0x00016808, 0x73f00000}, -	{0x0001680c, 0x00000000}, -	{0x00016840, 0x7f80fff8}, -	{0x0001684c, 0x76d005b5}, -	{0x00016850, 0x556cf031}, -	{0x00016854, 0x13449440}, -	{0x00016858, 0x0c51c92c}, -	{0x0001685c, 0x3db7fffc}, -	{0x00016860, 0xfffffffc}, -	{0x00016864, 0x000f0278}, -	{0x0001686c, 0x6db60000}, -	{0x00016900, 0x3fffbe01}, -	{0x00016904, 0xfff80000}, -	{0x00016908, 0x00080010}, -	{0x00016944, 0x02084080}, -	{0x00016948, 0x00000000}, -	{0x00016b80, 0x00000000}, -	{0x00016b84, 0x00000000}, -	{0x00016b88, 0x00800700}, -	{0x00016b8c, 0x00800700}, -	{0x00016b90, 0x00800700}, -	{0x00016b94, 0x00000000}, -	{0x00016b98, 0x00000000}, -	{0x00016b9c, 0x00000000}, -	{0x00016ba0, 0x00000001}, -	{0x00016ba4, 0x00000001}, -	{0x00016ba8, 0x00000000}, -	{0x00016bac, 0x00000000}, -	{0x00016bb0, 0x00000000}, -	{0x00016bb4, 0x00000000}, -	{0x00016bb8, 0x00000000}, -	{0x00016bbc, 0x00000000}, -	{0x00016bc0, 0x000000a0}, -	{0x00016bc4, 0x000c0000}, -	{0x00016bc8, 0x14021402}, -	{0x00016bcc, 0x00001402}, -	{0x00016bd0, 0x00000000}, -	{0x00016bd4, 0x00000000}, +	{0x0000a000, 0x00010000}, +	{0x0000a004, 0x00030002}, +	{0x0000a008, 0x00050004}, +	{0x0000a00c, 0x00810080}, +	{0x0000a010, 0x00830082}, +	{0x0000a014, 0x01810180}, +	{0x0000a018, 0x01830182}, +	{0x0000a01c, 0x01850184}, +	{0x0000a020, 0x01890188}, +	{0x0000a024, 0x018b018a}, +	{0x0000a028, 0x018d018c}, +	{0x0000a02c, 0x01910190}, +	{0x0000a030, 0x01930192}, +	{0x0000a034, 0x01950194}, +	{0x0000a038, 0x038a0196}, +	{0x0000a03c, 0x038c038b}, +	{0x0000a040, 0x0390038d}, +	{0x0000a044, 0x03920391}, +	{0x0000a048, 0x03940393}, +	{0x0000a04c, 0x03960395}, +	{0x0000a050, 0x00000000}, +	{0x0000a054, 0x00000000}, +	{0x0000a058, 0x00000000}, +	{0x0000a05c, 0x00000000}, +	{0x0000a060, 0x00000000}, +	{0x0000a064, 0x00000000}, +	{0x0000a068, 0x00000000}, +	{0x0000a06c, 0x00000000}, +	{0x0000a070, 0x00000000}, +	{0x0000a074, 0x00000000}, +	{0x0000a078, 0x00000000}, +	{0x0000a07c, 0x00000000}, +	{0x0000a080, 0x22222229}, +	{0x0000a084, 0x1d1d1d1d}, +	{0x0000a088, 0x1d1d1d1d}, +	{0x0000a08c, 0x1d1d1d1d}, +	{0x0000a090, 0x171d1d1d}, +	{0x0000a094, 0x11111717}, +	{0x0000a098, 0x00030311}, +	{0x0000a09c, 0x00000000}, +	{0x0000a0a0, 0x00000000}, +	{0x0000a0a4, 0x00000000}, +	{0x0000a0a8, 0x00000000}, +	{0x0000a0ac, 0x00000000}, +	{0x0000a0b0, 0x00000000}, +	{0x0000a0b4, 0x00000000}, +	{0x0000a0b8, 0x00000000}, +	{0x0000a0bc, 0x00000000}, +	{0x0000a0c0, 0x001f0000}, +	{0x0000a0c4, 0x01000101}, +	{0x0000a0c8, 0x011e011f}, +	{0x0000a0cc, 0x011c011d}, +	{0x0000a0d0, 0x02030204}, +	{0x0000a0d4, 0x02010202}, +	{0x0000a0d8, 0x021f0200}, +	{0x0000a0dc, 0x0302021e}, +	{0x0000a0e0, 0x03000301}, +	{0x0000a0e4, 0x031e031f}, +	{0x0000a0e8, 0x0402031d}, +	{0x0000a0ec, 0x04000401}, +	{0x0000a0f0, 0x041e041f}, +	{0x0000a0f4, 0x0502041d}, +	{0x0000a0f8, 0x05000501}, +	{0x0000a0fc, 0x051e051f}, +	{0x0000a100, 0x06010602}, +	{0x0000a104, 0x061f0600}, +	{0x0000a108, 0x061d061e}, +	{0x0000a10c, 0x07020703}, +	{0x0000a110, 0x07000701}, +	{0x0000a114, 0x00000000}, +	{0x0000a118, 0x00000000}, +	{0x0000a11c, 0x00000000}, +	{0x0000a120, 0x00000000}, +	{0x0000a124, 0x00000000}, +	{0x0000a128, 0x00000000}, +	{0x0000a12c, 0x00000000}, +	{0x0000a130, 0x00000000}, +	{0x0000a134, 0x00000000}, +	{0x0000a138, 0x00000000}, +	{0x0000a13c, 0x00000000}, +	{0x0000a140, 0x001f0000}, +	{0x0000a144, 0x01000101}, +	{0x0000a148, 0x011e011f}, +	{0x0000a14c, 0x011c011d}, +	{0x0000a150, 0x02030204}, +	{0x0000a154, 0x02010202}, +	{0x0000a158, 0x021f0200}, +	{0x0000a15c, 0x0302021e}, +	{0x0000a160, 0x03000301}, +	{0x0000a164, 0x031e031f}, +	{0x0000a168, 0x0402031d}, +	{0x0000a16c, 0x04000401}, +	{0x0000a170, 0x041e041f}, +	{0x0000a174, 0x0502041d}, +	{0x0000a178, 0x05000501}, +	{0x0000a17c, 0x051e051f}, +	{0x0000a180, 0x06010602}, +	{0x0000a184, 0x061f0600}, +	{0x0000a188, 0x061d061e}, +	{0x0000a18c, 0x07020703}, +	{0x0000a190, 0x07000701}, +	{0x0000a194, 0x00000000}, +	{0x0000a198, 0x00000000}, +	{0x0000a19c, 0x00000000}, +	{0x0000a1a0, 0x00000000}, +	{0x0000a1a4, 0x00000000}, +	{0x0000a1a8, 0x00000000}, +	{0x0000a1ac, 0x00000000}, +	{0x0000a1b0, 0x00000000}, +	{0x0000a1b4, 0x00000000}, +	{0x0000a1b8, 0x00000000}, +	{0x0000a1bc, 0x00000000}, +	{0x0000a1c0, 0x00000000}, +	{0x0000a1c4, 0x00000000}, +	{0x0000a1c8, 0x00000000}, +	{0x0000a1cc, 0x00000000}, +	{0x0000a1d0, 0x00000000}, +	{0x0000a1d4, 0x00000000}, +	{0x0000a1d8, 0x00000000}, +	{0x0000a1dc, 0x00000000}, +	{0x0000a1e0, 0x00000000}, +	{0x0000a1e4, 0x00000000}, +	{0x0000a1e8, 0x00000000}, +	{0x0000a1ec, 0x00000000}, +	{0x0000a1f0, 0x00000396}, +	{0x0000a1f4, 0x00000396}, +	{0x0000a1f8, 0x00000396}, +	{0x0000a1fc, 0x00000196}, +	{0x0000b000, 0x00010000}, +	{0x0000b004, 0x00030002}, +	{0x0000b008, 0x00050004}, +	{0x0000b00c, 0x00810080}, +	{0x0000b010, 0x00830082}, +	{0x0000b014, 0x01810180}, +	{0x0000b018, 0x01830182}, +	{0x0000b01c, 0x01850184}, +	{0x0000b020, 0x02810280}, +	{0x0000b024, 0x02830282}, +	{0x0000b028, 0x02850284}, +	{0x0000b02c, 0x02890288}, +	{0x0000b030, 0x028b028a}, +	{0x0000b034, 0x0388028c}, +	{0x0000b038, 0x038a0389}, +	{0x0000b03c, 0x038c038b}, +	{0x0000b040, 0x0390038d}, +	{0x0000b044, 0x03920391}, +	{0x0000b048, 0x03940393}, +	{0x0000b04c, 0x03960395}, +	{0x0000b050, 0x00000000}, +	{0x0000b054, 0x00000000}, +	{0x0000b058, 0x00000000}, +	{0x0000b05c, 0x00000000}, +	{0x0000b060, 0x00000000}, +	{0x0000b064, 0x00000000}, +	{0x0000b068, 0x00000000}, +	{0x0000b06c, 0x00000000}, +	{0x0000b070, 0x00000000}, +	{0x0000b074, 0x00000000}, +	{0x0000b078, 0x00000000}, +	{0x0000b07c, 0x00000000}, +	{0x0000b080, 0x23232323}, +	{0x0000b084, 0x21232323}, +	{0x0000b088, 0x19191c1e}, +	{0x0000b08c, 0x12141417}, +	{0x0000b090, 0x07070e0e}, +	{0x0000b094, 0x03030305}, +	{0x0000b098, 0x00000003}, +	{0x0000b09c, 0x00000000}, +	{0x0000b0a0, 0x00000000}, +	{0x0000b0a4, 0x00000000}, +	{0x0000b0a8, 0x00000000}, +	{0x0000b0ac, 0x00000000}, +	{0x0000b0b0, 0x00000000}, +	{0x0000b0b4, 0x00000000}, +	{0x0000b0b8, 0x00000000}, +	{0x0000b0bc, 0x00000000}, +	{0x0000b0c0, 0x003f0020}, +	{0x0000b0c4, 0x00400041}, +	{0x0000b0c8, 0x0140005f}, +	{0x0000b0cc, 0x0160015f}, +	{0x0000b0d0, 0x017e017f}, +	{0x0000b0d4, 0x02410242}, +	{0x0000b0d8, 0x025f0240}, +	{0x0000b0dc, 0x027f0260}, +	{0x0000b0e0, 0x0341027e}, +	{0x0000b0e4, 0x035f0340}, +	{0x0000b0e8, 0x037f0360}, +	{0x0000b0ec, 0x04400441}, +	{0x0000b0f0, 0x0460045f}, +	{0x0000b0f4, 0x0541047f}, +	{0x0000b0f8, 0x055f0540}, +	{0x0000b0fc, 0x057f0560}, +	{0x0000b100, 0x06400641}, +	{0x0000b104, 0x0660065f}, +	{0x0000b108, 0x067e067f}, +	{0x0000b10c, 0x07410742}, +	{0x0000b110, 0x075f0740}, +	{0x0000b114, 0x077f0760}, +	{0x0000b118, 0x07800781}, +	{0x0000b11c, 0x07a0079f}, +	{0x0000b120, 0x07c107bf}, +	{0x0000b124, 0x000007c0}, +	{0x0000b128, 0x00000000}, +	{0x0000b12c, 0x00000000}, +	{0x0000b130, 0x00000000}, +	{0x0000b134, 0x00000000}, +	{0x0000b138, 0x00000000}, +	{0x0000b13c, 0x00000000}, +	{0x0000b140, 0x003f0020}, +	{0x0000b144, 0x00400041}, +	{0x0000b148, 0x0140005f}, +	{0x0000b14c, 0x0160015f}, +	{0x0000b150, 0x017e017f}, +	{0x0000b154, 0x02410242}, +	{0x0000b158, 0x025f0240}, +	{0x0000b15c, 0x027f0260}, +	{0x0000b160, 0x0341027e}, +	{0x0000b164, 0x035f0340}, +	{0x0000b168, 0x037f0360}, +	{0x0000b16c, 0x04400441}, +	{0x0000b170, 0x0460045f}, +	{0x0000b174, 0x0541047f}, +	{0x0000b178, 0x055f0540}, +	{0x0000b17c, 0x057f0560}, +	{0x0000b180, 0x06400641}, +	{0x0000b184, 0x0660065f}, +	{0x0000b188, 0x067e067f}, +	{0x0000b18c, 0x07410742}, +	{0x0000b190, 0x075f0740}, +	{0x0000b194, 0x077f0760}, +	{0x0000b198, 0x07800781}, +	{0x0000b19c, 0x07a0079f}, +	{0x0000b1a0, 0x07c107bf}, +	{0x0000b1a4, 0x000007c0}, +	{0x0000b1a8, 0x00000000}, +	{0x0000b1ac, 0x00000000}, +	{0x0000b1b0, 0x00000000}, +	{0x0000b1b4, 0x00000000}, +	{0x0000b1b8, 0x00000000}, +	{0x0000b1bc, 0x00000000}, +	{0x0000b1c0, 0x00000000}, +	{0x0000b1c4, 0x00000000}, +	{0x0000b1c8, 0x00000000}, +	{0x0000b1cc, 0x00000000}, +	{0x0000b1d0, 0x00000000}, +	{0x0000b1d4, 0x00000000}, +	{0x0000b1d8, 0x00000000}, +	{0x0000b1dc, 0x00000000}, +	{0x0000b1e0, 0x00000000}, +	{0x0000b1e4, 0x00000000}, +	{0x0000b1e8, 0x00000000}, +	{0x0000b1ec, 0x00000000}, +	{0x0000b1f0, 0x00000396}, +	{0x0000b1f4, 0x00000396}, +	{0x0000b1f8, 0x00000396}, +	{0x0000b1fc, 0x00000196},  };  static const u32 ar9580_1p0_baseband_postamble[][5] = {  	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */  	{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, +	{0x00009814, 0x3280c00a, 0x3280c00a, 0x3280c00a, 0x3280c00a}, +	{0x00009818, 0x00000000, 0x00000000, 0x00000000, 0x00000000},  	{0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e},  	{0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},  	{0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, @@ -956,7 +1169,7 @@ static const u32 ar9580_1p0_baseband_postamble[][5] = {  	{0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},  	{0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},  	{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, -	{0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982}, +	{0x0000a2d0, 0x00041983, 0x00041983, 0x00041981, 0x00041982},  	{0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},  	{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},  	{0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, @@ -994,4 +1207,13 @@ static const u32 ar9580_1p0_pcie_phy_pll_on_clkreq[][2] = {  	{0x00004044, 0x00000000},  }; +static const u32 ar9580_1p0_baseband_postamble_dfs_channel[][3] = { +	/* Addr      5G          2G        */ +	{0x00009814, 0x3400c00f, 0x3400c00f}, +	{0x00009824, 0x5ac668d0, 0x5ac668d0}, +	{0x00009828, 0x06903080, 0x06903080}, +	{0x00009e0c, 0x6d4000e2, 0x6d4000e2}, +	{0x00009e14, 0x37b9625e, 0x37b9625e}, +}; +  #endif /* INITVALS_9580_1P0_H */ diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 2ee35f677c0..2ca8f7e0617 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -23,54 +23,38 @@  #include <linux/leds.h>  #include <linux/completion.h> -#include "debug.h"  #include "common.h" +#include "debug.h"  #include "mci.h"  #include "dfs.h" - -/* - * Header for the ath9k.ko driver core *only* -- hw code nor any other driver - * should rely on this file or its contents. - */ +#include "spectral.h"  struct ath_node; -/* Macro to expand scalars to 64-bit objects */ - -#define	ito64(x) (sizeof(x) == 1) ?			\ -	(((unsigned long long int)(x)) & (0xff)) :	\ -	(sizeof(x) == 2) ?				\ -	(((unsigned long long int)(x)) & 0xffff) :	\ -	((sizeof(x) == 4) ?				\ -	 (((unsigned long long int)(x)) & 0xffffffff) : \ -	 (unsigned long long int)(x)) - -/* increment with wrap-around */ -#define INCR(_l, _sz)   do {			\ -		(_l)++;				\ -		(_l) &= ((_sz) - 1);		\ -	} while (0) - -/* decrement with wrap-around */ -#define DECR(_l,  _sz)  do {			\ -		(_l)--;				\ -		(_l) &= ((_sz) - 1);		\ -	} while (0) - -#define TSF_TO_TU(_h,_l) \ -	((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) - -#define	ATH_TXQ_SETUP(sc, i)        ((sc)->tx.txqsetup & (1<<i)) +extern struct ieee80211_ops ath9k_ops; +extern int ath9k_modparam_nohwcrypt; +extern int led_blink; +extern bool is_ath9k_unloaded;  struct ath_config {  	u16 txpowlimit; -	u8 cabqReadytime;  };  /*************************/  /* Descriptor Management */  /*************************/ +#define ATH_TXSTATUS_RING_SIZE 512 + +/* Macro to expand scalars to 64-bit objects */ +#define	ito64(x) (sizeof(x) == 1) ?			\ +	(((unsigned long long int)(x)) & (0xff)) :	\ +	(sizeof(x) == 2) ?				\ +	(((unsigned long long int)(x)) & 0xffff) :	\ +	((sizeof(x) == 4) ?				\ +	 (((unsigned long long int)(x)) & 0xffffffff) : \ +	 (unsigned long long int)(x)) +  #define ATH_TXBUF_RESET(_bf) do {				\  		(_bf)->bf_lastbf = NULL;			\  		(_bf)->bf_next = NULL;				\ @@ -78,23 +62,6 @@ struct ath_config {  		       sizeof(struct ath_buf_state));		\  	} while (0) -/** - * enum buffer_type - Buffer type flags - * - * @BUF_AMPDU: This buffer is an ampdu, as part of an aggregate (during TX) - * @BUF_AGGR: Indicates whether the buffer can be aggregated - *	(used in aggregation scheduling) - */ -enum buffer_type { -	BUF_AMPDU		= BIT(0), -	BUF_AGGR		= BIT(1), -}; - -#define bf_isampdu(bf)		(bf->bf_state.bf_type & BUF_AMPDU) -#define bf_isaggr(bf)		(bf->bf_state.bf_type & BUF_AGGR) - -#define ATH_TXSTATUS_RING_SIZE 512 -  #define	DS2PHYS(_dd, _ds)						\  	((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))  #define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) @@ -114,11 +81,20 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,  /* RX / TX */  /***********/ +#define	ATH_TXQ_SETUP(sc, i) ((sc)->tx.txqsetup & (1<<i)) + +/* increment with wrap-around */ +#define INCR(_l, _sz)   do {			\ +		(_l)++;				\ +		(_l) &= ((_sz) - 1);		\ +	} while (0) +  #define ATH_RXBUF               512  #define ATH_TXBUF               512  #define ATH_TXBUF_RESERVE       5  #define ATH_MAX_QDEPTH          (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)  #define ATH_TXMAXTRY            13 +#define ATH_MAX_SW_RETRIES      30  #define TID_TO_WME_AC(_tid)				\  	((((_tid) == 0) || ((_tid) == 3)) ? IEEE80211_AC_BE :	\ @@ -134,6 +110,12 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,  #define ATH_AGGR_MIN_QDEPTH        2  /* minimum h/w qdepth for non-aggregated traffic */  #define ATH_NON_AGGR_MIN_QDEPTH    8 +#define ATH_TX_COMPLETE_POLL_INT   1000 +#define ATH_TXFIFO_DEPTH           8 +#define ATH_TX_ERROR               0x01 + +/* Stop tx traffic 1ms before the GO goes away */ +#define ATH_P2P_PS_STOP_TIME       1000  #define IEEE80211_SEQ_SEQ_SHIFT    4  #define IEEE80211_SEQ_MAX          4096 @@ -166,11 +148,15 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,  #define ATH_AN_2_TID(_an, _tidno)  (&(_an)->tid[(_tidno)]) -#define IS_CCK_RATE(rate) ((rate >= 0x18) && (rate <= 0x1e)) +#define IS_HT_RATE(rate)   (rate & 0x80) +#define IS_CCK_RATE(rate)  ((rate >= 0x18) && (rate <= 0x1e)) +#define IS_OFDM_RATE(rate) ((rate >= 0x8) && (rate <= 0xf)) -#define ATH_TX_COMPLETE_POLL_INT	1000 +enum { +       WLAN_RC_PHY_OFDM, +       WLAN_RC_PHY_CCK, +}; -#define ATH_TXFIFO_DEPTH 8  struct ath_txq {  	int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */  	u32 axq_qnum; /* ath9k hardware queue number */ @@ -207,6 +193,29 @@ struct ath_frame_info {  	u8 baw_tracked : 1;  }; +struct ath_rxbuf { +	struct list_head list; +	struct sk_buff *bf_mpdu; +	void *bf_desc; +	dma_addr_t bf_daddr; +	dma_addr_t bf_buf_addr; +}; + +/** + * enum buffer_type - Buffer type flags + * + * @BUF_AMPDU: This buffer is an ampdu, as part of an aggregate (during TX) + * @BUF_AGGR: Indicates whether the buffer can be aggregated + *	(used in aggregation scheduling) + */ +enum buffer_type { +	BUF_AMPDU		= BIT(0), +	BUF_AGGR		= BIT(1), +}; + +#define bf_isampdu(bf)		(bf->bf_state.bf_type & BUF_AMPDU) +#define bf_isaggr(bf)		(bf->bf_state.bf_type & BUF_AGGR) +  struct ath_buf_state {  	u8 bf_type;  	u8 bfs_paprd; @@ -245,7 +254,6 @@ struct ath_atx_tid {  	s8 bar_index;  	bool sched; -	bool paused;  	bool active;  }; @@ -262,6 +270,11 @@ struct ath_node {  	bool sleeping;  	bool no_ps_filter; + +#ifdef CONFIG_ATH9K_STATION_STATISTICS +	struct ath_rx_rate_stats rx_rate_stats; +#endif +	u8 key_idx[4];  };  struct ath_tx_control { @@ -271,7 +284,6 @@ struct ath_tx_control {  	struct ieee80211_sta *sta;  }; -#define ATH_TX_ERROR        0x01  /**   * @txq_map:  Index is mac80211 queue number.  This is @@ -307,7 +319,7 @@ struct ath_rx {  	struct ath_descdma rxdma;  	struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX]; -	struct ath_buf *buf_hold; +	struct ath_rxbuf *buf_hold;  	struct sk_buff *frag;  	u32 ampdu_ref; @@ -358,13 +370,33 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,  /********/  struct ath_vif { +	struct ieee80211_vif *vif;  	struct ath_node mcast_node;  	int av_bslot;  	bool primary_sta_vif;  	__le64 tsf_adjust; /* TSF adjustment for staggered beacons */  	struct ath_buf *av_bcbuf; + +	/* P2P Client */ +	struct ieee80211_noa_data noa;  }; +struct ath9k_vif_iter_data { +	u8 hw_macaddr[ETH_ALEN]; /* address of the first vif */ +	u8 mask[ETH_ALEN]; /* bssid mask */ +	bool has_hw_macaddr; + +	int naps;      /* number of AP vifs */ +	int nmeshes;   /* number of mesh vifs */ +	int nstations; /* number of station vifs */ +	int nwds;      /* number of WDS vifs */ +	int nadhocs;   /* number of adhoc vifs */ +}; + +void ath9k_calculate_iter_data(struct ieee80211_hw *hw, +			       struct ieee80211_vif *vif, +			       struct ath9k_vif_iter_data *iter_data); +  /*******************/  /* Beacon Handling */  /*******************/ @@ -378,17 +410,9 @@ struct ath_vif {  #define	ATH_BCBUF               	8  #define ATH_DEFAULT_BINTVAL     	100 /* TU */  #define ATH_DEFAULT_BMISS_LIMIT 	10 -#define IEEE80211_MS_TO_TU(x)           (((x) * 1000) / 1024) - -struct ath_beacon_config { -	int beacon_interval; -	u16 listen_interval; -	u16 dtim_period; -	u16 bmiss_timeout; -	u8 dtim_count; -	bool enable_beacon; -	bool ibss_creator; -}; + +#define TSF_TO_TU(_h,_l) \ +	((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))  struct ath_beacon {  	enum { @@ -399,11 +423,9 @@ struct ath_beacon {  	u32 beaconq;  	u32 bmisscnt; -	u32 bc_tstamp;  	struct ieee80211_vif *bslot[ATH_BCBUF];  	int slottime;  	int slotupdate; -	struct ath9k_tx_queue_info beacon_qi;  	struct ath_descdma bdma;  	struct ath_txq *cabq;  	struct list_head bbuf; @@ -413,14 +435,13 @@ struct ath_beacon {  };  void ath9k_beacon_tasklet(unsigned long data); -bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);  void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,  			 u32 changed);  void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif);  void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif); -void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif);  void ath9k_set_beacon(struct ath_softc *sc); -bool ath9k_csa_is_finished(struct ath_softc *sc); +bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif); +void ath9k_csa_update(struct ath_softc *sc);  /*******************/  /* Link Monitoring */ @@ -433,17 +454,14 @@ bool ath9k_csa_is_finished(struct ath_softc *sc);  #define ATH_LONG_CALINTERVAL_INT  1000    /* 1000 ms */  #define ATH_LONG_CALINTERVAL      30000   /* 30 seconds */  #define ATH_RESTART_CALINTERVAL   1200000 /* 20 minutes */ -#define ATH_ANI_MAX_SKIP_COUNT  10 - -#define ATH_PAPRD_TIMEOUT	100 /* msecs */ -#define ATH_PLL_WORK_INTERVAL   100 +#define ATH_ANI_MAX_SKIP_COUNT    10 +#define ATH_PAPRD_TIMEOUT         100 /* msecs */ +#define ATH_PLL_WORK_INTERVAL     100  void ath_tx_complete_poll_work(struct work_struct *work);  void ath_reset_work(struct work_struct *work); -void ath_hw_check(struct work_struct *work); +bool ath_hw_check(struct ath_softc *sc);  void ath_hw_pll_work(struct work_struct *work); -void ath_rx_poll(unsigned long data); -void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon);  void ath_paprd_calibrate(struct work_struct *work);  void ath_ani_calibrate(unsigned long data);  void ath_start_ani(struct ath_softc *sc); @@ -452,6 +470,9 @@ void ath_check_ani(struct ath_softc *sc);  int ath_update_survey_stats(struct ath_softc *sc);  void ath_update_survey_nf(struct ath_softc *sc, int channel);  void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type); +void ath_ps_full_sleep(unsigned long data); +void ath9k_p2p_ps_timer(void *priv); +void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif);  /**********/  /* BTCOEX */ @@ -459,8 +480,8 @@ void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type);  #define ATH_DUMP_BTCOEX(_s, _val)				\  	do {							\ -		len += snprintf(buf + len, size - len,		\ -				"%20s : %10d\n", _s, (_val));	\ +		len += scnprintf(buf + len, size - len,		\ +				 "%20s : %10d\n", _s, (_val));	\  	} while (0)  enum bt_op_flags { @@ -469,20 +490,19 @@ enum bt_op_flags {  };  struct ath_btcoex { -	bool hw_timer_enabled;  	spinlock_t btcoex_lock;  	struct timer_list period_timer; /* Timer for BT period */ +	struct timer_list no_stomp_timer;  	u32 bt_priority_cnt;  	unsigned long bt_priority_time;  	unsigned long op_flags;  	int bt_stomp_type; /* Types of BT stomping */ -	u32 btcoex_no_stomp; /* in usec */ +	u32 btcoex_no_stomp; /* in msec */  	u32 btcoex_period; /* in msec */ -	u32 btscan_no_stomp; /* in usec */ +	u32 btscan_no_stomp; /* in msec */  	u32 duty_cycle;  	u32 bt_wait_time;  	int rssi_count; -	struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */  	struct ath_mci_profile mci;  	u8 stomp_audio;  }; @@ -530,12 +550,6 @@ static inline int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 size)  }  #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ -struct ath9k_wow_pattern { -	u8 pattern_bytes[MAX_PATTERN_SIZE]; -	u8 mask_bytes[MAX_PATTERN_SIZE]; -	u32 pattern_len; -}; -  /********************/  /*   LED Control    */  /********************/ @@ -563,6 +577,40 @@ static inline void ath_fill_led_pin(struct ath_softc *sc)  }  #endif +/************************/ +/* Wake on Wireless LAN */ +/************************/ + +struct ath9k_wow_pattern { +	u8 pattern_bytes[MAX_PATTERN_SIZE]; +	u8 mask_bytes[MAX_PATTERN_SIZE]; +	u32 pattern_len; +}; + +#ifdef CONFIG_ATH9K_WOW +void ath9k_init_wow(struct ieee80211_hw *hw); +int ath9k_suspend(struct ieee80211_hw *hw, +		  struct cfg80211_wowlan *wowlan); +int ath9k_resume(struct ieee80211_hw *hw); +void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled); +#else +static inline void ath9k_init_wow(struct ieee80211_hw *hw) +{ +} +static inline int ath9k_suspend(struct ieee80211_hw *hw, +				struct cfg80211_wowlan *wowlan) +{ +	return 0; +} +static inline int ath9k_resume(struct ieee80211_hw *hw) +{ +	return 0; +} +static inline void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled) +{ +} +#endif /* CONFIG_ATH9K_WOW */ +  /*******************************/  /* Antenna diversity/combining */  /*******************************/ @@ -581,7 +629,6 @@ static inline void ath_fill_led_pin(struct ath_softc *sc)  #define ATH_ANT_DIV_COMB_ALT_ANT_RATIO_LOW_RSSI 50  #define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2_LOW_RSSI 50 -#define ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA -1  #define ATH_ANT_DIV_COMB_LNA1_DELTA_HI -4  #define ATH_ANT_DIV_COMB_LNA1_DELTA_MID -2  #define ATH_ANT_DIV_COMB_LNA1_DELTA_LOW 2 @@ -626,34 +673,26 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs);  /* Main driver core */  /********************/ -#define ATH9K_PCI_CUS198     0x0001 -#define ATH9K_PCI_CUS230     0x0002 -#define ATH9K_PCI_CUS217     0x0004 -#define ATH9K_PCI_WOW        0x0008 -#define ATH9K_PCI_BT_ANT_DIV 0x0010 -#define ATH9K_PCI_D3_L1_WAR  0x0020 +#define ATH9K_PCI_CUS198          0x0001 +#define ATH9K_PCI_CUS230          0x0002 +#define ATH9K_PCI_CUS217          0x0004 +#define ATH9K_PCI_CUS252          0x0008 +#define ATH9K_PCI_WOW             0x0010 +#define ATH9K_PCI_BT_ANT_DIV      0x0020 +#define ATH9K_PCI_D3_L1_WAR       0x0040 +#define ATH9K_PCI_AR9565_1ANT     0x0080 +#define ATH9K_PCI_AR9565_2ANT     0x0100 +#define ATH9K_PCI_NO_PLL_PWRSAVE  0x0200 +#define ATH9K_PCI_KILLER          0x0400  /*   * Default cache line size, in bytes.   * Used when PCI device not fully initialized by bootrom/BIOS  */  #define DEFAULT_CACHELINE       32 -#define ATH_REGCLASSIDS_MAX     10  #define ATH_CABQ_READY_TIME     80      /* % of beacon interval */ -#define ATH_MAX_SW_RETRIES      30 -#define ATH_CHAN_MAX            255 -  #define ATH_TXPOWER_MAX         100     /* .5 dBm units */ -#define ATH_RATE_DUMMY_MARKER   0 - -enum sc_op_flags { -	SC_OP_INVALID, -	SC_OP_BEACONS, -	SC_OP_ANI_RUN, -	SC_OP_PRIM_STA_VIF, -	SC_OP_HW_RESET, -	SC_OP_SCANNING, -}; +#define MAX_GTT_CNT             5  /* Powersave flags */  #define PS_WAIT_FOR_BEACON        BIT(0) @@ -663,37 +702,6 @@ enum sc_op_flags {  #define PS_BEACON_SYNC            BIT(4)  #define PS_WAIT_FOR_ANI           BIT(5) -struct ath_rate_table; - -struct ath9k_vif_iter_data { -	u8 hw_macaddr[ETH_ALEN]; /* address of the first vif */ -	u8 mask[ETH_ALEN]; /* bssid mask */ -	bool has_hw_macaddr; - -	int naps;      /* number of AP vifs */ -	int nmeshes;   /* number of mesh vifs */ -	int nstations; /* number of station vifs */ -	int nwds;      /* number of WDS vifs */ -	int nadhocs;   /* number of adhoc vifs */ -}; - -/* enum spectral_mode: - * - * @SPECTRAL_DISABLED: spectral mode is disabled - * @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with - *	something else. - * @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples - *	is performed manually. - * @SPECTRAL_CHANSCAN: Like manual, but also triggered when changing channels - *	during a channel scan. - */ -enum spectral_mode { -	SPECTRAL_DISABLED = 0, -	SPECTRAL_BACKGROUND, -	SPECTRAL_MANUAL, -	SPECTRAL_CHANSCAN, -}; -  struct ath_softc {  	struct ieee80211_hw *hw;  	struct device *dev; @@ -711,14 +719,16 @@ struct ath_softc {  	spinlock_t sc_pcu_lock;  	struct mutex mutex;  	struct work_struct paprd_work; -	struct work_struct hw_check_work;  	struct work_struct hw_reset_work;  	struct completion paprd_complete; +	wait_queue_head_t tx_wait; + +	struct ath_gen_timer *p2p_ps_timer; +	struct ath_vif *p2p_ps_vif; -	unsigned int hw_busy_count; -	unsigned long sc_flags;  	unsigned long driver_data; +	u8 gtt_cnt;  	u32 intrstatus;  	u16 ps_flags; /* PS_* */  	u16 curtxpow; @@ -732,7 +742,6 @@ struct ath_softc {  	struct ath_rx rx;  	struct ath_tx tx;  	struct ath_beacon beacon; -	struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];  #ifdef CONFIG_MAC80211_LEDS  	bool led_registered; @@ -741,7 +750,6 @@ struct ath_softc {  #endif  	struct ath9k_hw_cal_data caldata; -	int last_rssi;  #ifdef CONFIG_ATH9K_DEBUGFS  	struct ath9k_debug debug; @@ -749,7 +757,7 @@ struct ath_softc {  	struct ath_beacon_config cur_beacon_conf;  	struct delayed_work tx_complete_work;  	struct delayed_work hw_pll_work; -	struct timer_list rx_poll_timer; +	struct timer_list sleep_timer;  #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT  	struct ath_btcoex btcoex; @@ -758,177 +766,70 @@ struct ath_softc {  #endif  	struct ath_descdma txsdma; -	struct ieee80211_vif *csa_vif;  	struct ath_ant_comb ant_comb;  	u8 ant_tx, ant_rx;  	struct dfs_pattern_detector *dfs_detector; +	u64 dfs_prev_pulse_ts;  	u32 wow_enabled;  	/* relay(fs) channel for spectral scan */  	struct rchan *rfs_chan_spec_scan;  	enum spectral_mode spectral_mode;  	struct ath_spec_scan spec_config; -#ifdef CONFIG_PM_SLEEP +	struct ieee80211_vif *tx99_vif; +	struct sk_buff *tx99_skb; +	bool tx99_state; +	s16 tx99_power; + +#ifdef CONFIG_ATH9K_WOW  	atomic_t wow_got_bmiss_intr;  	atomic_t wow_sleep_proc_intr; /* in the middle of WoW sleep ? */  	u32 wow_intr_before_sleep;  #endif  }; -#define SPECTRAL_SCAN_BITMASK		0x10 -/* Radar info packet format, used for DFS and spectral formats. */ -struct ath_radar_info { -	u8 pulse_length_pri; -	u8 pulse_length_ext; -	u8 pulse_bw_info; -} __packed; - -/* The HT20 spectral data has 4 bytes of additional information at it's end. - * - * [7:0]: all bins {max_magnitude[1:0], bitmap_weight[5:0]} - * [7:0]: all bins  max_magnitude[9:2] - * [7:0]: all bins {max_index[5:0], max_magnitude[11:10]} - * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned) - */ -struct ath_ht20_mag_info { -	u8 all_bins[3]; -	u8 max_exp; -} __packed; - -#define SPECTRAL_HT20_NUM_BINS		56 - -/* WARNING: don't actually use this struct! MAC may vary the amount of - * data by -1/+2. This struct is for reference only. - */ -struct ath_ht20_fft_packet { -	u8 data[SPECTRAL_HT20_NUM_BINS]; -	struct ath_ht20_mag_info mag_info; -	struct ath_radar_info radar_info; -} __packed; - -#define SPECTRAL_HT20_TOTAL_DATA_LEN	(sizeof(struct ath_ht20_fft_packet)) - -/* Dynamic 20/40 mode: - * - * [7:0]: lower bins {max_magnitude[1:0], bitmap_weight[5:0]} - * [7:0]: lower bins  max_magnitude[9:2] - * [7:0]: lower bins {max_index[5:0], max_magnitude[11:10]} - * [7:0]: upper bins {max_magnitude[1:0], bitmap_weight[5:0]} - * [7:0]: upper bins  max_magnitude[9:2] - * [7:0]: upper bins {max_index[5:0], max_magnitude[11:10]} - * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned) - */ -struct ath_ht20_40_mag_info { -	u8 lower_bins[3]; -	u8 upper_bins[3]; -	u8 max_exp; -} __packed; - -#define SPECTRAL_HT20_40_NUM_BINS		128 - -/* WARNING: don't actually use this struct! MAC may vary the amount of - * data. This struct is for reference only. - */ -struct ath_ht20_40_fft_packet { -	u8 data[SPECTRAL_HT20_40_NUM_BINS]; -	struct ath_ht20_40_mag_info mag_info; -	struct ath_radar_info radar_info; -} __packed; - - -#define SPECTRAL_HT20_40_TOTAL_DATA_LEN	(sizeof(struct ath_ht20_40_fft_packet)) - -/* grabs the max magnitude from the all/upper/lower bins */ -static inline u16 spectral_max_magnitude(u8 *bins) -{ -	return (bins[0] & 0xc0) >> 6 | -	       (bins[1] & 0xff) << 2 | -	       (bins[2] & 0x03) << 10; -} +/********/ +/* TX99 */ +/********/ -/* return the max magnitude from the all/upper/lower bins */ -static inline u8 spectral_max_index(u8 *bins) +#ifdef CONFIG_ATH9K_TX99 +void ath9k_tx99_init_debug(struct ath_softc *sc); +int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb, +		    struct ath_tx_control *txctl); +#else +static inline void ath9k_tx99_init_debug(struct ath_softc *sc)  { -	s8 m = (bins[2] & 0xfc) >> 2; - -	/* TODO: this still doesn't always report the right values ... */ -	if (m > 32) -		m |= 0xe0; -	else -		m &= ~0xe0; - -	return m + 29;  } - -/* return the bitmap weight from the all/upper/lower bins */ -static inline u8 spectral_bitmap_weight(u8 *bins) +static inline int ath9k_tx99_send(struct ath_softc *sc, +				  struct sk_buff *skb, +				  struct ath_tx_control *txctl)  { -	return bins[0] & 0x3f; +	return 0;  } - -/* FFT sample format given to userspace via debugfs. - * - * Please keep the type/length at the front position and change - * other fields after adding another sample type - * - * TODO: this might need rework when switching to nl80211-based - * interface. - */ -enum ath_fft_sample_type { -	ATH_FFT_SAMPLE_HT20 = 1, -}; - -struct fft_sample_tlv { -	u8 type;	/* see ath_fft_sample */ -	__be16 length; -	/* type dependent data follows */ -} __packed; - -struct fft_sample_ht20 { -	struct fft_sample_tlv tlv; - -	u8 max_exp; - -	__be16 freq; -	s8 rssi; -	s8 noise; - -	__be16 max_magnitude; -	u8 max_index; -	u8 bitmap_weight; - -	__be64 tsf; - -	u8 data[SPECTRAL_HT20_NUM_BINS]; -} __packed; - -void ath9k_tasklet(unsigned long data); -int ath_cabq_update(struct ath_softc *); +#endif /* CONFIG_ATH9K_TX99 */  static inline void ath_read_cachesize(struct ath_common *common, int *csz)  {  	common->bus_ops->read_cachesize(common, csz);  } -extern struct ieee80211_ops ath9k_ops; -extern int ath9k_modparam_nohwcrypt; -extern int led_blink; -extern bool is_ath9k_unloaded; - +void ath9k_tasklet(unsigned long data); +int ath_cabq_update(struct ath_softc *);  u8 ath9k_parse_mpdudensity(u8 mpdudensity);  irqreturn_t ath_isr(int irq, void *dev); +int ath_reset(struct ath_softc *sc); +void ath_cancel_work(struct ath_softc *sc); +void ath_restart_work(struct ath_softc *sc);  int ath9k_init_device(u16 devid, struct ath_softc *sc,  		    const struct ath_bus_ops *bus_ops);  void ath9k_deinit_device(struct ath_softc *sc); -void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);  void ath9k_reload_chainmask_settings(struct ath_softc *sc); - -bool ath9k_uses_beacons(int type); -void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw); -int ath9k_spectral_scan_config(struct ieee80211_hw *hw, -			       enum spectral_mode spectral_mode); - +u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate); +void ath_start_rfkill_poll(struct ath_softc *sc); +void ath9k_rfkill_poll_state(struct ieee80211_hw *hw); +void ath9k_ps_wakeup(struct ath_softc *sc); +void ath9k_ps_restore(struct ath_softc *sc);  #ifdef CONFIG_ATH9K_PCI  int ath_pci_init(void); @@ -946,15 +847,4 @@ static inline int ath_ahb_init(void) { return 0; };  static inline void ath_ahb_exit(void) {};  #endif -void ath9k_ps_wakeup(struct ath_softc *sc); -void ath9k_ps_restore(struct ath_softc *sc); - -u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate); - -void ath_start_rfkill_poll(struct ath_softc *sc); -extern void ath9k_rfkill_poll_state(struct ieee80211_hw *hw); -void ath9k_calculate_iter_data(struct ieee80211_hw *hw, -			       struct ieee80211_vif *vif, -			       struct ath9k_vif_iter_data *iter_data); -  #endif /* ATH9K_H */ diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index b5c16b3a37b..e387f0b2954 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -80,7 +80,7 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,  	u8 chainmask = ah->txchainmask;  	u8 rate = 0; -	sband = &sc->sbands[common->hw->conf.chandef.chan->band]; +	sband = &common->sbands[common->hw->conf.chandef.chan->band];  	rate = sband->bitrates[rateidx].hw_value;  	if (vif->bss_conf.use_short_preamble)  		rate |= sband->bitrates[rateidx].hw_value_short; @@ -274,28 +274,26 @@ static int ath9k_beacon_choose_slot(struct ath_softc *sc)  	return slot;  } -void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif) +static void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif)  {  	struct ath_common *common = ath9k_hw_common(sc->sc_ah);  	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;  	struct ath_vif *avp = (void *)vif->drv_priv; -	u64 tsfadjust; +	u32 tsfadjust;  	if (avp->av_bslot == 0)  		return; -	tsfadjust = cur_conf->beacon_interval * avp->av_bslot / ATH_BCBUF; -	avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); +	tsfadjust = cur_conf->beacon_interval * avp->av_bslot; +	tsfadjust = TU_TO_USEC(tsfadjust) / ATH_BCBUF; +	avp->tsf_adjust = cpu_to_le64(tsfadjust);  	ath_dbg(common, CONFIG, "tsfadjust is: %llu for bslot: %d\n",  		(unsigned long long)tsfadjust, avp->av_bslot);  } -bool ath9k_csa_is_finished(struct ath_softc *sc) +bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif)  { -	struct ieee80211_vif *vif; - -	vif = sc->csa_vif;  	if (!vif || !vif->csa_active)  		return false; @@ -303,11 +301,22 @@ bool ath9k_csa_is_finished(struct ath_softc *sc)  		return false;  	ieee80211_csa_finish(vif); - -	sc->csa_vif = NULL;  	return true;  } +static void ath9k_csa_update_vif(void *data, u8 *mac, struct ieee80211_vif *vif) +{ +	struct ath_softc *sc = data; +	ath9k_csa_is_finished(sc, vif); +} + +void ath9k_csa_update(struct ath_softc *sc) +{ +	ieee80211_iterate_active_interfaces_atomic(sc->hw, +						   IEEE80211_IFACE_ITER_NORMAL, +						   ath9k_csa_update_vif, sc); +} +  void ath9k_beacon_tasklet(unsigned long data)  {  	struct ath_softc *sc = (struct ath_softc *)data; @@ -318,7 +327,7 @@ void ath9k_beacon_tasklet(unsigned long data)  	bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);  	int slot; -	if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) { +	if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) {  		ath_dbg(common, RESET,  			"reset work is pending, skip beaconing now\n");  		return; @@ -334,8 +343,16 @@ void ath9k_beacon_tasklet(unsigned long data)  	if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) {  		sc->beacon.bmisscnt++; -		if (!ath9k_hw_check_alive(ah)) -			ieee80211_queue_work(sc->hw, &sc->hw_check_work); +		ath9k_hw_check_nav(ah); + +		/* +		 * If the previous beacon has not been transmitted +		 * and a MAC/BB hang has been identified, return +		 * here because a chip reset would have been +		 * initiated. +		 */ +		if (!ath_hw_check(sc)) +			return;  		if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) {  			ath_dbg(common, BSTUCK, @@ -353,13 +370,13 @@ void ath9k_beacon_tasklet(unsigned long data)  		return;  	} -	/* EDMA devices check that in the tx completion function. */ -	if (!edma && ath9k_csa_is_finished(sc)) -		return; -  	slot = ath9k_beacon_choose_slot(sc);  	vif = sc->beacon.bslot[slot]; +	/* EDMA devices check that in the tx completion function. */ +	if (!edma && ath9k_csa_is_finished(sc, vif)) +		return; +  	if (!vif || !vif->bss_conf.enable_beacon)  		return; @@ -438,146 +455,18 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc,  				   struct ath_beacon_config *conf)  {  	struct ath_hw *ah = sc->sc_ah; -	struct ath_common *common = ath9k_hw_common(ah); -	u32 nexttbtt, intval; - -	/* NB: the beacon interval is kept internally in TU's */ -	intval = TU_TO_USEC(conf->beacon_interval); -	intval /= ATH_BCBUF; -	nexttbtt = intval; - -	if (conf->enable_beacon) -		ah->imask |= ATH9K_INT_SWBA; -	else -		ah->imask &= ~ATH9K_INT_SWBA; - -	ath_dbg(common, BEACON, -		"AP (%s) nexttbtt: %u intval: %u conf_intval: %u\n", -		(conf->enable_beacon) ? "Enable" : "Disable", -		nexttbtt, intval, conf->beacon_interval); -	ath9k_beacon_init(sc, nexttbtt, intval, true); +	ath9k_cmn_beacon_config_ap(ah, conf, ATH_BCBUF); +	ath9k_beacon_init(sc, conf->nexttbtt, conf->intval, false);  } -/* - * This sets up the beacon timers according to the timestamp of the last - * received beacon and the current TSF, configures PCF and DTIM - * handling, programs the sleep registers so the hardware will wakeup in - * time to receive beacons, and configures the beacon miss handling so - * we'll receive a BMISS interrupt when we stop seeing beacons from the AP - * we've associated with. - */ -static void ath9k_beacon_config_sta(struct ath_softc *sc, +static void ath9k_beacon_config_sta(struct ath_hw *ah,  				    struct ath_beacon_config *conf)  { -	struct ath_hw *ah = sc->sc_ah; -	struct ath_common *common = ath9k_hw_common(ah);  	struct ath9k_beacon_state bs; -	int dtimperiod, dtimcount, sleepduration; -	int cfpperiod, cfpcount; -	u32 nexttbtt = 0, intval, tsftu; -	u64 tsf; -	int num_beacons, offset, dtim_dec_count, cfp_dec_count; -	/* No need to configure beacon if we are not associated */ -	if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { -		ath_dbg(common, BEACON, -			"STA is not yet associated..skipping beacon config\n"); +	if (ath9k_cmn_beacon_config_sta(ah, conf, &bs) == -EPERM)  		return; -	} - -	memset(&bs, 0, sizeof(bs)); -	intval = conf->beacon_interval; - -	/* -	 * Setup dtim and cfp parameters according to -	 * last beacon we received (which may be none). -	 */ -	dtimperiod = conf->dtim_period; -	dtimcount = conf->dtim_count; -	if (dtimcount >= dtimperiod)	/* NB: sanity check */ -		dtimcount = 0; -	cfpperiod = 1;			/* NB: no PCF support yet */ -	cfpcount = 0; - -	sleepduration = conf->listen_interval * intval; - -	/* -	 * Pull nexttbtt forward to reflect the current -	 * TSF and calculate dtim+cfp state for the result. -	 */ -	tsf = ath9k_hw_gettsf64(ah); -	tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; - -	num_beacons = tsftu / intval + 1; -	offset = tsftu % intval; -	nexttbtt = tsftu - offset; -	if (offset) -		nexttbtt += intval; - -	/* DTIM Beacon every dtimperiod Beacon */ -	dtim_dec_count = num_beacons % dtimperiod; -	/* CFP every cfpperiod DTIM Beacon */ -	cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod; -	if (dtim_dec_count) -		cfp_dec_count++; - -	dtimcount -= dtim_dec_count; -	if (dtimcount < 0) -		dtimcount += dtimperiod; - -	cfpcount -= cfp_dec_count; -	if (cfpcount < 0) -		cfpcount += cfpperiod; - -	bs.bs_intval = intval; -	bs.bs_nexttbtt = nexttbtt; -	bs.bs_dtimperiod = dtimperiod*intval; -	bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval; -	bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod; -	bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod; -	bs.bs_cfpmaxduration = 0; - -	/* -	 * Calculate the number of consecutive beacons to miss* before taking -	 * a BMISS interrupt. The configuration is specified in TU so we only -	 * need calculate based	on the beacon interval.  Note that we clamp the -	 * result to at most 15 beacons. -	 */ -	if (sleepduration > intval) { -		bs.bs_bmissthreshold = conf->listen_interval * -			ATH_DEFAULT_BMISS_LIMIT / 2; -	} else { -		bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval); -		if (bs.bs_bmissthreshold > 15) -			bs.bs_bmissthreshold = 15; -		else if (bs.bs_bmissthreshold <= 0) -			bs.bs_bmissthreshold = 1; -	} - -	/* -	 * Calculate sleep duration. The configuration is given in ms. -	 * We ensure a multiple of the beacon period is used. Also, if the sleep -	 * duration is greater than the DTIM period then it makes senses -	 * to make it a multiple of that. -	 * -	 * XXX fixed at 100ms -	 */ - -	bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration); -	if (bs.bs_sleepduration > bs.bs_dtimperiod) -		bs.bs_sleepduration = bs.bs_dtimperiod; - -	/* TSF out of range threshold fixed at 1 second */ -	bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; - -	ath_dbg(common, BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu); -	ath_dbg(common, BEACON, -		"bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n", -		bs.bs_bmissthreshold, bs.bs_sleepduration, -		bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext); - -	/* Set the computed STA beacon timers */  	ath9k_hw_disable_interrupts(ah);  	ath9k_hw_set_sta_beacon_timers(ah, &bs); @@ -592,53 +481,23 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc,  {  	struct ath_hw *ah = sc->sc_ah;  	struct ath_common *common = ath9k_hw_common(ah); -	u32 intval, nexttbtt;  	ath9k_reset_beacon_status(sc); -	intval = TU_TO_USEC(conf->beacon_interval); +	ath9k_cmn_beacon_config_adhoc(ah, conf); -	if (conf->ibss_creator) { -		nexttbtt = intval; -	} else { -		u32 tbtt, offset, tsftu; -		u64 tsf; - -		/* -		 * Pull nexttbtt forward to reflect the current -		 * sync'd TSF. -		 */ -		tsf = ath9k_hw_gettsf64(ah); -		tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE; -		offset = tsftu % conf->beacon_interval; -		tbtt = tsftu - offset; -		if (offset) -			tbtt += conf->beacon_interval; - -		nexttbtt = TU_TO_USEC(tbtt); -	} - -	if (conf->enable_beacon) -		ah->imask |= ATH9K_INT_SWBA; -	else -		ah->imask &= ~ATH9K_INT_SWBA; - -	ath_dbg(common, BEACON, -		"IBSS (%s) nexttbtt: %u intval: %u conf_intval: %u\n", -		(conf->enable_beacon) ? "Enable" : "Disable", -		nexttbtt, intval, conf->beacon_interval); - -	ath9k_beacon_init(sc, nexttbtt, intval, conf->ibss_creator); +	ath9k_beacon_init(sc, conf->nexttbtt, conf->intval, conf->ibss_creator);  	/*  	 * Set the global 'beacon has been configured' flag for the  	 * joiner case in IBSS mode.  	 */  	if (!conf->ibss_creator && conf->enable_beacon) -		set_bit(SC_OP_BEACONS, &sc->sc_flags); +		set_bit(ATH_OP_BEACONS, &common->op_flags);  } -bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) +static bool ath9k_allow_beacon_config(struct ath_softc *sc, +				      struct ieee80211_vif *vif)  {  	struct ath_common *common = ath9k_hw_common(sc->sc_ah);  	struct ath_vif *avp = (void *)vif->drv_priv; @@ -654,7 +513,7 @@ bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)  	if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {  		if ((vif->type == NL80211_IFTYPE_STATION) && -		    test_bit(SC_OP_BEACONS, &sc->sc_flags) && +		    test_bit(ATH_OP_BEACONS, &common->op_flags) &&  		    !avp->primary_sta_vif) {  			ath_dbg(common, CONFIG,  				"Beacon already configured for a station interface\n"); @@ -676,11 +535,8 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc,  	cur_conf->beacon_interval = bss_conf->beacon_int;  	cur_conf->dtim_period = bss_conf->dtim_period; -	cur_conf->listen_interval = 1;  	cur_conf->dtim_count = 1;  	cur_conf->ibss_creator = bss_conf->ibss_creator; -	cur_conf->bmiss_timeout = -		ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;  	/*  	 * It looks like mac80211 may end up using beacon interval of zero in @@ -691,6 +547,9 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc,  	if (cur_conf->beacon_interval == 0)  		cur_conf->beacon_interval = 100; +	cur_conf->bmiss_timeout = +		ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; +  	/*  	 * We don't parse dtim period from mac80211 during the driver  	 * initialization as it breaks association with hidden-ssid @@ -706,15 +565,22 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,  {  	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;  	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; +        struct ath_hw *ah = sc->sc_ah; +        struct ath_common *common = ath9k_hw_common(ah);  	unsigned long flags;  	bool skip_beacon = false; +	if (vif->type == NL80211_IFTYPE_AP) +		ath9k_set_tsfadjust(sc, vif); + +	if (!ath9k_allow_beacon_config(sc, vif)) +		return; +  	if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {  		ath9k_cache_beacon_config(sc, bss_conf);  		ath9k_set_beacon(sc); -		set_bit(SC_OP_BEACONS, &sc->sc_flags); +		set_bit(ATH_OP_BEACONS, &common->op_flags);  		return; -  	}  	/* @@ -752,13 +618,13 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,  		}  		/* -		 * Do not set the SC_OP_BEACONS flag for IBSS joiner mode +		 * Do not set the ATH_OP_BEACONS flag for IBSS joiner mode  		 * here, it is done in ath9k_beacon_config_adhoc().  		 */  		if (cur_conf->enable_beacon && !skip_beacon) -			set_bit(SC_OP_BEACONS, &sc->sc_flags); +			set_bit(ATH_OP_BEACONS, &common->op_flags);  		else -			clear_bit(SC_OP_BEACONS, &sc->sc_flags); +			clear_bit(ATH_OP_BEACONS, &common->op_flags);  	}  } @@ -776,7 +642,7 @@ void ath9k_set_beacon(struct ath_softc *sc)  		ath9k_beacon_config_adhoc(sc, cur_conf);  		break;  	case NL80211_IFTYPE_STATION: -		ath9k_beacon_config_sta(sc, cur_conf); +		ath9k_beacon_config_sta(sc->sc_ah, cur_conf);  		break;  	default:  		ath_dbg(common, CONFIG, "Unsupported beaconing mode\n"); diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 9963b0bf9f7..3dfc2c7f1f0 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -66,7 +66,6 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)  		.bt_first_slot_time = 5,  		.bt_hold_rx_clear = true,  	}; -	u32 i, idx;  	bool rxclear_polarity = ath_bt_config.bt_rxclear_polarity;  	if (AR_SREV_9300_20_OR_LATER(ah)) @@ -88,11 +87,6 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)  		SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) |  		SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) |  		AR_BT_DISABLE_BT_ANT; - -	for (i = 0; i < 32; i++) { -		idx = (debruijn32 << i) >> 27; -		ah->hw_gen_timers.gen_timer_index[idx] = i; -	}  }  EXPORT_SYMBOL(ath9k_hw_init_btcoex_hw); diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 5e8219a91e2..278365b8a89 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -63,13 +63,13 @@ static s16 ath9k_hw_get_default_nf(struct ath_hw *ah,  	return ath9k_hw_get_nf_limits(ah, chan)->nominal;  } -s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) +s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan, +			   s16 nf)  {  	s8 noise = ATH_DEFAULT_NOISE_FLOOR; -	if (chan && chan->noisefloor) { -		s8 delta = chan->noisefloor - -			   ATH9K_NF_CAL_NOISE_THRESH - +	if (nf) { +		s8 delta = nf - ATH9K_NF_CAL_NOISE_THRESH -  			   ath9k_hw_get_default_nf(ah, chan);  		if (delta > 0)  			noise += delta; @@ -119,7 +119,7 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah,  			ath_dbg(common, CALIBRATE,  				"NFmid[%d] (%d) > MAX (%d), %s\n",  				i, h[i].privNF, limit->max, -				(cal->nfcal_interference ? +				(test_bit(NFCAL_INTF, &cal->cal_flags) ?  				 "not corrected (due to interference)" :  				 "correcting to MAX")); @@ -130,7 +130,7 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah,  			 * we bypass this limit here in order to better deal  			 * with our environment.  			 */ -			if (!cal->nfcal_interference) +			if (!test_bit(NFCAL_INTF, &cal->cal_flags))  				h[i].privNF = limit->max;  		}  	} @@ -141,7 +141,7 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah,  	 * Re-enable the enforcement of the NF maximum again.  	 */  	if (!high_nf_mid) -		cal->nfcal_interference = false; +		clear_bit(NFCAL_INTF, &cal->cal_flags);  }  static bool ath9k_hw_get_nf_thresh(struct ath_hw *ah, @@ -186,7 +186,6 @@ void ath9k_hw_reset_calibration(struct ath_hw *ah,  bool ath9k_hw_reset_calvalid(struct ath_hw *ah)  {  	struct ath_common *common = ath9k_hw_common(ah); -	struct ieee80211_conf *conf = &common->hw->conf;  	struct ath9k_cal_list *currCal = ah->cal_list_curr;  	if (!ah->caldata) @@ -208,7 +207,7 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah)  		return true;  	ath_dbg(common, CALIBRATE, "Resetting Cal %d state for channel %u\n", -		currCal->calData->calType, conf->chandef.chan->center_freq); +		currCal->calData->calType, ah->curchan->chan->center_freq);  	ah->caldata->CalValid &= ~currCal->calData->calType;  	currCal->calState = CAL_WAITING; @@ -220,7 +219,7 @@ EXPORT_SYMBOL(ath9k_hw_reset_calvalid);  void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update)  {  	if (ah->caldata) -		ah->caldata->nfcal_pending = true; +		set_bit(NFCAL_PENDING, &ah->caldata->cal_flags);  	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,  		    AR_PHY_AGC_CONTROL_ENABLE_NF); @@ -242,7 +241,6 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)  	int32_t val;  	u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;  	struct ath_common *common = ath9k_hw_common(ah); -	struct ieee80211_conf *conf = &common->hw->conf;  	s16 default_nf = ath9k_hw_get_default_nf(ah, chan);  	if (ah->caldata) @@ -252,7 +250,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)  		if (chainmask & (1 << i)) {  			s16 nfval; -			if ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf)) +			if ((i >= AR5416_MAX_CHAINS) && !IS_CHAN_HT40(chan))  				continue;  			if (h) @@ -314,7 +312,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)  	ENABLE_REGWRITE_BUFFER(ah);  	for (i = 0; i < NUM_NF_READINGS; i++) {  		if (chainmask & (1 << i)) { -			if ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf)) +			if ((i >= AR5416_MAX_CHAINS) && !IS_CHAN_HT40(chan))  				continue;  			val = REG_READ(ah, ah->nf_regs[i]); @@ -391,10 +389,10 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)  	}  	h = caldata->nfCalHist; -	caldata->nfcal_pending = false; +	clear_bit(NFCAL_PENDING, &caldata->cal_flags);  	ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray);  	chan->noisefloor = h[0].privNF; -	ah->noise = ath9k_hw_getchan_noise(ah, chan); +	ah->noise = ath9k_hw_getchan_noise(ah, chan, chan->noisefloor);  	return true;  }  EXPORT_SYMBOL(ath9k_hw_getnf); @@ -408,7 +406,6 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,  	ah->caldata->channel = chan->channel;  	ah->caldata->channelFlags = chan->channelFlags; -	ah->caldata->chanmode = chan->chanmode;  	h = ah->caldata->nfCalHist;  	default_nf = ath9k_hw_get_default_nf(ah, chan);  	for (i = 0; i < NUM_NF_READINGS; i++) { @@ -437,12 +434,12 @@ void ath9k_hw_bstuck_nfcal(struct ath_hw *ah)  	 * the baseband update the internal NF value itself, similar to  	 * what is being done after a full reset.  	 */ -	if (!caldata->nfcal_pending) +	if (!test_bit(NFCAL_PENDING, &caldata->cal_flags))  		ath9k_hw_start_nfcal(ah, true);  	else if (!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF))  		ath9k_hw_getnf(ah, ah->curchan); -	caldata->nfcal_interference = true; +	set_bit(NFCAL_INTF, &caldata->cal_flags);  }  EXPORT_SYMBOL(ath9k_hw_bstuck_nfcal); diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h index 3d70b8c2bcd..b8ed95e9a33 100644 --- a/drivers/net/wireless/ath/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h @@ -116,7 +116,8 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,  void ath9k_hw_bstuck_nfcal(struct ath_hw *ah);  void ath9k_hw_reset_calibration(struct ath_hw *ah,  				struct ath9k_cal_list *currCal); -s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan); +s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan, +			   s16 nf);  #endif /* CALIB_H */ diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.c b/drivers/net/wireless/ath/ath9k/common-beacon.c new file mode 100644 index 00000000000..775d1d20ce0 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-beacon.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2008-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "common.h" + +#define FUDGE 2 + +/* Calculate the modulo of a 64 bit TSF snapshot with a TU divisor */ +static u32 ath9k_mod_tsf64_tu(u64 tsf, u32 div_tu) +{ +	u32 tsf_mod, tsf_hi, tsf_lo, mod_hi, mod_lo; + +	tsf_mod = tsf & (BIT(10) - 1); +	tsf_hi = tsf >> 32; +	tsf_lo = ((u32) tsf) >> 10; + +	mod_hi = tsf_hi % div_tu; +	mod_lo = ((mod_hi << 22) + tsf_lo) % div_tu; + +	return (mod_lo << 10) | tsf_mod; +} + +static u32 ath9k_get_next_tbtt(struct ath_hw *ah, u64 tsf, +			       unsigned int interval) +{ +	unsigned int offset; + +	tsf += TU_TO_USEC(FUDGE + ah->config.sw_beacon_response_time); +	offset = ath9k_mod_tsf64_tu(tsf, interval); + +	return (u32) tsf + TU_TO_USEC(interval) - offset; +} + +/* + * This sets up the beacon timers according to the timestamp of the last + * received beacon and the current TSF, configures PCF and DTIM + * handling, programs the sleep registers so the hardware will wakeup in + * time to receive beacons, and configures the beacon miss handling so + * we'll receive a BMISS interrupt when we stop seeing beacons from the AP + * we've associated with. + */ +int ath9k_cmn_beacon_config_sta(struct ath_hw *ah, +				 struct ath_beacon_config *conf, +				 struct ath9k_beacon_state *bs) +{ +	struct ath_common *common = ath9k_hw_common(ah); +	int dtim_intval; +	u64 tsf; + +	/* No need to configure beacon if we are not associated */ +	if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { +		ath_dbg(common, BEACON, +			"STA is not yet associated..skipping beacon config\n"); +		return -EPERM; +	} + +	memset(bs, 0, sizeof(*bs)); +	conf->intval = conf->beacon_interval; + +	/* +	 * Setup dtim parameters according to +	 * last beacon we received (which may be none). +	 */ +	dtim_intval = conf->intval * conf->dtim_period; + +	/* +	 * Pull nexttbtt forward to reflect the current +	 * TSF and calculate dtim state for the result. +	 */ +	tsf = ath9k_hw_gettsf64(ah); +	conf->nexttbtt = ath9k_get_next_tbtt(ah, tsf, conf->intval); + +	bs->bs_intval = TU_TO_USEC(conf->intval); +	bs->bs_dtimperiod = conf->dtim_period * bs->bs_intval; +	bs->bs_nexttbtt = conf->nexttbtt; +	bs->bs_nextdtim = conf->nexttbtt; +	if (conf->dtim_period > 1) +		bs->bs_nextdtim = ath9k_get_next_tbtt(ah, tsf, dtim_intval); + +	/* +	 * Calculate the number of consecutive beacons to miss* before taking +	 * a BMISS interrupt. The configuration is specified in TU so we only +	 * need calculate based	on the beacon interval.  Note that we clamp the +	 * result to at most 15 beacons. +	 */ +	bs->bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, conf->intval); +	if (bs->bs_bmissthreshold > 15) +		bs->bs_bmissthreshold = 15; +	else if (bs->bs_bmissthreshold <= 0) +		bs->bs_bmissthreshold = 1; + +	/* +	 * Calculate sleep duration. The configuration is given in ms. +	 * We ensure a multiple of the beacon period is used. Also, if the sleep +	 * duration is greater than the DTIM period then it makes senses +	 * to make it a multiple of that. +	 * +	 * XXX fixed at 100ms +	 */ + +	bs->bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100), +						 conf->intval)); +	if (bs->bs_sleepduration > bs->bs_dtimperiod) +		bs->bs_sleepduration = bs->bs_dtimperiod; + +	/* TSF out of range threshold fixed at 1 second */ +	bs->bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; + +	ath_dbg(common, BEACON, "bmiss: %u sleep: %u\n", +		bs->bs_bmissthreshold, bs->bs_sleepduration); +	return 0; +} +EXPORT_SYMBOL(ath9k_cmn_beacon_config_sta); + +void ath9k_cmn_beacon_config_adhoc(struct ath_hw *ah, +				   struct ath_beacon_config *conf) +{ +	struct ath_common *common = ath9k_hw_common(ah); + +	conf->intval = TU_TO_USEC(conf->beacon_interval); + +	if (conf->ibss_creator) +		conf->nexttbtt = conf->intval; +	else +		conf->nexttbtt = ath9k_get_next_tbtt(ah, ath9k_hw_gettsf64(ah), +					       conf->beacon_interval); + +	if (conf->enable_beacon) +		ah->imask |= ATH9K_INT_SWBA; +	else +		ah->imask &= ~ATH9K_INT_SWBA; + +	ath_dbg(common, BEACON, +		"IBSS (%s) nexttbtt: %u intval: %u conf_intval: %u\n", +		(conf->enable_beacon) ? "Enable" : "Disable", +		conf->nexttbtt, conf->intval, conf->beacon_interval); +} +EXPORT_SYMBOL(ath9k_cmn_beacon_config_adhoc); + +/* + * For multi-bss ap support beacons are either staggered evenly over N slots or + * burst together.  For the former arrange for the SWBA to be delivered for each + * slot. Slots that are not occupied will generate nothing. + */ +void ath9k_cmn_beacon_config_ap(struct ath_hw *ah, +				struct ath_beacon_config *conf, +				unsigned int bc_buf) +{ +	struct ath_common *common = ath9k_hw_common(ah); + +	/* NB: the beacon interval is kept internally in TU's */ +	conf->intval = TU_TO_USEC(conf->beacon_interval); +	conf->intval /= bc_buf; +	conf->nexttbtt = ath9k_get_next_tbtt(ah, ath9k_hw_gettsf64(ah), +				       conf->beacon_interval); + +	if (conf->enable_beacon) +		ah->imask |= ATH9K_INT_SWBA; +	else +		ah->imask &= ~ATH9K_INT_SWBA; + +	ath_dbg(common, BEACON, +		"AP (%s) nexttbtt: %u intval: %u conf_intval: %u\n", +		(conf->enable_beacon) ? "Enable" : "Disable", +		conf->nexttbtt, conf->intval, conf->beacon_interval); +} +EXPORT_SYMBOL(ath9k_cmn_beacon_config_ap); diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.h b/drivers/net/wireless/ath/ath9k/common-beacon.h new file mode 100644 index 00000000000..3665d27f0dc --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-beacon.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2009-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +struct ath_beacon_config; + +int ath9k_cmn_beacon_config_sta(struct ath_hw *ah, +				struct ath_beacon_config *conf, +				struct ath9k_beacon_state *bs); +void ath9k_cmn_beacon_config_adhoc(struct ath_hw *ah, +				   struct ath_beacon_config *conf); +void ath9k_cmn_beacon_config_ap(struct ath_hw *ah, +				struct ath_beacon_config *conf, +				unsigned int bc_buf); diff --git a/drivers/net/wireless/ath/ath9k/common-debug.c b/drivers/net/wireless/ath/ath9k/common-debug.c new file mode 100644 index 00000000000..3b289f93340 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-debug.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2008-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "common.h" + +static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf, +				      size_t count, loff_t *ppos) +{ +	struct ath_hw *ah = file->private_data; +	u32 len = 0, size = 6000; +	char *buf; +	size_t retval; + +	buf = kzalloc(size, GFP_KERNEL); +	if (buf == NULL) +		return -ENOMEM; + +	len = ah->eep_ops->dump_eeprom(ah, false, buf, len, size); + +	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); +	kfree(buf); + +	return retval; +} + +static const struct file_operations fops_modal_eeprom = { +	.read = read_file_modal_eeprom, +	.open = simple_open, +	.owner = THIS_MODULE, +	.llseek = default_llseek, +}; + + +void ath9k_cmn_debug_modal_eeprom(struct dentry *debugfs_phy, +				  struct ath_hw *ah) +{ +	debugfs_create_file("modal_eeprom", S_IRUSR, debugfs_phy, ah, +			    &fops_modal_eeprom); +} +EXPORT_SYMBOL(ath9k_cmn_debug_modal_eeprom); + +static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf, +				     size_t count, loff_t *ppos) +{ +	struct ath_hw *ah = file->private_data; +	u32 len = 0, size = 1500; +	ssize_t retval = 0; +	char *buf; + +	buf = kzalloc(size, GFP_KERNEL); +	if (!buf) +		return -ENOMEM; + +	len = ah->eep_ops->dump_eeprom(ah, true, buf, len, size); + +	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); +	kfree(buf); + +	return retval; +} + +static const struct file_operations fops_base_eeprom = { +	.read = read_file_base_eeprom, +	.open = simple_open, +	.owner = THIS_MODULE, +	.llseek = default_llseek, +}; + +void ath9k_cmn_debug_base_eeprom(struct dentry *debugfs_phy, +				 struct ath_hw *ah) +{ +	debugfs_create_file("base_eeprom", S_IRUSR, debugfs_phy, ah, +			    &fops_base_eeprom); +} +EXPORT_SYMBOL(ath9k_cmn_debug_base_eeprom); + +void ath9k_cmn_debug_stat_rx(struct ath_rx_stats *rxstats, +			     struct ath_rx_status *rs) +{ +#define RX_PHY_ERR_INC(c) rxstats->phy_err_stats[c]++ +#define RX_CMN_STAT_INC(c) (rxstats->c++) + +	RX_CMN_STAT_INC(rx_pkts_all); +	rxstats->rx_bytes_all += rs->rs_datalen; + +	if (rs->rs_status & ATH9K_RXERR_CRC) +		RX_CMN_STAT_INC(crc_err); +	if (rs->rs_status & ATH9K_RXERR_DECRYPT) +		RX_CMN_STAT_INC(decrypt_crc_err); +	if (rs->rs_status & ATH9K_RXERR_MIC) +		RX_CMN_STAT_INC(mic_err); +	if (rs->rs_status & ATH9K_RX_DELIM_CRC_PRE) +		RX_CMN_STAT_INC(pre_delim_crc_err); +	if (rs->rs_status & ATH9K_RX_DELIM_CRC_POST) +		RX_CMN_STAT_INC(post_delim_crc_err); +	if (rs->rs_status & ATH9K_RX_DECRYPT_BUSY) +		RX_CMN_STAT_INC(decrypt_busy_err); + +	if (rs->rs_status & ATH9K_RXERR_PHY) { +		RX_CMN_STAT_INC(phy_err); +		if (rs->rs_phyerr < ATH9K_PHYERR_MAX) +			RX_PHY_ERR_INC(rs->rs_phyerr); +	} + +#undef RX_CMN_STAT_INC +#undef RX_PHY_ERR_INC +} +EXPORT_SYMBOL(ath9k_cmn_debug_stat_rx); + +static ssize_t read_file_recv(struct file *file, char __user *user_buf, +			      size_t count, loff_t *ppos) +{ +#define RXS_ERR(s, e)					\ +	do {						\ +		len += scnprintf(buf + len, size - len,	\ +				 "%18s : %10u\n", s,	\ +				 rxstats->e);		\ +	} while (0) + +	struct ath_rx_stats *rxstats = file->private_data; +	char *buf; +	unsigned int len = 0, size = 1600; +	ssize_t retval = 0; + +	buf = kzalloc(size, GFP_KERNEL); +	if (buf == NULL) +		return -ENOMEM; + +	RXS_ERR("PKTS-ALL", rx_pkts_all); +	RXS_ERR("BYTES-ALL", rx_bytes_all); +	RXS_ERR("BEACONS", rx_beacons); +	RXS_ERR("FRAGS", rx_frags); +	RXS_ERR("SPECTRAL", rx_spectral); + +	RXS_ERR("CRC ERR", crc_err); +	RXS_ERR("DECRYPT CRC ERR", decrypt_crc_err); +	RXS_ERR("PHY ERR", phy_err); +	RXS_ERR("MIC ERR", mic_err); +	RXS_ERR("PRE-DELIM CRC ERR", pre_delim_crc_err); +	RXS_ERR("POST-DELIM CRC ERR", post_delim_crc_err); +	RXS_ERR("DECRYPT BUSY ERR", decrypt_busy_err); +	RXS_ERR("LENGTH-ERR", rx_len_err); +	RXS_ERR("OOM-ERR", rx_oom_err); +	RXS_ERR("RATE-ERR", rx_rate_err); +	RXS_ERR("TOO-MANY-FRAGS", rx_too_many_frags_err); + +	if (len > size) +		len = size; + +	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); +	kfree(buf); + +	return retval; + +#undef RXS_ERR +} + +static const struct file_operations fops_recv = { +	.read = read_file_recv, +	.open = simple_open, +	.owner = THIS_MODULE, +	.llseek = default_llseek, +}; + +void ath9k_cmn_debug_recv(struct dentry *debugfs_phy, +			  struct ath_rx_stats *rxstats) +{ +	debugfs_create_file("recv", S_IRUSR, debugfs_phy, rxstats, +			    &fops_recv); +} +EXPORT_SYMBOL(ath9k_cmn_debug_recv); + +static ssize_t read_file_phy_err(struct file *file, char __user *user_buf, +				 size_t count, loff_t *ppos) +{ +#define PHY_ERR(s, p) \ +	len += scnprintf(buf + len, size - len, "%22s : %10u\n", s, \ +			 rxstats->phy_err_stats[p]); + +	struct ath_rx_stats *rxstats = file->private_data; +	char *buf; +	unsigned int len = 0, size = 1600; +	ssize_t retval = 0; + +	buf = kzalloc(size, GFP_KERNEL); +	if (buf == NULL) +		return -ENOMEM; + +	PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN); +	PHY_ERR("TIMING ERR", ATH9K_PHYERR_TIMING); +	PHY_ERR("PARITY ERR", ATH9K_PHYERR_PARITY); +	PHY_ERR("RATE ERR", ATH9K_PHYERR_RATE); +	PHY_ERR("LENGTH ERR", ATH9K_PHYERR_LENGTH); +	PHY_ERR("RADAR ERR", ATH9K_PHYERR_RADAR); +	PHY_ERR("SERVICE ERR", ATH9K_PHYERR_SERVICE); +	PHY_ERR("TOR ERR", ATH9K_PHYERR_TOR); +	PHY_ERR("OFDM-TIMING ERR", ATH9K_PHYERR_OFDM_TIMING); +	PHY_ERR("OFDM-SIGNAL-PARITY ERR", ATH9K_PHYERR_OFDM_SIGNAL_PARITY); +	PHY_ERR("OFDM-RATE ERR", ATH9K_PHYERR_OFDM_RATE_ILLEGAL); +	PHY_ERR("OFDM-LENGTH ERR", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL); +	PHY_ERR("OFDM-POWER-DROP ERR", ATH9K_PHYERR_OFDM_POWER_DROP); +	PHY_ERR("OFDM-SERVICE ERR", ATH9K_PHYERR_OFDM_SERVICE); +	PHY_ERR("OFDM-RESTART ERR", ATH9K_PHYERR_OFDM_RESTART); +	PHY_ERR("FALSE-RADAR-EXT ERR", ATH9K_PHYERR_FALSE_RADAR_EXT); +	PHY_ERR("CCK-TIMING ERR", ATH9K_PHYERR_CCK_TIMING); +	PHY_ERR("CCK-HEADER-CRC ERR", ATH9K_PHYERR_CCK_HEADER_CRC); +	PHY_ERR("CCK-RATE ERR", ATH9K_PHYERR_CCK_RATE_ILLEGAL); +	PHY_ERR("CCK-SERVICE ERR", ATH9K_PHYERR_CCK_SERVICE); +	PHY_ERR("CCK-RESTART ERR", ATH9K_PHYERR_CCK_RESTART); +	PHY_ERR("CCK-LENGTH ERR", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL); +	PHY_ERR("CCK-POWER-DROP ERR", ATH9K_PHYERR_CCK_POWER_DROP); +	PHY_ERR("HT-CRC ERR", ATH9K_PHYERR_HT_CRC_ERROR); +	PHY_ERR("HT-LENGTH ERR", ATH9K_PHYERR_HT_LENGTH_ILLEGAL); +	PHY_ERR("HT-RATE ERR", ATH9K_PHYERR_HT_RATE_ILLEGAL); + +	if (len > size) +		len = size; + +	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); +	kfree(buf); + +	return retval; + +#undef PHY_ERR +} + +static const struct file_operations fops_phy_err = { +	.read = read_file_phy_err, +	.open = simple_open, +	.owner = THIS_MODULE, +	.llseek = default_llseek, +}; + +void ath9k_cmn_debug_phy_err(struct dentry *debugfs_phy, +			     struct ath_rx_stats *rxstats) +{ +	debugfs_create_file("phy_err", S_IRUSR, debugfs_phy, rxstats, +			    &fops_phy_err); +} +EXPORT_SYMBOL(ath9k_cmn_debug_phy_err); diff --git a/drivers/net/wireless/ath/ath9k/common-debug.h b/drivers/net/wireless/ath/ath9k/common-debug.h new file mode 100644 index 00000000000..7c9788490f7 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-debug.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2008-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + + +/** + * struct ath_rx_stats - RX Statistics + * @rx_pkts_all:  No. of total frames received, including ones that +	may have had errors. + * @rx_bytes_all:  No. of total bytes received, including ones that +	may have had errors. + * @crc_err: No. of frames with incorrect CRC value + * @decrypt_crc_err: No. of frames whose CRC check failed after +	decryption process completed + * @phy_err: No. of frames whose reception failed because the PHY +	encountered an error + * @mic_err: No. of frames with incorrect TKIP MIC verification failure + * @pre_delim_crc_err: Pre-Frame delimiter CRC error detections + * @post_delim_crc_err: Post-Frame delimiter CRC error detections + * @decrypt_busy_err: Decryption interruptions counter + * @phy_err_stats: Individual PHY error statistics + * @rx_len_err:  No. of frames discarded due to bad length. + * @rx_oom_err:  No. of frames dropped due to OOM issues. + * @rx_rate_err:  No. of frames dropped due to rate errors. + * @rx_too_many_frags_err:  Frames dropped due to too-many-frags received. + * @rx_beacons:  No. of beacons received. + * @rx_frags:  No. of rx-fragements received. + * @rx_spectral: No of spectral packets received. + */ +struct ath_rx_stats { +	u32 rx_pkts_all; +	u32 rx_bytes_all; +	u32 crc_err; +	u32 decrypt_crc_err; +	u32 phy_err; +	u32 mic_err; +	u32 pre_delim_crc_err; +	u32 post_delim_crc_err; +	u32 decrypt_busy_err; +	u32 phy_err_stats[ATH9K_PHYERR_MAX]; +	u32 rx_len_err; +	u32 rx_oom_err; +	u32 rx_rate_err; +	u32 rx_too_many_frags_err; +	u32 rx_beacons; +	u32 rx_frags; +	u32 rx_spectral; +}; + +void ath9k_cmn_debug_modal_eeprom(struct dentry *debugfs_phy, +				  struct ath_hw *ah); +void ath9k_cmn_debug_base_eeprom(struct dentry *debugfs_phy, +				 struct ath_hw *ah); +void ath9k_cmn_debug_stat_rx(struct ath_rx_stats *rxstats, +			     struct ath_rx_status *rs); +void ath9k_cmn_debug_recv(struct dentry *debugfs_phy, +			  struct ath_rx_stats *rxstats); +void ath9k_cmn_debug_phy_err(struct dentry *debugfs_phy, +			     struct ath_rx_stats *rxstats); diff --git a/drivers/net/wireless/ath/ath9k/common-init.c b/drivers/net/wireless/ath/ath9k/common-init.c new file mode 100644 index 00000000000..a006c149972 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-init.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2008-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* We use the hw_value as an index into our private channel structure */ + +#include "common.h" + +#define CHAN2G(_freq, _idx)  { \ +	.band = IEEE80211_BAND_2GHZ, \ +	.center_freq = (_freq), \ +	.hw_value = (_idx), \ +	.max_power = 20, \ +} + +#define CHAN5G(_freq, _idx) { \ +	.band = IEEE80211_BAND_5GHZ, \ +	.center_freq = (_freq), \ +	.hw_value = (_idx), \ +	.max_power = 20, \ +} + +/* Some 2 GHz radios are actually tunable on 2312-2732 + * on 5 MHz steps, we support the channels which we know + * we have calibration data for all cards though to make + * this static */ +static const struct ieee80211_channel ath9k_2ghz_chantable[] = { +	CHAN2G(2412, 0), /* Channel 1 */ +	CHAN2G(2417, 1), /* Channel 2 */ +	CHAN2G(2422, 2), /* Channel 3 */ +	CHAN2G(2427, 3), /* Channel 4 */ +	CHAN2G(2432, 4), /* Channel 5 */ +	CHAN2G(2437, 5), /* Channel 6 */ +	CHAN2G(2442, 6), /* Channel 7 */ +	CHAN2G(2447, 7), /* Channel 8 */ +	CHAN2G(2452, 8), /* Channel 9 */ +	CHAN2G(2457, 9), /* Channel 10 */ +	CHAN2G(2462, 10), /* Channel 11 */ +	CHAN2G(2467, 11), /* Channel 12 */ +	CHAN2G(2472, 12), /* Channel 13 */ +	CHAN2G(2484, 13), /* Channel 14 */ +}; + +/* Some 5 GHz radios are actually tunable on XXXX-YYYY + * on 5 MHz steps, we support the channels which we know + * we have calibration data for all cards though to make + * this static */ +static const struct ieee80211_channel ath9k_5ghz_chantable[] = { +	/* _We_ call this UNII 1 */ +	CHAN5G(5180, 14), /* Channel 36 */ +	CHAN5G(5200, 15), /* Channel 40 */ +	CHAN5G(5220, 16), /* Channel 44 */ +	CHAN5G(5240, 17), /* Channel 48 */ +	/* _We_ call this UNII 2 */ +	CHAN5G(5260, 18), /* Channel 52 */ +	CHAN5G(5280, 19), /* Channel 56 */ +	CHAN5G(5300, 20), /* Channel 60 */ +	CHAN5G(5320, 21), /* Channel 64 */ +	/* _We_ call this "Middle band" */ +	CHAN5G(5500, 22), /* Channel 100 */ +	CHAN5G(5520, 23), /* Channel 104 */ +	CHAN5G(5540, 24), /* Channel 108 */ +	CHAN5G(5560, 25), /* Channel 112 */ +	CHAN5G(5580, 26), /* Channel 116 */ +	CHAN5G(5600, 27), /* Channel 120 */ +	CHAN5G(5620, 28), /* Channel 124 */ +	CHAN5G(5640, 29), /* Channel 128 */ +	CHAN5G(5660, 30), /* Channel 132 */ +	CHAN5G(5680, 31), /* Channel 136 */ +	CHAN5G(5700, 32), /* Channel 140 */ +	/* _We_ call this UNII 3 */ +	CHAN5G(5745, 33), /* Channel 149 */ +	CHAN5G(5765, 34), /* Channel 153 */ +	CHAN5G(5785, 35), /* Channel 157 */ +	CHAN5G(5805, 36), /* Channel 161 */ +	CHAN5G(5825, 37), /* Channel 165 */ +}; + +/* Atheros hardware rate code addition for short premble */ +#define SHPCHECK(__hw_rate, __flags) \ +	((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0) + +#define RATE(_bitrate, _hw_rate, _flags) {              \ +	.bitrate        = (_bitrate),                   \ +	.flags          = (_flags),                     \ +	.hw_value       = (_hw_rate),                   \ +	.hw_value_short = (SHPCHECK(_hw_rate, _flags))  \ +} + +static struct ieee80211_rate ath9k_legacy_rates[] = { +	RATE(10, 0x1b, 0), +	RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), +	RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), +	RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), +	RATE(60, 0x0b, (IEEE80211_RATE_SUPPORTS_5MHZ | +			IEEE80211_RATE_SUPPORTS_10MHZ)), +	RATE(90, 0x0f, (IEEE80211_RATE_SUPPORTS_5MHZ | +			IEEE80211_RATE_SUPPORTS_10MHZ)), +	RATE(120, 0x0a, (IEEE80211_RATE_SUPPORTS_5MHZ | +			 IEEE80211_RATE_SUPPORTS_10MHZ)), +	RATE(180, 0x0e, (IEEE80211_RATE_SUPPORTS_5MHZ | +			 IEEE80211_RATE_SUPPORTS_10MHZ)), +	RATE(240, 0x09, (IEEE80211_RATE_SUPPORTS_5MHZ | +			 IEEE80211_RATE_SUPPORTS_10MHZ)), +	RATE(360, 0x0d, (IEEE80211_RATE_SUPPORTS_5MHZ | +			 IEEE80211_RATE_SUPPORTS_10MHZ)), +	RATE(480, 0x08, (IEEE80211_RATE_SUPPORTS_5MHZ | +			 IEEE80211_RATE_SUPPORTS_10MHZ)), +	RATE(540, 0x0c, (IEEE80211_RATE_SUPPORTS_5MHZ | +			 IEEE80211_RATE_SUPPORTS_10MHZ)), +}; + +int ath9k_cmn_init_channels_rates(struct ath_common *common) +{ +	struct ath_hw *ah = (struct ath_hw *)common->ah; +	void *channels; + +	BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) + +		     ARRAY_SIZE(ath9k_5ghz_chantable) != +		     ATH9K_NUM_CHANNELS); + +	if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) { +		channels = devm_kzalloc(ah->dev, +			sizeof(ath9k_2ghz_chantable), GFP_KERNEL); +		if (!channels) +		    return -ENOMEM; + +		memcpy(channels, ath9k_2ghz_chantable, +		       sizeof(ath9k_2ghz_chantable)); +		common->sbands[IEEE80211_BAND_2GHZ].channels = channels; +		common->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; +		common->sbands[IEEE80211_BAND_2GHZ].n_channels = +			ARRAY_SIZE(ath9k_2ghz_chantable); +		common->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; +		common->sbands[IEEE80211_BAND_2GHZ].n_bitrates = +			ARRAY_SIZE(ath9k_legacy_rates); +	} + +	if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) { +		channels = devm_kzalloc(ah->dev, +			sizeof(ath9k_5ghz_chantable), GFP_KERNEL); +		if (!channels) +			return -ENOMEM; + +		memcpy(channels, ath9k_5ghz_chantable, +		       sizeof(ath9k_5ghz_chantable)); +		common->sbands[IEEE80211_BAND_5GHZ].channels = channels; +		common->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; +		common->sbands[IEEE80211_BAND_5GHZ].n_channels = +			ARRAY_SIZE(ath9k_5ghz_chantable); +		common->sbands[IEEE80211_BAND_5GHZ].bitrates = +			ath9k_legacy_rates + 4; +		common->sbands[IEEE80211_BAND_5GHZ].n_bitrates = +			ARRAY_SIZE(ath9k_legacy_rates) - 4; +	} +	return 0; +} +EXPORT_SYMBOL(ath9k_cmn_init_channels_rates); + +void ath9k_cmn_setup_ht_cap(struct ath_hw *ah, +			    struct ieee80211_sta_ht_cap *ht_info) +{ +	struct ath_common *common = ath9k_hw_common(ah); +	u8 tx_streams, rx_streams; +	int i, max_streams; + +	ht_info->ht_supported = true; +	ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | +		       IEEE80211_HT_CAP_SM_PS | +		       IEEE80211_HT_CAP_SGI_40 | +		       IEEE80211_HT_CAP_DSSSCCK40; + +	if (ah->caps.hw_caps & ATH9K_HW_CAP_LDPC) +		ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; + +	if (ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20) +		ht_info->cap |= IEEE80211_HT_CAP_SGI_20; + +	ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; +	ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; + +	if (AR_SREV_9271(ah) || AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah)) +		max_streams = 1; +	else if (AR_SREV_9462(ah)) +		max_streams = 2; +	else if (AR_SREV_9300_20_OR_LATER(ah)) +		max_streams = 3; +	else +		max_streams = 2; + +	if (AR_SREV_9280_20_OR_LATER(ah)) { +		if (max_streams >= 2) +			ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; +		ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); +	} + +	/* set up supported mcs set */ +	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); +	tx_streams = ath9k_cmn_count_streams(ah->txchainmask, max_streams); +	rx_streams = ath9k_cmn_count_streams(ah->rxchainmask, max_streams); + +	ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n", +		tx_streams, rx_streams); + +	if (tx_streams != rx_streams) { +		ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; +		ht_info->mcs.tx_params |= ((tx_streams - 1) << +				IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); +	} + +	for (i = 0; i < rx_streams; i++) +		ht_info->mcs.rx_mask[i] = 0xff; + +	ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; +} +EXPORT_SYMBOL(ath9k_cmn_setup_ht_cap); + +void ath9k_cmn_reload_chainmask(struct ath_hw *ah) +{ +	struct ath_common *common = ath9k_hw_common(ah); + +	if (!(ah->caps.hw_caps & ATH9K_HW_CAP_HT)) +		return; + +	if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) +		ath9k_cmn_setup_ht_cap(ah, +			&common->sbands[IEEE80211_BAND_2GHZ].ht_cap); +	if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) +		ath9k_cmn_setup_ht_cap(ah, +			&common->sbands[IEEE80211_BAND_5GHZ].ht_cap); +} +EXPORT_SYMBOL(ath9k_cmn_reload_chainmask); diff --git a/drivers/net/wireless/ath/ath9k/common-init.h b/drivers/net/wireless/ath/ath9k/common-init.h new file mode 100644 index 00000000000..ac03fca5ffd --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-init.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2009-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +int ath9k_cmn_init_channels_rates(struct ath_common *common); +void ath9k_cmn_setup_ht_cap(struct ath_hw *ah, +			    struct ieee80211_sta_ht_cap *ht_info); +void ath9k_cmn_reload_chainmask(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index d3063c21e16..c6dd7f1fed6 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -27,6 +27,250 @@ MODULE_AUTHOR("Atheros Communications");  MODULE_DESCRIPTION("Shared library for Atheros wireless 802.11n LAN cards.");  MODULE_LICENSE("Dual BSD/GPL"); +/* Assumes you've already done the endian to CPU conversion */ +bool ath9k_cmn_rx_accept(struct ath_common *common, +			 struct ieee80211_hdr *hdr, +			 struct ieee80211_rx_status *rxs, +			 struct ath_rx_status *rx_stats, +			 bool *decrypt_error, +			 unsigned int rxfilter) +{ +	struct ath_hw *ah = common->ah; +	bool is_mc, is_valid_tkip, strip_mic, mic_error; +	__le16 fc; + +	fc = hdr->frame_control; + +	is_mc = !!is_multicast_ether_addr(hdr->addr1); +	is_valid_tkip = rx_stats->rs_keyix != ATH9K_RXKEYIX_INVALID && +		test_bit(rx_stats->rs_keyix, common->tkip_keymap); +	strip_mic = is_valid_tkip && ieee80211_is_data(fc) && +		ieee80211_has_protected(fc) && +		!(rx_stats->rs_status & +		(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC | +		 ATH9K_RXERR_KEYMISS)); + +	/* +	 * Key miss events are only relevant for pairwise keys where the +	 * descriptor does contain a valid key index. This has been observed +	 * mostly with CCMP encryption. +	 */ +	if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID || +	    !test_bit(rx_stats->rs_keyix, common->ccmp_keymap)) +		rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS; + +	mic_error = is_valid_tkip && !ieee80211_is_ctl(fc) && +		!ieee80211_has_morefrags(fc) && +		!(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) && +		(rx_stats->rs_status & ATH9K_RXERR_MIC); + +	/* +	 * The rx_stats->rs_status will not be set until the end of the +	 * chained descriptors so it can be ignored if rs_more is set. The +	 * rs_more will be false at the last element of the chained +	 * descriptors. +	 */ +	if (rx_stats->rs_status != 0) { +		u8 status_mask; + +		if (rx_stats->rs_status & ATH9K_RXERR_CRC) { +			rxs->flag |= RX_FLAG_FAILED_FCS_CRC; +			mic_error = false; +		} + +		if ((rx_stats->rs_status & ATH9K_RXERR_DECRYPT) || +		    (!is_mc && (rx_stats->rs_status & ATH9K_RXERR_KEYMISS))) { +			*decrypt_error = true; +			mic_error = false; +		} + + +		/* +		 * Reject error frames with the exception of +		 * decryption and MIC failures. For monitor mode, +		 * we also ignore the CRC error. +		 */ +		status_mask = ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | +			      ATH9K_RXERR_KEYMISS; + +		if (ah->is_monitoring && (rxfilter & FIF_FCSFAIL)) +			status_mask |= ATH9K_RXERR_CRC; + +		if (rx_stats->rs_status & ~status_mask) +			return false; +	} + +	/* +	 * For unicast frames the MIC error bit can have false positives, +	 * so all MIC error reports need to be validated in software. +	 * False negatives are not common, so skip software verification +	 * if the hardware considers the MIC valid. +	 */ +	if (strip_mic) +		rxs->flag |= RX_FLAG_MMIC_STRIPPED; +	else if (is_mc && mic_error) +		rxs->flag |= RX_FLAG_MMIC_ERROR; + +	return true; +} +EXPORT_SYMBOL(ath9k_cmn_rx_accept); + +void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, +				  struct sk_buff *skb, +				  struct ath_rx_status *rx_stats, +				  struct ieee80211_rx_status *rxs, +				  bool decrypt_error) +{ +	struct ath_hw *ah = common->ah; +	struct ieee80211_hdr *hdr; +	int hdrlen, padpos, padsize; +	u8 keyix; +	__le16 fc; + +	/* see if any padding is done by the hw and remove it */ +	hdr = (struct ieee80211_hdr *) skb->data; +	hdrlen = ieee80211_get_hdrlen_from_skb(skb); +	fc = hdr->frame_control; +	padpos = ieee80211_hdrlen(fc); + +	/* The MAC header is padded to have 32-bit boundary if the +	 * packet payload is non-zero. The general calculation for +	 * padsize would take into account odd header lengths: +	 * padsize = (4 - padpos % 4) % 4; However, since only +	 * even-length headers are used, padding can only be 0 or 2 +	 * bytes and we can optimize this a bit. In addition, we must +	 * not try to remove padding from short control frames that do +	 * not have payload. */ +	padsize = padpos & 3; +	if (padsize && skb->len>=padpos+padsize+FCS_LEN) { +		memmove(skb->data + padsize, skb->data, padpos); +		skb_pull(skb, padsize); +	} + +	keyix = rx_stats->rs_keyix; + +	if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error && +	    ieee80211_has_protected(fc)) { +		rxs->flag |= RX_FLAG_DECRYPTED; +	} else if (ieee80211_has_protected(fc) +		   && !decrypt_error && skb->len >= hdrlen + 4) { +		keyix = skb->data[hdrlen + 3] >> 6; + +		if (test_bit(keyix, common->keymap)) +			rxs->flag |= RX_FLAG_DECRYPTED; +	} +	if (ah->sw_mgmt_crypto && +	    (rxs->flag & RX_FLAG_DECRYPTED) && +	    ieee80211_is_mgmt(fc)) +		/* Use software decrypt for management frames. */ +		rxs->flag &= ~RX_FLAG_DECRYPTED; +} +EXPORT_SYMBOL(ath9k_cmn_rx_skb_postprocess); + +int ath9k_cmn_process_rate(struct ath_common *common, +			   struct ieee80211_hw *hw, +			   struct ath_rx_status *rx_stats, +			   struct ieee80211_rx_status *rxs) +{ +	struct ieee80211_supported_band *sband; +	enum ieee80211_band band; +	unsigned int i = 0; +	struct ath_hw *ah = common->ah; + +	band = ah->curchan->chan->band; +	sband = hw->wiphy->bands[band]; + +	if (IS_CHAN_QUARTER_RATE(ah->curchan)) +		rxs->flag |= RX_FLAG_5MHZ; +	else if (IS_CHAN_HALF_RATE(ah->curchan)) +		rxs->flag |= RX_FLAG_10MHZ; + +	if (rx_stats->rs_rate & 0x80) { +		/* HT rate */ +		rxs->flag |= RX_FLAG_HT; +		rxs->flag |= rx_stats->flag; +		rxs->rate_idx = rx_stats->rs_rate & 0x7f; +		return 0; +	} + +	for (i = 0; i < sband->n_bitrates; i++) { +		if (sband->bitrates[i].hw_value == rx_stats->rs_rate) { +			rxs->rate_idx = i; +			return 0; +		} +		if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) { +			rxs->flag |= RX_FLAG_SHORTPRE; +			rxs->rate_idx = i; +			return 0; +		} +	} + +	return -EINVAL; +} +EXPORT_SYMBOL(ath9k_cmn_process_rate); + +void ath9k_cmn_process_rssi(struct ath_common *common, +			    struct ieee80211_hw *hw, +			    struct ath_rx_status *rx_stats, +			    struct ieee80211_rx_status *rxs) +{ +	struct ath_hw *ah = common->ah; +	int last_rssi; +	int rssi = rx_stats->rs_rssi; +	int i, j; + +	/* +	 * RSSI is not available for subframes in an A-MPDU. +	 */ +	if (rx_stats->rs_moreaggr) { +		rxs->flag |= RX_FLAG_NO_SIGNAL_VAL; +		return; +	} + +	/* +	 * Check if the RSSI for the last subframe in an A-MPDU +	 * or an unaggregated frame is valid. +	 */ +	if (rx_stats->rs_rssi == ATH9K_RSSI_BAD) { +		rxs->flag |= RX_FLAG_NO_SIGNAL_VAL; +		return; +	} + +	for (i = 0, j = 0; i < ARRAY_SIZE(rx_stats->rs_rssi_ctl); i++) { +		s8 rssi; + +		if (!(ah->rxchainmask & BIT(i))) +			continue; + +		rssi = rx_stats->rs_rssi_ctl[i]; +		if (rssi != ATH9K_RSSI_BAD) { +		    rxs->chains |= BIT(j); +		    rxs->chain_signal[j] = ah->noise + rssi; +		} +		j++; +	} + +	/* +	 * Update Beacon RSSI, this is used by ANI. +	 */ +	if (rx_stats->is_mybeacon && +	    ((ah->opmode == NL80211_IFTYPE_STATION) || +	     (ah->opmode == NL80211_IFTYPE_ADHOC))) { +		ATH_RSSI_LPF(common->last_rssi, rx_stats->rs_rssi); +		last_rssi = common->last_rssi; + +		if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) +			rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); +		if (rssi < 0) +			rssi = 0; + +		ah->stats.avgbrssi = rssi; +	} + +	rxs->signal = ah->noise + rx_stats->rs_rssi; +} +EXPORT_SYMBOL(ath9k_cmn_process_rssi); +  int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb)  {  	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); @@ -49,103 +293,62 @@ int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb)  }  EXPORT_SYMBOL(ath9k_cmn_get_hw_crypto_keytype); -static u32 ath9k_get_extchanmode(struct cfg80211_chan_def *chandef) -{ -	u32 chanmode = 0; - -	switch (chandef->chan->band) { -	case IEEE80211_BAND_2GHZ: -		switch (chandef->width) { -		case NL80211_CHAN_WIDTH_20_NOHT: -		case NL80211_CHAN_WIDTH_20: -			chanmode = CHANNEL_G_HT20; -			break; -		case NL80211_CHAN_WIDTH_40: -			if (chandef->center_freq1 > chandef->chan->center_freq) -				chanmode = CHANNEL_G_HT40PLUS; -			else -				chanmode = CHANNEL_G_HT40MINUS; -			break; -		default: -			break; -		} -		break; -	case IEEE80211_BAND_5GHZ: -		switch (chandef->width) { -		case NL80211_CHAN_WIDTH_20_NOHT: -		case NL80211_CHAN_WIDTH_20: -			chanmode = CHANNEL_A_HT20; -			break; -		case NL80211_CHAN_WIDTH_40: -			if (chandef->center_freq1 > chandef->chan->center_freq) -				chanmode = CHANNEL_A_HT40PLUS; -			else -				chanmode = CHANNEL_A_HT40MINUS; -			break; -		default: -			break; -		} -		break; -	default: -		break; -	} - -	return chanmode; -} -  /*   * Update internal channel flags.   */ -void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, -			       struct cfg80211_chan_def *chandef) +static void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, +				      struct cfg80211_chan_def *chandef)  { -	ichan->channel = chandef->chan->center_freq; -	ichan->chan = chandef->chan; - -	if (chandef->chan->band == IEEE80211_BAND_2GHZ) { -		ichan->chanmode = CHANNEL_G; -		ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM; -	} else { -		ichan->chanmode = CHANNEL_A; -		ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; -	} +	struct ieee80211_channel *chan = chandef->chan; +	u16 flags = 0; + +	ichan->channel = chan->center_freq; +	ichan->chan = chan; + +	if (chan->band == IEEE80211_BAND_5GHZ) +		flags |= CHANNEL_5GHZ;  	switch (chandef->width) {  	case NL80211_CHAN_WIDTH_5: -		ichan->channelFlags |= CHANNEL_QUARTER; +		flags |= CHANNEL_QUARTER;  		break;  	case NL80211_CHAN_WIDTH_10: -		ichan->channelFlags |= CHANNEL_HALF; +		flags |= CHANNEL_HALF;  		break;  	case NL80211_CHAN_WIDTH_20_NOHT:  		break;  	case NL80211_CHAN_WIDTH_20: +		flags |= CHANNEL_HT; +		break;  	case NL80211_CHAN_WIDTH_40: -		ichan->chanmode = ath9k_get_extchanmode(chandef); +		if (chandef->center_freq1 > chandef->chan->center_freq) +			flags |= CHANNEL_HT40PLUS | CHANNEL_HT; +		else +			flags |= CHANNEL_HT40MINUS | CHANNEL_HT;  		break;  	default:  		WARN_ON(1);  	} + +	ichan->channelFlags = flags;  } -EXPORT_SYMBOL(ath9k_cmn_update_ichannel);  /*   * Get the internal channel reference.   */ -struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw, -					       struct ath_hw *ah) +struct ath9k_channel *ath9k_cmn_get_channel(struct ieee80211_hw *hw, +					    struct ath_hw *ah, +					    struct cfg80211_chan_def *chandef)  { -	struct ieee80211_channel *curchan = hw->conf.chandef.chan; +	struct ieee80211_channel *curchan = chandef->chan;  	struct ath9k_channel *channel; -	u8 chan_idx; -	chan_idx = curchan->hw_value; -	channel = &ah->channels[chan_idx]; -	ath9k_cmn_update_ichannel(channel, &hw->conf.chandef); +	channel = &ah->channels[curchan->hw_value]; +	ath9k_cmn_update_ichannel(channel, chandef);  	return channel;  } -EXPORT_SYMBOL(ath9k_cmn_get_curchannel); +EXPORT_SYMBOL(ath9k_cmn_get_channel);  int ath9k_cmn_count_streams(unsigned int chainmask, int max)  { diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index e039bcbfbd7..ffc454b1863 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -21,6 +21,10 @@  #include "hw.h"  #include "hw-ops.h" +#include "common-init.h" +#include "common-beacon.h" +#include "common-debug.h" +  /* Common header for Atheros 802.11n base driver cores */  #define WME_BA_BMP_SIZE         64 @@ -42,11 +46,42 @@  #define ATH_EP_RND(x, mul) 						\  	(((x) + ((mul)/2)) / (mul)) +#define IEEE80211_MS_TO_TU(x)   (((x) * 1000) / 1024) + +struct ath_beacon_config { +	int beacon_interval; +	u16 dtim_period; +	u16 bmiss_timeout; +	u8 dtim_count; +	bool enable_beacon; +	bool ibss_creator; +	u32 nexttbtt; +	u32 intval; +}; + +bool ath9k_cmn_rx_accept(struct ath_common *common, +			 struct ieee80211_hdr *hdr, +			 struct ieee80211_rx_status *rxs, +			 struct ath_rx_status *rx_stats, +			 bool *decrypt_error, +			 unsigned int rxfilter); +void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, +				  struct sk_buff *skb, +				  struct ath_rx_status *rx_stats, +				  struct ieee80211_rx_status *rxs, +				  bool decrypt_error); +int ath9k_cmn_process_rate(struct ath_common *common, +			   struct ieee80211_hw *hw, +			   struct ath_rx_status *rx_stats, +			   struct ieee80211_rx_status *rxs); +void ath9k_cmn_process_rssi(struct ath_common *common, +			    struct ieee80211_hw *hw, +			    struct ath_rx_status *rx_stats, +			    struct ieee80211_rx_status *rxs);  int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb); -void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, -			       struct cfg80211_chan_def *chandef); -struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw, -					       struct ath_hw *ah); +struct ath9k_channel *ath9k_cmn_get_channel(struct ieee80211_hw *hw, +					    struct ath_hw *ah, +					    struct cfg80211_chan_def *chandef);  int ath9k_cmn_count_streams(unsigned int chainmask, int max);  void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common,  				  enum ath_stomp_type stomp_type); diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index c088744a6bf..6cc42be48d4 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -17,7 +17,6 @@  #include <linux/slab.h>  #include <linux/vmalloc.h>  #include <linux/export.h> -#include <linux/relay.h>  #include <asm/unaligned.h>  #include "ath9k.h" @@ -27,6 +26,47 @@  #define REG_READ_D(_ah, _reg) \  	ath9k_hw_common(_ah)->ops->read((_ah), (_reg)) +void ath9k_debug_sync_cause(struct ath_softc *sc, u32 sync_cause) +{ +	if (sync_cause) +		sc->debug.stats.istats.sync_cause_all++; +	if (sync_cause & AR_INTR_SYNC_RTC_IRQ) +		sc->debug.stats.istats.sync_rtc_irq++; +	if (sync_cause & AR_INTR_SYNC_MAC_IRQ) +		sc->debug.stats.istats.sync_mac_irq++; +	if (sync_cause & AR_INTR_SYNC_EEPROM_ILLEGAL_ACCESS) +		sc->debug.stats.istats.eeprom_illegal_access++; +	if (sync_cause & AR_INTR_SYNC_APB_TIMEOUT) +		sc->debug.stats.istats.apb_timeout++; +	if (sync_cause & AR_INTR_SYNC_PCI_MODE_CONFLICT) +		sc->debug.stats.istats.pci_mode_conflict++; +	if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) +		sc->debug.stats.istats.host1_fatal++; +	if (sync_cause & AR_INTR_SYNC_HOST1_PERR) +		sc->debug.stats.istats.host1_perr++; +	if (sync_cause & AR_INTR_SYNC_TRCV_FIFO_PERR) +		sc->debug.stats.istats.trcv_fifo_perr++; +	if (sync_cause & AR_INTR_SYNC_RADM_CPL_EP) +		sc->debug.stats.istats.radm_cpl_ep++; +	if (sync_cause & AR_INTR_SYNC_RADM_CPL_DLLP_ABORT) +		sc->debug.stats.istats.radm_cpl_dllp_abort++; +	if (sync_cause & AR_INTR_SYNC_RADM_CPL_TLP_ABORT) +		sc->debug.stats.istats.radm_cpl_tlp_abort++; +	if (sync_cause & AR_INTR_SYNC_RADM_CPL_ECRC_ERR) +		sc->debug.stats.istats.radm_cpl_ecrc_err++; +	if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) +		sc->debug.stats.istats.radm_cpl_timeout++; +	if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) +		sc->debug.stats.istats.local_timeout++; +	if (sync_cause & AR_INTR_SYNC_PM_ACCESS) +		sc->debug.stats.istats.pm_access++; +	if (sync_cause & AR_INTR_SYNC_MAC_AWAKE) +		sc->debug.stats.istats.mac_awake++; +	if (sync_cause & AR_INTR_SYNC_MAC_ASLEEP) +		sc->debug.stats.istats.mac_asleep++; +	if (sync_cause & AR_INTR_SYNC_MAC_SLEEP_ACCESS) +		sc->debug.stats.istats.mac_sleep_access++; +}  static ssize_t ath9k_debugfs_read_buf(struct file *file, char __user *user_buf,  				      size_t count, loff_t *ppos) @@ -95,46 +135,45 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf,  	struct ath_softc *sc = file->private_data;  	struct ath_common *common = ath9k_hw_common(sc->sc_ah);  	struct ath_hw *ah = sc->sc_ah; -	unsigned int len = 0, size = 1024; +	unsigned int len = 0; +	const unsigned int size = 1024;  	ssize_t retval = 0;  	char *buf; +	int i; +	struct { +		const char *name; +		unsigned int val; +	} ani_info[] = { +		{ "ANI RESET", ah->stats.ast_ani_reset }, +		{ "OFDM LEVEL", ah->ani.ofdmNoiseImmunityLevel }, +		{ "CCK LEVEL", ah->ani.cckNoiseImmunityLevel }, +		{ "SPUR UP", ah->stats.ast_ani_spurup }, +		{ "SPUR DOWN", ah->stats.ast_ani_spurup }, +		{ "OFDM WS-DET ON", ah->stats.ast_ani_ofdmon }, +		{ "OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff }, +		{ "MRC-CCK ON", ah->stats.ast_ani_ccklow }, +		{ "MRC-CCK OFF", ah->stats.ast_ani_cckhigh }, +		{ "FIR-STEP UP", ah->stats.ast_ani_stepup }, +		{ "FIR-STEP DOWN", ah->stats.ast_ani_stepdown }, +		{ "INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero }, +		{ "OFDM ERRORS", ah->stats.ast_ani_ofdmerrs }, +		{ "CCK ERRORS", ah->stats.ast_ani_cckerrs }, +	};  	buf = kzalloc(size, GFP_KERNEL);  	if (buf == NULL)  		return -ENOMEM; -	if (common->disable_ani) { -		len += snprintf(buf + len, size - len, "%s: %s\n", -				"ANI", "DISABLED"); +	len += scnprintf(buf + len, size - len, "%15s: %s\n", "ANI", +			 common->disable_ani ? "DISABLED" : "ENABLED"); + +	if (common->disable_ani)  		goto exit; -	} -	len += snprintf(buf + len, size - len, "%15s: %s\n", -			"ANI", "ENABLED"); -	len += snprintf(buf + len, size - len, "%15s: %u\n", -			"ANI RESET", ah->stats.ast_ani_reset); -	len += snprintf(buf + len, size - len, "%15s: %u\n", -			"SPUR UP", ah->stats.ast_ani_spurup); -	len += snprintf(buf + len, size - len, "%15s: %u\n", -			"SPUR DOWN", ah->stats.ast_ani_spurup); -	len += snprintf(buf + len, size - len, "%15s: %u\n", -			"OFDM WS-DET ON", ah->stats.ast_ani_ofdmon); -	len += snprintf(buf + len, size - len, "%15s: %u\n", -			"OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff); -	len += snprintf(buf + len, size - len, "%15s: %u\n", -			"MRC-CCK ON", ah->stats.ast_ani_ccklow); -	len += snprintf(buf + len, size - len, "%15s: %u\n", -			"MRC-CCK OFF", ah->stats.ast_ani_cckhigh); -	len += snprintf(buf + len, size - len, "%15s: %u\n", -			"FIR-STEP UP", ah->stats.ast_ani_stepup); -	len += snprintf(buf + len, size - len, "%15s: %u\n", -			"FIR-STEP DOWN", ah->stats.ast_ani_stepdown); -	len += snprintf(buf + len, size - len, "%15s: %u\n", -			"INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero); -	len += snprintf(buf + len, size - len, "%15s: %u\n", -			"OFDM ERRORS", ah->stats.ast_ani_ofdmerrs); -	len += snprintf(buf + len, size - len, "%15s: %u\n", -			"CCK ERRORS", ah->stats.ast_ani_cckerrs); +	for (i = 0; i < ARRAY_SIZE(ani_info); i++) +		len += scnprintf(buf + len, size - len, "%15s: %u\n", +				 ani_info[i].name, ani_info[i].val); +  exit:  	if (len > size)  		len = size; @@ -169,7 +208,7 @@ static ssize_t write_file_ani(struct file *file,  	common->disable_ani = !ani;  	if (common->disable_ani) { -		clear_bit(SC_OP_ANI_RUN, &sc->sc_flags); +		clear_bit(ATH_OP_ANI_RUN, &common->op_flags);  		ath_stop_ani(sc);  	} else {  		ath_check_ani(sc); @@ -267,83 +306,83 @@ static ssize_t read_file_antenna_diversity(struct file *file,  	struct ath_antenna_stats *as_main = &sc->debug.stats.ant_stats[ANT_MAIN];  	struct ath_antenna_stats *as_alt = &sc->debug.stats.ant_stats[ANT_ALT];  	struct ath_hw_antcomb_conf div_ant_conf; -	unsigned int len = 0, size = 1024; +	unsigned int len = 0; +	const unsigned int size = 1024;  	ssize_t retval = 0;  	char *buf; -	char *lna_conf_str[4] = {"LNA1_MINUS_LNA2", -				 "LNA2", -				 "LNA1", -				 "LNA1_PLUS_LNA2"}; +	static const char *lna_conf_str[4] = { +		"LNA1_MINUS_LNA2", "LNA2", "LNA1", "LNA1_PLUS_LNA2" +	};  	buf = kzalloc(size, GFP_KERNEL);  	if (buf == NULL)  		return -ENOMEM;  	if (!(pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)) { -		len += snprintf(buf + len, size - len, "%s\n", -				"Antenna Diversity Combining is disabled"); +		len += scnprintf(buf + len, size - len, "%s\n", +				 "Antenna Diversity Combining is disabled");  		goto exit;  	}  	ath9k_ps_wakeup(sc);  	ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf); -	len += snprintf(buf + len, size - len, "Current MAIN config : %s\n", -			lna_conf_str[div_ant_conf.main_lna_conf]); -	len += snprintf(buf + len, size - len, "Current ALT config  : %s\n", -			lna_conf_str[div_ant_conf.alt_lna_conf]); -	len += snprintf(buf + len, size - len, "Average MAIN RSSI   : %d\n", -			as_main->rssi_avg); -	len += snprintf(buf + len, size - len, "Average ALT RSSI    : %d\n\n", -			as_alt->rssi_avg); +	len += scnprintf(buf + len, size - len, "Current MAIN config : %s\n", +			 lna_conf_str[div_ant_conf.main_lna_conf]); +	len += scnprintf(buf + len, size - len, "Current ALT config  : %s\n", +			 lna_conf_str[div_ant_conf.alt_lna_conf]); +	len += scnprintf(buf + len, size - len, "Average MAIN RSSI   : %d\n", +			 as_main->rssi_avg); +	len += scnprintf(buf + len, size - len, "Average ALT RSSI    : %d\n\n", +			 as_alt->rssi_avg);  	ath9k_ps_restore(sc); -	len += snprintf(buf + len, size - len, "Packet Receive Cnt:\n"); -	len += snprintf(buf + len, size - len, "-------------------\n"); - -	len += snprintf(buf + len, size - len, "%30s%15s\n", -			"MAIN", "ALT"); -	len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n", -			"TOTAL COUNT", -			as_main->recv_cnt, -			as_alt->recv_cnt); -	len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n", -			"LNA1", -			as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1], -			as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1]); -	len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n", -			"LNA2", -			as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA2], -			as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA2]); -	len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n", -			"LNA1 + LNA2", -			as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2], -			as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2]); -	len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n", -			"LNA1 - LNA2", -			as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2], -			as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2]); - -	len += snprintf(buf + len, size - len, "\nLNA Config Attempts:\n"); -	len += snprintf(buf + len, size - len, "--------------------\n"); - -	len += snprintf(buf + len, size - len, "%30s%15s\n", -			"MAIN", "ALT"); -	len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n", -			"LNA1", -			as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1], -			as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1]); -	len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n", -			"LNA2", -			as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA2], -			as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA2]); -	len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n", -			"LNA1 + LNA2", -			as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2], -			as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2]); -	len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n", -			"LNA1 - LNA2", -			as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2], -			as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2]); +	len += scnprintf(buf + len, size - len, "Packet Receive Cnt:\n"); +	len += scnprintf(buf + len, size - len, "-------------------\n"); + +	len += scnprintf(buf + len, size - len, "%30s%15s\n", +			 "MAIN", "ALT"); +	len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n", +			 "TOTAL COUNT", +			 as_main->recv_cnt, +			 as_alt->recv_cnt); +	len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n", +			 "LNA1", +			 as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1], +			 as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1]); +	len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n", +			 "LNA2", +			 as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA2], +			 as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA2]); +	len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n", +			 "LNA1 + LNA2", +			 as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2], +			 as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2]); +	len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n", +			 "LNA1 - LNA2", +			 as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2], +			 as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2]); + +	len += scnprintf(buf + len, size - len, "\nLNA Config Attempts:\n"); +	len += scnprintf(buf + len, size - len, "--------------------\n"); + +	len += scnprintf(buf + len, size - len, "%30s%15s\n", +			 "MAIN", "ALT"); +	len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n", +			 "LNA1", +			 as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1], +			 as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1]); +	len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n", +			 "LNA2", +			 as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA2], +			 as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA2]); +	len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n", +			 "LNA1 + LNA2", +			 as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2], +			 as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2]); +	len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n", +			 "LNA1 - LNA2", +			 as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2], +			 as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2]);  exit:  	if (len > size) @@ -385,21 +424,21 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,  		   (AR_MACMISC_MISC_OBS_BUS_1 <<  		    AR_MACMISC_MISC_OBS_BUS_MSB_S))); -	len += snprintf(buf + len, DMA_BUF_LEN - len, -			"Raw DMA Debug values:\n"); +	len += scnprintf(buf + len, DMA_BUF_LEN - len, +			 "Raw DMA Debug values:\n");  	for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) {  		if (i % 4 == 0) -			len += snprintf(buf + len, DMA_BUF_LEN - len, "\n"); +			len += scnprintf(buf + len, DMA_BUF_LEN - len, "\n");  		val[i] = REG_READ_D(ah, AR_DMADBG_0 + (i * sizeof(u32))); -		len += snprintf(buf + len, DMA_BUF_LEN - len, "%d: %08x ", -				i, val[i]); +		len += scnprintf(buf + len, DMA_BUF_LEN - len, "%d: %08x ", +				 i, val[i]);  	} -	len += snprintf(buf + len, DMA_BUF_LEN - len, "\n\n"); -	len += snprintf(buf + len, DMA_BUF_LEN - len, -			"Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n"); +	len += scnprintf(buf + len, DMA_BUF_LEN - len, "\n\n"); +	len += scnprintf(buf + len, DMA_BUF_LEN - len, +			 "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n");  	for (i = 0; i < ATH9K_NUM_QUEUES; i++, qcuOffset += 4, dcuOffset += 5) {  		if (i == 8) { @@ -412,39 +451,39 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,  			dcuBase++;  		} -		len += snprintf(buf + len, DMA_BUF_LEN - len, -			"%2d          %2x      %1x     %2x           %2x\n", -			i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, -			(*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3), -			val[2] & (0x7 << (i * 3)) >> (i * 3), -			(*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); +		len += scnprintf(buf + len, DMA_BUF_LEN - len, +			 "%2d          %2x      %1x     %2x           %2x\n", +			 i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, +			 (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3), +			 val[2] & (0x7 << (i * 3)) >> (i * 3), +			 (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset);  	} -	len += snprintf(buf + len, DMA_BUF_LEN - len, "\n"); +	len += scnprintf(buf + len, DMA_BUF_LEN - len, "\n"); -	len += snprintf(buf + len, DMA_BUF_LEN - len, +	len += scnprintf(buf + len, DMA_BUF_LEN - len,  		"qcu_stitch state:   %2x    qcu_fetch state:        %2x\n",  		(val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22); -	len += snprintf(buf + len, DMA_BUF_LEN - len, +	len += scnprintf(buf + len, DMA_BUF_LEN - len,  		"qcu_complete state: %2x    dcu_complete state:     %2x\n",  		(val[3] & 0x1c000000) >> 26, (val[6] & 0x3)); -	len += snprintf(buf + len, DMA_BUF_LEN - len, +	len += scnprintf(buf + len, DMA_BUF_LEN - len,  		"dcu_arb state:      %2x    dcu_fp state:           %2x\n",  		(val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27); -	len += snprintf(buf + len, DMA_BUF_LEN - len, +	len += scnprintf(buf + len, DMA_BUF_LEN - len,  		"chan_idle_dur:     %3d    chan_idle_dur_valid:     %1d\n",  		(val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10); -	len += snprintf(buf + len, DMA_BUF_LEN - len, +	len += scnprintf(buf + len, DMA_BUF_LEN - len,  		"txfifo_valid_0:      %1d    txfifo_valid_1:          %1d\n",  		(val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12); -	len += snprintf(buf + len, DMA_BUF_LEN - len, +	len += scnprintf(buf + len, DMA_BUF_LEN - len,  		"txfifo_dcu_num_0:   %2d    txfifo_dcu_num_1:       %2d\n",  		(val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17); -	len += snprintf(buf + len, DMA_BUF_LEN - len, "pcu observe: 0x%x\n", -			REG_READ_D(ah, AR_OBS_BUS_1)); -	len += snprintf(buf + len, DMA_BUF_LEN - len, -			"AR_CR: 0x%x\n", REG_READ_D(ah, AR_CR)); +	len += scnprintf(buf + len, DMA_BUF_LEN - len, "pcu observe: 0x%x\n", +			 REG_READ_D(ah, AR_OBS_BUS_1)); +	len += scnprintf(buf + len, DMA_BUF_LEN - len, +			 "AR_CR: 0x%x\n", REG_READ_D(ah, AR_CR));  	ath9k_ps_restore(sc); @@ -530,9 +569,9 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,  #define PR_IS(a, s)						\  	do {							\ -		len += snprintf(buf + len, mxlen - len,		\ -				"%21s: %10u\n", a,		\ -				sc->debug.stats.istats.s);	\ +		len += scnprintf(buf + len, mxlen - len,	\ +				 "%21s: %10u\n", a,		\ +				 sc->debug.stats.istats.s);	\  	} while (0)  	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { @@ -563,8 +602,8 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,  	PR_IS("GENTIMER", gen_timer);  	PR_IS("TOTAL", total); -	len += snprintf(buf + len, mxlen - len, -			"SYNC_CAUSE stats:\n"); +	len += scnprintf(buf + len, mxlen - len, +			 "SYNC_CAUSE stats:\n");  	PR_IS("Sync-All", sync_cause_all);  	PR_IS("RTC-IRQ", sync_rtc_irq); @@ -655,16 +694,16 @@ static ssize_t print_queue(struct ath_softc *sc, struct ath_txq *txq,  	ath_txq_lock(sc, txq); -	len += snprintf(buf + len, size - len, "%s: %d ", -			"qnum", txq->axq_qnum); -	len += snprintf(buf + len, size - len, "%s: %2d ", -			"qdepth", txq->axq_depth); -	len += snprintf(buf + len, size - len, "%s: %2d ", -			"ampdu-depth", txq->axq_ampdu_depth); -	len += snprintf(buf + len, size - len, "%s: %3d ", -			"pending", txq->pending_frames); -	len += snprintf(buf + len, size - len, "%s: %d\n", -			"stopped", txq->stopped); +	len += scnprintf(buf + len, size - len, "%s: %d ", +			 "qnum", txq->axq_qnum); +	len += scnprintf(buf + len, size - len, "%s: %2d ", +			 "qdepth", txq->axq_depth); +	len += scnprintf(buf + len, size - len, "%s: %2d ", +			 "ampdu-depth", txq->axq_ampdu_depth); +	len += scnprintf(buf + len, size - len, "%s: %3d ", +			 "pending", txq->pending_frames); +	len += scnprintf(buf + len, size - len, "%s: %d\n", +			 "stopped", txq->stopped);  	ath_txq_unlock(sc, txq);  	return len; @@ -676,10 +715,13 @@ static ssize_t read_file_queues(struct file *file, char __user *user_buf,  	struct ath_softc *sc = file->private_data;  	struct ath_txq *txq;  	char *buf; -	unsigned int len = 0, size = 1024; +	unsigned int len = 0; +	const unsigned int size = 1024;  	ssize_t retval = 0;  	int i; -	char *qname[4] = {"VO", "VI", "BE", "BK"}; +	static const char *qname[4] = { +		"VO", "VI", "BE", "BK" +	};  	buf = kzalloc(size, GFP_KERNEL);  	if (buf == NULL) @@ -687,11 +729,11 @@ static ssize_t read_file_queues(struct file *file, char __user *user_buf,  	for (i = 0; i < IEEE80211_NUM_ACS; i++) {  		txq = sc->tx.txq_map[i]; -		len += snprintf(buf + len, size - len, "(%s):  ", qname[i]); +		len += scnprintf(buf + len, size - len, "(%s):  ", qname[i]);  		len += print_queue(sc, txq, buf + len, size - len);  	} -	len += snprintf(buf + len, size - len, "(CAB): "); +	len += scnprintf(buf + len, size - len, "(CAB): ");  	len += print_queue(sc, sc->beacon.cabq, buf + len, size - len);  	if (len > size) @@ -716,80 +758,82 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf,  	unsigned int reg;  	u32 rxfilter; -	len += snprintf(buf + len, sizeof(buf) - len, -			"BSSID: %pM\n", common->curbssid); -	len += snprintf(buf + len, sizeof(buf) - len, -			"BSSID-MASK: %pM\n", common->bssidmask); -	len += snprintf(buf + len, sizeof(buf) - len, -			"OPMODE: %s\n", ath_opmode_to_string(sc->sc_ah->opmode)); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "BSSID: %pM\n", common->curbssid); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "BSSID-MASK: %pM\n", common->bssidmask); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "OPMODE: %s\n", +			 ath_opmode_to_string(sc->sc_ah->opmode));  	ath9k_ps_wakeup(sc);  	rxfilter = ath9k_hw_getrxfilter(sc->sc_ah);  	ath9k_ps_restore(sc); -	len += snprintf(buf + len, sizeof(buf) - len, -			"RXFILTER: 0x%x", rxfilter); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "RXFILTER: 0x%x", rxfilter);  	if (rxfilter & ATH9K_RX_FILTER_UCAST) -		len += snprintf(buf + len, sizeof(buf) - len, " UCAST"); +		len += scnprintf(buf + len, sizeof(buf) - len, " UCAST");  	if (rxfilter & ATH9K_RX_FILTER_MCAST) -		len += snprintf(buf + len, sizeof(buf) - len, " MCAST"); +		len += scnprintf(buf + len, sizeof(buf) - len, " MCAST");  	if (rxfilter & ATH9K_RX_FILTER_BCAST) -		len += snprintf(buf + len, sizeof(buf) - len, " BCAST"); +		len += scnprintf(buf + len, sizeof(buf) - len, " BCAST");  	if (rxfilter & ATH9K_RX_FILTER_CONTROL) -		len += snprintf(buf + len, sizeof(buf) - len, " CONTROL"); +		len += scnprintf(buf + len, sizeof(buf) - len, " CONTROL");  	if (rxfilter & ATH9K_RX_FILTER_BEACON) -		len += snprintf(buf + len, sizeof(buf) - len, " BEACON"); +		len += scnprintf(buf + len, sizeof(buf) - len, " BEACON");  	if (rxfilter & ATH9K_RX_FILTER_PROM) -		len += snprintf(buf + len, sizeof(buf) - len, " PROM"); +		len += scnprintf(buf + len, sizeof(buf) - len, " PROM");  	if (rxfilter & ATH9K_RX_FILTER_PROBEREQ) -		len += snprintf(buf + len, sizeof(buf) - len, " PROBEREQ"); +		len += scnprintf(buf + len, sizeof(buf) - len, " PROBEREQ");  	if (rxfilter & ATH9K_RX_FILTER_PHYERR) -		len += snprintf(buf + len, sizeof(buf) - len, " PHYERR"); +		len += scnprintf(buf + len, sizeof(buf) - len, " PHYERR");  	if (rxfilter & ATH9K_RX_FILTER_MYBEACON) -		len += snprintf(buf + len, sizeof(buf) - len, " MYBEACON"); +		len += scnprintf(buf + len, sizeof(buf) - len, " MYBEACON");  	if (rxfilter & ATH9K_RX_FILTER_COMP_BAR) -		len += snprintf(buf + len, sizeof(buf) - len, " COMP_BAR"); +		len += scnprintf(buf + len, sizeof(buf) - len, " COMP_BAR");  	if (rxfilter & ATH9K_RX_FILTER_PSPOLL) -		len += snprintf(buf + len, sizeof(buf) - len, " PSPOLL"); +		len += scnprintf(buf + len, sizeof(buf) - len, " PSPOLL");  	if (rxfilter & ATH9K_RX_FILTER_PHYRADAR) -		len += snprintf(buf + len, sizeof(buf) - len, " PHYRADAR"); +		len += scnprintf(buf + len, sizeof(buf) - len, " PHYRADAR");  	if (rxfilter & ATH9K_RX_FILTER_MCAST_BCAST_ALL) -		len += snprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL"); +		len += scnprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL");  	if (rxfilter & ATH9K_RX_FILTER_CONTROL_WRAPPER) -		len += snprintf(buf + len, sizeof(buf) - len, " CONTROL_WRAPPER"); +		len += scnprintf(buf + len, sizeof(buf) - len, " CONTROL_WRAPPER"); -	len += snprintf(buf + len, sizeof(buf) - len, "\n"); +	len += scnprintf(buf + len, sizeof(buf) - len, "\n");  	reg = sc->sc_ah->imask; -	len += snprintf(buf + len, sizeof(buf) - len, "INTERRUPT-MASK: 0x%x", reg); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "INTERRUPT-MASK: 0x%x", reg);  	if (reg & ATH9K_INT_SWBA) -		len += snprintf(buf + len, sizeof(buf) - len, " SWBA"); +		len += scnprintf(buf + len, sizeof(buf) - len, " SWBA");  	if (reg & ATH9K_INT_BMISS) -		len += snprintf(buf + len, sizeof(buf) - len, " BMISS"); +		len += scnprintf(buf + len, sizeof(buf) - len, " BMISS");  	if (reg & ATH9K_INT_CST) -		len += snprintf(buf + len, sizeof(buf) - len, " CST"); +		len += scnprintf(buf + len, sizeof(buf) - len, " CST");  	if (reg & ATH9K_INT_RX) -		len += snprintf(buf + len, sizeof(buf) - len, " RX"); +		len += scnprintf(buf + len, sizeof(buf) - len, " RX");  	if (reg & ATH9K_INT_RXHP) -		len += snprintf(buf + len, sizeof(buf) - len, " RXHP"); +		len += scnprintf(buf + len, sizeof(buf) - len, " RXHP");  	if (reg & ATH9K_INT_RXLP) -		len += snprintf(buf + len, sizeof(buf) - len, " RXLP"); +		len += scnprintf(buf + len, sizeof(buf) - len, " RXLP");  	if (reg & ATH9K_INT_BB_WATCHDOG) -		len += snprintf(buf + len, sizeof(buf) - len, " BB_WATCHDOG"); +		len += scnprintf(buf + len, sizeof(buf) - len, " BB_WATCHDOG"); -	len += snprintf(buf + len, sizeof(buf) - len, "\n"); +	len += scnprintf(buf + len, sizeof(buf) - len, "\n");  	ath9k_calculate_iter_data(hw, NULL, &iter_data); -	len += snprintf(buf + len, sizeof(buf) - len, -			"VIF-COUNTS: AP: %i STA: %i MESH: %i WDS: %i" -			" ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n", -			iter_data.naps, iter_data.nstations, iter_data.nmeshes, -			iter_data.nwds, iter_data.nadhocs, -			sc->nvifs, sc->nbcnvifs); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "VIF-COUNTS: AP: %i STA: %i MESH: %i WDS: %i" +			 " ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n", +			 iter_data.naps, iter_data.nstations, iter_data.nmeshes, +			 iter_data.nwds, iter_data.nadhocs, +			 sc->nvifs, sc->nbcnvifs);  	if (len > sizeof(buf))  		len = sizeof(buf); @@ -805,27 +849,33 @@ static ssize_t read_file_reset(struct file *file, char __user *user_buf,  	char buf[512];  	unsigned int len = 0; -	len += snprintf(buf + len, sizeof(buf) - len, -			"%17s: %2d\n", "Baseband Hang", -			sc->debug.stats.reset[RESET_TYPE_BB_HANG]); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%17s: %2d\n", "Baseband Watchdog", -			sc->debug.stats.reset[RESET_TYPE_BB_WATCHDOG]); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%17s: %2d\n", "Fatal HW Error", -			sc->debug.stats.reset[RESET_TYPE_FATAL_INT]); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%17s: %2d\n", "TX HW error", -			sc->debug.stats.reset[RESET_TYPE_TX_ERROR]); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%17s: %2d\n", "TX Path Hang", -			sc->debug.stats.reset[RESET_TYPE_TX_HANG]); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%17s: %2d\n", "PLL RX Hang", -			sc->debug.stats.reset[RESET_TYPE_PLL_HANG]); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%17s: %2d\n", "MCI Reset", -			sc->debug.stats.reset[RESET_TYPE_MCI]); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%17s: %2d\n", "Baseband Hang", +			 sc->debug.stats.reset[RESET_TYPE_BB_HANG]); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%17s: %2d\n", "Baseband Watchdog", +			 sc->debug.stats.reset[RESET_TYPE_BB_WATCHDOG]); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%17s: %2d\n", "Fatal HW Error", +			 sc->debug.stats.reset[RESET_TYPE_FATAL_INT]); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%17s: %2d\n", "TX HW error", +			 sc->debug.stats.reset[RESET_TYPE_TX_ERROR]); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%17s: %2d\n", "TX Path Hang", +			 sc->debug.stats.reset[RESET_TYPE_TX_HANG]); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%17s: %2d\n", "PLL RX Hang", +			 sc->debug.stats.reset[RESET_TYPE_PLL_HANG]); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%17s: %2d\n", "MAC Hang", +			 sc->debug.stats.reset[RESET_TYPE_MAC_HANG]); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%17s: %2d\n", "Stuck Beacon", +			 sc->debug.stats.reset[RESET_TYPE_BEACON_STUCK]); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%17s: %2d\n", "MCI Reset", +			 sc->debug.stats.reset[RESET_TYPE_MCI]);  	if (len > sizeof(buf))  		len = sizeof(buf); @@ -898,406 +948,11 @@ static const struct file_operations fops_reset = {  	.llseek = default_llseek,  }; -static ssize_t read_file_recv(struct file *file, char __user *user_buf, -			      size_t count, loff_t *ppos) -{ -#define PHY_ERR(s, p) \ -	len += snprintf(buf + len, size - len, "%22s : %10u\n", s, \ -			sc->debug.stats.rxstats.phy_err_stats[p]); - -#define RXS_ERR(s, e)					    \ -	do {						    \ -		len += snprintf(buf + len, size - len,	    \ -				"%22s : %10u\n", s,	    \ -				sc->debug.stats.rxstats.e); \ -	} while (0) - -	struct ath_softc *sc = file->private_data; -	char *buf; -	unsigned int len = 0, size = 1600; -	ssize_t retval = 0; - -	buf = kzalloc(size, GFP_KERNEL); -	if (buf == NULL) -		return -ENOMEM; - -	RXS_ERR("CRC ERR", crc_err); -	RXS_ERR("DECRYPT CRC ERR", decrypt_crc_err); -	RXS_ERR("PHY ERR", phy_err); -	RXS_ERR("MIC ERR", mic_err); -	RXS_ERR("PRE-DELIM CRC ERR", pre_delim_crc_err); -	RXS_ERR("POST-DELIM CRC ERR", post_delim_crc_err); -	RXS_ERR("DECRYPT BUSY ERR", decrypt_busy_err); -	RXS_ERR("RX-LENGTH-ERR", rx_len_err); -	RXS_ERR("RX-OOM-ERR", rx_oom_err); -	RXS_ERR("RX-RATE-ERR", rx_rate_err); -	RXS_ERR("RX-TOO-MANY-FRAGS", rx_too_many_frags_err); - -	PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN); -	PHY_ERR("TIMING ERR", ATH9K_PHYERR_TIMING); -	PHY_ERR("PARITY ERR", ATH9K_PHYERR_PARITY); -	PHY_ERR("RATE ERR", ATH9K_PHYERR_RATE); -	PHY_ERR("LENGTH ERR", ATH9K_PHYERR_LENGTH); -	PHY_ERR("RADAR ERR", ATH9K_PHYERR_RADAR); -	PHY_ERR("SERVICE ERR", ATH9K_PHYERR_SERVICE); -	PHY_ERR("TOR ERR", ATH9K_PHYERR_TOR); -	PHY_ERR("OFDM-TIMING ERR", ATH9K_PHYERR_OFDM_TIMING); -	PHY_ERR("OFDM-SIGNAL-PARITY ERR", ATH9K_PHYERR_OFDM_SIGNAL_PARITY); -	PHY_ERR("OFDM-RATE ERR", ATH9K_PHYERR_OFDM_RATE_ILLEGAL); -	PHY_ERR("OFDM-LENGTH ERR", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL); -	PHY_ERR("OFDM-POWER-DROP ERR", ATH9K_PHYERR_OFDM_POWER_DROP); -	PHY_ERR("OFDM-SERVICE ERR", ATH9K_PHYERR_OFDM_SERVICE); -	PHY_ERR("OFDM-RESTART ERR", ATH9K_PHYERR_OFDM_RESTART); -	PHY_ERR("FALSE-RADAR-EXT ERR", ATH9K_PHYERR_FALSE_RADAR_EXT); -	PHY_ERR("CCK-TIMING ERR", ATH9K_PHYERR_CCK_TIMING); -	PHY_ERR("CCK-HEADER-CRC ERR", ATH9K_PHYERR_CCK_HEADER_CRC); -	PHY_ERR("CCK-RATE ERR", ATH9K_PHYERR_CCK_RATE_ILLEGAL); -	PHY_ERR("CCK-SERVICE ERR", ATH9K_PHYERR_CCK_SERVICE); -	PHY_ERR("CCK-RESTART ERR", ATH9K_PHYERR_CCK_RESTART); -	PHY_ERR("CCK-LENGTH ERR", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL); -	PHY_ERR("CCK-POWER-DROP ERR", ATH9K_PHYERR_CCK_POWER_DROP); -	PHY_ERR("HT-CRC ERR", ATH9K_PHYERR_HT_CRC_ERROR); -	PHY_ERR("HT-LENGTH ERR", ATH9K_PHYERR_HT_LENGTH_ILLEGAL); -	PHY_ERR("HT-RATE ERR", ATH9K_PHYERR_HT_RATE_ILLEGAL); - -	RXS_ERR("RX-Pkts-All", rx_pkts_all); -	RXS_ERR("RX-Bytes-All", rx_bytes_all); -	RXS_ERR("RX-Beacons", rx_beacons); -	RXS_ERR("RX-Frags", rx_frags); -	RXS_ERR("RX-Spectral", rx_spectral); - -	if (len > size) -		len = size; - -	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); -	kfree(buf); - -	return retval; - -#undef RXS_ERR -#undef PHY_ERR -} -  void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs)  { -#define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++ - -	RX_STAT_INC(rx_pkts_all); -	sc->debug.stats.rxstats.rx_bytes_all += rs->rs_datalen; - -	if (rs->rs_status & ATH9K_RXERR_CRC) -		RX_STAT_INC(crc_err); -	if (rs->rs_status & ATH9K_RXERR_DECRYPT) -		RX_STAT_INC(decrypt_crc_err); -	if (rs->rs_status & ATH9K_RXERR_MIC) -		RX_STAT_INC(mic_err); -	if (rs->rs_status & ATH9K_RX_DELIM_CRC_PRE) -		RX_STAT_INC(pre_delim_crc_err); -	if (rs->rs_status & ATH9K_RX_DELIM_CRC_POST) -		RX_STAT_INC(post_delim_crc_err); -	if (rs->rs_status & ATH9K_RX_DECRYPT_BUSY) -		RX_STAT_INC(decrypt_busy_err); - -	if (rs->rs_status & ATH9K_RXERR_PHY) { -		RX_STAT_INC(phy_err); -		if (rs->rs_phyerr < ATH9K_PHYERR_MAX) -			RX_PHY_ERR_INC(rs->rs_phyerr); -	} - -#undef RX_PHY_ERR_INC -} - -static const struct file_operations fops_recv = { -	.read = read_file_recv, -	.open = simple_open, -	.owner = THIS_MODULE, -	.llseek = default_llseek, -}; - -static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf, -				       size_t count, loff_t *ppos) -{ -	struct ath_softc *sc = file->private_data; -	char *mode = ""; -	unsigned int len; - -	switch (sc->spectral_mode) { -	case SPECTRAL_DISABLED: -		mode = "disable"; -		break; -	case SPECTRAL_BACKGROUND: -		mode = "background"; -		break; -	case SPECTRAL_CHANSCAN: -		mode = "chanscan"; -		break; -	case SPECTRAL_MANUAL: -		mode = "manual"; -		break; -	} -	len = strlen(mode); -	return simple_read_from_buffer(user_buf, count, ppos, mode, len); -} - -static ssize_t write_file_spec_scan_ctl(struct file *file, -					const char __user *user_buf, -					size_t count, loff_t *ppos) -{ -	struct ath_softc *sc = file->private_data; -	struct ath_common *common = ath9k_hw_common(sc->sc_ah); -	char buf[32]; -	ssize_t len; - -	len = min(count, sizeof(buf) - 1); -	if (copy_from_user(buf, user_buf, len)) -		return -EFAULT; - -	buf[len] = '\0'; - -	if (strncmp("trigger", buf, 7) == 0) { -		ath9k_spectral_scan_trigger(sc->hw); -	} else if (strncmp("background", buf, 9) == 0) { -		ath9k_spectral_scan_config(sc->hw, SPECTRAL_BACKGROUND); -		ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n"); -	} else if (strncmp("chanscan", buf, 8) == 0) { -		ath9k_spectral_scan_config(sc->hw, SPECTRAL_CHANSCAN); -		ath_dbg(common, CONFIG, "spectral scan: channel scan mode enabled\n"); -	} else if (strncmp("manual", buf, 6) == 0) { -		ath9k_spectral_scan_config(sc->hw, SPECTRAL_MANUAL); -		ath_dbg(common, CONFIG, "spectral scan: manual mode enabled\n"); -	} else if (strncmp("disable", buf, 7) == 0) { -		ath9k_spectral_scan_config(sc->hw, SPECTRAL_DISABLED); -		ath_dbg(common, CONFIG, "spectral scan: disabled\n"); -	} else { -		return -EINVAL; -	} - -	return count; -} - -static const struct file_operations fops_spec_scan_ctl = { -	.read = read_file_spec_scan_ctl, -	.write = write_file_spec_scan_ctl, -	.open = simple_open, -	.owner = THIS_MODULE, -	.llseek = default_llseek, -}; - -static ssize_t read_file_spectral_short_repeat(struct file *file, -					       char __user *user_buf, -					       size_t count, loff_t *ppos) -{ -	struct ath_softc *sc = file->private_data; -	char buf[32]; -	unsigned int len; - -	len = sprintf(buf, "%d\n", sc->spec_config.short_repeat); -	return simple_read_from_buffer(user_buf, count, ppos, buf, len); +	ath9k_cmn_debug_stat_rx(&sc->debug.stats.rxstats, rs);  } -static ssize_t write_file_spectral_short_repeat(struct file *file, -						const char __user *user_buf, -						size_t count, loff_t *ppos) -{ -	struct ath_softc *sc = file->private_data; -	unsigned long val; -	char buf[32]; -	ssize_t len; - -	len = min(count, sizeof(buf) - 1); -	if (copy_from_user(buf, user_buf, len)) -		return -EFAULT; - -	buf[len] = '\0'; -	if (kstrtoul(buf, 0, &val)) -		return -EINVAL; - -	if (val < 0 || val > 1) -		return -EINVAL; - -	sc->spec_config.short_repeat = val; -	return count; -} - -static const struct file_operations fops_spectral_short_repeat = { -	.read = read_file_spectral_short_repeat, -	.write = write_file_spectral_short_repeat, -	.open = simple_open, -	.owner = THIS_MODULE, -	.llseek = default_llseek, -}; - -static ssize_t read_file_spectral_count(struct file *file, -					char __user *user_buf, -					size_t count, loff_t *ppos) -{ -	struct ath_softc *sc = file->private_data; -	char buf[32]; -	unsigned int len; - -	len = sprintf(buf, "%d\n", sc->spec_config.count); -	return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t write_file_spectral_count(struct file *file, -					 const char __user *user_buf, -					 size_t count, loff_t *ppos) -{ -	struct ath_softc *sc = file->private_data; -	unsigned long val; -	char buf[32]; -	ssize_t len; - -	len = min(count, sizeof(buf) - 1); -	if (copy_from_user(buf, user_buf, len)) -		return -EFAULT; - -	buf[len] = '\0'; -	if (kstrtoul(buf, 0, &val)) -		return -EINVAL; - -	if (val < 0 || val > 255) -		return -EINVAL; - -	sc->spec_config.count = val; -	return count; -} - -static const struct file_operations fops_spectral_count = { -	.read = read_file_spectral_count, -	.write = write_file_spectral_count, -	.open = simple_open, -	.owner = THIS_MODULE, -	.llseek = default_llseek, -}; - -static ssize_t read_file_spectral_period(struct file *file, -					 char __user *user_buf, -					 size_t count, loff_t *ppos) -{ -	struct ath_softc *sc = file->private_data; -	char buf[32]; -	unsigned int len; - -	len = sprintf(buf, "%d\n", sc->spec_config.period); -	return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t write_file_spectral_period(struct file *file, -					  const char __user *user_buf, -					  size_t count, loff_t *ppos) -{ -	struct ath_softc *sc = file->private_data; -	unsigned long val; -	char buf[32]; -	ssize_t len; - -	len = min(count, sizeof(buf) - 1); -	if (copy_from_user(buf, user_buf, len)) -		return -EFAULT; - -	buf[len] = '\0'; -	if (kstrtoul(buf, 0, &val)) -		return -EINVAL; - -	if (val < 0 || val > 255) -		return -EINVAL; - -	sc->spec_config.period = val; -	return count; -} - -static const struct file_operations fops_spectral_period = { -	.read = read_file_spectral_period, -	.write = write_file_spectral_period, -	.open = simple_open, -	.owner = THIS_MODULE, -	.llseek = default_llseek, -}; - -static ssize_t read_file_spectral_fft_period(struct file *file, -					     char __user *user_buf, -					     size_t count, loff_t *ppos) -{ -	struct ath_softc *sc = file->private_data; -	char buf[32]; -	unsigned int len; - -	len = sprintf(buf, "%d\n", sc->spec_config.fft_period); -	return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t write_file_spectral_fft_period(struct file *file, -					      const char __user *user_buf, -					      size_t count, loff_t *ppos) -{ -	struct ath_softc *sc = file->private_data; -	unsigned long val; -	char buf[32]; -	ssize_t len; - -	len = min(count, sizeof(buf) - 1); -	if (copy_from_user(buf, user_buf, len)) -		return -EFAULT; - -	buf[len] = '\0'; -	if (kstrtoul(buf, 0, &val)) -		return -EINVAL; - -	if (val < 0 || val > 15) -		return -EINVAL; - -	sc->spec_config.fft_period = val; -	return count; -} - -static const struct file_operations fops_spectral_fft_period = { -	.read = read_file_spectral_fft_period, -	.write = write_file_spectral_fft_period, -	.open = simple_open, -	.owner = THIS_MODULE, -	.llseek = default_llseek, -}; - -static struct dentry *create_buf_file_handler(const char *filename, -					      struct dentry *parent, -					      umode_t mode, -					      struct rchan_buf *buf, -					      int *is_global) -{ -	struct dentry *buf_file; - -	buf_file = debugfs_create_file(filename, mode, parent, buf, -				       &relay_file_operations); -	*is_global = 1; -	return buf_file; -} - -static int remove_buf_file_handler(struct dentry *dentry) -{ -	debugfs_remove(dentry); - -	return 0; -} - -void ath_debug_send_fft_sample(struct ath_softc *sc, -			       struct fft_sample_tlv *fft_sample_tlv) -{ -	int length; -	if (!sc->rfs_chan_spec_scan) -		return; - -	length = __be16_to_cpu(fft_sample_tlv->length) + -		 sizeof(*fft_sample_tlv); -	relay_write(sc->rfs_chan_spec_scan, fft_sample_tlv, length); -} - -static struct rchan_callbacks rfs_spec_scan_cb = { -	.create_buf_file = create_buf_file_handler, -	.remove_buf_file = remove_buf_file_handler, -}; - -  static ssize_t read_file_regidx(struct file *file, char __user *user_buf,                                  size_t count, loff_t *ppos)  { @@ -1439,22 +1094,22 @@ static ssize_t read_file_dump_nfcal(struct file *file, char __user *user_buf,  	if (!buf)  		return -ENOMEM; -	len += snprintf(buf + len, size - len, -			"Channel Noise Floor : %d\n", ah->noise); -	len += snprintf(buf + len, size - len, -			"Chain | privNF | # Readings | NF Readings\n"); +	len += scnprintf(buf + len, size - len, +			 "Channel Noise Floor : %d\n", ah->noise); +	len += scnprintf(buf + len, size - len, +			 "Chain | privNF | # Readings | NF Readings\n");  	for (i = 0; i < NUM_NF_READINGS; i++) {  		if (!(chainmask & (1 << i)) ||  		    ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf)))  			continue;  		nread = AR_PHY_CCA_FILTERWINDOW_LENGTH - h[i].invalidNFcount; -		len += snprintf(buf + len, size - len, " %d\t %d\t %d\t\t", -				i, h[i].privNF, nread); +		len += scnprintf(buf + len, size - len, " %d\t %d\t %d\t\t", +				 i, h[i].privNF, nread);  		for (j = 0; j < nread; j++) -			len += snprintf(buf + len, size - len, -					" %d", h[i].nfCalBuffer[j]); -		len += snprintf(buf + len, size - len, "\n"); +			len += scnprintf(buf + len, size - len, +					 " %d", h[i].nfCalBuffer[j]); +		len += scnprintf(buf + len, size - len, "\n");  	}  	if (len > size) @@ -1473,62 +1128,6 @@ static const struct file_operations fops_dump_nfcal = {  	.llseek = default_llseek,  }; -static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf, -				     size_t count, loff_t *ppos) -{ -	struct ath_softc *sc = file->private_data; -	struct ath_hw *ah = sc->sc_ah; -	u32 len = 0, size = 1500; -	ssize_t retval = 0; -	char *buf; - -	buf = kzalloc(size, GFP_KERNEL); -	if (!buf) -		return -ENOMEM; - -	len = ah->eep_ops->dump_eeprom(ah, true, buf, len, size); - -	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); -	kfree(buf); - -	return retval; -} - -static const struct file_operations fops_base_eeprom = { -	.read = read_file_base_eeprom, -	.open = simple_open, -	.owner = THIS_MODULE, -	.llseek = default_llseek, -}; - -static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf, -				      size_t count, loff_t *ppos) -{ -	struct ath_softc *sc = file->private_data; -	struct ath_hw *ah = sc->sc_ah; -	u32 len = 0, size = 6000; -	char *buf; -	size_t retval; - -	buf = kzalloc(size, GFP_KERNEL); -	if (buf == NULL) -		return -ENOMEM; - -	len = ah->eep_ops->dump_eeprom(ah, false, buf, len, size); - -	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); -	kfree(buf); - -	return retval; -} - -static const struct file_operations fops_modal_eeprom = { -	.read = read_file_modal_eeprom, -	.open = simple_open, -	.owner = THIS_MODULE, -	.llseek = default_llseek, -}; -  #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT  static ssize_t read_file_btcoex(struct file *file, char __user *user_buf,  				size_t count, loff_t *ppos) @@ -1543,8 +1142,8 @@ static ssize_t read_file_btcoex(struct file *file, char __user *user_buf,  		return -ENOMEM;  	if (!sc->sc_ah->common.btcoex_enabled) { -		len = snprintf(buf, size, "%s\n", -			       "BTCOEX is disabled"); +		len = scnprintf(buf, size, "%s\n", +				"BTCOEX is disabled");  		goto exit;  	} @@ -1564,86 +1163,6 @@ static const struct file_operations fops_btcoex = {  };  #endif -static ssize_t read_file_node_stat(struct file *file, char __user *user_buf, -				   size_t count, loff_t *ppos) -{ -	struct ath_node *an = file->private_data; -	struct ath_softc *sc = an->sc; -	struct ath_atx_tid *tid; -	struct ath_atx_ac *ac; -	struct ath_txq *txq; -	u32 len = 0, size = 4096; -	char *buf; -	size_t retval; -	int tidno, acno; - -	buf = kzalloc(size, GFP_KERNEL); -	if (buf == NULL) -		return -ENOMEM; - -	if (!an->sta->ht_cap.ht_supported) { -		len = snprintf(buf, size, "%s\n", -			       "HT not supported"); -		goto exit; -	} - -	len = snprintf(buf, size, "Max-AMPDU: %d\n", -		       an->maxampdu); -	len += snprintf(buf + len, size - len, "MPDU Density: %d\n\n", -			an->mpdudensity); - -	len += snprintf(buf + len, size - len, -			"%2s%7s\n", "AC", "SCHED"); - -	for (acno = 0, ac = &an->ac[acno]; -	     acno < IEEE80211_NUM_ACS; acno++, ac++) { -		txq = ac->txq; -		ath_txq_lock(sc, txq); -		len += snprintf(buf + len, size - len, -				"%2d%7d\n", -				acno, ac->sched); -		ath_txq_unlock(sc, txq); -	} - -	len += snprintf(buf + len, size - len, -			"\n%3s%11s%10s%10s%10s%10s%9s%6s%8s\n", -			"TID", "SEQ_START", "SEQ_NEXT", "BAW_SIZE", -			"BAW_HEAD", "BAW_TAIL", "BAR_IDX", "SCHED", "PAUSED"); - -	for (tidno = 0, tid = &an->tid[tidno]; -	     tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { -		txq = tid->ac->txq; -		ath_txq_lock(sc, txq); -		len += snprintf(buf + len, size - len, -				"%3d%11d%10d%10d%10d%10d%9d%6d%8d\n", -				tid->tidno, tid->seq_start, tid->seq_next, -				tid->baw_size, tid->baw_head, tid->baw_tail, -				tid->bar_index, tid->sched, tid->paused); -		ath_txq_unlock(sc, txq); -	} -exit: -	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); -	kfree(buf); - -	return retval; -} - -static const struct file_operations fops_node_stat = { -	.read = read_file_node_stat, -	.open = simple_open, -	.owner = THIS_MODULE, -	.llseek = default_llseek, -}; - -void ath9k_sta_add_debugfs(struct ieee80211_hw *hw, -			   struct ieee80211_vif *vif, -			   struct ieee80211_sta *sta, -			   struct dentry *dir) -{ -	struct ath_node *an = (struct ath_node *)sta->drv_priv; -	debugfs_create_file("node_stat", S_IRUGO, dir, an, &fops_node_stat); -} -  /* Ethtool support for get-stats */  #define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO" @@ -1767,10 +1286,7 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw,  void ath9k_deinit_debug(struct ath_softc *sc)  { -	if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) { -		relay_close(sc->rfs_chan_spec_scan); -		sc->rfs_chan_spec_scan = NULL; -	} +	ath9k_spectral_deinit_debug(sc);  }  int ath9k_init_debug(struct ath_hw *ah) @@ -1789,6 +1305,8 @@ int ath9k_init_debug(struct ath_hw *ah)  #endif  	ath9k_dfs_init_debug(sc); +	ath9k_tx99_init_debug(sc); +	ath9k_spectral_init_debug(sc);  	debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc,  			    &fops_dma); @@ -1810,8 +1328,10 @@ int ath9k_init_debug(struct ath_hw *ah)  			    &fops_misc);  	debugfs_create_file("reset", S_IRUSR, sc->debug.debugfs_phy, sc,  			    &fops_reset); -	debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, sc, -			    &fops_recv); + +	ath9k_cmn_debug_recv(sc->debug.debugfs_phy, &sc->debug.stats.rxstats); +	ath9k_cmn_debug_phy_err(sc->debug.debugfs_phy, &sc->debug.stats.rxstats); +  	debugfs_create_u8("rx_chainmask", S_IRUSR, sc->debug.debugfs_phy,  			  &ah->rxchainmask);  	debugfs_create_u8("tx_chainmask", S_IRUSR, sc->debug.debugfs_phy, @@ -1831,27 +1351,10 @@ int ath9k_init_debug(struct ath_hw *ah)  			    &fops_regdump);  	debugfs_create_file("dump_nfcal", S_IRUSR, sc->debug.debugfs_phy, sc,  			    &fops_dump_nfcal); -	debugfs_create_file("base_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc, -			    &fops_base_eeprom); -	debugfs_create_file("modal_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc, -			    &fops_modal_eeprom); -	sc->rfs_chan_spec_scan = relay_open("spectral_scan", -					    sc->debug.debugfs_phy, -					    1024, 256, &rfs_spec_scan_cb, -					    NULL); -	debugfs_create_file("spectral_scan_ctl", S_IRUSR | S_IWUSR, -			    sc->debug.debugfs_phy, sc, -			    &fops_spec_scan_ctl); -	debugfs_create_file("spectral_short_repeat", S_IRUSR | S_IWUSR, -			    sc->debug.debugfs_phy, sc, -			    &fops_spectral_short_repeat); -	debugfs_create_file("spectral_count", S_IRUSR | S_IWUSR, -			    sc->debug.debugfs_phy, sc, &fops_spectral_count); -	debugfs_create_file("spectral_period", S_IRUSR | S_IWUSR, -			    sc->debug.debugfs_phy, sc, &fops_spectral_period); -	debugfs_create_file("spectral_fft_period", S_IRUSR | S_IWUSR, -			    sc->debug.debugfs_phy, sc, -			    &fops_spectral_fft_period); + +	ath9k_cmn_debug_base_eeprom(sc->debug.debugfs_phy, sc->sc_ah); +	ath9k_cmn_debug_modal_eeprom(sc->debug.debugfs_phy, sc->sc_ah); +  	debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR,  			   sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask);  	debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR, @@ -1864,5 +1367,6 @@ int ath9k_init_debug(struct ath_hw *ah)  	debugfs_create_file("btcoex", S_IRUSR, sc->debug.debugfs_phy, sc,  			    &fops_btcoex);  #endif +  	return 0;  } diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 6e1556fa2f3..53ae15bd0c9 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -18,7 +18,6 @@  #define DEBUG_H  #include "hw.h" -#include "rc.h"  #include "dfs_debug.h"  struct ath_txq; @@ -27,11 +26,13 @@ struct fft_sample_tlv;  #ifdef CONFIG_ATH9K_DEBUGFS  #define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++ +#define RX_STAT_INC(c) (sc->debug.stats.rxstats.c++)  #define RESET_STAT_INC(sc, type) sc->debug.stats.reset[type]++  #define ANT_STAT_INC(i, c) sc->debug.stats.ant_stats[i].c++  #define ANT_LNA_INC(i, c) sc->debug.stats.ant_stats[i].lna_recv_cnt[c]++;  #else  #define TX_STAT_INC(q, c) do { } while (0) +#define RX_STAT_INC(c)  #define RESET_STAT_INC(sc, type) do { } while (0)  #define ANT_STAT_INC(i, c) do { } while (0)  #define ANT_LNA_INC(i, c) do { } while (0) @@ -42,6 +43,7 @@ enum ath_reset_type {  	RESET_TYPE_BB_WATCHDOG,  	RESET_TYPE_FATAL_INT,  	RESET_TYPE_TX_ERROR, +	RESET_TYPE_TX_GTT,  	RESET_TYPE_TX_HANG,  	RESET_TYPE_PLL_HANG,  	RESET_TYPE_MAC_HANG, @@ -193,58 +195,30 @@ struct ath_tx_stats {  #define TXSTATS sc->debug.stats.txstats  #define PR(str, elem)							\  	do {								\ -		len += snprintf(buf + len, size - len,			\ -				"%s%13u%11u%10u%10u\n", str,		\ -				TXSTATS[PR_QNUM(IEEE80211_AC_BE)].elem,	\ -				TXSTATS[PR_QNUM(IEEE80211_AC_BK)].elem,	\ -				TXSTATS[PR_QNUM(IEEE80211_AC_VI)].elem,	\ -				TXSTATS[PR_QNUM(IEEE80211_AC_VO)].elem); \ +		len += scnprintf(buf + len, size - len,			\ +				 "%s%13u%11u%10u%10u\n", str,		\ +				 TXSTATS[PR_QNUM(IEEE80211_AC_BE)].elem,\ +				 TXSTATS[PR_QNUM(IEEE80211_AC_BK)].elem,\ +				 TXSTATS[PR_QNUM(IEEE80211_AC_VI)].elem,\ +				 TXSTATS[PR_QNUM(IEEE80211_AC_VO)].elem); \  	} while(0) -#define RX_STAT_INC(c) (sc->debug.stats.rxstats.c++) +struct ath_rx_rate_stats { +	struct { +		u32 ht20_cnt; +		u32 ht40_cnt; +		u32 sgi_cnt; +		u32 lgi_cnt; +	} ht_stats[24]; -/** - * struct ath_rx_stats - RX Statistics - * @rx_pkts_all:  No. of total frames received, including ones that -	may have had errors. - * @rx_bytes_all:  No. of total bytes received, including ones that -	may have had errors. - * @crc_err: No. of frames with incorrect CRC value - * @decrypt_crc_err: No. of frames whose CRC check failed after -	decryption process completed - * @phy_err: No. of frames whose reception failed because the PHY -	encountered an error - * @mic_err: No. of frames with incorrect TKIP MIC verification failure - * @pre_delim_crc_err: Pre-Frame delimiter CRC error detections - * @post_delim_crc_err: Post-Frame delimiter CRC error detections - * @decrypt_busy_err: Decryption interruptions counter - * @phy_err_stats: Individual PHY error statistics - * @rx_len_err:  No. of frames discarded due to bad length. - * @rx_oom_err:  No. of frames dropped due to OOM issues. - * @rx_rate_err:  No. of frames dropped due to rate errors. - * @rx_too_many_frags_err:  Frames dropped due to too-many-frags received. - * @rx_beacons:  No. of beacons received. - * @rx_frags:  No. of rx-fragements received. - * @rx_spectral: No of spectral packets received. - */ -struct ath_rx_stats { -	u32 rx_pkts_all; -	u32 rx_bytes_all; -	u32 crc_err; -	u32 decrypt_crc_err; -	u32 phy_err; -	u32 mic_err; -	u32 pre_delim_crc_err; -	u32 post_delim_crc_err; -	u32 decrypt_busy_err; -	u32 phy_err_stats[ATH9K_PHYERR_MAX]; -	u32 rx_len_err; -	u32 rx_oom_err; -	u32 rx_rate_err; -	u32 rx_too_many_frags_err; -	u32 rx_beacons; -	u32 rx_frags; -	u32 rx_spectral; +	struct { +		u32 ofdm_cnt; +	} ofdm_stats[8]; + +	struct { +		u32 cck_lp_cnt; +		u32 cck_sp_cnt; +	} cck_stats[4];  };  #define ANT_MAIN 0 @@ -292,14 +266,12 @@ void ath9k_sta_add_debugfs(struct ieee80211_hw *hw,  			   struct ieee80211_vif *vif,  			   struct ieee80211_sta *sta,  			   struct dentry *dir); -void ath_debug_send_fft_sample(struct ath_softc *sc, -			       struct fft_sample_tlv *fft_sample);  void ath9k_debug_stat_ant(struct ath_softc *sc,  			  struct ath_hw_antcomb_conf *div_ant_conf,  			  int main_rssi_avg, int alt_rssi_avg); -#else +void ath9k_debug_sync_cause(struct ath_softc *sc, u32 sync_cause); -#define RX_STAT_INC(c) /* NOP */ +#else  static inline int ath9k_init_debug(struct ath_hw *ah)  { @@ -331,6 +303,23 @@ static inline void ath9k_debug_stat_ant(struct ath_softc *sc,  } +static inline void +ath9k_debug_sync_cause(struct ath_softc *sc, u32 sync_cause) +{ +} +  #endif /* CONFIG_ATH9K_DEBUGFS */ +#ifdef CONFIG_ATH9K_STATION_STATISTICS +void ath_debug_rate_stats(struct ath_softc *sc, +			  struct ath_rx_status *rs, +			  struct sk_buff *skb); +#else +static inline void ath_debug_rate_stats(struct ath_softc *sc, +					struct ath_rx_status *rs, +					struct sk_buff *skb) +{ +} +#endif /* CONFIG_ATH9K_STATION_STATISTICS */ +  #endif /* DEBUG_H */ diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c b/drivers/net/wireless/ath/ath9k/debug_sta.c new file mode 100644 index 00000000000..ffca918ff16 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/debug_sta.c @@ -0,0 +1,268 @@ +/* + * Copyright (c) 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 "ath9k.h" + +/*************/ +/* node_aggr */ +/*************/ + +static ssize_t read_file_node_aggr(struct file *file, char __user *user_buf, +				   size_t count, loff_t *ppos) +{ +	struct ath_node *an = file->private_data; +	struct ath_softc *sc = an->sc; +	struct ath_atx_tid *tid; +	struct ath_atx_ac *ac; +	struct ath_txq *txq; +	u32 len = 0, size = 4096; +	char *buf; +	size_t retval; +	int tidno, acno; + +	buf = kzalloc(size, GFP_KERNEL); +	if (buf == NULL) +		return -ENOMEM; + +	if (!an->sta->ht_cap.ht_supported) { +		len = scnprintf(buf, size, "%s\n", +				"HT not supported"); +		goto exit; +	} + +	len = scnprintf(buf, size, "Max-AMPDU: %d\n", +			an->maxampdu); +	len += scnprintf(buf + len, size - len, "MPDU Density: %d\n\n", +			 an->mpdudensity); + +	len += scnprintf(buf + len, size - len, +			 "%2s%7s\n", "AC", "SCHED"); + +	for (acno = 0, ac = &an->ac[acno]; +	     acno < IEEE80211_NUM_ACS; acno++, ac++) { +		txq = ac->txq; +		ath_txq_lock(sc, txq); +		len += scnprintf(buf + len, size - len, +				 "%2d%7d\n", +				 acno, ac->sched); +		ath_txq_unlock(sc, txq); +	} + +	len += scnprintf(buf + len, size - len, +			 "\n%3s%11s%10s%10s%10s%10s%9s%6s%8s\n", +			 "TID", "SEQ_START", "SEQ_NEXT", "BAW_SIZE", +			 "BAW_HEAD", "BAW_TAIL", "BAR_IDX", "SCHED", "PAUSED"); + +	for (tidno = 0, tid = &an->tid[tidno]; +	     tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { +		txq = tid->ac->txq; +		ath_txq_lock(sc, txq); +		if (tid->active) { +			len += scnprintf(buf + len, size - len, +					 "%3d%11d%10d%10d%10d%10d%9d%6d\n", +					 tid->tidno, +					 tid->seq_start, +					 tid->seq_next, +					 tid->baw_size, +					 tid->baw_head, +					 tid->baw_tail, +					 tid->bar_index, +					 tid->sched); +		} +		ath_txq_unlock(sc, txq); +	} +exit: +	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); +	kfree(buf); + +	return retval; +} + +static const struct file_operations fops_node_aggr = { +	.read = read_file_node_aggr, +	.open = simple_open, +	.owner = THIS_MODULE, +	.llseek = default_llseek, +}; + +/*************/ +/* node_recv */ +/*************/ + +void ath_debug_rate_stats(struct ath_softc *sc, +			  struct ath_rx_status *rs, +			  struct sk_buff *skb) +{ +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; +	struct ath_hw *ah = sc->sc_ah; +	struct ieee80211_rx_status *rxs; +	struct ath_rx_rate_stats *rstats; +	struct ieee80211_sta *sta; +	struct ath_node *an; + +	if (!ieee80211_is_data(hdr->frame_control)) +		return; + +	rcu_read_lock(); + +	sta = ieee80211_find_sta_by_ifaddr(sc->hw, hdr->addr2, NULL); +	if (!sta) +		goto exit; + +	an = (struct ath_node *) sta->drv_priv; +	rstats = &an->rx_rate_stats; +	rxs = IEEE80211_SKB_RXCB(skb); + +	if (IS_HT_RATE(rs->rs_rate)) { +		if (rxs->rate_idx >= ARRAY_SIZE(rstats->ht_stats)) +			goto exit; + +		if (rxs->flag & RX_FLAG_40MHZ) +			rstats->ht_stats[rxs->rate_idx].ht40_cnt++; +		else +			rstats->ht_stats[rxs->rate_idx].ht20_cnt++; + +		if (rxs->flag & RX_FLAG_SHORT_GI) +			rstats->ht_stats[rxs->rate_idx].sgi_cnt++; +		else +			rstats->ht_stats[rxs->rate_idx].lgi_cnt++; + +		goto exit; +	} + +	if (IS_CCK_RATE(rs->rs_rate)) { +		if (rxs->flag & RX_FLAG_SHORTPRE) +			rstats->cck_stats[rxs->rate_idx].cck_sp_cnt++; +		else +			rstats->cck_stats[rxs->rate_idx].cck_lp_cnt++; + +		goto exit; +	} + +	if (IS_OFDM_RATE(rs->rs_rate)) { +		if (ah->curchan->chan->band == IEEE80211_BAND_2GHZ) +			rstats->ofdm_stats[rxs->rate_idx - 4].ofdm_cnt++; +		else +			rstats->ofdm_stats[rxs->rate_idx].ofdm_cnt++; +	} +exit: +	rcu_read_unlock(); +} + +#define PRINT_CCK_RATE(str, i, sp)					\ +	do {								\ +		len += scnprintf(buf + len, size - len,			\ +			 "%11s : %10u\n",				\ +			 str,						\ +			 (sp) ? rstats->cck_stats[i].cck_sp_cnt :	\ +			 rstats->cck_stats[i].cck_lp_cnt);		\ +	} while (0) + +#define PRINT_OFDM_RATE(str, i)					\ +	do {							\ +		len += scnprintf(buf + len, size - len,		\ +			 "%11s : %10u\n",			\ +			 str,					\ +			 rstats->ofdm_stats[i].ofdm_cnt);	\ +	} while (0) + +static ssize_t read_file_node_recv(struct file *file, char __user *user_buf, +				   size_t count, loff_t *ppos) +{ +	struct ath_node *an = file->private_data; +	struct ath_softc *sc = an->sc; +	struct ath_hw *ah = sc->sc_ah; +	struct ath_rx_rate_stats *rstats; +	struct ieee80211_sta *sta = an->sta; +	enum ieee80211_band band; +	u32 len = 0, size = 4096; +	char *buf; +	size_t retval; +	int i; + +	buf = kzalloc(size, GFP_KERNEL); +	if (buf == NULL) +		return -ENOMEM; + +	band = ah->curchan->chan->band; +	rstats = &an->rx_rate_stats; + +	if (!sta->ht_cap.ht_supported) +		goto legacy; + +	len += scnprintf(buf + len, size - len, +			 "%24s%10s%10s%10s\n", +			 "HT20", "HT40", "SGI", "LGI"); + +	for (i = 0; i < 24; i++) { +		len += scnprintf(buf + len, size - len, +				 "%8s%3u : %10u%10u%10u%10u\n", +				 "MCS", i, +				 rstats->ht_stats[i].ht20_cnt, +				 rstats->ht_stats[i].ht40_cnt, +				 rstats->ht_stats[i].sgi_cnt, +				 rstats->ht_stats[i].lgi_cnt); +	} + +	len += scnprintf(buf + len, size - len, "\n"); + +legacy: +	if (band == IEEE80211_BAND_2GHZ) { +		PRINT_CCK_RATE("CCK-1M/LP", 0, false); +		PRINT_CCK_RATE("CCK-2M/LP", 1, false); +		PRINT_CCK_RATE("CCK-5.5M/LP", 2, false); +		PRINT_CCK_RATE("CCK-11M/LP", 3, false); + +		PRINT_CCK_RATE("CCK-2M/SP", 1, true); +		PRINT_CCK_RATE("CCK-5.5M/SP", 2, true); +		PRINT_CCK_RATE("CCK-11M/SP", 3, true); +	} + +	PRINT_OFDM_RATE("OFDM-6M", 0); +	PRINT_OFDM_RATE("OFDM-9M", 1); +	PRINT_OFDM_RATE("OFDM-12M", 2); +	PRINT_OFDM_RATE("OFDM-18M", 3); +	PRINT_OFDM_RATE("OFDM-24M", 4); +	PRINT_OFDM_RATE("OFDM-36M", 5); +	PRINT_OFDM_RATE("OFDM-48M", 6); +	PRINT_OFDM_RATE("OFDM-54M", 7); + +	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); +	kfree(buf); + +	return retval; +} + +#undef PRINT_OFDM_RATE +#undef PRINT_CCK_RATE + +static const struct file_operations fops_node_recv = { +	.read = read_file_node_recv, +	.open = simple_open, +	.owner = THIS_MODULE, +	.llseek = default_llseek, +}; + +void ath9k_sta_add_debugfs(struct ieee80211_hw *hw, +			   struct ieee80211_vif *vif, +			   struct ieee80211_sta *sta, +			   struct dentry *dir) +{ +	struct ath_node *an = (struct ath_node *)sta->drv_priv; + +	debugfs_create_file("node_aggr", S_IRUGO, dir, an, &fops_node_aggr); +	debugfs_create_file("node_recv", S_IRUGO, dir, an, &fops_node_recv); +} diff --git a/drivers/net/wireless/ath/ath9k/dfs.c b/drivers/net/wireless/ath/ath9k/dfs.c index 7187d367151..726271c7c33 100644 --- a/drivers/net/wireless/ath/ath9k/dfs.c +++ b/drivers/net/wireless/ath/ath9k/dfs.c @@ -158,8 +158,8 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data,  		return;  	} -	ard.rssi = rs->rs_rssi_ctl0; -	ard.ext_rssi = rs->rs_rssi_ext0; +	ard.rssi = rs->rs_rssi_ctl[0]; +	ard.ext_rssi = rs->rs_rssi_ext[0];  	/*  	 * hardware stores this as 8 bit signed value. @@ -178,12 +178,12 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data,  	pe.ts = mactime;  	if (ath9k_postprocess_radar_event(sc, &ard, &pe)) {  		struct dfs_pattern_detector *pd = sc->dfs_detector; -		static u64 last_ts;  		ath_dbg(common, DFS,  			"ath9k_dfs_process_phyerr: channel=%d, ts=%llu, "  			"width=%d, rssi=%d, delta_ts=%llu\n", -			pe.freq, pe.ts, pe.width, pe.rssi, pe.ts-last_ts); -		last_ts = pe.ts; +			pe.freq, pe.ts, pe.width, pe.rssi, +			pe.ts - sc->dfs_prev_pulse_ts); +		sc->dfs_prev_pulse_ts = pe.ts;  		DFS_STAT_INC(sc, pulses_processed);  		if (pd != NULL && pd->add_pulse(pd, &pe)) {  			DFS_STAT_INC(sc, radar_detected); diff --git a/drivers/net/wireless/ath/ath9k/dfs.h b/drivers/net/wireless/ath/ath9k/dfs.h index 3c839f06a06..c6fa3d5b5d7 100644 --- a/drivers/net/wireless/ath/ath9k/dfs.h +++ b/drivers/net/wireless/ath/ath9k/dfs.h @@ -17,7 +17,7 @@  #ifndef ATH9K_DFS_H  #define ATH9K_DFS_H -#include "dfs_pattern_detector.h" +#include "../dfs_pattern_detector.h"  #if defined(CONFIG_ATH9K_DFS_CERTIFIED)  /** diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.c b/drivers/net/wireless/ath/ath9k/dfs_debug.c index 3c6e4138a95..8824610c21f 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_debug.c +++ b/drivers/net/wireless/ath/ath9k/dfs_debug.c @@ -20,16 +20,16 @@  #include "ath9k.h"  #include "dfs_debug.h" +#include "../dfs_pattern_detector.h" - -struct ath_dfs_pool_stats global_dfs_pool_stats = { 0 }; +static struct ath_dfs_pool_stats dfs_pool_stats = { 0 };  #define ATH9K_DFS_STAT(s, p) \ -	len += snprintf(buf + len, size - len, "%28s : %10u\n", s, \ -			sc->debug.stats.dfs_stats.p); +	len += scnprintf(buf + len, size - len, "%28s : %10u\n", s, \ +			 sc->debug.stats.dfs_stats.p);  #define ATH9K_DFS_POOL_STAT(s, p) \ -	len += snprintf(buf + len, size - len, "%28s : %10u\n", s, \ -			global_dfs_pool_stats.p); +	len += scnprintf(buf + len, size - len, "%28s : %10u\n", s, \ +			 dfs_pool_stats.p);  static ssize_t read_file_dfs(struct file *file, char __user *user_buf,  			     size_t count, loff_t *ppos) @@ -44,12 +44,21 @@ static ssize_t read_file_dfs(struct file *file, char __user *user_buf,  	if (buf == NULL)  		return -ENOMEM; -	len += snprintf(buf + len, size - len, "DFS support for " -			"macVersion = 0x%x, macRev = 0x%x: %s\n", -			hw_ver->macVersion, hw_ver->macRev, -			(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_DFS) ? +	len += scnprintf(buf + len, size - len, "DFS support for " +			 "macVersion = 0x%x, macRev = 0x%x: %s\n", +			 hw_ver->macVersion, hw_ver->macRev, +			 (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_DFS) ?  					"enabled" : "disabled"); -	len += snprintf(buf + len, size - len, "Pulse detector statistics:\n"); + +	if (!sc->dfs_detector) { +		len += scnprintf(buf + len, size - len, +				 "DFS detector not enabled\n"); +		goto exit; +	} + +	dfs_pool_stats = sc->dfs_detector->get_stats(sc->dfs_detector); + +	len += scnprintf(buf + len, size - len, "Pulse detector statistics:\n");  	ATH9K_DFS_STAT("pulse events reported   ", pulses_total);  	ATH9K_DFS_STAT("invalid pulse events    ", pulses_no_dfs);  	ATH9K_DFS_STAT("DFS pulses detected     ", pulses_detected); @@ -59,11 +68,12 @@ static ssize_t read_file_dfs(struct file *file, char __user *user_buf,  	ATH9K_DFS_STAT("Primary channel pulses  ", pri_phy_errors);  	ATH9K_DFS_STAT("Secondary channel pulses", ext_phy_errors);  	ATH9K_DFS_STAT("Dual channel pulses     ", dc_phy_errors); -	len += snprintf(buf + len, size - len, "Radar detector statistics " -			"(current DFS region: %d)\n", sc->dfs_detector->region); +	len += scnprintf(buf + len, size - len, "Radar detector statistics " +			 "(current DFS region: %d)\n", +			 sc->dfs_detector->region);  	ATH9K_DFS_STAT("Pulse events processed  ", pulses_processed);  	ATH9K_DFS_STAT("Radars detected         ", radar_detected); -	len += snprintf(buf + len, size - len, "Global Pool statistics:\n"); +	len += scnprintf(buf + len, size - len, "Global Pool statistics:\n");  	ATH9K_DFS_POOL_STAT("Pool references         ", pool_reference);  	ATH9K_DFS_POOL_STAT("Pulses allocated        ", pulse_allocated);  	ATH9K_DFS_POOL_STAT("Pulses alloc error      ", pulse_alloc_error); @@ -72,6 +82,7 @@ static ssize_t read_file_dfs(struct file *file, char __user *user_buf,  	ATH9K_DFS_POOL_STAT("Seqs. alloc error       ", pseq_alloc_error);  	ATH9K_DFS_POOL_STAT("Seqs. in use            ", pseq_used); +exit:  	if (len > size)  		len = size; diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.h b/drivers/net/wireless/ath/ath9k/dfs_debug.h index e36810a4b58..7936c9126a2 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_debug.h +++ b/drivers/net/wireless/ath/ath9k/dfs_debug.h @@ -21,6 +21,8 @@  #include "hw.h" +struct ath_softc; +  /**   * struct ath_dfs_stats - DFS Statistics per wiphy   * @pulses_total:     pulses reported by HW @@ -51,25 +53,11 @@ struct ath_dfs_stats {  	u32 radar_detected;  }; -/** - * struct ath_dfs_pool_stats - DFS Statistics for global pools - */ -struct ath_dfs_pool_stats { -	u32 pool_reference; -	u32 pulse_allocated; -	u32 pulse_alloc_error; -	u32 pulse_used; -	u32 pseq_allocated; -	u32 pseq_alloc_error; -	u32 pseq_used; -};  #if defined(CONFIG_ATH9K_DFS_DEBUGFS)  #define DFS_STAT_INC(sc, c) (sc->debug.stats.dfs_stats.c++)  void ath9k_dfs_init_debug(struct ath_softc *sc); -#define DFS_POOL_STAT_INC(c) (global_dfs_pool_stats.c++) -#define DFS_POOL_STAT_DEC(c) (global_dfs_pool_stats.c--)  extern struct ath_dfs_pool_stats global_dfs_pool_stats;  #else @@ -77,8 +65,6 @@ extern struct ath_dfs_pool_stats global_dfs_pool_stats;  #define DFS_STAT_INC(sc, c) do { } while (0)  static inline void ath9k_dfs_init_debug(struct ath_softc *sc) { } -#define DFS_POOL_STAT_INC(c) do { } while (0) -#define DFS_POOL_STAT_DEC(c) do { } while (0)  #endif /* CONFIG_ATH9K_DFS_DEBUGFS */  #endif /* ATH9K_DFS_DEBUG_H */ diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 9ea8e4b779c..07b806c56c5 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -129,10 +129,10 @@ static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,  	struct base_eep_header_4k *pBase = &eep->baseEepHeader;  	if (!dump_base_hdr) { -		len += snprintf(buf + len, size - len, -				"%20s :\n", "2GHz modal Header"); +		len += scnprintf(buf + len, size - len, +				 "%20s :\n", "2GHz modal Header");  		len = ath9k_dump_4k_modal_eeprom(buf, len, size, -						  &eep->modalHeader); +						 &eep->modalHeader);  		goto out;  	} @@ -160,8 +160,8 @@ static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,  	PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF);  	PR_EEP("TX Gain type", pBase->txGainType); -	len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", -			pBase->macAddr); +	len += scnprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", +			 pBase->macAddr);  out:  	if (len > size) @@ -1085,31 +1085,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,  static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)  { -#define EEP_MAP4K_SPURCHAN \ -	(ah->eeprom.map4k.modalHeader.spurChans[i].spurChan) -	struct ath_common *common = ath9k_hw_common(ah); - -	u16 spur_val = AR_NO_SPUR; - -	ath_dbg(common, ANI, "Getting spur idx:%d is2Ghz:%d val:%x\n", -		i, is2GHz, ah->config.spurchans[i][is2GHz]); - -	switch (ah->config.spurmode) { -	case SPUR_DISABLE: -		break; -	case SPUR_ENABLE_IOCTL: -		spur_val = ah->config.spurchans[i][is2GHz]; -		ath_dbg(common, ANI, "Getting spur val from new loc. %d\n", -			spur_val); -		break; -	case SPUR_ENABLE_EEPROM: -		spur_val = EEP_MAP4K_SPURCHAN; -		break; -	} - -	return spur_val; - -#undef EEP_MAP4K_SPURCHAN +	return ah->eeprom.map4k.modalHeader.spurChans[i].spurChan;  }  const struct eeprom_ops eep_4k_ops = { diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 3ae1f3df063..5ba1385c983 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -125,8 +125,8 @@ static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,  	struct base_eep_ar9287_header *pBase = &eep->baseEepHeader;  	if (!dump_base_hdr) { -		len += snprintf(buf + len, size - len, -				"%20s :\n", "2GHz modal Header"); +		len += scnprintf(buf + len, size - len, +				 "%20s :\n", "2GHz modal Header");  		len = ar9287_dump_modal_eeprom(buf, len, size,  						&eep->modalHeader);  		goto out; @@ -157,8 +157,8 @@ static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,  	PR_EEP("Power Table Offset", pBase->pwrTableOffset);  	PR_EEP("OpenLoop Power Ctrl", pBase->openLoopPwrCntl); -	len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", -			pBase->macAddr); +	len += scnprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", +			 pBase->macAddr);  out:  	if (len > size) @@ -1004,31 +1004,7 @@ static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah,  static u16 ath9k_hw_ar9287_get_spur_channel(struct ath_hw *ah,  					    u16 i, bool is2GHz)  { -#define EEP_MAP9287_SPURCHAN \ -	(ah->eeprom.map9287.modalHeader.spurChans[i].spurChan) - -	struct ath_common *common = ath9k_hw_common(ah); -	u16 spur_val = AR_NO_SPUR; - -	ath_dbg(common, ANI, "Getting spur idx:%d is2Ghz:%d val:%x\n", -		i, is2GHz, ah->config.spurchans[i][is2GHz]); - -	switch (ah->config.spurmode) { -	case SPUR_DISABLE: -		break; -	case SPUR_ENABLE_IOCTL: -		spur_val = ah->config.spurchans[i][is2GHz]; -		ath_dbg(common, ANI, "Getting spur val from new loc. %d\n", -			spur_val); -		break; -	case SPUR_ENABLE_EEPROM: -		spur_val = EEP_MAP9287_SPURCHAN; -		break; -	} - -	return spur_val; - -#undef EEP_MAP9287_SPURCHAN +	return ah->eeprom.map9287.modalHeader.spurChans[i].spurChan;  }  const struct eeprom_ops eep_ar9287_ops = { diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 1c25368b383..3218ca99474 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -205,12 +205,12 @@ static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,  	struct base_eep_header *pBase = &eep->baseEepHeader;  	if (!dump_base_hdr) { -		len += snprintf(buf + len, size - len, -				"%20s :\n", "2GHz modal Header"); +		len += scnprintf(buf + len, size - len, +				 "%20s :\n", "2GHz modal Header");  		len = ath9k_def_dump_modal_eeprom(buf, len, size,  						   &eep->modalHeader[0]); -		len += snprintf(buf + len, size - len, -				"%20s :\n", "5GHz modal Header"); +		len += scnprintf(buf + len, size - len, +				 "%20s :\n", "5GHz modal Header");  		len = ath9k_def_dump_modal_eeprom(buf, len, size,  						   &eep->modalHeader[1]);  		goto out; @@ -240,8 +240,8 @@ static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,  	PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF);  	PR_EEP("OpenLoop Power Ctrl", pBase->openLoopPwrCntl); -	len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", -			pBase->macAddr); +	len += scnprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", +			 pBase->macAddr);  out:  	if (len > size) @@ -1348,31 +1348,7 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,  static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)  { -#define EEP_DEF_SPURCHAN \ -	(ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan) -	struct ath_common *common = ath9k_hw_common(ah); - -	u16 spur_val = AR_NO_SPUR; - -	ath_dbg(common, ANI, "Getting spur idx:%d is2Ghz:%d val:%x\n", -		i, is2GHz, ah->config.spurchans[i][is2GHz]); - -	switch (ah->config.spurmode) { -	case SPUR_DISABLE: -		break; -	case SPUR_ENABLE_IOCTL: -		spur_val = ah->config.spurchans[i][is2GHz]; -		ath_dbg(common, ANI, "Getting spur val from new loc. %d\n", -			spur_val); -		break; -	case SPUR_ENABLE_EEPROM: -		spur_val = EEP_DEF_SPURCHAN; -		break; -	} - -	return spur_val; - -#undef EEP_DEF_SPURCHAN +	return ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan;  }  const struct eeprom_ops eep_def_ops = { diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 4b412aaf4f3..b1956bf6e01 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -157,36 +157,6 @@ static void ath_detect_bt_priority(struct ath_softc *sc)  	}  } -static void ath9k_gen_timer_start(struct ath_hw *ah, -				  struct ath_gen_timer *timer, -				  u32 trig_timeout, -				  u32 timer_period) -{ -	ath9k_hw_gen_timer_start(ah, timer, trig_timeout, timer_period); - -	if ((ah->imask & ATH9K_INT_GENTIMER) == 0) { -		ath9k_hw_disable_interrupts(ah); -		ah->imask |= ATH9K_INT_GENTIMER; -		ath9k_hw_set_interrupts(ah); -		ath9k_hw_enable_interrupts(ah); -	} -} - -static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) -{ -	struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; - -	ath9k_hw_gen_timer_stop(ah, timer); - -	/* if no timer is enabled, turn off interrupt mask */ -	if (timer_table->timer_mask.val == 0) { -		ath9k_hw_disable_interrupts(ah); -		ah->imask &= ~ATH9K_INT_GENTIMER; -		ath9k_hw_set_interrupts(ah); -		ath9k_hw_enable_interrupts(ah); -	} -} -  static void ath_mci_ftp_adjust(struct ath_softc *sc)  {  	struct ath_btcoex *btcoex = &sc->btcoex; @@ -257,19 +227,9 @@ static void ath_btcoex_period_timer(unsigned long data)  	spin_unlock_bh(&btcoex->btcoex_lock); -	/* -	 * btcoex_period is in msec while (btocex/btscan_)no_stomp are in usec, -	 * ensure that we properly convert btcoex_period to usec -	 * for any comparision with (btcoex/btscan_)no_stomp. -	 */ -	if (btcoex->btcoex_period * 1000 != btcoex->btcoex_no_stomp) { -		if (btcoex->hw_timer_enabled) -			ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); - -		ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, timer_period, -				      timer_period * 10); -		btcoex->hw_timer_enabled = true; -	} +	if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) +		mod_timer(&btcoex->no_stomp_timer, +			 jiffies + msecs_to_jiffies(timer_period));  	ath9k_ps_restore(sc); @@ -282,7 +242,7 @@ skip_hw_wakeup:   * Generic tsf based hw timer which configures weight   * registers to time slice between wlan and bt traffic   */ -static void ath_btcoex_no_stomp_timer(void *arg) +static void ath_btcoex_no_stomp_timer(unsigned long arg)  {  	struct ath_softc *sc = (struct ath_softc *)arg;  	struct ath_hw *ah = sc->sc_ah; @@ -311,24 +271,18 @@ static int ath_init_btcoex_timer(struct ath_softc *sc)  	struct ath_btcoex *btcoex = &sc->btcoex;  	btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD; -	btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * 1000 * +	btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *  		btcoex->btcoex_period / 100; -	btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) * 1000 * +	btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) *  				   btcoex->btcoex_period / 100;  	setup_timer(&btcoex->period_timer, ath_btcoex_period_timer,  			(unsigned long) sc); +	setup_timer(&btcoex->no_stomp_timer, ath_btcoex_no_stomp_timer, +			(unsigned long) sc);  	spin_lock_init(&btcoex->btcoex_lock); -	btcoex->no_stomp_timer = ath_gen_timer_alloc(sc->sc_ah, -			ath_btcoex_no_stomp_timer, -			ath_btcoex_no_stomp_timer, -			(void *) sc, AR_FIRST_NDP_TIMER); - -	if (!btcoex->no_stomp_timer) -		return -ENOMEM; -  	return 0;  } @@ -343,10 +297,7 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc)  	ath_dbg(ath9k_hw_common(ah), BTCOEX, "Starting btcoex timers\n");  	/* make sure duty cycle timer is also stopped when resuming */ -	if (btcoex->hw_timer_enabled) { -		ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); -		btcoex->hw_timer_enabled = false; -	} +	del_timer_sync(&btcoex->no_stomp_timer);  	btcoex->bt_priority_cnt = 0;  	btcoex->bt_priority_time = jiffies; @@ -363,24 +314,16 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc)  void ath9k_btcoex_timer_pause(struct ath_softc *sc)  {  	struct ath_btcoex *btcoex = &sc->btcoex; -	struct ath_hw *ah = sc->sc_ah;  	del_timer_sync(&btcoex->period_timer); - -	if (btcoex->hw_timer_enabled) { -		ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); -		btcoex->hw_timer_enabled = false; -	} +	del_timer_sync(&btcoex->no_stomp_timer);  }  void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc)  {  	struct ath_btcoex *btcoex = &sc->btcoex; -	if (btcoex->hw_timer_enabled) { -		ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); -		btcoex->hw_timer_enabled = false; -	} +	del_timer_sync(&btcoex->no_stomp_timer);  }  u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen) @@ -400,12 +343,6 @@ u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen)  void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status)  { -	struct ath_hw *ah = sc->sc_ah; - -	if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) -		if (status & ATH9K_INT_GENTIMER) -			ath_gen_timer_isr(sc->sc_ah); -  	if (status & ATH9K_INT_MCI)  		ath_mci_intr(sc);  } @@ -447,10 +384,6 @@ void ath9k_deinit_btcoex(struct ath_softc *sc)  {  	struct ath_hw *ah = sc->sc_ah; -        if ((sc->btcoex.no_stomp_timer) && -	    ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_3WIRE) -		ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer); -  	if (ath9k_hw_mci_is_enabled(ah))  		ath_mci_cleanup(sc);  } @@ -522,22 +455,22 @@ static int ath9k_dump_mci_btcoex(struct ath_softc *sc, u8 *buf, u32 size)  	ATH_DUMP_BTCOEX("Concurrent Tx", btcoex_hw->mci.concur_tx);  	ATH_DUMP_BTCOEX("Concurrent RSSI cnt", btcoex->rssi_count); -	len += snprintf(buf + len, size - len, "BT Weights: "); +	len += scnprintf(buf + len, size - len, "BT Weights: ");  	for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++) -		len += snprintf(buf + len, size - len, "%08x ", -				btcoex_hw->bt_weight[i]); -	len += snprintf(buf + len, size - len, "\n"); -	len += snprintf(buf + len, size - len, "WLAN Weights: "); +		len += scnprintf(buf + len, size - len, "%08x ", +				 btcoex_hw->bt_weight[i]); +	len += scnprintf(buf + len, size - len, "\n"); +	len += scnprintf(buf + len, size - len, "WLAN Weights: ");  	for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++) -		len += snprintf(buf + len, size - len, "%08x ", -				btcoex_hw->wlan_weight[i]); -	len += snprintf(buf + len, size - len, "\n"); -	len += snprintf(buf + len, size - len, "Tx Priorities: "); +		len += scnprintf(buf + len, size - len, "%08x ", +				 btcoex_hw->wlan_weight[i]); +	len += scnprintf(buf + len, size - len, "\n"); +	len += scnprintf(buf + len, size - len, "Tx Priorities: ");  	for (i = 0; i < ATH_BTCOEX_STOMP_MAX; i++) -		len += snprintf(buf + len, size - len, "%08x ", +		len += scnprintf(buf + len, size - len, "%08x ",  				btcoex_hw->tx_prio[i]); -	len += snprintf(buf + len, size - len, "\n"); +	len += scnprintf(buf + len, size - len, "\n");  	return len;  } diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 6d5d716adc1..8e7153b186e 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -54,6 +54,8 @@ static struct usb_device_id ath9k_hif_usb_ids[] = {  	  .driver_info = AR9280_USB },  /* SMC Networks */  	{ USB_DEVICE(0x0411, 0x017f),  	  .driver_info = AR9280_USB },  /* Sony UWA-BR100 */ +	{ USB_DEVICE(0x0411, 0x0197), +	  .driver_info = AR9280_USB },  /* Buffalo WLI-UV-AG300P */  	{ USB_DEVICE(0x04da, 0x3904),  	  .driver_info = AR9280_USB }, diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 055d7c25e09..09a5d72f3ff 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -39,7 +39,6 @@  #define ATH_RESTART_CALINTERVAL   1200000 /* 20 minutes */  #define ATH_DEFAULT_BMISS_LIMIT 10 -#define IEEE80211_MS_TO_TU(x)   (((x) * 1000) / 1024)  #define TSF_TO_TU(_h, _l) \  	((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) @@ -262,6 +261,8 @@ enum tid_aggr_state {  struct ath9k_htc_sta {  	u8 index;  	enum tid_aggr_state tid_state[ATH9K_HTC_MAX_TID]; +	struct work_struct rc_update_work; +	struct ath9k_htc_priv *htc_priv;  };  #define ATH9K_HTC_RXBUF 256 @@ -275,7 +276,6 @@ struct ath9k_htc_rxbuf {  };  struct ath9k_htc_rx { -	int last_rssi; /* FIXME: per-STA */  	struct list_head rxbuf;  	spinlock_t rxbuflock;  }; @@ -325,14 +325,14 @@ static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb)  #define TX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c++)  #define TX_STAT_ADD(c, a) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c += a) -#define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c++) -#define RX_STAT_ADD(c, a) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c += a) +#define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.skbrx_stats.c++) +#define RX_STAT_ADD(c, a) (hif_dev->htc_handle->drv_priv->debug.skbrx_stats.c += a)  #define CAB_STAT_INC   priv->debug.tx_stats.cab_queued++  #define TX_QSTAT_INC(q) (priv->debug.tx_stats.queue_stats[q]++)  void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, -			   struct ath_htc_rx_status *rxs); +			   struct ath_rx_status *rs);  struct ath_tx_stats {  	u32 buf_queued; @@ -345,25 +345,18 @@ struct ath_tx_stats {  	u32 queue_stats[IEEE80211_NUM_ACS];  }; -struct ath_rx_stats { +struct ath_skbrx_stats {  	u32 skb_allocated;  	u32 skb_completed;  	u32 skb_completed_bytes;  	u32 skb_dropped; -	u32 err_crc; -	u32 err_decrypt_crc; -	u32 err_mic; -	u32 err_pre_delim; -	u32 err_post_delim; -	u32 err_decrypt_busy; -	u32 err_phy; -	u32 err_phy_stats[ATH9K_PHYERR_MAX];  };  struct ath9k_debug {  	struct dentry *debugfs_phy;  	struct ath_tx_stats tx_stats;  	struct ath_rx_stats rx_stats; +	struct ath_skbrx_stats skbrx_stats;  };  void ath9k_htc_get_et_strings(struct ieee80211_hw *hw, @@ -385,7 +378,7 @@ void ath9k_htc_get_et_stats(struct ieee80211_hw *hw,  #define TX_QSTAT_INC(c) do { } while (0)  static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, -					 struct ath_htc_rx_status *rxs) +					 struct ath_rx_status *rs)  {  } @@ -405,12 +398,18 @@ static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv,  #define DEFAULT_SWBA_RESPONSE 40 /* in TUs */  #define MIN_SWBA_RESPONSE     10 /* in TUs */ -struct htc_beacon_config { +struct htc_beacon { +	enum { +		OK,		/* no change needed */ +		UPDATE,		/* update pending */ +		COMMIT		/* beacon sent, commit change */ +	} updateslot;		/* slot time update fsm */ +  	struct ieee80211_vif *bslot[ATH9K_HTC_MAX_BCN_VIF]; -	u16 beacon_interval; -	u16 dtim_period; -	u16 bmiss_timeout; -	u32 bmiss_cnt; +	u32 bmisscnt; +	u32 beaconq; +	int slottime; +	int slotupdate;  };  struct ath_btcoex { @@ -438,12 +437,8 @@ static inline void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv)  }  #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ -#define OP_INVALID		   BIT(0) -#define OP_SCANNING		   BIT(1) -#define OP_ENABLE_BEACON           BIT(2)  #define OP_BT_PRIORITY_DETECTED    BIT(3)  #define OP_BT_SCAN                 BIT(4) -#define OP_ANI_RUNNING             BIT(5)  #define OP_TSF_RESET               BIT(6)  struct ath9k_htc_priv { @@ -486,10 +481,10 @@ struct ath9k_htc_priv {  	unsigned long op_flags;  	struct ath9k_hw_cal_data caldata; -	struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];  	spinlock_t beacon_lock; -	struct htc_beacon_config cur_beacon_conf; +	struct ath_beacon_config cur_beacon_conf; +	struct htc_beacon beacon;  	struct ath9k_htc_rx rx;  	struct ath9k_htc_tx tx; @@ -514,7 +509,6 @@ struct ath9k_htc_priv {  	struct work_struct led_work;  #endif -	int beaconq;  	int cabq;  	int hwq_map[IEEE80211_NUM_ACS]; @@ -600,10 +594,15 @@ void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw);  struct base_eep_header *ath9k_htc_get_eeprom_base(struct ath9k_htc_priv *priv);  #ifdef CONFIG_MAC80211_LEDS +void ath9k_configure_leds(struct ath9k_htc_priv *priv);  void ath9k_init_leds(struct ath9k_htc_priv *priv);  void ath9k_deinit_leds(struct ath9k_htc_priv *priv);  void ath9k_led_work(struct work_struct *work);  #else +static inline void ath9k_configure_leds(struct ath9k_htc_priv *priv) +{ +} +  static inline void ath9k_init_leds(struct ath9k_htc_priv *priv)  {  } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index e0c03bd6418..e8b6ec3c1db 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -26,7 +26,7 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)  	memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));  	memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info)); -	ath9k_hw_get_txq_props(ah, priv->beaconq, &qi); +	ath9k_hw_get_txq_props(ah, priv->beacon.beaconq, &qi);  	if (priv->ah->opmode == NL80211_IFTYPE_AP ||  	    priv->ah->opmode == NL80211_IFTYPE_MESH_POINT) { @@ -54,235 +54,78 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)  	} -	if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) { +	if (!ath9k_hw_set_txq_props(ah, priv->beacon.beaconq, &qi)) {  		ath_err(ath9k_hw_common(ah), -			"Unable to update beacon queue %u!\n", priv->beaconq); +			"Unable to update beacon queue %u!\n", priv->beacon.beaconq);  	} else { -		ath9k_hw_resettxqueue(ah, priv->beaconq); +		ath9k_hw_resettxqueue(ah, priv->beacon.beaconq);  	}  } - -static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, -					struct htc_beacon_config *bss_conf) +/* + * Both nexttbtt and intval have to be in usecs. + */ +static void ath9k_htc_beacon_init(struct ath9k_htc_priv *priv, +				  struct ath_beacon_config *conf, +				  bool reset_tsf)  { -	struct ath_common *common = ath9k_hw_common(priv->ah); -	struct ath9k_beacon_state bs; -	enum ath9k_int imask = 0; -	int dtimperiod, dtimcount, sleepduration; -	int cfpperiod, cfpcount, bmiss_timeout; -	u32 nexttbtt = 0, intval, tsftu; -	__be32 htc_imask = 0; -	u64 tsf; -	int num_beacons, offset, dtim_dec_count, cfp_dec_count; +	struct ath_hw *ah = priv->ah;  	int ret __attribute__ ((unused)); +	__be32 htc_imask = 0;  	u8 cmd_rsp; -	memset(&bs, 0, sizeof(bs)); - -	intval = bss_conf->beacon_interval; -	bmiss_timeout = (ATH_DEFAULT_BMISS_LIMIT * bss_conf->beacon_interval); - -	/* -	 * Setup dtim and cfp parameters according to -	 * last beacon we received (which may be none). -	 */ -	dtimperiod = bss_conf->dtim_period; -	if (dtimperiod <= 0)		/* NB: 0 if not known */ -		dtimperiod = 1; -	dtimcount = 1; -	if (dtimcount >= dtimperiod)	/* NB: sanity check */ -		dtimcount = 0; -	cfpperiod = 1;			/* NB: no PCF support yet */ -	cfpcount = 0; - -	sleepduration = intval; -	if (sleepduration <= 0) -		sleepduration = intval; - -	/* -	 * Pull nexttbtt forward to reflect the current -	 * TSF and calculate dtim+cfp state for the result. -	 */ -	tsf = ath9k_hw_gettsf64(priv->ah); -	tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; - -	num_beacons = tsftu / intval + 1; -	offset = tsftu % intval; -	nexttbtt = tsftu - offset; -	if (offset) -		nexttbtt += intval; - -	/* DTIM Beacon every dtimperiod Beacon */ -	dtim_dec_count = num_beacons % dtimperiod; -	/* CFP every cfpperiod DTIM Beacon */ -	cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod; -	if (dtim_dec_count) -		cfp_dec_count++; - -	dtimcount -= dtim_dec_count; -	if (dtimcount < 0) -		dtimcount += dtimperiod; - -	cfpcount -= cfp_dec_count; -	if (cfpcount < 0) -		cfpcount += cfpperiod; - -	bs.bs_intval = intval; -	bs.bs_nexttbtt = nexttbtt; -	bs.bs_dtimperiod = dtimperiod*intval; -	bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval; -	bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod; -	bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod; -	bs.bs_cfpmaxduration = 0; - -	/* -	 * Calculate the number of consecutive beacons to miss* before taking -	 * a BMISS interrupt. The configuration is specified in TU so we only -	 * need calculate based	on the beacon interval.  Note that we clamp the -	 * result to at most 15 beacons. -	 */ -	if (sleepduration > intval) { -		bs.bs_bmissthreshold = ATH_DEFAULT_BMISS_LIMIT / 2; -	} else { -		bs.bs_bmissthreshold = DIV_ROUND_UP(bmiss_timeout, intval); -		if (bs.bs_bmissthreshold > 15) -			bs.bs_bmissthreshold = 15; -		else if (bs.bs_bmissthreshold <= 0) -			bs.bs_bmissthreshold = 1; -	} - -	/* -	 * Calculate sleep duration. The configuration is given in ms. -	 * We ensure a multiple of the beacon period is used. Also, if the sleep -	 * duration is greater than the DTIM period then it makes senses -	 * to make it a multiple of that. -	 * -	 * XXX fixed at 100ms -	 */ - -	bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration); -	if (bs.bs_sleepduration > bs.bs_dtimperiod) -		bs.bs_sleepduration = bs.bs_dtimperiod; - -	/* TSF out of range threshold fixed at 1 second */ -	bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; - -	ath_dbg(common, CONFIG, "intval: %u tsf: %llu tsftu: %u\n", -		intval, tsf, tsftu); -	ath_dbg(common, CONFIG, -		"bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n", -		bs.bs_bmissthreshold, bs.bs_sleepduration, -		bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext); - -	/* Set the computed STA beacon timers */ +	if (conf->intval >= TU_TO_USEC(DEFAULT_SWBA_RESPONSE)) +		ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; +	else +		ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE;  	WMI_CMD(WMI_DISABLE_INTR_CMDID); -	ath9k_hw_set_sta_beacon_timers(priv->ah, &bs); -	imask |= ATH9K_INT_BMISS; -	htc_imask = cpu_to_be32(imask); +	if (reset_tsf) +		ath9k_hw_reset_tsf(ah); +	ath9k_htc_beaconq_config(priv); +	ath9k_hw_beaconinit(ah, conf->nexttbtt, conf->intval); +	priv->beacon.bmisscnt = 0; +	htc_imask = cpu_to_be32(ah->imask);  	WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);  } -static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, -				       struct htc_beacon_config *bss_conf) +static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, +					struct ath_beacon_config *bss_conf)  { -	struct ath_common *common = ath9k_hw_common(priv->ah); +	struct ath9k_beacon_state bs;  	enum ath9k_int imask = 0; -	u32 nexttbtt, intval, tsftu;  	__be32 htc_imask = 0;  	int ret __attribute__ ((unused));  	u8 cmd_rsp; -	u64 tsf; -	intval = bss_conf->beacon_interval; -	intval /= ATH9K_HTC_MAX_BCN_VIF; -	nexttbtt = intval; - -	/* -	 * To reduce beacon misses under heavy TX load, -	 * set the beacon response time to a larger value. -	 */ -	if (intval > DEFAULT_SWBA_RESPONSE) -		priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; -	else -		priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; - -	if (test_bit(OP_TSF_RESET, &priv->op_flags)) { -		ath9k_hw_reset_tsf(priv->ah); -		clear_bit(OP_TSF_RESET, &priv->op_flags); -	} else { -		/* -		 * Pull nexttbtt forward to reflect the current TSF. -		 */ -		tsf = ath9k_hw_gettsf64(priv->ah); -		tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE; -		do { -			nexttbtt += intval; -		} while (nexttbtt < tsftu); -	} - -	if (test_bit(OP_ENABLE_BEACON, &priv->op_flags)) -		imask |= ATH9K_INT_SWBA; - -	ath_dbg(common, CONFIG, -		"AP Beacon config, intval: %d, nexttbtt: %u, resp_time: %d imask: 0x%x\n", -		bss_conf->beacon_interval, nexttbtt, -		priv->ah->config.sw_beacon_response_time, imask); - -	ath9k_htc_beaconq_config(priv); +	if (ath9k_cmn_beacon_config_sta(priv->ah, bss_conf, &bs) == -EPERM) +		return;  	WMI_CMD(WMI_DISABLE_INTR_CMDID); -	ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); -	priv->cur_beacon_conf.bmiss_cnt = 0; +	ath9k_hw_set_sta_beacon_timers(priv->ah, &bs); +	imask |= ATH9K_INT_BMISS;  	htc_imask = cpu_to_be32(imask);  	WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);  } -static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, -					  struct htc_beacon_config *bss_conf) +static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, +				       struct ath_beacon_config *conf)  { -	struct ath_common *common = ath9k_hw_common(priv->ah); -	enum ath9k_int imask = 0; -	u32 nexttbtt, intval, tsftu; -	__be32 htc_imask = 0; -	int ret __attribute__ ((unused)); -	u8 cmd_rsp; -	u64 tsf; - -	intval = bss_conf->beacon_interval; -	nexttbtt = intval; - -	/* -	 * Pull nexttbtt forward to reflect the current TSF. -	 */ -	tsf = ath9k_hw_gettsf64(priv->ah); -	tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE; -	do { -		nexttbtt += intval; -	} while (nexttbtt < tsftu); - -	/* -	 * Only one IBSS interfce is allowed. -	 */ -	if (intval > DEFAULT_SWBA_RESPONSE) -		priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; -	else -		priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; +	struct ath_hw *ah = priv->ah; +	ah->imask = 0; -	if (test_bit(OP_ENABLE_BEACON, &priv->op_flags)) -		imask |= ATH9K_INT_SWBA; +	ath9k_cmn_beacon_config_ap(ah, conf, ATH9K_HTC_MAX_BCN_VIF); +	ath9k_htc_beacon_init(priv, conf, false); +} -	ath_dbg(common, CONFIG, -		"IBSS Beacon config, intval: %d, nexttbtt: %u, resp_time: %d, imask: 0x%x\n", -		bss_conf->beacon_interval, nexttbtt, -		priv->ah->config.sw_beacon_response_time, imask); +static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, +					  struct ath_beacon_config *conf) +{ +	struct ath_hw *ah = priv->ah; +	ah->imask = 0; -	WMI_CMD(WMI_DISABLE_INTR_CMDID); -	ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); -	priv->cur_beacon_conf.bmiss_cnt = 0; -	htc_imask = cpu_to_be32(imask); -	WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); +	ath9k_cmn_beacon_config_adhoc(ah, conf); +	ath9k_htc_beacon_init(priv, conf, conf->ibss_creator);  }  void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, @@ -302,7 +145,7 @@ static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv,  	spin_lock_bh(&priv->beacon_lock); -	vif = priv->cur_beacon_conf.bslot[slot]; +	vif = priv->beacon.bslot[slot];  	skb = ieee80211_get_buffered_bc(priv->hw, vif); @@ -363,10 +206,10 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv,  	spin_lock_bh(&priv->beacon_lock); -	vif = priv->cur_beacon_conf.bslot[slot]; +	vif = priv->beacon.bslot[slot];  	avp = (struct ath9k_htc_vif *)vif->drv_priv; -	if (unlikely(test_bit(OP_SCANNING, &priv->op_flags))) { +	if (unlikely(test_bit(ATH_OP_SCANNING, &common->op_flags))) {  		spin_unlock_bh(&priv->beacon_lock);  		return;  	} @@ -446,8 +289,8 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv,  	int slot;  	if (swba->beacon_pending != 0) { -		priv->cur_beacon_conf.bmiss_cnt++; -		if (priv->cur_beacon_conf.bmiss_cnt > BSTUCK_THRESHOLD) { +		priv->beacon.bmisscnt++; +		if (priv->beacon.bmisscnt > BSTUCK_THRESHOLD) {  			ath_dbg(common, BSTUCK, "Beacon stuck, HW reset\n");  			ieee80211_queue_work(priv->hw,  					     &priv->fatal_work); @@ -455,16 +298,16 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv,  		return;  	} -	if (priv->cur_beacon_conf.bmiss_cnt) { +	if (priv->beacon.bmisscnt) {  		ath_dbg(common, BSTUCK,  			"Resuming beacon xmit after %u misses\n", -			priv->cur_beacon_conf.bmiss_cnt); -		priv->cur_beacon_conf.bmiss_cnt = 0; +			priv->beacon.bmisscnt); +		priv->beacon.bmisscnt = 0;  	}  	slot = ath9k_htc_choose_bslot(priv, swba);  	spin_lock_bh(&priv->beacon_lock); -	if (priv->cur_beacon_conf.bslot[slot] == NULL) { +	if (priv->beacon.bslot[slot] == NULL) {  		spin_unlock_bh(&priv->beacon_lock);  		return;  	} @@ -483,13 +326,13 @@ void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv,  	spin_lock_bh(&priv->beacon_lock);  	for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) { -		if (priv->cur_beacon_conf.bslot[i] == NULL) { +		if (priv->beacon.bslot[i] == NULL) {  			avp->bslot = i;  			break;  		}  	} -	priv->cur_beacon_conf.bslot[avp->bslot] = vif; +	priv->beacon.bslot[avp->bslot] = vif;  	spin_unlock_bh(&priv->beacon_lock);  	ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n", @@ -503,7 +346,7 @@ void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv,  	struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv;  	spin_lock_bh(&priv->beacon_lock); -	priv->cur_beacon_conf.bslot[avp->bslot] = NULL; +	priv->beacon.bslot[avp->bslot] = NULL;  	spin_unlock_bh(&priv->beacon_lock);  	ath_dbg(common, CONFIG, "Removed interface at beacon slot: %d\n", @@ -519,7 +362,7 @@ void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv,  {  	struct ath_common *common = ath9k_hw_common(priv->ah);  	struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; -	struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; +	struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf;  	u64 tsfadjust;  	if (avp->bslot == 0) @@ -551,7 +394,7 @@ static bool ath9k_htc_check_beacon_config(struct ath9k_htc_priv *priv,  					  struct ieee80211_vif *vif)  {  	struct ath_common *common = ath9k_hw_common(priv->ah); -	struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; +	struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf;  	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;  	bool beacon_configured; @@ -606,7 +449,7 @@ void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,  			     struct ieee80211_vif *vif)  {  	struct ath_common *common = ath9k_hw_common(priv->ah); -	struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; +	struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf;  	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;  	struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv; @@ -642,7 +485,7 @@ void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,  void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv)  {  	struct ath_common *common = ath9k_hw_common(priv->ah); -	struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; +	struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf;  	switch (priv->ah->opmode) {  	case NL80211_IFTYPE_STATION: diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index c1b45e2f848..8b529e4b8ac 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -37,29 +37,29 @@ static ssize_t read_file_tgt_int_stats(struct file *file, char __user *user_buf,  	ath9k_htc_ps_restore(priv); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "RX", -			be32_to_cpu(cmd_rsp.rx)); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "RX", +			 be32_to_cpu(cmd_rsp.rx)); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "RXORN", -			be32_to_cpu(cmd_rsp.rxorn)); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "RXORN", +			 be32_to_cpu(cmd_rsp.rxorn)); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "RXEOL", -			be32_to_cpu(cmd_rsp.rxeol)); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "RXEOL", +			 be32_to_cpu(cmd_rsp.rxeol)); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "TXURN", -			be32_to_cpu(cmd_rsp.txurn)); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "TXURN", +			 be32_to_cpu(cmd_rsp.txurn)); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "TXTO", -			be32_to_cpu(cmd_rsp.txto)); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "TXTO", +			 be32_to_cpu(cmd_rsp.txto)); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "CST", -			be32_to_cpu(cmd_rsp.cst)); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "CST", +			 be32_to_cpu(cmd_rsp.cst));  	if (len > sizeof(buf))  		len = sizeof(buf); @@ -95,41 +95,41 @@ static ssize_t read_file_tgt_tx_stats(struct file *file, char __user *user_buf,  	ath9k_htc_ps_restore(priv); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "Xretries", -			be32_to_cpu(cmd_rsp.xretries)); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "Xretries", +			 be32_to_cpu(cmd_rsp.xretries)); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "FifoErr", -			be32_to_cpu(cmd_rsp.fifoerr)); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "FifoErr", +			 be32_to_cpu(cmd_rsp.fifoerr)); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "Filtered", -			be32_to_cpu(cmd_rsp.filtered)); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "Filtered", +			 be32_to_cpu(cmd_rsp.filtered)); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "TimerExp", -			be32_to_cpu(cmd_rsp.timer_exp)); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "TimerExp", +			 be32_to_cpu(cmd_rsp.timer_exp)); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "ShortRetries", -			be32_to_cpu(cmd_rsp.shortretries)); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "ShortRetries", +			 be32_to_cpu(cmd_rsp.shortretries)); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "LongRetries", -			be32_to_cpu(cmd_rsp.longretries)); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "LongRetries", +			 be32_to_cpu(cmd_rsp.longretries)); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "QueueNull", -			be32_to_cpu(cmd_rsp.qnull)); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "QueueNull", +			 be32_to_cpu(cmd_rsp.qnull)); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "EncapFail", -			be32_to_cpu(cmd_rsp.encap_fail)); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "EncapFail", +			 be32_to_cpu(cmd_rsp.encap_fail)); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "NoBuf", -			be32_to_cpu(cmd_rsp.nobuf)); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "NoBuf", +			 be32_to_cpu(cmd_rsp.nobuf));  	if (len > sizeof(buf))  		len = sizeof(buf); @@ -165,17 +165,17 @@ static ssize_t read_file_tgt_rx_stats(struct file *file, char __user *user_buf,  	ath9k_htc_ps_restore(priv); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "NoBuf", -			be32_to_cpu(cmd_rsp.nobuf)); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "NoBuf", +			 be32_to_cpu(cmd_rsp.nobuf)); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "HostSend", -			be32_to_cpu(cmd_rsp.host_send)); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "HostSend", +			 be32_to_cpu(cmd_rsp.host_send)); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "HostDone", -			be32_to_cpu(cmd_rsp.host_done)); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "HostDone", +			 be32_to_cpu(cmd_rsp.host_done));  	if (len > sizeof(buf))  		len = sizeof(buf); @@ -197,37 +197,37 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,  	char buf[512];  	unsigned int len = 0; -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "Buffers queued", -			priv->debug.tx_stats.buf_queued); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "Buffers completed", -			priv->debug.tx_stats.buf_completed); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "SKBs queued", -			priv->debug.tx_stats.skb_queued); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "SKBs success", -			priv->debug.tx_stats.skb_success); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "SKBs failed", -			priv->debug.tx_stats.skb_failed); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "CAB queued", -			priv->debug.tx_stats.cab_queued); - -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "BE queued", -			priv->debug.tx_stats.queue_stats[IEEE80211_AC_BE]); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "BK queued", -			priv->debug.tx_stats.queue_stats[IEEE80211_AC_BK]); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "VI queued", -			priv->debug.tx_stats.queue_stats[IEEE80211_AC_VI]); -	len += snprintf(buf + len, sizeof(buf) - len, -			"%20s : %10u\n", "VO queued", -			priv->debug.tx_stats.queue_stats[IEEE80211_AC_VO]); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "Buffers queued", +			 priv->debug.tx_stats.buf_queued); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "Buffers completed", +			 priv->debug.tx_stats.buf_completed); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "SKBs queued", +			 priv->debug.tx_stats.skb_queued); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "SKBs success", +			 priv->debug.tx_stats.skb_success); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "SKBs failed", +			 priv->debug.tx_stats.skb_failed); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "CAB queued", +			 priv->debug.tx_stats.cab_queued); + +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "BE queued", +			 priv->debug.tx_stats.queue_stats[IEEE80211_AC_BE]); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "BK queued", +			 priv->debug.tx_stats.queue_stats[IEEE80211_AC_BK]); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "VI queued", +			 priv->debug.tx_stats.queue_stats[IEEE80211_AC_VI]); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "%20s : %10u\n", "VO queued", +			 priv->debug.tx_stats.queue_stats[IEEE80211_AC_VO]);  	if (len > sizeof(buf))  		len = sizeof(buf); @@ -243,39 +243,14 @@ static const struct file_operations fops_xmit = {  };  void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, -			   struct ath_htc_rx_status *rxs) +			     struct ath_rx_status *rs)  { -#define RX_PHY_ERR_INC(c) priv->debug.rx_stats.err_phy_stats[c]++ - -	if (rxs->rs_status & ATH9K_RXERR_CRC) -		priv->debug.rx_stats.err_crc++; -	if (rxs->rs_status & ATH9K_RXERR_DECRYPT) -		priv->debug.rx_stats.err_decrypt_crc++; -	if (rxs->rs_status & ATH9K_RXERR_MIC) -		priv->debug.rx_stats.err_mic++; -	if (rxs->rs_status & ATH9K_RX_DELIM_CRC_PRE) -		priv->debug.rx_stats.err_pre_delim++; -	if (rxs->rs_status & ATH9K_RX_DELIM_CRC_POST) -		priv->debug.rx_stats.err_post_delim++; -	if (rxs->rs_status & ATH9K_RX_DECRYPT_BUSY) -		priv->debug.rx_stats.err_decrypt_busy++; - -	if (rxs->rs_status & ATH9K_RXERR_PHY) { -		priv->debug.rx_stats.err_phy++; -		if (rxs->rs_phyerr < ATH9K_PHYERR_MAX) -			RX_PHY_ERR_INC(rxs->rs_phyerr); -	} - -#undef RX_PHY_ERR_INC +	ath9k_cmn_debug_stat_rx(&priv->debug.rx_stats, rs);  } -static ssize_t read_file_recv(struct file *file, char __user *user_buf, +static ssize_t read_file_skb_rx(struct file *file, char __user *user_buf,  			      size_t count, loff_t *ppos)  { -#define PHY_ERR(s, p)							\ -	len += snprintf(buf + len, size - len, "%20s : %10u\n", s,	\ -			priv->debug.rx_stats.err_phy_stats[p]); -  	struct ath9k_htc_priv *priv = file->private_data;  	char *buf;  	unsigned int len = 0, size = 1500; @@ -285,65 +260,15 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,  	if (buf == NULL)  		return -ENOMEM; -	len += snprintf(buf + len, size - len, -			"%20s : %10u\n", "SKBs allocated", -			priv->debug.rx_stats.skb_allocated); -	len += snprintf(buf + len, size - len, -			"%20s : %10u\n", "SKBs completed", -			priv->debug.rx_stats.skb_completed); -	len += snprintf(buf + len, size - len, -			"%20s : %10u\n", "SKBs Dropped", -			priv->debug.rx_stats.skb_dropped); - -	len += snprintf(buf + len, size - len, -			"%20s : %10u\n", "CRC ERR", -			priv->debug.rx_stats.err_crc); -	len += snprintf(buf + len, size - len, -			"%20s : %10u\n", "DECRYPT CRC ERR", -			priv->debug.rx_stats.err_decrypt_crc); -	len += snprintf(buf + len, size - len, -			"%20s : %10u\n", "MIC ERR", -			priv->debug.rx_stats.err_mic); -	len += snprintf(buf + len, size - len, -			"%20s : %10u\n", "PRE-DELIM CRC ERR", -			priv->debug.rx_stats.err_pre_delim); -	len += snprintf(buf + len, size - len, -			"%20s : %10u\n", "POST-DELIM CRC ERR", -			priv->debug.rx_stats.err_post_delim); -	len += snprintf(buf + len, size - len, -			"%20s : %10u\n", "DECRYPT BUSY ERR", -			priv->debug.rx_stats.err_decrypt_busy); -	len += snprintf(buf + len, size - len, -			"%20s : %10u\n", "TOTAL PHY ERR", -			priv->debug.rx_stats.err_phy); - - -	PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN); -	PHY_ERR("TIMING", ATH9K_PHYERR_TIMING); -	PHY_ERR("PARITY", ATH9K_PHYERR_PARITY); -	PHY_ERR("RATE", ATH9K_PHYERR_RATE); -	PHY_ERR("LENGTH", ATH9K_PHYERR_LENGTH); -	PHY_ERR("RADAR", ATH9K_PHYERR_RADAR); -	PHY_ERR("SERVICE", ATH9K_PHYERR_SERVICE); -	PHY_ERR("TOR", ATH9K_PHYERR_TOR); -	PHY_ERR("OFDM-TIMING", ATH9K_PHYERR_OFDM_TIMING); -	PHY_ERR("OFDM-SIGNAL-PARITY", ATH9K_PHYERR_OFDM_SIGNAL_PARITY); -	PHY_ERR("OFDM-RATE", ATH9K_PHYERR_OFDM_RATE_ILLEGAL); -	PHY_ERR("OFDM-LENGTH", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL); -	PHY_ERR("OFDM-POWER-DROP", ATH9K_PHYERR_OFDM_POWER_DROP); -	PHY_ERR("OFDM-SERVICE", ATH9K_PHYERR_OFDM_SERVICE); -	PHY_ERR("OFDM-RESTART", ATH9K_PHYERR_OFDM_RESTART); -	PHY_ERR("FALSE-RADAR-EXT", ATH9K_PHYERR_FALSE_RADAR_EXT); -	PHY_ERR("CCK-TIMING", ATH9K_PHYERR_CCK_TIMING); -	PHY_ERR("CCK-HEADER-CRC", ATH9K_PHYERR_CCK_HEADER_CRC); -	PHY_ERR("CCK-RATE", ATH9K_PHYERR_CCK_RATE_ILLEGAL); -	PHY_ERR("CCK-SERVICE", ATH9K_PHYERR_CCK_SERVICE); -	PHY_ERR("CCK-RESTART", ATH9K_PHYERR_CCK_RESTART); -	PHY_ERR("CCK-LENGTH", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL); -	PHY_ERR("CCK-POWER-DROP", ATH9K_PHYERR_CCK_POWER_DROP); -	PHY_ERR("HT-CRC", ATH9K_PHYERR_HT_CRC_ERROR); -	PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL); -	PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL); +	len += scnprintf(buf + len, size - len, +			 "%20s : %10u\n", "SKBs allocated", +			 priv->debug.skbrx_stats.skb_allocated); +	len += scnprintf(buf + len, size - len, +			 "%20s : %10u\n", "SKBs completed", +			 priv->debug.skbrx_stats.skb_completed); +	len += scnprintf(buf + len, size - len, +			 "%20s : %10u\n", "SKBs Dropped", +			 priv->debug.skbrx_stats.skb_dropped);  	if (len > size)  		len = size; @@ -352,12 +277,10 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,  	kfree(buf);  	return retval; - -#undef PHY_ERR  } -static const struct file_operations fops_recv = { -	.read = read_file_recv, +static const struct file_operations fops_skb_rx = { +	.read = read_file_skb_rx,  	.open = simple_open,  	.owner = THIS_MODULE,  	.llseek = default_llseek, @@ -372,16 +295,16 @@ static ssize_t read_file_slot(struct file *file, char __user *user_buf,  	spin_lock_bh(&priv->tx.tx_lock); -	len += snprintf(buf + len, sizeof(buf) - len, "TX slot bitmap : "); +	len += scnprintf(buf + len, sizeof(buf) - len, "TX slot bitmap : ");  	len += bitmap_scnprintf(buf + len, sizeof(buf) - len,  			       priv->tx.tx_slot, MAX_TX_BUF_NUM); -	len += snprintf(buf + len, sizeof(buf) - len, "\n"); +	len += scnprintf(buf + len, sizeof(buf) - len, "\n"); -	len += snprintf(buf + len, sizeof(buf) - len, -			"Used slots     : %d\n", -			bitmap_weight(priv->tx.tx_slot, MAX_TX_BUF_NUM)); +	len += scnprintf(buf + len, sizeof(buf) - len, +			 "Used slots     : %d\n", +			 bitmap_weight(priv->tx.tx_slot, MAX_TX_BUF_NUM));  	spin_unlock_bh(&priv->tx.tx_lock); @@ -405,30 +328,30 @@ static ssize_t read_file_queue(struct file *file, char __user *user_buf,  	char buf[512];  	unsigned int len = 0; -	len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", -			"Mgmt endpoint", skb_queue_len(&priv->tx.mgmt_ep_queue)); +	len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", +			 "Mgmt endpoint", skb_queue_len(&priv->tx.mgmt_ep_queue)); -	len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", -			"Cab endpoint", skb_queue_len(&priv->tx.cab_ep_queue)); +	len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", +			 "Cab endpoint", skb_queue_len(&priv->tx.cab_ep_queue)); -	len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", -			"Data BE endpoint", skb_queue_len(&priv->tx.data_be_queue)); +	len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", +			 "Data BE endpoint", skb_queue_len(&priv->tx.data_be_queue)); -	len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", -			"Data BK endpoint", skb_queue_len(&priv->tx.data_bk_queue)); +	len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", +			 "Data BK endpoint", skb_queue_len(&priv->tx.data_bk_queue)); -	len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", -			"Data VI endpoint", skb_queue_len(&priv->tx.data_vi_queue)); +	len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", +			 "Data VI endpoint", skb_queue_len(&priv->tx.data_vi_queue)); -	len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", -			"Data VO endpoint", skb_queue_len(&priv->tx.data_vo_queue)); +	len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", +			 "Data VO endpoint", skb_queue_len(&priv->tx.data_vo_queue)); -	len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", -			"Failed queue", skb_queue_len(&priv->tx.tx_failed)); +	len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", +			 "Failed queue", skb_queue_len(&priv->tx.tx_failed));  	spin_lock_bh(&priv->tx.tx_lock); -	len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", -			"Queued count", priv->tx.queued_cnt); +	len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", +			 "Queued count", priv->tx.queued_cnt);  	spin_unlock_bh(&priv->tx.tx_lock);  	if (len > sizeof(buf)) @@ -486,423 +409,6 @@ static const struct file_operations fops_debug = {  	.llseek = default_llseek,  }; -static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf, -				     size_t count, loff_t *ppos) -{ -	struct ath9k_htc_priv *priv = file->private_data; -	struct ath_common *common = ath9k_hw_common(priv->ah); -	struct base_eep_header *pBase = NULL; -	unsigned int len = 0, size = 1500; -	ssize_t retval = 0; -	char *buf; - -	pBase = ath9k_htc_get_eeprom_base(priv); - -	if (pBase == NULL) { -		ath_err(common, "Unknown EEPROM type\n"); -		return 0; -	} - -	buf = kzalloc(size, GFP_KERNEL); -	if (buf == NULL) -		return -ENOMEM; - -	len += snprintf(buf + len, size - len, -			"%20s : %10d\n", "Major Version", -			pBase->version >> 12); -	len += snprintf(buf + len, size - len, -			"%20s : %10d\n", "Minor Version", -			pBase->version & 0xFFF); -	len += snprintf(buf + len, size - len, -			"%20s : %10d\n", "Checksum", -			pBase->checksum); -	len += snprintf(buf + len, size - len, -			"%20s : %10d\n", "Length", -			pBase->length); -	len += snprintf(buf + len, size - len, -			"%20s : %10d\n", "RegDomain1", -			pBase->regDmn[0]); -	len += snprintf(buf + len, size - len, -			"%20s : %10d\n", "RegDomain2", -			pBase->regDmn[1]); -	len += snprintf(buf + len, size - len, -			"%20s : %10d\n", -			"TX Mask", pBase->txMask); -	len += snprintf(buf + len, size - len, -			"%20s : %10d\n", -			"RX Mask", pBase->rxMask); -	len += snprintf(buf + len, size - len, -			"%20s : %10d\n", -			"Allow 5GHz", -			!!(pBase->opCapFlags & AR5416_OPFLAGS_11A)); -	len += snprintf(buf + len, size - len, -			"%20s : %10d\n", -			"Allow 2GHz", -			!!(pBase->opCapFlags & AR5416_OPFLAGS_11G)); -	len += snprintf(buf + len, size - len, -			"%20s : %10d\n", -			"Disable 2GHz HT20", -			!!(pBase->opCapFlags & AR5416_OPFLAGS_N_2G_HT20)); -	len += snprintf(buf + len, size - len, -			"%20s : %10d\n", -			"Disable 2GHz HT40", -			!!(pBase->opCapFlags & AR5416_OPFLAGS_N_2G_HT40)); -	len += snprintf(buf + len, size - len, -			"%20s : %10d\n", -			"Disable 5Ghz HT20", -			!!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT20)); -	len += snprintf(buf + len, size - len, -			"%20s : %10d\n", -			"Disable 5Ghz HT40", -			!!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT40)); -	len += snprintf(buf + len, size - len, -			"%20s : %10d\n", -			"Big Endian", -			!!(pBase->eepMisc & 0x01)); -	len += snprintf(buf + len, size - len, -			"%20s : %10d\n", -			"Cal Bin Major Ver", -			(pBase->binBuildNumber >> 24) & 0xFF); -	len += snprintf(buf + len, size - len, -			"%20s : %10d\n", -			"Cal Bin Minor Ver", -			(pBase->binBuildNumber >> 16) & 0xFF); -	len += snprintf(buf + len, size - len, -			"%20s : %10d\n", -			"Cal Bin Build", -			(pBase->binBuildNumber >> 8) & 0xFF); - -	/* -	 * UB91 specific data. -	 */ -	if (AR_SREV_9271(priv->ah)) { -		struct base_eep_header_4k *pBase4k = -			&priv->ah->eeprom.map4k.baseEepHeader; - -		len += snprintf(buf + len, size - len, -				"%20s : %10d\n", -				"TX Gain type", -				pBase4k->txGainType); -	} - -	/* -	 * UB95 specific data. -	 */ -	if (priv->ah->hw_version.usbdev == AR9287_USB) { -		struct base_eep_ar9287_header *pBase9287 = -			&priv->ah->eeprom.map9287.baseEepHeader; - -		len += snprintf(buf + len, size - len, -				"%20s : %10ddB\n", -				"Power Table Offset", -				pBase9287->pwrTableOffset); - -		len += snprintf(buf + len, size - len, -				"%20s : %10d\n", -				"OpenLoop Power Ctrl", -				pBase9287->openLoopPwrCntl); -	} - -	len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", -			pBase->macAddr); -	if (len > size) -		len = size; - -	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); -	kfree(buf); - -	return retval; -} - -static const struct file_operations fops_base_eeprom = { -	.read = read_file_base_eeprom, -	.open = simple_open, -	.owner = THIS_MODULE, -	.llseek = default_llseek, -}; - -static ssize_t read_4k_modal_eeprom(struct file *file, -				    char __user *user_buf, -				    size_t count, loff_t *ppos) -{ -#define PR_EEP(_s, _val)						\ -	do {								\ -		len += snprintf(buf + len, size - len, "%20s : %10d\n",	\ -				_s, (_val));				\ -	} while (0) - -	struct ath9k_htc_priv *priv = file->private_data; -	struct modal_eep_4k_header *pModal = &priv->ah->eeprom.map4k.modalHeader; -	unsigned int len = 0, size = 2048; -	ssize_t retval = 0; -	char *buf; - -	buf = kzalloc(size, GFP_KERNEL); -	if (buf == NULL) -		return -ENOMEM; - -	PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]); -	PR_EEP("Ant. Common Control", pModal->antCtrlCommon); -	PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]); -	PR_EEP("Switch Settle", pModal->switchSettling); -	PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]); -	PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]); -	PR_EEP("ADC Desired size", pModal->adcDesiredSize); -	PR_EEP("PGA Desired size", pModal->pgaDesiredSize); -	PR_EEP("Chain0 xlna Gain", pModal->xlnaGainCh[0]); -	PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff); -	PR_EEP("txEndToRxOn", pModal->txEndToRxOn); -	PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn); -	PR_EEP("CCA Threshold)", pModal->thresh62); -	PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]); -	PR_EEP("xpdGain", pModal->xpdGain); -	PR_EEP("External PD", pModal->xpd); -	PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]); -	PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]); -	PR_EEP("pdGainOverlap", pModal->pdGainOverlap); -	PR_EEP("O/D Bias Version", pModal->version); -	PR_EEP("CCK OutputBias", pModal->ob_0); -	PR_EEP("BPSK OutputBias", pModal->ob_1); -	PR_EEP("QPSK OutputBias", pModal->ob_2); -	PR_EEP("16QAM OutputBias", pModal->ob_3); -	PR_EEP("64QAM OutputBias", pModal->ob_4); -	PR_EEP("CCK Driver1_Bias", pModal->db1_0); -	PR_EEP("BPSK Driver1_Bias", pModal->db1_1); -	PR_EEP("QPSK Driver1_Bias", pModal->db1_2); -	PR_EEP("16QAM Driver1_Bias", pModal->db1_3); -	PR_EEP("64QAM Driver1_Bias", pModal->db1_4); -	PR_EEP("CCK Driver2_Bias", pModal->db2_0); -	PR_EEP("BPSK Driver2_Bias", pModal->db2_1); -	PR_EEP("QPSK Driver2_Bias", pModal->db2_2); -	PR_EEP("16QAM Driver2_Bias", pModal->db2_3); -	PR_EEP("64QAM Driver2_Bias", pModal->db2_4); -	PR_EEP("xPA Bias Level", pModal->xpaBiasLvl); -	PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart); -	PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn); -	PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc); -	PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]); -	PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]); -	PR_EEP("HT40 Switch Settle", pModal->swSettleHt40); -	PR_EEP("Chain0 xatten2Db", pModal->xatten2Db[0]); -	PR_EEP("Chain0 xatten2Margin", pModal->xatten2Margin[0]); -	PR_EEP("Ant. Diversity ctl1", pModal->antdiv_ctl1); -	PR_EEP("Ant. Diversity ctl2", pModal->antdiv_ctl2); -	PR_EEP("TX Diversity", pModal->tx_diversity); - -	if (len > size) -		len = size; - -	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); -	kfree(buf); - -	return retval; - -#undef PR_EEP -} - -static ssize_t read_def_modal_eeprom(struct file *file, -				     char __user *user_buf, -				     size_t count, loff_t *ppos) -{ -#define PR_EEP(_s, _val)						\ -	do {								\ -		if (pBase->opCapFlags & AR5416_OPFLAGS_11G) {		\ -			pModal = &priv->ah->eeprom.def.modalHeader[1];	\ -			len += snprintf(buf + len, size - len, "%20s : %8d%7s", \ -					_s, (_val), "|");		\ -		}							\ -		if (pBase->opCapFlags & AR5416_OPFLAGS_11A) {		\ -			pModal = &priv->ah->eeprom.def.modalHeader[0];	\ -			len += snprintf(buf + len, size - len, "%9d\n", \ -					(_val));			\ -		}							\ -	} while (0) - -	struct ath9k_htc_priv *priv = file->private_data; -	struct base_eep_header *pBase = &priv->ah->eeprom.def.baseEepHeader; -	struct modal_eep_header *pModal = NULL; -	unsigned int len = 0, size = 3500; -	ssize_t retval = 0; -	char *buf; - -	buf = kzalloc(size, GFP_KERNEL); -	if (buf == NULL) -		return -ENOMEM; - -	len += snprintf(buf + len, size - len, -			"%31s %15s\n", "2G", "5G"); -	len += snprintf(buf + len, size - len, -			"%32s %16s\n", "====", "====\n"); - -	PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]); -	PR_EEP("Chain1 Ant. Control", pModal->antCtrlChain[1]); -	PR_EEP("Chain2 Ant. Control", pModal->antCtrlChain[2]); -	PR_EEP("Ant. Common Control", pModal->antCtrlCommon); -	PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]); -	PR_EEP("Chain1 Ant. Gain", pModal->antennaGainCh[1]); -	PR_EEP("Chain2 Ant. Gain", pModal->antennaGainCh[2]); -	PR_EEP("Switch Settle", pModal->switchSettling); -	PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]); -	PR_EEP("Chain1 TxRxAtten", pModal->txRxAttenCh[1]); -	PR_EEP("Chain2 TxRxAtten", pModal->txRxAttenCh[2]); -	PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]); -	PR_EEP("Chain1 RxTxMargin", pModal->rxTxMarginCh[1]); -	PR_EEP("Chain2 RxTxMargin", pModal->rxTxMarginCh[2]); -	PR_EEP("ADC Desired size", pModal->adcDesiredSize); -	PR_EEP("PGA Desired size", pModal->pgaDesiredSize); -	PR_EEP("Chain0 xlna Gain", pModal->xlnaGainCh[0]); -	PR_EEP("Chain1 xlna Gain", pModal->xlnaGainCh[1]); -	PR_EEP("Chain2 xlna Gain", pModal->xlnaGainCh[2]); -	PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff); -	PR_EEP("txEndToRxOn", pModal->txEndToRxOn); -	PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn); -	PR_EEP("CCA Threshold)", pModal->thresh62); -	PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]); -	PR_EEP("Chain1 NF Threshold", pModal->noiseFloorThreshCh[1]); -	PR_EEP("Chain2 NF Threshold", pModal->noiseFloorThreshCh[2]); -	PR_EEP("xpdGain", pModal->xpdGain); -	PR_EEP("External PD", pModal->xpd); -	PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]); -	PR_EEP("Chain1 I Coefficient", pModal->iqCalICh[1]); -	PR_EEP("Chain2 I Coefficient", pModal->iqCalICh[2]); -	PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]); -	PR_EEP("Chain1 Q Coefficient", pModal->iqCalQCh[1]); -	PR_EEP("Chain2 Q Coefficient", pModal->iqCalQCh[2]); -	PR_EEP("pdGainOverlap", pModal->pdGainOverlap); -	PR_EEP("Chain0 OutputBias", pModal->ob); -	PR_EEP("Chain0 DriverBias", pModal->db); -	PR_EEP("xPA Bias Level", pModal->xpaBiasLvl); -	PR_EEP("2chain pwr decrease", pModal->pwrDecreaseFor2Chain); -	PR_EEP("3chain pwr decrease", pModal->pwrDecreaseFor3Chain); -	PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart); -	PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn); -	PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc); -	PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]); -	PR_EEP("Chain1 bswAtten", pModal->bswAtten[1]); -	PR_EEP("Chain2 bswAtten", pModal->bswAtten[2]); -	PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]); -	PR_EEP("Chain1 bswMargin", pModal->bswMargin[1]); -	PR_EEP("Chain2 bswMargin", pModal->bswMargin[2]); -	PR_EEP("HT40 Switch Settle", pModal->swSettleHt40); -	PR_EEP("Chain0 xatten2Db", pModal->xatten2Db[0]); -	PR_EEP("Chain1 xatten2Db", pModal->xatten2Db[1]); -	PR_EEP("Chain2 xatten2Db", pModal->xatten2Db[2]); -	PR_EEP("Chain0 xatten2Margin", pModal->xatten2Margin[0]); -	PR_EEP("Chain1 xatten2Margin", pModal->xatten2Margin[1]); -	PR_EEP("Chain2 xatten2Margin", pModal->xatten2Margin[2]); -	PR_EEP("Chain1 OutputBias", pModal->ob_ch1); -	PR_EEP("Chain1 DriverBias", pModal->db_ch1); -	PR_EEP("LNA Control", pModal->lna_ctl); -	PR_EEP("XPA Bias Freq0", pModal->xpaBiasLvlFreq[0]); -	PR_EEP("XPA Bias Freq1", pModal->xpaBiasLvlFreq[1]); -	PR_EEP("XPA Bias Freq2", pModal->xpaBiasLvlFreq[2]); - -	if (len > size) -		len = size; - -	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); -	kfree(buf); - -	return retval; - -#undef PR_EEP -} - -static ssize_t read_9287_modal_eeprom(struct file *file, -				      char __user *user_buf, -				      size_t count, loff_t *ppos) -{ -#define PR_EEP(_s, _val)						\ -	do {								\ -		len += snprintf(buf + len, size - len, "%20s : %10d\n",	\ -				_s, (_val));				\ -	} while (0) - -	struct ath9k_htc_priv *priv = file->private_data; -	struct modal_eep_ar9287_header *pModal = &priv->ah->eeprom.map9287.modalHeader; -	unsigned int len = 0, size = 3000; -	ssize_t retval = 0; -	char *buf; - -	buf = kzalloc(size, GFP_KERNEL); -	if (buf == NULL) -		return -ENOMEM; - -	PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]); -	PR_EEP("Chain1 Ant. Control", pModal->antCtrlChain[1]); -	PR_EEP("Ant. Common Control", pModal->antCtrlCommon); -	PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]); -	PR_EEP("Chain1 Ant. Gain", pModal->antennaGainCh[1]); -	PR_EEP("Switch Settle", pModal->switchSettling); -	PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]); -	PR_EEP("Chain1 TxRxAtten", pModal->txRxAttenCh[1]); -	PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]); -	PR_EEP("Chain1 RxTxMargin", pModal->rxTxMarginCh[1]); -	PR_EEP("ADC Desired size", pModal->adcDesiredSize); -	PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff); -	PR_EEP("txEndToRxOn", pModal->txEndToRxOn); -	PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn); -	PR_EEP("CCA Threshold)", pModal->thresh62); -	PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]); -	PR_EEP("Chain1 NF Threshold", pModal->noiseFloorThreshCh[1]); -	PR_EEP("xpdGain", pModal->xpdGain); -	PR_EEP("External PD", pModal->xpd); -	PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]); -	PR_EEP("Chain1 I Coefficient", pModal->iqCalICh[1]); -	PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]); -	PR_EEP("Chain1 Q Coefficient", pModal->iqCalQCh[1]); -	PR_EEP("pdGainOverlap", pModal->pdGainOverlap); -	PR_EEP("xPA Bias Level", pModal->xpaBiasLvl); -	PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart); -	PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn); -	PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc); -	PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]); -	PR_EEP("Chain1 bswAtten", pModal->bswAtten[1]); -	PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]); -	PR_EEP("Chain1 bswMargin", pModal->bswMargin[1]); -	PR_EEP("HT40 Switch Settle", pModal->swSettleHt40); -	PR_EEP("AR92x7 Version", pModal->version); -	PR_EEP("DriverBias1", pModal->db1); -	PR_EEP("DriverBias2", pModal->db1); -	PR_EEP("CCK OutputBias", pModal->ob_cck); -	PR_EEP("PSK OutputBias", pModal->ob_psk); -	PR_EEP("QAM OutputBias", pModal->ob_qam); -	PR_EEP("PAL_OFF OutputBias", pModal->ob_pal_off); - -	if (len > size) -		len = size; - -	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); -	kfree(buf); - -	return retval; - -#undef PR_EEP -} - -static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf, -				      size_t count, loff_t *ppos) -{ -	struct ath9k_htc_priv *priv = file->private_data; - -	if (AR_SREV_9271(priv->ah)) -		return read_4k_modal_eeprom(file, user_buf, count, ppos); -	else if (priv->ah->hw_version.usbdev == AR9280_USB) -		return read_def_modal_eeprom(file, user_buf, count, ppos); -	else if (priv->ah->hw_version.usbdev == AR9287_USB) -		return read_9287_modal_eeprom(file, user_buf, count, ppos); - -	return 0; -} - -static const struct file_operations fops_modal_eeprom = { -	.read = read_file_modal_eeprom, -	.open = simple_open, -	.owner = THIS_MODULE, -	.llseek = default_llseek, -}; - -  /* Ethtool support for get-stats */  #define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO"  static const char ath9k_htc_gstrings_stats[][ETH_GSTRING_LEN] = { @@ -947,6 +453,8 @@ int ath9k_htc_get_et_sset_count(struct ieee80211_hw *hw,  #define STXBASE priv->debug.tx_stats  #define SRXBASE priv->debug.rx_stats +#define SKBTXBASE priv->debug.tx_stats +#define SKBRXBASE priv->debug.skbrx_stats  #define ASTXQ(a)					\  	data[i++] = STXBASE.a[IEEE80211_AC_BE];		\  	data[i++] = STXBASE.a[IEEE80211_AC_BK];		\ @@ -960,24 +468,24 @@ void ath9k_htc_get_et_stats(struct ieee80211_hw *hw,  	struct ath9k_htc_priv *priv = hw->priv;  	int i = 0; -	data[i++] = STXBASE.skb_success; -	data[i++] = STXBASE.skb_success_bytes; -	data[i++] = SRXBASE.skb_completed; -	data[i++] = SRXBASE.skb_completed_bytes; +	data[i++] = SKBTXBASE.skb_success; +	data[i++] = SKBTXBASE.skb_success_bytes; +	data[i++] = SKBRXBASE.skb_completed; +	data[i++] = SKBRXBASE.skb_completed_bytes;  	ASTXQ(queue_stats); -	data[i++] = SRXBASE.err_crc; -	data[i++] = SRXBASE.err_decrypt_crc; -	data[i++] = SRXBASE.err_phy; -	data[i++] = SRXBASE.err_mic; -	data[i++] = SRXBASE.err_pre_delim; -	data[i++] = SRXBASE.err_post_delim; -	data[i++] = SRXBASE.err_decrypt_busy; +	data[i++] = SRXBASE.crc_err; +	data[i++] = SRXBASE.decrypt_crc_err; +	data[i++] = SRXBASE.phy_err; +	data[i++] = SRXBASE.mic_err; +	data[i++] = SRXBASE.pre_delim_crc_err; +	data[i++] = SRXBASE.post_delim_crc_err; +	data[i++] = SRXBASE.decrypt_busy_err; -	data[i++] = SRXBASE.err_phy_stats[ATH9K_PHYERR_RADAR]; -	data[i++] = SRXBASE.err_phy_stats[ATH9K_PHYERR_OFDM_TIMING]; -	data[i++] = SRXBASE.err_phy_stats[ATH9K_PHYERR_CCK_TIMING]; +	data[i++] = SRXBASE.phy_err_stats[ATH9K_PHYERR_RADAR]; +	data[i++] = SRXBASE.phy_err_stats[ATH9K_PHYERR_OFDM_TIMING]; +	data[i++] = SRXBASE.phy_err_stats[ATH9K_PHYERR_CCK_TIMING];  	WARN_ON(i != ATH9K_HTC_SSTATS_LEN);  } @@ -1001,18 +509,21 @@ int ath9k_htc_init_debug(struct ath_hw *ah)  			    priv, &fops_tgt_rx_stats);  	debugfs_create_file("xmit", S_IRUSR, priv->debug.debugfs_phy,  			    priv, &fops_xmit); -	debugfs_create_file("recv", S_IRUSR, priv->debug.debugfs_phy, -			    priv, &fops_recv); +	debugfs_create_file("skb_rx", S_IRUSR, priv->debug.debugfs_phy, +			    priv, &fops_skb_rx); + +	ath9k_cmn_debug_recv(priv->debug.debugfs_phy, &priv->debug.rx_stats); +	ath9k_cmn_debug_phy_err(priv->debug.debugfs_phy, &priv->debug.rx_stats); +  	debugfs_create_file("slot", S_IRUSR, priv->debug.debugfs_phy,  			    priv, &fops_slot);  	debugfs_create_file("queue", S_IRUSR, priv->debug.debugfs_phy,  			    priv, &fops_queue);  	debugfs_create_file("debug", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy,  			    priv, &fops_debug); -	debugfs_create_file("base_eeprom", S_IRUSR, priv->debug.debugfs_phy, -			    priv, &fops_base_eeprom); -	debugfs_create_file("modal_eeprom", S_IRUSR, priv->debug.debugfs_phy, -			    priv, &fops_modal_eeprom); + +	ath9k_cmn_debug_base_eeprom(priv->debug.debugfs_phy, priv->ah); +	ath9k_cmn_debug_modal_eeprom(priv->debug.debugfs_phy, priv->ah);  	return 0;  } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index 105582d6b71..50f74a2a4cf 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c @@ -255,6 +255,17 @@ void ath9k_deinit_leds(struct ath9k_htc_priv *priv)  	cancel_work_sync(&priv->led_work);  } + +void ath9k_configure_leds(struct ath9k_htc_priv *priv) +{ +	/* Configure gpio 1 for output */ +	ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin, +			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT); +	/* LED off, active low */ +	ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1); + +} +  void ath9k_init_leds(struct ath9k_htc_priv *priv)  {  	int ret; @@ -268,11 +279,7 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv)  	else  		priv->ah->led_pin = ATH_LED_PIN_DEF; -	/* Configure gpio 1 for output */ -	ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin, -			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT); -	/* LED off, active low */ -	ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1); +	ath9k_configure_leds(priv);  	snprintf(priv->led_name, sizeof(priv->led_name),  		"ath9k_htc-%s", wiphy_name(priv->hw->wiphy)); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index c3676bf1d6c..8a3bd5fe3a5 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -34,92 +34,9 @@ static int ath9k_htc_btcoex_enable;  module_param_named(btcoex_enable, ath9k_htc_btcoex_enable, int, 0444);  MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence"); -#define CHAN2G(_freq, _idx)  { \ -	.center_freq = (_freq), \ -	.hw_value = (_idx), \ -	.max_power = 20, \ -} - -#define CHAN5G(_freq, _idx) { \ -	.band = IEEE80211_BAND_5GHZ, \ -	.center_freq = (_freq), \ -	.hw_value = (_idx), \ -	.max_power = 20, \ -} - -static struct ieee80211_channel ath9k_2ghz_channels[] = { -	CHAN2G(2412, 0), /* Channel 1 */ -	CHAN2G(2417, 1), /* Channel 2 */ -	CHAN2G(2422, 2), /* Channel 3 */ -	CHAN2G(2427, 3), /* Channel 4 */ -	CHAN2G(2432, 4), /* Channel 5 */ -	CHAN2G(2437, 5), /* Channel 6 */ -	CHAN2G(2442, 6), /* Channel 7 */ -	CHAN2G(2447, 7), /* Channel 8 */ -	CHAN2G(2452, 8), /* Channel 9 */ -	CHAN2G(2457, 9), /* Channel 10 */ -	CHAN2G(2462, 10), /* Channel 11 */ -	CHAN2G(2467, 11), /* Channel 12 */ -	CHAN2G(2472, 12), /* Channel 13 */ -	CHAN2G(2484, 13), /* Channel 14 */ -}; - -static struct ieee80211_channel ath9k_5ghz_channels[] = { -	/* _We_ call this UNII 1 */ -	CHAN5G(5180, 14), /* Channel 36 */ -	CHAN5G(5200, 15), /* Channel 40 */ -	CHAN5G(5220, 16), /* Channel 44 */ -	CHAN5G(5240, 17), /* Channel 48 */ -	/* _We_ call this UNII 2 */ -	CHAN5G(5260, 18), /* Channel 52 */ -	CHAN5G(5280, 19), /* Channel 56 */ -	CHAN5G(5300, 20), /* Channel 60 */ -	CHAN5G(5320, 21), /* Channel 64 */ -	/* _We_ call this "Middle band" */ -	CHAN5G(5500, 22), /* Channel 100 */ -	CHAN5G(5520, 23), /* Channel 104 */ -	CHAN5G(5540, 24), /* Channel 108 */ -	CHAN5G(5560, 25), /* Channel 112 */ -	CHAN5G(5580, 26), /* Channel 116 */ -	CHAN5G(5600, 27), /* Channel 120 */ -	CHAN5G(5620, 28), /* Channel 124 */ -	CHAN5G(5640, 29), /* Channel 128 */ -	CHAN5G(5660, 30), /* Channel 132 */ -	CHAN5G(5680, 31), /* Channel 136 */ -	CHAN5G(5700, 32), /* Channel 140 */ -	/* _We_ call this UNII 3 */ -	CHAN5G(5745, 33), /* Channel 149 */ -	CHAN5G(5765, 34), /* Channel 153 */ -	CHAN5G(5785, 35), /* Channel 157 */ -	CHAN5G(5805, 36), /* Channel 161 */ -	CHAN5G(5825, 37), /* Channel 165 */ -}; - -/* Atheros hardware rate code addition for short premble */ -#define SHPCHECK(__hw_rate, __flags) \ -	((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04) : 0) - -#define RATE(_bitrate, _hw_rate, _flags) {		\ -	.bitrate	= (_bitrate),			\ -	.flags		= (_flags),			\ -	.hw_value	= (_hw_rate),			\ -	.hw_value_short = (SHPCHECK(_hw_rate, _flags))	\ -} - -static struct ieee80211_rate ath9k_legacy_rates[] = { -	RATE(10, 0x1b, 0), -	RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp : 0x1e */ -	RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp: 0x1d */ -	RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), /* short: 0x1c */ -	RATE(60, 0x0b, 0), -	RATE(90, 0x0f, 0), -	RATE(120, 0x0a, 0), -	RATE(180, 0x0e, 0), -	RATE(240, 0x09, 0), -	RATE(360, 0x0d, 0), -	RATE(480, 0x08, 0), -	RATE(540, 0x0c, 0), -}; +static int ath9k_ps_enable; +module_param_named(ps_enable, ath9k_ps_enable, int, 0444); +MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave");  #ifdef CONFIG_MAC80211_LEDS  static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = { @@ -339,6 +256,25 @@ static void ath9k_multi_regread(void *hw_priv, u32 *addr,         }  } +static void ath9k_regwrite_multi(struct ath_common *common) +{ +	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; +	u32 rsp_status; +	int r; + +	r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, +			  (u8 *) &priv->wmi->multi_write, +			  sizeof(struct register_write) * priv->wmi->multi_write_idx, +			  (u8 *) &rsp_status, sizeof(rsp_status), +			  100); +	if (unlikely(r)) { +		ath_dbg(common, WMI, +			"REGISTER WRITE FAILED, multi len: %d\n", +			priv->wmi->multi_write_idx); +	} +	priv->wmi->multi_write_idx = 0; +} +  static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset)  {  	struct ath_hw *ah = (struct ath_hw *) hw_priv; @@ -365,8 +301,6 @@ static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset)  	struct ath_hw *ah = (struct ath_hw *) hw_priv;  	struct ath_common *common = ath9k_hw_common(ah);  	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; -	u32 rsp_status; -	int r;  	mutex_lock(&priv->wmi->multi_write_mutex); @@ -379,19 +313,8 @@ static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset)  	priv->wmi->multi_write_idx++;  	/* If the buffer is full, send it out. */ -	if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) { -		r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, -			  (u8 *) &priv->wmi->multi_write, -			  sizeof(struct register_write) * priv->wmi->multi_write_idx, -			  (u8 *) &rsp_status, sizeof(rsp_status), -			  100); -		if (unlikely(r)) { -			ath_dbg(common, WMI, -				"REGISTER WRITE FAILED, multi len: %d\n", -				priv->wmi->multi_write_idx); -		} -		priv->wmi->multi_write_idx = 0; -	} +	if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) +		ath9k_regwrite_multi(common);  	mutex_unlock(&priv->wmi->multi_write_mutex);  } @@ -422,26 +345,13 @@ static void ath9k_regwrite_flush(void *hw_priv)  	struct ath_hw *ah = (struct ath_hw *) hw_priv;  	struct ath_common *common = ath9k_hw_common(ah);  	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; -	u32 rsp_status; -	int r;  	atomic_dec(&priv->wmi->mwrite_cnt);  	mutex_lock(&priv->wmi->multi_write_mutex); -	if (priv->wmi->multi_write_idx) { -		r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, -			  (u8 *) &priv->wmi->multi_write, -			  sizeof(struct register_write) * priv->wmi->multi_write_idx, -			  (u8 *) &rsp_status, sizeof(rsp_status), -			  100); -		if (unlikely(r)) { -			ath_dbg(common, WMI, -				"REGISTER WRITE FAILED, multi len: %d\n", -				priv->wmi->multi_write_idx); -		} -		priv->wmi->multi_write_idx = 0; -	} +	if (priv->wmi->multi_write_idx) +		ath9k_regwrite_multi(common);  	mutex_unlock(&priv->wmi->multi_write_mutex);  } @@ -487,51 +397,6 @@ static const struct ath_bus_ops ath9k_usb_bus_ops = {  	.eeprom_read = ath_usb_eeprom_read,  }; -static void setup_ht_cap(struct ath9k_htc_priv *priv, -			 struct ieee80211_sta_ht_cap *ht_info) -{ -	struct ath_common *common = ath9k_hw_common(priv->ah); -	u8 tx_streams, rx_streams; -	int i; - -	ht_info->ht_supported = true; -	ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | -		       IEEE80211_HT_CAP_SM_PS | -		       IEEE80211_HT_CAP_SGI_40 | -		       IEEE80211_HT_CAP_DSSSCCK40; - -	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20) -		ht_info->cap |= IEEE80211_HT_CAP_SGI_20; - -	ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); - -	ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; -	ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; - -	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); - -	/* ath9k_htc supports only 1 or 2 stream devices */ -	tx_streams = ath9k_cmn_count_streams(priv->ah->txchainmask, 2); -	rx_streams = ath9k_cmn_count_streams(priv->ah->rxchainmask, 2); - -	ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n", -		tx_streams, rx_streams); - -	if (tx_streams >= 2) -		ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; - -	if (tx_streams != rx_streams) { -		ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; -		ht_info->mcs.tx_params |= ((tx_streams - 1) << -					   IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); -	} - -	for (i = 0; i < rx_streams; i++) -		ht_info->mcs.rx_mask[i] = 0xff; - -	ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; -} -  static int ath9k_init_queues(struct ath9k_htc_priv *priv)  {  	struct ath_common *common = ath9k_hw_common(priv->ah); @@ -540,8 +405,8 @@ static int ath9k_init_queues(struct ath9k_htc_priv *priv)  	for (i = 0; i < ARRAY_SIZE(priv->hwq_map); i++)  		priv->hwq_map[i] = -1; -	priv->beaconq = ath9k_hw_beaconq_setup(priv->ah); -	if (priv->beaconq == -1) { +	priv->beacon.beaconq = ath9k_hw_beaconq_setup(priv->ah); +	if (priv->beacon.beaconq == -1) {  		ath_err(common, "Unable to setup BEACON xmit queue\n");  		goto err;  	} @@ -576,37 +441,13 @@ err:  	return -EINVAL;  } -static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv) -{ -	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) { -		priv->sbands[IEEE80211_BAND_2GHZ].channels = -			ath9k_2ghz_channels; -		priv->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; -		priv->sbands[IEEE80211_BAND_2GHZ].n_channels = -			ARRAY_SIZE(ath9k_2ghz_channels); -		priv->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; -		priv->sbands[IEEE80211_BAND_2GHZ].n_bitrates = -			ARRAY_SIZE(ath9k_legacy_rates); -	} - -	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) { -		priv->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_channels; -		priv->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; -		priv->sbands[IEEE80211_BAND_5GHZ].n_channels = -			ARRAY_SIZE(ath9k_5ghz_channels); -		priv->sbands[IEEE80211_BAND_5GHZ].bitrates = -			ath9k_legacy_rates + 4; -		priv->sbands[IEEE80211_BAND_5GHZ].n_bitrates = -			ARRAY_SIZE(ath9k_legacy_rates) - 4; -	} -} -  static void ath9k_init_misc(struct ath9k_htc_priv *priv)  {  	struct ath_common *common = ath9k_hw_common(priv->ah);  	memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); +	common->last_rssi = ATH_RSSI_DUMMY_MARKER;  	priv->ah->opmode = NL80211_IFTYPE_STATION;  } @@ -618,12 +459,11 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,  	struct ath_common *common;  	int i, ret = 0, csz = 0; -	set_bit(OP_INVALID, &priv->op_flags); -  	ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);  	if (!ah)  		return -ENOMEM; +	ah->dev = priv->dev;  	ah->hw_version.devid = devid;  	ah->hw_version.usbdev = drv_info;  	ah->ah_flags |= AH_USE_EEPROM; @@ -643,6 +483,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,  	common->priv = priv;  	common->debug_mask = ath9k_debug;  	common->btcoex_enabled = ath9k_htc_btcoex_enable == 1; +	set_bit(ATH_OP_INVALID, &common->op_flags);  	spin_lock_init(&priv->beacon_lock);  	spin_lock_init(&priv->tx.tx_lock); @@ -678,10 +519,11 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,  		goto err_queues;  	for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) -		priv->cur_beacon_conf.bslot[i] = NULL; +		priv->beacon.bslot[i] = NULL; +	priv->beacon.slottime = ATH9K_SLOT_TIME_9; +	ath9k_cmn_init_channels_rates(common);  	ath9k_cmn_init_crypto(ah); -	ath9k_init_channels_rates(priv);  	ath9k_init_misc(priv);  	ath9k_htc_init_btcoex(priv, product); @@ -717,6 +559,7 @@ static const struct ieee80211_iface_combination if_comb = {  static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,  			       struct ieee80211_hw *hw)  { +	struct ath_hw *ah = priv->ah;  	struct ath_common *common = ath9k_hw_common(priv->ah);  	struct base_eep_header *pBase; @@ -725,12 +568,14 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,  		IEEE80211_HW_SPECTRUM_MGMT |  		IEEE80211_HW_HAS_RATE_CONTROL |  		IEEE80211_HW_RX_INCLUDES_FCS | -		IEEE80211_HW_SUPPORTS_PS |  		IEEE80211_HW_PS_NULLFUNC_STACK |  		IEEE80211_HW_REPORTS_TX_ACK_STATUS |  		IEEE80211_HW_MFP_CAPABLE |  		IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; +	if (ath9k_ps_enable) +		hw->flags |= IEEE80211_HW_SUPPORTS_PS; +  	hw->wiphy->interface_modes =  		BIT(NL80211_IFTYPE_STATION) |  		BIT(NL80211_IFTYPE_ADHOC) | @@ -748,7 +593,6 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,  			    WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;  	hw->queues = 4; -	hw->channel_change_time = 5000;  	hw->max_listen_interval = 1;  	hw->vif_data_size = sizeof(struct ath9k_htc_vif); @@ -760,19 +604,12 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,  	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)  		hw->wiphy->bands[IEEE80211_BAND_2GHZ] = -			&priv->sbands[IEEE80211_BAND_2GHZ]; +			&common->sbands[IEEE80211_BAND_2GHZ];  	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)  		hw->wiphy->bands[IEEE80211_BAND_5GHZ] = -			&priv->sbands[IEEE80211_BAND_5GHZ]; - -	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) { -		if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) -			setup_ht_cap(priv, -				     &priv->sbands[IEEE80211_BAND_2GHZ].ht_cap); -		if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) -			setup_ht_cap(priv, -				     &priv->sbands[IEEE80211_BAND_5GHZ].ht_cap); -	} +			&common->sbands[IEEE80211_BAND_5GHZ]; + +	ath9k_cmn_reload_chainmask(ah);  	pBase = ath9k_htc_get_eeprom_base(priv);  	if (pBase) { @@ -1000,6 +837,8 @@ int ath9k_htc_resume(struct htc_target *htc_handle)  	ret = ath9k_init_htc_services(priv, priv->ah->hw_version.devid,  				      priv->ah->hw_version.usbdev); +	ath9k_configure_leds(priv); +  	return ret;  }  #endif diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index d44258172c0..5627917c5ff 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -24,30 +24,10 @@  static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv,  					      struct ath9k_channel *ichan)  { -	enum htc_phymode mode; - -	mode = -EINVAL; - -	switch (ichan->chanmode) { -	case CHANNEL_G: -	case CHANNEL_G_HT20: -	case CHANNEL_G_HT40PLUS: -	case CHANNEL_G_HT40MINUS: -		mode = HTC_MODE_11NG; -		break; -	case CHANNEL_A: -	case CHANNEL_A_HT20: -	case CHANNEL_A_HT40PLUS: -	case CHANNEL_A_HT40MINUS: -		mode = HTC_MODE_11NA; -		break; -	default: -		break; -	} - -	WARN_ON(mode < 0); +	if (IS_CHAN_5GHZ(ichan)) +		return HTC_MODE_11NA; -	return mode; +	return HTC_MODE_11NG;  }  bool ath9k_htc_setpower(struct ath9k_htc_priv *priv, @@ -115,8 +95,10 @@ static void ath9k_htc_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)  	if ((vif->type == NL80211_IFTYPE_AP ||  	     vif->type == NL80211_IFTYPE_MESH_POINT) && -	    bss_conf->enable_beacon) +	    bss_conf->enable_beacon) {  		priv->reconfig_beacon = true; +		priv->rearm_ani = true; +	}  	if (bss_conf->assoc) {  		priv->rearm_ani = true; @@ -147,21 +129,26 @@ static void ath9k_htc_bssid_iter(void *data, u8 *mac, struct ieee80211_vif *vif)  	struct ath9k_vif_iter_data *iter_data = data;  	int i; -	for (i = 0; i < ETH_ALEN; i++) -		iter_data->mask[i] &= ~(iter_data->hw_macaddr[i] ^ mac[i]); +	if (iter_data->hw_macaddr != NULL) { +		for (i = 0; i < ETH_ALEN; i++) +			iter_data->mask[i] &= ~(iter_data->hw_macaddr[i] ^ mac[i]); +	} else { +		iter_data->hw_macaddr = mac; +	}  } -static void ath9k_htc_set_bssid_mask(struct ath9k_htc_priv *priv, +static void ath9k_htc_set_mac_bssid_mask(struct ath9k_htc_priv *priv,  				     struct ieee80211_vif *vif)  {  	struct ath_common *common = ath9k_hw_common(priv->ah);  	struct ath9k_vif_iter_data iter_data;  	/* -	 * Use the hardware MAC address as reference, the hardware uses it -	 * together with the BSSID mask when matching addresses. +	 * Pick the MAC address of the first interface as the new hardware +	 * MAC address. The hardware will use it together with the BSSID mask +	 * when matching addresses.  	 */ -	iter_data.hw_macaddr = common->macaddr; +	iter_data.hw_macaddr = NULL;  	memset(&iter_data.mask, 0xff, ETH_ALEN);  	if (vif) @@ -173,6 +160,10 @@ static void ath9k_htc_set_bssid_mask(struct ath9k_htc_priv *priv,  		ath9k_htc_bssid_iter, &iter_data);  	memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); + +	if (iter_data.hw_macaddr) +		memcpy(common->macaddr, iter_data.hw_macaddr, ETH_ALEN); +  	ath_hw_setbssidmask(common);  } @@ -261,13 +252,14 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,  	u8 cmd_rsp;  	int ret; -	if (test_bit(OP_INVALID, &priv->op_flags)) +	if (test_bit(ATH_OP_INVALID, &common->op_flags))  		return -EIO;  	fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL);  	ath9k_htc_ps_wakeup(priv); +	ath9k_htc_stop_ani(priv);  	del_timer_sync(&priv->tx.cleanup_timer);  	ath9k_htc_tx_drain(priv); @@ -315,7 +307,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,  	htc_start(priv->htc); -	if (!test_bit(OP_SCANNING, &priv->op_flags) && +	if (!test_bit(ATH_OP_SCANNING, &common->op_flags) &&  	    !(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))  		ath9k_htc_vif_reconfig(priv); @@ -759,7 +751,7 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv)  	common->ani.shortcal_timer = timestamp;  	common->ani.checkani_timer = timestamp; -	set_bit(OP_ANI_RUNNING, &priv->op_flags); +	set_bit(ATH_OP_ANI_RUN, &common->op_flags);  	ieee80211_queue_delayed_work(common->hw, &priv->ani_work,  				     msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); @@ -767,8 +759,9 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv)  void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv)  { +	struct ath_common *common = ath9k_hw_common(priv->ah);  	cancel_delayed_work_sync(&priv->ani_work); -	clear_bit(OP_ANI_RUNNING, &priv->op_flags); +	clear_bit(ATH_OP_ANI_RUN, &common->op_flags);  }  void ath9k_htc_ani_work(struct work_struct *work) @@ -926,7 +919,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)  	WMI_CMD(WMI_FLUSH_RECV_CMDID);  	/* setup initial channel */ -	init_channel = ath9k_cmn_get_curchannel(hw, ah); +	init_channel = ath9k_cmn_get_channel(hw, ah, &hw->conf.chandef);  	ret = ath9k_hw_reset(ah, init_channel, ah->caldata, false);  	if (ret) { @@ -953,7 +946,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)  		ath_dbg(common, CONFIG,  			"Failed to update capability in target\n"); -	clear_bit(OP_INVALID, &priv->op_flags); +	clear_bit(ATH_OP_INVALID, &common->op_flags);  	htc_start(priv->htc);  	spin_lock_bh(&priv->tx.tx_lock); @@ -982,7 +975,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)  	mutex_lock(&priv->mutex); -	if (test_bit(OP_INVALID, &priv->op_flags)) { +	if (test_bit(ATH_OP_INVALID, &common->op_flags)) {  		ath_dbg(common, ANY, "Device not present\n");  		mutex_unlock(&priv->mutex);  		return; @@ -1024,7 +1017,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)  	ath9k_htc_ps_restore(priv);  	ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP); -	set_bit(OP_INVALID, &priv->op_flags); +	set_bit(ATH_OP_INVALID, &common->op_flags);  	ath_dbg(common, CONFIG, "Driver halt\n");  	mutex_unlock(&priv->mutex); @@ -1083,7 +1076,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,  		goto out;  	} -	ath9k_htc_set_bssid_mask(priv, vif); +	ath9k_htc_set_mac_bssid_mask(priv, vif);  	priv->vif_slot |= (1 << avp->index);  	priv->nvifs++; @@ -1098,7 +1091,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,  	ath9k_htc_set_opmode(priv);  	if ((priv->ah->opmode == NL80211_IFTYPE_AP) && -	    !test_bit(OP_ANI_RUNNING, &priv->op_flags)) { +	    !test_bit(ATH_OP_ANI_RUN, &common->op_flags)) {  		ath9k_hw_set_tsfadjust(priv->ah, true);  		ath9k_htc_start_ani(priv);  	} @@ -1148,7 +1141,7 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,  	ath9k_htc_set_opmode(priv); -	ath9k_htc_set_bssid_mask(priv, vif); +	ath9k_htc_set_mac_bssid_mask(priv, vif);  	/*  	 * Stop ANI only if there are no associated station interfaces. @@ -1208,9 +1201,7 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)  		ath_dbg(common, CONFIG, "Set channel: %d MHz\n",  			curchan->center_freq); -		ath9k_cmn_update_ichannel(&priv->ah->channels[pos], -					  &hw->conf.chandef); - +		ath9k_cmn_get_channel(hw, priv->ah, &hw->conf.chandef);  		if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {  			ath_err(common, "Unable to set channel\n");  			ret = -EINVAL; @@ -1258,13 +1249,14 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,  				       u64 multicast)  {  	struct ath9k_htc_priv *priv = hw->priv; +	struct ath_common *common = ath9k_hw_common(priv->ah);  	u32 rfilt;  	mutex_lock(&priv->mutex);  	changed_flags &= SUPPORTED_FILTERS;  	*total_flags &= SUPPORTED_FILTERS; -	if (test_bit(OP_INVALID, &priv->op_flags)) { +	if (test_bit(ATH_OP_INVALID, &common->op_flags)) {  		ath_dbg(ath9k_hw_common(priv->ah), ANY,  			"Unable to configure filter on invalid state\n");  		mutex_unlock(&priv->mutex); @@ -1283,18 +1275,50 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,  	mutex_unlock(&priv->mutex);  } +static void ath9k_htc_sta_rc_update_work(struct work_struct *work) +{ +	struct ath9k_htc_sta *ista = +	    container_of(work, struct ath9k_htc_sta, rc_update_work); +	struct ieee80211_sta *sta = +	    container_of((void *)ista, struct ieee80211_sta, drv_priv); +	struct ath9k_htc_priv *priv = ista->htc_priv; +	struct ath_common *common = ath9k_hw_common(priv->ah); +	struct ath9k_htc_target_rate trate; + +	mutex_lock(&priv->mutex); +	ath9k_htc_ps_wakeup(priv); + +	memset(&trate, 0, sizeof(struct ath9k_htc_target_rate)); +	ath9k_htc_setup_rate(priv, sta, &trate); +	if (!ath9k_htc_send_rate_cmd(priv, &trate)) +		ath_dbg(common, CONFIG, +			"Supported rates for sta: %pM updated, rate caps: 0x%X\n", +			sta->addr, be32_to_cpu(trate.capflags)); +	else +		ath_dbg(common, CONFIG, +			"Unable to update supported rates for sta: %pM\n", +			sta->addr); + +	ath9k_htc_ps_restore(priv); +	mutex_unlock(&priv->mutex); +} +  static int ath9k_htc_sta_add(struct ieee80211_hw *hw,  			     struct ieee80211_vif *vif,  			     struct ieee80211_sta *sta)  {  	struct ath9k_htc_priv *priv = hw->priv; +	struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv;  	int ret;  	mutex_lock(&priv->mutex);  	ath9k_htc_ps_wakeup(priv);  	ret = ath9k_htc_add_station(priv, vif, sta); -	if (!ret) +	if (!ret) { +		INIT_WORK(&ista->rc_update_work, ath9k_htc_sta_rc_update_work); +		ista->htc_priv = priv;  		ath9k_htc_init_rate(priv, sta); +	}  	ath9k_htc_ps_restore(priv);  	mutex_unlock(&priv->mutex); @@ -1306,12 +1330,13 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw,  				struct ieee80211_sta *sta)  {  	struct ath9k_htc_priv *priv = hw->priv; -	struct ath9k_htc_sta *ista; +	struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv;  	int ret; +	cancel_work_sync(&ista->rc_update_work); +  	mutex_lock(&priv->mutex);  	ath9k_htc_ps_wakeup(priv); -	ista = (struct ath9k_htc_sta *) sta->drv_priv;  	htc_sta_drain(priv->htc, ista->index);  	ret = ath9k_htc_remove_station(priv, vif, sta);  	ath9k_htc_ps_restore(priv); @@ -1324,28 +1349,12 @@ static void ath9k_htc_sta_rc_update(struct ieee80211_hw *hw,  				    struct ieee80211_vif *vif,  				    struct ieee80211_sta *sta, u32 changed)  { -	struct ath9k_htc_priv *priv = hw->priv; -	struct ath_common *common = ath9k_hw_common(priv->ah); -	struct ath9k_htc_target_rate trate; - -	mutex_lock(&priv->mutex); -	ath9k_htc_ps_wakeup(priv); +	struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv; -	if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { -		memset(&trate, 0, sizeof(struct ath9k_htc_target_rate)); -		ath9k_htc_setup_rate(priv, sta, &trate); -		if (!ath9k_htc_send_rate_cmd(priv, &trate)) -			ath_dbg(common, CONFIG, -				"Supported rates for sta: %pM updated, rate caps: 0x%X\n", -				sta->addr, be32_to_cpu(trate.capflags)); -		else -			ath_dbg(common, CONFIG, -				"Unable to update supported rates for sta: %pM\n", -				sta->addr); -	} +	if (!(changed & IEEE80211_RC_SUPP_RATES_CHANGED)) +		return; -	ath9k_htc_ps_restore(priv); -	mutex_unlock(&priv->mutex); +	schedule_work(&ista->rc_update_work);  }  static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, @@ -1470,7 +1479,9 @@ static void ath9k_htc_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)  	if ((vif->type == NL80211_IFTYPE_STATION) && bss_conf->assoc) {  		common->curaid = bss_conf->aid; +		common->last_rssi = ATH_RSSI_DUMMY_MARKER;  		memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); +		set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags);  	}  } @@ -1492,6 +1503,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,  	struct ath9k_htc_priv *priv = hw->priv;  	struct ath_hw *ah = priv->ah;  	struct ath_common *common = ath9k_hw_common(ah); +	int slottime;  	mutex_lock(&priv->mutex);  	ath9k_htc_ps_wakeup(priv); @@ -1503,6 +1515,9 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,  		bss_conf->assoc ?  			priv->num_sta_assoc_vif++ : priv->num_sta_assoc_vif--; +		if (!bss_conf->assoc) +			clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); +  		if (priv->ah->opmode == NL80211_IFTYPE_STATION) {  			ath9k_htc_choose_set_bssid(priv);  			if (bss_conf->assoc && (priv->num_sta_assoc_vif == 1)) @@ -1524,7 +1539,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,  		ath_dbg(common, CONFIG, "Beacon enabled for BSS: %pM\n",  			bss_conf->bssid);  		ath9k_htc_set_tsfadjust(priv, vif); -		set_bit(OP_ENABLE_BEACON, &priv->op_flags); +		priv->cur_beacon_conf.enable_beacon = 1;  		ath9k_htc_beacon_config(priv, vif);  	} @@ -1538,7 +1553,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,  			ath_dbg(common, CONFIG,  				"Beacon disabled for BSS: %pM\n",  				bss_conf->bssid); -			clear_bit(OP_ENABLE_BEACON, &priv->op_flags); +			priv->cur_beacon_conf.enable_beacon = 0;  			ath9k_htc_beacon_config(priv, vif);  		}  	} @@ -1564,11 +1579,21 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,  	if (changed & BSS_CHANGED_ERP_SLOT) {  		if (bss_conf->use_short_slot) -			ah->slottime = 9; +			slottime = 9;  		else -			ah->slottime = 20; - -		ath9k_hw_init_global_settings(ah); +			slottime = 20; +		if (vif->type == NL80211_IFTYPE_AP) { +			/* +			 * Defer update, so that connected stations can adjust +			 * their settings at the same time. +			 * See beacon.c for more details +			 */ +			priv->beacon.slottime = slottime; +			priv->beacon.updateslot = UPDATE; +		} else { +			ah->slottime = slottime; +			ath9k_hw_init_global_settings(ah); +		}  	}  	if (changed & BSS_CHANGED_HT) @@ -1665,10 +1690,11 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,  static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)  {  	struct ath9k_htc_priv *priv = hw->priv; +	struct ath_common *common = ath9k_hw_common(priv->ah);  	mutex_lock(&priv->mutex);  	spin_lock_bh(&priv->beacon_lock); -	set_bit(OP_SCANNING, &priv->op_flags); +	set_bit(ATH_OP_SCANNING, &common->op_flags);  	spin_unlock_bh(&priv->beacon_lock);  	cancel_work_sync(&priv->ps_work);  	ath9k_htc_stop_ani(priv); @@ -1678,10 +1704,11 @@ static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)  static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)  {  	struct ath9k_htc_priv *priv = hw->priv; +	struct ath_common *common = ath9k_hw_common(priv->ah);  	mutex_lock(&priv->mutex);  	spin_lock_bh(&priv->beacon_lock); -	clear_bit(OP_SCANNING, &priv->op_flags); +	clear_bit(ATH_OP_SCANNING, &common->op_flags);  	spin_unlock_bh(&priv->beacon_lock);  	ath9k_htc_ps_wakeup(priv);  	ath9k_htc_vif_reconfig(priv); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index c028df76b56..bb86eb2ffc9 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -471,8 +471,11 @@ static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv,  	if (!txok || !vif || !txs)  		goto send_mac80211; -	if (txs->ts_flags & ATH9K_HTC_TXSTAT_ACK) +	if (txs->ts_flags & ATH9K_HTC_TXSTAT_ACK) {  		tx_info->flags |= IEEE80211_TX_STAT_ACK; +		if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) +			tx_info->flags |= IEEE80211_TX_STAT_AMPDU; +	}  	if (txs->ts_flags & ATH9K_HTC_TXSTAT_FILT)  		tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; @@ -924,46 +927,43 @@ static void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv)  void ath9k_host_rx_init(struct ath9k_htc_priv *priv)  { +	struct ath_common *common = ath9k_hw_common(priv->ah);  	ath9k_hw_rxena(priv->ah);  	ath9k_htc_opmode_init(priv); -	ath9k_hw_startpcureceive(priv->ah, test_bit(OP_SCANNING, &priv->op_flags)); -	priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER; +	ath9k_hw_startpcureceive(priv->ah, test_bit(ATH_OP_SCANNING, &common->op_flags));  } -static void ath9k_process_rate(struct ieee80211_hw *hw, -			       struct ieee80211_rx_status *rxs, -			       u8 rx_rate, u8 rs_flags) +static inline void convert_htc_flag(struct ath_rx_status *rx_stats, +				   struct ath_htc_rx_status *rxstatus)  { -	struct ieee80211_supported_band *sband; -	enum ieee80211_band band; -	unsigned int i = 0; - -	if (rx_rate & 0x80) { -		/* HT rate */ -		rxs->flag |= RX_FLAG_HT; -		if (rs_flags & ATH9K_RX_2040) -			rxs->flag |= RX_FLAG_40MHZ; -		if (rs_flags & ATH9K_RX_GI) -			rxs->flag |= RX_FLAG_SHORT_GI; -		rxs->rate_idx = rx_rate & 0x7f; -		return; -	} - -	band = hw->conf.chandef.chan->band; -	sband = hw->wiphy->bands[band]; - -	for (i = 0; i < sband->n_bitrates; i++) { -		if (sband->bitrates[i].hw_value == rx_rate) { -			rxs->rate_idx = i; -			return; -		} -		if (sband->bitrates[i].hw_value_short == rx_rate) { -			rxs->rate_idx = i; -			rxs->flag |= RX_FLAG_SHORTPRE; -			return; -		} -	} +	rx_stats->flag = 0; +	if (rxstatus->rs_flags & ATH9K_RX_2040) +		rx_stats->flag |= RX_FLAG_40MHZ; +	if (rxstatus->rs_flags & ATH9K_RX_GI) +		rx_stats->flag |= RX_FLAG_SHORT_GI; +} +static void rx_status_htc_to_ath(struct ath_rx_status *rx_stats, +				 struct ath_htc_rx_status *rxstatus) +{ +	rx_stats->rs_datalen	= rxstatus->rs_datalen; +	rx_stats->rs_status	= rxstatus->rs_status; +	rx_stats->rs_phyerr	= rxstatus->rs_phyerr; +	rx_stats->rs_rssi	= rxstatus->rs_rssi; +	rx_stats->rs_keyix	= rxstatus->rs_keyix; +	rx_stats->rs_rate	= rxstatus->rs_rate; +	rx_stats->rs_antenna	= rxstatus->rs_antenna; +	rx_stats->rs_more	= rxstatus->rs_more; + +	memcpy(rx_stats->rs_rssi_ctl, rxstatus->rs_rssi_ctl, +		sizeof(rx_stats->rs_rssi_ctl)); +	memcpy(rx_stats->rs_rssi_ext, rxstatus->rs_rssi_ext, +		sizeof(rx_stats->rs_rssi_ext)); + +	rx_stats->rs_isaggr	= rxstatus->rs_isaggr; +	rx_stats->rs_moreaggr	= rxstatus->rs_moreaggr; +	rx_stats->rs_num_delims	= rxstatus->rs_num_delims; +	convert_htc_flag(rx_stats, rxstatus);  }  static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, @@ -975,10 +975,10 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,  	struct ieee80211_hw *hw = priv->hw;  	struct sk_buff *skb = rxbuf->skb;  	struct ath_common *common = ath9k_hw_common(priv->ah); +	struct ath_hw *ah = common->ah;  	struct ath_htc_rx_status *rxstatus; -	int hdrlen, padsize; -	int last_rssi = ATH_RSSI_DUMMY_MARKER; -	__le16 fc; +	struct ath_rx_status rx_stats; +	bool decrypt_error;  	if (skb->len < HTC_RX_FRAME_HEADER_SIZE) {  		ath_err(common, "Corrupted RX frame, dropping (len: %d)\n", @@ -996,108 +996,41 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,  		goto rx_next;  	} -	ath9k_htc_err_stat_rx(priv, rxstatus); -  	/* Get the RX status information */ -	memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE); -	skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); - -	hdr = (struct ieee80211_hdr *)skb->data; -	fc = hdr->frame_control; -	hdrlen = ieee80211_get_hdrlen_from_skb(skb); - -	padsize = hdrlen & 3; -	if (padsize && skb->len >= hdrlen+padsize+FCS_LEN) { -		memmove(skb->data + padsize, skb->data, hdrlen); -		skb_pull(skb, padsize); -	}  	memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); -	if (rxbuf->rxstatus.rs_status != 0) { -		if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_CRC) -			rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; -		if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_PHY) -			goto rx_next; - -		if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT) { -			/* FIXME */ -		} else if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_MIC) { -			if (ieee80211_is_ctl(fc)) -				/* -				 * Sometimes, we get invalid -				 * MIC failures on valid control frames. -				 * Remove these mic errors. -				 */ -				rxbuf->rxstatus.rs_status &= ~ATH9K_RXERR_MIC; -			else -				rx_status->flag |= RX_FLAG_MMIC_ERROR; -		} - -		/* -		 * Reject error frames with the exception of -		 * decryption and MIC failures. For monitor mode, -		 * we also ignore the CRC error. -		 */ -		if (priv->ah->opmode == NL80211_IFTYPE_MONITOR) { -			if (rxbuf->rxstatus.rs_status & -			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | -			      ATH9K_RXERR_CRC)) -				goto rx_next; -		} else { -			if (rxbuf->rxstatus.rs_status & -			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { -				goto rx_next; -			} -		} -	} - -	if (!(rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT)) { -		u8 keyix; -		keyix = rxbuf->rxstatus.rs_keyix; -		if (keyix != ATH9K_RXKEYIX_INVALID) { -			rx_status->flag |= RX_FLAG_DECRYPTED; -		} else if (ieee80211_has_protected(fc) && -			   skb->len >= hdrlen + 4) { -			keyix = skb->data[hdrlen + 3] >> 6; -			if (test_bit(keyix, common->keymap)) -				rx_status->flag |= RX_FLAG_DECRYPTED; -		} -	} - -	ath9k_process_rate(hw, rx_status, rxbuf->rxstatus.rs_rate, -			   rxbuf->rxstatus.rs_flags); - -	if (rxbuf->rxstatus.rs_rssi != ATH9K_RSSI_BAD && -	    !rxbuf->rxstatus.rs_moreaggr) -		ATH_RSSI_LPF(priv->rx.last_rssi, -			     rxbuf->rxstatus.rs_rssi); - -	last_rssi = priv->rx.last_rssi; +	/* Copy everything from ath_htc_rx_status (HTC_RX_FRAME_HEADER). +	 * After this, we can drop this part of skb. */ +	rx_status_htc_to_ath(&rx_stats, rxstatus); +	ath9k_htc_err_stat_rx(priv, &rx_stats); +	rx_status->mactime = be64_to_cpu(rxstatus->rs_tstamp); +	skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); -	if (ieee80211_is_beacon(hdr->frame_control) && -	    !is_zero_ether_addr(common->curbssid) && -	    ether_addr_equal(hdr->addr3, common->curbssid)) { -		s8 rssi = rxbuf->rxstatus.rs_rssi; +	/* +	 * everything but the rate is checked here, the rate check is done +	 * separately to avoid doing two lookups for a rate for each frame. +	 */ +	hdr = (struct ieee80211_hdr *)skb->data; +	if (!ath9k_cmn_rx_accept(common, hdr, rx_status, &rx_stats, +			&decrypt_error, priv->rxfilter)) +		goto rx_next; -		if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) -			rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); +	ath9k_cmn_rx_skb_postprocess(common, skb, &rx_stats, +				     rx_status, decrypt_error); -		if (rssi < 0) -			rssi = 0; +	if (ath9k_cmn_process_rate(common, hw, &rx_stats, rx_status)) +		goto rx_next; -		priv->ah->stats.avgbrssi = rssi; -	} +	rx_stats.is_mybeacon = ath_is_mybeacon(common, hdr); +	ath9k_cmn_process_rssi(common, hw, &rx_stats, rx_status); -	rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp); -	rx_status->band = hw->conf.chandef.chan->band; -	rx_status->freq = hw->conf.chandef.chan->center_freq; -	rx_status->signal =  rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR; -	rx_status->antenna = rxbuf->rxstatus.rs_antenna; +	rx_status->band = ah->curchan->chan->band; +	rx_status->freq = ah->curchan->chan->center_freq; +	rx_status->antenna = rx_stats.rs_antenna;  	rx_status->flag |= RX_FLAG_MACTIME_END;  	return true; -  rx_next:  	return false;  } diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index aac4a406a51..a0ff5b63705 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -358,6 +358,36 @@ ret:  		kfree_skb(skb);  } +static void ath9k_htc_fw_panic_report(struct htc_target *htc_handle, +				      struct sk_buff *skb) +{ +	uint32_t *pattern = (uint32_t *)skb->data; + +	switch (*pattern) { +	case 0x33221199: +		{ +		struct htc_panic_bad_vaddr *htc_panic; +		htc_panic = (struct htc_panic_bad_vaddr *) skb->data; +		dev_err(htc_handle->dev, "ath: firmware panic! " +			"exccause: 0x%08x; pc: 0x%08x; badvaddr: 0x%08x.\n", +			htc_panic->exccause, htc_panic->pc, +			htc_panic->badvaddr); +		break; +		} +	case 0x33221299: +		{ +		struct htc_panic_bad_epid *htc_panic; +		htc_panic = (struct htc_panic_bad_epid *) skb->data; +		dev_err(htc_handle->dev, "ath: firmware panic! " +			"bad epid: 0x%08x\n", htc_panic->epid); +		break; +		} +	default: +		dev_err(htc_handle->dev, "ath: uknown panic pattern!\n"); +		break; +	} +} +  /*   * HTC Messages are handled directly here and the obtained SKB   * is freed. @@ -379,6 +409,12 @@ void ath9k_htc_rx_msg(struct htc_target *htc_handle,  	htc_hdr = (struct htc_frame_hdr *) skb->data;  	epid = htc_hdr->endpoint_id; +	if (epid == 0x99) { +		ath9k_htc_fw_panic_report(htc_handle, skb); +		kfree_skb(skb); +		return; +	} +  	if (epid >= ENDPOINT_MAX) {  		if (pipe_id != USB_REG_IN_PIPE)  			dev_kfree_skb_any(skb); diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h index e1ffbb6bd63..06474ccc769 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.h +++ b/drivers/net/wireless/ath/ath9k/htc_hst.h @@ -77,6 +77,18 @@ struct htc_config_pipe_msg {  	u8 credits;  } __packed; +struct htc_panic_bad_vaddr { +	__be32 pattern; +	__be32 exccause; +	__be32 pc; +	__be32 badvaddr; +} __packed; + +struct htc_panic_bad_epid { +	__be32 pattern; +	__be32 epid; +} __packed; +  struct htc_ep_callbacks {  	void *priv;  	void (*tx) (void *, struct sk_buff *, enum htc_endpoint_id, bool txok); diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index 83f4927aeac..a47ea8423f1 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -49,9 +49,10 @@ static inline bool ath9k_hw_calibrate(struct ath_hw *ah,  	return ath9k_hw_ops(ah)->calibrate(ah, chan, rxchainmask, longcal);  } -static inline bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) +static inline bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked, +				   u32 *sync_cause_p)  { -	return ath9k_hw_ops(ah)->get_isr(ah, masked); +	return ath9k_hw_ops(ah)->get_isr(ah, masked, sync_cause_p);  }  static inline void ath9k_hw_set_txdesc(struct ath_hw *ah, void *ds, @@ -78,6 +79,22 @@ static inline void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah,  	ath9k_hw_ops(ah)->antdiv_comb_conf_set(ah, antconf);  } +static inline void ath9k_hw_tx99_start(struct ath_hw *ah, u32 qnum) +{ +	ath9k_hw_ops(ah)->tx99_start(ah, qnum); +} + +static inline void ath9k_hw_tx99_stop(struct ath_hw *ah) +{ +	ath9k_hw_ops(ah)->tx99_stop(ah); +} + +static inline void ath9k_hw_tx99_set_txpower(struct ath_hw *ah, u8 power) +{ +	if (ath9k_hw_ops(ah)->tx99_set_txpower) +		ath9k_hw_ops(ah)->tx99_set_txpower(ah, power); +} +  #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT  static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable) @@ -90,6 +107,21 @@ static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable)  /* Private hardware call ops */ +static inline void ath9k_hw_init_hang_checks(struct ath_hw *ah) +{ +	ath9k_hw_private_ops(ah)->init_hang_checks(ah); +} + +static inline bool ath9k_hw_detect_mac_hang(struct ath_hw *ah) +{ +	return ath9k_hw_private_ops(ah)->detect_mac_hang(ah); +} + +static inline bool ath9k_hw_detect_bb_hang(struct ath_hw *ah) +{ +	return ath9k_hw_private_ops(ah)->detect_bb_hang(ah); +} +  /* PHY ops */  static inline int ath9k_hw_rf_set_freq(struct ath_hw *ah, @@ -215,4 +247,31 @@ static inline void ath9k_hw_set_radar_params(struct ath_hw *ah)  	ath9k_hw_private_ops(ah)->set_radar_params(ah, &ah->radar_conf);  } +static inline void ath9k_hw_init_cal_settings(struct ath_hw *ah) +{ +	ath9k_hw_private_ops(ah)->init_cal_settings(ah); +} + +static inline u32 ath9k_hw_compute_pll_control(struct ath_hw *ah, +					       struct ath9k_channel *chan) +{ +	return ath9k_hw_private_ops(ah)->compute_pll_control(ah, chan); +} + +static inline void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah) +{ +	if (!ath9k_hw_private_ops(ah)->init_mode_gain_regs) +		return; + +	ath9k_hw_private_ops(ah)->init_mode_gain_regs(ah); +} + +static inline void ath9k_hw_ani_cache_ini_regs(struct ath_hw *ah) +{ +	if (!ath9k_hw_private_ops(ah)->ani_cache_ini_regs) +		return; + +	ath9k_hw_private_ops(ah)->ani_cache_ini_regs(ah); +} +  #endif /* ATH9K_HW_OPS_H */ diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index ecc6ec4a1ed..2a8ed8375ec 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -17,15 +17,15 @@  #include <linux/io.h>  #include <linux/slab.h>  #include <linux/module.h> +#include <linux/time.h> +#include <linux/bitops.h>  #include <asm/unaligned.h>  #include "hw.h"  #include "hw-ops.h" -#include "rc.h"  #include "ar9003_mac.h"  #include "ar9003_mci.h"  #include "ar9003_phy.h" -#include "debug.h"  #include "ath9k.h"  static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type); @@ -35,124 +35,30 @@ MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards.");  MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards");  MODULE_LICENSE("Dual BSD/GPL"); -static int __init ath9k_init(void) -{ -	return 0; -} -module_init(ath9k_init); - -static void __exit ath9k_exit(void) -{ -	return; -} -module_exit(ath9k_exit); - -/* Private hardware callbacks */ - -static void ath9k_hw_init_cal_settings(struct ath_hw *ah) -{ -	ath9k_hw_private_ops(ah)->init_cal_settings(ah); -} - -static u32 ath9k_hw_compute_pll_control(struct ath_hw *ah, -					struct ath9k_channel *chan) -{ -	return ath9k_hw_private_ops(ah)->compute_pll_control(ah, chan); -} - -static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah) -{ -	if (!ath9k_hw_private_ops(ah)->init_mode_gain_regs) -		return; - -	ath9k_hw_private_ops(ah)->init_mode_gain_regs(ah); -} - -static void ath9k_hw_ani_cache_ini_regs(struct ath_hw *ah) -{ -	/* You will not have this callback if using the old ANI */ -	if (!ath9k_hw_private_ops(ah)->ani_cache_ini_regs) -		return; - -	ath9k_hw_private_ops(ah)->ani_cache_ini_regs(ah); -} - -/********************/ -/* Helper Functions */ -/********************/ - -#ifdef CONFIG_ATH9K_DEBUGFS - -void ath9k_debug_sync_cause(struct ath_common *common, u32 sync_cause) -{ -	struct ath_softc *sc = common->priv; -	if (sync_cause) -		sc->debug.stats.istats.sync_cause_all++; -	if (sync_cause & AR_INTR_SYNC_RTC_IRQ) -		sc->debug.stats.istats.sync_rtc_irq++; -	if (sync_cause & AR_INTR_SYNC_MAC_IRQ) -		sc->debug.stats.istats.sync_mac_irq++; -	if (sync_cause & AR_INTR_SYNC_EEPROM_ILLEGAL_ACCESS) -		sc->debug.stats.istats.eeprom_illegal_access++; -	if (sync_cause & AR_INTR_SYNC_APB_TIMEOUT) -		sc->debug.stats.istats.apb_timeout++; -	if (sync_cause & AR_INTR_SYNC_PCI_MODE_CONFLICT) -		sc->debug.stats.istats.pci_mode_conflict++; -	if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) -		sc->debug.stats.istats.host1_fatal++; -	if (sync_cause & AR_INTR_SYNC_HOST1_PERR) -		sc->debug.stats.istats.host1_perr++; -	if (sync_cause & AR_INTR_SYNC_TRCV_FIFO_PERR) -		sc->debug.stats.istats.trcv_fifo_perr++; -	if (sync_cause & AR_INTR_SYNC_RADM_CPL_EP) -		sc->debug.stats.istats.radm_cpl_ep++; -	if (sync_cause & AR_INTR_SYNC_RADM_CPL_DLLP_ABORT) -		sc->debug.stats.istats.radm_cpl_dllp_abort++; -	if (sync_cause & AR_INTR_SYNC_RADM_CPL_TLP_ABORT) -		sc->debug.stats.istats.radm_cpl_tlp_abort++; -	if (sync_cause & AR_INTR_SYNC_RADM_CPL_ECRC_ERR) -		sc->debug.stats.istats.radm_cpl_ecrc_err++; -	if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) -		sc->debug.stats.istats.radm_cpl_timeout++; -	if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) -		sc->debug.stats.istats.local_timeout++; -	if (sync_cause & AR_INTR_SYNC_PM_ACCESS) -		sc->debug.stats.istats.pm_access++; -	if (sync_cause & AR_INTR_SYNC_MAC_AWAKE) -		sc->debug.stats.istats.mac_awake++; -	if (sync_cause & AR_INTR_SYNC_MAC_ASLEEP) -		sc->debug.stats.istats.mac_asleep++; -	if (sync_cause & AR_INTR_SYNC_MAC_SLEEP_ACCESS) -		sc->debug.stats.istats.mac_sleep_access++; -} -#endif - -  static void ath9k_hw_set_clockrate(struct ath_hw *ah)  { -	struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;  	struct ath_common *common = ath9k_hw_common(ah); +	struct ath9k_channel *chan = ah->curchan;  	unsigned int clockrate;  	/* AR9287 v1.3+ uses async FIFO and runs the MAC at 117 MHz */  	if (AR_SREV_9287(ah) && AR_SREV_9287_13_OR_LATER(ah))  		clockrate = 117; -	else if (!ah->curchan) /* should really check for CCK instead */ +	else if (!chan) /* should really check for CCK instead */  		clockrate = ATH9K_CLOCK_RATE_CCK; -	else if (conf->chandef.chan->band == IEEE80211_BAND_2GHZ) +	else if (IS_CHAN_2GHZ(chan))  		clockrate = ATH9K_CLOCK_RATE_2GHZ_OFDM;  	else if (ah->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK)  		clockrate = ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM;  	else  		clockrate = ATH9K_CLOCK_RATE_5GHZ_OFDM; -	if (conf_is_ht40(conf)) -		clockrate *= 2; - -	if (ah->curchan) { -		if (IS_CHAN_HALF_RATE(ah->curchan)) +	if (chan) { +		if (IS_CHAN_HT40(chan)) +			clockrate *= 2; +		if (IS_CHAN_HALF_RATE(chan))  			clockrate /= 2; -		if (IS_CHAN_QUARTER_RATE(ah->curchan)) +		if (IS_CHAN_QUARTER_RATE(chan))  			clockrate /= 4;  	} @@ -190,10 +96,7 @@ EXPORT_SYMBOL(ath9k_hw_wait);  void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan,  			  int hw_delay)  { -	if (IS_CHAN_B(chan)) -		hw_delay = (4 * hw_delay) / 22; -	else -		hw_delay /= 10; +	hw_delay /= 10;  	if (IS_CHAN_HALF_RATE(chan))  		hw_delay *= 2; @@ -294,8 +197,7 @@ void ath9k_hw_get_channel_centers(struct ath_hw *ah,  		return;  	} -	if ((chan->chanmode == CHANNEL_A_HT40PLUS) || -	    (chan->chanmode == CHANNEL_G_HT40PLUS)) { +	if (IS_CHAN_HT40PLUS(chan)) {  		centers->synth_center =  			chan->channel + HT40_CHANNEL_CENTER_SHIFT;  		extoff = 1; @@ -341,6 +243,11 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah)  	case AR9300_DEVID_QCA955X:  		ah->hw_version.macVersion = AR_SREV_VERSION_9550;  		return; +	case AR9300_DEVID_AR953X: +		ah->hw_version.macVersion = AR_SREV_VERSION_9531; +		if (ah->get_mac_revision) +			ah->hw_version.macRev = ah->get_mac_revision(); +		return;  	}  	val = REG_READ(ah, AR_SREV) & AR_SREV_ID; @@ -442,23 +349,22 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah)  static void ath9k_hw_init_config(struct ath_hw *ah)  { -	int i; +	struct ath_common *common = ath9k_hw_common(ah);  	ah->config.dma_beacon_response_time = 1;  	ah->config.sw_beacon_response_time = 6; -	ah->config.additional_swba_backoff = 0; -	ah->config.ack_6mb = 0x0;  	ah->config.cwm_ignore_extcca = 0; -	ah->config.pcie_clock_req = 0;  	ah->config.analog_shiftreg = 1; -	for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { -		ah->config.spurchans[i][0] = AR_NO_SPUR; -		ah->config.spurchans[i][1] = AR_NO_SPUR; -	} -  	ah->config.rx_intr_mitigation = true; -	ah->config.pcieSerDesWrite = true; + +	if (AR_SREV_9300_20_OR_LATER(ah)) { +		ah->config.rimt_last = 500; +		ah->config.rimt_first = 2000; +	} else { +		ah->config.rimt_last = 250; +		ah->config.rimt_first = 700; +	}  	/*  	 * We need this for PCI devices only (Cardbus, PCI, miniPCI) @@ -478,6 +384,24 @@ static void ath9k_hw_init_config(struct ath_hw *ah)  	 */  	if (num_possible_cpus() > 1)  		ah->config.serialize_regmode = SER_REG_MODE_AUTO; + +	if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_AUTO) { +		if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI || +		    ((AR_SREV_9160(ah) || AR_SREV_9280(ah) || AR_SREV_9287(ah)) && +		     !ah->is_pciexpress)) { +			ah->config.serialize_regmode = SER_REG_MODE_ON; +		} else { +			ah->config.serialize_regmode = SER_REG_MODE_OFF; +		} +	} + +	ath_dbg(common, RESET, "serialize_regmode is %d\n", +		ah->config.serialize_regmode); + +	if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) +		ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD >> 1; +	else +		ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD;  }  static void ath9k_hw_init_defaults(struct ath_hw *ah) @@ -490,16 +414,24 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)  	ah->hw_version.magic = AR5416_MAGIC;  	ah->hw_version.subvendorid = 0; -	ah->atim_window = 0; -	ah->sta_id1_defaults = -		AR_STA_ID1_CRPT_MIC_ENABLE | -		AR_STA_ID1_MCAST_KSRCH; +	ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE | +			       AR_STA_ID1_MCAST_KSRCH;  	if (AR_SREV_9100(ah))  		ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX; +  	ah->slottime = ATH9K_SLOT_TIME_9;  	ah->globaltxtimeout = (u32) -1;  	ah->power_mode = ATH9K_PM_UNDEFINED;  	ah->htc_reset_init = true; + +	ah->ani_function = ATH9K_ANI_ALL; +	if (!AR_SREV_9300_20_OR_LATER(ah)) +		ah->ani_function &= ~ATH9K_ANI_MRC_CCK; + +	if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) +		ah->tx_trig_level = (AR_FTRIG_256B >> AR_FTRIG_S); +	else +		ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S);  }  static int ath9k_hw_init_macaddr(struct ath_hw *ah) @@ -549,6 +481,18 @@ static int ath9k_hw_post_init(struct ath_hw *ah)  	ath9k_hw_ani_init(ah); +	/* +	 * EEPROM needs to be initialized before we do this. +	 * This is required for regulatory compliance. +	 */ +	if (AR_SREV_9300_20_OR_LATER(ah)) { +		u16 regdmn = ah->eep_ops->get_eeprom(ah, EEP_REG_0); +		if ((regdmn & 0xF0) == CTL_FCC) { +			ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_FCC_2GHZ; +			ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_FCC_5GHZ; +		} +	} +  	return 0;  } @@ -569,6 +513,31 @@ static int __ath9k_hw_init(struct ath_hw *ah)  	ath9k_hw_read_revisions(ah); +	switch (ah->hw_version.macVersion) { +	case AR_SREV_VERSION_5416_PCI: +	case AR_SREV_VERSION_5416_PCIE: +	case AR_SREV_VERSION_9160: +	case AR_SREV_VERSION_9100: +	case AR_SREV_VERSION_9280: +	case AR_SREV_VERSION_9285: +	case AR_SREV_VERSION_9287: +	case AR_SREV_VERSION_9271: +	case AR_SREV_VERSION_9300: +	case AR_SREV_VERSION_9330: +	case AR_SREV_VERSION_9485: +	case AR_SREV_VERSION_9340: +	case AR_SREV_VERSION_9462: +	case AR_SREV_VERSION_9550: +	case AR_SREV_VERSION_9565: +	case AR_SREV_VERSION_9531: +		break; +	default: +		ath_err(common, +			"Mac Chip Rev 0x%02x.%x is not supported by this driver\n", +			ah->hw_version.macVersion, ah->hw_version.macRev); +		return -EOPNOTSUPP; +	} +  	/*  	 * Read back AR_WA into a permanent copy and set bits 14 and 17.  	 * We need to do this to avoid RMW of this register. We cannot @@ -602,50 +571,6 @@ static int __ath9k_hw_init(struct ath_hw *ah)  		return -EIO;  	} -	if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_AUTO) { -		if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI || -		    ((AR_SREV_9160(ah) || AR_SREV_9280(ah) || AR_SREV_9287(ah)) && -		     !ah->is_pciexpress)) { -			ah->config.serialize_regmode = -				SER_REG_MODE_ON; -		} else { -			ah->config.serialize_regmode = -				SER_REG_MODE_OFF; -		} -	} - -	ath_dbg(common, RESET, "serialize_regmode is %d\n", -		ah->config.serialize_regmode); - -	if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) -		ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD >> 1; -	else -		ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD; - -	switch (ah->hw_version.macVersion) { -	case AR_SREV_VERSION_5416_PCI: -	case AR_SREV_VERSION_5416_PCIE: -	case AR_SREV_VERSION_9160: -	case AR_SREV_VERSION_9100: -	case AR_SREV_VERSION_9280: -	case AR_SREV_VERSION_9285: -	case AR_SREV_VERSION_9287: -	case AR_SREV_VERSION_9271: -	case AR_SREV_VERSION_9300: -	case AR_SREV_VERSION_9330: -	case AR_SREV_VERSION_9485: -	case AR_SREV_VERSION_9340: -	case AR_SREV_VERSION_9462: -	case AR_SREV_VERSION_9550: -	case AR_SREV_VERSION_9565: -		break; -	default: -		ath_err(common, -			"Mac Chip Rev 0x%02x.%x is not supported by this driver\n", -			ah->hw_version.macVersion, ah->hw_version.macRev); -		return -EOPNOTSUPP; -	} -  	if (AR_SREV_9271(ah) || AR_SREV_9100(ah) || AR_SREV_9340(ah) ||  	    AR_SREV_9330(ah) || AR_SREV_9550(ah))  		ah->is_pciexpress = false; @@ -653,10 +578,6 @@ static int __ath9k_hw_init(struct ath_hw *ah)  	ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID);  	ath9k_hw_init_cal_settings(ah); -	ah->ani_function = ATH9K_ANI_ALL; -	if (!AR_SREV_9300_20_OR_LATER(ah)) -		ah->ani_function &= ~ATH9K_ANI_MRC_CCK; -  	if (!ah->is_pciexpress)  		ath9k_hw_disablepcie(ah); @@ -675,15 +596,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)  		return r;  	} -	if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) -		ah->tx_trig_level = (AR_FTRIG_256B >> AR_FTRIG_S); -	else -		ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S); - -	if (AR_SREV_9330(ah)) -		ah->bb_watchdog_timeout_ms = 85; -	else -		ah->bb_watchdog_timeout_ms = 25; +	ath9k_hw_init_hang_checks(ah);  	common->state = ATH_HW_INITIALIZED; @@ -716,6 +629,7 @@ int ath9k_hw_init(struct ath_hw *ah)  	case AR9300_DEVID_AR9462:  	case AR9485_DEVID_AR1111:  	case AR9300_DEVID_AR9565: +	case AR9300_DEVID_AR953X:  		break;  	default:  		if (common->bus_ops->ath_bus_type == ATH_USB) @@ -851,7 +765,7 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,  		/* program BB PLL phase_shift */  		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3,  			      AR_CH0_BB_DPLL3_PHASE_SHIFT, 0x1); -	} else if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) { +	} else if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) {  		u32 regval, pll2_divint, pll2_divfrac, refdiv;  		REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); @@ -861,9 +775,15 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,  		udelay(100);  		if (ah->is_clk_25mhz) { -			pll2_divint = 0x54; -			pll2_divfrac = 0x1eb85; -			refdiv = 3; +			if (AR_SREV_9531(ah)) { +				pll2_divint = 0x1c; +				pll2_divfrac = 0xa3d2; +				refdiv = 1; +			} else { +				pll2_divint = 0x54; +				pll2_divfrac = 0x1eb85; +				refdiv = 3; +			}  		} else {  			if (AR_SREV_9340(ah)) {  				pll2_divint = 88; @@ -877,7 +797,10 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,  		}  		regval = REG_READ(ah, AR_PHY_PLL_MODE); -		regval |= (0x1 << 16); +		if (AR_SREV_9531(ah)) +			regval |= (0x1 << 22); +		else +			regval |= (0x1 << 16);  		REG_WRITE(ah, AR_PHY_PLL_MODE, regval);  		udelay(100); @@ -887,14 +810,33 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,  		regval = REG_READ(ah, AR_PHY_PLL_MODE);  		if (AR_SREV_9340(ah)) -			regval = (regval & 0x80071fff) | (0x1 << 30) | -				 (0x1 << 13) | (0x4 << 26) | (0x18 << 19); +			regval = (regval & 0x80071fff) | +				(0x1 << 30) | +				(0x1 << 13) | +				(0x4 << 26) | +				(0x18 << 19); +		else if (AR_SREV_9531(ah)) +			regval = (regval & 0x01c00fff) | +				(0x1 << 31) | +				(0x2 << 29) | +				(0xa << 25) | +				(0x1 << 19) | +				(0x6 << 12);  		else -			regval = (regval & 0x80071fff) | (0x3 << 30) | -				 (0x1 << 13) | (0x4 << 26) | (0x60 << 19); +			regval = (regval & 0x80071fff) | +				(0x3 << 30) | +				(0x1 << 13) | +				(0x4 << 26) | +				(0x60 << 19);  		REG_WRITE(ah, AR_PHY_PLL_MODE, regval); -		REG_WRITE(ah, AR_PHY_PLL_MODE, -			  REG_READ(ah, AR_PHY_PLL_MODE) & 0xfffeffff); + +		if (AR_SREV_9531(ah)) +			REG_WRITE(ah, AR_PHY_PLL_MODE, +				  REG_READ(ah, AR_PHY_PLL_MODE) & 0xffbfffff); +		else +			REG_WRITE(ah, AR_PHY_PLL_MODE, +				  REG_READ(ah, AR_PHY_PLL_MODE) & 0xfffeffff); +  		udelay(1000);  	} @@ -941,7 +883,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,  		AR_IMR_RXORN |  		AR_IMR_BCNMISC; -	if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) +	if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah))  		sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;  	if (AR_SREV_9300_20_OR_LATER(ah)) { @@ -1030,7 +972,6 @@ static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu)  void ath9k_hw_init_global_settings(struct ath_hw *ah)  {  	struct ath_common *common = ath9k_hw_common(ah); -	struct ieee80211_conf *conf = &common->hw->conf;  	const struct ath9k_channel *chan = ah->curchan;  	int acktimeout, ctstimeout, ack_offset = 0;  	int slottime; @@ -1105,8 +1046,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)  	 * BA frames in some implementations, but it has been found to fix ACK  	 * timeout issues in other cases as well.  	 */ -	if (conf->chandef.chan && -	    conf->chandef.chan->band == IEEE80211_BAND_2GHZ && +	if (IS_CHAN_2GHZ(chan) &&  	    !IS_CHAN_HALF_RATE(chan) && !IS_CHAN_QUARTER_RATE(chan)) {  		acktimeout += 64 - sifstime - ah->slottime;  		ctstimeout += 48 - sifstime - ah->slottime; @@ -1148,9 +1088,7 @@ u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan)  {  	u32 ctl = ath_regd_get_band_ctl(reg, chan->chan->band); -	if (IS_CHAN_B(chan)) -		ctl |= CTL_11B; -	else if (IS_CHAN_G(chan)) +	if (IS_CHAN_2GHZ(chan))  		ctl |= CTL_11G;  	else  		ctl |= CTL_11A; @@ -1278,6 +1216,42 @@ void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled,  	*coef_exponent = coef_exp - 16;  } +/* AR9330 WAR: + * call external reset function to reset WMAC if: + * - doing a cold reset + * - we have pending frames in the TX queues. + */ +static bool ath9k_hw_ar9330_reset_war(struct ath_hw *ah, int type) +{ +	int i, npend = 0; + +	for (i = 0; i < AR_NUM_QCU; i++) { +		npend = ath9k_hw_numtxpending(ah, i); +		if (npend) +			break; +	} + +	if (ah->external_reset && +	    (npend || type == ATH9K_RESET_COLD)) { +		int reset_err = 0; + +		ath_dbg(ath9k_hw_common(ah), RESET, +			"reset MAC via external reset\n"); + +		reset_err = ah->external_reset(); +		if (reset_err) { +			ath_err(ath9k_hw_common(ah), +				"External reset failed, err=%d\n", +				reset_err); +			return false; +		} + +		REG_WRITE(ah, AR_RTC_RESET, 1); +	} + +	return true; +} +  static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)  {  	u32 rst_flags; @@ -1328,38 +1302,8 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)  	}  	if (AR_SREV_9330(ah)) { -		int npend = 0; -		int i; - -		/* AR9330 WAR: -		 * call external reset function to reset WMAC if: -		 * - doing a cold reset -		 * - we have pending frames in the TX queues -		 */ - -		for (i = 0; i < AR_NUM_QCU; i++) { -			npend = ath9k_hw_numtxpending(ah, i); -			if (npend) -				break; -		} - -		if (ah->external_reset && -		    (npend || type == ATH9K_RESET_COLD)) { -			int reset_err = 0; - -			ath_dbg(ath9k_hw_common(ah), RESET, -				"reset MAC via external reset\n"); - -			reset_err = ah->external_reset(); -			if (reset_err) { -				ath_err(ath9k_hw_common(ah), -					"External reset failed, err=%d\n", -					reset_err); -				return false; -			} - -			REG_WRITE(ah, AR_RTC_RESET, 1); -		} +		if (!ath9k_hw_ar9330_reset_war(ah, type)) +			return false;  	}  	if (ath9k_hw_mci_is_enabled(ah)) @@ -1369,7 +1313,12 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)  	REGWRITE_BUFFER_FLUSH(ah); -	udelay(50); +	if (AR_SREV_9300_20_OR_LATER(ah)) +		udelay(50); +	else if (AR_SREV_9100(ah)) +		mdelay(10); +	else +		udelay(100);  	REG_WRITE(ah, AR_RTC_RC, 0);  	if (!ath9k_hw_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0, AH_WAIT_TIMEOUT)) { @@ -1405,8 +1354,7 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)  	REGWRITE_BUFFER_FLUSH(ah); -	if (!AR_SREV_9300_20_OR_LATER(ah)) -		udelay(2); +	udelay(2);  	if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah))  		REG_WRITE(ah, AR_RC, 0); @@ -1482,7 +1430,6 @@ static bool ath9k_hw_chip_reset(struct ath_hw *ah,  	if (AR_SREV_9330(ah))  		ar9003_hw_internal_regulator_apply(ah);  	ath9k_hw_init_pll(ah, chan); -	ath9k_hw_set_rfmode(ah, chan);  	return true;  } @@ -1498,10 +1445,9 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,  	int r;  	if (pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH) { -		u32 cur = ah->curchan->channelFlags & (CHANNEL_2GHZ | CHANNEL_5GHZ); -		u32 new = chan->channelFlags & (CHANNEL_2GHZ | CHANNEL_5GHZ); -		band_switch = (cur != new); -		mode_diff = (chan->chanmode != ah->curchan->chanmode); +		u32 flags_diff = chan->channelFlags ^ ah->curchan->channelFlags; +		band_switch = !!(flags_diff & CHANNEL_5GHZ); +		mode_diff = !!(flags_diff & ~CHANNEL_HT);  	}  	for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { @@ -1540,9 +1486,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,  	ath9k_hw_set_clockrate(ah);  	ath9k_hw_apply_txpower(ah, chan, false); -	if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan)) -		ath9k_hw_set_delta_slope(ah, chan); - +	ath9k_hw_set_delta_slope(ah, chan);  	ath9k_hw_spur_mitigate_freq(ah, chan);  	if (band_switch || ini_reloaded) @@ -1574,80 +1518,23 @@ static void ath9k_hw_apply_gpio_override(struct ath_hw *ah)  	}  } -static bool ath9k_hw_check_dcs(u32 dma_dbg, u32 num_dcu_states, -			       int *hang_state, int *hang_pos) +void ath9k_hw_check_nav(struct ath_hw *ah)  { -	static u32 dcu_chain_state[] = {5, 6, 9}; /* DCU chain stuck states */ -	u32 chain_state, dcs_pos, i; - -	for (dcs_pos = 0; dcs_pos < num_dcu_states; dcs_pos++) { -		chain_state = (dma_dbg >> (5 * dcs_pos)) & 0x1f; -		for (i = 0; i < 3; i++) { -			if (chain_state == dcu_chain_state[i]) { -				*hang_state = chain_state; -				*hang_pos = dcs_pos; -				return true; -			} -		} -	} -	return false; -} - -#define DCU_COMPLETE_STATE        1 -#define DCU_COMPLETE_STATE_MASK 0x3 -#define NUM_STATUS_READS         50 -static bool ath9k_hw_detect_mac_hang(struct ath_hw *ah) -{ -	u32 chain_state, comp_state, dcs_reg = AR_DMADBG_4; -	u32 i, hang_pos, hang_state, num_state = 6; - -	comp_state = REG_READ(ah, AR_DMADBG_6); - -	if ((comp_state & DCU_COMPLETE_STATE_MASK) != DCU_COMPLETE_STATE) { -		ath_dbg(ath9k_hw_common(ah), RESET, -			"MAC Hang signature not found at DCU complete\n"); -		return false; -	} - -	chain_state = REG_READ(ah, dcs_reg); -	if (ath9k_hw_check_dcs(chain_state, num_state, &hang_state, &hang_pos)) -		goto hang_check_iter; - -	dcs_reg = AR_DMADBG_5; -	num_state = 4; -	chain_state = REG_READ(ah, dcs_reg); -	if (ath9k_hw_check_dcs(chain_state, num_state, &hang_state, &hang_pos)) -		goto hang_check_iter; - -	ath_dbg(ath9k_hw_common(ah), RESET, -		"MAC Hang signature 1 not found\n"); -	return false; - -hang_check_iter: -	ath_dbg(ath9k_hw_common(ah), RESET, -		"DCU registers: chain %08x complete %08x Hang: state %d pos %d\n", -		chain_state, comp_state, hang_state, hang_pos); - -	for (i = 0; i < NUM_STATUS_READS; i++) { -		chain_state = REG_READ(ah, dcs_reg); -		chain_state = (chain_state >> (5 * hang_pos)) & 0x1f; -		comp_state = REG_READ(ah, AR_DMADBG_6); +	struct ath_common *common = ath9k_hw_common(ah); +	u32 val; -		if (((comp_state & DCU_COMPLETE_STATE_MASK) != -					DCU_COMPLETE_STATE) || -		    (chain_state != hang_state)) -			return false; +	val = REG_READ(ah, AR_NAV); +	if (val != 0xdeadbeef && val > 0x7fff) { +		ath_dbg(common, BSTUCK, "Abnormal NAV: 0x%x\n", val); +		REG_WRITE(ah, AR_NAV, 0);  	} - -	ath_dbg(ath9k_hw_common(ah), RESET, "MAC Hang signature 1 found\n"); - -	return true;  } +EXPORT_SYMBOL(ath9k_hw_check_nav);  bool ath9k_hw_check_alive(struct ath_hw *ah)  {  	int count = 50; -	u32 reg; +	u32 reg, last_val;  	if (AR_SREV_9300(ah))  		return !ath9k_hw_detect_mac_hang(ah); @@ -1655,9 +1542,14 @@ bool ath9k_hw_check_alive(struct ath_hw *ah)  	if (AR_SREV_9285_12_OR_LATER(ah))  		return true; +	last_val = REG_READ(ah, AR_OBS_BUS_1);  	do {  		reg = REG_READ(ah, AR_OBS_BUS_1); +		if (reg != last_val) +			return true; +		udelay(1); +		last_val = reg;  		if ((reg & 0x7E7FFFEF) == 0x00702400)  			continue; @@ -1705,7 +1597,6 @@ static void ath9k_hw_reset_opmode(struct ath_hw *ah,  	REG_RMW(ah, AR_STA_ID1, macStaId1  		  | AR_STA_ID1_RTS_USE_DEF -		  | (ah->config.ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0)  		  | ah->sta_id1_defaults,  		  ~AR_STA_ID1_SADH_MASK);  	ath_hw_setbssidmask(common); @@ -1764,7 +1655,7 @@ static void ath9k_hw_init_desc(struct ath_hw *ah)  		}  #ifdef __BIG_ENDIAN  		else if (AR_SREV_9330(ah) || AR_SREV_9340(ah) || -			 AR_SREV_9550(ah)) +			 AR_SREV_9550(ah) || AR_SREV_9531(ah))  			REG_RMW(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB, 0);  		else  			REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); @@ -1799,20 +1690,11 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)  		goto fail;  	/* -	 * If cross-band fcc is not supoprted, bail out if -	 * either channelFlags or chanmode differ. -	 * -	 * chanmode will be different if the HT operating mode -	 * changes because of CSA. +	 * If cross-band fcc is not supoprted, bail out if channelFlags differ.  	 */ -	if (!(pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH)) { -		if ((chan->channelFlags & CHANNEL_ALL) != -		    (ah->curchan->channelFlags & CHANNEL_ALL)) -			goto fail; - -		if (chan->chanmode != ah->curchan->chanmode) -			goto fail; -	} +	if (!(pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH) && +	    ((chan->channelFlags ^ ah->curchan->channelFlags) & ~CHANNEL_HT)) +		goto fail;  	if (!ath9k_hw_check_alive(ah))  		goto fail; @@ -1822,9 +1704,9 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)  	 * re-using are present.  	 */  	if (AR_SREV_9462(ah) && (ah->caldata && -				 (!ah->caldata->done_txiqcal_once || -				  !ah->caldata->done_txclcal_once || -				  !ah->caldata->rtt_done))) +				 (!test_bit(TXIQCAL_DONE, &ah->caldata->cal_flags) || +				  !test_bit(TXCLCAL_DONE, &ah->caldata->cal_flags) || +				  !test_bit(RTT_DONE, &ah->caldata->cal_flags))))  		goto fail;  	ath_dbg(common, RESET, "FastChannelChange for %d -> %d\n", @@ -1852,10 +1734,12 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,  		   struct ath9k_hw_cal_data *caldata, bool fastcc)  {  	struct ath_common *common = ath9k_hw_common(ah); +	struct timespec ts;  	u32 saveLedState;  	u32 saveDefAntenna;  	u32 macStaId1;  	u64 tsf = 0; +	s64 usec = 0;  	int r;  	bool start_mci_reset = false;  	bool save_fullsleep = ah->chip_fullsleep; @@ -1874,15 +1758,14 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,  	ah->caldata = caldata;  	if (caldata && (chan->channel != caldata->channel || -			chan->channelFlags != caldata->channelFlags || -			chan->chanmode != caldata->chanmode)) { +			chan->channelFlags != caldata->channelFlags)) {  		/* Operating channel changed, reset channel calibration data */  		memset(caldata, 0, sizeof(*caldata));  		ath9k_init_nfcal_hist_buffer(ah, chan);  	} else if (caldata) { -		caldata->paprd_packet_sent = false; +		clear_bit(PAPRD_PACKET_SENT, &caldata->cal_flags);  	} -	ah->noise = ath9k_hw_getchan_noise(ah, chan); +	ah->noise = ath9k_hw_getchan_noise(ah, chan, chan->noisefloor);  	if (fastcc) {  		r = ath9k_hw_do_fastcc(ah, chan); @@ -1899,10 +1782,10 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,  	macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B; -	/* For chips on which RTC reset is done, save TSF before it gets cleared */ -	if (AR_SREV_9100(ah) || -	    (AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))) -		tsf = ath9k_hw_gettsf64(ah); +	/* Save TSF before chip reset, a cold reset clears it */ +	tsf = ath9k_hw_gettsf64(ah); +	getrawmonotonic(&ts); +	usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000;  	saveLedState = REG_READ(ah, AR_CFG_LED) &  		(AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL | @@ -1935,8 +1818,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,  	}  	/* Restore TSF */ -	if (tsf) -		ath9k_hw_settsf64(ah, tsf); +	getrawmonotonic(&ts); +	usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000 - usec; +	ath9k_hw_settsf64(ah, tsf + usec);  	if (AR_SREV_9280_20_OR_LATER(ah))  		REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); @@ -1948,6 +1832,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,  	if (r)  		return r; +	ath9k_hw_set_rfmode(ah, chan); +  	if (ath9k_hw_mci_is_enabled(ah))  		ar9003_mci_reset(ah, false, IS_CHAN_2GHZ(chan), save_fullsleep); @@ -1964,9 +1850,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,  	ath9k_hw_init_mfp(ah); -	if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan)) -		ath9k_hw_set_delta_slope(ah, chan); - +	ath9k_hw_set_delta_slope(ah, chan);  	ath9k_hw_spur_mitigate_freq(ah, chan);  	ah->eep_ops->set_board_values(ah, chan); @@ -2005,8 +1889,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,  		REG_WRITE(ah, AR_OBS, 8);  	if (ah->config.rx_intr_mitigation) { -		REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500); -		REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000); +		REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, ah->config.rimt_last); +		REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, ah->config.rimt_first);  	}  	if (ah->config.tx_intr_mitigation) { @@ -2017,8 +1901,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,  	ath9k_hw_init_bb(ah, chan);  	if (caldata) { -		caldata->done_txiqcal_once = false; -		caldata->done_txclcal_once = false; +		clear_bit(TXIQCAL_DONE, &caldata->cal_flags); +		clear_bit(TXCLCAL_DONE, &caldata->cal_flags);  	}  	if (!ath9k_hw_init_cal(ah, chan))  		return -EIO; @@ -2044,10 +1928,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,  	ath9k_hw_loadnf(ah, chan);  	ath9k_hw_start_nfcal(ah, true); -	if (AR_SREV_9300_20_OR_LATER(ah)) { +	if (AR_SREV_9300_20_OR_LATER(ah))  		ar9003_hw_bb_watchdog_config(ah); + +	if (ah->config.hw_hang_checks & HW_PHYRESTART_CLC_WAR)  		ar9003_hw_disable_phy_restart(ah); -	}  	ath9k_hw_apply_gpio_override(ah); @@ -2171,7 +2056,10 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah)  	REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,  		    AR_RTC_FORCE_WAKE_EN); -	udelay(50); +	if (AR_SREV_9100(ah)) +		mdelay(10); +	else +		udelay(50);  	for (i = POWER_UP_TIME / 50; i > 0; i--) {  		val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M; @@ -2260,9 +2148,6 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)  	case NL80211_IFTYPE_ADHOC:  		REG_SET_BIT(ah, AR_TXCFG,  			    AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); -		REG_WRITE(ah, AR_NEXT_NDP_TIMER, next_beacon + -			  TU_TO_USEC(ah->atim_window ? ah->atim_window : 1)); -		flags |= AR_NDP_TIMER_EN;  	case NL80211_IFTYPE_MESH_POINT:  	case NL80211_IFTYPE_AP:  		REG_WRITE(ah, AR_NEXT_TBTT_TIMER, next_beacon); @@ -2283,7 +2168,6 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)  	REG_WRITE(ah, AR_BEACON_PERIOD, beacon_period);  	REG_WRITE(ah, AR_DMA_BEACON_PERIOD, beacon_period);  	REG_WRITE(ah, AR_SWBA_PERIOD, beacon_period); -	REG_WRITE(ah, AR_NDP_PERIOD, beacon_period);  	REGWRITE_BUFFER_FLUSH(ah); @@ -2300,12 +2184,9 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,  	ENABLE_REGWRITE_BUFFER(ah); -	REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt)); - -	REG_WRITE(ah, AR_BEACON_PERIOD, -		  TU_TO_USEC(bs->bs_intval)); -	REG_WRITE(ah, AR_DMA_BEACON_PERIOD, -		  TU_TO_USEC(bs->bs_intval)); +	REG_WRITE(ah, AR_NEXT_TBTT_TIMER, bs->bs_nexttbtt); +	REG_WRITE(ah, AR_BEACON_PERIOD, bs->bs_intval); +	REG_WRITE(ah, AR_DMA_BEACON_PERIOD, bs->bs_intval);  	REGWRITE_BUFFER_FLUSH(ah); @@ -2333,9 +2214,8 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,  	ENABLE_REGWRITE_BUFFER(ah); -	REG_WRITE(ah, AR_NEXT_DTIM, -		  TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP)); -	REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP)); +	REG_WRITE(ah, AR_NEXT_DTIM, bs->bs_nextdtim - SLEEP_SLOP); +	REG_WRITE(ah, AR_NEXT_TIM, nextTbtt - SLEEP_SLOP);  	REG_WRITE(ah, AR_SLEEP1,  		  SM((CAB_TIMEOUT_VAL << 3), AR_SLEEP1_CAB_TIMEOUT) @@ -2349,8 +2229,8 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,  	REG_WRITE(ah, AR_SLEEP2,  		  SM(beacontimeout, AR_SLEEP2_BEACON_TIMEOUT)); -	REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval)); -	REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod)); +	REG_WRITE(ah, AR_TIM_PERIOD, beaconintval); +	REG_WRITE(ah, AR_DTIM_PERIOD, dtimperiod);  	REGWRITE_BUFFER_FLUSH(ah); @@ -2608,13 +2488,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)  	    ah->eep_ops->get_eeprom(ah, EEP_PAPRD))  			pCap->hw_caps |= ATH9K_HW_CAP_PAPRD; -	/* -	 * Fast channel change across bands is available -	 * only for AR9462 and AR9565. -	 */ -	if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) -		pCap->hw_caps |= ATH9K_HW_CAP_FCC_BAND_SWITCH; -  	return 0;  } @@ -2943,12 +2816,11 @@ void ath9k_hw_set_tsfadjust(struct ath_hw *ah, bool set)  }  EXPORT_SYMBOL(ath9k_hw_set_tsfadjust); -void ath9k_hw_set11nmac2040(struct ath_hw *ah) +void ath9k_hw_set11nmac2040(struct ath_hw *ah, struct ath9k_channel *chan)  { -	struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;  	u32 macmode; -	if (conf_is_ht40(conf) && !ah->config.cwm_ignore_extcca) +	if (IS_CHAN_HT40(chan) && !ah->config.cwm_ignore_extcca)  		macmode = AR_2040_JOINED_RX_CLEAR;  	else  		macmode = 0; @@ -2987,20 +2859,6 @@ static const struct ath_gen_timer_configuration gen_tmr_configuration[] =  /* HW generic timer primitives */ -/* compute and clear index of rightmost 1 */ -static u32 rightmost_index(struct ath_gen_timer_table *timer_table, u32 *mask) -{ -	u32 b; - -	b = *mask; -	b &= (0-b); -	*mask &= ~b; -	b *= debruijn32; -	b >>= 27; - -	return timer_table->gen_timer_index[b]; -} -  u32 ath9k_hw_gettsf32(struct ath_hw *ah)  {  	return REG_READ(ah, AR_TSF_L32); @@ -3016,6 +2874,10 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,  	struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;  	struct ath_gen_timer *timer; +	if ((timer_index < AR_FIRST_NDP_TIMER) || +		(timer_index >= ATH_MAX_GEN_TIMER)) +		return NULL; +  	timer = kzalloc(sizeof(struct ath_gen_timer), GFP_KERNEL);  	if (timer == NULL)  		return NULL; @@ -3033,23 +2895,13 @@ EXPORT_SYMBOL(ath_gen_timer_alloc);  void ath9k_hw_gen_timer_start(struct ath_hw *ah,  			      struct ath_gen_timer *timer, -			      u32 trig_timeout, +			      u32 timer_next,  			      u32 timer_period)  {  	struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; -	u32 tsf, timer_next; - -	BUG_ON(!timer_period); +	u32 mask = 0; -	set_bit(timer->index, &timer_table->timer_mask.timer_bits); - -	tsf = ath9k_hw_gettsf32(ah); - -	timer_next = tsf + trig_timeout; - -	ath_dbg(ath9k_hw_common(ah), BTCOEX, -		"current tsf %x period %x timer_next %x\n", -		tsf, timer_period, timer_next); +	timer_table->timer_mask |= BIT(timer->index);  	/*  	 * Program generic timer registers @@ -3075,10 +2927,19 @@ void ath9k_hw_gen_timer_start(struct ath_hw *ah,  				       (1 << timer->index));  	} -	/* Enable both trigger and thresh interrupt masks */ -	REG_SET_BIT(ah, AR_IMR_S5, -		(SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) | -		SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG))); +	if (timer->trigger) +		mask |= SM(AR_GENTMR_BIT(timer->index), +			   AR_IMR_S5_GENTIMER_TRIG); +	if (timer->overflow) +		mask |= SM(AR_GENTMR_BIT(timer->index), +			   AR_IMR_S5_GENTIMER_THRESH); + +	REG_SET_BIT(ah, AR_IMR_S5, mask); + +	if ((ah->imask & ATH9K_INT_GENTIMER) == 0) { +		ah->imask |= ATH9K_INT_GENTIMER; +		ath9k_hw_set_interrupts(ah); +	}  }  EXPORT_SYMBOL(ath9k_hw_gen_timer_start); @@ -3086,11 +2947,6 @@ void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)  {  	struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; -	if ((timer->index < AR_FIRST_NDP_TIMER) || -		(timer->index >= ATH_MAX_GEN_TIMER)) { -		return; -	} -  	/* Clear generic timer enable bits. */  	REG_CLR_BIT(ah, gen_tmr_configuration[timer->index].mode_addr,  			gen_tmr_configuration[timer->index].mode_mask); @@ -3110,7 +2966,12 @@ void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)  		(SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) |  		SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG))); -	clear_bit(timer->index, &timer_table->timer_mask.timer_bits); +	timer_table->timer_mask &= ~BIT(timer->index); + +	if (timer_table->timer_mask == 0) { +		ah->imask &= ~ATH9K_INT_GENTIMER; +		ath9k_hw_set_interrupts(ah); +	}  }  EXPORT_SYMBOL(ath9k_hw_gen_timer_stop); @@ -3131,32 +2992,32 @@ void ath_gen_timer_isr(struct ath_hw *ah)  {  	struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;  	struct ath_gen_timer *timer; -	struct ath_common *common = ath9k_hw_common(ah); -	u32 trigger_mask, thresh_mask, index; +	unsigned long trigger_mask, thresh_mask; +	unsigned int index;  	/* get hardware generic timer interrupt status */  	trigger_mask = ah->intr_gen_timer_trigger;  	thresh_mask = ah->intr_gen_timer_thresh; -	trigger_mask &= timer_table->timer_mask.val; -	thresh_mask &= timer_table->timer_mask.val; +	trigger_mask &= timer_table->timer_mask; +	thresh_mask &= timer_table->timer_mask; -	trigger_mask &= ~thresh_mask; - -	while (thresh_mask) { -		index = rightmost_index(timer_table, &thresh_mask); +	for_each_set_bit(index, &thresh_mask, ARRAY_SIZE(timer_table->timers)) {  		timer = timer_table->timers[index]; -		BUG_ON(!timer); -		ath_dbg(common, BTCOEX, "TSF overflow for Gen timer %d\n", -			index); +		if (!timer) +		    continue; +		if (!timer->overflow) +		    continue; + +		trigger_mask &= ~BIT(index);  		timer->overflow(timer->arg);  	} -	while (trigger_mask) { -		index = rightmost_index(timer_table, &trigger_mask); +	for_each_set_bit(index, &trigger_mask, ARRAY_SIZE(timer_table->timers)) {  		timer = timer_table->timers[index]; -		BUG_ON(!timer); -		ath_dbg(common, BTCOEX, -			"Gen timer[%d] trigger\n", index); +		if (!timer) +		    continue; +		if (!timer->trigger) +		    continue;  		timer->trigger(timer->arg);  	}  } @@ -3187,6 +3048,7 @@ static struct {  	{ AR_SREV_VERSION_9462,         "9462" },  	{ AR_SREV_VERSION_9550,         "9550" },  	{ AR_SREV_VERSION_9565,         "9565" }, +	{ AR_SREV_VERSION_9531,         "9531" },  };  /* For devices with external radios */ @@ -3240,19 +3102,19 @@ void ath9k_hw_name(struct ath_hw *ah, char *hw_name, size_t len)  	/* chipsets >= AR9280 are single-chip */  	if (AR_SREV_9280_20_OR_LATER(ah)) { -		used = snprintf(hw_name, len, -			       "Atheros AR%s Rev:%x", -			       ath9k_hw_mac_bb_name(ah->hw_version.macVersion), -			       ah->hw_version.macRev); +		used = scnprintf(hw_name, len, +				 "Atheros AR%s Rev:%x", +				 ath9k_hw_mac_bb_name(ah->hw_version.macVersion), +				 ah->hw_version.macRev);  	}  	else { -		used = snprintf(hw_name, len, -			       "Atheros AR%s MAC/BB Rev:%x AR%s RF Rev:%x", -			       ath9k_hw_mac_bb_name(ah->hw_version.macVersion), -			       ah->hw_version.macRev, -			       ath9k_hw_rf_name((ah->hw_version.analog5GhzRev & -						AR_RADIO_SREV_MAJOR)), -			       ah->hw_version.phyRev); +		used = scnprintf(hw_name, len, +				 "Atheros AR%s MAC/BB Rev:%x AR%s RF Rev:%x", +				 ath9k_hw_mac_bb_name(ah->hw_version.macVersion), +				 ah->hw_version.macRev, +				 ath9k_hw_rf_name((ah->hw_version.analog5GhzRev +						  & AR_RADIO_SREV_MAJOR)), +				 ah->hw_version.phyRev);  	}  	hw_name[used] = '\0'; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 69a907b55a7..0acd4b5a489 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -52,6 +52,7 @@  #define AR9300_DEVID_QCA955X	0x0038  #define AR9485_DEVID_AR1111	0x0037  #define AR9300_DEVID_AR9565     0x0036 +#define AR9300_DEVID_AR953X     0x003d  #define AR5416_AR9100_DEVID	0x000b @@ -98,8 +99,8 @@  #define PR_EEP(_s, _val)						\  	do {								\ -		len += snprintf(buf + len, size - len, "%20s : %10d\n",	\ -				_s, (_val));				\ +		len += scnprintf(buf + len, size - len, "%20s : %10d\n",\ +				 _s, (_val));				\  	} while (0)  #define SM(_v, _f)  (((_v) << _f##_S) & _f) @@ -168,7 +169,7 @@  #define CAB_TIMEOUT_VAL             10  #define BEACON_TIMEOUT_VAL          10  #define MIN_BEACON_TIMEOUT_VAL      1 -#define SLEEP_SLOP                  3 +#define SLEEP_SLOP                  TU_TO_USEC(3)  #define INIT_CONFIG_STATUS          0x00000000  #define INIT_RSSI_THR               0x00000700 @@ -277,14 +278,25 @@ struct ath9k_hw_capabilities {  	u8 txs_len;  }; +#define AR_NO_SPUR      	0x8000 +#define AR_BASE_FREQ_2GHZ   	2300 +#define AR_BASE_FREQ_5GHZ   	4900 +#define AR_SPUR_FEEQ_BOUND_HT40 19 +#define AR_SPUR_FEEQ_BOUND_HT20 10 + +enum ath9k_hw_hang_checks { +	HW_BB_WATCHDOG            = BIT(0), +	HW_PHYRESTART_CLC_WAR     = BIT(1), +	HW_BB_RIFS_HANG           = BIT(2), +	HW_BB_DFS_HANG            = BIT(3), +	HW_BB_RX_CLEAR_STUCK_HANG = BIT(4), +	HW_MAC_HANG               = BIT(5), +}; +  struct ath9k_ops_config {  	int dma_beacon_response_time;  	int sw_beacon_response_time; -	int additional_swba_backoff; -	int ack_6mb;  	u32 cwm_ignore_extcca; -	bool pcieSerDesWrite; -	u8 pcie_clock_req;  	u32 pcie_waen;  	u8 analog_shiftreg;  	u32 ofdm_trig_low; @@ -295,20 +307,11 @@ struct ath9k_ops_config {  	int serialize_regmode;  	bool rx_intr_mitigation;  	bool tx_intr_mitigation; -#define SPUR_DISABLE        	0 -#define SPUR_ENABLE_IOCTL   	1 -#define SPUR_ENABLE_EEPROM  	2 -#define AR_SPUR_5413_1      	1640 -#define AR_SPUR_5413_2      	1200 -#define AR_NO_SPUR      	0x8000 -#define AR_BASE_FREQ_2GHZ   	2300 -#define AR_BASE_FREQ_5GHZ   	4900 -#define AR_SPUR_FEEQ_BOUND_HT40 19 -#define AR_SPUR_FEEQ_BOUND_HT20 10 -	int spurmode; -	u16 spurchans[AR_EEPROM_MODAL_SPURS][2];  	u8 max_txtrig_level;  	u16 ani_poll_interval; /* ANI poll interval in ms */ +	u16 hw_hang_checks; +	u16 rimt_first; +	u16 rimt_last;  	/* Platform specific config */  	u32 aspm_l1_fix; @@ -316,6 +319,8 @@ struct ath9k_ops_config {  	u32 ant_ctrl_comm2g_switch_enable;  	bool xatten_margin_cfg;  	bool alt_mingainidx; +	bool no_pll_pwrsave; +	bool tx_gain_buffalo;  };  enum ath9k_int { @@ -369,55 +374,30 @@ enum ath9k_int {  	ATH9K_INT_NOCARD = 0xffffffff  }; -#define CHANNEL_CCK       0x00020 -#define CHANNEL_OFDM      0x00040 -#define CHANNEL_2GHZ      0x00080 -#define CHANNEL_5GHZ      0x00100 -#define CHANNEL_PASSIVE   0x00200 -#define CHANNEL_DYN       0x00400 -#define CHANNEL_HALF      0x04000 -#define CHANNEL_QUARTER   0x08000 -#define CHANNEL_HT20      0x10000 -#define CHANNEL_HT40PLUS  0x20000 -#define CHANNEL_HT40MINUS 0x40000 - -#define CHANNEL_A           (CHANNEL_5GHZ|CHANNEL_OFDM) -#define CHANNEL_B           (CHANNEL_2GHZ|CHANNEL_CCK) -#define CHANNEL_G           (CHANNEL_2GHZ|CHANNEL_OFDM) -#define CHANNEL_G_HT20      (CHANNEL_2GHZ|CHANNEL_HT20) -#define CHANNEL_A_HT20      (CHANNEL_5GHZ|CHANNEL_HT20) -#define CHANNEL_G_HT40PLUS  (CHANNEL_2GHZ|CHANNEL_HT40PLUS) -#define CHANNEL_G_HT40MINUS (CHANNEL_2GHZ|CHANNEL_HT40MINUS) -#define CHANNEL_A_HT40PLUS  (CHANNEL_5GHZ|CHANNEL_HT40PLUS) -#define CHANNEL_A_HT40MINUS (CHANNEL_5GHZ|CHANNEL_HT40MINUS) -#define CHANNEL_ALL				\ -	(CHANNEL_OFDM|				\ -	 CHANNEL_CCK|				\ -	 CHANNEL_2GHZ |				\ -	 CHANNEL_5GHZ |				\ -	 CHANNEL_HT20 |				\ -	 CHANNEL_HT40PLUS |			\ -	 CHANNEL_HT40MINUS) -  #define MAX_RTT_TABLE_ENTRY     6  #define MAX_IQCAL_MEASUREMENT	8  #define MAX_CL_TAB_ENTRY	16  #define CL_TAB_ENTRY(reg_base)	(reg_base + (4 * j)) +enum ath9k_cal_flags { +	RTT_DONE, +	PAPRD_PACKET_SENT, +	PAPRD_DONE, +	NFCAL_PENDING, +	NFCAL_INTF, +	TXIQCAL_DONE, +	TXCLCAL_DONE, +	SW_PKDET_DONE, +}; +  struct ath9k_hw_cal_data {  	u16 channel; -	u32 channelFlags; -	u32 chanmode; +	u16 channelFlags; +	unsigned long cal_flags;  	int32_t CalValid;  	int8_t iCoff;  	int8_t qCoff; -	bool rtt_done; -	bool paprd_packet_sent; -	bool paprd_done; -	bool nfcal_pending; -	bool nfcal_interference; -	bool done_txiqcal_once; -	bool done_txclcal_once; +	u8 caldac[2];  	u16 small_signal_gain[AR9300_MAX_CHAINS];  	u32 pa_table[AR9300_MAX_CHAINS][PAPRD_TABLE_SZ];  	u32 num_measures[AR9300_MAX_CHAINS]; @@ -430,33 +410,34 @@ struct ath9k_hw_cal_data {  struct ath9k_channel {  	struct ieee80211_channel *chan;  	u16 channel; -	u32 channelFlags; -	u32 chanmode; +	u16 channelFlags;  	s16 noisefloor;  }; -#define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \ -       (((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \ -       (((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \ -       (((_c)->channelFlags & CHANNEL_G_HT40MINUS) == CHANNEL_G_HT40MINUS)) -#define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0) -#define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0) -#define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0) -#define IS_CHAN_HALF_RATE(_c) (((_c)->channelFlags & CHANNEL_HALF) != 0) -#define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0) +#define CHANNEL_5GHZ		BIT(0) +#define CHANNEL_HALF		BIT(1) +#define CHANNEL_QUARTER		BIT(2) +#define CHANNEL_HT		BIT(3) +#define CHANNEL_HT40PLUS	BIT(4) +#define CHANNEL_HT40MINUS	BIT(5) + +#define IS_CHAN_5GHZ(_c) (!!((_c)->channelFlags & CHANNEL_5GHZ)) +#define IS_CHAN_2GHZ(_c) (!IS_CHAN_5GHZ(_c)) + +#define IS_CHAN_HALF_RATE(_c) (!!((_c)->channelFlags & CHANNEL_HALF)) +#define IS_CHAN_QUARTER_RATE(_c) (!!((_c)->channelFlags & CHANNEL_QUARTER))  #define IS_CHAN_A_FAST_CLOCK(_ah, _c)			\ -	((((_c)->channelFlags & CHANNEL_5GHZ) != 0) &&	\ -	 ((_ah)->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK)) - -/* These macros check chanmode and not channelFlags */ -#define IS_CHAN_B(_c) ((_c)->chanmode == CHANNEL_B) -#define IS_CHAN_HT20(_c) (((_c)->chanmode == CHANNEL_A_HT20) ||	\ -			  ((_c)->chanmode == CHANNEL_G_HT20)) -#define IS_CHAN_HT40(_c) (((_c)->chanmode == CHANNEL_A_HT40PLUS) ||	\ -			  ((_c)->chanmode == CHANNEL_A_HT40MINUS) ||	\ -			  ((_c)->chanmode == CHANNEL_G_HT40PLUS) ||	\ -			  ((_c)->chanmode == CHANNEL_G_HT40MINUS)) -#define IS_CHAN_HT(_c) (IS_CHAN_HT20((_c)) || IS_CHAN_HT40((_c))) +	(IS_CHAN_5GHZ(_c) && ((_ah)->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK)) + +#define IS_CHAN_HT(_c) ((_c)->channelFlags & CHANNEL_HT) + +#define IS_CHAN_HT20(_c) (IS_CHAN_HT(_c) && !IS_CHAN_HT40(_c)) + +#define IS_CHAN_HT40(_c) \ +	(!!((_c)->channelFlags & (CHANNEL_HT40PLUS | CHANNEL_HT40MINUS))) + +#define IS_CHAN_HT40PLUS(_c) ((_c)->channelFlags & CHANNEL_HT40PLUS) +#define IS_CHAN_HT40MINUS(_c) ((_c)->channelFlags & CHANNEL_HT40MINUS)  enum ath9k_power_mode {  	ATH9K_PM_AWAKE = 0, @@ -483,10 +464,6 @@ struct ath9k_beacon_state {  	u32 bs_intval;  #define ATH9K_TSFOOR_THRESHOLD    0x00004240 /* 16k us */  	u32 bs_dtimperiod; -	u16 bs_cfpperiod; -	u16 bs_cfpmaxduration; -	u32 bs_cfpnext; -	u16 bs_timoffset;  	u16 bs_bmissthreshold;  	u32 bs_sleepduration;  	u32 bs_tsfoor_threshold; @@ -522,12 +499,6 @@ struct ath9k_hw_version {  #define AR_GENTMR_BIT(_index)	(1 << (_index)) -/* - * Using de Bruijin sequence to look up 1's index in a 32 bit number - * debruijn32 = 0000 0111 0111 1100 1011 0101 0011 0001 - */ -#define debruijn32 0x077CB531U -  struct ath_gen_timer_configuration {  	u32 next_addr;  	u32 period_addr; @@ -543,12 +514,8 @@ struct ath_gen_timer {  };  struct ath_gen_timer_table { -	u32 gen_timer_index[32];  	struct ath_gen_timer *timers[ATH_MAX_GEN_TIMER]; -	union { -		unsigned long timer_bits; -		u16 val; -	} timer_mask; +	u16 timer_mask;  };  struct ath_hw_antcomb_conf { @@ -558,6 +525,7 @@ struct ath_hw_antcomb_conf {  	u8 main_gaintb;  	u8 alt_gaintb;  	int lna1_lna2_delta; +	int lna1_lna2_switch_delta;  	u8 div_group;  }; @@ -618,6 +586,10 @@ struct ath_hw_radar_conf {   *	register settings through the register initialization.   */  struct ath_hw_private_ops { +	void (*init_hang_checks)(struct ath_hw *ah); +	bool (*detect_mac_hang)(struct ath_hw *ah); +	bool (*detect_bb_hang)(struct ath_hw *ah); +  	/* Calibration ops */  	void (*init_cal_settings)(struct ath_hw *ah);  	bool (*init_cal)(struct ath_hw *ah, struct ath9k_channel *chan); @@ -712,7 +684,8 @@ struct ath_hw_ops {  			  struct ath9k_channel *chan,  			  u8 rxchainmask,  			  bool longcal); -	bool (*get_isr)(struct ath_hw *ah, enum ath9k_int *masked); +	bool (*get_isr)(struct ath_hw *ah, enum ath9k_int *masked, +			u32 *sync_cause_p);  	void (*set_txdesc)(struct ath_hw *ah, void *ds,  			   struct ath_tx_info *i);  	int (*proc_txdesc)(struct ath_hw *ah, void *ds, @@ -726,6 +699,10 @@ struct ath_hw_ops {  	void (*spectral_scan_trigger)(struct ath_hw *ah);  	void (*spectral_scan_wait)(struct ath_hw *ah); +	void (*tx99_start)(struct ath_hw *ah, u32 qnum); +	void (*tx99_stop)(struct ath_hw *ah); +	void (*tx99_set_txpower)(struct ath_hw *ah, u8 power); +  #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT  	void (*set_bt_ant_diversity)(struct ath_hw *hw, bool enable);  #endif @@ -804,7 +781,6 @@ struct ath_hw {  	u32 txurn_interrupt_mask;  	atomic_t intr_ref_cnt;  	bool chip_fullsleep; -	u32 atim_window;  	u32 modes_index;  	/* Calibration */ @@ -883,6 +859,7 @@ struct ath_hw {  	u32 gpio_mask;  	u32 gpio_val; +	struct ar5416IniArray ini_dfs;  	struct ar5416IniArray iniModes;  	struct ar5416IniArray iniCommon;  	struct ar5416IniArray iniBB_RfGain; @@ -939,7 +916,7 @@ struct ath_hw {  	/* Enterprise mode cap */  	u32 ent_mode; -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_ATH9K_WOW  	u32 wow_event_mask;  #endif  	bool is_clk_25mhz; @@ -1026,21 +1003,15 @@ void ath9k_hw_reset_tsf(struct ath_hw *ah);  void ath9k_hw_set_tsfadjust(struct ath_hw *ah, bool set);  void ath9k_hw_init_global_settings(struct ath_hw *ah);  u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah); -void ath9k_hw_set11nmac2040(struct ath_hw *ah); +void ath9k_hw_set11nmac2040(struct ath_hw *ah, struct ath9k_channel *chan);  void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period);  void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,  				    const struct ath9k_beacon_state *bs); +void ath9k_hw_check_nav(struct ath_hw *ah);  bool ath9k_hw_check_alive(struct ath_hw *ah);  bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode); -#ifdef CONFIG_ATH9K_DEBUGFS -void ath9k_debug_sync_cause(struct ath_common *common, u32 sync_cause); -#else -static inline void ath9k_debug_sync_cause(struct ath_common *common, -					  u32 sync_cause) {} -#endif -  /* Generic hw timer primitives */  struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,  					  void (*trigger)(void *), @@ -1075,6 +1046,7 @@ void ar9002_hw_enable_async_fifo(struct ath_hw *ah);   * Code specific to AR9003, we stuff these here to avoid callbacks   * for older families   */ +bool ar9003_hw_bb_watchdog_check(struct ath_hw *ah);  void ar9003_hw_bb_watchdog_config(struct ath_hw *ah);  void ar9003_hw_bb_watchdog_read(struct ath_hw *ah);  void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah); @@ -1144,7 +1116,7 @@ ath9k_hw_get_btcoex_scheme(struct ath_hw *ah)  #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_ATH9K_WOW  const char *ath9k_hw_wow_event_to_string(u32 wow_event);  void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern,  				u8 *user_mask, int pattern_count, diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 9a1f349f926..0246b990fe8 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -57,112 +57,15 @@ static int ath9k_bt_ant_diversity;  module_param_named(bt_ant_diversity, ath9k_bt_ant_diversity, int, 0444);  MODULE_PARM_DESC(bt_ant_diversity, "Enable WLAN/BT RX antenna diversity"); -bool is_ath9k_unloaded; -/* We use the hw_value as an index into our private channel structure */ - -#define CHAN2G(_freq, _idx)  { \ -	.band = IEEE80211_BAND_2GHZ, \ -	.center_freq = (_freq), \ -	.hw_value = (_idx), \ -	.max_power = 20, \ -} - -#define CHAN5G(_freq, _idx) { \ -	.band = IEEE80211_BAND_5GHZ, \ -	.center_freq = (_freq), \ -	.hw_value = (_idx), \ -	.max_power = 20, \ -} - -/* Some 2 GHz radios are actually tunable on 2312-2732 - * on 5 MHz steps, we support the channels which we know - * we have calibration data for all cards though to make - * this static */ -static const struct ieee80211_channel ath9k_2ghz_chantable[] = { -	CHAN2G(2412, 0), /* Channel 1 */ -	CHAN2G(2417, 1), /* Channel 2 */ -	CHAN2G(2422, 2), /* Channel 3 */ -	CHAN2G(2427, 3), /* Channel 4 */ -	CHAN2G(2432, 4), /* Channel 5 */ -	CHAN2G(2437, 5), /* Channel 6 */ -	CHAN2G(2442, 6), /* Channel 7 */ -	CHAN2G(2447, 7), /* Channel 8 */ -	CHAN2G(2452, 8), /* Channel 9 */ -	CHAN2G(2457, 9), /* Channel 10 */ -	CHAN2G(2462, 10), /* Channel 11 */ -	CHAN2G(2467, 11), /* Channel 12 */ -	CHAN2G(2472, 12), /* Channel 13 */ -	CHAN2G(2484, 13), /* Channel 14 */ -}; +static int ath9k_ps_enable; +module_param_named(ps_enable, ath9k_ps_enable, int, 0444); +MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); -/* Some 5 GHz radios are actually tunable on XXXX-YYYY - * on 5 MHz steps, we support the channels which we know - * we have calibration data for all cards though to make - * this static */ -static const struct ieee80211_channel ath9k_5ghz_chantable[] = { -	/* _We_ call this UNII 1 */ -	CHAN5G(5180, 14), /* Channel 36 */ -	CHAN5G(5200, 15), /* Channel 40 */ -	CHAN5G(5220, 16), /* Channel 44 */ -	CHAN5G(5240, 17), /* Channel 48 */ -	/* _We_ call this UNII 2 */ -	CHAN5G(5260, 18), /* Channel 52 */ -	CHAN5G(5280, 19), /* Channel 56 */ -	CHAN5G(5300, 20), /* Channel 60 */ -	CHAN5G(5320, 21), /* Channel 64 */ -	/* _We_ call this "Middle band" */ -	CHAN5G(5500, 22), /* Channel 100 */ -	CHAN5G(5520, 23), /* Channel 104 */ -	CHAN5G(5540, 24), /* Channel 108 */ -	CHAN5G(5560, 25), /* Channel 112 */ -	CHAN5G(5580, 26), /* Channel 116 */ -	CHAN5G(5600, 27), /* Channel 120 */ -	CHAN5G(5620, 28), /* Channel 124 */ -	CHAN5G(5640, 29), /* Channel 128 */ -	CHAN5G(5660, 30), /* Channel 132 */ -	CHAN5G(5680, 31), /* Channel 136 */ -	CHAN5G(5700, 32), /* Channel 140 */ -	/* _We_ call this UNII 3 */ -	CHAN5G(5745, 33), /* Channel 149 */ -	CHAN5G(5765, 34), /* Channel 153 */ -	CHAN5G(5785, 35), /* Channel 157 */ -	CHAN5G(5805, 36), /* Channel 161 */ -	CHAN5G(5825, 37), /* Channel 165 */ -}; +static int ath9k_use_chanctx; +module_param_named(use_chanctx, ath9k_use_chanctx, int, 0444); +MODULE_PARM_DESC(use_chanctx, "Enable channel context for concurrency"); -/* Atheros hardware rate code addition for short premble */ -#define SHPCHECK(__hw_rate, __flags) \ -	((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0) - -#define RATE(_bitrate, _hw_rate, _flags) {              \ -	.bitrate        = (_bitrate),                   \ -	.flags          = (_flags),                     \ -	.hw_value       = (_hw_rate),                   \ -	.hw_value_short = (SHPCHECK(_hw_rate, _flags))  \ -} - -static struct ieee80211_rate ath9k_legacy_rates[] = { -	RATE(10, 0x1b, 0), -	RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), -	RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), -	RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), -	RATE(60, 0x0b, (IEEE80211_RATE_SUPPORTS_5MHZ | -			IEEE80211_RATE_SUPPORTS_10MHZ)), -	RATE(90, 0x0f, (IEEE80211_RATE_SUPPORTS_5MHZ | -			IEEE80211_RATE_SUPPORTS_10MHZ)), -	RATE(120, 0x0a, (IEEE80211_RATE_SUPPORTS_5MHZ | -			 IEEE80211_RATE_SUPPORTS_10MHZ)), -	RATE(180, 0x0e, (IEEE80211_RATE_SUPPORTS_5MHZ | -			 IEEE80211_RATE_SUPPORTS_10MHZ)), -	RATE(240, 0x09, (IEEE80211_RATE_SUPPORTS_5MHZ | -			 IEEE80211_RATE_SUPPORTS_10MHZ)), -	RATE(360, 0x0d, (IEEE80211_RATE_SUPPORTS_5MHZ | -			 IEEE80211_RATE_SUPPORTS_10MHZ)), -	RATE(480, 0x08, (IEEE80211_RATE_SUPPORTS_5MHZ | -			 IEEE80211_RATE_SUPPORTS_10MHZ)), -	RATE(540, 0x0c, (IEEE80211_RATE_SUPPORTS_5MHZ | -			 IEEE80211_RATE_SUPPORTS_10MHZ)), -}; +bool is_ath9k_unloaded;  #ifdef CONFIG_MAC80211_LEDS  static const struct ieee80211_tpt_blink ath9k_tpt_blink[] = { @@ -254,64 +157,6 @@ static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 cl  /*     Initialization     */  /**************************/ -static void setup_ht_cap(struct ath_softc *sc, -			 struct ieee80211_sta_ht_cap *ht_info) -{ -	struct ath_hw *ah = sc->sc_ah; -	struct ath_common *common = ath9k_hw_common(ah); -	u8 tx_streams, rx_streams; -	int i, max_streams; - -	ht_info->ht_supported = true; -	ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | -		       IEEE80211_HT_CAP_SM_PS | -		       IEEE80211_HT_CAP_SGI_40 | -		       IEEE80211_HT_CAP_DSSSCCK40; - -	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_LDPC) -		ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; - -	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20) -		ht_info->cap |= IEEE80211_HT_CAP_SGI_20; - -	ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; -	ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; - -	if (AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah)) -		max_streams = 1; -	else if (AR_SREV_9462(ah)) -		max_streams = 2; -	else if (AR_SREV_9300_20_OR_LATER(ah)) -		max_streams = 3; -	else -		max_streams = 2; - -	if (AR_SREV_9280_20_OR_LATER(ah)) { -		if (max_streams >= 2) -			ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; -		ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); -	} - -	/* set up supported mcs set */ -	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); -	tx_streams = ath9k_cmn_count_streams(ah->txchainmask, max_streams); -	rx_streams = ath9k_cmn_count_streams(ah->rxchainmask, max_streams); - -	ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n", -		tx_streams, rx_streams); - -	if (tx_streams != rx_streams) { -		ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; -		ht_info->mcs.tx_params |= ((tx_streams - 1) << -				IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); -	} - -	for (i = 0; i < rx_streams; i++) -		ht_info->mcs.rx_mask[i] = 0xff; - -	ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; -} -  static void ath9k_reg_notifier(struct wiphy *wiphy,  			       struct regulatory_request *request)  { @@ -347,7 +192,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,  {  	struct ath_common *common = ath9k_hw_common(sc->sc_ah);  	u8 *ds; -	struct ath_buf *bf;  	int i, bsize, desc_len;  	ath_dbg(common, CONFIG, "%s DMA: %u buffers %u desc/buf\n", @@ -399,33 +243,68 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,  		ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);  	/* allocate buffers */ -	bsize = sizeof(struct ath_buf) * nbuf; -	bf = devm_kzalloc(sc->dev, bsize, GFP_KERNEL); -	if (!bf) -		return -ENOMEM; +	if (is_tx) { +		struct ath_buf *bf; + +		bsize = sizeof(struct ath_buf) * nbuf; +		bf = devm_kzalloc(sc->dev, bsize, GFP_KERNEL); +		if (!bf) +			return -ENOMEM; + +		for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) { +			bf->bf_desc = ds; +			bf->bf_daddr = DS2PHYS(dd, ds); + +			if (!(sc->sc_ah->caps.hw_caps & +				  ATH9K_HW_CAP_4KB_SPLITTRANS)) { +				/* +				 * Skip descriptor addresses which can cause 4KB +				 * boundary crossing (addr + length) with a 32 dword +				 * descriptor fetch. +				 */ +				while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { +					BUG_ON((caddr_t) bf->bf_desc >= +						   ((caddr_t) dd->dd_desc + +						dd->dd_desc_len)); + +					ds += (desc_len * ndesc); +					bf->bf_desc = ds; +					bf->bf_daddr = DS2PHYS(dd, ds); +				} +			} +			list_add_tail(&bf->list, head); +		} +	} else { +		struct ath_rxbuf *bf; + +		bsize = sizeof(struct ath_rxbuf) * nbuf; +		bf = devm_kzalloc(sc->dev, bsize, GFP_KERNEL); +		if (!bf) +			return -ENOMEM; -	for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) { -		bf->bf_desc = ds; -		bf->bf_daddr = DS2PHYS(dd, ds); - -		if (!(sc->sc_ah->caps.hw_caps & -		      ATH9K_HW_CAP_4KB_SPLITTRANS)) { -			/* -			 * Skip descriptor addresses which can cause 4KB -			 * boundary crossing (addr + length) with a 32 dword -			 * descriptor fetch. -			 */ -			while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { -				BUG_ON((caddr_t) bf->bf_desc >= -				       ((caddr_t) dd->dd_desc + -					dd->dd_desc_len)); - -				ds += (desc_len * ndesc); -				bf->bf_desc = ds; -				bf->bf_daddr = DS2PHYS(dd, ds); +		for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) { +			bf->bf_desc = ds; +			bf->bf_daddr = DS2PHYS(dd, ds); + +			if (!(sc->sc_ah->caps.hw_caps & +				  ATH9K_HW_CAP_4KB_SPLITTRANS)) { +				/* +				 * Skip descriptor addresses which can cause 4KB +				 * boundary crossing (addr + length) with a 32 dword +				 * descriptor fetch. +				 */ +				while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { +					BUG_ON((caddr_t) bf->bf_desc >= +						   ((caddr_t) dd->dd_desc + +						dd->dd_desc_len)); + +					ds += (desc_len * ndesc); +					bf->bf_desc = ds; +					bf->bf_daddr = DS2PHYS(dd, ds); +				}  			} +			list_add_tail(&bf->list, head);  		} -		list_add_tail(&bf->list, head);  	}  	return 0;  } @@ -436,8 +315,6 @@ static int ath9k_init_queues(struct ath_softc *sc)  	sc->beacon.beaconq = ath9k_hw_beaconq_setup(sc->sc_ah);  	sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); - -	sc->config.cabqReadytime = ATH_CABQ_READY_TIME;  	ath_cabq_update(sc);  	sc->tx.uapsdq = ath_txq_setup(sc, ATH9K_TX_QUEUE_UAPSD, 0); @@ -450,51 +327,6 @@ static int ath9k_init_queues(struct ath_softc *sc)  	return 0;  } -static int ath9k_init_channels_rates(struct ath_softc *sc) -{ -	void *channels; - -	BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) + -		     ARRAY_SIZE(ath9k_5ghz_chantable) != -		     ATH9K_NUM_CHANNELS); - -	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) { -		channels = devm_kzalloc(sc->dev, -			sizeof(ath9k_2ghz_chantable), GFP_KERNEL); -		if (!channels) -		    return -ENOMEM; - -		memcpy(channels, ath9k_2ghz_chantable, -		       sizeof(ath9k_2ghz_chantable)); -		sc->sbands[IEEE80211_BAND_2GHZ].channels = channels; -		sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; -		sc->sbands[IEEE80211_BAND_2GHZ].n_channels = -			ARRAY_SIZE(ath9k_2ghz_chantable); -		sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; -		sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates = -			ARRAY_SIZE(ath9k_legacy_rates); -	} - -	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) { -		channels = devm_kzalloc(sc->dev, -			sizeof(ath9k_5ghz_chantable), GFP_KERNEL); -		if (!channels) -			return -ENOMEM; - -		memcpy(channels, ath9k_5ghz_chantable, -		       sizeof(ath9k_5ghz_chantable)); -		sc->sbands[IEEE80211_BAND_5GHZ].channels = channels; -		sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; -		sc->sbands[IEEE80211_BAND_5GHZ].n_channels = -			ARRAY_SIZE(ath9k_5ghz_chantable); -		sc->sbands[IEEE80211_BAND_5GHZ].bitrates = -			ath9k_legacy_rates + 4; -		sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates = -			ARRAY_SIZE(ath9k_legacy_rates) - 4; -	} -	return 0; -} -  static void ath9k_init_misc(struct ath_softc *sc)  {  	struct ath_common *common = ath9k_hw_common(sc->sc_ah); @@ -502,7 +334,7 @@ static void ath9k_init_misc(struct ath_softc *sc)  	setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc); -	sc->last_rssi = ATH_RSSI_DUMMY_MARKER; +	common->last_rssi = ATH_RSSI_DUMMY_MARKER;  	sc->config.txpowlimit = ATH_TXPOWER_MAX;  	memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);  	sc->beacon.slottime = ATH9K_SLOT_TIME_9; @@ -521,7 +353,7 @@ static void ath9k_init_misc(struct ath_softc *sc)  	sc->spec_config.fft_period = 0xF;  } -static void ath9k_init_platform(struct ath_softc *sc) +static void ath9k_init_pcoem_platform(struct ath_softc *sc)  {  	struct ath_hw *ah = sc->sc_ah;  	struct ath9k_hw_capabilities *pCap = &ah->caps; @@ -547,6 +379,29 @@ static void ath9k_init_platform(struct ath_softc *sc)  	if (sc->driver_data & ATH9K_PCI_CUS217)  		ath_info(common, "CUS217 card detected\n"); +	if (sc->driver_data & ATH9K_PCI_CUS252) +		ath_info(common, "CUS252 card detected\n"); + +	if (sc->driver_data & ATH9K_PCI_AR9565_1ANT) +		ath_info(common, "WB335 1-ANT card detected\n"); + +	if (sc->driver_data & ATH9K_PCI_AR9565_2ANT) +		ath_info(common, "WB335 2-ANT card detected\n"); + +	if (sc->driver_data & ATH9K_PCI_KILLER) +		ath_info(common, "Killer Wireless card detected\n"); + +	/* +	 * Some WB335 cards do not support antenna diversity. Since +	 * we use a hardcoded value for AR9565 instead of using the +	 * EEPROM/OTP data, remove the combining feature from +	 * the HW capabilities bitmap. +	 */ +	if (sc->driver_data & (ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_AR9565_2ANT)) { +		if (!(sc->driver_data & ATH9K_PCI_BT_ANT_DIV)) +			pCap->hw_caps &= ~ATH9K_HW_CAP_ANT_DIV_COMB; +	} +  	if (sc->driver_data & ATH9K_PCI_BT_ANT_DIV) {  		pCap->hw_caps |= ATH9K_HW_CAP_BT_ANT_DIV;  		ath_info(common, "Set BT/WLAN RX diversity capability\n"); @@ -556,6 +411,11 @@ static void ath9k_init_platform(struct ath_softc *sc)  		ah->config.pcie_waen = 0x0040473b;  		ath_info(common, "Enable WAR for ASPM D3/L1\n");  	} + +	if (sc->driver_data & ATH9K_PCI_NO_PLL_PWRSAVE) { +		ah->config.no_pll_pwrsave = true; +		ath_info(common, "Disable PLL PowerSave\n"); +	}  }  static void ath9k_eeprom_request_cb(const struct firmware *eeprom_blob, @@ -603,6 +463,27 @@ static void ath9k_eeprom_release(struct ath_softc *sc)  	release_firmware(sc->sc_ah->eeprom_blob);  } +static int ath9k_init_soc_platform(struct ath_softc *sc) +{ +	struct ath9k_platform_data *pdata = sc->dev->platform_data; +	struct ath_hw *ah = sc->sc_ah; +	int ret = 0; + +	if (!pdata) +		return 0; + +	if (pdata->eeprom_name) { +		ret = ath9k_eeprom_request(sc, pdata->eeprom_name); +		if (ret) +			return ret; +	} + +	if (pdata->tx_gain_buffalo) +		ah->config.tx_gain_buffalo = true; + +	return ret; +} +  static int ath9k_init_softc(u16 devid, struct ath_softc *sc,  			    const struct ath_bus_ops *bus_ops)  { @@ -623,13 +504,15 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,  	ah->reg_ops.read = ath9k_ioread32;  	ah->reg_ops.write = ath9k_iowrite32;  	ah->reg_ops.rmw = ath9k_reg_rmw; -	atomic_set(&ah->intr_ref_cnt, -1);  	sc->sc_ah = ah;  	pCap = &ah->caps; -	sc->dfs_detector = dfs_pattern_detector_init(ah, NL80211_DFS_UNSET); +	common = ath9k_hw_common(ah); +	sc->dfs_detector = dfs_pattern_detector_init(common, NL80211_DFS_UNSET); +	sc->tx99_power = MAX_RATE_POWER + 1; +	init_waitqueue_head(&sc->tx_wait); -	if (!pdata) { +	if (!pdata || pdata->use_eeprom) {  		ah->ah_flags |= AH_USE_EEPROM;  		sc->sc_ah->led_pin = -1;  	} else { @@ -641,7 +524,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,  		ah->external_reset = pdata->external_reset;  	} -	common = ath9k_hw_common(ah);  	common->ops = &ah->reg_ops;  	common->bus_ops = bus_ops;  	common->ah = ah; @@ -654,7 +536,11 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,  	/*  	 * Platform quirks.  	 */ -	ath9k_init_platform(sc); +	ath9k_init_pcoem_platform(sc); + +	ret = ath9k_init_soc_platform(sc); +	if (ret) +		return ret;  	/*  	 * Enable WLAN/BT RX Antenna diversity only when: @@ -668,7 +554,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,  		common->bt_ant_diversity = 1;  	spin_lock_init(&common->cc_lock); -  	spin_lock_init(&sc->sc_serial_rw);  	spin_lock_init(&sc->sc_pm_lock);  	mutex_init(&sc->mutex); @@ -676,11 +561,10 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,  	tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,  		     (unsigned long)sc); +	setup_timer(&sc->sleep_timer, ath_ps_full_sleep, (unsigned long)sc);  	INIT_WORK(&sc->hw_reset_work, ath_reset_work); -	INIT_WORK(&sc->hw_check_work, ath_hw_check);  	INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);  	INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); -	setup_timer(&sc->rx_poll_timer, ath_rx_poll, (unsigned long)sc);  	/*  	 * Cache line size is used to size and align various @@ -689,12 +573,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,  	ath_read_cachesize(common, &csz);  	common->cachelsz = csz << 2; /* convert to bytes */ -	if (pdata && pdata->eeprom_name) { -		ret = ath9k_eeprom_request(sc, pdata->eeprom_name); -		if (ret) -			return ret; -	} -  	/* Initializes the hardware for all supported chipsets */  	ret = ath9k_hw_init(ah);  	if (ret) @@ -711,10 +589,13 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,  	if (ret)  		goto err_btcoex; -	ret = ath9k_init_channels_rates(sc); +	ret = ath9k_cmn_init_channels_rates(common);  	if (ret)  		goto err_btcoex; +	sc->p2p_ps_timer = ath_gen_timer_alloc(sc->sc_ah, ath9k_p2p_ps_timer, +		NULL, sc, AR_FIRST_NDP_TIMER); +  	ath9k_cmn_init_crypto(sc->sc_ah);  	ath9k_init_misc(sc);  	ath_fill_led_pin(sc); @@ -732,6 +613,7 @@ err_queues:  	ath9k_hw_deinit(ah);  err_hw:  	ath9k_eeprom_release(sc); +	dev_kfree_skb_any(sc->tx99_skb);  	return ret;  } @@ -740,15 +622,16 @@ static void ath9k_init_band_txpower(struct ath_softc *sc, int band)  	struct ieee80211_supported_band *sband;  	struct ieee80211_channel *chan;  	struct ath_hw *ah = sc->sc_ah; +	struct ath_common *common = ath9k_hw_common(ah);  	struct cfg80211_chan_def chandef;  	int i; -	sband = &sc->sbands[band]; +	sband = &common->sbands[band];  	for (i = 0; i < sband->n_channels; i++) {  		chan = &sband->channels[i];  		ah->curchan = &ah->channels[chan->hw_value];  		cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20); -		ath9k_cmn_update_ichannel(ah->curchan, &chandef); +		ath9k_cmn_get_channel(sc->hw, ah, &chandef);  		ath9k_hw_set_txpowerlimit(ah, MAX_RATE_POWER, true);  	}  } @@ -766,32 +649,27 @@ static void ath9k_init_txpower_limits(struct ath_softc *sc)  	ah->curchan = curchan;  } -void ath9k_reload_chainmask_settings(struct ath_softc *sc) -{ -	if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)) -		return; - -	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) -		setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); -	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) -		setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); -} -  static const struct ieee80211_iface_limit if_limits[] = { -	{ .max = 2048,	.types = BIT(NL80211_IFTYPE_STATION) | -				 BIT(NL80211_IFTYPE_P2P_CLIENT) | -				 BIT(NL80211_IFTYPE_WDS) }, +	{ .max = 2048,	.types = BIT(NL80211_IFTYPE_STATION) },  	{ .max = 8,	.types =  #ifdef CONFIG_MAC80211_MESH  				 BIT(NL80211_IFTYPE_MESH_POINT) |  #endif -				 BIT(NL80211_IFTYPE_AP) | +				 BIT(NL80211_IFTYPE_AP) }, +	{ .max = 1,	.types = BIT(NL80211_IFTYPE_P2P_CLIENT) |  				 BIT(NL80211_IFTYPE_P2P_GO) },  }; +static const struct ieee80211_iface_limit wds_limits[] = { +	{ .max = 2048,	.types = BIT(NL80211_IFTYPE_WDS) }, +};  static const struct ieee80211_iface_limit if_dfs_limits[] = { -	{ .max = 1,	.types = BIT(NL80211_IFTYPE_AP) }, +	{ .max = 1,	.types = BIT(NL80211_IFTYPE_AP) | +#ifdef CONFIG_MAC80211_MESH +				 BIT(NL80211_IFTYPE_MESH_POINT) | +#endif +				 BIT(NL80211_IFTYPE_ADHOC) },  };  static const struct ieee80211_iface_combination if_comb[] = { @@ -803,26 +681,26 @@ static const struct ieee80211_iface_combination if_comb[] = {  		.beacon_int_infra_match = true,  	},  	{ +		.limits = wds_limits, +		.n_limits = ARRAY_SIZE(wds_limits), +		.max_interfaces = 2048, +		.num_different_channels = 1, +		.beacon_int_infra_match = true, +	}, +#ifdef CONFIG_ATH9K_DFS_CERTIFIED +	{  		.limits = if_dfs_limits,  		.n_limits = ARRAY_SIZE(if_dfs_limits),  		.max_interfaces = 1,  		.num_different_channels = 1,  		.beacon_int_infra_match = true, -		.radar_detect_widths =	BIT(NL80211_CHAN_NO_HT) | -					BIT(NL80211_CHAN_HT20), +		.radar_detect_widths =	BIT(NL80211_CHAN_WIDTH_20_NOHT) | +					BIT(NL80211_CHAN_WIDTH_20),  	} -}; - -#ifdef CONFIG_PM -static const struct wiphy_wowlan_support ath9k_wowlan_support = { -	.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, -	.n_patterns = MAX_NUM_USER_PATTERN, -	.pattern_min_len = 1, -	.pattern_max_len = MAX_PATTERN_SIZE, -};  #endif +}; -void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) +static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)  {  	struct ath_hw *ah = sc->sc_ah;  	struct ath_common *common = ath9k_hw_common(ah); @@ -830,13 +708,15 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)  	hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |  		IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |  		IEEE80211_HW_SIGNAL_DBM | -		IEEE80211_HW_SUPPORTS_PS |  		IEEE80211_HW_PS_NULLFUNC_STACK |  		IEEE80211_HW_SPECTRUM_MGMT |  		IEEE80211_HW_REPORTS_TX_ACK_STATUS |  		IEEE80211_HW_SUPPORTS_RC_TABLE |  		IEEE80211_HW_SUPPORTS_HT_CCK_RATES; +	if (ath9k_ps_enable) +		hw->flags |= IEEE80211_HW_SUPPORTS_PS; +  	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {  		hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; @@ -848,19 +728,24 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)  	if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt)  		hw->flags |= IEEE80211_HW_MFP_CAPABLE; -	hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; - -	hw->wiphy->interface_modes = -		BIT(NL80211_IFTYPE_P2P_GO) | -		BIT(NL80211_IFTYPE_P2P_CLIENT) | -		BIT(NL80211_IFTYPE_AP) | -		BIT(NL80211_IFTYPE_WDS) | -		BIT(NL80211_IFTYPE_STATION) | -		BIT(NL80211_IFTYPE_ADHOC) | -		BIT(NL80211_IFTYPE_MESH_POINT); - -	hw->wiphy->iface_combinations = if_comb; -	hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); +	hw->wiphy->features |= (NL80211_FEATURE_ACTIVE_MONITOR | +				NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE); + +	if (!config_enabled(CONFIG_ATH9K_TX99)) { +		hw->wiphy->interface_modes = +			BIT(NL80211_IFTYPE_P2P_GO) | +			BIT(NL80211_IFTYPE_P2P_CLIENT) | +			BIT(NL80211_IFTYPE_AP) | +			BIT(NL80211_IFTYPE_STATION) | +			BIT(NL80211_IFTYPE_ADHOC) | +			BIT(NL80211_IFTYPE_MESH_POINT); +		hw->wiphy->iface_combinations = if_comb; +		if (!ath9k_use_chanctx) { +			hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); +			hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_WDS); +		} else +			hw->wiphy->n_iface_combinations = 1; +	}  	hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; @@ -869,20 +754,10 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)  	hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;  	hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ;  	hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; - -#ifdef CONFIG_PM_SLEEP -	if ((ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) && -	    (sc->driver_data & ATH9K_PCI_WOW) && -	    device_can_wakeup(sc->dev)) -		hw->wiphy->wowlan = &ath9k_wowlan_support; - -	atomic_set(&sc->wow_sleep_proc_intr, -1); -	atomic_set(&sc->wow_got_bmiss_intr, -1); -#endif +	hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;  	hw->queues = 4;  	hw->max_rates = 4; -	hw->channel_change_time = 5000;  	hw->max_listen_interval = 1;  	hw->max_rate_tries = 10;  	hw->sta_data_size = sizeof(struct ath_node); @@ -900,12 +775,13 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)  	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)  		hw->wiphy->bands[IEEE80211_BAND_2GHZ] = -			&sc->sbands[IEEE80211_BAND_2GHZ]; +			&common->sbands[IEEE80211_BAND_2GHZ];  	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)  		hw->wiphy->bands[IEEE80211_BAND_5GHZ] = -			&sc->sbands[IEEE80211_BAND_5GHZ]; +			&common->sbands[IEEE80211_BAND_5GHZ]; -	ath9k_reload_chainmask_settings(sc); +	ath9k_init_wow(hw); +	ath9k_cmn_reload_chainmask(ah);  	SET_IEEE80211_PERM_ADDR(hw, common->macaddr);  } @@ -928,6 +804,9 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,  	common = ath9k_hw_common(ah);  	ath9k_set_hw_capab(sc, hw); +	/* Will be cleared in ath9k_start() */ +	set_bit(ATH_OP_INVALID, &common->op_flags); +  	/* Initialize regulatory */  	error = ath_regd_init(&common->regulatory, sc->hw->wiphy,  			      ath9k_reg_notifier); @@ -997,12 +876,16 @@ static void ath9k_deinit_softc(struct ath_softc *sc)  {  	int i = 0; +	if (sc->p2p_ps_timer) +		ath_gen_timer_free(sc->sc_ah, sc->p2p_ps_timer); +  	ath9k_deinit_btcoex(sc);  	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)  		if (ATH_TXQ_SETUP(sc, i))  			ath_tx_cleanupq(sc, &sc->tx.txq[i]); +	del_timer_sync(&sc->sleep_timer);  	ath9k_hw_deinit(sc->sc_ah);  	if (sc->dfs_detector != NULL)  		sc->dfs_detector->exit(sc->dfs_detector); @@ -1035,19 +918,11 @@ static int __init ath9k_init(void)  {  	int error; -	/* Register rate control algorithm */ -	error = ath_rate_control_register(); -	if (error != 0) { -		pr_err("Unable to register rate control algorithm: %d\n", -		       error); -		goto err_out; -	} -  	error = ath_pci_init();  	if (error < 0) {  		pr_err("No PCI devices found, driver not installed\n");  		error = -ENODEV; -		goto err_rate_unregister; +		goto err_out;  	}  	error = ath_ahb_init(); @@ -1060,9 +935,6 @@ static int __init ath9k_init(void)   err_pci_exit:  	ath_pci_exit(); - - err_rate_unregister: -	ath_rate_control_unregister();   err_out:  	return error;  } @@ -1073,7 +945,6 @@ static void __exit ath9k_exit(void)  	is_ath9k_unloaded = true;  	ath_ahb_exit();  	ath_pci_exit(); -	ath_rate_control_unregister();  	pr_info("%s: Driver unloaded\n", dev_info);  }  module_exit(ath9k_exit); diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 2f831db396a..72a715fe8f2 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -28,6 +28,13 @@ void ath_tx_complete_poll_work(struct work_struct *work)  	int i;  	bool needreset = false; + +	if (sc->tx99_state) { +		ath_dbg(ath9k_hw_common(sc->sc_ah), RESET, +			"skip tx hung detection on tx99\n"); +		return; +	} +  	for (i = 0; i < IEEE80211_NUM_ACS; i++) {  		txq = sc->tx.txq_map[i]; @@ -58,50 +65,26 @@ void ath_tx_complete_poll_work(struct work_struct *work)  /*   * Checks if the BB/MAC is hung.   */ -void ath_hw_check(struct work_struct *work) +bool ath_hw_check(struct ath_softc *sc)  { -	struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);  	struct ath_common *common = ath9k_hw_common(sc->sc_ah); -	unsigned long flags; -	int busy; -	u8 is_alive, nbeacon = 1;  	enum ath_reset_type type; +	bool is_alive;  	ath9k_ps_wakeup(sc); +  	is_alive = ath9k_hw_check_alive(sc->sc_ah); -	if (is_alive && !AR_SREV_9300(sc->sc_ah)) -		goto out; -	else if (!is_alive && AR_SREV_9300(sc->sc_ah)) { +	if (!is_alive) {  		ath_dbg(common, RESET, -			"DCU stuck is detected. Schedule chip reset\n"); +			"HW hang detected, schedule chip reset\n");  		type = RESET_TYPE_MAC_HANG; -		goto sched_reset; -	} - -	spin_lock_irqsave(&common->cc_lock, flags); -	busy = ath_update_survey_stats(sc); -	spin_unlock_irqrestore(&common->cc_lock, flags); - -	ath_dbg(common, RESET, "Possible baseband hang, busy=%d (try %d)\n", -		busy, sc->hw_busy_count + 1); -	if (busy >= 99) { -		if (++sc->hw_busy_count >= 3) { -			type = RESET_TYPE_BB_HANG; -			goto sched_reset; -		} -	} else if (busy >= 0) { -		sc->hw_busy_count = 0; -		nbeacon = 3; +		ath9k_queue_reset(sc, type);  	} -	ath_start_rx_poll(sc, nbeacon); -	goto out; - -sched_reset: -	ath9k_queue_reset(sc, type); -out:  	ath9k_ps_restore(sc); + +	return is_alive;  }  /* @@ -132,13 +115,17 @@ void ath_hw_pll_work(struct work_struct *work)  	u32 pll_sqsum;  	struct ath_softc *sc = container_of(work, struct ath_softc,  					    hw_pll_work.work); +	struct ath_common *common = ath9k_hw_common(sc->sc_ah);  	/*  	 * ensure that the PLL WAR is executed only  	 * after the STA is associated (or) if the  	 * beaconing had started in interfaces that  	 * uses beacons.  	 */ -	if (!test_bit(SC_OP_BEACONS, &sc->sc_flags)) +	if (!test_bit(ATH_OP_BEACONS, &common->op_flags)) +		return; + +	if (sc->tx99_state)  		return;  	ath9k_ps_wakeup(sc); @@ -152,29 +139,6 @@ void ath_hw_pll_work(struct work_struct *work)  }  /* - * RX Polling - monitors baseband hangs. - */ -void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon) -{ -	if (!AR_SREV_9300(sc->sc_ah)) -		return; - -	if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) -		return; - -	mod_timer(&sc->rx_poll_timer, jiffies + msecs_to_jiffies -		  (nbeacon * sc->cur_beacon_conf.beacon_interval)); -} - -void ath_rx_poll(unsigned long data) -{ -	struct ath_softc *sc = (struct ath_softc *)data; - -	if (!test_bit(SC_OP_INVALID, &sc->sc_flags)) -		ieee80211_queue_work(sc->hw, &sc->hw_check_work); -} - -/*   * PA Pre-distortion.   */  static void ath_paprd_activate(struct ath_softc *sc) @@ -184,7 +148,7 @@ static void ath_paprd_activate(struct ath_softc *sc)  	struct ath9k_hw_cal_data *caldata = ah->caldata;  	int chain; -	if (!caldata || !caldata->paprd_done) { +	if (!caldata || !test_bit(PAPRD_DONE, &caldata->cal_flags)) {  		ath_dbg(common, CALIBRATE, "Failed to activate PAPRD\n");  		return;  	} @@ -256,7 +220,9 @@ void ath_paprd_calibrate(struct work_struct *work)  	int len = 1800;  	int ret; -	if (!caldata || !caldata->paprd_packet_sent || caldata->paprd_done) { +	if (!caldata || +	    !test_bit(PAPRD_PACKET_SENT, &caldata->cal_flags) || +	    test_bit(PAPRD_DONE, &caldata->cal_flags)) {  		ath_dbg(common, CALIBRATE, "Skipping PAPRD calibration\n");  		return;  	} @@ -316,7 +282,7 @@ void ath_paprd_calibrate(struct work_struct *work)  	kfree_skb(skb);  	if (chain_ok) { -		caldata->paprd_done = true; +		set_bit(PAPRD_DONE, &caldata->cal_flags);  		ath_paprd_activate(sc);  	} @@ -343,7 +309,7 @@ void ath_ani_calibrate(unsigned long data)  	u32 cal_interval, short_cal_interval, long_cal_interval;  	unsigned long flags; -	if (ah->caldata && ah->caldata->nfcal_interference) +	if (ah->caldata && test_bit(NFCAL_INTF, &ah->caldata->cal_flags))  		long_cal_interval = ATH_LONG_CALINTERVAL_INT;  	else  		long_cal_interval = ATH_LONG_CALINTERVAL; @@ -397,10 +363,10 @@ void ath_ani_calibrate(unsigned long data)  	/* Call ANI routine if necessary */  	if (aniflag) { -		spin_lock_irqsave(&common->cc_lock, flags); +		spin_lock(&common->cc_lock);  		ath9k_hw_ani_monitor(ah, ah->curchan);  		ath_update_survey_stats(sc); -		spin_unlock_irqrestore(&common->cc_lock, flags); +		spin_unlock(&common->cc_lock);  	}  	/* Perform calibration if necessary */ @@ -432,7 +398,7 @@ set_timer:  	mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval));  	if (ar9003_is_paprd_enabled(ah) && ah->caldata) { -		if (!ah->caldata->paprd_done) { +		if (!test_bit(PAPRD_DONE, &ah->caldata->cal_flags)) {  			ieee80211_queue_work(sc->hw, &sc->paprd_work);  		} else if (!ah->paprd_table_write_done) {  			ath9k_ps_wakeup(sc); @@ -449,7 +415,7 @@ void ath_start_ani(struct ath_softc *sc)  	unsigned long timestamp = jiffies_to_msecs(jiffies);  	if (common->disable_ani || -	    !test_bit(SC_OP_ANI_RUN, &sc->sc_flags) || +	    !test_bit(ATH_OP_ANI_RUN, &common->op_flags) ||  	    (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))  		return; @@ -473,6 +439,7 @@ void ath_stop_ani(struct ath_softc *sc)  void ath_check_ani(struct ath_softc *sc)  {  	struct ath_hw *ah = sc->sc_ah; +	struct ath_common *common = ath9k_hw_common(sc->sc_ah);  	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;  	/* @@ -488,23 +455,23 @@ void ath_check_ani(struct ath_softc *sc)  			 * Disable ANI only when there are no  			 * associated stations.  			 */ -			if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) +			if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags))  				goto stop_ani;  		}  	} else if (ah->opmode == NL80211_IFTYPE_STATION) { -		if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) +		if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags))  			goto stop_ani;  	} -	if (!test_bit(SC_OP_ANI_RUN, &sc->sc_flags)) { -		set_bit(SC_OP_ANI_RUN, &sc->sc_flags); +	if (!test_bit(ATH_OP_ANI_RUN, &common->op_flags)) { +		set_bit(ATH_OP_ANI_RUN, &common->op_flags);  		ath_start_ani(sc);  	}  	return;  stop_ani: -	clear_bit(SC_OP_ANI_RUN, &sc->sc_flags); +	clear_bit(ATH_OP_ANI_RUN, &common->op_flags);  	ath_stop_ani(sc);  } @@ -516,7 +483,8 @@ void ath_update_survey_nf(struct ath_softc *sc, int channel)  	if (chan->noisefloor) {  		survey->filled |= SURVEY_INFO_NOISE_DBM; -		survey->noise = ath9k_hw_getchan_noise(ah, chan); +		survey->noise = ath9k_hw_getchan_noise(ah, chan, +						       chan->noisefloor);  	}  } diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index a3eff0986a3..275205ab5f1 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -374,7 +374,6 @@ EXPORT_SYMBOL(ath9k_hw_releasetxqueue);  bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)  {  	struct ath_common *common = ath9k_hw_common(ah); -	struct ath9k_channel *chan = ah->curchan;  	struct ath9k_tx_queue_info *qi;  	u32 cwMin, chanCwMin, value; @@ -387,10 +386,7 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)  	ath_dbg(common, QUEUE, "Reset TX queue: %u\n", q);  	if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) { -		if (chan && IS_CHAN_B(chan)) -			chanCwMin = INIT_CWMIN_11B; -		else -			chanCwMin = INIT_CWMIN; +		chanCwMin = INIT_CWMIN;  		for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1);  	} else @@ -485,8 +481,7 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)  			    | AR_Q_MISC_CBR_INCR_DIS0);  		value = (qi->tqi_readyTime -  			 (ah->config.sw_beacon_response_time - -			  ah->config.dma_beacon_response_time) - -			 ah->config.additional_swba_backoff) * 1024; +			  ah->config.dma_beacon_response_time)) * 1024;  		REG_WRITE(ah, AR_QRDYTIMECFG(q),  			  value | AR_Q_RDYTIMECFG_EN);  		REG_SET_BIT(ah, AR_DMISC(q), @@ -554,25 +549,25 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,  	if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) {  		rs->rs_rssi = ATH9K_RSSI_BAD; -		rs->rs_rssi_ctl0 = ATH9K_RSSI_BAD; -		rs->rs_rssi_ctl1 = ATH9K_RSSI_BAD; -		rs->rs_rssi_ctl2 = ATH9K_RSSI_BAD; -		rs->rs_rssi_ext0 = ATH9K_RSSI_BAD; -		rs->rs_rssi_ext1 = ATH9K_RSSI_BAD; -		rs->rs_rssi_ext2 = ATH9K_RSSI_BAD; +		rs->rs_rssi_ctl[0] = ATH9K_RSSI_BAD; +		rs->rs_rssi_ctl[1] = ATH9K_RSSI_BAD; +		rs->rs_rssi_ctl[2] = ATH9K_RSSI_BAD; +		rs->rs_rssi_ext[0] = ATH9K_RSSI_BAD; +		rs->rs_rssi_ext[1] = ATH9K_RSSI_BAD; +		rs->rs_rssi_ext[2] = ATH9K_RSSI_BAD;  	} else {  		rs->rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined); -		rs->rs_rssi_ctl0 = MS(ads.ds_rxstatus0, +		rs->rs_rssi_ctl[0] = MS(ads.ds_rxstatus0,  						AR_RxRSSIAnt00); -		rs->rs_rssi_ctl1 = MS(ads.ds_rxstatus0, +		rs->rs_rssi_ctl[1] = MS(ads.ds_rxstatus0,  						AR_RxRSSIAnt01); -		rs->rs_rssi_ctl2 = MS(ads.ds_rxstatus0, +		rs->rs_rssi_ctl[2] = MS(ads.ds_rxstatus0,  						AR_RxRSSIAnt02); -		rs->rs_rssi_ext0 = MS(ads.ds_rxstatus4, +		rs->rs_rssi_ext[0] = MS(ads.ds_rxstatus4,  						AR_RxRSSIAnt10); -		rs->rs_rssi_ext1 = MS(ads.ds_rxstatus4, +		rs->rs_rssi_ext[1] = MS(ads.ds_rxstatus4,  						AR_RxRSSIAnt11); -		rs->rs_rssi_ext2 = MS(ads.ds_rxstatus4, +		rs->rs_rssi_ext[2] = MS(ads.ds_rxstatus4,  						AR_RxRSSIAnt12);  	}  	if (ads.ds_rxstatus8 & AR_RxKeyIdxValid) @@ -832,7 +827,7 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah)  		return;  	} -	if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) +	if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah))  		sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;  	async_mask = AR_INTR_MAC_IRQ; @@ -927,11 +922,29 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah)  			mask2 |= AR_IMR_S2_CST;  	} +	if (ah->config.hw_hang_checks & HW_BB_WATCHDOG) { +		if (ints & ATH9K_INT_BB_WATCHDOG) { +			mask |= AR_IMR_BCNMISC; +			mask2 |= AR_IMR_S2_BB_WATCHDOG; +		} +	} +  	ath_dbg(common, INTERRUPT, "new IMR 0x%x\n", mask);  	REG_WRITE(ah, AR_IMR, mask); -	ah->imrs2_reg &= ~(AR_IMR_S2_TIM | AR_IMR_S2_DTIM | AR_IMR_S2_DTIMSYNC | -			   AR_IMR_S2_CABEND | AR_IMR_S2_CABTO | -			   AR_IMR_S2_TSFOOR | AR_IMR_S2_GTT | AR_IMR_S2_CST); +	ah->imrs2_reg &= ~(AR_IMR_S2_TIM | +			   AR_IMR_S2_DTIM | +			   AR_IMR_S2_DTIMSYNC | +			   AR_IMR_S2_CABEND | +			   AR_IMR_S2_CABTO | +			   AR_IMR_S2_TSFOOR | +			   AR_IMR_S2_GTT | +			   AR_IMR_S2_CST); + +	if (ah->config.hw_hang_checks & HW_BB_WATCHDOG) { +		if (ints & ATH9K_INT_BB_WATCHDOG) +			ah->imrs2_reg &= ~AR_IMR_S2_BB_WATCHDOG; +	} +  	ah->imrs2_reg |= mask2;  	REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg); @@ -945,3 +958,25 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah)  	return;  }  EXPORT_SYMBOL(ath9k_hw_set_interrupts); + +#define ATH9K_HW_MAX_DCU       10 +#define ATH9K_HW_SLICE_PER_DCU 16 +#define ATH9K_HW_BIT_IN_SLICE  16 +void ath9k_hw_set_tx_filter(struct ath_hw *ah, u8 destidx, bool set) +{ +	int dcu_idx; +	u32 filter; + +	for (dcu_idx = 0; dcu_idx < 10; dcu_idx++) { +		filter = SM(set, AR_D_TXBLK_WRITE_COMMAND); +		filter |= SM(dcu_idx, AR_D_TXBLK_WRITE_DCU); +		filter |= SM((destidx / ATH9K_HW_SLICE_PER_DCU), +			     AR_D_TXBLK_WRITE_SLICE); +		filter |= BIT(destidx % ATH9K_HW_BIT_IN_SLICE); +		ath_dbg(ath9k_hw_common(ah), PS, +			"DCU%d staid %d set %d txfilter %08x\n", +			dcu_idx, destidx, set, filter); +		REG_WRITE(ah, AR_D_TXBLK_BASE, filter); +	} +} +EXPORT_SYMBOL(ath9k_hw_set_tx_filter); diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index bfccaceed44..da768675753 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -133,12 +133,8 @@ struct ath_rx_status {  	u8 rs_rate;  	u8 rs_antenna;  	u8 rs_more; -	int8_t rs_rssi_ctl0; -	int8_t rs_rssi_ctl1; -	int8_t rs_rssi_ctl2; -	int8_t rs_rssi_ext0; -	int8_t rs_rssi_ext1; -	int8_t rs_rssi_ext2; +	int8_t rs_rssi_ctl[3]; +	int8_t rs_rssi_ext[3];  	u8 rs_isaggr;  	u8 rs_firstaggr;  	u8 rs_moreaggr; @@ -159,12 +155,8 @@ struct ath_htc_rx_status {  	u8 rs_status;  	u8 rs_phyerr;  	int8_t rs_rssi; -	int8_t rs_rssi_ctl0; -	int8_t rs_rssi_ctl1; -	int8_t rs_rssi_ctl2; -	int8_t rs_rssi_ext0; -	int8_t rs_rssi_ext1; -	int8_t rs_rssi_ext2; +	int8_t rs_rssi_ctl[3]; +	int8_t rs_rssi_ext[3];  	u8 rs_keyix;  	u8 rs_rate;  	u8 rs_antenna; @@ -174,6 +166,7 @@ struct ath_htc_rx_status {  	u8 rs_num_delims;  	u8 rs_flags;  	u8 rs_dummy; +	/* FIXME: evm* never used? */  	__be32 evm0;  	__be32 evm1;  	__be32 evm2; @@ -603,8 +596,6 @@ enum ath9k_tx_queue_flags {  #define ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS 0x00000001  #define ATH9K_DECOMP_MASK_SIZE     128 -#define ATH9K_READY_TIME_LO_BOUND  50 -#define ATH9K_READY_TIME_HI_BOUND  96  enum ath9k_pkt_type {  	ATH9K_PKT_TYPE_NORMAL = 0, @@ -738,6 +729,7 @@ void ath9k_hw_startpcureceive(struct ath_hw *ah, bool is_scanning);  void ath9k_hw_abortpcurecv(struct ath_hw *ah);  bool ath9k_hw_stopdmarecv(struct ath_hw *ah, bool *reset);  int ath9k_hw_beaconq_setup(struct ath_hw *ah); +void ath9k_hw_set_tx_filter(struct ath_hw *ah, u8 destidx, bool set);  /* Interrupt Handling */  bool ath9k_hw_intrpend(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index e4f65900132..62ac95d6bb9 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -82,6 +82,22 @@ static bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode)  	return ret;  } +void ath_ps_full_sleep(unsigned long data) +{ +	struct ath_softc *sc = (struct ath_softc *) data; +	struct ath_common *common = ath9k_hw_common(sc->sc_ah); +	bool reset; + +	spin_lock(&common->cc_lock); +	ath_hw_cycle_counters_update(common); +	spin_unlock(&common->cc_lock); + +	ath9k_hw_setrxabort(sc->sc_ah, 1); +	ath9k_hw_stopdmarecv(sc->sc_ah, &reset); + +	ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); +} +  void ath9k_ps_wakeup(struct ath_softc *sc)  {  	struct ath_common *common = ath9k_hw_common(sc->sc_ah); @@ -92,6 +108,7 @@ void ath9k_ps_wakeup(struct ath_softc *sc)  	if (++sc->ps_usecount != 1)  		goto unlock; +	del_timer_sync(&sc->sleep_timer);  	power_mode = sc->sc_ah->power_mode;  	ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); @@ -117,17 +134,17 @@ void ath9k_ps_restore(struct ath_softc *sc)  	struct ath_common *common = ath9k_hw_common(sc->sc_ah);  	enum ath9k_power_mode mode;  	unsigned long flags; -	bool reset;  	spin_lock_irqsave(&sc->sc_pm_lock, flags);  	if (--sc->ps_usecount != 0)  		goto unlock;  	if (sc->ps_idle) { -		ath9k_hw_setrxabort(sc->sc_ah, 1); -		ath9k_hw_stopdmarecv(sc->sc_ah, &reset); -		mode = ATH9K_PM_FULL_SLEEP; -	} else if (sc->ps_enabled && +		mod_timer(&sc->sleep_timer, jiffies + HZ / 10); +		goto unlock; +	} + +	if (sc->ps_enabled &&  		   !(sc->ps_flags & (PS_WAIT_FOR_BEACON |  				     PS_WAIT_FOR_CAB |  				     PS_WAIT_FOR_PSPOLL_DATA | @@ -153,7 +170,6 @@ void ath9k_ps_restore(struct ath_softc *sc)  static void __ath_cancel_work(struct ath_softc *sc)  {  	cancel_work_sync(&sc->paprd_work); -	cancel_work_sync(&sc->hw_check_work);  	cancel_delayed_work_sync(&sc->tx_complete_work);  	cancel_delayed_work_sync(&sc->hw_pll_work); @@ -163,13 +179,13 @@ static void __ath_cancel_work(struct ath_softc *sc)  #endif  } -static void ath_cancel_work(struct ath_softc *sc) +void ath_cancel_work(struct ath_softc *sc)  {  	__ath_cancel_work(sc);  	cancel_work_sync(&sc->hw_reset_work);  } -static void ath_restart_work(struct ath_softc *sc) +void ath_restart_work(struct ath_softc *sc)  {  	ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); @@ -177,7 +193,6 @@ static void ath_restart_work(struct ath_softc *sc)  		ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,  				     msecs_to_jiffies(ATH_PLL_WORK_INTERVAL)); -	ath_start_rx_poll(sc, 3);  	ath_start_ani(sc);  } @@ -187,11 +202,7 @@ static bool ath_prepare_reset(struct ath_softc *sc)  	bool ret = true;  	ieee80211_stop_queues(sc->hw); - -	sc->hw_busy_count = 0;  	ath_stop_ani(sc); -	del_timer_sync(&sc->rx_poll_timer); -  	ath9k_hw_disable_interrupts(ah);  	if (!ath_drain_all_txq(sc)) @@ -208,6 +219,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)  	struct ath_hw *ah = sc->sc_ah;  	struct ath_common *common = ath9k_hw_common(ah);  	unsigned long flags; +	int i;  	if (ath_startrecv(sc) != 0) {  		ath_err(common, "Unable to restart recv logic\n"); @@ -217,16 +229,16 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)  	ath9k_cmn_update_txpow(ah, sc->curtxpow,  			       sc->config.txpowlimit, &sc->curtxpow); -	clear_bit(SC_OP_HW_RESET, &sc->sc_flags); +	clear_bit(ATH_OP_HW_RESET, &common->op_flags);  	ath9k_hw_set_interrupts(ah);  	ath9k_hw_enable_interrupts(ah);  	if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) && start) { -		if (!test_bit(SC_OP_BEACONS, &sc->sc_flags)) +		if (!test_bit(ATH_OP_BEACONS, &common->op_flags))  			goto work;  		if (ah->opmode == NL80211_IFTYPE_STATION && -		    test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { +		    test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) {  			spin_lock_irqsave(&sc->sc_pm_lock, flags);  			sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;  			spin_unlock_irqrestore(&sc->sc_pm_lock, flags); @@ -235,10 +247,22 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)  		}  	work:  		ath_restart_work(sc); + +		for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { +			if (!ATH_TXQ_SETUP(sc, i)) +				continue; + +			spin_lock_bh(&sc->tx.txq[i].axq_lock); +			ath_txq_schedule(sc, &sc->tx.txq[i]); +			spin_unlock_bh(&sc->tx.txq[i].axq_lock); +		}  	} +	sc->gtt_cnt = 0;  	ieee80211_wake_queues(sc->hw); +	ath9k_p2p_ps_timer(sc); +  	return true;  } @@ -302,17 +326,90 @@ out:   * by reseting the chip.  To accomplish this we must first cleanup any pending   * DMA, then restart stuff.  */ -static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, -		    struct ath9k_channel *hchan) +static int ath_set_channel(struct ath_softc *sc, struct cfg80211_chan_def *chandef)  { +	struct ath_hw *ah = sc->sc_ah; +	struct ath_common *common = ath9k_hw_common(ah); +	struct ieee80211_hw *hw = sc->hw; +	struct ath9k_channel *hchan; +	struct ieee80211_channel *chan = chandef->chan; +	bool offchannel; +	int pos = chan->hw_value; +	int old_pos = -1;  	int r; -	if (test_bit(SC_OP_INVALID, &sc->sc_flags)) +	if (test_bit(ATH_OP_INVALID, &common->op_flags))  		return -EIO; +	offchannel = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL); + +	if (ah->curchan) +		old_pos = ah->curchan - &ah->channels[0]; + +	ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n", +		chan->center_freq, chandef->width); + +	/* update survey stats for the old channel before switching */ +	spin_lock_bh(&common->cc_lock); +	ath_update_survey_stats(sc); +	spin_unlock_bh(&common->cc_lock); + +	ath9k_cmn_get_channel(hw, ah, chandef); + +	/* +	 * If the operating channel changes, change the survey in-use flags +	 * along with it. +	 * Reset the survey data for the new channel, unless we're switching +	 * back to the operating channel from an off-channel operation. +	 */ +	if (!offchannel && sc->cur_survey != &sc->survey[pos]) { +		if (sc->cur_survey) +			sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE; + +		sc->cur_survey = &sc->survey[pos]; + +		memset(sc->cur_survey, 0, sizeof(struct survey_info)); +		sc->cur_survey->filled |= SURVEY_INFO_IN_USE; +	} else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) { +		memset(&sc->survey[pos], 0, sizeof(struct survey_info)); +	} + +	hchan = &sc->sc_ah->channels[pos];  	r = ath_reset_internal(sc, hchan); +	if (r) +		return r; -	return r; +	/* +	 * The most recent snapshot of channel->noisefloor for the old +	 * channel is only available after the hardware reset. Copy it to +	 * the survey stats now. +	 */ +	if (old_pos >= 0) +		ath_update_survey_nf(sc, old_pos); + +	/* +	 * Enable radar pulse detection if on a DFS channel. Spectral +	 * scanning and radar detection can not be used concurrently. +	 */ +	if (hw->conf.radar_enabled) { +		u32 rxfilter; + +		/* set HW specific DFS configuration */ +		ath9k_hw_set_radar_params(ah); +		rxfilter = ath9k_hw_getrxfilter(ah); +		rxfilter |= ATH9K_RX_FILTER_PHYRADAR | +				ATH9K_RX_FILTER_PHYERR; +		ath9k_hw_setrxfilter(ah, rxfilter); +		ath_dbg(common, DFS, "DFS enabled at freq %d\n", +			chan->center_freq); +	} else { +		/* perform spectral scan if requested. */ +		if (test_bit(ATH_OP_SCANNING, &common->op_flags) && +			sc->spectral_mode == SPECTRAL_CHANSCAN) +			ath9k_spectral_scan_trigger(hw); +	} + +	return 0;  }  static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, @@ -324,14 +421,9 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,  	an->sc = sc;  	an->sta = sta;  	an->vif = vif; +	memset(&an->key_idx, 0, sizeof(an->key_idx));  	ath_tx_node_init(sc, an); - -	if (sta->ht_cap.ht_supported) { -		an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + -				     sta->ht_cap.ampdu_factor); -		an->mpdudensity = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density); -	}  }  static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) @@ -353,16 +445,52 @@ void ath9k_tasklet(unsigned long data)  	ath9k_ps_wakeup(sc);  	spin_lock(&sc->sc_pcu_lock); -	if ((status & ATH9K_INT_FATAL) || +	if (status & ATH9K_INT_FATAL) { +		type = RESET_TYPE_FATAL_INT; +		ath9k_queue_reset(sc, type); + +		/* +		 * Increment the ref. counter here so that +		 * interrupts are enabled in the reset routine. +		 */ +		atomic_inc(&ah->intr_ref_cnt); +		ath_dbg(common, RESET, "FATAL: Skipping interrupts\n"); +		goto out; +	} + +	if ((ah->config.hw_hang_checks & HW_BB_WATCHDOG) &&  	    (status & ATH9K_INT_BB_WATCHDOG)) { +		spin_lock(&common->cc_lock); +		ath_hw_cycle_counters_update(common); +		ar9003_hw_bb_watchdog_dbg_info(ah); +		spin_unlock(&common->cc_lock); -		if (status & ATH9K_INT_FATAL) -			type = RESET_TYPE_FATAL_INT; -		else +		if (ar9003_hw_bb_watchdog_check(ah)) {  			type = RESET_TYPE_BB_WATCHDOG; +			ath9k_queue_reset(sc, type); -		ath9k_queue_reset(sc, type); -		goto out; +			/* +			 * Increment the ref. counter here so that +			 * interrupts are enabled in the reset routine. +			 */ +			atomic_inc(&ah->intr_ref_cnt); +			ath_dbg(common, RESET, +				"BB_WATCHDOG: Skipping interrupts\n"); +			goto out; +		} +	} + +	if (status & ATH9K_INT_GTT) { +		sc->gtt_cnt++; + +		if ((sc->gtt_cnt >= MAX_GTT_CNT) && !ath9k_hw_check_alive(ah)) { +			type = RESET_TYPE_TX_GTT; +			ath9k_queue_reset(sc, type); +			atomic_inc(&ah->intr_ref_cnt); +			ath_dbg(common, RESET, +				"GTT: Skipping interrupts\n"); +			goto out; +		}  	}  	spin_lock_irqsave(&sc->sc_pm_lock, flags); @@ -392,18 +520,31 @@ void ath9k_tasklet(unsigned long data)  	}  	if (status & ATH9K_INT_TX) { -		if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) +		if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { +			/* +			 * For EDMA chips, TX completion is enabled for the +			 * beacon queue, so if a beacon has been transmitted +			 * successfully after a GTT interrupt, the GTT counter +			 * gets reset to zero here. +			 */ +			sc->gtt_cnt = 0; +  			ath_tx_edma_tasklet(sc); -		else +		} else {  			ath_tx_tasklet(sc); +		} + +		wake_up(&sc->tx_wait);  	} +	if (status & ATH9K_INT_GENTIMER) +		ath_gen_timer_isr(sc->sc_ah); +  	ath9k_btcoex_handle_interrupt(sc, status); -out:  	/* re-enable hardware interrupt */  	ath9k_hw_enable_interrupts(ah); - +out:  	spin_unlock(&sc->sc_pcu_lock);  	ath9k_ps_restore(sc);  } @@ -421,6 +562,7 @@ irqreturn_t ath_isr(int irq, void *dev)  		ATH9K_INT_TX |			\  		ATH9K_INT_BMISS |		\  		ATH9K_INT_CST |			\ +		ATH9K_INT_GTT |			\  		ATH9K_INT_TSFOOR |		\  		ATH9K_INT_GENTIMER |		\  		ATH9K_INT_MCI) @@ -429,6 +571,7 @@ irqreturn_t ath_isr(int irq, void *dev)  	struct ath_hw *ah = sc->sc_ah;  	struct ath_common *common = ath9k_hw_common(ah);  	enum ath9k_int status; +	u32 sync_cause = 0;  	bool sched = false;  	/* @@ -436,7 +579,7 @@ irqreturn_t ath_isr(int irq, void *dev)  	 * touch anything. Note this can happen early  	 * on if the IRQ is shared.  	 */ -	if (test_bit(SC_OP_INVALID, &sc->sc_flags)) +	if (test_bit(ATH_OP_INVALID, &common->op_flags))  		return IRQ_NONE;  	/* shared irq, not for us */ @@ -444,7 +587,7 @@ irqreturn_t ath_isr(int irq, void *dev)  	if (!ath9k_hw_intrpend(ah))  		return IRQ_NONE; -	if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) { +	if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) {  		ath9k_hw_kill_interrupts(ah);  		return IRQ_HANDLED;  	} @@ -455,7 +598,8 @@ irqreturn_t ath_isr(int irq, void *dev)  	 * bits we haven't explicitly enabled so we mask the  	 * value to insure we only process bits we requested.  	 */ -	ath9k_hw_getisr(ah, &status);	/* NB: clears ISR too */ +	ath9k_hw_getisr(ah, &status, &sync_cause); /* NB: clears ISR too */ +	ath9k_debug_sync_cause(sc, sync_cause);  	status &= ah->imask;	/* discard unasked-for bits */  	/* @@ -479,25 +623,19 @@ irqreturn_t ath_isr(int irq, void *dev)  	    !(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)))  		goto chip_reset; -	if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && -	    (status & ATH9K_INT_BB_WATCHDOG)) { - -		spin_lock(&common->cc_lock); -		ath_hw_cycle_counters_update(common); -		ar9003_hw_bb_watchdog_dbg_info(ah); -		spin_unlock(&common->cc_lock); - +	if ((ah->config.hw_hang_checks & HW_BB_WATCHDOG) && +	    (status & ATH9K_INT_BB_WATCHDOG))  		goto chip_reset; -	} -#ifdef CONFIG_PM_SLEEP + +#ifdef CONFIG_ATH9K_WOW  	if (status & ATH9K_INT_BMISS) {  		if (atomic_read(&sc->wow_sleep_proc_intr) == 0) { -			ath_dbg(common, ANY, "during WoW we got a BMISS\n");  			atomic_inc(&sc->wow_got_bmiss_intr);  			atomic_dec(&sc->wow_sleep_proc_intr);  		}  	}  #endif +  	if (status & ATH9K_INT_SWBA)  		tasklet_schedule(&sc->bcon_tasklet); @@ -537,23 +675,12 @@ chip_reset:  #undef SCHED_INTR  } -static int ath_reset(struct ath_softc *sc) +int ath_reset(struct ath_softc *sc)  { -	int i, r; +	int r;  	ath9k_ps_wakeup(sc); -  	r = ath_reset_internal(sc, NULL); - -	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { -		if (!ATH_TXQ_SETUP(sc, i)) -			continue; - -		spin_lock_bh(&sc->tx.txq[i].axq_lock); -		ath_txq_schedule(sc, &sc->tx.txq[i]); -		spin_unlock_bh(&sc->tx.txq[i].axq_lock); -	} -  	ath9k_ps_restore(sc);  	return r; @@ -561,10 +688,11 @@ static int ath_reset(struct ath_softc *sc)  void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type)  { +	struct ath_common *common = ath9k_hw_common(sc->sc_ah);  #ifdef CONFIG_ATH9K_DEBUGFS  	RESET_STAT_INC(sc, type);  #endif -	set_bit(SC_OP_HW_RESET, &sc->sc_flags); +	set_bit(ATH_OP_HW_RESET, &common->op_flags);  	ieee80211_queue_work(sc->hw, &sc->hw_reset_work);  } @@ -595,7 +723,7 @@ static int ath9k_start(struct ieee80211_hw *hw)  	ath9k_ps_wakeup(sc);  	mutex_lock(&sc->mutex); -	init_channel = ath9k_cmn_get_curchannel(hw, ah); +	init_channel = ath9k_cmn_get_channel(hw, ah, &hw->conf.chandef);  	/* Reset SERDES registers */  	ath9k_hw_configpcipowersave(ah, false); @@ -626,19 +754,26 @@ static int ath9k_start(struct ieee80211_hw *hw)  	if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)  		ah->imask |= ATH9K_INT_RXHP | -			     ATH9K_INT_RXLP | -			     ATH9K_INT_BB_WATCHDOG; +			     ATH9K_INT_RXLP;  	else  		ah->imask |= ATH9K_INT_RX; -	ah->imask |= ATH9K_INT_GTT; +	if (ah->config.hw_hang_checks & HW_BB_WATCHDOG) +		ah->imask |= ATH9K_INT_BB_WATCHDOG; + +	/* +	 * Enable GTT interrupts only for AR9003/AR9004 chips +	 * for now. +	 */ +	if (AR_SREV_9300_20_OR_LATER(ah)) +		ah->imask |= ATH9K_INT_GTT;  	if (ah->caps.hw_caps & ATH9K_HW_CAP_HT)  		ah->imask |= ATH9K_INT_CST;  	ath_mci_enable(sc); -	clear_bit(SC_OP_INVALID, &sc->sc_flags); +	clear_bit(ATH_OP_INVALID, &common->op_flags);  	sc->sc_ah->is_monitoring = false;  	if (!ath_complete_reset(sc, false)) @@ -656,6 +791,8 @@ static int ath9k_start(struct ieee80211_hw *hw)  	 */  	ath9k_cmn_init_crypto(sc->sc_ah); +	ath9k_hw_reset_tsf(ah); +  	spin_unlock_bh(&sc->sc_pcu_lock);  	mutex_unlock(&sc->mutex); @@ -752,9 +889,8 @@ static void ath9k_stop(struct ieee80211_hw *hw)  	mutex_lock(&sc->mutex);  	ath_cancel_work(sc); -	del_timer_sync(&sc->rx_poll_timer); -	if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { +	if (test_bit(ATH_OP_INVALID, &common->op_flags)) {  		ath_dbg(common, ANY, "Device not present\n");  		mutex_unlock(&sc->mutex);  		return; @@ -798,7 +934,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)  	}  	if (!ah->curchan) -		ah->curchan = ath9k_cmn_get_curchannel(hw, ah); +		ah->curchan = ath9k_cmn_get_channel(hw, ah, &hw->conf.chandef);  	ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);  	ath9k_hw_phy_disable(ah); @@ -809,7 +945,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)  	ath9k_ps_restore(sc); -	set_bit(SC_OP_INVALID, &sc->sc_flags); +	set_bit(ATH_OP_INVALID, &common->op_flags);  	sc->ps_idle = prev_idle;  	mutex_unlock(&sc->mutex); @@ -817,7 +953,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)  	ath_dbg(common, CONFIG, "Driver halt\n");  } -bool ath9k_uses_beacons(int type) +static bool ath9k_uses_beacons(int type)  {  	switch (type) {  	case NL80211_IFTYPE_AP: @@ -886,8 +1022,9 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,  	struct ath_common *common = ath9k_hw_common(ah);  	/* -	 * Use the hardware MAC address as reference, the hardware uses it -	 * together with the BSSID mask when matching addresses. +	 * Pick the MAC address of the first interface as the new hardware +	 * MAC address. The hardware will use it together with the BSSID mask +	 * when matching addresses.  	 */  	memset(iter_data, 0, sizeof(*iter_data));  	memset(&iter_data->mask, 0xff, ETH_ALEN); @@ -949,7 +1086,7 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,  	 */  	if (ah->opmode == NL80211_IFTYPE_STATION &&  	    old_opmode == NL80211_IFTYPE_AP && -	    test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { +	    test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) {  		ieee80211_iterate_active_interfaces_atomic(  			sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL,  			ath9k_sta_vif_iter, sc); @@ -967,6 +1104,14 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,  	mutex_lock(&sc->mutex); +	if (config_enabled(CONFIG_ATH9K_TX99)) { +		if (sc->nvifs >= 1) { +			mutex_unlock(&sc->mutex); +			return -EOPNOTSUPP; +		} +		sc->tx99_vif = vif; +	} +  	ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type);  	sc->nvifs++; @@ -977,6 +1122,8 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,  	if (ath9k_uses_beacons(vif->type))  		ath9k_beacon_assign_slot(sc, vif); +	avp->vif = vif; +  	an->sc = sc;  	an->sta = NULL;  	an->vif = vif; @@ -995,9 +1142,15 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,  	struct ath_softc *sc = hw->priv;  	struct ath_common *common = ath9k_hw_common(sc->sc_ah); -	ath_dbg(common, CONFIG, "Change Interface\n");  	mutex_lock(&sc->mutex); +	if (config_enabled(CONFIG_ATH9K_TX99)) { +		mutex_unlock(&sc->mutex); +		return -EOPNOTSUPP; +	} + +	ath_dbg(common, CONFIG, "Change Interface\n"); +  	if (ath9k_uses_beacons(vif->type))  		ath9k_beacon_remove_slot(sc, vif); @@ -1015,6 +1168,29 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,  	return 0;  } +static void +ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp) +{ +	struct ath_hw *ah = sc->sc_ah; +	s32 tsf, target_tsf; + +	if (!avp || !avp->noa.has_next_tsf) +		return; + +	ath9k_hw_gen_timer_stop(ah, sc->p2p_ps_timer); + +	tsf = ath9k_hw_gettsf32(sc->sc_ah); + +	target_tsf = avp->noa.next_tsf; +	if (!avp->noa.absent) +		target_tsf -= ATH_P2P_PS_STOP_TIME; + +	if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME) +		target_tsf = tsf + ATH_P2P_PS_STOP_TIME; + +	ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000); +} +  static void ath9k_remove_interface(struct ieee80211_hw *hw,  				   struct ieee80211_vif *vif)  { @@ -1026,14 +1202,19 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,  	mutex_lock(&sc->mutex); +	spin_lock_bh(&sc->sc_pcu_lock); +	if (avp == sc->p2p_ps_vif) { +		sc->p2p_ps_vif = NULL; +		ath9k_update_p2p_ps_timer(sc, NULL); +	} +	spin_unlock_bh(&sc->sc_pcu_lock); +  	sc->nvifs--; +	sc->tx99_vif = NULL;  	if (ath9k_uses_beacons(vif->type))  		ath9k_beacon_remove_slot(sc, vif); -	if (sc->csa_vif == vif) -		sc->csa_vif = NULL; -  	ath9k_ps_wakeup(sc);  	ath9k_calculate_summary_state(hw, NULL);  	ath9k_ps_restore(sc); @@ -1048,6 +1229,9 @@ static void ath9k_enable_ps(struct ath_softc *sc)  	struct ath_hw *ah = sc->sc_ah;  	struct ath_common *common = ath9k_hw_common(ah); +	if (config_enabled(CONFIG_ATH9K_TX99)) +		return; +  	sc->ps_enabled = true;  	if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {  		if ((ah->imask & ATH9K_INT_TIM_TIMER) == 0) { @@ -1064,6 +1248,9 @@ static void ath9k_disable_ps(struct ath_softc *sc)  	struct ath_hw *ah = sc->sc_ah;  	struct ath_common *common = ath9k_hw_common(ah); +	if (config_enabled(CONFIG_ATH9K_TX99)) +		return; +  	sc->ps_enabled = false;  	ath9k_hw_setpower(ah, ATH9K_PM_AWAKE);  	if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { @@ -1087,6 +1274,9 @@ void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw)  	struct ath_common *common = ath9k_hw_common(ah);  	u32 rxfilter; +	if (config_enabled(CONFIG_ATH9K_TX99)) +		return; +  	if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {  		ath_err(common, "spectrum analyzer not implemented on this hardware\n");  		return; @@ -1202,81 +1392,12 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)  	}  	if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || reset_channel) { -		struct ieee80211_channel *curchan = hw->conf.chandef.chan; -		int pos = curchan->hw_value; -		int old_pos = -1; -		unsigned long flags; - -		if (ah->curchan) -			old_pos = ah->curchan - &ah->channels[0]; - -		ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n", -			curchan->center_freq, hw->conf.chandef.width); - -		/* update survey stats for the old channel before switching */ -		spin_lock_irqsave(&common->cc_lock, flags); -		ath_update_survey_stats(sc); -		spin_unlock_irqrestore(&common->cc_lock, flags); - -		ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos], -					  &conf->chandef); - -		/* -		 * If the operating channel changes, change the survey in-use flags -		 * along with it. -		 * Reset the survey data for the new channel, unless we're switching -		 * back to the operating channel from an off-channel operation. -		 */ -		if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) && -		    sc->cur_survey != &sc->survey[pos]) { - -			if (sc->cur_survey) -				sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE; - -			sc->cur_survey = &sc->survey[pos]; - -			memset(sc->cur_survey, 0, sizeof(struct survey_info)); -			sc->cur_survey->filled |= SURVEY_INFO_IN_USE; -		} else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) { -			memset(&sc->survey[pos], 0, sizeof(struct survey_info)); -		} - -		if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) { +		if (ath_set_channel(sc, &hw->conf.chandef) < 0) {  			ath_err(common, "Unable to set channel\n");  			mutex_unlock(&sc->mutex);  			ath9k_ps_restore(sc);  			return -EINVAL;  		} - -		/* -		 * The most recent snapshot of channel->noisefloor for the old -		 * channel is only available after the hardware reset. Copy it to -		 * the survey stats now. -		 */ -		if (old_pos >= 0) -			ath_update_survey_nf(sc, old_pos); - -		/* -		 * Enable radar pulse detection if on a DFS channel. Spectral -		 * scanning and radar detection can not be used concurrently. -		 */ -		if (hw->conf.radar_enabled) { -			u32 rxfilter; - -			/* set HW specific DFS configuration */ -			ath9k_hw_set_radar_params(ah); -			rxfilter = ath9k_hw_getrxfilter(ah); -			rxfilter |= ATH9K_RX_FILTER_PHYRADAR | -				    ATH9K_RX_FILTER_PHYERR; -			ath9k_hw_setrxfilter(ah, rxfilter); -			ath_dbg(common, DFS, "DFS enabled at freq %d\n", -				curchan->center_freq); -		} else { -			/* perform spectral scan if requested. */ -			if (test_bit(SC_OP_SCANNING, &sc->sc_flags) && -			    sc->spectral_mode == SPECTRAL_CHANSCAN) -				ath9k_spectral_scan_trigger(hw); -		}  	}  	if (changed & IEEE80211_CONF_CHANGE_POWER) { @@ -1341,8 +1462,10 @@ static int ath9k_sta_add(struct ieee80211_hw *hw,  		return 0;  	key = ath_key_config(common, vif, sta, &ps_key); -	if (key > 0) +	if (key > 0) {  		an->ps_key = key; +		an->key_idx[0] = key; +	}  	return 0;  } @@ -1360,6 +1483,7 @@ static void ath9k_del_ps_key(struct ath_softc *sc,  	ath_key_delete(common, &ps_key);  	an->ps_key = 0; +	an->key_idx[0] = 0;  }  static int ath9k_sta_remove(struct ieee80211_hw *hw, @@ -1374,6 +1498,19 @@ static int ath9k_sta_remove(struct ieee80211_hw *hw,  	return 0;  } +static void ath9k_sta_set_tx_filter(struct ath_hw *ah, +				    struct ath_node *an, +				    bool set) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) { +		if (!an->key_idx[i]) +			continue; +		ath9k_hw_set_tx_filter(ah, an->key_idx[i], set); +	} +} +  static void ath9k_sta_notify(struct ieee80211_hw *hw,  			 struct ieee80211_vif *vif,  			 enum sta_notify_cmd cmd, @@ -1386,8 +1523,10 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw,  	case STA_NOTIFY_SLEEP:  		an->sleeping = true;  		ath_tx_aggr_sleep(sta, sc, an); +		ath9k_sta_set_tx_filter(sc->sc_ah, an, true);  		break;  	case STA_NOTIFY_AWAKE: +		ath9k_sta_set_tx_filter(sc->sc_ah, an, false);  		an->sleeping = false;  		ath_tx_aggr_wakeup(sc, an);  		break; @@ -1443,7 +1582,8 @@ static int ath9k_set_key(struct ieee80211_hw *hw,  {  	struct ath_softc *sc = hw->priv;  	struct ath_common *common = ath9k_hw_common(sc->sc_ah); -	int ret = 0; +	struct ath_node *an = NULL; +	int ret = 0, i;  	if (ath9k_modparam_nohwcrypt)  		return -ENOSPC; @@ -1465,13 +1605,16 @@ static int ath9k_set_key(struct ieee80211_hw *hw,  	mutex_lock(&sc->mutex);  	ath9k_ps_wakeup(sc); -	ath_dbg(common, CONFIG, "Set HW Key\n"); +	ath_dbg(common, CONFIG, "Set HW Key %d\n", cmd); +	if (sta) +		an = (struct ath_node *)sta->drv_priv;  	switch (cmd) {  	case SET_KEY:  		if (sta)  			ath9k_del_ps_key(sc, vif, sta); +		key->hw_key_idx = 0;  		ret = ath_key_config(common, vif, sta, key);  		if (ret >= 0) {  			key->hw_key_idx = ret; @@ -1484,9 +1627,27 @@ static int ath9k_set_key(struct ieee80211_hw *hw,  				key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;  			ret = 0;  		} +		if (an && key->hw_key_idx) { +			for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) { +				if (an->key_idx[i]) +					continue; +				an->key_idx[i] = key->hw_key_idx; +				break; +			} +			WARN_ON(i == ARRAY_SIZE(an->key_idx)); +		}  		break;  	case DISABLE_KEY:  		ath_key_delete(common, key); +		if (an) { +			for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) { +				if (an->key_idx[i] != key->hw_key_idx) +					continue; +				an->key_idx[i] = 0; +				break; +			} +		} +		key->hw_key_idx = 0;  		break;  	default:  		ret = -EINVAL; @@ -1506,7 +1667,7 @@ static void ath9k_set_assoc_state(struct ath_softc *sc,  	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;  	unsigned long flags; -	set_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags); +	set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags);  	avp->primary_sta_vif = true;  	/* @@ -1522,7 +1683,7 @@ static void ath9k_set_assoc_state(struct ath_softc *sc,  	common->curaid = bss_conf->aid;  	ath9k_hw_write_associd(sc->sc_ah); -	sc->last_rssi = ATH_RSSI_DUMMY_MARKER; +	common->last_rssi = ATH_RSSI_DUMMY_MARKER;  	sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;  	spin_lock_irqsave(&sc->sc_pm_lock, flags); @@ -1541,14 +1702,75 @@ static void ath9k_bss_assoc_iter(void *data, u8 *mac, struct ieee80211_vif *vif)  {  	struct ath_softc *sc = data;  	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; +	struct ath_common *common = ath9k_hw_common(sc->sc_ah); -	if (test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) +	if (test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags))  		return;  	if (bss_conf->assoc)  		ath9k_set_assoc_state(sc, vif);  } +void ath9k_p2p_ps_timer(void *priv) +{ +	struct ath_softc *sc = priv; +	struct ath_vif *avp = sc->p2p_ps_vif; +	struct ieee80211_vif *vif; +	struct ieee80211_sta *sta; +	struct ath_node *an; +	u32 tsf; + +	if (!avp) +		return; + +	tsf = ath9k_hw_gettsf32(sc->sc_ah); +	if (!avp->noa.absent) +		tsf += ATH_P2P_PS_STOP_TIME; + +	if (!avp->noa.has_next_tsf || +	    avp->noa.next_tsf - tsf > BIT(31)) +		ieee80211_update_p2p_noa(&avp->noa, tsf); + +	ath9k_update_p2p_ps_timer(sc, avp); + +	rcu_read_lock(); + +	vif = avp->vif; +	sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); +	if (!sta) +		goto out; + +	an = (void *) sta->drv_priv; +	if (an->sleeping == !!avp->noa.absent) +		goto out; + +	an->sleeping = avp->noa.absent; +	if (an->sleeping) +		ath_tx_aggr_sleep(sta, sc, an); +	else +		ath_tx_aggr_wakeup(sc, an); + +out: +	rcu_read_unlock(); +} + +void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif) +{ +	struct ath_vif *avp = (void *)vif->drv_priv; +	u32 tsf; + +	if (!sc->p2p_ps_timer) +		return; + +	if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p) +		return; + +	sc->p2p_ps_vif = avp; +	tsf = ath9k_hw_gettsf32(sc->sc_ah); +	ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf); +	ath9k_update_p2p_ps_timer(sc, avp); +} +  static void ath9k_bss_info_changed(struct ieee80211_hw *hw,  				   struct ieee80211_vif *vif,  				   struct ieee80211_bss_conf *bss_conf, @@ -1563,6 +1785,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,  	struct ath_hw *ah = sc->sc_ah;  	struct ath_common *common = ath9k_hw_common(ah);  	struct ath_vif *avp = (void *)vif->drv_priv; +	unsigned long flags;  	int slottime;  	ath9k_ps_wakeup(sc); @@ -1573,18 +1796,18 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,  			bss_conf->bssid, bss_conf->assoc);  		if (avp->primary_sta_vif && !bss_conf->assoc) { -			clear_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags); +			clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags);  			avp->primary_sta_vif = false;  			if (ah->opmode == NL80211_IFTYPE_STATION) -				clear_bit(SC_OP_BEACONS, &sc->sc_flags); +				clear_bit(ATH_OP_BEACONS, &common->op_flags);  		}  		ieee80211_iterate_active_interfaces_atomic(  			sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL,  			ath9k_bss_assoc_iter, sc); -		if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags) && +		if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags) &&  		    ah->opmode == NL80211_IFTYPE_STATION) {  			memset(common->curbssid, 0, ETH_ALEN);  			common->curaid = 0; @@ -1601,13 +1824,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,  	}  	if ((changed & BSS_CHANGED_BEACON_ENABLED) || -	    (changed & BSS_CHANGED_BEACON_INT)) { -		if (ah->opmode == NL80211_IFTYPE_AP && -		    bss_conf->enable_beacon) -			ath9k_set_tsfadjust(sc, vif); -		if (ath9k_allow_beacon_config(sc, vif)) -			ath9k_beacon_config(sc, vif, changed); -	} +	    (changed & BSS_CHANGED_BEACON_INT)) +		ath9k_beacon_config(sc, vif, changed);  	if (changed & BSS_CHANGED_ERP_SLOT) {  		if (bss_conf->use_short_slot) @@ -1628,6 +1846,15 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,  		}  	} +	if (changed & BSS_CHANGED_P2P_PS) { +		spin_lock_bh(&sc->sc_pcu_lock); +		spin_lock_irqsave(&sc->sc_pm_lock, flags); +		if (!(sc->ps_flags & PS_BEACON_SYNC)) +			ath9k_update_p2p_ps(sc, vif); +		spin_unlock_irqrestore(&sc->sc_pm_lock, flags); +		spin_unlock_bh(&sc->sc_pcu_lock); +	} +  	if (changed & CHECK_ANI)  		ath_check_ani(sc); @@ -1732,10 +1959,12 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,  	struct ath_common *common = ath9k_hw_common(sc->sc_ah);  	struct ieee80211_supported_band *sband;  	struct ieee80211_channel *chan; -	unsigned long flags;  	int pos; -	spin_lock_irqsave(&common->cc_lock, flags); +	if (config_enabled(CONFIG_ATH9K_TX99)) +		return -EOPNOTSUPP; + +	spin_lock_bh(&common->cc_lock);  	if (idx == 0)  		ath_update_survey_stats(sc); @@ -1749,7 +1978,7 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,  		sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ];  	if (!sband || idx >= sband->n_channels) { -		spin_unlock_irqrestore(&common->cc_lock, flags); +		spin_unlock_bh(&common->cc_lock);  		return -ENOENT;  	} @@ -1757,7 +1986,7 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,  	pos = chan->hw_value;  	memcpy(survey, &sc->survey[pos], sizeof(*survey));  	survey->channel = chan; -	spin_unlock_irqrestore(&common->cc_lock, flags); +	spin_unlock_bh(&common->cc_lock);  	return 0;  } @@ -1767,6 +1996,9 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)  	struct ath_softc *sc = hw->priv;  	struct ath_hw *ah = sc->sc_ah; +	if (config_enabled(CONFIG_ATH9K_TX99)) +		return; +  	mutex_lock(&sc->mutex);  	ah->coverage_class = coverage_class; @@ -1777,13 +2009,32 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)  	mutex_unlock(&sc->mutex);  } -static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +static bool ath9k_has_tx_pending(struct ath_softc *sc) +{ +	int i, npend = 0; + +	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { +		if (!ATH_TXQ_SETUP(sc, i)) +			continue; + +		if (!sc->tx.txq[i].axq_depth) +			continue; + +		npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]); +		if (npend) +			break; +	} + +	return !!npend; +} + +static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +			u32 queues, bool drop)  {  	struct ath_softc *sc = hw->priv;  	struct ath_hw *ah = sc->sc_ah;  	struct ath_common *common = ath9k_hw_common(ah); -	int timeout = 200; /* ms */ -	int i, j; +	int timeout = HZ / 5; /* 200 ms */  	bool drain_txq;  	mutex_lock(&sc->mutex); @@ -1795,31 +2046,15 @@ static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)  		return;  	} -	if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { +	if (test_bit(ATH_OP_INVALID, &common->op_flags)) {  		ath_dbg(common, ANY, "Device not present\n");  		mutex_unlock(&sc->mutex);  		return;  	} -	for (j = 0; j < timeout; j++) { -		bool npend = false; - -		if (j) -			usleep_range(1000, 2000); - -		for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { -			if (!ATH_TXQ_SETUP(sc, i)) -				continue; - -			npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]); - -			if (npend) -				break; -		} - -		if (!npend) -		    break; -	} +	if (wait_event_timeout(sc->tx_wait, !ath9k_has_tx_pending(sc), +			       timeout) > 0) +		drop = false;  	if (drop) {  		ath9k_ps_wakeup(sc); @@ -1967,7 +2202,7 @@ static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)  		ah->rxchainmask = fill_chainmask(ah->caps.rx_chainmask, rx_ant);  	ah->txchainmask = fill_chainmask(ah->caps.tx_chainmask, tx_ant); -	ath9k_reload_chainmask_settings(sc); +	ath9k_cmn_reload_chainmask(ah);  	return 0;  } @@ -1981,356 +2216,18 @@ static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)  	return 0;  } -#ifdef CONFIG_PM_SLEEP - -static void ath9k_wow_map_triggers(struct ath_softc *sc, -				   struct cfg80211_wowlan *wowlan, -				   u32 *wow_triggers) -{ -	if (wowlan->disconnect) -		*wow_triggers |= AH_WOW_LINK_CHANGE | -				 AH_WOW_BEACON_MISS; -	if (wowlan->magic_pkt) -		*wow_triggers |= AH_WOW_MAGIC_PATTERN_EN; - -	if (wowlan->n_patterns) -		*wow_triggers |= AH_WOW_USER_PATTERN_EN; - -	sc->wow_enabled = *wow_triggers; - -} - -static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) -{ -	struct ath_hw *ah = sc->sc_ah; -	struct ath_common *common = ath9k_hw_common(ah); -	int pattern_count = 0; -	int i, byte_cnt; -	u8 dis_deauth_pattern[MAX_PATTERN_SIZE]; -	u8 dis_deauth_mask[MAX_PATTERN_SIZE]; - -	memset(dis_deauth_pattern, 0, MAX_PATTERN_SIZE); -	memset(dis_deauth_mask, 0, MAX_PATTERN_SIZE); - -	/* -	 * Create Dissassociate / Deauthenticate packet filter -	 * -	 *     2 bytes        2 byte    6 bytes   6 bytes  6 bytes -	 *  +--------------+----------+---------+--------+--------+---- -	 *  + Frame Control+ Duration +   DA    +  SA    +  BSSID + -	 *  +--------------+----------+---------+--------+--------+---- -	 * -	 * The above is the management frame format for disassociate/ -	 * deauthenticate pattern, from this we need to match the first byte -	 * of 'Frame Control' and DA, SA, and BSSID fields -	 * (skipping 2nd byte of FC and Duration feild. -	 * -	 * Disassociate pattern -	 * -------------------- -	 * Frame control = 00 00 1010 -	 * DA, SA, BSSID = x:x:x:x:x:x -	 * Pattern will be A0000000 | x:x:x:x:x:x | x:x:x:x:x:x -	 *			    | x:x:x:x:x:x  -- 22 bytes -	 * -	 * Deauthenticate pattern -	 * ---------------------- -	 * Frame control = 00 00 1100 -	 * DA, SA, BSSID = x:x:x:x:x:x -	 * Pattern will be C0000000 | x:x:x:x:x:x | x:x:x:x:x:x -	 *			    | x:x:x:x:x:x  -- 22 bytes -	 */ - -	/* Create Disassociate Pattern first */ - -	byte_cnt = 0; - -	/* Fill out the mask with all FF's */ - -	for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++) -		dis_deauth_mask[i] = 0xff; - -	/* copy the first byte of frame control field */ -	dis_deauth_pattern[byte_cnt] = 0xa0; -	byte_cnt++; - -	/* skip 2nd byte of frame control and Duration field */ -	byte_cnt += 3; - -	/* -	 * need not match the destination mac address, it can be a broadcast -	 * mac address or an unicast to this station -	 */ -	byte_cnt += 6; - -	/* copy the source mac address */ -	memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN); - -	byte_cnt += 6; - -	/* copy the bssid, its same as the source mac address */ - -	memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN); - -	/* Create Disassociate pattern mask */ - -	dis_deauth_mask[0] = 0xfe; -	dis_deauth_mask[1] = 0x03; -	dis_deauth_mask[2] = 0xc0; - -	ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n"); - -	ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, -				   pattern_count, byte_cnt); - -	pattern_count++; -	/* -	 * for de-authenticate pattern, only the first byte of the frame -	 * control field gets changed from 0xA0 to 0xC0 -	 */ -	dis_deauth_pattern[0] = 0xC0; - -	ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, -				   pattern_count, byte_cnt); - -} - -static void ath9k_wow_add_pattern(struct ath_softc *sc, -				  struct cfg80211_wowlan *wowlan) -{ -	struct ath_hw *ah = sc->sc_ah; -	struct ath9k_wow_pattern *wow_pattern = NULL; -	struct cfg80211_pkt_pattern *patterns = wowlan->patterns; -	int mask_len; -	s8 i = 0; - -	if (!wowlan->n_patterns) -		return; - -	/* -	 * Add the new user configured patterns -	 */ -	for (i = 0; i < wowlan->n_patterns; i++) { - -		wow_pattern = kzalloc(sizeof(*wow_pattern), GFP_KERNEL); - -		if (!wow_pattern) -			return; - -		/* -		 * TODO: convert the generic user space pattern to -		 * appropriate chip specific/802.11 pattern. -		 */ - -		mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8); -		memset(wow_pattern->pattern_bytes, 0, MAX_PATTERN_SIZE); -		memset(wow_pattern->mask_bytes, 0, MAX_PATTERN_SIZE); -		memcpy(wow_pattern->pattern_bytes, patterns[i].pattern, -		       patterns[i].pattern_len); -		memcpy(wow_pattern->mask_bytes, patterns[i].mask, mask_len); -		wow_pattern->pattern_len = patterns[i].pattern_len; - -		/* -		 * just need to take care of deauth and disssoc pattern, -		 * make sure we don't overwrite them. -		 */ - -		ath9k_hw_wow_apply_pattern(ah, wow_pattern->pattern_bytes, -					   wow_pattern->mask_bytes, -					   i + 2, -					   wow_pattern->pattern_len); -		kfree(wow_pattern); - -	} - -} - -static int ath9k_suspend(struct ieee80211_hw *hw, -			 struct cfg80211_wowlan *wowlan) -{ -	struct ath_softc *sc = hw->priv; -	struct ath_hw *ah = sc->sc_ah; -	struct ath_common *common = ath9k_hw_common(ah); -	u32 wow_triggers_enabled = 0; -	int ret = 0; - -	mutex_lock(&sc->mutex); - -	ath_cancel_work(sc); -	ath_stop_ani(sc); -	del_timer_sync(&sc->rx_poll_timer); - -	if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { -		ath_dbg(common, ANY, "Device not present\n"); -		ret = -EINVAL; -		goto fail_wow; -	} - -	if (WARN_ON(!wowlan)) { -		ath_dbg(common, WOW, "None of the WoW triggers enabled\n"); -		ret = -EINVAL; -		goto fail_wow; -	} - -	if (!device_can_wakeup(sc->dev)) { -		ath_dbg(common, WOW, "device_can_wakeup failed, WoW is not enabled\n"); -		ret = 1; -		goto fail_wow; -	} - -	/* -	 * none of the sta vifs are associated -	 * and we are not currently handling multivif -	 * cases, for instance we have to seperately -	 * configure 'keep alive frame' for each -	 * STA. -	 */ - -	if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { -		ath_dbg(common, WOW, "None of the STA vifs are associated\n"); -		ret = 1; -		goto fail_wow; -	} - -	if (sc->nvifs > 1) { -		ath_dbg(common, WOW, "WoW for multivif is not yet supported\n"); -		ret = 1; -		goto fail_wow; -	} - -	ath9k_wow_map_triggers(sc, wowlan, &wow_triggers_enabled); - -	ath_dbg(common, WOW, "WoW triggers enabled 0x%x\n", -		wow_triggers_enabled); - -	ath9k_ps_wakeup(sc); - -	ath9k_stop_btcoex(sc); - -	/* -	 * Enable wake up on recieving disassoc/deauth -	 * frame by default. -	 */ -	ath9k_wow_add_disassoc_deauth_pattern(sc); - -	if (wow_triggers_enabled & AH_WOW_USER_PATTERN_EN) -		ath9k_wow_add_pattern(sc, wowlan); - -	spin_lock_bh(&sc->sc_pcu_lock); -	/* -	 * To avoid false wake, we enable beacon miss interrupt only -	 * when we go to sleep. We save the current interrupt mask -	 * so we can restore it after the system wakes up -	 */ -	sc->wow_intr_before_sleep = ah->imask; -	ah->imask &= ~ATH9K_INT_GLOBAL; -	ath9k_hw_disable_interrupts(ah); -	ah->imask = ATH9K_INT_BMISS | ATH9K_INT_GLOBAL; -	ath9k_hw_set_interrupts(ah); -	ath9k_hw_enable_interrupts(ah); - -	spin_unlock_bh(&sc->sc_pcu_lock); - -	/* -	 * we can now sync irq and kill any running tasklets, since we already -	 * disabled interrupts and not holding a spin lock -	 */ -	synchronize_irq(sc->irq); -	tasklet_kill(&sc->intr_tq); - -	ath9k_hw_wow_enable(ah, wow_triggers_enabled); - -	ath9k_ps_restore(sc); -	ath_dbg(common, ANY, "WoW enabled in ath9k\n"); -	atomic_inc(&sc->wow_sleep_proc_intr); - -fail_wow: -	mutex_unlock(&sc->mutex); -	return ret; -} - -static int ath9k_resume(struct ieee80211_hw *hw) -{ -	struct ath_softc *sc = hw->priv; -	struct ath_hw *ah = sc->sc_ah; -	struct ath_common *common = ath9k_hw_common(ah); -	u32 wow_status; - -	mutex_lock(&sc->mutex); - -	ath9k_ps_wakeup(sc); - -	spin_lock_bh(&sc->sc_pcu_lock); - -	ath9k_hw_disable_interrupts(ah); -	ah->imask = sc->wow_intr_before_sleep; -	ath9k_hw_set_interrupts(ah); -	ath9k_hw_enable_interrupts(ah); - -	spin_unlock_bh(&sc->sc_pcu_lock); - -	wow_status = ath9k_hw_wow_wakeup(ah); - -	if (atomic_read(&sc->wow_got_bmiss_intr) == 0) { -		/* -		 * some devices may not pick beacon miss -		 * as the reason they woke up so we add -		 * that here for that shortcoming. -		 */ -		wow_status |= AH_WOW_BEACON_MISS; -		atomic_dec(&sc->wow_got_bmiss_intr); -		ath_dbg(common, ANY, "Beacon miss interrupt picked up during WoW sleep\n"); -	} - -	atomic_dec(&sc->wow_sleep_proc_intr); - -	if (wow_status) { -		ath_dbg(common, ANY, "Waking up due to WoW triggers %s with WoW status = %x\n", -			ath9k_hw_wow_event_to_string(wow_status), wow_status); -	} - -	ath_restart_work(sc); -	ath9k_start_btcoex(sc); - -	ath9k_ps_restore(sc); -	mutex_unlock(&sc->mutex); - -	return 0; -} - -static void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled) -{ -	struct ath_softc *sc = hw->priv; - -	mutex_lock(&sc->mutex); -	device_init_wakeup(sc->dev, 1); -	device_set_wakeup_enable(sc->dev, enabled); -	mutex_unlock(&sc->mutex); -} - -#endif  static void ath9k_sw_scan_start(struct ieee80211_hw *hw)  {  	struct ath_softc *sc = hw->priv; -	set_bit(SC_OP_SCANNING, &sc->sc_flags); +	struct ath_common *common = ath9k_hw_common(sc->sc_ah); +	set_bit(ATH_OP_SCANNING, &common->op_flags);  }  static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)  {  	struct ath_softc *sc = hw->priv; -	clear_bit(SC_OP_SCANNING, &sc->sc_flags); -} - -static void ath9k_channel_switch_beacon(struct ieee80211_hw *hw, -					struct ieee80211_vif *vif, -					struct cfg80211_chan_def *chandef) -{ -	struct ath_softc *sc = hw->priv; - -	/* mac80211 does not support CSA in multi-if cases (yet) */ -	if (WARN_ON(sc->csa_vif)) -		return; - -	sc->csa_vif = vif; +	struct ath_common *common = ath9k_hw_common(sc->sc_ah); +	clear_bit(ATH_OP_SCANNING, &common->op_flags);  }  struct ieee80211_ops ath9k_ops = { @@ -2363,7 +2260,7 @@ struct ieee80211_ops ath9k_ops = {  	.set_antenna	    = ath9k_set_antenna,  	.get_antenna	    = ath9k_get_antenna, -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_ATH9K_WOW  	.suspend	    = ath9k_suspend,  	.resume		    = ath9k_resume,  	.set_wakeup	    = ath9k_set_wakeup, @@ -2375,10 +2272,9 @@ struct ieee80211_ops ath9k_ops = {  	.get_et_strings     = ath9k_get_et_strings,  #endif -#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) +#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_STATION_STATISTICS)  	.sta_add_debugfs    = ath9k_sta_add_debugfs,  #endif  	.sw_scan_start	    = ath9k_sw_scan_start,  	.sw_scan_complete   = ath9k_sw_scan_complete, -	.channel_switch_beacon     = ath9k_channel_switch_beacon,  }; diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 815bee21c19..a0dbcc41238 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -200,7 +200,7 @@ skip_tuning:  	if (btcoex->duty_cycle > ATH_MCI_MAX_DUTY_CYCLE)  		btcoex->duty_cycle = ATH_MCI_MAX_DUTY_CYCLE; -	btcoex->btcoex_no_stomp =  btcoex->btcoex_period * 1000 * +	btcoex->btcoex_no_stomp =  btcoex->btcoex_period *  		(100 - btcoex->duty_cycle) / 100;  	ath9k_hw_btcoex_enable(sc->sc_ah); @@ -555,7 +555,7 @@ void ath_mci_intr(struct ath_softc *sc)  		mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_GPM;  		while (more_data == MCI_GPM_MORE) { -			if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) +			if (test_bit(ATH_OP_HW_RESET, &common->op_flags))  				return;  			pgpm = mci->gpm_buf.bf_addr; @@ -661,9 +661,9 @@ void ath9k_mci_update_wlan_channels(struct ath_softc *sc, bool allow_all)  	chan_start = wlan_chan - 10;  	chan_end = wlan_chan + 10; -	if (chan->chanmode == CHANNEL_G_HT40PLUS) +	if (IS_CHAN_HT40PLUS(chan))  		chan_end += 20; -	else if (chan->chanmode == CHANNEL_G_HT40MINUS) +	else if (IS_CHAN_HT40MINUS(chan))  		chan_start -= 20;  	/* adjust side band */ @@ -707,11 +707,11 @@ void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel,  	if (setchannel) {  		struct ath9k_hw_cal_data *caldata = &sc->caldata; -		if ((caldata->chanmode == CHANNEL_G_HT40PLUS) && +		if (IS_CHAN_HT40PLUS(ah->curchan) &&  		    (ah->curchan->channel > caldata->channel) &&  		    (ah->curchan->channel <= caldata->channel + 20))  			return; -		if ((caldata->chanmode == CHANNEL_G_HT40MINUS) && +		if (IS_CHAN_HT40MINUS(ah->curchan) &&  		    (ah->curchan->channel < caldata->channel) &&  		    (ah->curchan->channel >= caldata->channel - 20))  			return; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index d089a7cf01c..4dec09e565e 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -87,6 +87,19 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {  	{ PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */  	{ PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI   */  	{ PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */ + +	/* Killer Wireless (3x3) */ +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0030, +			 0x1A56, +			 0x2000), +	  .driver_data = ATH9K_PCI_KILLER }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0030, +			 0x1A56, +			 0x2001), +	  .driver_data = ATH9K_PCI_KILLER }, +  	{ PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E  AR9300 */  	/* PCI-E CUS198 */ @@ -195,6 +208,93 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {  			 0x3219),  	  .driver_data = ATH9K_PCI_BT_ANT_DIV }, +	/* AR9485 cards with PLL power-save disabled by default. */ +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0032, +			 PCI_VENDOR_ID_AZWAVE, +			 0x2C97), +	  .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0032, +			 PCI_VENDOR_ID_AZWAVE, +			 0x2100), +	  .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0032, +			 0x1C56, /* ASKEY */ +			 0x4001), +	  .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0032, +			 0x11AD, /* LITEON */ +			 0x6627), +	  .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0032, +			 0x11AD, /* LITEON */ +			 0x6628), +	  .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0032, +			 PCI_VENDOR_ID_FOXCONN, +			 0xE04E), +	  .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0032, +			 PCI_VENDOR_ID_FOXCONN, +			 0xE04F), +	  .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0032, +			 0x144F, /* ASKEY */ +			 0x7197), +	  .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0032, +			 0x1B9A, /* XAVI */ +			 0x2000), +	  .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0032, +			 0x1B9A, /* XAVI */ +			 0x2001), +	  .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0032, +			 PCI_VENDOR_ID_AZWAVE, +			 0x1186), +	  .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0032, +			 PCI_VENDOR_ID_AZWAVE, +			 0x1F86), +	  .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0032, +			 PCI_VENDOR_ID_AZWAVE, +			 0x1195), +	  .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0032, +			 PCI_VENDOR_ID_AZWAVE, +			 0x1F95), +	  .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0032, +			 0x1B9A, /* XAVI */ +			 0x1C00), +	  .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0032, +			 0x1B9A, /* XAVI */ +			 0x1C01), +	  .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0032, +			 PCI_VENDOR_ID_ASUSTEK, +			 0x850D), +	  .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, +  	{ PCI_VDEVICE(ATHEROS, 0x0032) }, /* PCI-E  AR9485 */  	{ PCI_VDEVICE(ATHEROS, 0x0033) }, /* PCI-E  AR9580 */ @@ -267,9 +367,297 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {  			 0x1783),  	  .driver_data = ATH9K_PCI_WOW }, +	/* Killer Wireless (2x2) */ +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0030, +			 0x1A56, +			 0x2003), +	  .driver_data = ATH9K_PCI_KILLER }, +  	{ PCI_VDEVICE(ATHEROS, 0x0034) }, /* PCI-E  AR9462 */  	{ PCI_VDEVICE(ATHEROS, 0x0037) }, /* PCI-E  AR1111/AR9485 */ -	{ PCI_VDEVICE(ATHEROS, 0x0036) }, /* PCI-E  AR9565 */ + +	/* CUS252 */ +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_ATHEROS, +			 0x3028), +	  .driver_data = ATH9K_PCI_CUS252 | +			 ATH9K_PCI_AR9565_2ANT | +			 ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_AZWAVE, +			 0x2176), +	  .driver_data = ATH9K_PCI_CUS252 | +			 ATH9K_PCI_AR9565_2ANT | +			 ATH9K_PCI_BT_ANT_DIV }, + +	/* WB335 1-ANT */ +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_FOXCONN, +			 0xE068), +	  .driver_data = ATH9K_PCI_AR9565_1ANT }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x185F, /* WNC */ +			 0xA119), +	  .driver_data = ATH9K_PCI_AR9565_1ANT }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x11AD, /* LITEON */ +			 0x0632), +	  .driver_data = ATH9K_PCI_AR9565_1ANT }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x11AD, /* LITEON */ +			 0x06B2), +	  .driver_data = ATH9K_PCI_AR9565_1ANT }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x11AD, /* LITEON */ +			 0x0842), +	  .driver_data = ATH9K_PCI_AR9565_1ANT }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x11AD, /* LITEON */ +			 0x6671), +	  .driver_data = ATH9K_PCI_AR9565_1ANT }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x1B9A, /* XAVI */ +			 0x2811), +	  .driver_data = ATH9K_PCI_AR9565_1ANT }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x1B9A, /* XAVI */ +			 0x2812), +	  .driver_data = ATH9K_PCI_AR9565_1ANT }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x1B9A, /* XAVI */ +			 0x28A1), +	  .driver_data = ATH9K_PCI_AR9565_1ANT }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_AZWAVE, +			 0x218A), +	  .driver_data = ATH9K_PCI_AR9565_1ANT }, + +	/* WB335 1-ANT / Antenna Diversity */ +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_ATHEROS, +			 0x3025), +	  .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_ATHEROS, +			 0x3026), +	  .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_ATHEROS, +			 0x302B), +	  .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_FOXCONN, +			 0xE069), +	  .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x185F, /* WNC */ +			 0x3028), +	  .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x11AD, /* LITEON */ +			 0x0622), +	  .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x11AD, /* LITEON */ +			 0x0672), +	  .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x11AD, /* LITEON */ +			 0x0662), +	  .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x11AD, /* LITEON */ +			 0x06A2), +	  .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x11AD, /* LITEON */ +			 0x0682), +	  .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_AZWAVE, +			 0x213A), +	  .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_HP, +			 0x18E3), +	  .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_HP, +			 0x217F), +	  .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_HP, +			 0x2005), +	  .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_DELL, +			 0x020C), +	  .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, + +	/* WB335 2-ANT / Antenna-Diversity */ +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_SAMSUNG, +			 0x411A), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_SAMSUNG, +			 0x411B), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_SAMSUNG, +			 0x411C), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_SAMSUNG, +			 0x411D), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_SAMSUNG, +			 0x411E), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_ATHEROS, +			 0x3027), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_ATHEROS, +			 0x302C), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x11AD, /* LITEON */ +			 0x0642), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x11AD, /* LITEON */ +			 0x0652), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x11AD, /* LITEON */ +			 0x0612), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x11AD, /* LITEON */ +			 0x0832), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x11AD, /* LITEON */ +			 0x0692), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_AZWAVE, +			 0x2130), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_AZWAVE, +			 0x213B), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_AZWAVE, +			 0x2182), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x144F, /* ASKEY */ +			 0x7202), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x1B9A, /* XAVI */ +			 0x2810), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x1B9A, /* XAVI */ +			 0x28A2), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x185F, /* WNC */ +			 0x3027), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 0x185F, /* WNC */ +			 0xA120), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_FOXCONN, +			 0xE07F), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_FOXCONN, +			 0xE081), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_LENOVO, +			 0x3026), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_LENOVO, +			 0x4026), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_ASUSTEK, +			 0x85F2), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +			 0x0036, +			 PCI_VENDOR_ID_DELL, +			 0x020E), +	  .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + +	/* PCI-E AR9565 (WB335) */ +	{ PCI_VDEVICE(ATHEROS, 0x0036), +	  .driver_data = ATH9K_PCI_BT_ANT_DIV }, +  	{ 0 }  }; @@ -298,7 +686,7 @@ static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data)  	struct ath_softc *sc = (struct ath_softc *) common->priv;  	struct ath9k_platform_data *pdata = sc->dev->platform_data; -	if (pdata) { +	if (pdata && !pdata->use_eeprom) {  		if (off >= (ARRAY_SIZE(pdata->eeprom_data))) {  			ath_err(common,  				"%s: eeprom read failed, offset %08x is out of range\n", @@ -470,9 +858,6 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)  	sc->mem = pcim_iomap_table(pdev)[0];  	sc->driver_data = id->driver_data; -	/* Will be cleared in ath9k_start() */ -	set_bit(SC_OP_INVALID, &sc->sc_flags); -  	ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc);  	if (ret) {  		dev_err(&pdev->dev, "request_irq failed\n"); @@ -529,6 +914,7 @@ static int ath_pci_suspend(struct device *device)  	 */  	ath9k_stop_btcoex(sc);  	ath9k_hw_disable(sc->sc_ah); +	del_timer_sync(&sc->sleep_timer);  	ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP);  	return 0; diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c deleted file mode 100644 index d3d7c51fa6c..00000000000 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ /dev/null @@ -1,1495 +0,0 @@ -/* - * Copyright (c) 2004 Video54 Technologies, Inc. - * Copyright (c) 2004-2011 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <linux/slab.h> -#include <linux/export.h> - -#include "ath9k.h" - -static const struct ath_rate_table ar5416_11na_ratetable = { -	68, -	8, /* MCS start */ -	{ -		[0] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 6000, -			5400, 0, 12 }, /* 6 Mb */ -		[1] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 9000, -			7800,  1, 18 }, /* 9 Mb */ -		[2] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, -			10000, 2, 24 }, /* 12 Mb */ -		[3] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, -			13900, 3, 36 }, /* 18 Mb */ -		[4] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, -			17300, 4, 48 }, /* 24 Mb */ -		[5] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, -			23000, 5, 72 }, /* 36 Mb */ -		[6] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, -			27400, 6, 96 }, /* 48 Mb */ -		[7] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, -			29300, 7, 108 }, /* 54 Mb */ -		[8] = { RC_HT_SDT_2040, WLAN_RC_PHY_HT_20_SS, 6500, -			6400, 0, 0 }, /* 6.5 Mb */ -		[9] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 13000, -			12700, 1, 1 }, /* 13 Mb */ -		[10] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 19500, -			18800, 2, 2 }, /* 19.5 Mb */ -		[11] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 26000, -			25000, 3, 3 }, /* 26 Mb */ -		[12] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 39000, -			36700, 4, 4 }, /* 39 Mb */ -		[13] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 52000, -			48100, 5, 5 }, /* 52 Mb */ -		[14] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 58500, -			53500, 6, 6 }, /* 58.5 Mb */ -		[15] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 65000, -			59000, 7, 7 }, /* 65 Mb */ -		[16] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS_HGI, 72200, -			65400, 7, 7 }, /* 75 Mb */ -		[17] = { RC_INVALID, WLAN_RC_PHY_HT_20_DS, 13000, -			12700, 8, 8 }, /* 13 Mb */ -		[18] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 26000, -			24800, 9, 9 }, /* 26 Mb */ -		[19] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 39000, -			36600, 10, 10 }, /* 39 Mb */ -		[20] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 52000, -			48100, 11, 11 }, /* 52 Mb */ -		[21] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 78000, -			69500, 12, 12 }, /* 78 Mb */ -		[22] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 104000, -			89500, 13, 13 }, /* 104 Mb */ -		[23] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 117000, -			98900, 14, 14 }, /* 117 Mb */ -		[24] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 130000, -			108300, 15, 15 }, /* 130 Mb */ -		[25] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS_HGI, 144400, -			120000, 15, 15 }, /* 144.4 Mb */ -		[26] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 19500, -			17400, 16, 16 }, /* 19.5 Mb */ -		[27] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 39000, -			35100, 17, 17 }, /* 39 Mb */ -		[28] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 58500, -			52600, 18, 18 }, /* 58.5 Mb */ -		[29] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 78000, -			70400, 19, 19 }, /* 78 Mb */ -		[30] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 117000, -			104900, 20, 20 }, /* 117 Mb */ -		[31] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS_HGI, 130000, -			115800, 20, 20 }, /* 130 Mb*/ -		[32] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 156000, -			137200, 21, 21 }, /* 156 Mb */ -		[33] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 173300, -			151100, 21, 21 }, /* 173.3 Mb */ -		[34] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 175500, -			152800, 22, 22 }, /* 175.5 Mb */ -		[35] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 195000, -			168400, 22, 22 }, /* 195 Mb*/ -		[36] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 195000, -			168400, 23, 23 }, /* 195 Mb */ -		[37] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 216700, -			185000, 23, 23 }, /* 216.7 Mb */ -		[38] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 13500, -			13200, 0, 0 }, /* 13.5 Mb*/ -		[39] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 27500, -			25900, 1, 1 }, /* 27.0 Mb*/ -		[40] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 40500, -			38600, 2, 2 }, /* 40.5 Mb*/ -		[41] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 54000, -			49800, 3, 3 }, /* 54 Mb */ -		[42] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 81500, -			72200, 4, 4 }, /* 81 Mb */ -		[43] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 108000, -			92900, 5, 5 }, /* 108 Mb */ -		[44] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 121500, -			102700, 6, 6 }, /* 121.5 Mb*/ -		[45] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 135000, -			112000, 7, 7 }, /* 135 Mb */ -		[46] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, -			122000, 7, 7 }, /* 150 Mb */ -		[47] = { RC_INVALID, WLAN_RC_PHY_HT_40_DS, 27000, -			25800, 8, 8 }, /* 27 Mb */ -		[48] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 54000, -			49800, 9, 9 }, /* 54 Mb */ -		[49] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 81000, -			71900, 10, 10 }, /* 81 Mb */ -		[50] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 108000, -			92500, 11, 11 }, /* 108 Mb */ -		[51] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 162000, -			130300, 12, 12 }, /* 162 Mb */ -		[52] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 216000, -			162800, 13, 13 }, /* 216 Mb */ -		[53] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 243000, -			178200, 14, 14 }, /* 243 Mb */ -		[54] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 270000, -			192100, 15, 15 }, /* 270 Mb */ -		[55] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS_HGI, 300000, -			207000, 15, 15 }, /* 300 Mb */ -		[56] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 40500, -			36100, 16, 16 }, /* 40.5 Mb */ -		[57] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 81000, -			72900, 17, 17 }, /* 81 Mb */ -		[58] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 121500, -			108300, 18, 18 }, /* 121.5 Mb */ -		[59] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 162000, -			142000, 19, 19 }, /*  162 Mb */ -		[60] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000, -			205100, 20, 20 }, /*  243 Mb */ -		[61] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000, -			224700, 20, 20 }, /*  270 Mb */ -		[62] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000, -			263100, 21, 21 }, /*  324 Mb */ -		[63] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000, -			288000, 21, 21 }, /*  360 Mb */ -		[64] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 364500, -			290700, 22, 22 }, /* 364.5 Mb */ -		[65] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 405000, -			317200, 22, 22 }, /* 405 Mb */ -		[66] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 405000, -			317200, 23, 23 }, /* 405 Mb */ -		[67] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 450000, -			346400, 23, 23 }, /* 450 Mb */ -	}, -	50,  /* probe interval */ -	WLAN_RC_HT_FLAG,  /* Phy rates allowed initially */ -}; - -/* 4ms frame limit not used for NG mode.  The values filled - * for HT are the 64K max aggregate limit */ - -static const struct ath_rate_table ar5416_11ng_ratetable = { -	72, -	12, /* MCS start */ -	{ -		[0] = { RC_ALL, WLAN_RC_PHY_CCK, 1000, -			900, 0, 2 }, /* 1 Mb */ -		[1] = { RC_ALL, WLAN_RC_PHY_CCK, 2000, -			1900, 1, 4 }, /* 2 Mb */ -		[2] = { RC_ALL, WLAN_RC_PHY_CCK, 5500, -			4900, 2, 11 }, /* 5.5 Mb */ -		[3] = { RC_ALL, WLAN_RC_PHY_CCK, 11000, -			8100, 3, 22 }, /* 11 Mb */ -		[4] = { RC_INVALID, WLAN_RC_PHY_OFDM, 6000, -			5400, 4, 12 }, /* 6 Mb */ -		[5] = { RC_INVALID, WLAN_RC_PHY_OFDM, 9000, -			7800, 5, 18 }, /* 9 Mb */ -		[6] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, -			10100, 6, 24 }, /* 12 Mb */ -		[7] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, -			14100, 7, 36 }, /* 18 Mb */ -		[8] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, -			17700, 8, 48 }, /* 24 Mb */ -		[9] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, -			23700, 9, 72 }, /* 36 Mb */ -		[10] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, -			27400, 10, 96 }, /* 48 Mb */ -		[11] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, -			30900, 11, 108 }, /* 54 Mb */ -		[12] = { RC_INVALID, WLAN_RC_PHY_HT_20_SS, 6500, -			6400, 0, 0 }, /* 6.5 Mb */ -		[13] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 13000, -			12700, 1, 1 }, /* 13 Mb */ -		[14] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 19500, -			18800, 2, 2 }, /* 19.5 Mb*/ -		[15] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 26000, -			25000, 3, 3 }, /* 26 Mb */ -		[16] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 39000, -			36700, 4, 4 }, /* 39 Mb */ -		[17] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 52000, -			48100, 5, 5 }, /* 52 Mb */ -		[18] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 58500, -			53500, 6, 6 }, /* 58.5 Mb */ -		[19] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 65000, -			59000, 7, 7 }, /* 65 Mb */ -		[20] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS_HGI, 72200, -			65400, 7, 7 }, /* 65 Mb*/ -		[21] = { RC_INVALID, WLAN_RC_PHY_HT_20_DS, 13000, -			12700, 8, 8 }, /* 13 Mb */ -		[22] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 26000, -			24800, 9, 9 }, /* 26 Mb */ -		[23] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 39000, -			36600, 10, 10 }, /* 39 Mb */ -		[24] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 52000, -			48100, 11, 11 }, /* 52 Mb */ -		[25] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 78000, -			69500, 12, 12 }, /* 78 Mb */ -		[26] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 104000, -			89500, 13, 13 }, /* 104 Mb */ -		[27] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 117000, -			98900, 14, 14 }, /* 117 Mb */ -		[28] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 130000, -			108300, 15, 15 }, /* 130 Mb */ -		[29] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS_HGI, 144400, -			120000, 15, 15 }, /* 144.4 Mb */ -		[30] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 19500, -			17400, 16, 16 }, /* 19.5 Mb */ -		[31] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 39000, -			35100, 17, 17 }, /* 39 Mb */ -		[32] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 58500, -			52600, 18, 18 }, /* 58.5 Mb */ -		[33] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 78000, -			70400, 19, 19 }, /* 78 Mb */ -		[34] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 117000, -			104900, 20, 20 }, /* 117 Mb */ -		[35] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS_HGI, 130000, -			115800, 20, 20 }, /* 130 Mb */ -		[36] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 156000, -			137200, 21, 21 }, /* 156 Mb */ -		[37] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 173300, -			151100, 21, 21 }, /* 173.3 Mb */ -		[38] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 175500, -			152800, 22, 22 }, /* 175.5 Mb */ -		[39] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 195000, -			168400, 22, 22 }, /* 195 Mb */ -		[40] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 195000, -			168400, 23, 23 }, /* 195 Mb */ -		[41] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 216700, -			185000, 23, 23 }, /* 216.7 Mb */ -		[42] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 13500, -			13200, 0, 0 }, /* 13.5 Mb */ -		[43] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 27500, -			25900, 1, 1 }, /* 27.0 Mb */ -		[44] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 40500, -			38600, 2, 2 }, /* 40.5 Mb */ -		[45] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 54000, -			49800, 3, 3 }, /* 54 Mb */ -		[46] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 81500, -			72200, 4, 4 }, /* 81 Mb */ -		[47] = { RC_HT_S_40 , WLAN_RC_PHY_HT_40_SS, 108000, -			92900, 5, 5 }, /* 108 Mb */ -		[48] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 121500, -			102700, 6, 6 }, /* 121.5 Mb */ -		[49] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 135000, -			112000, 7, 7 }, /* 135 Mb */ -		[50] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, -			122000, 7, 7 }, /* 150 Mb */ -		[51] = { RC_INVALID, WLAN_RC_PHY_HT_40_DS, 27000, -			25800, 8, 8 }, /* 27 Mb */ -		[52] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 54000, -			49800, 9, 9 }, /* 54 Mb */ -		[53] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 81000, -			71900, 10, 10 }, /* 81 Mb */ -		[54] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 108000, -			92500, 11, 11 }, /* 108 Mb */ -		[55] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 162000, -			130300, 12, 12 }, /* 162 Mb */ -		[56] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 216000, -			162800, 13, 13 }, /* 216 Mb */ -		[57] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 243000, -			178200, 14, 14 }, /* 243 Mb */ -		[58] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 270000, -			192100, 15, 15 }, /* 270 Mb */ -		[59] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS_HGI, 300000, -			207000, 15, 15 }, /* 300 Mb */ -		[60] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 40500, -			36100, 16, 16 }, /* 40.5 Mb */ -		[61] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 81000, -			72900, 17, 17 }, /* 81 Mb */ -		[62] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 121500, -			108300, 18, 18 }, /* 121.5 Mb */ -		[63] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 162000, -			142000, 19, 19 }, /* 162 Mb */ -		[64] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000, -			205100, 20, 20 }, /* 243 Mb */ -		[65] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000, -			224700, 20, 20 }, /* 270 Mb */ -		[66] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000, -			263100, 21, 21 }, /* 324 Mb */ -		[67] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000, -			288000, 21, 21 }, /* 360 Mb */ -		[68] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 364500, -			290700, 22, 22 }, /* 364.5 Mb */ -		[69] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 405000, -			317200, 22, 22 }, /* 405 Mb */ -		[70] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 405000, -			317200, 23, 23 }, /* 405 Mb */ -		[71] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 450000, -			346400, 23, 23 }, /* 450 Mb */ -	}, -	50,  /* probe interval */ -	WLAN_RC_HT_FLAG,  /* Phy rates allowed initially */ -}; - -static const struct ath_rate_table ar5416_11a_ratetable = { -	8, -	0, -	{ -		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ -			5400, 0, 12}, -		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ -			7800,  1, 18}, -		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ -			10000, 2, 24}, -		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ -			13900, 3, 36}, -		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ -			17300, 4, 48}, -		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ -			23000, 5, 72}, -		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ -			27400, 6, 96}, -		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ -			29300, 7, 108}, -	}, -	50,  /* probe interval */ -	0,   /* Phy rates allowed initially */ -}; - -static const struct ath_rate_table ar5416_11g_ratetable = { -	12, -	0, -	{ -		{ RC_L_SDT, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ -			900, 0, 2}, -		{ RC_L_SDT, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ -			1900, 1, 4}, -		{ RC_L_SDT, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ -			4900, 2, 11}, -		{ RC_L_SDT, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ -			8100, 3, 22}, -		{ RC_INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ -			5400, 4, 12}, -		{ RC_INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ -			7800, 5, 18}, -		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ -			10000, 6, 24}, -		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ -			13900, 7, 36}, -		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ -			17300, 8, 48}, -		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ -			23000, 9, 72}, -		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ -			27400, 10, 96}, -		{ RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ -			29300, 11, 108}, -	}, -	50,  /* probe interval */ -	0,   /* Phy rates allowed initially */ -}; - -static int ath_rc_get_rateindex(struct ath_rate_priv *ath_rc_priv, -				struct ieee80211_tx_rate *rate) -{ -	const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; -	int rix, i, idx = 0; - -	if (!(rate->flags & IEEE80211_TX_RC_MCS)) -		return rate->idx; - -	for (i = 0; i < ath_rc_priv->max_valid_rate; i++) { -		idx = ath_rc_priv->valid_rate_index[i]; - -		if (WLAN_RC_PHY_HT(rate_table->info[idx].phy) && -		    rate_table->info[idx].ratecode == rate->idx) -			break; -	} - -	rix = idx; - -	if (rate->flags & IEEE80211_TX_RC_SHORT_GI) -		rix++; - -	return rix; -} - -static void ath_rc_sort_validrates(struct ath_rate_priv *ath_rc_priv) -{ -	const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; -	u8 i, j, idx, idx_next; - -	for (i = ath_rc_priv->max_valid_rate - 1; i > 0; i--) { -		for (j = 0; j <= i-1; j++) { -			idx = ath_rc_priv->valid_rate_index[j]; -			idx_next = ath_rc_priv->valid_rate_index[j+1]; - -			if (rate_table->info[idx].ratekbps > -				rate_table->info[idx_next].ratekbps) { -				ath_rc_priv->valid_rate_index[j] = idx_next; -				ath_rc_priv->valid_rate_index[j+1] = idx; -			} -		} -	} -} - -static inline -int ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table, -				struct ath_rate_priv *ath_rc_priv, -				u8 cur_valid_txrate, -				u8 *next_idx) -{ -	u8 i; - -	for (i = 0; i < ath_rc_priv->max_valid_rate - 1; i++) { -		if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) { -			*next_idx = ath_rc_priv->valid_rate_index[i+1]; -			return 1; -		} -	} - -	/* No more valid rates */ -	*next_idx = 0; - -	return 0; -} - -/* Return true only for single stream */ - -static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw) -{ -	if (WLAN_RC_PHY_HT(phy) && !(capflag & WLAN_RC_HT_FLAG)) -		return 0; -	if (WLAN_RC_PHY_DS(phy) && !(capflag & WLAN_RC_DS_FLAG)) -		return 0; -	if (WLAN_RC_PHY_TS(phy) && !(capflag & WLAN_RC_TS_FLAG)) -		return 0; -	if (WLAN_RC_PHY_SGI(phy) && !(capflag & WLAN_RC_SGI_FLAG)) -		return 0; -	if (!ignore_cw && WLAN_RC_PHY_HT(phy)) -		if (WLAN_RC_PHY_40(phy) && !(capflag & WLAN_RC_40_FLAG)) -			return 0; -	return 1; -} - -static inline int -ath_rc_get_lower_rix(struct ath_rate_priv *ath_rc_priv, -		     u8 cur_valid_txrate, u8 *next_idx) -{ -	int8_t i; - -	for (i = 1; i < ath_rc_priv->max_valid_rate ; i++) { -		if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) { -			*next_idx = ath_rc_priv->valid_rate_index[i-1]; -			return 1; -		} -	} - -	return 0; -} - -static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv) -{ -	const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; -	u8 i, hi = 0; - -	for (i = 0; i < rate_table->rate_cnt; i++) { -		if (rate_table->info[i].rate_flags & RC_LEGACY) { -			u32 phy = rate_table->info[i].phy; -			u8 valid_rate_count = 0; - -			if (!ath_rc_valid_phyrate(phy, ath_rc_priv->ht_cap, 0)) -				continue; - -			valid_rate_count = ath_rc_priv->valid_phy_ratecnt[phy]; - -			ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = i; -			ath_rc_priv->valid_phy_ratecnt[phy] += 1; -			ath_rc_priv->valid_rate_index[i] = true; -			hi = i; -		} -	} - -	return hi; -} - -static inline bool ath_rc_check_legacy(u8 rate, u8 dot11rate, u16 rate_flags, -				       u32 phy, u32 capflag) -{ -	if (rate != dot11rate || WLAN_RC_PHY_HT(phy)) -		return false; - -	if ((rate_flags & WLAN_RC_CAP_MODE(capflag)) != WLAN_RC_CAP_MODE(capflag)) -		return false; - -	if (!(rate_flags & WLAN_RC_CAP_STREAM(capflag))) -		return false; - -	return true; -} - -static inline bool ath_rc_check_ht(u8 rate, u8 dot11rate, u16 rate_flags, -				   u32 phy, u32 capflag) -{ -	if (rate != dot11rate || !WLAN_RC_PHY_HT(phy)) -		return false; - -	if (!WLAN_RC_PHY_HT_VALID(rate_flags, capflag)) -		return false; - -	if (!(rate_flags & WLAN_RC_CAP_STREAM(capflag))) -		return false; - -	return true; -} - -static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, bool legacy) -{ -	const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; -	struct ath_rateset *rateset; -	u32 phy, capflag = ath_rc_priv->ht_cap; -	u16 rate_flags; -	u8 i, j, hi = 0, rate, dot11rate, valid_rate_count; - -	if (legacy) -		rateset = &ath_rc_priv->neg_rates; -	else -		rateset = &ath_rc_priv->neg_ht_rates; - -	for (i = 0; i < rateset->rs_nrates; i++) { -		for (j = 0; j < rate_table->rate_cnt; j++) { -			phy = rate_table->info[j].phy; -			rate_flags = rate_table->info[j].rate_flags; -			rate = rateset->rs_rates[i]; -			dot11rate = rate_table->info[j].dot11rate; - -			if (legacy && -			    !ath_rc_check_legacy(rate, dot11rate, -						 rate_flags, phy, capflag)) -				continue; - -			if (!legacy && -			    !ath_rc_check_ht(rate, dot11rate, -					     rate_flags, phy, capflag)) -				continue; - -			if (!ath_rc_valid_phyrate(phy, capflag, 0)) -				continue; - -			valid_rate_count = ath_rc_priv->valid_phy_ratecnt[phy]; -			ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = j; -			ath_rc_priv->valid_phy_ratecnt[phy] += 1; -			ath_rc_priv->valid_rate_index[j] = true; -			hi = max(hi, j); -		} -	} - -	return hi; -} - -static u8 ath_rc_get_highest_rix(struct ath_rate_priv *ath_rc_priv, -				 int *is_probing) -{ -	const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; -	u32 best_thruput, this_thruput, now_msec; -	u8 rate, next_rate, best_rate, maxindex, minindex; -	int8_t index = 0; - -	now_msec = jiffies_to_msecs(jiffies); -	*is_probing = 0; -	best_thruput = 0; -	maxindex = ath_rc_priv->max_valid_rate-1; -	minindex = 0; -	best_rate = minindex; - -	/* -	 * Try the higher rate first. It will reduce memory moving time -	 * if we have very good channel characteristics. -	 */ -	for (index = maxindex; index >= minindex ; index--) { -		u8 per_thres; - -		rate = ath_rc_priv->valid_rate_index[index]; -		if (rate > ath_rc_priv->rate_max_phy) -			continue; - -		/* -		 * For TCP the average collision rate is around 11%, -		 * so we ignore PERs less than this.  This is to -		 * prevent the rate we are currently using (whose -		 * PER might be in the 10-15 range because of TCP -		 * collisions) looking worse than the next lower -		 * rate whose PER has decayed close to 0.  If we -		 * used to next lower rate, its PER would grow to -		 * 10-15 and we would be worse off then staying -		 * at the current rate. -		 */ -		per_thres = ath_rc_priv->per[rate]; -		if (per_thres < 12) -			per_thres = 12; - -		this_thruput = rate_table->info[rate].user_ratekbps * -			(100 - per_thres); - -		if (best_thruput <= this_thruput) { -			best_thruput = this_thruput; -			best_rate    = rate; -		} -	} - -	rate = best_rate; - -	/* -	 * Must check the actual rate (ratekbps) to account for -	 * non-monoticity of 11g's rate table -	 */ - -	if (rate >= ath_rc_priv->rate_max_phy) { -		rate = ath_rc_priv->rate_max_phy; - -		/* Probe the next allowed phy state */ -		if (ath_rc_get_nextvalid_txrate(rate_table, -					ath_rc_priv, rate, &next_rate) && -		    (now_msec - ath_rc_priv->probe_time > -		     rate_table->probe_interval) && -		    (ath_rc_priv->hw_maxretry_pktcnt >= 1)) { -			rate = next_rate; -			ath_rc_priv->probe_rate = rate; -			ath_rc_priv->probe_time = now_msec; -			ath_rc_priv->hw_maxretry_pktcnt = 0; -			*is_probing = 1; -		} -	} - -	if (rate > (ath_rc_priv->rate_table_size - 1)) -		rate = ath_rc_priv->rate_table_size - 1; - -	if (RC_TS_ONLY(rate_table->info[rate].rate_flags) && -	    (ath_rc_priv->ht_cap & WLAN_RC_TS_FLAG)) -		return rate; - -	if (RC_DS_OR_LATER(rate_table->info[rate].rate_flags) && -	    (ath_rc_priv->ht_cap & (WLAN_RC_DS_FLAG | WLAN_RC_TS_FLAG))) -		return rate; - -	if (RC_SS_OR_LEGACY(rate_table->info[rate].rate_flags)) -		return rate; - -	/* This should not happen */ -	WARN_ON_ONCE(1); - -	rate = ath_rc_priv->valid_rate_index[0]; - -	return rate; -} - -static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table, -				   struct ieee80211_tx_rate *rate, -				   struct ieee80211_tx_rate_control *txrc, -				   u8 tries, u8 rix, int rtsctsenable) -{ -	rate->count = tries; -	rate->idx = rate_table->info[rix].ratecode; - -	if (txrc->rts || rtsctsenable) -		rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; - -	if (WLAN_RC_PHY_HT(rate_table->info[rix].phy)) { -		rate->flags |= IEEE80211_TX_RC_MCS; -		if (WLAN_RC_PHY_40(rate_table->info[rix].phy) && -		    conf_is_ht40(&txrc->hw->conf)) -			rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; -		if (WLAN_RC_PHY_SGI(rate_table->info[rix].phy)) -			rate->flags |= IEEE80211_TX_RC_SHORT_GI; -	} -} - -static void ath_rc_rate_set_rtscts(struct ath_softc *sc, -				   const struct ath_rate_table *rate_table, -				   struct ieee80211_tx_info *tx_info) -{ -	struct ieee80211_bss_conf *bss_conf; - -	if (!tx_info->control.vif) -		return; -	/* -	 * For legacy frames, mac80211 takes care of CTS protection. -	 */ -	if (!(tx_info->control.rates[0].flags & IEEE80211_TX_RC_MCS)) -		return; - -	bss_conf = &tx_info->control.vif->bss_conf; - -	if (!bss_conf->basic_rates) -		return; - -	/* -	 * For now, use the lowest allowed basic rate for HT frames. -	 */ -	tx_info->control.rts_cts_rate_idx = __ffs(bss_conf->basic_rates); -} - -static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, -			 struct ieee80211_tx_rate_control *txrc) -{ -	struct ath_softc *sc = priv; -	struct ath_rate_priv *ath_rc_priv = priv_sta; -	const struct ath_rate_table *rate_table; -	struct sk_buff *skb = txrc->skb; -	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); -	struct ieee80211_tx_rate *rates = tx_info->control.rates; -	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; -	__le16 fc = hdr->frame_control; -	u8 try_per_rate, i = 0, rix; -	int is_probe = 0; - -	if (rate_control_send_low(sta, priv_sta, txrc)) -		return; - -	/* -	 * For Multi Rate Retry we use a different number of -	 * retry attempt counts. This ends up looking like this: -	 * -	 * MRR[0] = 4 -	 * MRR[1] = 4 -	 * MRR[2] = 4 -	 * MRR[3] = 8 -	 * -	 */ -	try_per_rate = 4; - -	rate_table = ath_rc_priv->rate_table; -	rix = ath_rc_get_highest_rix(ath_rc_priv, &is_probe); - -	if (conf_is_ht(&sc->hw->conf) && -	    (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING)) -		tx_info->flags |= IEEE80211_TX_CTL_LDPC; - -	if (conf_is_ht(&sc->hw->conf) && -	    (sta->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)) -		tx_info->flags |= (1 << IEEE80211_TX_CTL_STBC_SHIFT); - -	if (is_probe) { -		/* -		 * Set one try for probe rates. For the -		 * probes don't enable RTS. -		 */ -		ath_rc_rate_set_series(rate_table, &rates[i++], txrc, -				       1, rix, 0); -		/* -		 * Get the next tried/allowed rate. -		 * No RTS for the next series after the probe rate. -		 */ -		ath_rc_get_lower_rix(ath_rc_priv, rix, &rix); -		ath_rc_rate_set_series(rate_table, &rates[i++], txrc, -				       try_per_rate, rix, 0); - -		tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; -	} else { -		/* -		 * Set the chosen rate. No RTS for first series entry. -		 */ -		ath_rc_rate_set_series(rate_table, &rates[i++], txrc, -				       try_per_rate, rix, 0); -	} - -	for ( ; i < 4; i++) { -		/* -		 * Use twice the number of tries for the last MRR segment. -		 */ -		if (i + 1 == 4) -			try_per_rate = 8; - -		ath_rc_get_lower_rix(ath_rc_priv, rix, &rix); - -		/* -		 * All other rates in the series have RTS enabled. -		 */ -		ath_rc_rate_set_series(rate_table, &rates[i], txrc, -				       try_per_rate, rix, 1); -	} - -	/* -	 * NB:Change rate series to enable aggregation when operating -	 * at lower MCS rates. When first rate in series is MCS2 -	 * in HT40 @ 2.4GHz, series should look like: -	 * -	 * {MCS2, MCS1, MCS0, MCS0}. -	 * -	 * When first rate in series is MCS3 in HT20 @ 2.4GHz, series should -	 * look like: -	 * -	 * {MCS3, MCS2, MCS1, MCS1} -	 * -	 * So, set fourth rate in series to be same as third one for -	 * above conditions. -	 */ -	if ((sc->hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ) && -	    (conf_is_ht(&sc->hw->conf))) { -		u8 dot11rate = rate_table->info[rix].dot11rate; -		u8 phy = rate_table->info[rix].phy; -		if (i == 4 && -		    ((dot11rate == 2 && phy == WLAN_RC_PHY_HT_40_SS) || -		     (dot11rate == 3 && phy == WLAN_RC_PHY_HT_20_SS))) { -			rates[3].idx = rates[2].idx; -			rates[3].flags = rates[2].flags; -		} -	} - -	/* -	 * Force hardware to use computed duration for next -	 * fragment by disabling multi-rate retry, which -	 * updates duration based on the multi-rate duration table. -	 * -	 * FIXME: Fix duration -	 */ -	if (ieee80211_has_morefrags(fc) || -	    (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) { -		rates[1].count = rates[2].count = rates[3].count = 0; -		rates[1].idx = rates[2].idx = rates[3].idx = 0; -		rates[0].count = ATH_TXMAXTRY; -	} - -	ath_rc_rate_set_rtscts(sc, rate_table, tx_info); -} - -static void ath_rc_update_per(struct ath_softc *sc, -			      const struct ath_rate_table *rate_table, -			      struct ath_rate_priv *ath_rc_priv, -				  struct ieee80211_tx_info *tx_info, -			      int tx_rate, int xretries, int retries, -			      u32 now_msec) -{ -	int count, n_bad_frames; -	u8 last_per; -	static const u32 nretry_to_per_lookup[10] = { -		100 * 0 / 1, -		100 * 1 / 4, -		100 * 1 / 2, -		100 * 3 / 4, -		100 * 4 / 5, -		100 * 5 / 6, -		100 * 6 / 7, -		100 * 7 / 8, -		100 * 8 / 9, -		100 * 9 / 10 -	}; - -	last_per = ath_rc_priv->per[tx_rate]; -	n_bad_frames = tx_info->status.ampdu_len - tx_info->status.ampdu_ack_len; - -	if (xretries) { -		if (xretries == 1) { -			ath_rc_priv->per[tx_rate] += 30; -			if (ath_rc_priv->per[tx_rate] > 100) -				ath_rc_priv->per[tx_rate] = 100; -		} else { -			/* xretries == 2 */ -			count = ARRAY_SIZE(nretry_to_per_lookup); -			if (retries >= count) -				retries = count - 1; - -			/* new_PER = 7/8*old_PER + 1/8*(currentPER) */ -			ath_rc_priv->per[tx_rate] = -				(u8)(last_per - (last_per >> 3) + (100 >> 3)); -		} - -		/* xretries == 1 or 2 */ - -		if (ath_rc_priv->probe_rate == tx_rate) -			ath_rc_priv->probe_rate = 0; - -	} else { /* xretries == 0 */ -		count = ARRAY_SIZE(nretry_to_per_lookup); -		if (retries >= count) -			retries = count - 1; - -		if (n_bad_frames) { -			/* new_PER = 7/8*old_PER + 1/8*(currentPER) -			 * Assuming that n_frames is not 0.  The current PER -			 * from the retries is 100 * retries / (retries+1), -			 * since the first retries attempts failed, and the -			 * next one worked.  For the one that worked, -			 * n_bad_frames subframes out of n_frames wored, -			 * so the PER for that part is -			 * 100 * n_bad_frames / n_frames, and it contributes -			 * 100 * n_bad_frames / (n_frames * (retries+1)) to -			 * the above PER.  The expression below is a -			 * simplified version of the sum of these two terms. -			 */ -			if (tx_info->status.ampdu_len > 0) { -				int n_frames, n_bad_tries; -				u8 cur_per, new_per; - -				n_bad_tries = retries * tx_info->status.ampdu_len + -					n_bad_frames; -				n_frames = tx_info->status.ampdu_len * (retries + 1); -				cur_per = (100 * n_bad_tries / n_frames) >> 3; -				new_per = (u8)(last_per - (last_per >> 3) + cur_per); -				ath_rc_priv->per[tx_rate] = new_per; -			} -		} else { -			ath_rc_priv->per[tx_rate] = -				(u8)(last_per - (last_per >> 3) + -				     (nretry_to_per_lookup[retries] >> 3)); -		} - - -		/* -		 * If we got at most one retry then increase the max rate if -		 * this was a probe.  Otherwise, ignore the probe. -		 */ -		if (ath_rc_priv->probe_rate && ath_rc_priv->probe_rate == tx_rate) { -			if (retries > 0 || 2 * n_bad_frames > tx_info->status.ampdu_len) { -				/* -				 * Since we probed with just a single attempt, -				 * any retries means the probe failed.  Also, -				 * if the attempt worked, but more than half -				 * the subframes were bad then also consider -				 * the probe a failure. -				 */ -				ath_rc_priv->probe_rate = 0; -			} else { -				u8 probe_rate = 0; - -				ath_rc_priv->rate_max_phy = -					ath_rc_priv->probe_rate; -				probe_rate = ath_rc_priv->probe_rate; - -				if (ath_rc_priv->per[probe_rate] > 30) -					ath_rc_priv->per[probe_rate] = 20; - -				ath_rc_priv->probe_rate = 0; - -				/* -				 * Since this probe succeeded, we allow the next -				 * probe twice as soon.  This allows the maxRate -				 * to move up faster if the probes are -				 * successful. -				 */ -				ath_rc_priv->probe_time = -					now_msec - rate_table->probe_interval / 2; -			} -		} - -		if (retries > 0) { -			/* -			 * Don't update anything.  We don't know if -			 * this was because of collisions or poor signal. -			 */ -			ath_rc_priv->hw_maxretry_pktcnt = 0; -		} else { -			/* -			 * It worked with no retries. First ignore bogus (small) -			 * rssi_ack values. -			 */ -			if (tx_rate == ath_rc_priv->rate_max_phy && -			    ath_rc_priv->hw_maxretry_pktcnt < 255) { -				ath_rc_priv->hw_maxretry_pktcnt++; -			} - -		} -	} -} - -static void ath_rc_update_ht(struct ath_softc *sc, -			     struct ath_rate_priv *ath_rc_priv, -			     struct ieee80211_tx_info *tx_info, -			     int tx_rate, int xretries, int retries) -{ -	u32 now_msec = jiffies_to_msecs(jiffies); -	int rate; -	u8 last_per; -	const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; -	int size = ath_rc_priv->rate_table_size; - -	if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt)) -		return; - -	last_per = ath_rc_priv->per[tx_rate]; - -	/* Update PER first */ -	ath_rc_update_per(sc, rate_table, ath_rc_priv, -			  tx_info, tx_rate, xretries, -			  retries, now_msec); - -	/* -	 * If this rate looks bad (high PER) then stop using it for -	 * a while (except if we are probing). -	 */ -	if (ath_rc_priv->per[tx_rate] >= 55 && tx_rate > 0 && -	    rate_table->info[tx_rate].ratekbps <= -	    rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) { -		ath_rc_get_lower_rix(ath_rc_priv, (u8)tx_rate, -				     &ath_rc_priv->rate_max_phy); - -		/* Don't probe for a little while. */ -		ath_rc_priv->probe_time = now_msec; -	} - -	/* Make sure the rates below this have lower PER */ -	/* Monotonicity is kept only for rates below the current rate. */ -	if (ath_rc_priv->per[tx_rate] < last_per) { -		for (rate = tx_rate - 1; rate >= 0; rate--) { - -			if (ath_rc_priv->per[rate] > -			    ath_rc_priv->per[rate+1]) { -				ath_rc_priv->per[rate] = -					ath_rc_priv->per[rate+1]; -			} -		} -	} - -	/* Maintain monotonicity for rates above the current rate */ -	for (rate = tx_rate; rate < size - 1; rate++) { -		if (ath_rc_priv->per[rate+1] < -		    ath_rc_priv->per[rate]) -			ath_rc_priv->per[rate+1] = -				ath_rc_priv->per[rate]; -	} - -	/* Every so often, we reduce the thresholds -	 * and PER (different for CCK and OFDM). */ -	if (now_msec - ath_rc_priv->per_down_time >= -	    rate_table->probe_interval) { -		for (rate = 0; rate < size; rate++) { -			ath_rc_priv->per[rate] = -				7 * ath_rc_priv->per[rate] / 8; -		} - -		ath_rc_priv->per_down_time = now_msec; -	} - -	ath_debug_stat_retries(ath_rc_priv, tx_rate, xretries, retries, -			       ath_rc_priv->per[tx_rate]); - -} - -static void ath_rc_tx_status(struct ath_softc *sc, -			     struct ath_rate_priv *ath_rc_priv, -			     struct sk_buff *skb) -{ -	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); -	struct ieee80211_tx_rate *rates = tx_info->status.rates; -	struct ieee80211_tx_rate *rate; -	int final_ts_idx = 0, xretries = 0, long_retry = 0; -	u8 flags; -	u32 i = 0, rix; - -	for (i = 0; i < sc->hw->max_rates; i++) { -		rate = &tx_info->status.rates[i]; -		if (rate->idx < 0 || !rate->count) -			break; - -		final_ts_idx = i; -		long_retry = rate->count - 1; -	} - -	if (!(tx_info->flags & IEEE80211_TX_STAT_ACK)) -		xretries = 1; - -	/* -	 * If the first rate is not the final index, there -	 * are intermediate rate failures to be processed. -	 */ -	if (final_ts_idx != 0) { -		for (i = 0; i < final_ts_idx ; i++) { -			if (rates[i].count != 0 && (rates[i].idx >= 0)) { -				flags = rates[i].flags; - -				/* If HT40 and we have switched mode from -				 * 40 to 20 => don't update */ - -				if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && -				    !(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG)) -					return; - -				rix = ath_rc_get_rateindex(ath_rc_priv, &rates[i]); -				ath_rc_update_ht(sc, ath_rc_priv, tx_info, -						 rix, xretries ? 1 : 2, -						 rates[i].count); -			} -		} -	} - -	flags = rates[final_ts_idx].flags; - -	/* If HT40 and we have switched mode from 40 to 20 => don't update */ -	if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && -	    !(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG)) -		return; - -	rix = ath_rc_get_rateindex(ath_rc_priv, &rates[final_ts_idx]); -	ath_rc_update_ht(sc, ath_rc_priv, tx_info, rix, xretries, long_retry); -	ath_debug_stat_rc(ath_rc_priv, rix); -} - -static const -struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, -					     enum ieee80211_band band, -					     bool is_ht) -{ -	switch(band) { -	case IEEE80211_BAND_2GHZ: -		if (is_ht) -			return &ar5416_11ng_ratetable; -		return &ar5416_11g_ratetable; -	case IEEE80211_BAND_5GHZ: -		if (is_ht) -			return &ar5416_11na_ratetable; -		return &ar5416_11a_ratetable; -	default: -		return NULL; -	} -} - -static void ath_rc_init(struct ath_softc *sc, -			struct ath_rate_priv *ath_rc_priv) -{ -	const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; -	struct ath_rateset *rateset = &ath_rc_priv->neg_rates; -	struct ath_common *common = ath9k_hw_common(sc->sc_ah); -	u8 i, j, k, hi = 0, hthi = 0; - -	ath_rc_priv->rate_table_size = RATE_TABLE_SIZE; - -	for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) { -		ath_rc_priv->per[i] = 0; -		ath_rc_priv->valid_rate_index[i] = 0; -	} - -	for (i = 0; i < WLAN_RC_PHY_MAX; i++) { -		for (j = 0; j < RATE_TABLE_SIZE; j++) -			ath_rc_priv->valid_phy_rateidx[i][j] = 0; -		ath_rc_priv->valid_phy_ratecnt[i] = 0; -	} - -	if (!rateset->rs_nrates) { -		hi = ath_rc_init_validrates(ath_rc_priv); -	} else { -		hi = ath_rc_setvalid_rates(ath_rc_priv, true); - -		if (ath_rc_priv->ht_cap & WLAN_RC_HT_FLAG) -			hthi = ath_rc_setvalid_rates(ath_rc_priv, false); - -		hi = max(hi, hthi); -	} - -	ath_rc_priv->rate_table_size = hi + 1; -	ath_rc_priv->rate_max_phy = 0; -	WARN_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE); - -	for (i = 0, k = 0; i < WLAN_RC_PHY_MAX; i++) { -		for (j = 0; j < ath_rc_priv->valid_phy_ratecnt[i]; j++) { -			ath_rc_priv->valid_rate_index[k++] = -				ath_rc_priv->valid_phy_rateidx[i][j]; -		} - -		if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, 1) || -		    !ath_rc_priv->valid_phy_ratecnt[i]) -			continue; - -		ath_rc_priv->rate_max_phy = ath_rc_priv->valid_phy_rateidx[i][j-1]; -	} -	WARN_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE); -	WARN_ON(k > RATE_TABLE_SIZE); - -	ath_rc_priv->max_valid_rate = k; -	ath_rc_sort_validrates(ath_rc_priv); -	ath_rc_priv->rate_max_phy = (k > 4) ? -		ath_rc_priv->valid_rate_index[k-4] : -		ath_rc_priv->valid_rate_index[k-1]; - -	ath_dbg(common, CONFIG, "RC Initialized with capabilities: 0x%x\n", -		ath_rc_priv->ht_cap); -} - -static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta) -{ -	u8 caps = 0; - -	if (sta->ht_cap.ht_supported) { -		caps = WLAN_RC_HT_FLAG; -		if (sta->ht_cap.mcs.rx_mask[1] && sta->ht_cap.mcs.rx_mask[2]) -			caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG; -		else if (sta->ht_cap.mcs.rx_mask[1]) -			caps |= WLAN_RC_DS_FLAG; -		if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) { -			caps |= WLAN_RC_40_FLAG; -			if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) -				caps |= WLAN_RC_SGI_FLAG; -		} else { -			if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) -				caps |= WLAN_RC_SGI_FLAG; -		} -	} - -	return caps; -} - -static bool ath_tx_aggr_check(struct ath_softc *sc, struct ieee80211_sta *sta, -			      u8 tidno) -{ -	struct ath_node *an = (struct ath_node *)sta->drv_priv; -	struct ath_atx_tid *txtid; - -	if (!sta->ht_cap.ht_supported) -		return false; - -	txtid = ATH_AN_2_TID(an, tidno); -	return !txtid->active; -} - - -/***********************************/ -/* mac80211 Rate Control callbacks */ -/***********************************/ - -static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, -			  struct ieee80211_sta *sta, void *priv_sta, -			  struct sk_buff *skb) -{ -	struct ath_softc *sc = priv; -	struct ath_rate_priv *ath_rc_priv = priv_sta; -	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); -	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; -	__le16 fc = hdr->frame_control; - -	if (!priv_sta || !ieee80211_is_data(fc)) -		return; - -	/* This packet was aggregated but doesn't carry status info */ -	if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && -	    !(tx_info->flags & IEEE80211_TX_STAT_AMPDU)) -		return; - -	if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) -		return; - -	ath_rc_tx_status(sc, ath_rc_priv, skb); - -	/* Check if aggregation has to be enabled for this tid */ -	if (conf_is_ht(&sc->hw->conf) && -	    !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { -		if (ieee80211_is_data_qos(fc) && -		    skb_get_queue_mapping(skb) != IEEE80211_AC_VO) { -			u8 *qc, tid; - -			qc = ieee80211_get_qos_ctl(hdr); -			tid = qc[0] & 0xf; - -			if(ath_tx_aggr_check(sc, sta, tid)) -				ieee80211_start_tx_ba_session(sta, tid, 0); -		} -	} -} - -static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, -			  struct cfg80211_chan_def *chandef, -                          struct ieee80211_sta *sta, void *priv_sta) -{ -	struct ath_softc *sc = priv; -	struct ath_common *common = ath9k_hw_common(sc->sc_ah); -	struct ath_rate_priv *ath_rc_priv = priv_sta; -	int i, j = 0; -	u32 rate_flags = ieee80211_chandef_rate_flags(&sc->hw->conf.chandef); - -	for (i = 0; i < sband->n_bitrates; i++) { -		if (sta->supp_rates[sband->band] & BIT(i)) { -			if ((rate_flags & sband->bitrates[i].flags) -			    != rate_flags) -				continue; - -			ath_rc_priv->neg_rates.rs_rates[j] -				= (sband->bitrates[i].bitrate * 2) / 10; -			j++; -		} -	} -	ath_rc_priv->neg_rates.rs_nrates = j; - -	if (sta->ht_cap.ht_supported) { -		for (i = 0, j = 0; i < 77; i++) { -			if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8))) -				ath_rc_priv->neg_ht_rates.rs_rates[j++] = i; -			if (j == ATH_RATE_MAX) -				break; -		} -		ath_rc_priv->neg_ht_rates.rs_nrates = j; -	} - -	ath_rc_priv->rate_table = ath_choose_rate_table(sc, sband->band, -							sta->ht_cap.ht_supported); -	if (!ath_rc_priv->rate_table) { -		ath_err(common, "No rate table chosen\n"); -		return; -	} - -	ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta); -	ath_rc_init(sc, priv_sta); -} - -static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, -			    struct cfg80211_chan_def *chandef, -			    struct ieee80211_sta *sta, void *priv_sta, -			    u32 changed) -{ -	struct ath_softc *sc = priv; -	struct ath_rate_priv *ath_rc_priv = priv_sta; - -	if (changed & IEEE80211_RC_BW_CHANGED) { -		ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta); -		ath_rc_init(sc, priv_sta); - -		ath_dbg(ath9k_hw_common(sc->sc_ah), CONFIG, -			"Operating Bandwidth changed to: %d\n", -			sc->hw->conf.chandef.width); -	} -} - -#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) - -void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate) -{ -	struct ath_rc_stats *stats; - -	stats = &rc->rcstats[final_rate]; -	stats->success++; -} - -void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, -			    int xretries, int retries, u8 per) -{ -	struct ath_rc_stats *stats = &rc->rcstats[rix]; - -	stats->xretries += xretries; -	stats->retries += retries; -	stats->per = per; -} - -static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, -				size_t count, loff_t *ppos) -{ -	struct ath_rate_priv *rc = file->private_data; -	char *buf; -	unsigned int len = 0, max; -	int rix; -	ssize_t retval; - -	if (rc->rate_table == NULL) -		return 0; - -	max = 80 + rc->rate_table_size * 1024 + 1; -	buf = kmalloc(max, GFP_KERNEL); -	if (buf == NULL) -		return -ENOMEM; - -	len += sprintf(buf, "%6s %6s %6s " -		       "%10s %10s %10s %10s\n", -		       "HT", "MCS", "Rate", -		       "Success", "Retries", "XRetries", "PER"); - -	for (rix = 0; rix < rc->max_valid_rate; rix++) { -		u8 i = rc->valid_rate_index[rix]; -		u32 ratekbps = rc->rate_table->info[i].ratekbps; -		struct ath_rc_stats *stats = &rc->rcstats[i]; -		char mcs[5]; -		char htmode[5]; -		int used_mcs = 0, used_htmode = 0; - -		if (WLAN_RC_PHY_HT(rc->rate_table->info[i].phy)) { -			used_mcs = snprintf(mcs, 5, "%d", -				rc->rate_table->info[i].ratecode); - -			if (WLAN_RC_PHY_40(rc->rate_table->info[i].phy)) -				used_htmode = snprintf(htmode, 5, "HT40"); -			else if (WLAN_RC_PHY_20(rc->rate_table->info[i].phy)) -				used_htmode = snprintf(htmode, 5, "HT20"); -			else -				used_htmode = snprintf(htmode, 5, "????"); -		} - -		mcs[used_mcs] = '\0'; -		htmode[used_htmode] = '\0'; - -		len += snprintf(buf + len, max - len, -			"%6s %6s %3u.%d: " -			"%10u %10u %10u %10u\n", -			htmode, -			mcs, -			ratekbps / 1000, -			(ratekbps % 1000) / 100, -			stats->success, -			stats->retries, -			stats->xretries, -			stats->per); -	} - -	if (len > max) -		len = max; - -	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); -	kfree(buf); -	return retval; -} - -static const struct file_operations fops_rcstat = { -	.read = read_file_rcstat, -	.open = simple_open, -	.owner = THIS_MODULE -}; - -static void ath_rate_add_sta_debugfs(void *priv, void *priv_sta, -				     struct dentry *dir) -{ -	struct ath_rate_priv *rc = priv_sta; -	rc->debugfs_rcstats = debugfs_create_file("rc_stats", S_IRUGO, -						  dir, rc, &fops_rcstat); -} - -static void ath_rate_remove_sta_debugfs(void *priv, void *priv_sta) -{ -	struct ath_rate_priv *rc = priv_sta; -	debugfs_remove(rc->debugfs_rcstats); -} - -#endif /* CONFIG_MAC80211_DEBUGFS && CONFIG_ATH9K_DEBUGFS */ - -static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) -{ -	return hw->priv; -} - -static void ath_rate_free(void *priv) -{ -	return; -} - -static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) -{ -	return kzalloc(sizeof(struct ath_rate_priv), gfp); -} - -static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta, -			      void *priv_sta) -{ -	struct ath_rate_priv *rate_priv = priv_sta; -	kfree(rate_priv); -} - -static struct rate_control_ops ath_rate_ops = { -	.module = NULL, -	.name = "ath9k_rate_control", -	.tx_status = ath_tx_status, -	.get_rate = ath_get_rate, -	.rate_init = ath_rate_init, -	.rate_update = ath_rate_update, -	.alloc = ath_rate_alloc, -	.free = ath_rate_free, -	.alloc_sta = ath_rate_alloc_sta, -	.free_sta = ath_rate_free_sta, - -#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) -	.add_sta_debugfs = ath_rate_add_sta_debugfs, -	.remove_sta_debugfs = ath_rate_remove_sta_debugfs, -#endif -}; - -int ath_rate_control_register(void) -{ -	return ieee80211_rate_control_register(&ath_rate_ops); -} - -void ath_rate_control_unregister(void) -{ -	ieee80211_rate_control_unregister(&ath_rate_ops); -} diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h deleted file mode 100644 index b9a87383cb4..00000000000 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (c) 2004 Sam Leffler, Errno Consulting - * Copyright (c) 2004 Video54 Technologies, Inc. - * Copyright (c) 2008-2011 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef RC_H -#define RC_H - -#include "hw.h" - -struct ath_softc; - -#define ATH_RATE_MAX     30 -#define RATE_TABLE_SIZE  72 - -#define RC_INVALID	0x0000 -#define RC_LEGACY	0x0001 -#define RC_SS		0x0002 -#define RC_DS		0x0004 -#define RC_TS		0x0008 -#define RC_HT_20	0x0010 -#define RC_HT_40	0x0020 - -#define RC_STREAM_MASK	0xe -#define RC_DS_OR_LATER(f)	((((f) & RC_STREAM_MASK) == RC_DS) || \ -				(((f) & RC_STREAM_MASK) == (RC_DS | RC_TS))) -#define RC_TS_ONLY(f)		(((f) & RC_STREAM_MASK) == RC_TS) -#define RC_SS_OR_LEGACY(f)	((f) & (RC_SS | RC_LEGACY)) - -#define RC_HT_2040		(RC_HT_20 | RC_HT_40) -#define RC_ALL_STREAM		(RC_SS | RC_DS | RC_TS) -#define RC_L_SD			(RC_LEGACY | RC_SS | RC_DS) -#define RC_L_SDT		(RC_LEGACY | RC_SS | RC_DS | RC_TS) -#define RC_HT_S_20		(RC_HT_20 | RC_SS) -#define RC_HT_D_20		(RC_HT_20 | RC_DS) -#define RC_HT_T_20		(RC_HT_20 | RC_TS) -#define RC_HT_S_40		(RC_HT_40 | RC_SS) -#define RC_HT_D_40		(RC_HT_40 | RC_DS) -#define RC_HT_T_40		(RC_HT_40 | RC_TS) - -#define RC_HT_SD_20		(RC_HT_20 | RC_SS | RC_DS) -#define RC_HT_DT_20		(RC_HT_20 | RC_DS | RC_TS) -#define RC_HT_SD_40		(RC_HT_40 | RC_SS | RC_DS) -#define RC_HT_DT_40		(RC_HT_40 | RC_DS | RC_TS) - -#define RC_HT_SD_2040		(RC_HT_2040 | RC_SS | RC_DS) -#define RC_HT_SDT_2040		(RC_HT_2040 | RC_SS | RC_DS | RC_TS) - -#define RC_HT_SDT_20		(RC_HT_20 | RC_SS | RC_DS | RC_TS) -#define RC_HT_SDT_40		(RC_HT_40 | RC_SS | RC_DS | RC_TS) - -#define RC_ALL			(RC_LEGACY | RC_HT_2040 | RC_ALL_STREAM) - -enum { -	WLAN_RC_PHY_OFDM, -	WLAN_RC_PHY_CCK, -	WLAN_RC_PHY_HT_20_SS, -	WLAN_RC_PHY_HT_20_DS, -	WLAN_RC_PHY_HT_20_TS, -	WLAN_RC_PHY_HT_40_SS, -	WLAN_RC_PHY_HT_40_DS, -	WLAN_RC_PHY_HT_40_TS, -	WLAN_RC_PHY_HT_20_SS_HGI, -	WLAN_RC_PHY_HT_20_DS_HGI, -	WLAN_RC_PHY_HT_20_TS_HGI, -	WLAN_RC_PHY_HT_40_SS_HGI, -	WLAN_RC_PHY_HT_40_DS_HGI, -	WLAN_RC_PHY_HT_40_TS_HGI, -	WLAN_RC_PHY_MAX -}; - -#define WLAN_RC_PHY_DS(_phy)   ((_phy == WLAN_RC_PHY_HT_20_DS)		\ -				|| (_phy == WLAN_RC_PHY_HT_40_DS)	\ -				|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI)	\ -				|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) -#define WLAN_RC_PHY_TS(_phy)   ((_phy == WLAN_RC_PHY_HT_20_TS)		\ -				|| (_phy == WLAN_RC_PHY_HT_40_TS)	\ -				|| (_phy == WLAN_RC_PHY_HT_20_TS_HGI)	\ -				|| (_phy == WLAN_RC_PHY_HT_40_TS_HGI)) -#define WLAN_RC_PHY_20(_phy)   ((_phy == WLAN_RC_PHY_HT_20_SS)		\ -				|| (_phy == WLAN_RC_PHY_HT_20_DS)	\ -				|| (_phy == WLAN_RC_PHY_HT_20_TS)	\ -				|| (_phy == WLAN_RC_PHY_HT_20_SS_HGI)	\ -				|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI)	\ -				|| (_phy == WLAN_RC_PHY_HT_20_TS_HGI)) -#define WLAN_RC_PHY_40(_phy)   ((_phy == WLAN_RC_PHY_HT_40_SS)		\ -				|| (_phy == WLAN_RC_PHY_HT_40_DS)	\ -				|| (_phy == WLAN_RC_PHY_HT_40_TS)	\ -				|| (_phy == WLAN_RC_PHY_HT_40_SS_HGI)	\ -				|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI)	\ -				|| (_phy == WLAN_RC_PHY_HT_40_TS_HGI)) -#define WLAN_RC_PHY_SGI(_phy)  ((_phy == WLAN_RC_PHY_HT_20_SS_HGI)      \ -				|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI)   \ -				|| (_phy == WLAN_RC_PHY_HT_20_TS_HGI)   \ -				|| (_phy == WLAN_RC_PHY_HT_40_SS_HGI)   \ -				|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI)   \ -				|| (_phy == WLAN_RC_PHY_HT_40_TS_HGI)) - -#define WLAN_RC_PHY_HT(_phy)    (_phy >= WLAN_RC_PHY_HT_20_SS) - -#define WLAN_RC_CAP_MODE(capflag) (((capflag & WLAN_RC_HT_FLAG) ?	\ -	((capflag & WLAN_RC_40_FLAG) ? RC_HT_40 : RC_HT_20) : RC_LEGACY)) - -#define WLAN_RC_CAP_STREAM(capflag) (((capflag & WLAN_RC_TS_FLAG) ?	\ -	(RC_TS) : ((capflag & WLAN_RC_DS_FLAG) ? RC_DS : RC_SS))) - -/* Return TRUE if flag supports HT20 && client supports HT20 or - * return TRUE if flag supports HT40 && client supports HT40. - * This is used becos some rates overlap between HT20/HT40. - */ -#define WLAN_RC_PHY_HT_VALID(flag, capflag)			\ -	(((flag & RC_HT_20) && !(capflag & WLAN_RC_40_FLAG)) || \ -	 ((flag & RC_HT_40) && (capflag & WLAN_RC_40_FLAG))) - -#define WLAN_RC_DS_FLAG         (0x01) -#define WLAN_RC_TS_FLAG         (0x02) -#define WLAN_RC_40_FLAG         (0x04) -#define WLAN_RC_SGI_FLAG        (0x08) -#define WLAN_RC_HT_FLAG         (0x10) - -/** - * struct ath_rate_table - Rate Control table - * @rate_cnt: total number of rates for the given wireless mode - * @mcs_start: MCS rate index offset - * @rate_flags: Rate Control flags - * @phy: CCK/OFDM/HT20/HT40 - * @ratekbps: rate in Kbits per second - * @user_ratekbps: user rate in Kbits per second - * @ratecode: rate that goes into HW descriptors - * @dot11rate: value that goes into supported - * 	rates info element of MLME - * @ctrl_rate: Index of next lower basic rate, used for duration computation - * @cw40index: Index of rates having 40MHz channel width - * @sgi_index: Index of rates having Short Guard Interval - * @ht_index: high throughput rates having 40MHz channel width and - * 	Short Guard Interval - * @probe_interval: interval for rate control to probe for other rates - * @initial_ratemax: initial ratemax value - */ -struct ath_rate_table { -	int rate_cnt; -	int mcs_start; -	struct { -		u16 rate_flags; -		u8 phy; -		u32 ratekbps; -		u32 user_ratekbps; -		u8 ratecode; -		u8 dot11rate; -	} info[RATE_TABLE_SIZE]; -	u32 probe_interval; -	u8 initial_ratemax; -}; - -struct ath_rateset { -	u8 rs_nrates; -	u8 rs_rates[ATH_RATE_MAX]; -}; - -struct ath_rc_stats { -	u32 success; -	u32 retries; -	u32 xretries; -	u8 per; -}; - -/** - * struct ath_rate_priv - Rate Control priv data - * @state: RC state - * @probe_rate: rate we are probing at - * @probe_time: msec timestamp for last probe - * @hw_maxretry_pktcnt: num of packets since we got HW max retry error - * @max_valid_rate: maximum number of valid rate - * @per_down_time: msec timestamp for last PER down step - * @valid_phy_ratecnt: valid rate count - * @rate_max_phy: phy index for the max rate - * @per: PER for every valid rate in % - * @probe_interval: interval for ratectrl to probe for other rates - * @ht_cap: HT capabilities - * @neg_rates: Negotatied rates - * @neg_ht_rates: Negotiated HT rates - */ -struct ath_rate_priv { -	u8 rate_table_size; -	u8 probe_rate; -	u8 hw_maxretry_pktcnt; -	u8 max_valid_rate; -	u8 valid_rate_index[RATE_TABLE_SIZE]; -	u8 ht_cap; -	u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; -	u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE]; -	u8 rate_max_phy; -	u8 per[RATE_TABLE_SIZE]; -	u32 probe_time; -	u32 per_down_time; -	u32 probe_interval; -	struct ath_rateset neg_rates; -	struct ath_rateset neg_ht_rates; -	const struct ath_rate_table *rate_table; - -#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) -	struct dentry *debugfs_rcstats; -	struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; -#endif -}; - -#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) -void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate); -void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, -			    int xretries, int retries, u8 per); -#else -static inline void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate) -{ -} -static inline void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, -					  int xretries, int retries, u8 per) -{ -} -#endif - -#ifdef CONFIG_ATH9K_LEGACY_RATE_CONTROL -int ath_rate_control_register(void); -void ath_rate_control_unregister(void); -#else -static inline int ath_rate_control_register(void) -{ -	return 0; -} - -static inline void ath_rate_control_unregister(void) -{ -} -#endif - -#endif /* RC_H */ diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index ab9e3a8410b..9105a92364f 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -15,11 +15,10 @@   */  #include <linux/dma-mapping.h> -#include <linux/relay.h>  #include "ath9k.h"  #include "ar9003_mac.h" -#define SKB_CB_ATHBUF(__skb)	(*((struct ath_buf **)__skb->cb)) +#define SKB_CB_ATHBUF(__skb)	(*((struct ath_rxbuf **)__skb->cb))  static inline bool ath9k_check_auto_sleep(struct ath_softc *sc)  { @@ -35,7 +34,8 @@ static inline bool ath9k_check_auto_sleep(struct ath_softc *sc)   * buffer (or rx fifo). This can incorrectly acknowledge packets   * to a sender if last desc is self-linked.   */ -static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) +static void ath_rx_buf_link(struct ath_softc *sc, struct ath_rxbuf *bf, +			    bool flush)  {  	struct ath_hw *ah = sc->sc_ah;  	struct ath_common *common = ath9k_hw_common(ah); @@ -60,18 +60,19 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)  			     common->rx_bufsize,  			     0); -	if (sc->rx.rxlink == NULL) -		ath9k_hw_putrxbuf(ah, bf->bf_daddr); -	else +	if (sc->rx.rxlink)  		*sc->rx.rxlink = bf->bf_daddr; +	else if (!flush) +		ath9k_hw_putrxbuf(ah, bf->bf_daddr);  	sc->rx.rxlink = &ds->ds_link;  } -static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_buf *bf) +static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_rxbuf *bf, +			      bool flush)  {  	if (sc->rx.buf_hold) -		ath_rx_buf_link(sc, sc->rx.buf_hold); +		ath_rx_buf_link(sc, sc->rx.buf_hold, flush);  	sc->rx.buf_hold = bf;  } @@ -112,13 +113,13 @@ static bool ath_rx_edma_buf_link(struct ath_softc *sc,  	struct ath_hw *ah = sc->sc_ah;  	struct ath_rx_edma *rx_edma;  	struct sk_buff *skb; -	struct ath_buf *bf; +	struct ath_rxbuf *bf;  	rx_edma = &sc->rx.rx_edma[qtype];  	if (skb_queue_len(&rx_edma->rx_fifo) >= rx_edma->rx_fifo_hwsize)  		return false; -	bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list); +	bf = list_first_entry(&sc->rx.rxbuf, struct ath_rxbuf, list);  	list_del_init(&bf->list);  	skb = bf->bf_mpdu; @@ -138,7 +139,7 @@ static void ath_rx_addbuffer_edma(struct ath_softc *sc,  				  enum ath9k_rx_qtype qtype)  {  	struct ath_common *common = ath9k_hw_common(sc->sc_ah); -	struct ath_buf *bf, *tbf; +	struct ath_rxbuf *bf, *tbf;  	if (list_empty(&sc->rx.rxbuf)) {  		ath_dbg(common, QUEUE, "No free rx buf available\n"); @@ -154,7 +155,7 @@ static void ath_rx_addbuffer_edma(struct ath_softc *sc,  static void ath_rx_remove_buffer(struct ath_softc *sc,  				 enum ath9k_rx_qtype qtype)  { -	struct ath_buf *bf; +	struct ath_rxbuf *bf;  	struct ath_rx_edma *rx_edma;  	struct sk_buff *skb; @@ -171,7 +172,7 @@ static void ath_rx_edma_cleanup(struct ath_softc *sc)  {  	struct ath_hw *ah = sc->sc_ah;  	struct ath_common *common = ath9k_hw_common(ah); -	struct ath_buf *bf; +	struct ath_rxbuf *bf;  	ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP);  	ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP); @@ -199,7 +200,7 @@ static int ath_rx_edma_init(struct ath_softc *sc, int nbufs)  	struct ath_common *common = ath9k_hw_common(sc->sc_ah);  	struct ath_hw *ah = sc->sc_ah;  	struct sk_buff *skb; -	struct ath_buf *bf; +	struct ath_rxbuf *bf;  	int error = 0, i;  	u32 size; @@ -211,7 +212,7 @@ static int ath_rx_edma_init(struct ath_softc *sc, int nbufs)  	ath_rx_edma_init_queue(&sc->rx.rx_edma[ATH9K_RX_QUEUE_HP],  			       ah->caps.rx_hp_qdepth); -	size = sizeof(struct ath_buf) * nbufs; +	size = sizeof(struct ath_rxbuf) * nbufs;  	bf = devm_kzalloc(sc->dev, size, GFP_KERNEL);  	if (!bf)  		return -ENOMEM; @@ -271,7 +272,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)  {  	struct ath_common *common = ath9k_hw_common(sc->sc_ah);  	struct sk_buff *skb; -	struct ath_buf *bf; +	struct ath_rxbuf *bf;  	int error = 0;  	spin_lock_init(&sc->sc_pcu_lock); @@ -332,7 +333,7 @@ void ath_rx_cleanup(struct ath_softc *sc)  	struct ath_hw *ah = sc->sc_ah;  	struct ath_common *common = ath9k_hw_common(ah);  	struct sk_buff *skb; -	struct ath_buf *bf; +	struct ath_rxbuf *bf;  	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {  		ath_rx_edma_cleanup(sc); @@ -375,6 +376,9 @@ u32 ath_calcrxfilter(struct ath_softc *sc)  {  	u32 rfilt; +	if (config_enabled(CONFIG_ATH9K_TX99)) +		return 0; +  	rfilt = ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST  		| ATH9K_RX_FILTER_MCAST; @@ -417,7 +421,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)  		rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL;  	} -	if (AR_SREV_9550(sc->sc_ah)) +	if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah))  		rfilt |= ATH9K_RX_FILTER_4ADDRESS;  	return rfilt; @@ -427,7 +431,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)  int ath_startrecv(struct ath_softc *sc)  {  	struct ath_hw *ah = sc->sc_ah; -	struct ath_buf *bf, *tbf; +	struct ath_rxbuf *bf, *tbf;  	if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {  		ath_edma_start_recv(sc); @@ -440,14 +444,14 @@ int ath_startrecv(struct ath_softc *sc)  	sc->rx.buf_hold = NULL;  	sc->rx.rxlink = NULL;  	list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) { -		ath_rx_buf_link(sc, bf); +		ath_rx_buf_link(sc, bf, false);  	}  	/* We could have deleted elements so the list may be empty now */  	if (list_empty(&sc->rx.rxbuf))  		goto start_recv; -	bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list); +	bf = list_first_entry(&sc->rx.rxbuf, struct ath_rxbuf, list);  	ath9k_hw_putrxbuf(ah, bf->bf_daddr);  	ath9k_hw_rxena(ah); @@ -536,7 +540,10 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)  		sc->ps_flags &= ~PS_BEACON_SYNC;  		ath_dbg(common, PS,  			"Reconfigure beacon timers based on synchronized timestamp\n"); -		ath9k_set_beacon(sc); +		if (!(WARN_ON_ONCE(sc->cur_beacon_conf.beacon_interval == 0))) +			ath9k_set_beacon(sc); +		if (sc->p2p_ps_vif) +			ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif);  	}  	if (ath_beacon_dtim_pending_cab(skb)) { @@ -603,13 +610,13 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb, bool mybeacon)  static bool ath_edma_get_buffers(struct ath_softc *sc,  				 enum ath9k_rx_qtype qtype,  				 struct ath_rx_status *rs, -				 struct ath_buf **dest) +				 struct ath_rxbuf **dest)  {  	struct ath_rx_edma *rx_edma = &sc->rx.rx_edma[qtype];  	struct ath_hw *ah = sc->sc_ah;  	struct ath_common *common = ath9k_hw_common(ah);  	struct sk_buff *skb; -	struct ath_buf *bf; +	struct ath_rxbuf *bf;  	int ret;  	skb = skb_peek(&rx_edma->rx_fifo); @@ -653,11 +660,11 @@ static bool ath_edma_get_buffers(struct ath_softc *sc,  	return true;  } -static struct ath_buf *ath_edma_get_next_rx_buf(struct ath_softc *sc, +static struct ath_rxbuf *ath_edma_get_next_rx_buf(struct ath_softc *sc,  						struct ath_rx_status *rs,  						enum ath9k_rx_qtype qtype)  { -	struct ath_buf *bf = NULL; +	struct ath_rxbuf *bf = NULL;  	while (ath_edma_get_buffers(sc, qtype, rs, &bf)) {  		if (!bf) @@ -668,13 +675,13 @@ static struct ath_buf *ath_edma_get_next_rx_buf(struct ath_softc *sc,  	return NULL;  } -static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc, +static struct ath_rxbuf *ath_get_next_rx_buf(struct ath_softc *sc,  					   struct ath_rx_status *rs)  {  	struct ath_hw *ah = sc->sc_ah;  	struct ath_common *common = ath9k_hw_common(ah);  	struct ath_desc *ds; -	struct ath_buf *bf; +	struct ath_rxbuf *bf;  	int ret;  	if (list_empty(&sc->rx.rxbuf)) { @@ -682,7 +689,7 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc,  		return NULL;  	} -	bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list); +	bf = list_first_entry(&sc->rx.rxbuf, struct ath_rxbuf, list);  	if (bf == sc->rx.buf_hold)  		return NULL; @@ -702,7 +709,7 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc,  	ret = ath9k_hw_rxprocdesc(ah, ds, rs);  	if (ret == -EINPROGRESS) {  		struct ath_rx_status trs; -		struct ath_buf *tbf; +		struct ath_rxbuf *tbf;  		struct ath_desc *tds;  		memset(&trs, 0, sizeof(trs)); @@ -711,7 +718,7 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc,  			return NULL;  		} -		tbf = list_entry(bf->list.next, struct ath_buf, list); +		tbf = list_entry(bf->list.next, struct ath_rxbuf, list);  		/*  		 * On some hardware the descriptor status words could @@ -730,11 +737,18 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc,  			return NULL;  		/* -		 * mark descriptor as zero-length and set the 'more' -		 * flag to ensure that both buffers get discarded +		 * Re-check previous descriptor, in case it has been filled +		 * in the mean time.  		 */ -		rs->rs_datalen = 0; -		rs->rs_more = true; +		ret = ath9k_hw_rxprocdesc(ah, ds, rs); +		if (ret == -EINPROGRESS) { +			/* +			 * mark descriptor as zero-length and set the 'more' +			 * flag to ensure that both buffers get discarded +			 */ +			rs->rs_datalen = 0; +			rs->rs_more = true; +		}  	}  	list_del(&bf->list); @@ -753,194 +767,6 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc,  	return bf;  } -/* Assumes you've already done the endian to CPU conversion */ -static bool ath9k_rx_accept(struct ath_common *common, -			    struct ieee80211_hdr *hdr, -			    struct ieee80211_rx_status *rxs, -			    struct ath_rx_status *rx_stats, -			    bool *decrypt_error) -{ -	struct ath_softc *sc = (struct ath_softc *) common->priv; -	bool is_mc, is_valid_tkip, strip_mic, mic_error; -	struct ath_hw *ah = common->ah; -	__le16 fc; - -	fc = hdr->frame_control; - -	is_mc = !!is_multicast_ether_addr(hdr->addr1); -	is_valid_tkip = rx_stats->rs_keyix != ATH9K_RXKEYIX_INVALID && -		test_bit(rx_stats->rs_keyix, common->tkip_keymap); -	strip_mic = is_valid_tkip && ieee80211_is_data(fc) && -		ieee80211_has_protected(fc) && -		!(rx_stats->rs_status & -		(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC | -		 ATH9K_RXERR_KEYMISS)); - -	/* -	 * Key miss events are only relevant for pairwise keys where the -	 * descriptor does contain a valid key index. This has been observed -	 * mostly with CCMP encryption. -	 */ -	if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID || -	    !test_bit(rx_stats->rs_keyix, common->ccmp_keymap)) -		rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS; - -	mic_error = is_valid_tkip && !ieee80211_is_ctl(fc) && -		!ieee80211_has_morefrags(fc) && -		!(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) && -		(rx_stats->rs_status & ATH9K_RXERR_MIC); - -	/* -	 * The rx_stats->rs_status will not be set until the end of the -	 * chained descriptors so it can be ignored if rs_more is set. The -	 * rs_more will be false at the last element of the chained -	 * descriptors. -	 */ -	if (rx_stats->rs_status != 0) { -		u8 status_mask; - -		if (rx_stats->rs_status & ATH9K_RXERR_CRC) { -			rxs->flag |= RX_FLAG_FAILED_FCS_CRC; -			mic_error = false; -		} - -		if ((rx_stats->rs_status & ATH9K_RXERR_DECRYPT) || -		    (!is_mc && (rx_stats->rs_status & ATH9K_RXERR_KEYMISS))) { -			*decrypt_error = true; -			mic_error = false; -		} - -		/* -		 * Reject error frames with the exception of -		 * decryption and MIC failures. For monitor mode, -		 * we also ignore the CRC error. -		 */ -		status_mask = ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | -			      ATH9K_RXERR_KEYMISS; - -		if (ah->is_monitoring && (sc->rx.rxfilter & FIF_FCSFAIL)) -			status_mask |= ATH9K_RXERR_CRC; - -		if (rx_stats->rs_status & ~status_mask) -			return false; -	} - -	/* -	 * For unicast frames the MIC error bit can have false positives, -	 * so all MIC error reports need to be validated in software. -	 * False negatives are not common, so skip software verification -	 * if the hardware considers the MIC valid. -	 */ -	if (strip_mic) -		rxs->flag |= RX_FLAG_MMIC_STRIPPED; -	else if (is_mc && mic_error) -		rxs->flag |= RX_FLAG_MMIC_ERROR; - -	return true; -} - -static int ath9k_process_rate(struct ath_common *common, -			      struct ieee80211_hw *hw, -			      struct ath_rx_status *rx_stats, -			      struct ieee80211_rx_status *rxs) -{ -	struct ieee80211_supported_band *sband; -	enum ieee80211_band band; -	unsigned int i = 0; -	struct ath_softc __maybe_unused *sc = common->priv; - -	band = hw->conf.chandef.chan->band; -	sband = hw->wiphy->bands[band]; - -	switch (hw->conf.chandef.width) { -	case NL80211_CHAN_WIDTH_5: -		rxs->flag |= RX_FLAG_5MHZ; -		break; -	case NL80211_CHAN_WIDTH_10: -		rxs->flag |= RX_FLAG_10MHZ; -		break; -	default: -		break; -	} - -	if (rx_stats->rs_rate & 0x80) { -		/* HT rate */ -		rxs->flag |= RX_FLAG_HT; -		rxs->flag |= rx_stats->flag; -		rxs->rate_idx = rx_stats->rs_rate & 0x7f; -		return 0; -	} - -	for (i = 0; i < sband->n_bitrates; i++) { -		if (sband->bitrates[i].hw_value == rx_stats->rs_rate) { -			rxs->rate_idx = i; -			return 0; -		} -		if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) { -			rxs->flag |= RX_FLAG_SHORTPRE; -			rxs->rate_idx = i; -			return 0; -		} -	} - -	/* -	 * No valid hardware bitrate found -- we should not get here -	 * because hardware has already validated this frame as OK. -	 */ -	ath_dbg(common, ANY, -		"unsupported hw bitrate detected 0x%02x using 1 Mbit\n", -		rx_stats->rs_rate); -	RX_STAT_INC(rx_rate_err); -	return -EINVAL; -} - -static void ath9k_process_rssi(struct ath_common *common, -			       struct ieee80211_hw *hw, -			       struct ath_rx_status *rx_stats, -			       struct ieee80211_rx_status *rxs) -{ -	struct ath_softc *sc = hw->priv; -	struct ath_hw *ah = common->ah; -	int last_rssi; -	int rssi = rx_stats->rs_rssi; - -	/* -	 * RSSI is not available for subframes in an A-MPDU. -	 */ -	if (rx_stats->rs_moreaggr) { -		rxs->flag |= RX_FLAG_NO_SIGNAL_VAL; -		return; -	} - -	/* -	 * Check if the RSSI for the last subframe in an A-MPDU -	 * or an unaggregated frame is valid. -	 */ -	if (rx_stats->rs_rssi == ATH9K_RSSI_BAD) { -		rxs->flag |= RX_FLAG_NO_SIGNAL_VAL; -		return; -	} - -	/* -	 * Update Beacon RSSI, this is used by ANI. -	 */ -	if (rx_stats->is_mybeacon && -	    ((ah->opmode == NL80211_IFTYPE_STATION) || -	     (ah->opmode == NL80211_IFTYPE_ADHOC))) { -		ATH_RSSI_LPF(sc->last_rssi, rx_stats->rs_rssi); -		last_rssi = sc->last_rssi; - -		if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) -			rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); -		if (rssi < 0) -			rssi = 0; - -		ah->stats.avgbrssi = rssi; -	} - -	rxs->signal = ah->noise + rx_stats->rs_rssi; -} -  static void ath9k_process_tsf(struct ath_rx_status *rs,  			      struct ieee80211_rx_status *rxs,  			      u64 tsf) @@ -957,131 +783,6 @@ static void ath9k_process_tsf(struct ath_rx_status *rs,  		rxs->mactime += 0x100000000ULL;  } -#ifdef CONFIG_ATH9K_DEBUGFS -static s8 fix_rssi_inv_only(u8 rssi_val) -{ -	if (rssi_val == 128) -		rssi_val = 0; -	return (s8) rssi_val; -} -#endif - -/* returns 1 if this was a spectral frame, even if not handled. */ -static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, -			   struct ath_rx_status *rs, u64 tsf) -{ -#ifdef CONFIG_ATH9K_DEBUGFS -	struct ath_hw *ah = sc->sc_ah; -	u8 bins[SPECTRAL_HT20_NUM_BINS]; -	u8 *vdata = (u8 *)hdr; -	struct fft_sample_ht20 fft_sample; -	struct ath_radar_info *radar_info; -	struct ath_ht20_mag_info *mag_info; -	int len = rs->rs_datalen; -	int dc_pos; -	u16 length, max_magnitude; - -	/* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer -	 * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT -	 * yet, but this is supposed to be possible as well. -	 */ -	if (rs->rs_phyerr != ATH9K_PHYERR_RADAR && -	    rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT && -	    rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL) -		return 0; - -	/* check if spectral scan bit is set. This does not have to be checked -	 * if received through a SPECTRAL phy error, but shouldn't hurt. -	 */ -	radar_info = ((struct ath_radar_info *)&vdata[len]) - 1; -	if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) -		return 0; - -	/* Variation in the data length is possible and will be fixed later. -	 * Note that we only support HT20 for now. -	 * -	 * TODO: add HT20_40 support as well. -	 */ -	if ((len > SPECTRAL_HT20_TOTAL_DATA_LEN + 2) || -	    (len < SPECTRAL_HT20_TOTAL_DATA_LEN - 1)) -		return 1; - -	fft_sample.tlv.type = ATH_FFT_SAMPLE_HT20; -	length = sizeof(fft_sample) - sizeof(fft_sample.tlv); -	fft_sample.tlv.length = __cpu_to_be16(length); - -	fft_sample.freq = __cpu_to_be16(ah->curchan->chan->center_freq); -	fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0); -	fft_sample.noise = ah->noise; - -	switch (len - SPECTRAL_HT20_TOTAL_DATA_LEN) { -	case 0: -		/* length correct, nothing to do. */ -		memcpy(bins, vdata, SPECTRAL_HT20_NUM_BINS); -		break; -	case -1: -		/* first byte missing, duplicate it. */ -		memcpy(&bins[1], vdata, SPECTRAL_HT20_NUM_BINS - 1); -		bins[0] = vdata[0]; -		break; -	case 2: -		/* MAC added 2 extra bytes at bin 30 and 32, remove them. */ -		memcpy(bins, vdata, 30); -		bins[30] = vdata[31]; -		memcpy(&bins[31], &vdata[33], SPECTRAL_HT20_NUM_BINS - 31); -		break; -	case 1: -		/* MAC added 2 extra bytes AND first byte is missing. */ -		bins[0] = vdata[0]; -		memcpy(&bins[0], vdata, 30); -		bins[31] = vdata[31]; -		memcpy(&bins[32], &vdata[33], SPECTRAL_HT20_NUM_BINS - 32); -		break; -	default: -		return 1; -	} - -	/* DC value (value in the middle) is the blind spot of the spectral -	 * sample and invalid, interpolate it. -	 */ -	dc_pos = SPECTRAL_HT20_NUM_BINS / 2; -	bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2; - -	/* mag data is at the end of the frame, in front of radar_info */ -	mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1; - -	/* copy raw bins without scaling them */ -	memcpy(fft_sample.data, bins, SPECTRAL_HT20_NUM_BINS); -	fft_sample.max_exp = mag_info->max_exp & 0xf; - -	max_magnitude = spectral_max_magnitude(mag_info->all_bins); -	fft_sample.max_magnitude = __cpu_to_be16(max_magnitude); -	fft_sample.max_index = spectral_max_index(mag_info->all_bins); -	fft_sample.bitmap_weight = spectral_bitmap_weight(mag_info->all_bins); -	fft_sample.tsf = __cpu_to_be64(tsf); - -	ath_debug_send_fft_sample(sc, &fft_sample.tlv); -	return 1; -#else -	return 0; -#endif -} - -static bool ath9k_is_mybeacon(struct ath_softc *sc, struct ieee80211_hdr *hdr) -{ -	struct ath_hw *ah = sc->sc_ah; -	struct ath_common *common = ath9k_hw_common(ah); - -	if (ieee80211_is_beacon(hdr->frame_control)) { -		RX_STAT_INC(rx_beacons); -		if (!is_zero_ether_addr(common->curbssid) && -		    ether_addr_equal(hdr->addr3, common->curbssid)) -			return true; -	} - -	return false; -} -  /*   * For Decrypt or Demic errors, we only mark packet status here and always push   * up the frame up to let mac80211 handle the actual error case, be it no @@ -1098,32 +799,32 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,  	struct ath_common *common = ath9k_hw_common(ah);  	struct ieee80211_hdr *hdr;  	bool discard_current = sc->rx.discard_next; -	int ret = 0;  	/*  	 * Discard corrupt descriptors which are marked in  	 * ath_get_next_rx_buf().  	 */ -	sc->rx.discard_next = rx_stats->rs_more;  	if (discard_current) -		return -EINVAL; +		goto corrupt; + +	sc->rx.discard_next = false;  	/*  	 * Discard zero-length packets.  	 */  	if (!rx_stats->rs_datalen) {  		RX_STAT_INC(rx_len_err); -		return -EINVAL; +		goto corrupt;  	} -        /* -         * rs_status follows rs_datalen so if rs_datalen is too large -         * we can take a hint that hardware corrupted it, so ignore -         * those frames. -         */ +	/* +	 * rs_status follows rs_datalen so if rs_datalen is too large +	 * we can take a hint that hardware corrupted it, so ignore +	 * those frames. +	 */  	if (rx_stats->rs_datalen > (common->rx_bufsize - ah->caps.rx_status_len)) {  		RX_STAT_INC(rx_len_err); -		return -EINVAL; +		goto corrupt;  	}  	/* Only use status info from the last fragment */ @@ -1137,10 +838,8 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,  	 * This is different from the other corrupt descriptor  	 * condition handled above.  	 */ -	if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) { -		ret = -EINVAL; -		goto exit; -	} +	if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) +		goto corrupt;  	hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len); @@ -1156,34 +855,42 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,  		if (ath_process_fft(sc, hdr, rx_stats, rx_status->mactime))  			RX_STAT_INC(rx_spectral); -		ret = -EINVAL; -		goto exit; +		return -EINVAL;  	}  	/*  	 * everything but the rate is checked here, the rate check is done  	 * separately to avoid doing two lookups for a rate for each frame.  	 */ -	if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) { -		ret = -EINVAL; -		goto exit; -	} +	if (!ath9k_cmn_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error, sc->rx.rxfilter)) +		return -EINVAL; -	rx_stats->is_mybeacon = ath9k_is_mybeacon(sc, hdr); -	if (rx_stats->is_mybeacon) { -		sc->hw_busy_count = 0; -		ath_start_rx_poll(sc, 3); +	if (ath_is_mybeacon(common, hdr)) { +		RX_STAT_INC(rx_beacons); +		rx_stats->is_mybeacon = true;  	} -	if (ath9k_process_rate(common, hw, rx_stats, rx_status)) { -		ret =-EINVAL; -		goto exit; +	/* +	 * This shouldn't happen, but have a safety check anyway. +	 */ +	if (WARN_ON(!ah->curchan)) +		return -EINVAL; + +	if (ath9k_cmn_process_rate(common, hw, rx_stats, rx_status)) { +		/* +		 * No valid hardware bitrate found -- we should not get here +		 * because hardware has already validated this frame as OK. +		 */ +		ath_dbg(common, ANY, "unsupported hw bitrate detected 0x%02x using 1 Mbit\n", +			rx_stats->rs_rate); +		RX_STAT_INC(rx_rate_err); +		return -EINVAL;  	} -	ath9k_process_rssi(common, hw, rx_stats, rx_status); +	ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status); -	rx_status->band = hw->conf.chandef.chan->band; -	rx_status->freq = hw->conf.chandef.chan->center_freq; +	rx_status->band = ah->curchan->chan->band; +	rx_status->freq = ah->curchan->chan->center_freq;  	rx_status->antenna = rx_stats->rs_antenna;  	rx_status->flag |= RX_FLAG_MACTIME_END; @@ -1193,60 +900,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,  		sc->rx.num_pkts++;  #endif -exit: -	sc->rx.discard_next = false; -	return ret; -} - -static void ath9k_rx_skb_postprocess(struct ath_common *common, -				     struct sk_buff *skb, -				     struct ath_rx_status *rx_stats, -				     struct ieee80211_rx_status *rxs, -				     bool decrypt_error) -{ -	struct ath_hw *ah = common->ah; -	struct ieee80211_hdr *hdr; -	int hdrlen, padpos, padsize; -	u8 keyix; -	__le16 fc; - -	/* see if any padding is done by the hw and remove it */ -	hdr = (struct ieee80211_hdr *) skb->data; -	hdrlen = ieee80211_get_hdrlen_from_skb(skb); -	fc = hdr->frame_control; -	padpos = ieee80211_hdrlen(fc); - -	/* The MAC header is padded to have 32-bit boundary if the -	 * packet payload is non-zero. The general calculation for -	 * padsize would take into account odd header lengths: -	 * padsize = (4 - padpos % 4) % 4; However, since only -	 * even-length headers are used, padding can only be 0 or 2 -	 * bytes and we can optimize this a bit. In addition, we must -	 * not try to remove padding from short control frames that do -	 * not have payload. */ -	padsize = padpos & 3; -	if (padsize && skb->len>=padpos+padsize+FCS_LEN) { -		memmove(skb->data + padsize, skb->data, padpos); -		skb_pull(skb, padsize); -	} - -	keyix = rx_stats->rs_keyix; - -	if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error && -	    ieee80211_has_protected(fc)) { -		rxs->flag |= RX_FLAG_DECRYPTED; -	} else if (ieee80211_has_protected(fc) -		   && !decrypt_error && skb->len >= hdrlen + 4) { -		keyix = skb->data[hdrlen + 3] >> 6; +	return 0; -		if (test_bit(keyix, common->keymap)) -			rxs->flag |= RX_FLAG_DECRYPTED; -	} -	if (ah->sw_mgmt_crypto && -	    (rxs->flag & RX_FLAG_DECRYPTED) && -	    ieee80211_is_mgmt(fc)) -		/* Use software decrypt for management frames. */ -		rxs->flag &= ~RX_FLAG_DECRYPTED; +corrupt: +	sc->rx.discard_next = rx_stats->rs_more; +	return -EINVAL;  }  /* @@ -1308,7 +966,7 @@ static void ath9k_apply_ampdu_details(struct ath_softc *sc,  int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)  { -	struct ath_buf *bf; +	struct ath_rxbuf *bf;  	struct sk_buff *skb = NULL, *requeue_skb, *hdr_skb;  	struct ieee80211_rx_status *rxs;  	struct ath_hw *ah = sc->sc_ah; @@ -1322,6 +980,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)  	u64 tsf = 0;  	unsigned long flags;  	dma_addr_t new_buf_addr; +	unsigned int budget = 512;  	if (edma)  		dma_type = DMA_BIDIRECTIONAL; @@ -1398,8 +1057,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)  			skb_pull(skb, ah->caps.rx_status_len);  		if (!rs.rs_more) -			ath9k_rx_skb_postprocess(common, hdr_skb, &rs, -						 rxs, decrypt_error); +			ath9k_cmn_rx_skb_postprocess(common, hdr_skb, &rs, +						     rxs, decrypt_error);  		if (rs.rs_more) {  			RX_STAT_INC(rx_frags); @@ -1448,8 +1107,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)  		spin_unlock_irqrestore(&sc->sc_pm_lock, flags);  		ath9k_antenna_check(sc, &rs); -  		ath9k_apply_ampdu_details(sc, &rs, rxs); +		ath_debug_rate_stats(sc, &rs, skb);  		ieee80211_rx(hw, skb); @@ -1460,15 +1119,17 @@ requeue_drop_frag:  		}  requeue:  		list_add_tail(&bf->list, &sc->rx.rxbuf); -		if (flush) -			continue; -		if (edma) { +		if (!edma) { +			ath_rx_buf_relink(sc, bf, flush); +			if (!flush) +				ath9k_hw_rxena(ah); +		} else if (!flush) {  			ath_rx_edma_buf_link(sc, qtype); -		} else { -			ath_rx_buf_relink(sc, bf); -			ath9k_hw_rxena(ah);  		} + +		if (!budget--) +			break;  	} while (1);  	if (!(ah->imask & ATH9K_INT_RXEOL)) { diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index a13b2d143d9..f1bbce3f777 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -304,6 +304,7 @@  #define AR_IMR_S2              0x00ac  #define AR_IMR_S2_QCU_TXURN    0x000003FF  #define AR_IMR_S2_QCU_TXURN_S  0 +#define AR_IMR_S2_BB_WATCHDOG  0x00010000  #define AR_IMR_S2_CST          0x00400000  #define AR_IMR_S2_GTT          0x00800000  #define AR_IMR_S2_TIM          0x01000000 @@ -504,9 +505,6 @@  #define AR_D_QCUMASK         0x000003FF  #define AR_D_QCUMASK_RESV0   0xFFFFFC00 -#define AR_D_TXBLK_CMD  0x1038 -#define AR_D_TXBLK_DATA(i) (AR_D_TXBLK_CMD+(i)) -  #define AR_D0_LCL_IFS     0x1040  #define AR_D1_LCL_IFS     0x1044  #define AR_D2_LCL_IFS     0x1048 @@ -809,7 +807,12 @@  #define AR_SREV_REVISION_9462_21	3  #define AR_SREV_VERSION_9565            0x2C0  #define AR_SREV_REVISION_9565_10        0 +#define AR_SREV_REVISION_9565_101       1 +#define AR_SREV_REVISION_9565_11        2  #define AR_SREV_VERSION_9550		0x400 +#define AR_SREV_VERSION_9531            0x500 +#define AR_SREV_REVISION_9531_10        0 +#define AR_SREV_REVISION_9531_11        1  #define AR_SREV_5416(_ah) \  	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ @@ -881,9 +884,6 @@  #define AR_SREV_9330(_ah) \  	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9330)) -#define AR_SREV_9330_10(_ah) \ -	(AR_SREV_9330((_ah)) && \ -	 ((_ah)->hw_version.macRev == AR_SREV_REVISION_9330_10))  #define AR_SREV_9330_11(_ah) \  	(AR_SREV_9330((_ah)) && \  	 ((_ah)->hw_version.macRev == AR_SREV_REVISION_9330_11)) @@ -927,10 +927,18 @@  #define AR_SREV_9565(_ah) \  	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565)) -  #define AR_SREV_9565_10(_ah) \  	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \  	 ((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_10)) +#define AR_SREV_9565_101(_ah) \ +	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \ +	 ((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_101)) +#define AR_SREV_9565_11(_ah) \ +	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \ +	 ((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_11)) +#define AR_SREV_9565_11_OR_LATER(_ah) \ +	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \ +	 ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9565_11))  #define AR_SREV_9550(_ah) \  	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9550)) @@ -938,11 +946,19 @@  #define AR_SREV_9580(_ah) \  	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9580) && \  	((_ah)->hw_version.macRev >= AR_SREV_REVISION_9580_10)) -  #define AR_SREV_9580_10(_ah) \  	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9580) && \  	((_ah)->hw_version.macRev == AR_SREV_REVISION_9580_10)) +#define AR_SREV_9531(_ah) \ +	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531)) +#define AR_SREV_9531_10(_ah) \ +	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \ +	 ((_ah)->hw_version.macRev == AR_SREV_REVISION_9531_10)) +#define AR_SREV_9531_11(_ah) \ +	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \ +	 ((_ah)->hw_version.macRev == AR_SREV_REVISION_9531_11)) +  /* NOTE: When adding chips newer than Peacock, add chip check here */  #define AR_SREV_9580_10_OR_LATER(_ah) \  	(AR_SREV_9580(_ah)) diff --git a/drivers/net/wireless/ath/ath9k/spectral.c b/drivers/net/wireless/ath/ath9k/spectral.c new file mode 100644 index 00000000000..99f4de95c26 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/spectral.c @@ -0,0 +1,543 @@ +/* + * Copyright (c) 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/relay.h> +#include "ath9k.h" + +static s8 fix_rssi_inv_only(u8 rssi_val) +{ +	if (rssi_val == 128) +		rssi_val = 0; +	return (s8) rssi_val; +} + +static void ath_debug_send_fft_sample(struct ath_softc *sc, +				      struct fft_sample_tlv *fft_sample_tlv) +{ +	int length; +	if (!sc->rfs_chan_spec_scan) +		return; + +	length = __be16_to_cpu(fft_sample_tlv->length) + +		 sizeof(*fft_sample_tlv); +	relay_write(sc->rfs_chan_spec_scan, fft_sample_tlv, length); +} + +/* returns 1 if this was a spectral frame, even if not handled. */ +int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, +		    struct ath_rx_status *rs, u64 tsf) +{ +	struct ath_hw *ah = sc->sc_ah; +	u8 num_bins, *bins, *vdata = (u8 *)hdr; +	struct fft_sample_ht20 fft_sample_20; +	struct fft_sample_ht20_40 fft_sample_40; +	struct fft_sample_tlv *tlv; +	struct ath_radar_info *radar_info; +	int len = rs->rs_datalen; +	int dc_pos; +	u16 fft_len, length, freq = ah->curchan->chan->center_freq; +	enum nl80211_channel_type chan_type; + +	/* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer +	 * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT +	 * yet, but this is supposed to be possible as well. +	 */ +	if (rs->rs_phyerr != ATH9K_PHYERR_RADAR && +	    rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT && +	    rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL) +		return 0; + +	/* check if spectral scan bit is set. This does not have to be checked +	 * if received through a SPECTRAL phy error, but shouldn't hurt. +	 */ +	radar_info = ((struct ath_radar_info *)&vdata[len]) - 1; +	if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) +		return 0; + +	chan_type = cfg80211_get_chandef_type(&sc->hw->conf.chandef); +	if ((chan_type == NL80211_CHAN_HT40MINUS) || +	    (chan_type == NL80211_CHAN_HT40PLUS)) { +		fft_len = SPECTRAL_HT20_40_TOTAL_DATA_LEN; +		num_bins = SPECTRAL_HT20_40_NUM_BINS; +		bins = (u8 *)fft_sample_40.data; +	} else { +		fft_len = SPECTRAL_HT20_TOTAL_DATA_LEN; +		num_bins = SPECTRAL_HT20_NUM_BINS; +		bins = (u8 *)fft_sample_20.data; +	} + +	/* Variation in the data length is possible and will be fixed later */ +	if ((len > fft_len + 2) || (len < fft_len - 1)) +		return 1; + +	switch (len - fft_len) { +	case 0: +		/* length correct, nothing to do. */ +		memcpy(bins, vdata, num_bins); +		break; +	case -1: +		/* first byte missing, duplicate it. */ +		memcpy(&bins[1], vdata, num_bins - 1); +		bins[0] = vdata[0]; +		break; +	case 2: +		/* MAC added 2 extra bytes at bin 30 and 32, remove them. */ +		memcpy(bins, vdata, 30); +		bins[30] = vdata[31]; +		memcpy(&bins[31], &vdata[33], num_bins - 31); +		break; +	case 1: +		/* MAC added 2 extra bytes AND first byte is missing. */ +		bins[0] = vdata[0]; +		memcpy(&bins[1], vdata, 30); +		bins[31] = vdata[31]; +		memcpy(&bins[32], &vdata[33], num_bins - 32); +		break; +	default: +		return 1; +	} + +	/* DC value (value in the middle) is the blind spot of the spectral +	 * sample and invalid, interpolate it. +	 */ +	dc_pos = num_bins / 2; +	bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2; + +	if ((chan_type == NL80211_CHAN_HT40MINUS) || +	    (chan_type == NL80211_CHAN_HT40PLUS)) { +		s8 lower_rssi, upper_rssi; +		s16 ext_nf; +		u8 lower_max_index, upper_max_index; +		u8 lower_bitmap_w, upper_bitmap_w; +		u16 lower_mag, upper_mag; +		struct ath9k_hw_cal_data *caldata = ah->caldata; +		struct ath_ht20_40_mag_info *mag_info; + +		if (caldata) +			ext_nf = ath9k_hw_getchan_noise(ah, ah->curchan, +					caldata->nfCalHist[3].privNF); +		else +			ext_nf = ATH_DEFAULT_NOISE_FLOOR; + +		length = sizeof(fft_sample_40) - sizeof(struct fft_sample_tlv); +		fft_sample_40.tlv.type = ATH_FFT_SAMPLE_HT20_40; +		fft_sample_40.tlv.length = __cpu_to_be16(length); +		fft_sample_40.freq = __cpu_to_be16(freq); +		fft_sample_40.channel_type = chan_type; + +		if (chan_type == NL80211_CHAN_HT40PLUS) { +			lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]); +			upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]); + +			fft_sample_40.lower_noise = ah->noise; +			fft_sample_40.upper_noise = ext_nf; +		} else { +			lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]); +			upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]); + +			fft_sample_40.lower_noise = ext_nf; +			fft_sample_40.upper_noise = ah->noise; +		} +		fft_sample_40.lower_rssi = lower_rssi; +		fft_sample_40.upper_rssi = upper_rssi; + +		mag_info = ((struct ath_ht20_40_mag_info *)radar_info) - 1; +		lower_mag = spectral_max_magnitude(mag_info->lower_bins); +		upper_mag = spectral_max_magnitude(mag_info->upper_bins); +		fft_sample_40.lower_max_magnitude = __cpu_to_be16(lower_mag); +		fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag); +		lower_max_index = spectral_max_index(mag_info->lower_bins); +		upper_max_index = spectral_max_index(mag_info->upper_bins); +		fft_sample_40.lower_max_index = lower_max_index; +		fft_sample_40.upper_max_index = upper_max_index; +		lower_bitmap_w = spectral_bitmap_weight(mag_info->lower_bins); +		upper_bitmap_w = spectral_bitmap_weight(mag_info->upper_bins); +		fft_sample_40.lower_bitmap_weight = lower_bitmap_w; +		fft_sample_40.upper_bitmap_weight = upper_bitmap_w; +		fft_sample_40.max_exp = mag_info->max_exp & 0xf; + +		fft_sample_40.tsf = __cpu_to_be64(tsf); + +		tlv = (struct fft_sample_tlv *)&fft_sample_40; +	} else { +		u8 max_index, bitmap_w; +		u16 magnitude; +		struct ath_ht20_mag_info *mag_info; + +		length = sizeof(fft_sample_20) - sizeof(struct fft_sample_tlv); +		fft_sample_20.tlv.type = ATH_FFT_SAMPLE_HT20; +		fft_sample_20.tlv.length = __cpu_to_be16(length); +		fft_sample_20.freq = __cpu_to_be16(freq); + +		fft_sample_20.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]); +		fft_sample_20.noise = ah->noise; + +		mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1; +		magnitude = spectral_max_magnitude(mag_info->all_bins); +		fft_sample_20.max_magnitude = __cpu_to_be16(magnitude); +		max_index = spectral_max_index(mag_info->all_bins); +		fft_sample_20.max_index = max_index; +		bitmap_w = spectral_bitmap_weight(mag_info->all_bins); +		fft_sample_20.bitmap_weight = bitmap_w; +		fft_sample_20.max_exp = mag_info->max_exp & 0xf; + +		fft_sample_20.tsf = __cpu_to_be64(tsf); + +		tlv = (struct fft_sample_tlv *)&fft_sample_20; +	} + +	ath_debug_send_fft_sample(sc, tlv); + +	return 1; +} + +/*********************/ +/* spectral_scan_ctl */ +/*********************/ + +static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf, +				       size_t count, loff_t *ppos) +{ +	struct ath_softc *sc = file->private_data; +	char *mode = ""; +	unsigned int len; + +	switch (sc->spectral_mode) { +	case SPECTRAL_DISABLED: +		mode = "disable"; +		break; +	case SPECTRAL_BACKGROUND: +		mode = "background"; +		break; +	case SPECTRAL_CHANSCAN: +		mode = "chanscan"; +		break; +	case SPECTRAL_MANUAL: +		mode = "manual"; +		break; +	} +	len = strlen(mode); +	return simple_read_from_buffer(user_buf, count, ppos, mode, len); +} + +static ssize_t write_file_spec_scan_ctl(struct file *file, +					const char __user *user_buf, +					size_t count, loff_t *ppos) +{ +	struct ath_softc *sc = file->private_data; +	struct ath_common *common = ath9k_hw_common(sc->sc_ah); +	char buf[32]; +	ssize_t len; + +	if (config_enabled(CONFIG_ATH9K_TX99)) +		return -EOPNOTSUPP; + +	len = min(count, sizeof(buf) - 1); +	if (copy_from_user(buf, user_buf, len)) +		return -EFAULT; + +	buf[len] = '\0'; + +	if (strncmp("trigger", buf, 7) == 0) { +		ath9k_spectral_scan_trigger(sc->hw); +	} else if (strncmp("background", buf, 9) == 0) { +		ath9k_spectral_scan_config(sc->hw, SPECTRAL_BACKGROUND); +		ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n"); +	} else if (strncmp("chanscan", buf, 8) == 0) { +		ath9k_spectral_scan_config(sc->hw, SPECTRAL_CHANSCAN); +		ath_dbg(common, CONFIG, "spectral scan: channel scan mode enabled\n"); +	} else if (strncmp("manual", buf, 6) == 0) { +		ath9k_spectral_scan_config(sc->hw, SPECTRAL_MANUAL); +		ath_dbg(common, CONFIG, "spectral scan: manual mode enabled\n"); +	} else if (strncmp("disable", buf, 7) == 0) { +		ath9k_spectral_scan_config(sc->hw, SPECTRAL_DISABLED); +		ath_dbg(common, CONFIG, "spectral scan: disabled\n"); +	} else { +		return -EINVAL; +	} + +	return count; +} + +static const struct file_operations fops_spec_scan_ctl = { +	.read = read_file_spec_scan_ctl, +	.write = write_file_spec_scan_ctl, +	.open = simple_open, +	.owner = THIS_MODULE, +	.llseek = default_llseek, +}; + +/*************************/ +/* spectral_short_repeat */ +/*************************/ + +static ssize_t read_file_spectral_short_repeat(struct file *file, +					       char __user *user_buf, +					       size_t count, loff_t *ppos) +{ +	struct ath_softc *sc = file->private_data; +	char buf[32]; +	unsigned int len; + +	len = sprintf(buf, "%d\n", sc->spec_config.short_repeat); +	return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_spectral_short_repeat(struct file *file, +						const char __user *user_buf, +						size_t count, loff_t *ppos) +{ +	struct ath_softc *sc = file->private_data; +	unsigned long val; +	char buf[32]; +	ssize_t len; + +	len = min(count, sizeof(buf) - 1); +	if (copy_from_user(buf, user_buf, len)) +		return -EFAULT; + +	buf[len] = '\0'; +	if (kstrtoul(buf, 0, &val)) +		return -EINVAL; + +	if (val < 0 || val > 1) +		return -EINVAL; + +	sc->spec_config.short_repeat = val; +	return count; +} + +static const struct file_operations fops_spectral_short_repeat = { +	.read = read_file_spectral_short_repeat, +	.write = write_file_spectral_short_repeat, +	.open = simple_open, +	.owner = THIS_MODULE, +	.llseek = default_llseek, +}; + +/******************/ +/* spectral_count */ +/******************/ + +static ssize_t read_file_spectral_count(struct file *file, +					char __user *user_buf, +					size_t count, loff_t *ppos) +{ +	struct ath_softc *sc = file->private_data; +	char buf[32]; +	unsigned int len; + +	len = sprintf(buf, "%d\n", sc->spec_config.count); +	return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_spectral_count(struct file *file, +					 const char __user *user_buf, +					 size_t count, loff_t *ppos) +{ +	struct ath_softc *sc = file->private_data; +	unsigned long val; +	char buf[32]; +	ssize_t len; + +	len = min(count, sizeof(buf) - 1); +	if (copy_from_user(buf, user_buf, len)) +		return -EFAULT; + +	buf[len] = '\0'; +	if (kstrtoul(buf, 0, &val)) +		return -EINVAL; + +	if (val < 0 || val > 255) +		return -EINVAL; + +	sc->spec_config.count = val; +	return count; +} + +static const struct file_operations fops_spectral_count = { +	.read = read_file_spectral_count, +	.write = write_file_spectral_count, +	.open = simple_open, +	.owner = THIS_MODULE, +	.llseek = default_llseek, +}; + +/*******************/ +/* spectral_period */ +/*******************/ + +static ssize_t read_file_spectral_period(struct file *file, +					 char __user *user_buf, +					 size_t count, loff_t *ppos) +{ +	struct ath_softc *sc = file->private_data; +	char buf[32]; +	unsigned int len; + +	len = sprintf(buf, "%d\n", sc->spec_config.period); +	return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_spectral_period(struct file *file, +					  const char __user *user_buf, +					  size_t count, loff_t *ppos) +{ +	struct ath_softc *sc = file->private_data; +	unsigned long val; +	char buf[32]; +	ssize_t len; + +	len = min(count, sizeof(buf) - 1); +	if (copy_from_user(buf, user_buf, len)) +		return -EFAULT; + +	buf[len] = '\0'; +	if (kstrtoul(buf, 0, &val)) +		return -EINVAL; + +	if (val < 0 || val > 255) +		return -EINVAL; + +	sc->spec_config.period = val; +	return count; +} + +static const struct file_operations fops_spectral_period = { +	.read = read_file_spectral_period, +	.write = write_file_spectral_period, +	.open = simple_open, +	.owner = THIS_MODULE, +	.llseek = default_llseek, +}; + +/***********************/ +/* spectral_fft_period */ +/***********************/ + +static ssize_t read_file_spectral_fft_period(struct file *file, +					     char __user *user_buf, +					     size_t count, loff_t *ppos) +{ +	struct ath_softc *sc = file->private_data; +	char buf[32]; +	unsigned int len; + +	len = sprintf(buf, "%d\n", sc->spec_config.fft_period); +	return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_spectral_fft_period(struct file *file, +					      const char __user *user_buf, +					      size_t count, loff_t *ppos) +{ +	struct ath_softc *sc = file->private_data; +	unsigned long val; +	char buf[32]; +	ssize_t len; + +	len = min(count, sizeof(buf) - 1); +	if (copy_from_user(buf, user_buf, len)) +		return -EFAULT; + +	buf[len] = '\0'; +	if (kstrtoul(buf, 0, &val)) +		return -EINVAL; + +	if (val < 0 || val > 15) +		return -EINVAL; + +	sc->spec_config.fft_period = val; +	return count; +} + +static const struct file_operations fops_spectral_fft_period = { +	.read = read_file_spectral_fft_period, +	.write = write_file_spectral_fft_period, +	.open = simple_open, +	.owner = THIS_MODULE, +	.llseek = default_llseek, +}; + +/*******************/ +/* Relay interface */ +/*******************/ + +static struct dentry *create_buf_file_handler(const char *filename, +					      struct dentry *parent, +					      umode_t mode, +					      struct rchan_buf *buf, +					      int *is_global) +{ +	struct dentry *buf_file; + +	buf_file = debugfs_create_file(filename, mode, parent, buf, +				       &relay_file_operations); +	*is_global = 1; +	return buf_file; +} + +static int remove_buf_file_handler(struct dentry *dentry) +{ +	debugfs_remove(dentry); + +	return 0; +} + +static struct rchan_callbacks rfs_spec_scan_cb = { +	.create_buf_file = create_buf_file_handler, +	.remove_buf_file = remove_buf_file_handler, +}; + +/*********************/ +/* Debug Init/Deinit */ +/*********************/ + +void ath9k_spectral_deinit_debug(struct ath_softc *sc) +{ +	if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) { +		relay_close(sc->rfs_chan_spec_scan); +		sc->rfs_chan_spec_scan = NULL; +	} +} + +void ath9k_spectral_init_debug(struct ath_softc *sc) +{ +	sc->rfs_chan_spec_scan = relay_open("spectral_scan", +					    sc->debug.debugfs_phy, +					    1024, 256, &rfs_spec_scan_cb, +					    NULL); +	debugfs_create_file("spectral_scan_ctl", +			    S_IRUSR | S_IWUSR, +			    sc->debug.debugfs_phy, sc, +			    &fops_spec_scan_ctl); +	debugfs_create_file("spectral_short_repeat", +			    S_IRUSR | S_IWUSR, +			    sc->debug.debugfs_phy, sc, +			    &fops_spectral_short_repeat); +	debugfs_create_file("spectral_count", +			    S_IRUSR | S_IWUSR, +			    sc->debug.debugfs_phy, sc, +			    &fops_spectral_count); +	debugfs_create_file("spectral_period", +			    S_IRUSR | S_IWUSR, +			    sc->debug.debugfs_phy, sc, +			    &fops_spectral_period); +	debugfs_create_file("spectral_fft_period", +			    S_IRUSR | S_IWUSR, +			    sc->debug.debugfs_phy, sc, +			    &fops_spectral_fft_period); +} diff --git a/drivers/net/wireless/ath/ath9k/spectral.h b/drivers/net/wireless/ath/ath9k/spectral.h new file mode 100644 index 00000000000..ead63412ee1 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/spectral.h @@ -0,0 +1,212 @@ +/* + * Copyright (c) 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 SPECTRAL_H +#define SPECTRAL_H + +/* enum spectral_mode: + * + * @SPECTRAL_DISABLED: spectral mode is disabled + * @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with + *	something else. + * @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples + *	is performed manually. + * @SPECTRAL_CHANSCAN: Like manual, but also triggered when changing channels + *	during a channel scan. + */ +enum spectral_mode { +	SPECTRAL_DISABLED = 0, +	SPECTRAL_BACKGROUND, +	SPECTRAL_MANUAL, +	SPECTRAL_CHANSCAN, +}; + +#define SPECTRAL_SCAN_BITMASK		0x10 +/* Radar info packet format, used for DFS and spectral formats. */ +struct ath_radar_info { +	u8 pulse_length_pri; +	u8 pulse_length_ext; +	u8 pulse_bw_info; +} __packed; + +/* The HT20 spectral data has 4 bytes of additional information at it's end. + * + * [7:0]: all bins {max_magnitude[1:0], bitmap_weight[5:0]} + * [7:0]: all bins  max_magnitude[9:2] + * [7:0]: all bins {max_index[5:0], max_magnitude[11:10]} + * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned) + */ +struct ath_ht20_mag_info { +	u8 all_bins[3]; +	u8 max_exp; +} __packed; + +#define SPECTRAL_HT20_NUM_BINS		56 + +/* WARNING: don't actually use this struct! MAC may vary the amount of + * data by -1/+2. This struct is for reference only. + */ +struct ath_ht20_fft_packet { +	u8 data[SPECTRAL_HT20_NUM_BINS]; +	struct ath_ht20_mag_info mag_info; +	struct ath_radar_info radar_info; +} __packed; + +#define SPECTRAL_HT20_TOTAL_DATA_LEN	(sizeof(struct ath_ht20_fft_packet)) + +/* Dynamic 20/40 mode: + * + * [7:0]: lower bins {max_magnitude[1:0], bitmap_weight[5:0]} + * [7:0]: lower bins  max_magnitude[9:2] + * [7:0]: lower bins {max_index[5:0], max_magnitude[11:10]} + * [7:0]: upper bins {max_magnitude[1:0], bitmap_weight[5:0]} + * [7:0]: upper bins  max_magnitude[9:2] + * [7:0]: upper bins {max_index[5:0], max_magnitude[11:10]} + * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned) + */ +struct ath_ht20_40_mag_info { +	u8 lower_bins[3]; +	u8 upper_bins[3]; +	u8 max_exp; +} __packed; + +#define SPECTRAL_HT20_40_NUM_BINS		128 + +/* WARNING: don't actually use this struct! MAC may vary the amount of + * data. This struct is for reference only. + */ +struct ath_ht20_40_fft_packet { +	u8 data[SPECTRAL_HT20_40_NUM_BINS]; +	struct ath_ht20_40_mag_info mag_info; +	struct ath_radar_info radar_info; +} __packed; + + +#define SPECTRAL_HT20_40_TOTAL_DATA_LEN	(sizeof(struct ath_ht20_40_fft_packet)) + +/* grabs the max magnitude from the all/upper/lower bins */ +static inline u16 spectral_max_magnitude(u8 *bins) +{ +	return (bins[0] & 0xc0) >> 6 | +	       (bins[1] & 0xff) << 2 | +	       (bins[2] & 0x03) << 10; +} + +/* return the max magnitude from the all/upper/lower bins */ +static inline u8 spectral_max_index(u8 *bins) +{ +	s8 m = (bins[2] & 0xfc) >> 2; + +	/* TODO: this still doesn't always report the right values ... */ +	if (m > 32) +		m |= 0xe0; +	else +		m &= ~0xe0; + +	return m + 29; +} + +/* return the bitmap weight from the all/upper/lower bins */ +static inline u8 spectral_bitmap_weight(u8 *bins) +{ +	return bins[0] & 0x3f; +} + +/* FFT sample format given to userspace via debugfs. + * + * Please keep the type/length at the front position and change + * other fields after adding another sample type + * + * TODO: this might need rework when switching to nl80211-based + * interface. + */ +enum ath_fft_sample_type { +	ATH_FFT_SAMPLE_HT20 = 1, +	ATH_FFT_SAMPLE_HT20_40, +}; + +struct fft_sample_tlv { +	u8 type;	/* see ath_fft_sample */ +	__be16 length; +	/* type dependent data follows */ +} __packed; + +struct fft_sample_ht20 { +	struct fft_sample_tlv tlv; + +	u8 max_exp; + +	__be16 freq; +	s8 rssi; +	s8 noise; + +	__be16 max_magnitude; +	u8 max_index; +	u8 bitmap_weight; + +	__be64 tsf; + +	u8 data[SPECTRAL_HT20_NUM_BINS]; +} __packed; + +struct fft_sample_ht20_40 { +	struct fft_sample_tlv tlv; + +	u8 channel_type; +	__be16 freq; + +	s8 lower_rssi; +	s8 upper_rssi; + +	__be64 tsf; + +	s8 lower_noise; +	s8 upper_noise; + +	__be16 lower_max_magnitude; +	__be16 upper_max_magnitude; + +	u8 lower_max_index; +	u8 upper_max_index; + +	u8 lower_bitmap_weight; +	u8 upper_bitmap_weight; + +	u8 max_exp; + +	u8 data[SPECTRAL_HT20_40_NUM_BINS]; +} __packed; + +void ath9k_spectral_init_debug(struct ath_softc *sc); +void ath9k_spectral_deinit_debug(struct ath_softc *sc); + +void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw); +int ath9k_spectral_scan_config(struct ieee80211_hw *hw, +			       enum spectral_mode spectral_mode); + +#ifdef CONFIG_ATH9K_DEBUGFS +int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, +		    struct ath_rx_status *rs, u64 tsf); +#else +static inline int ath_process_fft(struct ath_softc *sc, +				  struct ieee80211_hdr *hdr, +				  struct ath_rx_status *rs, u64 tsf) +{ +	return 0; +} +#endif /* CONFIG_ATH9K_DEBUGFS */ + +#endif /* SPECTRAL_H */ diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c new file mode 100644 index 00000000000..a65cfb91adc --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/tx99.c @@ -0,0 +1,272 @@ +/* + * Copyright (c) 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 "ath9k.h" + +static void ath9k_tx99_stop(struct ath_softc *sc) +{ +	struct ath_hw *ah = sc->sc_ah; +	struct ath_common *common = ath9k_hw_common(ah); + +	ath_drain_all_txq(sc); +	ath_startrecv(sc); + +	ath9k_hw_set_interrupts(ah); +	ath9k_hw_enable_interrupts(ah); + +	ieee80211_wake_queues(sc->hw); + +	kfree_skb(sc->tx99_skb); +	sc->tx99_skb = NULL; +	sc->tx99_state = false; + +	ath9k_hw_tx99_stop(sc->sc_ah); +	ath_dbg(common, XMIT, "TX99 stopped\n"); +} + +static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc) +{ +	static u8 PN9Data[] = {0xff, 0x87, 0xb8, 0x59, 0xb7, 0xa1, 0xcc, 0x24, +			       0x57, 0x5e, 0x4b, 0x9c, 0x0e, 0xe9, 0xea, 0x50, +			       0x2a, 0xbe, 0xb4, 0x1b, 0xb6, 0xb0, 0x5d, 0xf1, +			       0xe6, 0x9a, 0xe3, 0x45, 0xfd, 0x2c, 0x53, 0x18, +			       0x0c, 0xca, 0xc9, 0xfb, 0x49, 0x37, 0xe5, 0xa8, +			       0x51, 0x3b, 0x2f, 0x61, 0xaa, 0x72, 0x18, 0x84, +			       0x02, 0x23, 0x23, 0xab, 0x63, 0x89, 0x51, 0xb3, +			       0xe7, 0x8b, 0x72, 0x90, 0x4c, 0xe8, 0xfb, 0xc0}; +	u32 len = 1200; +	struct ieee80211_tx_rate *rate; +	struct ieee80211_hw *hw = sc->hw; +	struct ath_hw *ah = sc->sc_ah; +	struct ieee80211_hdr *hdr; +	struct ieee80211_tx_info *tx_info; +	struct sk_buff *skb; + +	skb = alloc_skb(len, GFP_KERNEL); +	if (!skb) +		return NULL; + +	skb_put(skb, len); + +	memset(skb->data, 0, len); + +	hdr = (struct ieee80211_hdr *)skb->data; +	hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA); +	hdr->duration_id = 0; + +	memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN); +	memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN); +	memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN); + +	hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); + +	tx_info = IEEE80211_SKB_CB(skb); +	memset(tx_info, 0, sizeof(*tx_info)); +	rate = &tx_info->control.rates[0]; +	tx_info->band = hw->conf.chandef.chan->band; +	tx_info->flags = IEEE80211_TX_CTL_NO_ACK; +	tx_info->control.vif = sc->tx99_vif; +	rate->count = 1; +	if (ah->curchan && IS_CHAN_HT(ah->curchan)) { +		rate->flags |= IEEE80211_TX_RC_MCS; +		if (IS_CHAN_HT40(ah->curchan)) +			rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; +	} + +	memcpy(skb->data + sizeof(*hdr), PN9Data, sizeof(PN9Data)); + +	return skb; +} + +static void ath9k_tx99_deinit(struct ath_softc *sc) +{ +	ath_reset(sc); + +	ath9k_ps_wakeup(sc); +	ath9k_tx99_stop(sc); +	ath9k_ps_restore(sc); +} + +static int ath9k_tx99_init(struct ath_softc *sc) +{ +	struct ieee80211_hw *hw = sc->hw; +	struct ath_hw *ah = sc->sc_ah; +	struct ath_common *common = ath9k_hw_common(ah); +	struct ath_tx_control txctl; +	int r; + +	if (test_bit(ATH_OP_INVALID, &common->op_flags)) { +		ath_err(common, +			"driver is in invalid state unable to use TX99"); +		return -EINVAL; +	} + +	sc->tx99_skb = ath9k_build_tx99_skb(sc); +	if (!sc->tx99_skb) +		return -ENOMEM; + +	memset(&txctl, 0, sizeof(txctl)); +	txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; + +	ath_reset(sc); + +	ath9k_ps_wakeup(sc); + +	ath9k_hw_disable_interrupts(ah); +	atomic_set(&ah->intr_ref_cnt, -1); +	ath_drain_all_txq(sc); +	ath_stoprecv(sc); + +	sc->tx99_state = true; + +	ieee80211_stop_queues(hw); + +	if (sc->tx99_power == MAX_RATE_POWER + 1) +		sc->tx99_power = MAX_RATE_POWER; + +	ath9k_hw_tx99_set_txpower(ah, sc->tx99_power); +	r = ath9k_tx99_send(sc, sc->tx99_skb, &txctl); +	if (r) { +		ath_dbg(common, XMIT, "Failed to xmit TX99 skb\n"); +		return r; +	} + +	ath_dbg(common, XMIT, "TX99 xmit started using %d ( %ddBm)\n", +		sc->tx99_power, +		sc->tx99_power / 2); + +	/* We leave the harware awake as it will be chugging on */ + +	return 0; +} + +static ssize_t read_file_tx99(struct file *file, char __user *user_buf, +			      size_t count, loff_t *ppos) +{ +	struct ath_softc *sc = file->private_data; +	char buf[3]; +	unsigned int len; + +	len = sprintf(buf, "%d\n", sc->tx99_state); +	return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_tx99(struct file *file, const char __user *user_buf, +			       size_t count, loff_t *ppos) +{ +	struct ath_softc *sc = file->private_data; +	struct ath_common *common = ath9k_hw_common(sc->sc_ah); +	char buf[32]; +	bool start; +	ssize_t len; +	int r; + +	if (sc->nvifs > 1) +		return -EOPNOTSUPP; + +	len = min(count, sizeof(buf) - 1); +	if (copy_from_user(buf, user_buf, len)) +		return -EFAULT; + +	if (strtobool(buf, &start)) +		return -EINVAL; + +	if (start == sc->tx99_state) { +		if (!start) +			return count; +		ath_dbg(common, XMIT, "Resetting TX99\n"); +		ath9k_tx99_deinit(sc); +	} + +	if (!start) { +		ath9k_tx99_deinit(sc); +		return count; +	} + +	r = ath9k_tx99_init(sc); +	if (r) +		return r; + +	return count; +} + +static const struct file_operations fops_tx99 = { +	.read = read_file_tx99, +	.write = write_file_tx99, +	.open = simple_open, +	.owner = THIS_MODULE, +	.llseek = default_llseek, +}; + +static ssize_t read_file_tx99_power(struct file *file, +				    char __user *user_buf, +				    size_t count, loff_t *ppos) +{ +	struct ath_softc *sc = file->private_data; +	char buf[32]; +	unsigned int len; + +	len = sprintf(buf, "%d (%d dBm)\n", +		      sc->tx99_power, +		      sc->tx99_power / 2); + +	return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_tx99_power(struct file *file, +				     const char __user *user_buf, +				     size_t count, loff_t *ppos) +{ +	struct ath_softc *sc = file->private_data; +	int r; +	u8 tx_power; + +	r = kstrtou8_from_user(user_buf, count, 0, &tx_power); +	if (r) +		return r; + +	if (tx_power > MAX_RATE_POWER) +		return -EINVAL; + +	sc->tx99_power = tx_power; + +	ath9k_ps_wakeup(sc); +	ath9k_hw_tx99_set_txpower(sc->sc_ah, sc->tx99_power); +	ath9k_ps_restore(sc); + +	return count; +} + +static const struct file_operations fops_tx99_power = { +	.read = read_file_tx99_power, +	.write = write_file_tx99_power, +	.open = simple_open, +	.owner = THIS_MODULE, +	.llseek = default_llseek, +}; + +void ath9k_tx99_init_debug(struct ath_softc *sc) +{ +	if (!AR_SREV_9300_20_OR_LATER(sc->sc_ah)) +		return; + +	debugfs_create_file("tx99", S_IRUSR | S_IWUSR, +			    sc->debug.debugfs_phy, sc, +			    &fops_tx99); +	debugfs_create_file("tx99_power", S_IRUSR | S_IWUSR, +			    sc->debug.debugfs_phy, sc, +			    &fops_tx99_power); +} diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h index fde6da619f3..0db37f23001 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.h +++ b/drivers/net/wireless/ath/ath9k/wmi.h @@ -39,7 +39,7 @@ struct wmi_fw_version {  struct wmi_event_swba {  	__be64 tsf;  	u8 beacon_pending; -}; +} __packed;  /*   * 64 - HTC header - WMI header - 1 / txstatus diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 81c88dd606d..2879887f569 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 2012 Qualcomm Atheros, Inc. + * Copyright (c) 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 @@ -14,409 +14,347 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <linux/export.h>  #include "ath9k.h" -#include "reg.h" -#include "hw-ops.h" -const char *ath9k_hw_wow_event_to_string(u32 wow_event) -{ -	if (wow_event & AH_WOW_MAGIC_PATTERN_EN) -		return "Magic pattern"; -	if (wow_event & AH_WOW_USER_PATTERN_EN) -		return "User pattern"; -	if (wow_event & AH_WOW_LINK_CHANGE) -		return "Link change"; -	if (wow_event & AH_WOW_BEACON_MISS) -		return "Beacon miss"; - -	return  "unknown reason"; -} -EXPORT_SYMBOL(ath9k_hw_wow_event_to_string); +static const struct wiphy_wowlan_support ath9k_wowlan_support = { +	.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, +	.n_patterns = MAX_NUM_USER_PATTERN, +	.pattern_min_len = 1, +	.pattern_max_len = MAX_PATTERN_SIZE, +}; -static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah) +static void ath9k_wow_map_triggers(struct ath_softc *sc, +				   struct cfg80211_wowlan *wowlan, +				   u32 *wow_triggers)  { -	struct ath_common *common = ath9k_hw_common(ah); +	if (wowlan->disconnect) +		*wow_triggers |= AH_WOW_LINK_CHANGE | +				 AH_WOW_BEACON_MISS; +	if (wowlan->magic_pkt) +		*wow_triggers |= AH_WOW_MAGIC_PATTERN_EN; -	REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); +	if (wowlan->n_patterns) +		*wow_triggers |= AH_WOW_USER_PATTERN_EN; -	/* set rx disable bit */ -	REG_WRITE(ah, AR_CR, AR_CR_RXD); - -	if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0, AH_WAIT_TIMEOUT)) { -		ath_err(common, "Failed to stop Rx DMA in 10ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n", -			REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW)); -		return; -	} +	sc->wow_enabled = *wow_triggers; -	REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT);  } -static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah) +static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)  { +	struct ath_hw *ah = sc->sc_ah;  	struct ath_common *common = ath9k_hw_common(ah); -	u8 sta_mac_addr[ETH_ALEN], ap_mac_addr[ETH_ALEN]; -	u32 ctl[13] = {0}; -	u32 data_word[KAL_NUM_DATA_WORDS]; -	u8 i; -	u32 wow_ka_data_word0; - -	memcpy(sta_mac_addr, common->macaddr, ETH_ALEN); -	memcpy(ap_mac_addr, common->curbssid, ETH_ALEN); - -	/* set the transmit buffer */ -	ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16)); -	ctl[1] = 0; -	ctl[3] = 0xb;	/* OFDM_6M hardware value for this rate */ -	ctl[4] = 0; -	ctl[7] = (ah->txchainmask) << 2; -	ctl[2] = 0xf << 16; /* tx_tries 0 */ - -	for (i = 0; i < KAL_NUM_DESC_WORDS; i++) -		REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); - -	REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); - -	data_word[0] = (KAL_FRAME_TYPE << 2) | (KAL_FRAME_SUB_TYPE << 4) | -		       (KAL_TO_DS << 8) | (KAL_DURATION_ID << 16); -	data_word[1] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) | -		       (ap_mac_addr[1] << 8) | (ap_mac_addr[0]); -	data_word[2] = (sta_mac_addr[1] << 24) | (sta_mac_addr[0] << 16) | -		       (ap_mac_addr[5] << 8) | (ap_mac_addr[4]); -	data_word[3] = (sta_mac_addr[5] << 24) | (sta_mac_addr[4] << 16) | -		       (sta_mac_addr[3] << 8) | (sta_mac_addr[2]); -	data_word[4] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) | -		       (ap_mac_addr[1] << 8) | (ap_mac_addr[0]); -	data_word[5] = (ap_mac_addr[5] << 8) | (ap_mac_addr[4]); - -	if (AR_SREV_9462_20(ah)) { -		/* AR9462 2.0 has an extra descriptor word (time based -		 * discard) compared to other chips */ -		REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + (12 * 4)), 0); -		wow_ka_data_word0 = AR_WOW_TXBUF(13); -	} else { -		wow_ka_data_word0 = AR_WOW_TXBUF(12); -	} - -	for (i = 0; i < KAL_NUM_DATA_WORDS; i++) -		REG_WRITE(ah, (wow_ka_data_word0 + i*4), data_word[i]); - -} - -void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, -				u8 *user_mask, int pattern_count, -				int pattern_len) -{ -	int i; -	u32 pattern_val, mask_val; -	u32 set, clr; +	int pattern_count = 0; +	int i, byte_cnt; +	u8 dis_deauth_pattern[MAX_PATTERN_SIZE]; +	u8 dis_deauth_mask[MAX_PATTERN_SIZE]; -	/* FIXME: should check count by querying the hardware capability */ -	if (pattern_count >= MAX_NUM_PATTERN) -		return; - -	REG_SET_BIT(ah, AR_WOW_PATTERN, BIT(pattern_count)); - -	/* set the registers for pattern */ -	for (i = 0; i < MAX_PATTERN_SIZE; i += 4) { -		memcpy(&pattern_val, user_pattern, 4); -		REG_WRITE(ah, (AR_WOW_TB_PATTERN(pattern_count) + i), -			  pattern_val); -		user_pattern += 4; -	} - -	/* set the registers for mask */ -	for (i = 0; i < MAX_PATTERN_MASK_SIZE; i += 4) { -		memcpy(&mask_val, user_mask, 4); -		REG_WRITE(ah, (AR_WOW_TB_MASK(pattern_count) + i), mask_val); -		user_mask += 4; -	} +	memset(dis_deauth_pattern, 0, MAX_PATTERN_SIZE); +	memset(dis_deauth_mask, 0, MAX_PATTERN_SIZE); -	/* set the pattern length to be matched +	/* +	 * Create Dissassociate / Deauthenticate packet filter +	 * +	 *     2 bytes        2 byte    6 bytes   6 bytes  6 bytes +	 *  +--------------+----------+---------+--------+--------+---- +	 *  + Frame Control+ Duration +   DA    +  SA    +  BSSID + +	 *  +--------------+----------+---------+--------+--------+----  	 * -	 * AR_WOW_LENGTH1_REG1 -	 * bit 31:24 pattern 0 length -	 * bit 23:16 pattern 1 length -	 * bit 15:8 pattern 2 length -	 * bit 7:0 pattern 3 length +	 * The above is the management frame format for disassociate/ +	 * deauthenticate pattern, from this we need to match the first byte +	 * of 'Frame Control' and DA, SA, and BSSID fields +	 * (skipping 2nd byte of FC and Duration feild.  	 * -	 * AR_WOW_LENGTH1_REG2 -	 * bit 31:24 pattern 4 length -	 * bit 23:16 pattern 5 length -	 * bit 15:8 pattern 6 length -	 * bit 7:0 pattern 7 length +	 * Disassociate pattern +	 * -------------------- +	 * Frame control = 00 00 1010 +	 * DA, SA, BSSID = x:x:x:x:x:x +	 * Pattern will be A0000000 | x:x:x:x:x:x | x:x:x:x:x:x +	 *			    | x:x:x:x:x:x  -- 22 bytes  	 * -	 * the below logic writes out the new -	 * pattern length for the corresponding -	 * pattern_count, while masking out the -	 * other fields +	 * Deauthenticate pattern +	 * ---------------------- +	 * Frame control = 00 00 1100 +	 * DA, SA, BSSID = x:x:x:x:x:x +	 * Pattern will be C0000000 | x:x:x:x:x:x | x:x:x:x:x:x +	 *			    | x:x:x:x:x:x  -- 22 bytes  	 */ -	ah->wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT); - -	if (pattern_count < 4) { -		/* Pattern 0-3 uses AR_WOW_LENGTH1 register */ -		set = (pattern_len & AR_WOW_LENGTH_MAX) << -		       AR_WOW_LEN1_SHIFT(pattern_count); -		clr = AR_WOW_LENGTH1_MASK(pattern_count); -		REG_RMW(ah, AR_WOW_LENGTH1, set, clr); -	} else { -		/* Pattern 4-7 uses AR_WOW_LENGTH2 register */ -		set = (pattern_len & AR_WOW_LENGTH_MAX) << -		       AR_WOW_LEN2_SHIFT(pattern_count); -		clr = AR_WOW_LENGTH2_MASK(pattern_count); -		REG_RMW(ah, AR_WOW_LENGTH2, set, clr); -	} +	/* Create Disassociate Pattern first */ -} -EXPORT_SYMBOL(ath9k_hw_wow_apply_pattern); +	byte_cnt = 0; -u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) -{ -	u32 wow_status = 0; -	u32 val = 0, rval; +	/* Fill out the mask with all FF's */ -	/* -	 * read the WoW status register to know -	 * the wakeup reason -	 */ -	rval = REG_READ(ah, AR_WOW_PATTERN); -	val = AR_WOW_STATUS(rval); +	for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++) +		dis_deauth_mask[i] = 0xff; -	/* -	 * mask only the WoW events that we have enabled. Sometimes -	 * we have spurious WoW events from the AR_WOW_PATTERN -	 * register. This mask will clean it up. -	 */ +	/* copy the first byte of frame control field */ +	dis_deauth_pattern[byte_cnt] = 0xa0; +	byte_cnt++; -	val &= ah->wow_event_mask; - -	if (val) { -		if (val & AR_WOW_MAGIC_PAT_FOUND) -			wow_status |= AH_WOW_MAGIC_PATTERN_EN; -		if (AR_WOW_PATTERN_FOUND(val)) -			wow_status |= AH_WOW_USER_PATTERN_EN; -		if (val & AR_WOW_KEEP_ALIVE_FAIL) -			wow_status |= AH_WOW_LINK_CHANGE; -		if (val & AR_WOW_BEACON_FAIL) -			wow_status |= AH_WOW_BEACON_MISS; -	} +	/* skip 2nd byte of frame control and Duration field */ +	byte_cnt += 3;  	/* -	 * set and clear WOW_PME_CLEAR registers for the chip to -	 * generate next wow signal. -	 * disable D3 before accessing other registers ? +	 * need not match the destination mac address, it can be a broadcast +	 * mac address or an unicast to this station  	 */ +	byte_cnt += 6; -	/* do we need to check the bit value 0x01000000 (7-10) ?? */ -	REG_RMW(ah, AR_PCIE_PM_CTRL, AR_PMCTRL_WOW_PME_CLR, -		AR_PMCTRL_PWR_STATE_D1D3); +	/* copy the source mac address */ +	memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN); -	/* -	 * clear all events -	 */ -	REG_WRITE(ah, AR_WOW_PATTERN, -		  AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN))); +	byte_cnt += 6; -	/* -	 * restore the beacon threshold to init value -	 */ -	REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR); +	/* copy the bssid, its same as the source mac address */ + +	memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN); + +	/* Create Disassociate pattern mask */ + +	dis_deauth_mask[0] = 0xfe; +	dis_deauth_mask[1] = 0x03; +	dis_deauth_mask[2] = 0xc0; + +	ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n"); +	ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, +				   pattern_count, byte_cnt); + +	pattern_count++;  	/* -	 * Restore the way the PCI-E reset, Power-On-Reset, external -	 * PCIE_POR_SHORT pins are tied to its original value. -	 * Previously just before WoW sleep, we untie the PCI-E -	 * reset to our Chip's Power On Reset so that any PCI-E -	 * reset from the bus will not reset our chip +	 * for de-authenticate pattern, only the first byte of the frame +	 * control field gets changed from 0xA0 to 0xC0  	 */ -	if (ah->is_pciexpress) -		ath9k_hw_configpcipowersave(ah, false); +	dis_deauth_pattern[0] = 0xC0; -	ah->wow_event_mask = 0; +	ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, +				   pattern_count, byte_cnt); -	return wow_status;  } -EXPORT_SYMBOL(ath9k_hw_wow_wakeup); -void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) +static void ath9k_wow_add_pattern(struct ath_softc *sc, +				  struct cfg80211_wowlan *wowlan)  { -	u32 wow_event_mask; -	u32 set, clr; +	struct ath_hw *ah = sc->sc_ah; +	struct ath9k_wow_pattern *wow_pattern = NULL; +	struct cfg80211_pkt_pattern *patterns = wowlan->patterns; +	int mask_len; +	s8 i = 0; -	/* -	 * wow_event_mask is a mask to the AR_WOW_PATTERN register to -	 * indicate which WoW events we have enabled. The WoW events -	 * are from the 'pattern_enable' in this function and -	 * 'pattern_count' of ath9k_hw_wow_apply_pattern() -	 */ -	wow_event_mask = ah->wow_event_mask; +	if (!wowlan->n_patterns) +		return;  	/* -	 * Untie Power-on-Reset from the PCI-E-Reset. When we are in -	 * WOW sleep, we do want the Reset from the PCI-E to disturb -	 * our hw state +	 * Add the new user configured patterns  	 */ -	if (ah->is_pciexpress) { +	for (i = 0; i < wowlan->n_patterns; i++) { + +		wow_pattern = kzalloc(sizeof(*wow_pattern), GFP_KERNEL); + +		if (!wow_pattern) +			return; + +		/* +		 * TODO: convert the generic user space pattern to +		 * appropriate chip specific/802.11 pattern. +		 */ + +		mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8); +		memset(wow_pattern->pattern_bytes, 0, MAX_PATTERN_SIZE); +		memset(wow_pattern->mask_bytes, 0, MAX_PATTERN_SIZE); +		memcpy(wow_pattern->pattern_bytes, patterns[i].pattern, +		       patterns[i].pattern_len); +		memcpy(wow_pattern->mask_bytes, patterns[i].mask, mask_len); +		wow_pattern->pattern_len = patterns[i].pattern_len; +  		/* -		 * we need to untie the internal POR (power-on-reset) -		 * to the external PCI-E reset. We also need to tie -		 * the PCI-E Phy reset to the PCI-E reset. +		 * just need to take care of deauth and disssoc pattern, +		 * make sure we don't overwrite them.  		 */ -		set = AR_WA_RESET_EN | AR_WA_POR_SHORT; -		clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE; -		REG_RMW(ah, AR_WA, set, clr); + +		ath9k_hw_wow_apply_pattern(ah, wow_pattern->pattern_bytes, +					   wow_pattern->mask_bytes, +					   i + 2, +					   wow_pattern->pattern_len); +		kfree(wow_pattern); +  	} -	/* -	 * set the power states appropriately and enable PME -	 */ -	set = AR_PMCTRL_HOST_PME_EN | AR_PMCTRL_PWR_PM_CTRL_ENA | -	      AR_PMCTRL_AUX_PWR_DET | AR_PMCTRL_WOW_PME_CLR; +} -	/* -	 * set and clear WOW_PME_CLEAR registers for the chip -	 * to generate next wow signal. -	 */ -	REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set); -	clr = AR_PMCTRL_WOW_PME_CLR; -	REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr); +int ath9k_suspend(struct ieee80211_hw *hw, +		  struct cfg80211_wowlan *wowlan) +{ +	struct ath_softc *sc = hw->priv; +	struct ath_hw *ah = sc->sc_ah; +	struct ath_common *common = ath9k_hw_common(ah); +	u32 wow_triggers_enabled = 0; +	int ret = 0; -	/* -	 * Setup for: -	 *	- beacon misses -	 *	- magic pattern -	 *	- keep alive timeout -	 *	- pattern matching -	 */ +	mutex_lock(&sc->mutex); -	/* -	 * Program default values for pattern backoff, aifs/slot/KAL count, -	 * beacon miss timeout, KAL timeout, etc. -	 */ -	set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF); -	REG_SET_BIT(ah, AR_WOW_PATTERN, set); +	ath_cancel_work(sc); +	ath_stop_ani(sc); -	set = AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) | -	      AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) | -	      AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT); -	REG_SET_BIT(ah, AR_WOW_COUNT, set); +	if (test_bit(ATH_OP_INVALID, &common->op_flags)) { +		ath_dbg(common, ANY, "Device not present\n"); +		ret = -EINVAL; +		goto fail_wow; +	} -	if (pattern_enable & AH_WOW_BEACON_MISS) -		set = AR_WOW_BEACON_TIMO; -	/* We are not using beacon miss, program a large value */ -	else -		set = AR_WOW_BEACON_TIMO_MAX; +	if (WARN_ON(!wowlan)) { +		ath_dbg(common, WOW, "None of the WoW triggers enabled\n"); +		ret = -EINVAL; +		goto fail_wow; +	} -	REG_WRITE(ah, AR_WOW_BCN_TIMO, set); +	if (!device_can_wakeup(sc->dev)) { +		ath_dbg(common, WOW, "device_can_wakeup failed, WoW is not enabled\n"); +		ret = 1; +		goto fail_wow; +	}  	/* -	 * Keep alive timo in ms except AR9280 +	 * none of the sta vifs are associated +	 * and we are not currently handling multivif +	 * cases, for instance we have to seperately +	 * configure 'keep alive frame' for each +	 * STA.  	 */ -	if (!pattern_enable) -		set = AR_WOW_KEEP_ALIVE_NEVER; -	else -		set = KAL_TIMEOUT * 32; -	REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, set); +	if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { +		ath_dbg(common, WOW, "None of the STA vifs are associated\n"); +		ret = 1; +		goto fail_wow; +	} + +	if (sc->nvifs > 1) { +		ath_dbg(common, WOW, "WoW for multivif is not yet supported\n"); +		ret = 1; +		goto fail_wow; +	} + +	ath9k_wow_map_triggers(sc, wowlan, &wow_triggers_enabled); + +	ath_dbg(common, WOW, "WoW triggers enabled 0x%x\n", +		wow_triggers_enabled); + +	ath9k_ps_wakeup(sc); + +	ath9k_stop_btcoex(sc);  	/* -	 * Keep alive delay in us. based on 'power on clock', -	 * therefore in usec +	 * Enable wake up on recieving disassoc/deauth +	 * frame by default.  	 */ -	set = KAL_DELAY * 1000; -	REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY, set); +	ath9k_wow_add_disassoc_deauth_pattern(sc); + +	if (wow_triggers_enabled & AH_WOW_USER_PATTERN_EN) +		ath9k_wow_add_pattern(sc, wowlan); +	spin_lock_bh(&sc->sc_pcu_lock);  	/* -	 * Create keep alive pattern to respond to beacons +	 * To avoid false wake, we enable beacon miss interrupt only +	 * when we go to sleep. We save the current interrupt mask +	 * so we can restore it after the system wakes up  	 */ -	ath9k_wow_create_keep_alive_pattern(ah); +	sc->wow_intr_before_sleep = ah->imask; +	ah->imask &= ~ATH9K_INT_GLOBAL; +	ath9k_hw_disable_interrupts(ah); +	ah->imask = ATH9K_INT_BMISS | ATH9K_INT_GLOBAL; +	ath9k_hw_set_interrupts(ah); +	ath9k_hw_enable_interrupts(ah); + +	spin_unlock_bh(&sc->sc_pcu_lock);  	/* -	 * Configure MAC WoW Registers +	 * we can now sync irq and kill any running tasklets, since we already +	 * disabled interrupts and not holding a spin lock  	 */ -	set = 0; -	/* Send keep alive timeouts anyway */ -	clr = AR_WOW_KEEP_ALIVE_AUTO_DIS; +	synchronize_irq(sc->irq); +	tasklet_kill(&sc->intr_tq); -	if (pattern_enable & AH_WOW_LINK_CHANGE) -		wow_event_mask |= AR_WOW_KEEP_ALIVE_FAIL; -	else -		set = AR_WOW_KEEP_ALIVE_FAIL_DIS; +	ath9k_hw_wow_enable(ah, wow_triggers_enabled); -	set = AR_WOW_KEEP_ALIVE_FAIL_DIS; -	REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr); +	ath9k_ps_restore(sc); +	ath_dbg(common, ANY, "WoW enabled in ath9k\n"); +	atomic_inc(&sc->wow_sleep_proc_intr); -	/* -	 * we are relying on a bmiss failure. ensure we have -	 * enough threshold to prevent false positives -	 */ -	REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, -		      AR_WOW_BMISSTHRESHOLD); +fail_wow: +	mutex_unlock(&sc->mutex); +	return ret; +} + +int ath9k_resume(struct ieee80211_hw *hw) +{ +	struct ath_softc *sc = hw->priv; +	struct ath_hw *ah = sc->sc_ah; +	struct ath_common *common = ath9k_hw_common(ah); +	u32 wow_status; -	set = 0; -	clr = 0; +	mutex_lock(&sc->mutex); -	if (pattern_enable & AH_WOW_BEACON_MISS) { -		set = AR_WOW_BEACON_FAIL_EN; -		wow_event_mask |= AR_WOW_BEACON_FAIL; -	} else { -		clr = AR_WOW_BEACON_FAIL_EN; +	ath9k_ps_wakeup(sc); + +	spin_lock_bh(&sc->sc_pcu_lock); + +	ath9k_hw_disable_interrupts(ah); +	ah->imask = sc->wow_intr_before_sleep; +	ath9k_hw_set_interrupts(ah); +	ath9k_hw_enable_interrupts(ah); + +	spin_unlock_bh(&sc->sc_pcu_lock); + +	wow_status = ath9k_hw_wow_wakeup(ah); + +	if (atomic_read(&sc->wow_got_bmiss_intr) == 0) { +		/* +		 * some devices may not pick beacon miss +		 * as the reason they woke up so we add +		 * that here for that shortcoming. +		 */ +		wow_status |= AH_WOW_BEACON_MISS; +		atomic_dec(&sc->wow_got_bmiss_intr); +		ath_dbg(common, ANY, "Beacon miss interrupt picked up during WoW sleep\n");  	} -	REG_RMW(ah, AR_WOW_BCN_EN, set, clr); +	atomic_dec(&sc->wow_sleep_proc_intr); -	set = 0; -	clr = 0; -	/* -	 * Enable the magic packet registers -	 */ -	if (pattern_enable & AH_WOW_MAGIC_PATTERN_EN) { -		set = AR_WOW_MAGIC_EN; -		wow_event_mask |= AR_WOW_MAGIC_PAT_FOUND; -	} else { -		clr = AR_WOW_MAGIC_EN; +	if (wow_status) { +		ath_dbg(common, ANY, "Waking up due to WoW triggers %s with WoW status = %x\n", +			ath9k_hw_wow_event_to_string(wow_status), wow_status);  	} -	set |= AR_WOW_MAC_INTR_EN; -	REG_RMW(ah, AR_WOW_PATTERN, set, clr); -	REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B, -		  AR_WOW_PATTERN_SUPPORTED); +	ath_restart_work(sc); +	ath9k_start_btcoex(sc); -	/* -	 * Set the power states appropriately and enable PME -	 */ -	clr = 0; -	set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN | -	      AR_PMCTRL_PWR_PM_CTRL_ENA; +	ath9k_ps_restore(sc); +	mutex_unlock(&sc->mutex); -	clr = AR_PCIE_PM_CTRL_ENA; -	REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr); +	return 0; +} -	/* -	 * this is needed to prevent the chip waking up -	 * the host within 3-4 seconds with certain -	 * platform/BIOS. The fix is to enable -	 * D1 & D3 to match original definition and -	 * also match the OTP value. Anyway this -	 * is more related to SW WOW. -	 */ -	clr = AR_PMCTRL_PWR_STATE_D1D3; -	REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr); +void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled) +{ +	struct ath_softc *sc = hw->priv; -	set = AR_PMCTRL_PWR_STATE_D1D3_REAL; -	REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set); +	mutex_lock(&sc->mutex); +	device_init_wakeup(sc->dev, 1); +	device_set_wakeup_enable(sc->dev, enabled); +	mutex_unlock(&sc->mutex); +} -	REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM); +void ath9k_init_wow(struct ieee80211_hw *hw) +{ +	struct ath_softc *sc = hw->priv; -	/* to bring down WOW power low margin */ -	set = BIT(13); -	REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set); -	/* HW WoW */ -	clr = BIT(5); -	REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr); +	if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) && +	    (sc->driver_data & ATH9K_PCI_WOW) && +	    device_can_wakeup(sc->dev)) +		hw->wiphy->wowlan = &ath9k_wowlan_support; -	ath9k_hw_set_powermode_wow_sleep(ah); -	ah->wow_event_mask = wow_event_mask; +	atomic_set(&sc->wow_sleep_proc_intr, -1); +	atomic_set(&sc->wow_got_bmiss_intr, -1);  } -EXPORT_SYMBOL(ath9k_hw_wow_enable); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index dd30452df96..7c28cb55610 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -47,8 +47,6 @@ static u16 bits_per_symbol[][2] = {  	{   260,  540 },     /*  7: 64-QAM 5/6 */  }; -#define IS_HT_RATE(_rate)     ((_rate) & 0x80) -  static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,  			       struct ath_atx_tid *tid, struct sk_buff *skb);  static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, @@ -109,9 +107,6 @@ static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)  {  	struct ath_atx_ac *ac = tid->ac; -	if (tid->paused) -		return; -  	if (tid->sched)  		return; @@ -174,14 +169,7 @@ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,  static struct ath_atx_tid *  ath_get_skb_tid(struct ath_softc *sc, struct ath_node *an, struct sk_buff *skb)  { -	struct ieee80211_hdr *hdr; -	u8 tidno = 0; - -	hdr = (struct ieee80211_hdr *) skb->data; -	if (ieee80211_is_data_qos(hdr->frame_control)) -		tidno = ieee80211_get_qos_ctl(hdr)[0]; - -	tidno &= IEEE80211_QOS_CTL_TID_MASK; +	u8 tidno = skb->priority & IEEE80211_QOS_CTL_TID_MASK;  	return ATH_AN_2_TID(an, tidno);  } @@ -781,11 +769,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,  	if (bt_aggr_limit)  		aggr_limit = bt_aggr_limit; -	/* -	 * h/w can accept aggregates up to 16 bit lengths (65535). -	 * The IE, however can hold up to 65536, which shows up here -	 * as zero. Ignore 65536 since we  are constrained by hw. -	 */  	if (tid->an->maxampdu)  		aggr_limit = min(aggr_limit, tid->an->maxampdu); @@ -904,6 +887,15 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,  		tx_info = IEEE80211_SKB_CB(skb);  		tx_info->flags &= ~IEEE80211_TX_CTL_CLEAR_PS_FILT; + +		/* +		 * No aggregation session is running, but there may be frames +		 * from a previous session or a failed attempt in the queue. +		 * Send them out as normal data frames +		 */ +		if (!tid->active) +			tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU; +  		if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) {  			bf->bf_state.bf_type = 0;  			return bf; @@ -1054,11 +1046,11 @@ static int ath_max_framelen(int usec, int mcs, bool ht40, bool sgi)  	int symbols, bits;  	int bytes = 0; +	usec -= L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);  	symbols = sgi ? TIME_SYMBOLS_HALFGI(usec) : TIME_SYMBOLS(usec);  	bits = symbols * bits_per_symbol[mcs % 8][ht40] * streams;  	bits -= OFDM_PLCP_BITS;  	bytes = bits / 8; -	bytes -= L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);  	if (bytes > 65532)  		bytes = 65532; @@ -1090,6 +1082,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,  			     struct ath_tx_info *info, int len, bool rts)  {  	struct ath_hw *ah = sc->sc_ah; +	struct ath_common *common = ath9k_hw_common(ah);  	struct sk_buff *skb;  	struct ieee80211_tx_info *tx_info;  	struct ieee80211_tx_rate *rates; @@ -1159,7 +1152,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,  		}  		/* legacy rates */ -		rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx]; +		rate = &common->sbands[tx_info->band].bitrates[rates[i].idx];  		if ((tx_info->band == IEEE80211_BAND_2GHZ) &&  		    !(rate->flags & IEEE80211_RATE_ERP_G))  			phy = WLAN_RC_PHY_CCK; @@ -1241,12 +1234,13 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,  		if (bf->bf_next)  			info.link = bf->bf_next->bf_daddr;  		else -			info.link = 0; +			info.link = (sc->tx99_state) ? bf->bf_daddr : 0;  		if (!bf_first) {  			bf_first = bf; -			info.flags = ATH9K_TXDESC_INTREQ; +			if (!sc->tx99_state) +				info.flags = ATH9K_TXDESC_INTREQ;  			if ((tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) ||  			    txq == sc->tx.uapsdq)  				info.flags |= ATH9K_TXDESC_CLRDMASK; @@ -1275,6 +1269,10 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,  				if (!rts_thresh || (len > rts_thresh))  					rts = true;  			} + +			if (!aggr) +				len = fi->framelen; +  			ath_buf_set_rate(sc, bf, &info, len, rts);  		} @@ -1405,8 +1403,8 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,  	 * has already been added.  	 */  	if (sta->ht_cap.ht_supported) { -		an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + -				     sta->ht_cap.ampdu_factor); +		an->maxampdu = (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + +				      sta->ht_cap.ampdu_factor)) - 1;  		density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density);  		an->mpdudensity = density;  	} @@ -1415,7 +1413,6 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,  	ath_tx_tid_change_state(sc, txtid);  	txtid->active = true; -	txtid->paused = true;  	*ssn = txtid->seq_start = txtid->seq_next;  	txtid->bar_index = -1; @@ -1435,7 +1432,6 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)  	ath_txq_lock(sc, txq);  	txtid->active = false; -	txtid->paused = false;  	ath_tx_flush_tid(sc, txtid);  	ath_tx_tid_change_state(sc, txtid);  	ath_txq_unlock_complete(sc, txq); @@ -1453,14 +1449,16 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,  	for (tidno = 0, tid = &an->tid[tidno];  	     tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { -		if (!tid->sched) -			continue; -  		ac = tid->ac;  		txq = ac->txq;  		ath_txq_lock(sc, txq); +		if (!tid->sched) { +			ath_txq_unlock(sc, txq); +			continue; +		} +  		buffered = ath_tid_has_buffered(tid);  		tid->sched = false; @@ -1493,7 +1491,7 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)  		ath_txq_lock(sc, txq);  		ac->clear_ps_filter = true; -		if (!tid->paused && ath_tid_has_buffered(tid)) { +		if (ath_tid_has_buffered(tid)) {  			ath_tx_queue_tid(txq, tid);  			ath_txq_schedule(sc, txq);  		} @@ -1516,7 +1514,6 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta,  	ath_txq_lock(sc, txq);  	tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; -	tid->paused = false;  	if (ath_tid_has_buffered(tid)) {  		ath_tx_queue_tid(txq, tid); @@ -1550,8 +1547,6 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,  			continue;  		tid = ATH_AN_2_TID(an, i); -		if (tid->paused) -			continue;  		ath_txq_lock(sc, tid->ac->txq);  		while (nframes > 0) { @@ -1704,16 +1699,9 @@ int ath_cabq_update(struct ath_softc *sc)  	int qnum = sc->beacon.cabq->axq_qnum;  	ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi); -	/* -	 * Ensure the readytime % is within the bounds. -	 */ -	if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND) -		sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND; -	else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND) -		sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND; -	qi.tqi_readyTime = (cur_conf->beacon_interval * -			    sc->config.cabqReadytime) / 100; +	qi.tqi_readyTime = (TU_TO_USEC(cur_conf->beacon_interval) * +			    ATH_CABQ_READY_TIME) / 100;  	ath_txq_update(sc, qnum, &qi);  	return 0; @@ -1782,7 +1770,7 @@ bool ath_drain_all_txq(struct ath_softc *sc)  	int i;  	u32 npend = 0; -	if (test_bit(SC_OP_INVALID, &sc->sc_flags)) +	if (test_bit(ATH_OP_INVALID, &common->op_flags))  		return true;  	ath9k_hw_abort_tx_dma(ah); @@ -1792,6 +1780,9 @@ bool ath_drain_all_txq(struct ath_softc *sc)  		if (!ATH_TXQ_SETUP(sc, i))  			continue; +		if (!sc->tx.txq[i].axq_depth) +			continue; +  		if (ath9k_hw_numtxpending(ah, sc->tx.txq[i].axq_qnum))  			npend |= BIT(i);  	} @@ -1827,11 +1818,12 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)   */  void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)  { +	struct ath_common *common = ath9k_hw_common(sc->sc_ah);  	struct ath_atx_ac *ac, *last_ac;  	struct ath_atx_tid *tid, *last_tid;  	bool sent = false; -	if (test_bit(SC_OP_HW_RESET, &sc->sc_flags) || +	if (test_bit(ATH_OP_HW_RESET, &common->op_flags) ||  	    list_empty(&txq->axq_acq))  		return; @@ -1853,9 +1845,6 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)  			list_del(&tid->list);  			tid->sched = false; -			if (tid->paused) -				continue; -  			if (ath_tx_sched_aggr(sc, txq, tid, &stop))  				sent = true; @@ -1948,7 +1937,7 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,  			txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);  	} -	if (!edma) { +	if (!edma || sc->tx99_state) {  		TX_STAT_INC(txq->axq_qnum, txstart);  		ath9k_hw_txstart(ah, txq->axq_qnum);  	} @@ -2027,6 +2016,9 @@ static void setup_frame_info(struct ieee80211_hw *hw,  		fi->keyix = ATH9K_TXKEYIX_INVALID;  	fi->keytype = keytype;  	fi->framelen = framelen; + +	if (!rate) +		return;  	fi->rtscts_rate = rate->hw_value;  	if (short_preamble)  		fi->rtscts_rate |= rate->hw_value_short; @@ -2037,8 +2029,7 @@ u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate)  	struct ath_hw *ah = sc->sc_ah;  	struct ath9k_channel *curchan = ah->curchan; -	if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && -	    (curchan->channelFlags & CHANNEL_5GHZ) && +	if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && IS_CHAN_5GHZ(curchan) &&  	    (chainmask == 0x7) && (rate < 0x90))  		return 0x3;  	else if (AR_SREV_9462(ah) && ath9k_hw_btcoex_is_enabled(ah) && @@ -2072,7 +2063,7 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,  	ATH_TXBUF_RESET(bf); -	if (tid) { +	if (tid && ieee80211_is_data_present(hdr->frame_control)) {  		fragno = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;  		seqno = tid->seq_next;  		hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT); @@ -2195,14 +2186,15 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,  		txq->stopped = true;  	} +	if (txctl->an && ieee80211_is_data_present(hdr->frame_control)) +		tid = ath_get_skb_tid(sc, txctl->an, skb); +  	if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) {  		ath_txq_unlock(sc, txq);  		txq = sc->tx.uapsdq;  		ath_txq_lock(sc, txq);  	} else if (txctl->an &&  		   ieee80211_is_data_present(hdr->frame_control)) { -		tid = ath_get_skb_tid(sc, txctl->an, skb); -  		WARN_ON(tid->ac->txq != txctl->txq);  		if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) @@ -2329,7 +2321,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,  	ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb);  	if (sc->sc_ah->caldata) -		sc->sc_ah->caldata->paprd_packet_sent = true; +		set_bit(PAPRD_PACKET_SENT, &sc->sc_ah->caldata->cal_flags);  	if (!(tx_flags & ATH_TX_ERROR))  		/* Frame was ACKed */ @@ -2379,6 +2371,8 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,  	dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE);  	bf->bf_buf_addr = 0; +	if (sc->tx99_state) +		goto skip_tx_complete;  	if (bf->bf_state.bfs_paprd) {  		if (time_after(jiffies, @@ -2391,6 +2385,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,  		ath_debug_stat_tx(sc, bf, ts, txq, tx_flags);  		ath_tx_complete(sc, skb, tx_flags, txq);  	} +skip_tx_complete:  	/* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't  	 * accidentally reference it later.  	 */ @@ -2475,7 +2470,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)  	ath_txq_lock(sc, txq);  	for (;;) { -		if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) +		if (test_bit(ATH_OP_HW_RESET, &common->op_flags))  			break;  		if (list_empty(&txq->axq_q)) { @@ -2558,7 +2553,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)  	int status;  	for (;;) { -		if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) +		if (test_bit(ATH_OP_HW_RESET, &common->op_flags))  			break;  		status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts); @@ -2574,7 +2569,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)  			sc->beacon.tx_processed = true;  			sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK); -			ath9k_csa_is_finished(sc); +			ath9k_csa_update(sc);  			continue;  		} @@ -2701,7 +2696,6 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)  		tid->baw_size  = WME_MAX_BA;  		tid->baw_head  = tid->baw_tail = 0;  		tid->sched     = false; -		tid->paused    = false;  		tid->active	   = false;  		__skb_queue_head_init(&tid->buf_q);  		__skb_queue_head_init(&tid->retry_q); @@ -2749,3 +2743,50 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)  		ath_txq_unlock(sc, txq);  	}  } + +#ifdef CONFIG_ATH9K_TX99 + +int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb, +		    struct ath_tx_control *txctl) +{ +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; +	struct ath_frame_info *fi = get_frame_info(skb); +	struct ath_common *common = ath9k_hw_common(sc->sc_ah); +	struct ath_buf *bf; +	int padpos, padsize; + +	padpos = ieee80211_hdrlen(hdr->frame_control); +	padsize = padpos & 3; + +	if (padsize && skb->len > padpos) { +		if (skb_headroom(skb) < padsize) { +			ath_dbg(common, XMIT, +				"tx99 padding failed\n"); +		return -EINVAL; +		} + +		skb_push(skb, padsize); +		memmove(skb->data, skb->data + padsize, padpos); +	} + +	fi->keyix = ATH9K_TXKEYIX_INVALID; +	fi->framelen = skb->len + FCS_LEN; +	fi->keytype = ATH9K_KEY_TYPE_CLEAR; + +	bf = ath_tx_setup_buffer(sc, txctl->txq, NULL, skb); +	if (!bf) { +		ath_dbg(common, XMIT, "tx99 buffer setup failed\n"); +		return -EINVAL; +	} + +	ath_set_rates(sc->tx99_vif, NULL, bf); + +	ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, bf->bf_daddr); +	ath9k_hw_tx99_start(sc->sc_ah, txctl->txq->axq_qnum); + +	ath_tx_send_normal(sc, txctl->txq, NULL, skb); + +	return 0; +} + +#endif /* CONFIG_ATH9K_TX99 */ diff --git a/drivers/net/wireless/ath/carl9170/debug.c b/drivers/net/wireless/ath/carl9170/debug.c index 3d70cd277fd..1c0af9cd9a8 100644 --- a/drivers/net/wireless/ath/carl9170/debug.c +++ b/drivers/net/wireless/ath/carl9170/debug.c @@ -37,7 +37,6 @@   *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/seq_file.h> diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 349fa22a921..f8ded84b7be 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -37,7 +37,6 @@   *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/etherdevice.h> @@ -1708,7 +1707,9 @@ found:  	return 0;  } -static void carl9170_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +static void carl9170_op_flush(struct ieee80211_hw *hw, +			      struct ieee80211_vif *vif, +			      u32 queues, bool drop)  {  	struct ar9170 *ar = hw->priv;  	unsigned int vid; @@ -1968,18 +1969,6 @@ static int carl9170_parse_eeprom(struct ar9170 *ar)  		return -ENOMEM;  	ar->num_channels = chans; -	/* -	 * I measured this, a bandswitch takes roughly -	 * 135 ms and a frequency switch about 80. -	 * -	 * FIXME: measure these values again once EEPROM settings -	 *	  are used, that will influence them! -	 */ -	if (bands == 2) -		ar->hw->channel_change_time = 135 * 1000; -	else -		ar->hw->channel_change_time = 80 * 1000; -  	regulatory->current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]);  	/* second part of wiphy init */ diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index e935f61c7fa..924135b8e57 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c @@ -37,7 +37,6 @@   *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/etherdevice.h> @@ -520,6 +519,7 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len)  {  	struct ieee80211_hdr *hdr = data;  	struct ieee80211_tim_ie *tim_ie; +	struct ath_common *common = &ar->common;  	u8 *tim;  	u8 tim_len;  	bool cam; @@ -527,17 +527,13 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len)  	if (likely(!(ar->hw->conf.flags & IEEE80211_CONF_PS)))  		return; -	/* check if this really is a beacon */ -	if (!ieee80211_is_beacon(hdr->frame_control)) -		return; -  	/* min. beacon length + FCS_LEN */  	if (len <= 40 + FCS_LEN)  		return; +	/* check if this really is a beacon */  	/* and only beacons from the associated BSSID, please */ -	if (!ether_addr_equal(hdr->addr3, ar->common.curbssid) || -	    !ar->common.curaid) +	if (!ath_is_mybeacon(common, hdr) || !common->curaid)  		return;  	ar->ps.last_beacon = jiffies; @@ -576,7 +572,7 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len)  static void carl9170_ba_check(struct ar9170 *ar, void *data, unsigned int len)  { -	struct ieee80211_bar *bar = (void *) data; +	struct ieee80211_bar *bar = data;  	struct carl9170_bar_list_entry *entry;  	unsigned int queue; @@ -602,8 +598,8 @@ static void carl9170_ba_check(struct ar9170 *ar, void *data, unsigned int len)  		if (bar->start_seq_num == entry_bar->start_seq_num &&  		    TID_CHECK(bar->control, entry_bar->control) && -		    ether_addr_equal(bar->ra, entry_bar->ta) && -		    ether_addr_equal(bar->ta, entry_bar->ra)) { +		    ether_addr_equal_64bits(bar->ra, entry_bar->ta) && +		    ether_addr_equal_64bits(bar->ta, entry_bar->ra)) {  			struct ieee80211_tx_info *tx_info;  			tx_info = IEEE80211_SKB_CB(entry_skb); diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index e3f696ee4d2..4cadfd48ffd 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -37,7 +37,6 @@   *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/etherdevice.h> diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c index 307bc0ddff9..f35c7f30f9a 100644 --- a/drivers/net/wireless/ath/carl9170/usb.c +++ b/drivers/net/wireless/ath/carl9170/usb.c @@ -773,7 +773,7 @@ void carl9170_usb_stop(struct ar9170 *ar)  	complete_all(&ar->cmd_wait);  	/* This is required to prevent an early completion on _start */ -	INIT_COMPLETION(ar->cmd_wait); +	reinit_completion(&ar->cmd_wait);  	/*  	 * Note: @@ -1076,8 +1076,14 @@ static int carl9170_usb_probe(struct usb_interface *intf,  	carl9170_set_state(ar, CARL9170_STOPPED); -	return request_firmware_nowait(THIS_MODULE, 1, CARL9170FW_NAME, +	err = request_firmware_nowait(THIS_MODULE, 1, CARL9170FW_NAME,  		&ar->udev->dev, GFP_KERNEL, ar, carl9170_usb_firmware_step2); +	if (err) { +		usb_put_dev(udev); +		usb_put_dev(udev); +		carl9170_free(ar); +	} +	return err;  }  static void carl9170_usb_disconnect(struct usb_interface *intf) diff --git a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c b/drivers/net/wireless/ath/dfs_pattern_detector.c index 491305c81fc..650be79c7ac 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c +++ b/drivers/net/wireless/ath/dfs_pattern_detector.c @@ -19,7 +19,7 @@  #include "dfs_pattern_detector.h"  #include "dfs_pri_detector.h" -#include "ath9k.h" +#include "ath.h"  /*   * tolerated deviation of radar time stamp in usecs on both sides @@ -73,9 +73,52 @@ static const struct radar_types etsi_radar_types_v15 = {  	.radar_types		= etsi_radar_ref_types_v15,  }; -/* for now, we support ETSI radar types, FCC and JP are TODO */ +#define FCC_PATTERN(ID, WMIN, WMAX, PMIN, PMAX, PRF, PPB)	\ +{								\ +	ID, WIDTH_LOWER(WMIN), WIDTH_UPPER(WMAX),		\ +	PMIN - PRI_TOLERANCE,					\ +	PMAX * PRF + PRI_TOLERANCE, PRF, PPB * PRF,		\ +	PPB_THRESH(PPB), PRI_TOLERANCE,				\ +} + +static const struct radar_detector_specs fcc_radar_ref_types[] = { +	FCC_PATTERN(0, 0, 1, 1428, 1428, 1, 18), +	FCC_PATTERN(1, 0, 5, 150, 230, 1, 23), +	FCC_PATTERN(2, 6, 10, 200, 500, 1, 16), +	FCC_PATTERN(3, 11, 20, 200, 500, 1, 12), +	FCC_PATTERN(4, 50, 100, 1000, 2000, 20, 1), +	FCC_PATTERN(5, 0, 1, 333, 333, 1, 9), +}; + +static const struct radar_types fcc_radar_types = { +	.region			= NL80211_DFS_FCC, +	.num_radar_types	= ARRAY_SIZE(fcc_radar_ref_types), +	.radar_types		= fcc_radar_ref_types, +}; + +#define JP_PATTERN FCC_PATTERN +static const struct radar_detector_specs jp_radar_ref_types[] = { +	JP_PATTERN(0, 0, 1, 1428, 1428, 1, 18), +	JP_PATTERN(1, 2, 3, 3846, 3846, 1, 18), +	JP_PATTERN(2, 0, 1, 1388, 1388, 1, 18), +	JP_PATTERN(3, 1, 2, 4000, 4000, 1, 18), +	JP_PATTERN(4, 0, 5, 150, 230, 1, 23), +	JP_PATTERN(5, 6, 10, 200, 500, 1, 16), +	JP_PATTERN(6, 11, 20, 200, 500, 1, 12), +	JP_PATTERN(7, 50, 100, 1000, 2000, 20, 1), +	JP_PATTERN(5, 0, 1, 333, 333, 1, 9), +}; + +static const struct radar_types jp_radar_types = { +	.region			= NL80211_DFS_JP, +	.num_radar_types	= ARRAY_SIZE(jp_radar_ref_types), +	.radar_types		= jp_radar_ref_types, +}; +  static const struct radar_types *dfs_domains[] = {  	&etsi_radar_types_v15, +	&fcc_radar_types, +	&jp_radar_types,  };  /** @@ -143,7 +186,6 @@ channel_detector_create(struct dfs_pattern_detector *dpd, u16 freq)  {  	u32 sz, i;  	struct channel_detector *cd; -	struct ath_common *common = ath9k_hw_common(dpd->ah);  	cd = kmalloc(sizeof(*cd), GFP_ATOMIC);  	if (cd == NULL) @@ -167,7 +209,7 @@ channel_detector_create(struct dfs_pattern_detector *dpd, u16 freq)  	return cd;  fail: -	ath_dbg(common, DFS, +	ath_dbg(dpd->common, DFS,  		"failed to allocate channel_detector for freq=%d\n", freq);  	channel_detector_exit(dpd, cd);  	return NULL; @@ -242,7 +284,7 @@ dpd_add_pulse(struct dfs_pattern_detector *dpd, struct pulse_event *event)  		struct pri_detector *pd = cd->detectors[i];  		struct pri_sequence *ps = pd->add_pulse(pd, event);  		if (ps != NULL) { -			ath_dbg(ath9k_hw_common(dpd->ah), DFS, +			ath_dbg(dpd->common, DFS,  				"DFS: radar found on freq=%d: id=%d, pri=%d, "  				"count=%d, count_false=%d\n",  				event->freq, pd->rs->type_id, @@ -254,6 +296,12 @@ dpd_add_pulse(struct dfs_pattern_detector *dpd, struct pulse_event *event)  	return false;  } +static struct ath_dfs_pool_stats +dpd_get_stats(struct dfs_pattern_detector *dpd) +{ +	return global_dfs_pool_stats; +} +  static bool dpd_set_domain(struct dfs_pattern_detector *dpd,  			   enum nl80211_dfs_regions region)  { @@ -284,14 +332,18 @@ static struct dfs_pattern_detector default_dpd = {  	.exit		= dpd_exit,  	.set_dfs_domain	= dpd_set_domain,  	.add_pulse	= dpd_add_pulse, +	.get_stats	= dpd_get_stats,  	.region		= NL80211_DFS_UNSET,  };  struct dfs_pattern_detector * -dfs_pattern_detector_init(struct ath_hw *ah, enum nl80211_dfs_regions region) +dfs_pattern_detector_init(struct ath_common *common, +			  enum nl80211_dfs_regions region)  {  	struct dfs_pattern_detector *dpd; -	struct ath_common *common = ath9k_hw_common(ah); + +	if (!config_enabled(CONFIG_CFG80211_CERTIFICATION_ONUS)) +		return NULL;  	dpd = kmalloc(sizeof(*dpd), GFP_KERNEL);  	if (dpd == NULL) @@ -300,7 +352,7 @@ dfs_pattern_detector_init(struct ath_hw *ah, enum nl80211_dfs_regions region)  	*dpd = default_dpd;  	INIT_LIST_HEAD(&dpd->channel_detectors); -	dpd->ah = ah; +	dpd->common = common;  	if (dpd->set_dfs_domain(dpd, region))  		return dpd; diff --git a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h b/drivers/net/wireless/ath/dfs_pattern_detector.h index 90a5abcc426..dde2652b787 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h +++ b/drivers/net/wireless/ath/dfs_pattern_detector.h @@ -22,6 +22,19 @@  #include <linux/nl80211.h>  /** + * struct ath_dfs_pool_stats - DFS Statistics for global pools + */ +struct ath_dfs_pool_stats { +	u32 pool_reference; +	u32 pulse_allocated; +	u32 pulse_alloc_error; +	u32 pulse_used; +	u32 pseq_allocated; +	u32 pseq_alloc_error; +	u32 pseq_used; +}; + +/**   * struct pulse_event - describing pulses reported by PHY   * @ts: pulse time stamp in us   * @freq: channel frequency in MHz @@ -77,11 +90,12 @@ struct dfs_pattern_detector {  	bool (*add_pulse)(struct dfs_pattern_detector *dpd,  			  struct pulse_event *pe); +	struct ath_dfs_pool_stats (*get_stats)(struct dfs_pattern_detector *dpd);  	enum nl80211_dfs_regions region;  	u8 num_radar_types;  	u64 last_pulse_ts;  	/* needed for ath_dbg() */ -	struct ath_hw *ah; +	struct ath_common *common;  	const struct radar_detector_specs *radar_spec;  	struct list_head channel_detectors; @@ -92,15 +106,7 @@ struct dfs_pattern_detector {   * @param region: DFS domain to be used, can be NL80211_DFS_UNSET at creation   * @return instance pointer on success, NULL otherwise   */ -#if defined(CONFIG_ATH9K_DFS_CERTIFIED)  extern struct dfs_pattern_detector * -dfs_pattern_detector_init(struct ath_hw *ah, enum nl80211_dfs_regions region); -#else -static inline struct dfs_pattern_detector * -dfs_pattern_detector_init(struct ath_hw *ah, enum nl80211_dfs_regions region) -{ -	return NULL; -} -#endif /* CONFIG_ATH9K_DFS_CERTIFIED */ - +dfs_pattern_detector_init(struct ath_common *common, +			  enum nl80211_dfs_regions region);  #endif /* DFS_PATTERN_DETECTOR_H */ diff --git a/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c b/drivers/net/wireless/ath/dfs_pri_detector.c index 5ba4b6fe37c..43b60817888 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c +++ b/drivers/net/wireless/ath/dfs_pri_detector.c @@ -17,10 +17,14 @@  #include <linux/slab.h>  #include <linux/spinlock.h> -#include "ath9k.h" +#include "ath.h"  #include "dfs_pattern_detector.h"  #include "dfs_pri_detector.h" -#include "dfs_debug.h" + +struct ath_dfs_pool_stats global_dfs_pool_stats = {}; + +#define DFS_POOL_STAT_INC(c) (global_dfs_pool_stats.c++) +#define DFS_POOL_STAT_DEC(c) (global_dfs_pool_stats.c--)  /**   * struct pulse_elem - elements in pulse queue @@ -392,7 +396,7 @@ static struct pri_sequence *pri_detector_add_pulse(struct pri_detector *de,  	if (!pseq_handler_create_sequences(de, ts, max_updated_seq)) {  		pri_detector_reset(de, ts); -		return false; +		return NULL;  	}  	ps = pseq_handler_check_detection(de); diff --git a/drivers/net/wireless/ath/ath9k/dfs_pri_detector.h b/drivers/net/wireless/ath/dfs_pri_detector.h index 723962d1abc..79f0fff4d1e 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_pri_detector.h +++ b/drivers/net/wireless/ath/dfs_pri_detector.h @@ -19,6 +19,8 @@  #include <linux/list.h> +extern struct ath_dfs_pool_stats global_dfs_pool_stats; +  /**   * struct pri_sequence - sequence of pulses matching one PRI   * @head: list_head diff --git a/drivers/net/wireless/ath/main.c b/drivers/net/wireless/ath/main.c index 8e99540cd90..8b0ac14d5c3 100644 --- a/drivers/net/wireless/ath/main.c +++ b/drivers/net/wireless/ath/main.c @@ -59,6 +59,14 @@ struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,  }  EXPORT_SYMBOL(ath_rxbuf_alloc); +bool ath_is_mybeacon(struct ath_common *common, struct ieee80211_hdr *hdr) +{ +	return ieee80211_is_beacon(hdr->frame_control) && +		!is_zero_ether_addr(common->curbssid) && +		ether_addr_equal_64bits(hdr->addr3, common->curbssid); +} +EXPORT_SYMBOL(ath_is_mybeacon); +  void ath_printk(const char *level, const struct ath_common* common,  		const char *fmt, ...)  { diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 7d077c752dd..415393dfb6f 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -37,17 +37,18 @@ static int __ath_regd_init(struct ath_regulatory *reg);  /* We enable active scan on these a case by case basis by regulatory domain */  #define ATH9K_2GHZ_CH12_13	REG_RULE(2467-10, 2472+10, 40, 0, 20,\ -					NL80211_RRF_PASSIVE_SCAN) +					 NL80211_RRF_NO_IR)  #define ATH9K_2GHZ_CH14		REG_RULE(2484-10, 2484+10, 40, 0, 20,\ -				NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM) +					 NL80211_RRF_NO_IR | \ +					 NL80211_RRF_NO_OFDM)  /* We allow IBSS on these on a case by case basis by regulatory domain */  #define ATH9K_5GHZ_5150_5350	REG_RULE(5150-10, 5350+10, 80, 0, 30,\ -				NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) +					 NL80211_RRF_NO_IR)  #define ATH9K_5GHZ_5470_5850	REG_RULE(5470-10, 5850+10, 80, 0, 30,\ -				NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) +					 NL80211_RRF_NO_IR)  #define ATH9K_5GHZ_5725_5850	REG_RULE(5725-10, 5850+10, 80, 0, 30,\ -				NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) +					 NL80211_RRF_NO_IR)  #define ATH9K_2GHZ_ALL		ATH9K_2GHZ_CH01_11, \  				ATH9K_2GHZ_CH12_13, \ @@ -113,6 +114,87 @@ static const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = {  	}  }; +static bool dynamic_country_user_possible(struct ath_regulatory *reg) +{ +	if (config_enabled(CONFIG_ATH_REG_DYNAMIC_USER_CERT_TESTING)) +		return true; + +	switch (reg->country_code) { +	case CTRY_UNITED_STATES: +	case CTRY_JAPAN1: +	case CTRY_JAPAN2: +	case CTRY_JAPAN3: +	case CTRY_JAPAN4: +	case CTRY_JAPAN5: +	case CTRY_JAPAN6: +	case CTRY_JAPAN7: +	case CTRY_JAPAN8: +	case CTRY_JAPAN9: +	case CTRY_JAPAN10: +	case CTRY_JAPAN11: +	case CTRY_JAPAN12: +	case CTRY_JAPAN13: +	case CTRY_JAPAN14: +	case CTRY_JAPAN15: +	case CTRY_JAPAN16: +	case CTRY_JAPAN17: +	case CTRY_JAPAN18: +	case CTRY_JAPAN19: +	case CTRY_JAPAN20: +	case CTRY_JAPAN21: +	case CTRY_JAPAN22: +	case CTRY_JAPAN23: +	case CTRY_JAPAN24: +	case CTRY_JAPAN25: +	case CTRY_JAPAN26: +	case CTRY_JAPAN27: +	case CTRY_JAPAN28: +	case CTRY_JAPAN29: +	case CTRY_JAPAN30: +	case CTRY_JAPAN31: +	case CTRY_JAPAN32: +	case CTRY_JAPAN33: +	case CTRY_JAPAN34: +	case CTRY_JAPAN35: +	case CTRY_JAPAN36: +	case CTRY_JAPAN37: +	case CTRY_JAPAN38: +	case CTRY_JAPAN39: +	case CTRY_JAPAN40: +	case CTRY_JAPAN41: +	case CTRY_JAPAN42: +	case CTRY_JAPAN43: +	case CTRY_JAPAN44: +	case CTRY_JAPAN45: +	case CTRY_JAPAN46: +	case CTRY_JAPAN47: +	case CTRY_JAPAN48: +	case CTRY_JAPAN49: +	case CTRY_JAPAN50: +	case CTRY_JAPAN51: +	case CTRY_JAPAN52: +	case CTRY_JAPAN53: +	case CTRY_JAPAN54: +	case CTRY_JAPAN55: +	case CTRY_JAPAN56: +	case CTRY_JAPAN57: +	case CTRY_JAPAN58: +	case CTRY_JAPAN59: +		return false; +	} + +	return true; +} + +static bool ath_reg_dyn_country_user_allow(struct ath_regulatory *reg) +{ +	if (!config_enabled(CONFIG_ATH_REG_DYNAMIC_USER_REG_HINTS)) +		return false; +	if (!dynamic_country_user_possible(reg)) +		return false; +	return true; +} +  static inline bool is_wwr_sku(u16 regd)  {  	return ((regd & COUNTRY_ERD_FLAG) != COUNTRY_ERD_FLAG) && @@ -140,7 +222,7 @@ static const struct ieee80211_regdomain *ath_default_world_regdomain(void)  static const struct  ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg)  { -	switch (reg->regpair->regDmnEnum) { +	switch (reg->regpair->reg_domain) {  	case 0x60:  	case 0x61:  	case 0x62: @@ -177,118 +259,139 @@ static bool ath_is_radar_freq(u16 center_freq)  	return (center_freq >= 5260 && center_freq <= 5700);  } +static void ath_force_clear_no_ir_chan(struct wiphy *wiphy, +				       struct ieee80211_channel *ch) +{ +	const struct ieee80211_reg_rule *reg_rule; + +	reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(ch->center_freq)); +	if (IS_ERR(reg_rule)) +		return; + +	if (!(reg_rule->flags & NL80211_RRF_NO_IR)) +		if (ch->flags & IEEE80211_CHAN_NO_IR) +			ch->flags &= ~IEEE80211_CHAN_NO_IR; +} + +static void ath_force_clear_no_ir_freq(struct wiphy *wiphy, u16 center_freq) +{ +	struct ieee80211_channel *ch; + +	ch = ieee80211_get_channel(wiphy, center_freq); +	if (!ch) +		return; + +	ath_force_clear_no_ir_chan(wiphy, ch); +} + +static void ath_force_no_ir_chan(struct ieee80211_channel *ch) +{ +	ch->flags |= IEEE80211_CHAN_NO_IR; +} + +static void ath_force_no_ir_freq(struct wiphy *wiphy, u16 center_freq) +{ +	struct ieee80211_channel *ch; + +	ch = ieee80211_get_channel(wiphy, center_freq); +	if (!ch) +		return; + +	ath_force_no_ir_chan(ch); +} + +static void +__ath_reg_apply_beaconing_flags(struct wiphy *wiphy, +				struct ath_regulatory *reg, +				enum nl80211_reg_initiator initiator, +				struct ieee80211_channel *ch) +{ +	if (ath_is_radar_freq(ch->center_freq) || +	    (ch->flags & IEEE80211_CHAN_RADAR)) +		return; + +	switch (initiator) { +	case NL80211_REGDOM_SET_BY_COUNTRY_IE: +		ath_force_clear_no_ir_chan(wiphy, ch); +		break; +	case NL80211_REGDOM_SET_BY_USER: +		if (ath_reg_dyn_country_user_allow(reg)) +			ath_force_clear_no_ir_chan(wiphy, ch); +		break; +	default: +		if (ch->beacon_found) +			ch->flags &= ~IEEE80211_CHAN_NO_IR; +	} +} +  /* - * N.B: These exception rules do not apply radar freqs. + * These exception rules do not apply radar frequencies.   * - * - We enable adhoc (or beaconing) if allowed by 11d - * - We enable active scan if the channel is allowed by 11d + * - We enable initiating radiation if the country IE says its fine:   * - If no country IE has been processed and a we determine we have - *   received a beacon on a channel we can enable active scan and - *   adhoc (or beaconing). + *   received a beacon on a channel we can enable initiating radiation.   */  static void  ath_reg_apply_beaconing_flags(struct wiphy *wiphy, +			      struct ath_regulatory *reg,  			      enum nl80211_reg_initiator initiator)  {  	enum ieee80211_band band;  	struct ieee80211_supported_band *sband; -	const struct ieee80211_reg_rule *reg_rule;  	struct ieee80211_channel *ch;  	unsigned int i;  	for (band = 0; band < IEEE80211_NUM_BANDS; band++) { -  		if (!wiphy->bands[band])  			continue; -  		sband = wiphy->bands[band]; -  		for (i = 0; i < sband->n_channels; i++) { -  			ch = &sband->channels[i]; - -			if (ath_is_radar_freq(ch->center_freq) || -			    (ch->flags & IEEE80211_CHAN_RADAR)) -				continue; - -			if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { -				reg_rule = freq_reg_info(wiphy, ch->center_freq); -				if (IS_ERR(reg_rule)) -					continue; -				/* -				 * If 11d had a rule for this channel ensure -				 * we enable adhoc/beaconing if it allows us to -				 * use it. Note that we would have disabled it -				 * by applying our static world regdomain by -				 * default during init, prior to calling our -				 * regulatory_hint(). -				 */ -				if (!(reg_rule->flags & -				    NL80211_RRF_NO_IBSS)) -					ch->flags &= -					  ~IEEE80211_CHAN_NO_IBSS; -				if (!(reg_rule->flags & -				    NL80211_RRF_PASSIVE_SCAN)) -					ch->flags &= -					  ~IEEE80211_CHAN_PASSIVE_SCAN; -			} else { -				if (ch->beacon_found) -					ch->flags &= ~(IEEE80211_CHAN_NO_IBSS | -					  IEEE80211_CHAN_PASSIVE_SCAN); -			} +			__ath_reg_apply_beaconing_flags(wiphy, reg, +							initiator, ch);  		}  	} -  } -/* Allows active scan scan on Ch 12 and 13 */ +/** + * ath_reg_apply_ir_flags() + * @wiphy: the wiphy to use + * @initiator: the regulatory hint initiator + * + * If no country IE has been received always enable passive scan + * and no-ibss on these channels. This is only done for specific + * regulatory SKUs. + * + * If a country IE has been received check its rule for this + * channel first before enabling active scan. The passive scan + * would have been enforced by the initial processing of our + * custom regulatory domain. + */  static void -ath_reg_apply_active_scan_flags(struct wiphy *wiphy, -				enum nl80211_reg_initiator initiator) +ath_reg_apply_ir_flags(struct wiphy *wiphy, +		       struct ath_regulatory *reg, +		       enum nl80211_reg_initiator initiator)  {  	struct ieee80211_supported_band *sband; -	struct ieee80211_channel *ch; -	const struct ieee80211_reg_rule *reg_rule;  	sband = wiphy->bands[IEEE80211_BAND_2GHZ];  	if (!sband)  		return; -	/* -	 * If no country IE has been received always enable active scan -	 * on these channels. This is only done for specific regulatory SKUs -	 */ -	if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { -		ch = &sband->channels[11]; /* CH 12 */ -		if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) -			ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; -		ch = &sband->channels[12]; /* CH 13 */ -		if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) -			ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; -		return; -	} - -	/* -	 * If a country IE has been received check its rule for this -	 * channel first before enabling active scan. The passive scan -	 * would have been enforced by the initial processing of our -	 * custom regulatory domain. -	 */ - -	ch = &sband->channels[11]; /* CH 12 */ -	reg_rule = freq_reg_info(wiphy, ch->center_freq); -	if (!IS_ERR(reg_rule)) { -		if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) -			if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) -				ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; -	} - -	ch = &sband->channels[12]; /* CH 13 */ -	reg_rule = freq_reg_info(wiphy, ch->center_freq); -	if (!IS_ERR(reg_rule)) { -		if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) -			if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) -				ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; +	switch(initiator) { +	case NL80211_REGDOM_SET_BY_COUNTRY_IE: +		ath_force_clear_no_ir_freq(wiphy, 2467); +		ath_force_clear_no_ir_freq(wiphy, 2472); +		break; +	case NL80211_REGDOM_SET_BY_USER: +		if (!ath_reg_dyn_country_user_allow(reg)) +			break; +		ath_force_clear_no_ir_freq(wiphy, 2467); +		ath_force_clear_no_ir_freq(wiphy, 2472); +		break; +	default: +		ath_force_no_ir_freq(wiphy, 2467); +		ath_force_no_ir_freq(wiphy, 2472);  	}  } @@ -320,8 +423,7 @@ static void ath_reg_apply_radar_flags(struct wiphy *wiphy)  		 */  		if (!(ch->flags & IEEE80211_CHAN_DISABLED))  			ch->flags |= IEEE80211_CHAN_RADAR | -				     IEEE80211_CHAN_NO_IBSS | -				     IEEE80211_CHAN_PASSIVE_SCAN; +				     IEEE80211_CHAN_NO_IR;  	}  } @@ -329,18 +431,21 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy,  				      enum nl80211_reg_initiator initiator,  				      struct ath_regulatory *reg)  { -	switch (reg->regpair->regDmnEnum) { +	switch (reg->regpair->reg_domain) {  	case 0x60:  	case 0x63:  	case 0x66:  	case 0x67:  	case 0x6C: -		ath_reg_apply_beaconing_flags(wiphy, initiator); +		ath_reg_apply_beaconing_flags(wiphy, reg, initiator);  		break;  	case 0x68: -		ath_reg_apply_beaconing_flags(wiphy, initiator); -		ath_reg_apply_active_scan_flags(wiphy, initiator); +		ath_reg_apply_beaconing_flags(wiphy, reg, initiator); +		ath_reg_apply_ir_flags(wiphy, reg, initiator);  		break; +	default: +		if (ath_reg_dyn_country_user_allow(reg)) +			ath_reg_apply_beaconing_flags(wiphy, reg, initiator);  	}  } @@ -356,14 +461,49 @@ static u16 ath_regd_find_country_by_name(char *alpha2)  	return -1;  } +static int __ath_reg_dyn_country(struct wiphy *wiphy, +				 struct ath_regulatory *reg, +				 struct regulatory_request *request) +{ +	u16 country_code; + +	if (request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && +	    !ath_is_world_regd(reg)) +		return -EINVAL; + +	country_code = ath_regd_find_country_by_name(request->alpha2); +	if (country_code == (u16) -1) +		return -EINVAL; + +	reg->current_rd = COUNTRY_ERD_FLAG; +	reg->current_rd |= country_code; + +	__ath_regd_init(reg); + +	ath_reg_apply_world_flags(wiphy, request->initiator, reg); + +	return 0; +} + +static void ath_reg_dyn_country(struct wiphy *wiphy, +				struct ath_regulatory *reg, +				struct regulatory_request *request) +{ +	if (__ath_reg_dyn_country(wiphy, reg, request)) +		return; + +	printk(KERN_DEBUG "ath: regdomain 0x%0x " +			  "dynamically updated by %s\n", +	       reg->current_rd, +	       reg_initiator_name(request->initiator)); +} +  void ath_reg_notifier_apply(struct wiphy *wiphy,  			    struct regulatory_request *request,  			    struct ath_regulatory *reg)  {  	struct ath_common *common = container_of(reg, struct ath_common,  						 regulatory); -	u16 country_code; -  	/* We always apply this */  	ath_reg_apply_radar_flags(wiphy); @@ -388,25 +528,13 @@ void ath_reg_notifier_apply(struct wiphy *wiphy,  		       sizeof(struct ath_regulatory));  		break;  	case NL80211_REGDOM_SET_BY_DRIVER: +		break;  	case NL80211_REGDOM_SET_BY_USER: +		if (ath_reg_dyn_country_user_allow(reg)) +			ath_reg_dyn_country(wiphy, reg, request);  		break;  	case NL80211_REGDOM_SET_BY_COUNTRY_IE: -		if (!ath_is_world_regd(reg)) -			break; - -		country_code = ath_regd_find_country_by_name(request->alpha2); -		if (country_code == (u16) -1) -			break; - -		reg->current_rd = COUNTRY_ERD_FLAG; -		reg->current_rd |= country_code; - -		printk(KERN_DEBUG "ath: regdomain 0x%0x updated by CountryIE\n", -			reg->current_rd); -		__ath_regd_init(reg); - -		ath_reg_apply_world_flags(wiphy, request->initiator, reg); - +		ath_reg_dyn_country(wiphy, reg, request);  		break;  	}  } @@ -432,7 +560,7 @@ static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg)  			printk(KERN_DEBUG "ath: EEPROM indicates we "  			       "should expect a direct regpair map\n");  		for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) -			if (regDomainPairs[i].regDmnEnum == rd) +			if (regDomainPairs[i].reg_domain == rd)  				return true;  	}  	printk(KERN_DEBUG @@ -489,7 +617,7 @@ ath_get_regpair(int regdmn)  	if (regdmn == NO_ENUMRD)  		return NULL;  	for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) { -		if (regDomainPairs[i].regDmnEnum == regdmn) +		if (regDomainPairs[i].reg_domain == regdmn)  			return ®DomainPairs[i];  	}  	return NULL; @@ -504,7 +632,8 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,  	const struct ieee80211_regdomain *regd;  	wiphy->reg_notifier = reg_notifier; -	wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; +	wiphy->regulatory_flags |= REGULATORY_STRICT_REG | +				   REGULATORY_CUSTOM_REG;  	if (ath_is_world_regd(reg)) {  		/* @@ -512,7 +641,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,  		 * saved on the wiphy orig_* parameters  		 */  		regd = ath_world_regdomain(reg); -		wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; +		wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_FOLLOW_POWER;  	} else {  		/*  		 * This gets applied in the case of the absence of CRDA, @@ -521,6 +650,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,  		 */  		regd = ath_default_world_regdomain();  	} +  	wiphy_apply_custom_regulatory(wiphy, regd);  	ath_reg_apply_radar_flags(wiphy);  	ath_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg); @@ -611,7 +741,7 @@ static int __ath_regd_init(struct ath_regulatory *reg)  	printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n",  		reg->alpha2[0], reg->alpha2[1]);  	printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n", -		reg->regpair->regDmnEnum); +		reg->regpair->reg_domain);  	return 0;  } diff --git a/drivers/net/wireless/ath/wcn36xx/Kconfig b/drivers/net/wireless/ath/wcn36xx/Kconfig new file mode 100644 index 00000000000..591ebaea826 --- /dev/null +++ b/drivers/net/wireless/ath/wcn36xx/Kconfig @@ -0,0 +1,16 @@ +config WCN36XX +	tristate "Qualcomm Atheros WCN3660/3680 support" +	depends on MAC80211 && HAS_DMA +	---help--- +	  This module adds support for wireless adapters based on +	  Qualcomm Atheros WCN3660 and WCN3680 mobile chipsets. + +	  If you choose to build a module, it'll be called wcn36xx. + +config WCN36XX_DEBUGFS +	bool "WCN36XX debugfs support" +	depends on WCN36XX +	---help--- +	  Enabled debugfs support + +	  If unsure, say Y to make it easier to debug problems. diff --git a/drivers/net/wireless/ath/wcn36xx/Makefile b/drivers/net/wireless/ath/wcn36xx/Makefile new file mode 100644 index 00000000000..50c43b4382b --- /dev/null +++ b/drivers/net/wireless/ath/wcn36xx/Makefile @@ -0,0 +1,7 @@ +obj-$(CONFIG_WCN36XX) := wcn36xx.o +wcn36xx-y +=   main.o \ +               dxe.o \ +               txrx.o \ +               smd.o \ +               pmc.o \ +               debug.o diff --git a/drivers/net/wireless/ath/wcn36xx/debug.c b/drivers/net/wireless/ath/wcn36xx/debug.c new file mode 100644 index 00000000000..ef44a2da644 --- /dev/null +++ b/drivers/net/wireless/ath/wcn36xx/debug.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com> + * + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/debugfs.h> +#include <linux/uaccess.h> +#include "wcn36xx.h" +#include "debug.h" +#include "pmc.h" + +#ifdef CONFIG_WCN36XX_DEBUGFS + +static ssize_t read_file_bool_bmps(struct file *file, char __user *user_buf, +				   size_t count, loff_t *ppos) +{ +	struct wcn36xx *wcn = file->private_data; +	struct wcn36xx_vif *vif_priv = NULL; +	struct ieee80211_vif *vif = NULL; +	char buf[3]; + +	list_for_each_entry(vif_priv, &wcn->vif_list, list) { +			vif = container_of((void *)vif_priv, +				   struct ieee80211_vif, +				   drv_priv); +			if (NL80211_IFTYPE_STATION == vif->type) { +				if (vif_priv->pw_state == WCN36XX_BMPS) +					buf[0] = '1'; +				else +					buf[0] = '0'; +				break; +			} +	} +	buf[1] = '\n'; +	buf[2] = 0x00; + +	return simple_read_from_buffer(user_buf, count, ppos, buf, 2); +} + +static ssize_t write_file_bool_bmps(struct file *file, +				    const char __user *user_buf, +				    size_t count, loff_t *ppos) +{ +	struct wcn36xx *wcn = file->private_data; +	struct wcn36xx_vif *vif_priv = NULL; +	struct ieee80211_vif *vif = NULL; + +	char buf[32]; +	int buf_size; + +	buf_size = min(count, (sizeof(buf)-1)); +	if (copy_from_user(buf, user_buf, buf_size)) +		return -EFAULT; + +	switch (buf[0]) { +	case 'y': +	case 'Y': +	case '1': +		list_for_each_entry(vif_priv, &wcn->vif_list, list) { +			vif = container_of((void *)vif_priv, +				   struct ieee80211_vif, +				   drv_priv); +			if (NL80211_IFTYPE_STATION == vif->type) { +				wcn36xx_enable_keep_alive_null_packet(wcn, vif); +				wcn36xx_pmc_enter_bmps_state(wcn, vif); +			} +		} +		break; +	case 'n': +	case 'N': +	case '0': +		list_for_each_entry(vif_priv, &wcn->vif_list, list) { +			vif = container_of((void *)vif_priv, +				   struct ieee80211_vif, +				   drv_priv); +			if (NL80211_IFTYPE_STATION == vif->type) +				wcn36xx_pmc_exit_bmps_state(wcn, vif); +		} +		break; +	} + +	return count; +} + +static const struct file_operations fops_wcn36xx_bmps = { +	.open = simple_open, +	.read  =       read_file_bool_bmps, +	.write =       write_file_bool_bmps, +}; + +static ssize_t write_file_dump(struct file *file, +				    const char __user *user_buf, +				    size_t count, loff_t *ppos) +{ +	struct wcn36xx *wcn = file->private_data; +	char buf[255], *tmp; +	int buf_size; +	u32 arg[WCN36xx_MAX_DUMP_ARGS]; +	int i; + +	memset(buf, 0, sizeof(buf)); +	memset(arg, 0, sizeof(arg)); + +	buf_size = min(count, (sizeof(buf) - 1)); +	if (copy_from_user(buf, user_buf, buf_size)) +		return -EFAULT; + +	tmp = buf; + +	for (i = 0; i < WCN36xx_MAX_DUMP_ARGS; i++) { +		char *begin; +		begin = strsep(&tmp, " "); +		if (begin == NULL) +			break; + +		if (kstrtou32(begin, 0, &arg[i]) != 0) +			break; +	} + +	wcn36xx_info("DUMP args is %d %d %d %d %d\n", arg[0], arg[1], arg[2], +		     arg[3], arg[4]); +	wcn36xx_smd_dump_cmd_req(wcn, arg[0], arg[1], arg[2], arg[3], arg[4]); + +	return count; +} + +static const struct file_operations fops_wcn36xx_dump = { +	.open = simple_open, +	.write =       write_file_dump, +}; + +#define ADD_FILE(name, mode, fop, priv_data)		\ +	do {							\ +		struct dentry *d;				\ +		d = debugfs_create_file(__stringify(name),	\ +					mode, dfs->rootdir,	\ +					priv_data, fop);	\ +		dfs->file_##name.dentry = d;			\ +		if (IS_ERR(d)) {				\ +			wcn36xx_warn("Create the debugfs entry failed");\ +			dfs->file_##name.dentry = NULL;		\ +		}						\ +	} while (0) + + +void wcn36xx_debugfs_init(struct wcn36xx *wcn) +{ +	struct wcn36xx_dfs_entry *dfs = &wcn->dfs; + +	dfs->rootdir = debugfs_create_dir(KBUILD_MODNAME, +					  wcn->hw->wiphy->debugfsdir); +	if (IS_ERR(dfs->rootdir)) { +		wcn36xx_warn("Create the debugfs failed\n"); +		dfs->rootdir = NULL; +	} + +	ADD_FILE(bmps_switcher, S_IRUSR | S_IWUSR, +		 &fops_wcn36xx_bmps, wcn); +	ADD_FILE(dump, S_IWUSR, &fops_wcn36xx_dump, wcn); +} + +void wcn36xx_debugfs_exit(struct wcn36xx *wcn) +{ +	struct wcn36xx_dfs_entry *dfs = &wcn->dfs; +	debugfs_remove_recursive(dfs->rootdir); +} + +#endif /* CONFIG_WCN36XX_DEBUGFS */ diff --git a/drivers/net/wireless/ath/wcn36xx/debug.h b/drivers/net/wireless/ath/wcn36xx/debug.h new file mode 100644 index 00000000000..46307aa562d --- /dev/null +++ b/drivers/net/wireless/ath/wcn36xx/debug.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com> + * + * 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 _WCN36XX_DEBUG_H_ +#define _WCN36XX_DEBUG_H_ + +#include <linux/kernel.h> + +#define WCN36xx_MAX_DUMP_ARGS	5 + +#ifdef CONFIG_WCN36XX_DEBUGFS +struct wcn36xx_dfs_file { +	struct dentry *dentry; +	u32 value; +}; + +struct wcn36xx_dfs_entry { +	struct dentry *rootdir; +	struct wcn36xx_dfs_file file_bmps_switcher; +	struct wcn36xx_dfs_file file_dump; +}; + +void wcn36xx_debugfs_init(struct wcn36xx *wcn); +void wcn36xx_debugfs_exit(struct wcn36xx *wcn); + +#else +static inline void wcn36xx_debugfs_init(struct wcn36xx *wcn) +{ +} +static inline void wcn36xx_debugfs_exit(struct wcn36xx *wcn) +{ +} + +#endif /* CONFIG_WCN36XX_DEBUGFS */ + +#endif	/* _WCN36XX_DEBUG_H_ */ diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c new file mode 100644 index 00000000000..73f12f196f1 --- /dev/null +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -0,0 +1,813 @@ +/* + * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com> + * + * 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. + */ + +/* DXE - DMA transfer engine + * we have 2 channels(High prio and Low prio) for TX and 2 channels for RX. + * through low channels data packets are transfered + * through high channels managment packets are transfered + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/interrupt.h> +#include "wcn36xx.h" +#include "txrx.h" + +void *wcn36xx_dxe_get_next_bd(struct wcn36xx *wcn, bool is_low) +{ +	struct wcn36xx_dxe_ch *ch = is_low ? +		&wcn->dxe_tx_l_ch : +		&wcn->dxe_tx_h_ch; + +	return ch->head_blk_ctl->bd_cpu_addr; +} + +static void wcn36xx_dxe_write_register(struct wcn36xx *wcn, int addr, int data) +{ +	wcn36xx_dbg(WCN36XX_DBG_DXE, +		    "wcn36xx_dxe_write_register: addr=%x, data=%x\n", +		    addr, data); + +	writel(data, wcn->mmio + addr); +} + +#define wcn36xx_dxe_write_register_x(wcn, reg, reg_data)		 \ +do {									 \ +	if (wcn->chip_version == WCN36XX_CHIP_3680)			 \ +		wcn36xx_dxe_write_register(wcn, reg ## _3680, reg_data); \ +	else								 \ +		wcn36xx_dxe_write_register(wcn, reg ## _3660, reg_data); \ +} while (0)								 \ + +static void wcn36xx_dxe_read_register(struct wcn36xx *wcn, int addr, int *data) +{ +	*data = readl(wcn->mmio + addr); + +	wcn36xx_dbg(WCN36XX_DBG_DXE, +		    "wcn36xx_dxe_read_register: addr=%x, data=%x\n", +		    addr, *data); +} + +static void wcn36xx_dxe_free_ctl_block(struct wcn36xx_dxe_ch *ch) +{ +	struct wcn36xx_dxe_ctl *ctl = ch->head_blk_ctl, *next; +	int i; + +	for (i = 0; i < ch->desc_num && ctl; i++) { +		next = ctl->next; +		kfree(ctl); +		ctl = next; +	} +} + +static int wcn36xx_dxe_allocate_ctl_block(struct wcn36xx_dxe_ch *ch) +{ +	struct wcn36xx_dxe_ctl *prev_ctl = NULL; +	struct wcn36xx_dxe_ctl *cur_ctl = NULL; +	int i; + +	for (i = 0; i < ch->desc_num; i++) { +		cur_ctl = kzalloc(sizeof(*cur_ctl), GFP_KERNEL); +		if (!cur_ctl) +			goto out_fail; + +		cur_ctl->ctl_blk_order = i; +		if (i == 0) { +			ch->head_blk_ctl = cur_ctl; +			ch->tail_blk_ctl = cur_ctl; +		} else if (ch->desc_num - 1 == i) { +			prev_ctl->next = cur_ctl; +			cur_ctl->next = ch->head_blk_ctl; +		} else { +			prev_ctl->next = cur_ctl; +		} +		prev_ctl = cur_ctl; +	} + +	return 0; + +out_fail: +	wcn36xx_dxe_free_ctl_block(ch); +	return -ENOMEM; +} + +int wcn36xx_dxe_alloc_ctl_blks(struct wcn36xx *wcn) +{ +	int ret; + +	wcn->dxe_tx_l_ch.ch_type = WCN36XX_DXE_CH_TX_L; +	wcn->dxe_tx_h_ch.ch_type = WCN36XX_DXE_CH_TX_H; +	wcn->dxe_rx_l_ch.ch_type = WCN36XX_DXE_CH_RX_L; +	wcn->dxe_rx_h_ch.ch_type = WCN36XX_DXE_CH_RX_H; + +	wcn->dxe_tx_l_ch.desc_num = WCN36XX_DXE_CH_DESC_NUMB_TX_L; +	wcn->dxe_tx_h_ch.desc_num = WCN36XX_DXE_CH_DESC_NUMB_TX_H; +	wcn->dxe_rx_l_ch.desc_num = WCN36XX_DXE_CH_DESC_NUMB_RX_L; +	wcn->dxe_rx_h_ch.desc_num = WCN36XX_DXE_CH_DESC_NUMB_RX_H; + +	wcn->dxe_tx_l_ch.dxe_wq =  WCN36XX_DXE_WQ_TX_L; +	wcn->dxe_tx_h_ch.dxe_wq =  WCN36XX_DXE_WQ_TX_H; + +	wcn->dxe_tx_l_ch.ctrl_bd = WCN36XX_DXE_CTRL_TX_L_BD; +	wcn->dxe_tx_h_ch.ctrl_bd = WCN36XX_DXE_CTRL_TX_H_BD; + +	wcn->dxe_tx_l_ch.ctrl_skb = WCN36XX_DXE_CTRL_TX_L_SKB; +	wcn->dxe_tx_h_ch.ctrl_skb = WCN36XX_DXE_CTRL_TX_H_SKB; + +	wcn->dxe_tx_l_ch.reg_ctrl = WCN36XX_DXE_REG_CTL_TX_L; +	wcn->dxe_tx_h_ch.reg_ctrl = WCN36XX_DXE_REG_CTL_TX_H; + +	wcn->dxe_tx_l_ch.def_ctrl = WCN36XX_DXE_CH_DEFAULT_CTL_TX_L; +	wcn->dxe_tx_h_ch.def_ctrl = WCN36XX_DXE_CH_DEFAULT_CTL_TX_H; + +	/* DXE control block allocation */ +	ret = wcn36xx_dxe_allocate_ctl_block(&wcn->dxe_tx_l_ch); +	if (ret) +		goto out_err; +	ret = wcn36xx_dxe_allocate_ctl_block(&wcn->dxe_tx_h_ch); +	if (ret) +		goto out_err; +	ret = wcn36xx_dxe_allocate_ctl_block(&wcn->dxe_rx_l_ch); +	if (ret) +		goto out_err; +	ret = wcn36xx_dxe_allocate_ctl_block(&wcn->dxe_rx_h_ch); +	if (ret) +		goto out_err; + +	/* Initialize SMSM state  Clear TX Enable RING EMPTY STATE */ +	ret = wcn->ctrl_ops->smsm_change_state( +		WCN36XX_SMSM_WLAN_TX_ENABLE, +		WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY); + +	return 0; + +out_err: +	wcn36xx_err("Failed to allocate DXE control blocks\n"); +	wcn36xx_dxe_free_ctl_blks(wcn); +	return -ENOMEM; +} + +void wcn36xx_dxe_free_ctl_blks(struct wcn36xx *wcn) +{ +	wcn36xx_dxe_free_ctl_block(&wcn->dxe_tx_l_ch); +	wcn36xx_dxe_free_ctl_block(&wcn->dxe_tx_h_ch); +	wcn36xx_dxe_free_ctl_block(&wcn->dxe_rx_l_ch); +	wcn36xx_dxe_free_ctl_block(&wcn->dxe_rx_h_ch); +} + +static int wcn36xx_dxe_init_descs(struct wcn36xx_dxe_ch *wcn_ch) +{ +	struct wcn36xx_dxe_desc *cur_dxe = NULL; +	struct wcn36xx_dxe_desc *prev_dxe = NULL; +	struct wcn36xx_dxe_ctl *cur_ctl = NULL; +	size_t size; +	int i; + +	size = wcn_ch->desc_num * sizeof(struct wcn36xx_dxe_desc); +	wcn_ch->cpu_addr = dma_alloc_coherent(NULL, size, &wcn_ch->dma_addr, +					      GFP_KERNEL); +	if (!wcn_ch->cpu_addr) +		return -ENOMEM; + +	memset(wcn_ch->cpu_addr, 0, size); + +	cur_dxe = (struct wcn36xx_dxe_desc *)wcn_ch->cpu_addr; +	cur_ctl = wcn_ch->head_blk_ctl; + +	for (i = 0; i < wcn_ch->desc_num; i++) { +		cur_ctl->desc = cur_dxe; +		cur_ctl->desc_phy_addr = wcn_ch->dma_addr + +			i * sizeof(struct wcn36xx_dxe_desc); + +		switch (wcn_ch->ch_type) { +		case WCN36XX_DXE_CH_TX_L: +			cur_dxe->ctrl = WCN36XX_DXE_CTRL_TX_L; +			cur_dxe->dst_addr_l = WCN36XX_DXE_WQ_TX_L; +			break; +		case WCN36XX_DXE_CH_TX_H: +			cur_dxe->ctrl = WCN36XX_DXE_CTRL_TX_H; +			cur_dxe->dst_addr_l = WCN36XX_DXE_WQ_TX_H; +			break; +		case WCN36XX_DXE_CH_RX_L: +			cur_dxe->ctrl = WCN36XX_DXE_CTRL_RX_L; +			cur_dxe->src_addr_l = WCN36XX_DXE_WQ_RX_L; +			break; +		case WCN36XX_DXE_CH_RX_H: +			cur_dxe->ctrl = WCN36XX_DXE_CTRL_RX_H; +			cur_dxe->src_addr_l = WCN36XX_DXE_WQ_RX_H; +			break; +		} +		if (0 == i) { +			cur_dxe->phy_next_l = 0; +		} else if ((0 < i) && (i < wcn_ch->desc_num - 1)) { +			prev_dxe->phy_next_l = +				cur_ctl->desc_phy_addr; +		} else if (i == (wcn_ch->desc_num - 1)) { +			prev_dxe->phy_next_l = +				cur_ctl->desc_phy_addr; +			cur_dxe->phy_next_l = +				wcn_ch->head_blk_ctl->desc_phy_addr; +		} +		cur_ctl = cur_ctl->next; +		prev_dxe = cur_dxe; +		cur_dxe++; +	} + +	return 0; +} + +static void wcn36xx_dxe_init_tx_bd(struct wcn36xx_dxe_ch *ch, +				   struct wcn36xx_dxe_mem_pool *pool) +{ +	int i, chunk_size = pool->chunk_size; +	dma_addr_t bd_phy_addr = pool->phy_addr; +	void *bd_cpu_addr = pool->virt_addr; +	struct wcn36xx_dxe_ctl *cur = ch->head_blk_ctl; + +	for (i = 0; i < ch->desc_num; i++) { +		/* Only every second dxe needs a bd pointer, +		   the other will point to the skb data */ +		if (!(i & 1)) { +			cur->bd_phy_addr = bd_phy_addr; +			cur->bd_cpu_addr = bd_cpu_addr; +			bd_phy_addr += chunk_size; +			bd_cpu_addr += chunk_size; +		} else { +			cur->bd_phy_addr = 0; +			cur->bd_cpu_addr = NULL; +		} +		cur = cur->next; +	} +} + +static int wcn36xx_dxe_enable_ch_int(struct wcn36xx *wcn, u16 wcn_ch) +{ +	int reg_data = 0; + +	wcn36xx_dxe_read_register(wcn, +				  WCN36XX_DXE_INT_MASK_REG, +				  ®_data); + +	reg_data |= wcn_ch; + +	wcn36xx_dxe_write_register(wcn, +				   WCN36XX_DXE_INT_MASK_REG, +				   (int)reg_data); +	return 0; +} + +static int wcn36xx_dxe_fill_skb(struct wcn36xx_dxe_ctl *ctl) +{ +	struct wcn36xx_dxe_desc *dxe = ctl->desc; +	struct sk_buff *skb; + +	skb = alloc_skb(WCN36XX_PKT_SIZE, GFP_ATOMIC); +	if (skb == NULL) +		return -ENOMEM; + +	dxe->dst_addr_l = dma_map_single(NULL, +					 skb_tail_pointer(skb), +					 WCN36XX_PKT_SIZE, +					 DMA_FROM_DEVICE); +	ctl->skb = skb; + +	return 0; +} + +static int wcn36xx_dxe_ch_alloc_skb(struct wcn36xx *wcn, +				    struct wcn36xx_dxe_ch *wcn_ch) +{ +	int i; +	struct wcn36xx_dxe_ctl *cur_ctl = NULL; + +	cur_ctl = wcn_ch->head_blk_ctl; + +	for (i = 0; i < wcn_ch->desc_num; i++) { +		wcn36xx_dxe_fill_skb(cur_ctl); +		cur_ctl = cur_ctl->next; +	} + +	return 0; +} + +static void wcn36xx_dxe_ch_free_skbs(struct wcn36xx *wcn, +				     struct wcn36xx_dxe_ch *wcn_ch) +{ +	struct wcn36xx_dxe_ctl *cur = wcn_ch->head_blk_ctl; +	int i; + +	for (i = 0; i < wcn_ch->desc_num; i++) { +		kfree_skb(cur->skb); +		cur = cur->next; +	} +} + +void wcn36xx_dxe_tx_ack_ind(struct wcn36xx *wcn, u32 status) +{ +	struct ieee80211_tx_info *info; +	struct sk_buff *skb; +	unsigned long flags; + +	spin_lock_irqsave(&wcn->dxe_lock, flags); +	skb = wcn->tx_ack_skb; +	wcn->tx_ack_skb = NULL; +	spin_unlock_irqrestore(&wcn->dxe_lock, flags); + +	if (!skb) { +		wcn36xx_warn("Spurious TX complete indication\n"); +		return; +	} + +	info = IEEE80211_SKB_CB(skb); + +	if (status == 1) +		info->flags |= IEEE80211_TX_STAT_ACK; + +	wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ack status: %d\n", status); + +	ieee80211_tx_status_irqsafe(wcn->hw, skb); +	ieee80211_wake_queues(wcn->hw); +} + +static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch) +{ +	struct wcn36xx_dxe_ctl *ctl = ch->tail_blk_ctl; +	struct ieee80211_tx_info *info; +	unsigned long flags; + +	/* +	 * Make at least one loop of do-while because in case ring is +	 * completely full head and tail are pointing to the same element +	 * and while-do will not make any cycles. +	 */ +	do { +		if (ctl->skb) { +			dma_unmap_single(NULL, ctl->desc->src_addr_l, +					 ctl->skb->len, DMA_TO_DEVICE); +			info = IEEE80211_SKB_CB(ctl->skb); +			if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) { +				/* Keep frame until TX status comes */ +				ieee80211_free_txskb(wcn->hw, ctl->skb); +			} +			spin_lock_irqsave(&ctl->skb_lock, flags); +			if (wcn->queues_stopped) { +				wcn->queues_stopped = false; +				ieee80211_wake_queues(wcn->hw); +			} +			spin_unlock_irqrestore(&ctl->skb_lock, flags); + +			ctl->skb = NULL; +		} +		ctl = ctl->next; +	} while (ctl != ch->head_blk_ctl && +	       !(ctl->desc->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)); + +	ch->tail_blk_ctl = ctl; +} + +static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev) +{ +	struct wcn36xx *wcn = (struct wcn36xx *)dev; +	int int_src, int_reason; + +	wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_INT_SRC_RAW_REG, &int_src); + +	if (int_src & WCN36XX_INT_MASK_CHAN_TX_H) { +		wcn36xx_dxe_read_register(wcn, +					  WCN36XX_DXE_CH_STATUS_REG_ADDR_TX_H, +					  &int_reason); + +		/* TODO: Check int_reason */ + +		wcn36xx_dxe_write_register(wcn, +					   WCN36XX_DXE_0_INT_CLR, +					   WCN36XX_INT_MASK_CHAN_TX_H); + +		wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_ED_CLR, +					   WCN36XX_INT_MASK_CHAN_TX_H); +		wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ready high\n"); +		reap_tx_dxes(wcn, &wcn->dxe_tx_h_ch); +	} + +	if (int_src & WCN36XX_INT_MASK_CHAN_TX_L) { +		wcn36xx_dxe_read_register(wcn, +					  WCN36XX_DXE_CH_STATUS_REG_ADDR_TX_L, +					  &int_reason); +		/* TODO: Check int_reason */ + +		wcn36xx_dxe_write_register(wcn, +					   WCN36XX_DXE_0_INT_CLR, +					   WCN36XX_INT_MASK_CHAN_TX_L); + +		wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_ED_CLR, +					   WCN36XX_INT_MASK_CHAN_TX_L); +		wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ready low\n"); +		reap_tx_dxes(wcn, &wcn->dxe_tx_l_ch); +	} + +	return IRQ_HANDLED; +} + +static irqreturn_t wcn36xx_irq_rx_ready(int irq, void *dev) +{ +	struct wcn36xx *wcn = (struct wcn36xx *)dev; + +	disable_irq_nosync(wcn->rx_irq); +	wcn36xx_dxe_rx_frame(wcn); +	enable_irq(wcn->rx_irq); +	return IRQ_HANDLED; +} + +static int wcn36xx_dxe_request_irqs(struct wcn36xx *wcn) +{ +	int ret; + +	ret = request_irq(wcn->tx_irq, wcn36xx_irq_tx_complete, +			  IRQF_TRIGGER_HIGH, "wcn36xx_tx", wcn); +	if (ret) { +		wcn36xx_err("failed to alloc tx irq\n"); +		goto out_err; +	} + +	ret = request_irq(wcn->rx_irq, wcn36xx_irq_rx_ready, IRQF_TRIGGER_HIGH, +			  "wcn36xx_rx", wcn); +	if (ret) { +		wcn36xx_err("failed to alloc rx irq\n"); +		goto out_txirq; +	} + +	enable_irq_wake(wcn->rx_irq); + +	return 0; + +out_txirq: +	free_irq(wcn->tx_irq, wcn); +out_err: +	return ret; + +} + +static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn, +				     struct wcn36xx_dxe_ch *ch) +{ +	struct wcn36xx_dxe_ctl *ctl = ch->head_blk_ctl; +	struct wcn36xx_dxe_desc *dxe = ctl->desc; +	dma_addr_t  dma_addr; +	struct sk_buff *skb; + +	while (!(dxe->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)) { +		skb = ctl->skb; +		dma_addr = dxe->dst_addr_l; +		wcn36xx_dxe_fill_skb(ctl); + +		switch (ch->ch_type) { +		case WCN36XX_DXE_CH_RX_L: +			dxe->ctrl = WCN36XX_DXE_CTRL_RX_L; +			wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_ENCH_ADDR, +						   WCN36XX_DXE_INT_CH1_MASK); +			break; +		case WCN36XX_DXE_CH_RX_H: +			dxe->ctrl = WCN36XX_DXE_CTRL_RX_H; +			wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_ENCH_ADDR, +						   WCN36XX_DXE_INT_CH3_MASK); +			break; +		default: +			wcn36xx_warn("Unknown channel\n"); +		} + +		dma_unmap_single(NULL, dma_addr, WCN36XX_PKT_SIZE, +				 DMA_FROM_DEVICE); +		wcn36xx_rx_skb(wcn, skb); +		ctl = ctl->next; +		dxe = ctl->desc; +	} + +	ch->head_blk_ctl = ctl; + +	return 0; +} + +void wcn36xx_dxe_rx_frame(struct wcn36xx *wcn) +{ +	int int_src; + +	wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_INT_SRC_RAW_REG, &int_src); + +	/* RX_LOW_PRI */ +	if (int_src & WCN36XX_DXE_INT_CH1_MASK) { +		wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_CLR, +					   WCN36XX_DXE_INT_CH1_MASK); +		wcn36xx_rx_handle_packets(wcn, &(wcn->dxe_rx_l_ch)); +	} + +	/* RX_HIGH_PRI */ +	if (int_src & WCN36XX_DXE_INT_CH3_MASK) { +		/* Clean up all the INT within this channel */ +		wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_CLR, +					   WCN36XX_DXE_INT_CH3_MASK); +		wcn36xx_rx_handle_packets(wcn, &(wcn->dxe_rx_h_ch)); +	} + +	if (!int_src) +		wcn36xx_warn("No DXE interrupt pending\n"); +} + +int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn) +{ +	size_t s; +	void *cpu_addr; + +	/* Allocate BD headers for MGMT frames */ + +	/* Where this come from ask QC */ +	wcn->mgmt_mem_pool.chunk_size =	WCN36XX_BD_CHUNK_SIZE + +		16 - (WCN36XX_BD_CHUNK_SIZE % 8); + +	s = wcn->mgmt_mem_pool.chunk_size * WCN36XX_DXE_CH_DESC_NUMB_TX_H; +	cpu_addr = dma_alloc_coherent(NULL, s, &wcn->mgmt_mem_pool.phy_addr, +				      GFP_KERNEL); +	if (!cpu_addr) +		goto out_err; + +	wcn->mgmt_mem_pool.virt_addr = cpu_addr; +	memset(cpu_addr, 0, s); + +	/* Allocate BD headers for DATA frames */ + +	/* Where this come from ask QC */ +	wcn->data_mem_pool.chunk_size = WCN36XX_BD_CHUNK_SIZE + +		16 - (WCN36XX_BD_CHUNK_SIZE % 8); + +	s = wcn->data_mem_pool.chunk_size * WCN36XX_DXE_CH_DESC_NUMB_TX_L; +	cpu_addr = dma_alloc_coherent(NULL, s, &wcn->data_mem_pool.phy_addr, +				      GFP_KERNEL); +	if (!cpu_addr) +		goto out_err; + +	wcn->data_mem_pool.virt_addr = cpu_addr; +	memset(cpu_addr, 0, s); + +	return 0; + +out_err: +	wcn36xx_dxe_free_mem_pools(wcn); +	wcn36xx_err("Failed to allocate BD mempool\n"); +	return -ENOMEM; +} + +void wcn36xx_dxe_free_mem_pools(struct wcn36xx *wcn) +{ +	if (wcn->mgmt_mem_pool.virt_addr) +		dma_free_coherent(NULL, wcn->mgmt_mem_pool.chunk_size * +				  WCN36XX_DXE_CH_DESC_NUMB_TX_H, +				  wcn->mgmt_mem_pool.virt_addr, +				  wcn->mgmt_mem_pool.phy_addr); + +	if (wcn->data_mem_pool.virt_addr) { +		dma_free_coherent(NULL, wcn->data_mem_pool.chunk_size * +				  WCN36XX_DXE_CH_DESC_NUMB_TX_L, +				  wcn->data_mem_pool.virt_addr, +				  wcn->data_mem_pool.phy_addr); +	} +} + +int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, +			 struct wcn36xx_vif *vif_priv, +			 struct sk_buff *skb, +			 bool is_low) +{ +	struct wcn36xx_dxe_ctl *ctl = NULL; +	struct wcn36xx_dxe_desc *desc = NULL; +	struct wcn36xx_dxe_ch *ch = NULL; +	unsigned long flags; + +	ch = is_low ? &wcn->dxe_tx_l_ch : &wcn->dxe_tx_h_ch; + +	ctl = ch->head_blk_ctl; + +	spin_lock_irqsave(&ctl->next->skb_lock, flags); + +	/* +	 * If skb is not null that means that we reached the tail of the ring +	 * hence ring is full. Stop queues to let mac80211 back off until ring +	 * has an empty slot again. +	 */ +	if (NULL != ctl->next->skb) { +		ieee80211_stop_queues(wcn->hw); +		wcn->queues_stopped = true; +		spin_unlock_irqrestore(&ctl->next->skb_lock, flags); +		return -EBUSY; +	} +	spin_unlock_irqrestore(&ctl->next->skb_lock, flags); + +	ctl->skb = NULL; +	desc = ctl->desc; + +	/* Set source address of the BD we send */ +	desc->src_addr_l = ctl->bd_phy_addr; + +	desc->dst_addr_l = ch->dxe_wq; +	desc->fr_len = sizeof(struct wcn36xx_tx_bd); +	desc->ctrl = ch->ctrl_bd; + +	wcn36xx_dbg(WCN36XX_DBG_DXE, "DXE TX\n"); + +	wcn36xx_dbg_dump(WCN36XX_DBG_DXE_DUMP, "DESC1 >>> ", +			 (char *)desc, sizeof(*desc)); +	wcn36xx_dbg_dump(WCN36XX_DBG_DXE_DUMP, +			 "BD   >>> ", (char *)ctl->bd_cpu_addr, +			 sizeof(struct wcn36xx_tx_bd)); + +	/* Set source address of the SKB we send */ +	ctl = ctl->next; +	ctl->skb = skb; +	desc = ctl->desc; +	if (ctl->bd_cpu_addr) { +		wcn36xx_err("bd_cpu_addr cannot be NULL for skb DXE\n"); +		return -EINVAL; +	} + +	desc->src_addr_l = dma_map_single(NULL, +					  ctl->skb->data, +					  ctl->skb->len, +					  DMA_TO_DEVICE); + +	desc->dst_addr_l = ch->dxe_wq; +	desc->fr_len = ctl->skb->len; + +	/* set dxe descriptor to VALID */ +	desc->ctrl = ch->ctrl_skb; + +	wcn36xx_dbg_dump(WCN36XX_DBG_DXE_DUMP, "DESC2 >>> ", +			 (char *)desc, sizeof(*desc)); +	wcn36xx_dbg_dump(WCN36XX_DBG_DXE_DUMP, "SKB   >>> ", +			 (char *)ctl->skb->data, ctl->skb->len); + +	/* Move the head of the ring to the next empty descriptor */ +	 ch->head_blk_ctl = ctl->next; + +	/* +	 * When connected and trying to send data frame chip can be in sleep +	 * mode and writing to the register will not wake up the chip. Instead +	 * notify chip about new frame through SMSM bus. +	 */ +	if (is_low &&  vif_priv->pw_state == WCN36XX_BMPS) { +		wcn->ctrl_ops->smsm_change_state( +				  0, +				  WCN36XX_SMSM_WLAN_TX_ENABLE); +	} else { +		/* indicate End Of Packet and generate interrupt on descriptor +		 * done. +		 */ +		wcn36xx_dxe_write_register(wcn, +			ch->reg_ctrl, ch->def_ctrl); +	} + +	return 0; +} + +int wcn36xx_dxe_init(struct wcn36xx *wcn) +{ +	int reg_data = 0, ret; + +	reg_data = WCN36XX_DXE_REG_RESET; +	wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_REG_CSR_RESET, reg_data); + +	/* Setting interrupt path */ +	reg_data = WCN36XX_DXE_CCU_INT; +	wcn36xx_dxe_write_register_x(wcn, WCN36XX_DXE_REG_CCU_INT, reg_data); + +	/***************************************/ +	/* Init descriptors for TX LOW channel */ +	/***************************************/ +	wcn36xx_dxe_init_descs(&wcn->dxe_tx_l_ch); +	wcn36xx_dxe_init_tx_bd(&wcn->dxe_tx_l_ch, &wcn->data_mem_pool); + +	/* Write channel head to a NEXT register */ +	wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_CH_NEXT_DESC_ADDR_TX_L, +		wcn->dxe_tx_l_ch.head_blk_ctl->desc_phy_addr); + +	/* Program DMA destination addr for TX LOW */ +	wcn36xx_dxe_write_register(wcn, +		WCN36XX_DXE_CH_DEST_ADDR_TX_L, +		WCN36XX_DXE_WQ_TX_L); + +	wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_REG_CH_EN, ®_data); +	wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_TX_L); + +	/***************************************/ +	/* Init descriptors for TX HIGH channel */ +	/***************************************/ +	wcn36xx_dxe_init_descs(&wcn->dxe_tx_h_ch); +	wcn36xx_dxe_init_tx_bd(&wcn->dxe_tx_h_ch, &wcn->mgmt_mem_pool); + +	/* Write channel head to a NEXT register */ +	wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_CH_NEXT_DESC_ADDR_TX_H, +		wcn->dxe_tx_h_ch.head_blk_ctl->desc_phy_addr); + +	/* Program DMA destination addr for TX HIGH */ +	wcn36xx_dxe_write_register(wcn, +		WCN36XX_DXE_CH_DEST_ADDR_TX_H, +		WCN36XX_DXE_WQ_TX_H); + +	wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_REG_CH_EN, ®_data); + +	/* Enable channel interrupts */ +	wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_TX_H); + +	/***************************************/ +	/* Init descriptors for RX LOW channel */ +	/***************************************/ +	wcn36xx_dxe_init_descs(&wcn->dxe_rx_l_ch); + +	/* For RX we need to preallocated buffers */ +	wcn36xx_dxe_ch_alloc_skb(wcn, &wcn->dxe_rx_l_ch); + +	/* Write channel head to a NEXT register */ +	wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_CH_NEXT_DESC_ADDR_RX_L, +		wcn->dxe_rx_l_ch.head_blk_ctl->desc_phy_addr); + +	/* Write DMA source address */ +	wcn36xx_dxe_write_register(wcn, +		WCN36XX_DXE_CH_SRC_ADDR_RX_L, +		WCN36XX_DXE_WQ_RX_L); + +	/* Program preallocated destination address */ +	wcn36xx_dxe_write_register(wcn, +		WCN36XX_DXE_CH_DEST_ADDR_RX_L, +		wcn->dxe_rx_l_ch.head_blk_ctl->desc->phy_next_l); + +	/* Enable default control registers */ +	wcn36xx_dxe_write_register(wcn, +		WCN36XX_DXE_REG_CTL_RX_L, +		WCN36XX_DXE_CH_DEFAULT_CTL_RX_L); + +	/* Enable channel interrupts */ +	wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_RX_L); + +	/***************************************/ +	/* Init descriptors for RX HIGH channel */ +	/***************************************/ +	wcn36xx_dxe_init_descs(&wcn->dxe_rx_h_ch); + +	/* For RX we need to prealocat buffers */ +	wcn36xx_dxe_ch_alloc_skb(wcn, &wcn->dxe_rx_h_ch); + +	/* Write chanel head to a NEXT register */ +	wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_CH_NEXT_DESC_ADDR_RX_H, +		wcn->dxe_rx_h_ch.head_blk_ctl->desc_phy_addr); + +	/* Write DMA source address */ +	wcn36xx_dxe_write_register(wcn, +		WCN36XX_DXE_CH_SRC_ADDR_RX_H, +		WCN36XX_DXE_WQ_RX_H); + +	/* Program preallocated destination address */ +	wcn36xx_dxe_write_register(wcn, +		WCN36XX_DXE_CH_DEST_ADDR_RX_H, +		 wcn->dxe_rx_h_ch.head_blk_ctl->desc->phy_next_l); + +	/* Enable default control registers */ +	wcn36xx_dxe_write_register(wcn, +		WCN36XX_DXE_REG_CTL_RX_H, +		WCN36XX_DXE_CH_DEFAULT_CTL_RX_H); + +	/* Enable channel interrupts */ +	wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_RX_H); + +	ret = wcn36xx_dxe_request_irqs(wcn); +	if (ret < 0) +		goto out_err; + +	return 0; + +out_err: +	return ret; +} + +void wcn36xx_dxe_deinit(struct wcn36xx *wcn) +{ +	free_irq(wcn->tx_irq, wcn); +	free_irq(wcn->rx_irq, wcn); + +	if (wcn->tx_ack_skb) { +		ieee80211_tx_status_irqsafe(wcn->hw, wcn->tx_ack_skb); +		wcn->tx_ack_skb = NULL; +	} + +	wcn36xx_dxe_ch_free_skbs(wcn, &wcn->dxe_rx_l_ch); +	wcn36xx_dxe_ch_free_skbs(wcn, &wcn->dxe_rx_h_ch); +} diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.h b/drivers/net/wireless/ath/wcn36xx/dxe.h new file mode 100644 index 00000000000..35ee7e966bd --- /dev/null +++ b/drivers/net/wireless/ath/wcn36xx/dxe.h @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com> + * + * 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 _DXE_H_ +#define _DXE_H_ + +#include "wcn36xx.h" + +/* +TX_LOW	= DMA0 +TX_HIGH	= DMA4 +RX_LOW	= DMA1 +RX_HIGH	= DMA3 +H2H_TEST_RX_TX = DMA2 +*/ + +/* DXE registers */ +#define WCN36XX_DXE_MEM_REG			0x202000 + +#define WCN36XX_DXE_CCU_INT			0xA0011 +#define WCN36XX_DXE_REG_CCU_INT_3660		0x200b10 +#define WCN36XX_DXE_REG_CCU_INT_3680		0x2050dc + +/* TODO This must calculated properly but not hardcoded */ +#define WCN36XX_DXE_CTRL_TX_L			0x328a44 +#define WCN36XX_DXE_CTRL_TX_H			0x32ce44 +#define WCN36XX_DXE_CTRL_RX_L			0x12ad2f +#define WCN36XX_DXE_CTRL_RX_H			0x12d12f +#define WCN36XX_DXE_CTRL_TX_H_BD		0x30ce45 +#define WCN36XX_DXE_CTRL_TX_H_SKB		0x32ce4d +#define WCN36XX_DXE_CTRL_TX_L_BD		0x308a45 +#define WCN36XX_DXE_CTRL_TX_L_SKB		0x328a4d + +/* TODO This must calculated properly but not hardcoded */ +#define WCN36XX_DXE_WQ_TX_L			0x17 +#define WCN36XX_DXE_WQ_TX_H			0x17 +#define WCN36XX_DXE_WQ_RX_L			0xB +#define WCN36XX_DXE_WQ_RX_H			0x4 + +/* DXE descriptor control filed */ +#define WCN36XX_DXE_CTRL_VALID_MASK (0x00000001) + +/* TODO This must calculated properly but not hardcoded */ +/* DXE default control register values */ +#define WCN36XX_DXE_CH_DEFAULT_CTL_RX_L		0x847EAD2F +#define WCN36XX_DXE_CH_DEFAULT_CTL_RX_H		0x84FED12F +#define WCN36XX_DXE_CH_DEFAULT_CTL_TX_H		0x853ECF4D +#define WCN36XX_DXE_CH_DEFAULT_CTL_TX_L		0x843e8b4d + +/* Common DXE registers */ +#define WCN36XX_DXE_MEM_CSR			(WCN36XX_DXE_MEM_REG + 0x00) +#define WCN36XX_DXE_REG_CSR_RESET		(WCN36XX_DXE_MEM_REG + 0x00) +#define WCN36XX_DXE_ENCH_ADDR			(WCN36XX_DXE_MEM_REG + 0x04) +#define WCN36XX_DXE_REG_CH_EN			(WCN36XX_DXE_MEM_REG + 0x08) +#define WCN36XX_DXE_REG_CH_DONE			(WCN36XX_DXE_MEM_REG + 0x0C) +#define WCN36XX_DXE_REG_CH_ERR			(WCN36XX_DXE_MEM_REG + 0x10) +#define WCN36XX_DXE_INT_MASK_REG		(WCN36XX_DXE_MEM_REG + 0x18) +#define WCN36XX_DXE_INT_SRC_RAW_REG		(WCN36XX_DXE_MEM_REG + 0x20) +	/* #define WCN36XX_DXE_INT_CH6_MASK	0x00000040 */ +	/* #define WCN36XX_DXE_INT_CH5_MASK	0x00000020 */ +	#define WCN36XX_DXE_INT_CH4_MASK	0x00000010 +	#define WCN36XX_DXE_INT_CH3_MASK	0x00000008 +	/* #define WCN36XX_DXE_INT_CH2_MASK	0x00000004 */ +	#define WCN36XX_DXE_INT_CH1_MASK	0x00000002 +	#define WCN36XX_DXE_INT_CH0_MASK	0x00000001 +#define WCN36XX_DXE_0_INT_CLR			(WCN36XX_DXE_MEM_REG + 0x30) +#define WCN36XX_DXE_0_INT_ED_CLR		(WCN36XX_DXE_MEM_REG + 0x34) +#define WCN36XX_DXE_0_INT_DONE_CLR		(WCN36XX_DXE_MEM_REG + 0x38) +#define WCN36XX_DXE_0_INT_ERR_CLR		(WCN36XX_DXE_MEM_REG + 0x3C) + +#define WCN36XX_DXE_0_CH0_STATUS		(WCN36XX_DXE_MEM_REG + 0x404) +#define WCN36XX_DXE_0_CH1_STATUS		(WCN36XX_DXE_MEM_REG + 0x444) +#define WCN36XX_DXE_0_CH2_STATUS		(WCN36XX_DXE_MEM_REG + 0x484) +#define WCN36XX_DXE_0_CH3_STATUS		(WCN36XX_DXE_MEM_REG + 0x4C4) +#define WCN36XX_DXE_0_CH4_STATUS		(WCN36XX_DXE_MEM_REG + 0x504) + +#define WCN36XX_DXE_REG_RESET			0x5c89 + +/* Temporary BMU Workqueue 4 */ +#define WCN36XX_DXE_BMU_WQ_RX_LOW		0xB +#define WCN36XX_DXE_BMU_WQ_RX_HIGH		0x4 +/* DMA channel offset */ +#define WCN36XX_DXE_TX_LOW_OFFSET		0x400 +#define WCN36XX_DXE_TX_HIGH_OFFSET		0x500 +#define WCN36XX_DXE_RX_LOW_OFFSET		0x440 +#define WCN36XX_DXE_RX_HIGH_OFFSET		0x4C0 + +/* Address of the next DXE descriptor */ +#define WCN36XX_DXE_CH_NEXT_DESC_ADDR		0x001C +#define WCN36XX_DXE_CH_NEXT_DESC_ADDR_TX_L	(WCN36XX_DXE_MEM_REG + \ +						 WCN36XX_DXE_TX_LOW_OFFSET + \ +						 WCN36XX_DXE_CH_NEXT_DESC_ADDR) +#define WCN36XX_DXE_CH_NEXT_DESC_ADDR_TX_H	(WCN36XX_DXE_MEM_REG + \ +						 WCN36XX_DXE_TX_HIGH_OFFSET + \ +						 WCN36XX_DXE_CH_NEXT_DESC_ADDR) +#define WCN36XX_DXE_CH_NEXT_DESC_ADDR_RX_L	(WCN36XX_DXE_MEM_REG + \ +						 WCN36XX_DXE_RX_LOW_OFFSET + \ +						 WCN36XX_DXE_CH_NEXT_DESC_ADDR) +#define WCN36XX_DXE_CH_NEXT_DESC_ADDR_RX_H	(WCN36XX_DXE_MEM_REG + \ +						 WCN36XX_DXE_RX_HIGH_OFFSET + \ +						 WCN36XX_DXE_CH_NEXT_DESC_ADDR) + +/* DXE Descriptor source address */ +#define WCN36XX_DXE_CH_SRC_ADDR			0x000C +#define WCN36XX_DXE_CH_SRC_ADDR_RX_L		(WCN36XX_DXE_MEM_REG + \ +						 WCN36XX_DXE_RX_LOW_OFFSET + \ +						 WCN36XX_DXE_CH_SRC_ADDR) +#define WCN36XX_DXE_CH_SRC_ADDR_RX_H		(WCN36XX_DXE_MEM_REG + \ +						 WCN36XX_DXE_RX_HIGH_OFFSET + \ +						 WCN36XX_DXE_CH_SRC_ADDR) + +/* DXE Descriptor address destination address */ +#define WCN36XX_DXE_CH_DEST_ADDR		0x0014 +#define WCN36XX_DXE_CH_DEST_ADDR_TX_L		(WCN36XX_DXE_MEM_REG + \ +						 WCN36XX_DXE_TX_LOW_OFFSET + \ +						 WCN36XX_DXE_CH_DEST_ADDR) +#define WCN36XX_DXE_CH_DEST_ADDR_TX_H		(WCN36XX_DXE_MEM_REG + \ +						 WCN36XX_DXE_TX_HIGH_OFFSET + \ +						 WCN36XX_DXE_CH_DEST_ADDR) +#define WCN36XX_DXE_CH_DEST_ADDR_RX_L		(WCN36XX_DXE_MEM_REG + \ +						 WCN36XX_DXE_RX_LOW_OFFSET + \ +						 WCN36XX_DXE_CH_DEST_ADDR) +#define WCN36XX_DXE_CH_DEST_ADDR_RX_H		(WCN36XX_DXE_MEM_REG + \ +						 WCN36XX_DXE_RX_HIGH_OFFSET + \ +						 WCN36XX_DXE_CH_DEST_ADDR) + +/* Interrupt status */ +#define WCN36XX_DXE_CH_STATUS_REG_ADDR		0x0004 +#define WCN36XX_DXE_CH_STATUS_REG_ADDR_TX_L	(WCN36XX_DXE_MEM_REG + \ +						 WCN36XX_DXE_TX_LOW_OFFSET + \ +						 WCN36XX_DXE_CH_STATUS_REG_ADDR) +#define WCN36XX_DXE_CH_STATUS_REG_ADDR_TX_H	(WCN36XX_DXE_MEM_REG + \ +						 WCN36XX_DXE_TX_HIGH_OFFSET + \ +						 WCN36XX_DXE_CH_STATUS_REG_ADDR) +#define WCN36XX_DXE_CH_STATUS_REG_ADDR_RX_L	(WCN36XX_DXE_MEM_REG + \ +						 WCN36XX_DXE_RX_LOW_OFFSET + \ +						 WCN36XX_DXE_CH_STATUS_REG_ADDR) +#define WCN36XX_DXE_CH_STATUS_REG_ADDR_RX_H	(WCN36XX_DXE_MEM_REG + \ +						 WCN36XX_DXE_RX_HIGH_OFFSET + \ +						 WCN36XX_DXE_CH_STATUS_REG_ADDR) + + +/* DXE default control register */ +#define WCN36XX_DXE_REG_CTL_RX_L		(WCN36XX_DXE_MEM_REG + \ +						 WCN36XX_DXE_RX_LOW_OFFSET) +#define WCN36XX_DXE_REG_CTL_RX_H		(WCN36XX_DXE_MEM_REG + \ +						 WCN36XX_DXE_RX_HIGH_OFFSET) +#define WCN36XX_DXE_REG_CTL_TX_H		(WCN36XX_DXE_MEM_REG + \ +						 WCN36XX_DXE_TX_HIGH_OFFSET) +#define WCN36XX_DXE_REG_CTL_TX_L		(WCN36XX_DXE_MEM_REG + \ +						 WCN36XX_DXE_TX_LOW_OFFSET) + +#define WCN36XX_SMSM_WLAN_TX_ENABLE		0x00000400 +#define WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY	0x00000200 + + +/* Interrupt control channel mask */ +#define WCN36XX_INT_MASK_CHAN_TX_L		0x00000001 +#define WCN36XX_INT_MASK_CHAN_RX_L		0x00000002 +#define WCN36XX_INT_MASK_CHAN_RX_H		0x00000008 +#define WCN36XX_INT_MASK_CHAN_TX_H		0x00000010 + +#define WCN36XX_BD_CHUNK_SIZE			128 + +#define WCN36XX_PKT_SIZE			0xF20 +enum wcn36xx_dxe_ch_type { +	WCN36XX_DXE_CH_TX_L, +	WCN36XX_DXE_CH_TX_H, +	WCN36XX_DXE_CH_RX_L, +	WCN36XX_DXE_CH_RX_H +}; + +/* amount of descriptors per channel */ +enum wcn36xx_dxe_ch_desc_num { +	WCN36XX_DXE_CH_DESC_NUMB_TX_L		= 128, +	WCN36XX_DXE_CH_DESC_NUMB_TX_H		= 10, +	WCN36XX_DXE_CH_DESC_NUMB_RX_L		= 512, +	WCN36XX_DXE_CH_DESC_NUMB_RX_H		= 40 +}; + +/** + * struct wcn36xx_dxe_desc - describes descriptor of one DXE buffer + * + * @ctrl: is a union that consists of following bits: + * union { + *	u32	valid		:1; //0 = DMA stop, 1 = DMA continue with this + *				    //descriptor + *	u32	transfer_type	:2; //0 = Host to Host space + *	u32	eop		:1; //End of Packet + *	u32	bd_handling	:1; //if transferType = Host to BMU, then 0 + *				    // means first 128 bytes contain BD, and 1 + *				    // means create new empty BD + *	u32	siq		:1; // SIQ + *	u32	diq		:1; // DIQ + *	u32	pdu_rel		:1; //0 = don't release BD and PDUs when done, + *				    // 1 = release them + *	u32	bthld_sel	:4; //BMU Threshold Select + *	u32	prio		:3; //Specifies the priority level to use for + *				    // the transfer + *	u32	stop_channel	:1; //1 = DMA stops processing further, channel + *				    //requires re-enabling after this + *	u32	intr		:1; //Interrupt on Descriptor Done + *	u32	rsvd		:1; //reserved + *	u32	size		:14;//14 bits used - ignored for BMU transfers, + *				    //only used for host to host transfers? + * } ctrl; + */ +struct wcn36xx_dxe_desc { +	u32	ctrl; +	u32	fr_len; + +	u32	src_addr_l; +	u32	dst_addr_l; +	u32	phy_next_l; +	u32	src_addr_h; +	u32	dst_addr_h; +	u32	phy_next_h; +} __packed; + +/* DXE Control block */ +struct wcn36xx_dxe_ctl { +	struct wcn36xx_dxe_ctl	*next; +	struct wcn36xx_dxe_desc	*desc; +	unsigned int		desc_phy_addr; +	int			ctl_blk_order; +	struct sk_buff		*skb; +	spinlock_t              skb_lock; +	void			*bd_cpu_addr; +	dma_addr_t		bd_phy_addr; +}; + +struct wcn36xx_dxe_ch { +	enum wcn36xx_dxe_ch_type	ch_type; +	void				*cpu_addr; +	dma_addr_t			dma_addr; +	enum wcn36xx_dxe_ch_desc_num	desc_num; +	/* DXE control block ring */ +	struct wcn36xx_dxe_ctl		*head_blk_ctl; +	struct wcn36xx_dxe_ctl		*tail_blk_ctl; + +	/* DXE channel specific configs */ +	u32				dxe_wq; +	u32				ctrl_bd; +	u32				ctrl_skb; +	u32				reg_ctrl; +	u32				def_ctrl; +}; + +/* Memory Pool for BD headers */ +struct wcn36xx_dxe_mem_pool { +	int		chunk_size; +	void		*virt_addr; +	dma_addr_t	phy_addr; +}; + +struct wcn36xx_vif; +int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn); +void wcn36xx_dxe_free_mem_pools(struct wcn36xx *wcn); +void wcn36xx_dxe_rx_frame(struct wcn36xx *wcn); +int wcn36xx_dxe_alloc_ctl_blks(struct wcn36xx *wcn); +void wcn36xx_dxe_free_ctl_blks(struct wcn36xx *wcn); +int wcn36xx_dxe_init(struct wcn36xx *wcn); +void wcn36xx_dxe_deinit(struct wcn36xx *wcn); +int wcn36xx_dxe_init_channels(struct wcn36xx *wcn); +int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, +			 struct wcn36xx_vif *vif_priv, +			 struct sk_buff *skb, +			 bool is_low); +void wcn36xx_dxe_tx_ack_ind(struct wcn36xx *wcn, u32 status); +void *wcn36xx_dxe_get_next_bd(struct wcn36xx *wcn, bool is_low); +#endif	/* _DXE_H_ */ diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h new file mode 100644 index 00000000000..a1f1127d780 --- /dev/null +++ b/drivers/net/wireless/ath/wcn36xx/hal.h @@ -0,0 +1,4659 @@ +/* + * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com> + * + * 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 _HAL_H_ +#define _HAL_H_ + +/*--------------------------------------------------------------------------- +  API VERSIONING INFORMATION + +  The RIVA API is versioned as MAJOR.MINOR.VERSION.REVISION +  The MAJOR is incremented for major product/architecture changes +      (and then MINOR/VERSION/REVISION are zeroed) +  The MINOR is incremented for minor product/architecture changes +      (and then VERSION/REVISION are zeroed) +  The VERSION is incremented if a significant API change occurs +      (and then REVISION is zeroed) +  The REVISION is incremented if an insignificant API change occurs +      or if a new API is added +  All values are in the range 0..255 (ie they are 8-bit values) + ---------------------------------------------------------------------------*/ +#define WCN36XX_HAL_VER_MAJOR 1 +#define WCN36XX_HAL_VER_MINOR 4 +#define WCN36XX_HAL_VER_VERSION 1 +#define WCN36XX_HAL_VER_REVISION 2 + +/* This is to force compiler to use the maximum of an int ( 4 bytes ) */ +#define WCN36XX_HAL_MAX_ENUM_SIZE    0x7FFFFFFF +#define WCN36XX_HAL_MSG_TYPE_MAX_ENUM_SIZE    0x7FFF + +/* Max no. of transmit categories */ +#define STACFG_MAX_TC    8 + +/* The maximum value of access category */ +#define WCN36XX_HAL_MAX_AC  4 + +#define WCN36XX_HAL_IPV4_ADDR_LEN       4 + +#define WALN_HAL_STA_INVALID_IDX 0xFF +#define WCN36XX_HAL_BSS_INVALID_IDX 0xFF + +/* Default Beacon template size */ +#define BEACON_TEMPLATE_SIZE 0x180 + +/* Param Change Bitmap sent to HAL */ +#define PARAM_BCN_INTERVAL_CHANGED                      (1 << 0) +#define PARAM_SHORT_PREAMBLE_CHANGED                 (1 << 1) +#define PARAM_SHORT_SLOT_TIME_CHANGED                 (1 << 2) +#define PARAM_llACOEXIST_CHANGED                            (1 << 3) +#define PARAM_llBCOEXIST_CHANGED                            (1 << 4) +#define PARAM_llGCOEXIST_CHANGED                            (1 << 5) +#define PARAM_HT20MHZCOEXIST_CHANGED                  (1<<6) +#define PARAM_NON_GF_DEVICES_PRESENT_CHANGED (1<<7) +#define PARAM_RIFS_MODE_CHANGED                            (1<<8) +#define PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED   (1<<9) +#define PARAM_OBSS_MODE_CHANGED                               (1<<10) +#define PARAM_BEACON_UPDATE_MASK \ +	(PARAM_BCN_INTERVAL_CHANGED |					\ +	 PARAM_SHORT_PREAMBLE_CHANGED |					\ +	 PARAM_SHORT_SLOT_TIME_CHANGED |				\ +	 PARAM_llACOEXIST_CHANGED |					\ +	 PARAM_llBCOEXIST_CHANGED |					\ +	 PARAM_llGCOEXIST_CHANGED |					\ +	 PARAM_HT20MHZCOEXIST_CHANGED |					\ +	 PARAM_NON_GF_DEVICES_PRESENT_CHANGED |				\ +	 PARAM_RIFS_MODE_CHANGED |					\ +	 PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED |				\ +	 PARAM_OBSS_MODE_CHANGED) + +/* dump command response Buffer size */ +#define DUMPCMD_RSP_BUFFER 100 + +/* version string max length (including NULL) */ +#define WCN36XX_HAL_VERSION_LENGTH  64 + +/* message types for messages exchanged between WDI and HAL */ +enum wcn36xx_hal_host_msg_type { +	/* Init/De-Init */ +	WCN36XX_HAL_START_REQ = 0, +	WCN36XX_HAL_START_RSP = 1, +	WCN36XX_HAL_STOP_REQ = 2, +	WCN36XX_HAL_STOP_RSP = 3, + +	/* Scan */ +	WCN36XX_HAL_INIT_SCAN_REQ = 4, +	WCN36XX_HAL_INIT_SCAN_RSP = 5, +	WCN36XX_HAL_START_SCAN_REQ = 6, +	WCN36XX_HAL_START_SCAN_RSP = 7, +	WCN36XX_HAL_END_SCAN_REQ = 8, +	WCN36XX_HAL_END_SCAN_RSP = 9, +	WCN36XX_HAL_FINISH_SCAN_REQ = 10, +	WCN36XX_HAL_FINISH_SCAN_RSP = 11, + +	/* HW STA configuration/deconfiguration */ +	WCN36XX_HAL_CONFIG_STA_REQ = 12, +	WCN36XX_HAL_CONFIG_STA_RSP = 13, +	WCN36XX_HAL_DELETE_STA_REQ = 14, +	WCN36XX_HAL_DELETE_STA_RSP = 15, +	WCN36XX_HAL_CONFIG_BSS_REQ = 16, +	WCN36XX_HAL_CONFIG_BSS_RSP = 17, +	WCN36XX_HAL_DELETE_BSS_REQ = 18, +	WCN36XX_HAL_DELETE_BSS_RSP = 19, + +	/* Infra STA asscoiation */ +	WCN36XX_HAL_JOIN_REQ = 20, +	WCN36XX_HAL_JOIN_RSP = 21, +	WCN36XX_HAL_POST_ASSOC_REQ = 22, +	WCN36XX_HAL_POST_ASSOC_RSP = 23, + +	/* Security */ +	WCN36XX_HAL_SET_BSSKEY_REQ = 24, +	WCN36XX_HAL_SET_BSSKEY_RSP = 25, +	WCN36XX_HAL_SET_STAKEY_REQ = 26, +	WCN36XX_HAL_SET_STAKEY_RSP = 27, +	WCN36XX_HAL_RMV_BSSKEY_REQ = 28, +	WCN36XX_HAL_RMV_BSSKEY_RSP = 29, +	WCN36XX_HAL_RMV_STAKEY_REQ = 30, +	WCN36XX_HAL_RMV_STAKEY_RSP = 31, + +	/* Qos Related */ +	WCN36XX_HAL_ADD_TS_REQ = 32, +	WCN36XX_HAL_ADD_TS_RSP = 33, +	WCN36XX_HAL_DEL_TS_REQ = 34, +	WCN36XX_HAL_DEL_TS_RSP = 35, +	WCN36XX_HAL_UPD_EDCA_PARAMS_REQ = 36, +	WCN36XX_HAL_UPD_EDCA_PARAMS_RSP = 37, +	WCN36XX_HAL_ADD_BA_REQ = 38, +	WCN36XX_HAL_ADD_BA_RSP = 39, +	WCN36XX_HAL_DEL_BA_REQ = 40, +	WCN36XX_HAL_DEL_BA_RSP = 41, + +	WCN36XX_HAL_CH_SWITCH_REQ = 42, +	WCN36XX_HAL_CH_SWITCH_RSP = 43, +	WCN36XX_HAL_SET_LINK_ST_REQ = 44, +	WCN36XX_HAL_SET_LINK_ST_RSP = 45, +	WCN36XX_HAL_GET_STATS_REQ = 46, +	WCN36XX_HAL_GET_STATS_RSP = 47, +	WCN36XX_HAL_UPDATE_CFG_REQ = 48, +	WCN36XX_HAL_UPDATE_CFG_RSP = 49, + +	WCN36XX_HAL_MISSED_BEACON_IND = 50, +	WCN36XX_HAL_UNKNOWN_ADDR2_FRAME_RX_IND = 51, +	WCN36XX_HAL_MIC_FAILURE_IND = 52, +	WCN36XX_HAL_FATAL_ERROR_IND = 53, +	WCN36XX_HAL_SET_KEYDONE_MSG = 54, + +	/* NV Interface */ +	WCN36XX_HAL_DOWNLOAD_NV_REQ = 55, +	WCN36XX_HAL_DOWNLOAD_NV_RSP = 56, + +	WCN36XX_HAL_ADD_BA_SESSION_REQ = 57, +	WCN36XX_HAL_ADD_BA_SESSION_RSP = 58, +	WCN36XX_HAL_TRIGGER_BA_REQ = 59, +	WCN36XX_HAL_TRIGGER_BA_RSP = 60, +	WCN36XX_HAL_UPDATE_BEACON_REQ = 61, +	WCN36XX_HAL_UPDATE_BEACON_RSP = 62, +	WCN36XX_HAL_SEND_BEACON_REQ = 63, +	WCN36XX_HAL_SEND_BEACON_RSP = 64, + +	WCN36XX_HAL_SET_BCASTKEY_REQ = 65, +	WCN36XX_HAL_SET_BCASTKEY_RSP = 66, +	WCN36XX_HAL_DELETE_STA_CONTEXT_IND = 67, +	WCN36XX_HAL_UPDATE_PROBE_RSP_TEMPLATE_REQ = 68, +	WCN36XX_HAL_UPDATE_PROBE_RSP_TEMPLATE_RSP = 69, + +	/* PTT interface support */ +	WCN36XX_HAL_PROCESS_PTT_REQ = 70, +	WCN36XX_HAL_PROCESS_PTT_RSP = 71, + +	/* BTAMP related events */ +	WCN36XX_HAL_SIGNAL_BTAMP_EVENT_REQ = 72, +	WCN36XX_HAL_SIGNAL_BTAMP_EVENT_RSP = 73, +	WCN36XX_HAL_TL_HAL_FLUSH_AC_REQ = 74, +	WCN36XX_HAL_TL_HAL_FLUSH_AC_RSP = 75, + +	WCN36XX_HAL_ENTER_IMPS_REQ = 76, +	WCN36XX_HAL_EXIT_IMPS_REQ = 77, +	WCN36XX_HAL_ENTER_BMPS_REQ = 78, +	WCN36XX_HAL_EXIT_BMPS_REQ = 79, +	WCN36XX_HAL_ENTER_UAPSD_REQ = 80, +	WCN36XX_HAL_EXIT_UAPSD_REQ = 81, +	WCN36XX_HAL_UPDATE_UAPSD_PARAM_REQ = 82, +	WCN36XX_HAL_CONFIGURE_RXP_FILTER_REQ = 83, +	WCN36XX_HAL_ADD_BCN_FILTER_REQ = 84, +	WCN36XX_HAL_REM_BCN_FILTER_REQ = 85, +	WCN36XX_HAL_ADD_WOWL_BCAST_PTRN = 86, +	WCN36XX_HAL_DEL_WOWL_BCAST_PTRN = 87, +	WCN36XX_HAL_ENTER_WOWL_REQ = 88, +	WCN36XX_HAL_EXIT_WOWL_REQ = 89, +	WCN36XX_HAL_HOST_OFFLOAD_REQ = 90, +	WCN36XX_HAL_SET_RSSI_THRESH_REQ = 91, +	WCN36XX_HAL_GET_RSSI_REQ = 92, +	WCN36XX_HAL_SET_UAPSD_AC_PARAMS_REQ = 93, +	WCN36XX_HAL_CONFIGURE_APPS_CPU_WAKEUP_STATE_REQ = 94, + +	WCN36XX_HAL_ENTER_IMPS_RSP = 95, +	WCN36XX_HAL_EXIT_IMPS_RSP = 96, +	WCN36XX_HAL_ENTER_BMPS_RSP = 97, +	WCN36XX_HAL_EXIT_BMPS_RSP = 98, +	WCN36XX_HAL_ENTER_UAPSD_RSP = 99, +	WCN36XX_HAL_EXIT_UAPSD_RSP = 100, +	WCN36XX_HAL_SET_UAPSD_AC_PARAMS_RSP = 101, +	WCN36XX_HAL_UPDATE_UAPSD_PARAM_RSP = 102, +	WCN36XX_HAL_CONFIGURE_RXP_FILTER_RSP = 103, +	WCN36XX_HAL_ADD_BCN_FILTER_RSP = 104, +	WCN36XX_HAL_REM_BCN_FILTER_RSP = 105, +	WCN36XX_HAL_SET_RSSI_THRESH_RSP = 106, +	WCN36XX_HAL_HOST_OFFLOAD_RSP = 107, +	WCN36XX_HAL_ADD_WOWL_BCAST_PTRN_RSP = 108, +	WCN36XX_HAL_DEL_WOWL_BCAST_PTRN_RSP = 109, +	WCN36XX_HAL_ENTER_WOWL_RSP = 110, +	WCN36XX_HAL_EXIT_WOWL_RSP = 111, +	WCN36XX_HAL_RSSI_NOTIFICATION_IND = 112, +	WCN36XX_HAL_GET_RSSI_RSP = 113, +	WCN36XX_HAL_CONFIGURE_APPS_CPU_WAKEUP_STATE_RSP = 114, + +	/* 11k related events */ +	WCN36XX_HAL_SET_MAX_TX_POWER_REQ = 115, +	WCN36XX_HAL_SET_MAX_TX_POWER_RSP = 116, + +	/* 11R related msgs */ +	WCN36XX_HAL_AGGR_ADD_TS_REQ = 117, +	WCN36XX_HAL_AGGR_ADD_TS_RSP = 118, + +	/* P2P  WLAN_FEATURE_P2P */ +	WCN36XX_HAL_SET_P2P_GONOA_REQ = 119, +	WCN36XX_HAL_SET_P2P_GONOA_RSP = 120, + +	/* WLAN Dump commands */ +	WCN36XX_HAL_DUMP_COMMAND_REQ = 121, +	WCN36XX_HAL_DUMP_COMMAND_RSP = 122, + +	/* OEM_DATA FEATURE SUPPORT */ +	WCN36XX_HAL_START_OEM_DATA_REQ = 123, +	WCN36XX_HAL_START_OEM_DATA_RSP = 124, + +	/* ADD SELF STA REQ and RSP */ +	WCN36XX_HAL_ADD_STA_SELF_REQ = 125, +	WCN36XX_HAL_ADD_STA_SELF_RSP = 126, + +	/* DEL SELF STA SUPPORT */ +	WCN36XX_HAL_DEL_STA_SELF_REQ = 127, +	WCN36XX_HAL_DEL_STA_SELF_RSP = 128, + +	/* Coex Indication */ +	WCN36XX_HAL_COEX_IND = 129, + +	/* Tx Complete Indication */ +	WCN36XX_HAL_OTA_TX_COMPL_IND = 130, + +	/* Host Suspend/resume messages */ +	WCN36XX_HAL_HOST_SUSPEND_IND = 131, +	WCN36XX_HAL_HOST_RESUME_REQ = 132, +	WCN36XX_HAL_HOST_RESUME_RSP = 133, + +	WCN36XX_HAL_SET_TX_POWER_REQ = 134, +	WCN36XX_HAL_SET_TX_POWER_RSP = 135, +	WCN36XX_HAL_GET_TX_POWER_REQ = 136, +	WCN36XX_HAL_GET_TX_POWER_RSP = 137, + +	WCN36XX_HAL_P2P_NOA_ATTR_IND = 138, + +	WCN36XX_HAL_ENABLE_RADAR_DETECT_REQ = 139, +	WCN36XX_HAL_ENABLE_RADAR_DETECT_RSP = 140, +	WCN36XX_HAL_GET_TPC_REPORT_REQ = 141, +	WCN36XX_HAL_GET_TPC_REPORT_RSP = 142, +	WCN36XX_HAL_RADAR_DETECT_IND = 143, +	WCN36XX_HAL_RADAR_DETECT_INTR_IND = 144, +	WCN36XX_HAL_KEEP_ALIVE_REQ = 145, +	WCN36XX_HAL_KEEP_ALIVE_RSP = 146, + +	/* PNO messages */ +	WCN36XX_HAL_SET_PREF_NETWORK_REQ = 147, +	WCN36XX_HAL_SET_PREF_NETWORK_RSP = 148, +	WCN36XX_HAL_SET_RSSI_FILTER_REQ = 149, +	WCN36XX_HAL_SET_RSSI_FILTER_RSP = 150, +	WCN36XX_HAL_UPDATE_SCAN_PARAM_REQ = 151, +	WCN36XX_HAL_UPDATE_SCAN_PARAM_RSP = 152, +	WCN36XX_HAL_PREF_NETW_FOUND_IND = 153, + +	WCN36XX_HAL_SET_TX_PER_TRACKING_REQ = 154, +	WCN36XX_HAL_SET_TX_PER_TRACKING_RSP = 155, +	WCN36XX_HAL_TX_PER_HIT_IND = 156, + +	WCN36XX_HAL_8023_MULTICAST_LIST_REQ = 157, +	WCN36XX_HAL_8023_MULTICAST_LIST_RSP = 158, + +	WCN36XX_HAL_SET_PACKET_FILTER_REQ = 159, +	WCN36XX_HAL_SET_PACKET_FILTER_RSP = 160, +	WCN36XX_HAL_PACKET_FILTER_MATCH_COUNT_REQ = 161, +	WCN36XX_HAL_PACKET_FILTER_MATCH_COUNT_RSP = 162, +	WCN36XX_HAL_CLEAR_PACKET_FILTER_REQ = 163, +	WCN36XX_HAL_CLEAR_PACKET_FILTER_RSP = 164, + +	/* +	 * This is temp fix. Should be removed once Host and Riva code is +	 * in sync. +	 */ +	WCN36XX_HAL_INIT_SCAN_CON_REQ = 165, + +	WCN36XX_HAL_SET_POWER_PARAMS_REQ = 166, +	WCN36XX_HAL_SET_POWER_PARAMS_RSP = 167, + +	WCN36XX_HAL_TSM_STATS_REQ = 168, +	WCN36XX_HAL_TSM_STATS_RSP = 169, + +	/* wake reason indication (WOW) */ +	WCN36XX_HAL_WAKE_REASON_IND = 170, + +	/* GTK offload support */ +	WCN36XX_HAL_GTK_OFFLOAD_REQ = 171, +	WCN36XX_HAL_GTK_OFFLOAD_RSP = 172, +	WCN36XX_HAL_GTK_OFFLOAD_GETINFO_REQ = 173, +	WCN36XX_HAL_GTK_OFFLOAD_GETINFO_RSP = 174, + +	WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_REQ = 175, +	WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_RSP = 176, +	WCN36XX_HAL_EXCLUDE_UNENCRYPTED_IND = 177, + +	WCN36XX_HAL_SET_THERMAL_MITIGATION_REQ = 178, +	WCN36XX_HAL_SET_THERMAL_MITIGATION_RSP = 179, + +	WCN36XX_HAL_UPDATE_VHT_OP_MODE_REQ = 182, +	WCN36XX_HAL_UPDATE_VHT_OP_MODE_RSP = 183, + +	WCN36XX_HAL_P2P_NOA_START_IND = 184, + +	WCN36XX_HAL_GET_ROAM_RSSI_REQ = 185, +	WCN36XX_HAL_GET_ROAM_RSSI_RSP = 186, + +	WCN36XX_HAL_CLASS_B_STATS_IND = 187, +	WCN36XX_HAL_DEL_BA_IND = 188, +	WCN36XX_HAL_DHCP_START_IND = 189, +	WCN36XX_HAL_DHCP_STOP_IND = 190, + +	WCN36XX_HAL_MSG_MAX = WCN36XX_HAL_MSG_TYPE_MAX_ENUM_SIZE +}; + +/* Enumeration for Version */ +enum wcn36xx_hal_host_msg_version { +	WCN36XX_HAL_MSG_VERSION0 = 0, +	WCN36XX_HAL_MSG_VERSION1 = 1, +	/* define as 2 bytes data */ +	WCN36XX_HAL_MSG_WCNSS_CTRL_VERSION = 0x7FFF, +	WCN36XX_HAL_MSG_VERSION_MAX_FIELD = WCN36XX_HAL_MSG_WCNSS_CTRL_VERSION +}; + +enum driver_type { +	DRIVER_TYPE_PRODUCTION = 0, +	DRIVER_TYPE_MFG = 1, +	DRIVER_TYPE_DVT = 2, +	DRIVER_TYPE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE +}; + +enum wcn36xx_hal_stop_type { +	HAL_STOP_TYPE_SYS_RESET, +	HAL_STOP_TYPE_SYS_DEEP_SLEEP, +	HAL_STOP_TYPE_RF_KILL, +	HAL_STOP_TYPE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE +}; + +enum wcn36xx_hal_sys_mode { +	HAL_SYS_MODE_NORMAL, +	HAL_SYS_MODE_LEARN, +	HAL_SYS_MODE_SCAN, +	HAL_SYS_MODE_PROMISC, +	HAL_SYS_MODE_SUSPEND_LINK, +	HAL_SYS_MODE_ROAM_SCAN, +	HAL_SYS_MODE_ROAM_SUSPEND_LINK, +	HAL_SYS_MODE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE +}; + +enum phy_chan_bond_state { +	/* 20MHz IF bandwidth centered on IF carrier */ +	PHY_SINGLE_CHANNEL_CENTERED = 0, + +	/* 40MHz IF bandwidth with lower 20MHz supporting the primary channel */ +	PHY_DOUBLE_CHANNEL_LOW_PRIMARY = 1, + +	/* 40MHz IF bandwidth centered on IF carrier */ +	PHY_DOUBLE_CHANNEL_CENTERED = 2, + +	/* 40MHz IF bandwidth with higher 20MHz supporting the primary ch */ +	PHY_DOUBLE_CHANNEL_HIGH_PRIMARY = 3, + +	/* 20/40MHZ offset LOW 40/80MHZ offset CENTERED */ +	PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED = 4, + +	/* 20/40MHZ offset CENTERED 40/80MHZ offset CENTERED */ +	PHY_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED = 5, + +	/* 20/40MHZ offset HIGH 40/80MHZ offset CENTERED */ +	PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED = 6, + +	/* 20/40MHZ offset LOW 40/80MHZ offset LOW */ +	PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW = 7, + +	/* 20/40MHZ offset HIGH 40/80MHZ offset LOW */ +	PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW = 8, + +	/* 20/40MHZ offset LOW 40/80MHZ offset HIGH */ +	PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH = 9, + +	/* 20/40MHZ offset-HIGH 40/80MHZ offset HIGH */ +	PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH = 10, + +	PHY_CHANNEL_BONDING_STATE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE +}; + +/* Spatial Multiplexing(SM) Power Save mode */ +enum wcn36xx_hal_ht_mimo_state { +	/* Static SM Power Save mode */ +	WCN36XX_HAL_HT_MIMO_PS_STATIC = 0, + +	/* Dynamic SM Power Save mode */ +	WCN36XX_HAL_HT_MIMO_PS_DYNAMIC = 1, + +	/* reserved */ +	WCN36XX_HAL_HT_MIMO_PS_NA = 2, + +	/* SM Power Save disabled */ +	WCN36XX_HAL_HT_MIMO_PS_NO_LIMIT = 3, + +	WCN36XX_HAL_HT_MIMO_PS_MAX = WCN36XX_HAL_MAX_ENUM_SIZE +}; + +/* each station added has a rate mode which specifies the sta attributes */ +enum sta_rate_mode { +	STA_TAURUS = 0, +	STA_TITAN, +	STA_POLARIS, +	STA_11b, +	STA_11bg, +	STA_11a, +	STA_11n, +	STA_11ac, +	STA_INVALID_RATE_MODE = WCN36XX_HAL_MAX_ENUM_SIZE +}; + +/* 1,2,5.5,11 */ +#define WCN36XX_HAL_NUM_DSSS_RATES           4 + +/* 6,9,12,18,24,36,48,54 */ +#define WCN36XX_HAL_NUM_OFDM_RATES           8 + +/* 72,96,108 */ +#define WCN36XX_HAL_NUM_POLARIS_RATES       3 + +#define WCN36XX_HAL_MAC_MAX_SUPPORTED_MCS_SET    16 + +enum wcn36xx_hal_bss_type { +	WCN36XX_HAL_INFRASTRUCTURE_MODE, + +	/* Added for softAP support */ +	WCN36XX_HAL_INFRA_AP_MODE, + +	WCN36XX_HAL_IBSS_MODE, + +	/* Added for BT-AMP support */ +	WCN36XX_HAL_BTAMP_STA_MODE, + +	/* Added for BT-AMP support */ +	WCN36XX_HAL_BTAMP_AP_MODE, + +	WCN36XX_HAL_AUTO_MODE, + +	WCN36XX_HAL_DONOT_USE_BSS_TYPE = WCN36XX_HAL_MAX_ENUM_SIZE +}; + +enum wcn36xx_hal_nw_type { +	WCN36XX_HAL_11A_NW_TYPE, +	WCN36XX_HAL_11B_NW_TYPE, +	WCN36XX_HAL_11G_NW_TYPE, +	WCN36XX_HAL_11N_NW_TYPE, +	WCN36XX_HAL_DONOT_USE_NW_TYPE = WCN36XX_HAL_MAX_ENUM_SIZE +}; + +#define WCN36XX_HAL_MAC_RATESET_EID_MAX            12 + +enum wcn36xx_hal_ht_operating_mode { +	/* No Protection */ +	WCN36XX_HAL_HT_OP_MODE_PURE, + +	/* Overlap Legacy device present, protection is optional */ +	WCN36XX_HAL_HT_OP_MODE_OVERLAP_LEGACY, + +	/* No legacy device, but 20 MHz HT present */ +	WCN36XX_HAL_HT_OP_MODE_NO_LEGACY_20MHZ_HT, + +	/* Protection is required */ +	WCN36XX_HAL_HT_OP_MODE_MIXED, + +	WCN36XX_HAL_HT_OP_MODE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE +}; + +/* Encryption type enum used with peer */ +enum ani_ed_type { +	WCN36XX_HAL_ED_NONE, +	WCN36XX_HAL_ED_WEP40, +	WCN36XX_HAL_ED_WEP104, +	WCN36XX_HAL_ED_TKIP, +	WCN36XX_HAL_ED_CCMP, +	WCN36XX_HAL_ED_WPI, +	WCN36XX_HAL_ED_AES_128_CMAC, +	WCN36XX_HAL_ED_NOT_IMPLEMENTED = WCN36XX_HAL_MAX_ENUM_SIZE +}; + +#define WLAN_MAX_KEY_RSC_LEN                16 +#define WLAN_WAPI_KEY_RSC_LEN               16 + +/* MAX key length when ULA is used */ +#define WCN36XX_HAL_MAC_MAX_KEY_LENGTH              32 +#define WCN36XX_HAL_MAC_MAX_NUM_OF_DEFAULT_KEYS     4 + +/* + * Enum to specify whether key is used for TX only, RX only or both. + */ +enum ani_key_direction { +	WCN36XX_HAL_TX_ONLY, +	WCN36XX_HAL_RX_ONLY, +	WCN36XX_HAL_TX_RX, +	WCN36XX_HAL_TX_DEFAULT, +	WCN36XX_HAL_DONOT_USE_KEY_DIRECTION = WCN36XX_HAL_MAX_ENUM_SIZE +}; + +enum ani_wep_type { +	WCN36XX_HAL_WEP_STATIC, +	WCN36XX_HAL_WEP_DYNAMIC, +	WCN36XX_HAL_WEP_MAX = WCN36XX_HAL_MAX_ENUM_SIZE +}; + +enum wcn36xx_hal_link_state { + +	WCN36XX_HAL_LINK_IDLE_STATE = 0, +	WCN36XX_HAL_LINK_PREASSOC_STATE = 1, +	WCN36XX_HAL_LINK_POSTASSOC_STATE = 2, +	WCN36XX_HAL_LINK_AP_STATE = 3, +	WCN36XX_HAL_LINK_IBSS_STATE = 4, + +	/* BT-AMP Case */ +	WCN36XX_HAL_LINK_BTAMP_PREASSOC_STATE = 5, +	WCN36XX_HAL_LINK_BTAMP_POSTASSOC_STATE = 6, +	WCN36XX_HAL_LINK_BTAMP_AP_STATE = 7, +	WCN36XX_HAL_LINK_BTAMP_STA_STATE = 8, + +	/* Reserved for HAL Internal Use */ +	WCN36XX_HAL_LINK_LEARN_STATE = 9, +	WCN36XX_HAL_LINK_SCAN_STATE = 10, +	WCN36XX_HAL_LINK_FINISH_SCAN_STATE = 11, +	WCN36XX_HAL_LINK_INIT_CAL_STATE = 12, +	WCN36XX_HAL_LINK_FINISH_CAL_STATE = 13, +	WCN36XX_HAL_LINK_LISTEN_STATE = 14, + +	WCN36XX_HAL_LINK_MAX = WCN36XX_HAL_MAX_ENUM_SIZE +}; + +enum wcn36xx_hal_stats_mask { +	HAL_SUMMARY_STATS_INFO = 0x00000001, +	HAL_GLOBAL_CLASS_A_STATS_INFO = 0x00000002, +	HAL_GLOBAL_CLASS_B_STATS_INFO = 0x00000004, +	HAL_GLOBAL_CLASS_C_STATS_INFO = 0x00000008, +	HAL_GLOBAL_CLASS_D_STATS_INFO = 0x00000010, +	HAL_PER_STA_STATS_INFO = 0x00000020 +}; + +/* BT-AMP events type */ +enum bt_amp_event_type { +	BTAMP_EVENT_CONNECTION_START, +	BTAMP_EVENT_CONNECTION_STOP, +	BTAMP_EVENT_CONNECTION_TERMINATED, + +	/* This and beyond are invalid values */ +	BTAMP_EVENT_TYPE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE, +}; + +/* PE Statistics */ +enum pe_stats_mask { +	PE_SUMMARY_STATS_INFO = 0x00000001, +	PE_GLOBAL_CLASS_A_STATS_INFO = 0x00000002, +	PE_GLOBAL_CLASS_B_STATS_INFO = 0x00000004, +	PE_GLOBAL_CLASS_C_STATS_INFO = 0x00000008, +	PE_GLOBAL_CLASS_D_STATS_INFO = 0x00000010, +	PE_PER_STA_STATS_INFO = 0x00000020, + +	/* This and beyond are invalid values */ +	PE_STATS_TYPE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE +}; + +/* + * Configuration Parameter IDs + */ +#define WCN36XX_HAL_CFG_STA_ID				0 +#define WCN36XX_HAL_CFG_CURRENT_TX_ANTENNA		1 +#define WCN36XX_HAL_CFG_CURRENT_RX_ANTENNA		2 +#define WCN36XX_HAL_CFG_LOW_GAIN_OVERRIDE		3 +#define WCN36XX_HAL_CFG_POWER_STATE_PER_CHAIN		4 +#define WCN36XX_HAL_CFG_CAL_PERIOD			5 +#define WCN36XX_HAL_CFG_CAL_CONTROL			6 +#define WCN36XX_HAL_CFG_PROXIMITY			7 +#define WCN36XX_HAL_CFG_NETWORK_DENSITY			8 +#define WCN36XX_HAL_CFG_MAX_MEDIUM_TIME			9 +#define WCN36XX_HAL_CFG_MAX_MPDUS_IN_AMPDU		10 +#define WCN36XX_HAL_CFG_RTS_THRESHOLD			11 +#define WCN36XX_HAL_CFG_SHORT_RETRY_LIMIT		12 +#define WCN36XX_HAL_CFG_LONG_RETRY_LIMIT		13 +#define WCN36XX_HAL_CFG_FRAGMENTATION_THRESHOLD		14 +#define WCN36XX_HAL_CFG_DYNAMIC_THRESHOLD_ZERO		15 +#define WCN36XX_HAL_CFG_DYNAMIC_THRESHOLD_ONE		16 +#define WCN36XX_HAL_CFG_DYNAMIC_THRESHOLD_TWO		17 +#define WCN36XX_HAL_CFG_FIXED_RATE			18 +#define WCN36XX_HAL_CFG_RETRYRATE_POLICY		19 +#define WCN36XX_HAL_CFG_RETRYRATE_SECONDARY		20 +#define WCN36XX_HAL_CFG_RETRYRATE_TERTIARY		21 +#define WCN36XX_HAL_CFG_FORCE_POLICY_PROTECTION		22 +#define WCN36XX_HAL_CFG_FIXED_RATE_MULTICAST_24GHZ	23 +#define WCN36XX_HAL_CFG_FIXED_RATE_MULTICAST_5GHZ	24 +#define WCN36XX_HAL_CFG_DEFAULT_RATE_INDEX_24GHZ	25 +#define WCN36XX_HAL_CFG_DEFAULT_RATE_INDEX_5GHZ		26 +#define WCN36XX_HAL_CFG_MAX_BA_SESSIONS			27 +#define WCN36XX_HAL_CFG_PS_DATA_INACTIVITY_TIMEOUT	28 +#define WCN36XX_HAL_CFG_PS_ENABLE_BCN_FILTER		29 +#define WCN36XX_HAL_CFG_PS_ENABLE_RSSI_MONITOR		30 +#define WCN36XX_HAL_CFG_NUM_BEACON_PER_RSSI_AVERAGE	31 +#define WCN36XX_HAL_CFG_STATS_PERIOD			32 +#define WCN36XX_HAL_CFG_CFP_MAX_DURATION		33 +#define WCN36XX_HAL_CFG_FRAME_TRANS_ENABLED		34 +#define WCN36XX_HAL_CFG_DTIM_PERIOD			35 +#define WCN36XX_HAL_CFG_EDCA_WMM_ACBK			36 +#define WCN36XX_HAL_CFG_EDCA_WMM_ACBE			37 +#define WCN36XX_HAL_CFG_EDCA_WMM_ACVO			38 +#define WCN36XX_HAL_CFG_EDCA_WMM_ACVI			39 +#define WCN36XX_HAL_CFG_BA_THRESHOLD_HIGH		40 +#define WCN36XX_HAL_CFG_MAX_BA_BUFFERS			41 +#define WCN36XX_HAL_CFG_RPE_POLLING_THRESHOLD		42 +#define WCN36XX_HAL_CFG_RPE_AGING_THRESHOLD_FOR_AC0_REG	43 +#define WCN36XX_HAL_CFG_RPE_AGING_THRESHOLD_FOR_AC1_REG	44 +#define WCN36XX_HAL_CFG_RPE_AGING_THRESHOLD_FOR_AC2_REG	45 +#define WCN36XX_HAL_CFG_RPE_AGING_THRESHOLD_FOR_AC3_REG	46 +#define WCN36XX_HAL_CFG_NO_OF_ONCHIP_REORDER_SESSIONS	47 +#define WCN36XX_HAL_CFG_PS_LISTEN_INTERVAL		48 +#define WCN36XX_HAL_CFG_PS_HEART_BEAT_THRESHOLD		49 +#define WCN36XX_HAL_CFG_PS_NTH_BEACON_FILTER		50 +#define WCN36XX_HAL_CFG_PS_MAX_PS_POLL			51 +#define WCN36XX_HAL_CFG_PS_MIN_RSSI_THRESHOLD		52 +#define WCN36XX_HAL_CFG_PS_RSSI_FILTER_PERIOD		53 +#define WCN36XX_HAL_CFG_PS_BROADCAST_FRAME_FILTER_ENABLE 54 +#define WCN36XX_HAL_CFG_PS_IGNORE_DTIM			55 +#define WCN36XX_HAL_CFG_PS_ENABLE_BCN_EARLY_TERM	56 +#define WCN36XX_HAL_CFG_DYNAMIC_PS_POLL_VALUE		57 +#define WCN36XX_HAL_CFG_PS_NULLDATA_AP_RESP_TIMEOUT	58 +#define WCN36XX_HAL_CFG_TELE_BCN_WAKEUP_EN		59 +#define WCN36XX_HAL_CFG_TELE_BCN_TRANS_LI		60 +#define WCN36XX_HAL_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS	61 +#define WCN36XX_HAL_CFG_TELE_BCN_MAX_LI			62 +#define WCN36XX_HAL_CFG_TELE_BCN_MAX_LI_IDLE_BCNS	63 +#define WCN36XX_HAL_CFG_TX_PWR_CTRL_ENABLE		64 +#define WCN36XX_HAL_CFG_VALID_RADAR_CHANNEL_LIST	65 +#define WCN36XX_HAL_CFG_TX_POWER_24_20			66 +#define WCN36XX_HAL_CFG_TX_POWER_24_40			67 +#define WCN36XX_HAL_CFG_TX_POWER_50_20			68 +#define WCN36XX_HAL_CFG_TX_POWER_50_40			69 +#define WCN36XX_HAL_CFG_MCAST_BCAST_FILTER_SETTING	70 +#define WCN36XX_HAL_CFG_BCN_EARLY_TERM_WAKEUP_INTERVAL	71 +#define WCN36XX_HAL_CFG_MAX_TX_POWER_2_4		72 +#define WCN36XX_HAL_CFG_MAX_TX_POWER_5			73 +#define WCN36XX_HAL_CFG_INFRA_STA_KEEP_ALIVE_PERIOD	74 +#define WCN36XX_HAL_CFG_ENABLE_CLOSE_LOOP		75 +#define WCN36XX_HAL_CFG_BTC_EXECUTION_MODE		76 +#define WCN36XX_HAL_CFG_BTC_DHCP_BT_SLOTS_TO_BLOCK	77 +#define WCN36XX_HAL_CFG_BTC_A2DP_DHCP_BT_SUB_INTERVALS	78 +#define WCN36XX_HAL_CFG_PS_TX_INACTIVITY_TIMEOUT	79 +#define WCN36XX_HAL_CFG_WCNSS_API_VERSION		80 +#define WCN36XX_HAL_CFG_AP_KEEPALIVE_TIMEOUT		81 +#define WCN36XX_HAL_CFG_GO_KEEPALIVE_TIMEOUT		82 +#define WCN36XX_HAL_CFG_ENABLE_MC_ADDR_LIST		83 +#define WCN36XX_HAL_CFG_BTC_STATIC_LEN_INQ_BT		84 +#define WCN36XX_HAL_CFG_BTC_STATIC_LEN_PAGE_BT		85 +#define WCN36XX_HAL_CFG_BTC_STATIC_LEN_CONN_BT		86 +#define WCN36XX_HAL_CFG_BTC_STATIC_LEN_LE_BT		87 +#define WCN36XX_HAL_CFG_BTC_STATIC_LEN_INQ_WLAN		88 +#define WCN36XX_HAL_CFG_BTC_STATIC_LEN_PAGE_WLAN	89 +#define WCN36XX_HAL_CFG_BTC_STATIC_LEN_CONN_WLAN	90 +#define WCN36XX_HAL_CFG_BTC_STATIC_LEN_LE_WLAN		91 +#define WCN36XX_HAL_CFG_BTC_DYN_MAX_LEN_BT		92 +#define WCN36XX_HAL_CFG_BTC_DYN_MAX_LEN_WLAN		93 +#define WCN36XX_HAL_CFG_BTC_MAX_SCO_BLOCK_PERC		94 +#define WCN36XX_HAL_CFG_BTC_DHCP_PROT_ON_A2DP		95 +#define WCN36XX_HAL_CFG_BTC_DHCP_PROT_ON_SCO		96 +#define WCN36XX_HAL_CFG_ENABLE_UNICAST_FILTER		97 +#define WCN36XX_HAL_CFG_MAX_ASSOC_LIMIT			98 +#define WCN36XX_HAL_CFG_ENABLE_LPWR_IMG_TRANSITION	99 +#define WCN36XX_HAL_CFG_ENABLE_MCC_ADAPTIVE_SCHEDULER	100 +#define WCN36XX_HAL_CFG_ENABLE_DETECT_PS_SUPPORT	101 +#define WCN36XX_HAL_CFG_AP_LINK_MONITOR_TIMEOUT		102 +#define WCN36XX_HAL_CFG_BTC_DWELL_TIME_MULTIPLIER	103 +#define WCN36XX_HAL_CFG_ENABLE_TDLS_OXYGEN_MODE		104 +#define WCN36XX_HAL_CFG_MAX_PARAMS			105 + +/* Message definitons - All the messages below need to be packed */ + +/* Definition for HAL API Version. */ +struct wcnss_wlan_version { +	u8 revision; +	u8 version; +	u8 minor; +	u8 major; +} __packed; + +/* Definition for Encryption Keys */ +struct wcn36xx_hal_keys { +	u8 id; + +	/* 0 for multicast */ +	u8 unicast; + +	enum ani_key_direction direction; + +	/* Usage is unknown */ +	u8 rsc[WLAN_MAX_KEY_RSC_LEN]; + +	/* =1 for authenticator,=0 for supplicant */ +	u8 pae_role; + +	u16 length; +	u8 key[WCN36XX_HAL_MAC_MAX_KEY_LENGTH]; +} __packed; + +/* + * set_sta_key_params Moving here since it is shared by + * configbss/setstakey msgs + */ +struct wcn36xx_hal_set_sta_key_params { +	/* STA Index */ +	u16 sta_index; + +	/* Encryption Type used with peer */ +	enum ani_ed_type enc_type; + +	/* STATIC/DYNAMIC - valid only for WEP */ +	enum ani_wep_type wep_type; + +	/* Default WEP key, valid only for static WEP, must between 0 and 3. */ +	u8 def_wep_idx; + +	/* valid only for non-static WEP encyrptions */ +	struct wcn36xx_hal_keys key[WCN36XX_HAL_MAC_MAX_NUM_OF_DEFAULT_KEYS]; + +	/* +	 * Control for Replay Count, 1= Single TID based replay count on Tx +	 * 0 = Per TID based replay count on TX +	 */ +	u8 single_tid_rc; + +} __packed; + +/* 4-byte control message header used by HAL*/ +struct wcn36xx_hal_msg_header { +	enum wcn36xx_hal_host_msg_type msg_type:16; +	enum wcn36xx_hal_host_msg_version msg_version:16; +	u32 len; +} __packed; + +/* Config format required by HAL for each CFG item*/ +struct wcn36xx_hal_cfg { +	/* Cfg Id. The Id required by HAL is exported by HAL +	 * in shared header file between UMAC and HAL.*/ +	u16 id; + +	/* Length of the Cfg. This parameter is used to go to next cfg +	 * in the TLV format.*/ +	u16 len; + +	/* Padding bytes for unaligned address's */ +	u16 pad_bytes; + +	/* Reserve bytes for making cfgVal to align address */ +	u16 reserve; + +	/* Following the uCfgLen field there should be a 'uCfgLen' bytes +	 * containing the uCfgValue ; u8 uCfgValue[uCfgLen] */ +} __packed; + +struct wcn36xx_hal_mac_start_parameters { +	/* Drive Type - Production or FTM etc */ +	enum driver_type type; + +	/* Length of the config buffer */ +	u32 len; + +	/* Following this there is a TLV formatted buffer of length +	 * "len" bytes containing all config values. +	 * The TLV is expected to be formatted like this: +	 * 0           15            31           31+CFG_LEN-1        length-1 +	 * |   CFG_ID   |   CFG_LEN   |   CFG_BODY    |  CFG_ID  |......| +	 */ +} __packed; + +struct wcn36xx_hal_mac_start_req_msg { +	/* config buffer must start in TLV format just here */ +	struct wcn36xx_hal_msg_header header; +	struct wcn36xx_hal_mac_start_parameters params; +} __packed; + +struct wcn36xx_hal_mac_start_rsp_params { +	/* success or failure */ +	u16 status; + +	/* Max number of STA supported by the device */ +	u8 stations; + +	/* Max number of BSS supported by the device */ +	u8 bssids; + +	/* API Version */ +	struct wcnss_wlan_version version; + +	/* CRM build information */ +	u8 crm_version[WCN36XX_HAL_VERSION_LENGTH]; + +	/* hardware/chipset/misc version information */ +	u8 wlan_version[WCN36XX_HAL_VERSION_LENGTH]; + +} __packed; + +struct wcn36xx_hal_mac_start_rsp_msg { +	struct wcn36xx_hal_msg_header header; +	struct wcn36xx_hal_mac_start_rsp_params start_rsp_params; +} __packed; + +struct wcn36xx_hal_mac_stop_req_params { +	/* The reason for which the device is being stopped */ +	enum wcn36xx_hal_stop_type reason; + +} __packed; + +struct wcn36xx_hal_mac_stop_req_msg { +	struct wcn36xx_hal_msg_header header; +	struct wcn36xx_hal_mac_stop_req_params stop_req_params; +} __packed; + +struct wcn36xx_hal_mac_stop_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +} __packed; + +struct wcn36xx_hal_update_cfg_req_msg { +	/* +	 * Note: The length specified in tHalUpdateCfgReqMsg messages should be +	 * header.msgLen = sizeof(tHalUpdateCfgReqMsg) + uConfigBufferLen +	 */ +	struct wcn36xx_hal_msg_header header; + +	/* Length of the config buffer. Allows UMAC to update multiple CFGs */ +	u32 len; + +	/* +	 * Following this there is a TLV formatted buffer of length +	 * "uConfigBufferLen" bytes containing all config values. +	 * The TLV is expected to be formatted like this: +	 * 0           15            31           31+CFG_LEN-1        length-1 +	 * |   CFG_ID   |   CFG_LEN   |   CFG_BODY    |  CFG_ID  |......| +	 */ + +} __packed; + +struct wcn36xx_hal_update_cfg_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; + +} __packed; + +/* Frame control field format (2 bytes) */ +struct wcn36xx_hal_mac_frame_ctl { + +#ifndef ANI_LITTLE_BIT_ENDIAN + +	u8 subType:4; +	u8 type:2; +	u8 protVer:2; + +	u8 order:1; +	u8 wep:1; +	u8 moreData:1; +	u8 powerMgmt:1; +	u8 retry:1; +	u8 moreFrag:1; +	u8 fromDS:1; +	u8 toDS:1; + +#else + +	u8 protVer:2; +	u8 type:2; +	u8 subType:4; + +	u8 toDS:1; +	u8 fromDS:1; +	u8 moreFrag:1; +	u8 retry:1; +	u8 powerMgmt:1; +	u8 moreData:1; +	u8 wep:1; +	u8 order:1; + +#endif + +}; + +/* Sequence control field */ +struct wcn36xx_hal_mac_seq_ctl { +	u8 fragNum:4; +	u8 seqNumLo:4; +	u8 seqNumHi:8; +}; + +/* Management header format */ +struct wcn36xx_hal_mac_mgmt_hdr { +	struct wcn36xx_hal_mac_frame_ctl fc; +	u8 durationLo; +	u8 durationHi; +	u8 da[6]; +	u8 sa[6]; +	u8 bssId[6]; +	struct wcn36xx_hal_mac_seq_ctl seqControl; +}; + +/* FIXME: pronto v1 apparently has 4 */ +#define WCN36XX_HAL_NUM_BSSID               2 + +/* Scan Entry to hold active BSS idx's */ +struct wcn36xx_hal_scan_entry { +	u8 bss_index[WCN36XX_HAL_NUM_BSSID]; +	u8 active_bss_count; +}; + +struct wcn36xx_hal_init_scan_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* LEARN - AP Role +	   SCAN - STA Role */ +	enum wcn36xx_hal_sys_mode mode; + +	/* BSSID of the BSS */ +	u8 bssid[ETH_ALEN]; + +	/* Whether BSS needs to be notified */ +	u8 notify; + +	/* Kind of frame to be used for notifying the BSS (Data Null, QoS +	 * Null, or CTS to Self). Must always be a valid frame type. */ +	u8 frame_type; + +	/* UMAC has the option of passing the MAC frame to be used for +	 * notifying the BSS. If non-zero, HAL will use the MAC frame +	 * buffer pointed to by macMgmtHdr. If zero, HAL will generate the +	 * appropriate MAC frame based on frameType. */ +	u8 frame_len; + +	/* Following the framelength there is a MAC frame buffer if +	 * frameLength is non-zero. */ +	struct wcn36xx_hal_mac_mgmt_hdr mac_mgmt_hdr; + +	/* Entry to hold number of active BSS idx's */ +	struct wcn36xx_hal_scan_entry scan_entry; +}; + +struct wcn36xx_hal_init_scan_con_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* LEARN - AP Role +	   SCAN - STA Role */ +	enum wcn36xx_hal_sys_mode mode; + +	/* BSSID of the BSS */ +	u8 bssid[ETH_ALEN]; + +	/* Whether BSS needs to be notified */ +	u8 notify; + +	/* Kind of frame to be used for notifying the BSS (Data Null, QoS +	 * Null, or CTS to Self). Must always be a valid frame type. */ +	u8 frame_type; + +	/* UMAC has the option of passing the MAC frame to be used for +	 * notifying the BSS. If non-zero, HAL will use the MAC frame +	 * buffer pointed to by macMgmtHdr. If zero, HAL will generate the +	 * appropriate MAC frame based on frameType. */ +	u8 frame_length; + +	/* Following the framelength there is a MAC frame buffer if +	 * frameLength is non-zero. */ +	struct wcn36xx_hal_mac_mgmt_hdr mac_mgmt_hdr; + +	/* Entry to hold number of active BSS idx's */ +	struct wcn36xx_hal_scan_entry scan_entry; + +	/* Single NoA usage in Scanning */ +	u8 use_noa; + +	/* Indicates the scan duration (in ms) */ +	u16 scan_duration; + +}; + +struct wcn36xx_hal_init_scan_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; + +} __packed; + +struct wcn36xx_hal_start_scan_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Indicates the channel to scan */ +	u8 scan_channel; +} __packed; + +struct wcn36xx_hal_start_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; + +	u32 start_tsf[2]; +	u8 tx_mgmt_power; + +} __packed; + +struct wcn36xx_hal_end_scan_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Indicates the channel to stop scanning. Not used really. But +	 * retained for symmetry with "start Scan" message. It can also +	 * help in error check if needed. */ +	u8 scan_channel; +} __packed; + +struct wcn36xx_hal_end_scan_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +} __packed; + +struct wcn36xx_hal_finish_scan_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Identifies the operational state of the AP/STA +	 * LEARN - AP Role SCAN - STA Role */ +	enum wcn36xx_hal_sys_mode mode; + +	/* Operating channel to tune to. */ +	u8 oper_channel; + +	/* Channel Bonding state If 20/40 MHz is operational, this will +	 * indicate the 40 MHz extension channel in combination with the +	 * control channel */ +	enum phy_chan_bond_state cb_state; + +	/* BSSID of the BSS */ +	u8 bssid[ETH_ALEN]; + +	/* Whether BSS needs to be notified */ +	u8 notify; + +	/* Kind of frame to be used for notifying the BSS (Data Null, QoS +	 * Null, or CTS to Self). Must always be a valid frame type. */ +	u8 frame_type; + +	/* UMAC has the option of passing the MAC frame to be used for +	 * notifying the BSS. If non-zero, HAL will use the MAC frame +	 * buffer pointed to by macMgmtHdr. If zero, HAL will generate the +	 * appropriate MAC frame based on frameType. */ +	u8 frame_length; + +	/* Following the framelength there is a MAC frame buffer if +	 * frameLength is non-zero. */ +	struct wcn36xx_hal_mac_mgmt_hdr mac_mgmt_hdr; + +	/* Entry to hold number of active BSS idx's */ +	struct wcn36xx_hal_scan_entry scan_entry; + +} __packed; + +struct wcn36xx_hal_finish_scan_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; + +} __packed; + +enum wcn36xx_hal_rate_index { +	HW_RATE_INDEX_1MBPS	= 0x82, +	HW_RATE_INDEX_2MBPS	= 0x84, +	HW_RATE_INDEX_5_5MBPS	= 0x8B, +	HW_RATE_INDEX_6MBPS	= 0x0C, +	HW_RATE_INDEX_9MBPS	= 0x12, +	HW_RATE_INDEX_11MBPS	= 0x96, +	HW_RATE_INDEX_12MBPS	= 0x18, +	HW_RATE_INDEX_18MBPS	= 0x24, +	HW_RATE_INDEX_24MBPS	= 0x30, +	HW_RATE_INDEX_36MBPS	= 0x48, +	HW_RATE_INDEX_48MBPS	= 0x60, +	HW_RATE_INDEX_54MBPS	= 0x6C +}; + +struct wcn36xx_hal_supported_rates { +	/* +	 * For Self STA Entry: this represents Self Mode. +	 * For Peer Stations, this represents the mode of the peer. +	 * On Station: +	 * +	 * --this mode is updated when PE adds the Self Entry. +	 * +	 * -- OR when PE sends 'ADD_BSS' message and station context in BSS +	 *    is used to indicate the mode of the AP. +	 * +	 * ON AP: +	 * +	 * -- this mode is updated when PE sends 'ADD_BSS' and Sta entry +	 *     for that BSS is used to indicate the self mode of the AP. +	 * +	 * -- OR when a station is associated, PE sends 'ADD_STA' message +	 *    with this mode updated. +	 */ + +	enum sta_rate_mode op_rate_mode; + +	/* 11b, 11a and aniLegacyRates are IE rates which gives rate in +	 * unit of 500Kbps */ +	u16 dsss_rates[WCN36XX_HAL_NUM_DSSS_RATES]; +	u16 ofdm_rates[WCN36XX_HAL_NUM_OFDM_RATES]; +	u16 legacy_rates[WCN36XX_HAL_NUM_POLARIS_RATES]; +	u16 reserved; + +	/* Taurus only supports 26 Titan Rates(no ESF/concat Rates will be +	 * supported) First 26 bits are reserved for those Titan rates and +	 * the last 4 bits(bit28-31) for Taurus, 2(bit26-27) bits are +	 * reserved. */ +	/* Titan and Taurus Rates */ +	u32 enhanced_rate_bitmap; + +	/* +	 * 0-76 bits used, remaining reserved +	 * bits 0-15 and 32 should be set. +	 */ +	u8 supported_mcs_set[WCN36XX_HAL_MAC_MAX_SUPPORTED_MCS_SET]; + +	/* +	 * RX Highest Supported Data Rate defines the highest data +	 * rate that the STA is able to receive, in unites of 1Mbps. +	 * This value is derived from "Supported MCS Set field" inside +	 * the HT capability element. +	 */ +	u16 rx_highest_data_rate; + +} __packed; + +struct wcn36xx_hal_config_sta_params { +	/* BSSID of STA */ +	u8 bssid[ETH_ALEN]; + +	/* ASSOC ID, as assigned by UMAC */ +	u16 aid; + +	/* STA entry Type: 0 - Self, 1 - Other/Peer, 2 - BSSID, 3 - BCAST */ +	u8 type; + +	/* Short Preamble Supported. */ +	u8 short_preamble_supported; + +	/* MAC Address of STA */ +	u8 mac[ETH_ALEN]; + +	/* Listen interval of the STA */ +	u16 listen_interval; + +	/* Support for 11e/WMM */ +	u8 wmm_enabled; + +	/* 11n HT capable STA */ +	u8 ht_capable; + +	/* TX Width Set: 0 - 20 MHz only, 1 - 20/40 MHz */ +	u8 tx_channel_width_set; + +	/* RIFS mode 0 - NA, 1 - Allowed */ +	u8 rifs_mode; + +	/* L-SIG TXOP Protection mechanism +	   0 - No Support, 1 - Supported +	   SG - there is global field */ +	u8 lsig_txop_protection; + +	/* Max Ampdu Size supported by STA. TPE programming. +	   0 : 8k , 1 : 16k, 2 : 32k, 3 : 64k */ +	u8 max_ampdu_size; + +	/* Max Ampdu density. Used by RA.  3 : 0~7 : 2^(11nAMPDUdensity -4) */ +	u8 max_ampdu_density; + +	/* Max AMSDU size 1 : 3839 bytes, 0 : 7935 bytes */ +	u8 max_amsdu_size; + +	/* Short GI support for 40Mhz packets */ +	u8 sgi_40mhz; + +	/* Short GI support for 20Mhz packets */ +	u8 sgi_20Mhz; + +	/* TODO move this parameter to the end for 3680 */ +	/* These rates are the intersection of peer and self capabilities. */ +	struct wcn36xx_hal_supported_rates supported_rates; + +	/* Robust Management Frame (RMF) enabled/disabled */ +	u8 rmf; + +	/* The unicast encryption type in the association */ +	u32 encrypt_type; + +	/* HAL should update the existing STA entry, if this flag is set. UMAC +	   will set this flag in case of RE-ASSOC, where we want to reuse the +	   old STA ID. 0 = Add, 1 = Update */ +	u8 action; + +	/* U-APSD Flags: 1b per AC.  Encoded as follows: +	   b7 b6 b5 b4 b3 b2 b1 b0 = +	   X  X  X  X  BE BK VI VO */ +	u8 uapsd; + +	/* Max SP Length */ +	u8 max_sp_len; + +	/* 11n Green Field preamble support +	   0 - Not supported, 1 - Supported */ +	u8 green_field_capable; + +	/* MIMO Power Save mode */ +	enum wcn36xx_hal_ht_mimo_state mimo_ps; + +	/* Delayed BA Support */ +	u8 delayed_ba_support; + +	/* Max AMPDU duration in 32us */ +	u8 max_ampdu_duration; + +	/* HT STA should set it to 1 if it is enabled in BSS. HT STA should +	 * set it to 0 if AP does not support it. This indication is sent +	 * to HAL and HAL uses this flag to pickup up appropriate 40Mhz +	 * rates. */ +	u8 dsss_cck_mode_40mhz; + +	/* Valid STA Idx when action=Update. Set to 0xFF when invalid! +	 * Retained for backward compalibity with existing HAL code */ +	u8 sta_index; + +	/* BSSID of BSS to which station is associated. Set to 0xFF when +	 * invalid. Retained for backward compalibity with existing HAL +	 * code */ +	u8 bssid_index; + +	u8 p2p; + +	/* TODO add this parameter for 3680. */ +	/* Reserved to align next field on a dword boundary */ +	/* u8 reserved; */ +} __packed; + +struct wcn36xx_hal_config_sta_req_msg { +	struct wcn36xx_hal_msg_header header; +	struct wcn36xx_hal_config_sta_params sta_params; +} __packed; + +struct wcn36xx_hal_config_sta_params_v1 { +	/* BSSID of STA */ +	u8 bssid[ETH_ALEN]; + +	/* ASSOC ID, as assigned by UMAC */ +	u16 aid; + +	/* STA entry Type: 0 - Self, 1 - Other/Peer, 2 - BSSID, 3 - BCAST */ +	u8 type; + +	/* Short Preamble Supported. */ +	u8 short_preamble_supported; + +	/* MAC Address of STA */ +	u8 mac[ETH_ALEN]; + +	/* Listen interval of the STA */ +	u16 listen_interval; + +	/* Support for 11e/WMM */ +	u8 wmm_enabled; + +	/* 11n HT capable STA */ +	u8 ht_capable; + +	/* TX Width Set: 0 - 20 MHz only, 1 - 20/40 MHz */ +	u8 tx_channel_width_set; + +	/* RIFS mode 0 - NA, 1 - Allowed */ +	u8 rifs_mode; + +	/* L-SIG TXOP Protection mechanism +	   0 - No Support, 1 - Supported +	   SG - there is global field */ +	u8 lsig_txop_protection; + +	/* Max Ampdu Size supported by STA. TPE programming. +	   0 : 8k , 1 : 16k, 2 : 32k, 3 : 64k */ +	u8 max_ampdu_size; + +	/* Max Ampdu density. Used by RA.  3 : 0~7 : 2^(11nAMPDUdensity -4) */ +	u8 max_ampdu_density; + +	/* Max AMSDU size 1 : 3839 bytes, 0 : 7935 bytes */ +	u8 max_amsdu_size; + +	/* Short GI support for 40Mhz packets */ +	u8 sgi_40mhz; + +	/* Short GI support for 20Mhz packets */ +	u8 sgi_20Mhz; + +	/* Robust Management Frame (RMF) enabled/disabled */ +	u8 rmf; + +	/* The unicast encryption type in the association */ +	u32 encrypt_type; + +	/* HAL should update the existing STA entry, if this flag is set. UMAC +	   will set this flag in case of RE-ASSOC, where we want to reuse the +	   old STA ID. 0 = Add, 1 = Update */ +	u8 action; + +	/* U-APSD Flags: 1b per AC.  Encoded as follows: +	   b7 b6 b5 b4 b3 b2 b1 b0 = +	   X  X  X  X  BE BK VI VO */ +	u8 uapsd; + +	/* Max SP Length */ +	u8 max_sp_len; + +	/* 11n Green Field preamble support +	   0 - Not supported, 1 - Supported */ +	u8 green_field_capable; + +	/* MIMO Power Save mode */ +	enum wcn36xx_hal_ht_mimo_state mimo_ps; + +	/* Delayed BA Support */ +	u8 delayed_ba_support; + +	/* Max AMPDU duration in 32us */ +	u8 max_ampdu_duration; + +	/* HT STA should set it to 1 if it is enabled in BSS. HT STA should +	 * set it to 0 if AP does not support it. This indication is sent +	 * to HAL and HAL uses this flag to pickup up appropriate 40Mhz +	 * rates. */ +	u8 dsss_cck_mode_40mhz; + +	/* Valid STA Idx when action=Update. Set to 0xFF when invalid! +	 * Retained for backward compalibity with existing HAL code */ +	u8 sta_index; + +	/* BSSID of BSS to which station is associated. Set to 0xFF when +	 * invalid. Retained for backward compalibity with existing HAL +	 * code */ +	u8 bssid_index; + +	u8 p2p; + +	/* Reserved to align next field on a dword boundary */ +	u8 reserved; + +	/* These rates are the intersection of peer and self capabilities. */ +	struct wcn36xx_hal_supported_rates supported_rates; +} __packed; + +struct wcn36xx_hal_config_sta_req_msg_v1 { +	struct wcn36xx_hal_msg_header header; +	struct wcn36xx_hal_config_sta_params_v1 sta_params; +} __packed; + +struct config_sta_rsp_params { +	/* success or failure */ +	u32 status; + +	/* Station index; valid only when 'status' field value SUCCESS */ +	u8 sta_index; + +	/* BSSID Index of BSS to which the station is associated */ +	u8 bssid_index; + +	/* DPU Index for PTK */ +	u8 dpu_index; + +	/* DPU Index for GTK */ +	u8 bcast_dpu_index; + +	/* DPU Index for IGTK  */ +	u8 bcast_mgmt_dpu_idx; + +	/* PTK DPU signature */ +	u8 uc_ucast_sig; + +	/* GTK DPU isignature */ +	u8 uc_bcast_sig; + +	/* IGTK DPU signature */ +	u8 uc_mgmt_sig; + +	u8 p2p; + +} __packed; + +struct wcn36xx_hal_config_sta_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	struct config_sta_rsp_params params; +} __packed; + +/* Delete STA Request message */ +struct wcn36xx_hal_delete_sta_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Index of STA to delete */ +	u8 sta_index; + +} __packed; + +/* Delete STA Response message */ +struct wcn36xx_hal_delete_sta_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; + +	/* Index of STA deleted */ +	u8 sta_id; +} __packed; + +/* 12 Bytes long because this structure can be used to represent rate and + * extended rate set IEs. The parser assume this to be at least 12 */ +struct wcn36xx_hal_rate_set { +	u8 num_rates; +	u8 rate[WCN36XX_HAL_MAC_RATESET_EID_MAX]; +} __packed; + +/* access category record */ +struct wcn36xx_hal_aci_aifsn { +#ifndef ANI_LITTLE_BIT_ENDIAN +	u8 rsvd:1; +	u8 aci:2; +	u8 acm:1; +	u8 aifsn:4; +#else +	u8 aifsn:4; +	u8 acm:1; +	u8 aci:2; +	u8 rsvd:1; +#endif +} __packed; + +/* contention window size */ +struct wcn36xx_hal_mac_cw { +#ifndef ANI_LITTLE_BIT_ENDIAN +	u8 max:4; +	u8 min:4; +#else +	u8 min:4; +	u8 max:4; +#endif +} __packed; + +struct wcn36xx_hal_edca_param_record { +	struct wcn36xx_hal_aci_aifsn aci; +	struct wcn36xx_hal_mac_cw cw; +	u16 txop_limit; +} __packed; + +struct wcn36xx_hal_mac_ssid { +	u8 length; +	u8 ssid[32]; +} __packed; + +/* Concurrency role. These are generic IDs that identify the various roles + *  in the software system. */ +enum wcn36xx_hal_con_mode { +	WCN36XX_HAL_STA_MODE = 0, + +	/* to support softAp mode . This is misleading. +	   It means AP MODE only. */ +	WCN36XX_HAL_STA_SAP_MODE = 1, + +	WCN36XX_HAL_P2P_CLIENT_MODE, +	WCN36XX_HAL_P2P_GO_MODE, +	WCN36XX_HAL_MONITOR_MODE, +}; + +/* This is a bit pattern to be set for each mode + * bit 0 - sta mode + * bit 1 - ap mode + * bit 2 - p2p client mode + * bit 3 - p2p go mode */ +enum wcn36xx_hal_concurrency_mode { +	HAL_STA = 1, +	HAL_SAP = 2, + +	/* to support sta, softAp  mode . This means STA+AP mode */ +	HAL_STA_SAP = 3, + +	HAL_P2P_CLIENT = 4, +	HAL_P2P_GO = 8, +	HAL_MAX_CONCURRENCY_PERSONA = 4 +}; + +struct wcn36xx_hal_config_bss_params { +	/* BSSID */ +	u8 bssid[ETH_ALEN]; + +	/* Self Mac Address */ +	u8 self_mac_addr[ETH_ALEN]; + +	/* BSS type */ +	enum wcn36xx_hal_bss_type bss_type; + +	/* Operational Mode: AP =0, STA = 1 */ +	u8 oper_mode; + +	/* Network Type */ +	enum wcn36xx_hal_nw_type nw_type; + +	/* Used to classify PURE_11G/11G_MIXED to program MTU */ +	u8 short_slot_time_supported; + +	/* Co-exist with 11a STA */ +	u8 lla_coexist; + +	/* Co-exist with 11b STA */ +	u8 llb_coexist; + +	/* Co-exist with 11g STA */ +	u8 llg_coexist; + +	/* Coexistence with 11n STA */ +	u8 ht20_coexist; + +	/* Non GF coexist flag */ +	u8 lln_non_gf_coexist; + +	/* TXOP protection support */ +	u8 lsig_tx_op_protection_full_support; + +	/* RIFS mode */ +	u8 rifs_mode; + +	/* Beacon Interval in TU */ +	u16 beacon_interval; + +	/* DTIM period */ +	u8 dtim_period; + +	/* TX Width Set: 0 - 20 MHz only, 1 - 20/40 MHz */ +	u8 tx_channel_width_set; + +	/* Operating channel */ +	u8 oper_channel; + +	/* Extension channel for channel bonding */ +	u8 ext_channel; + +	/* Reserved to align next field on a dword boundary */ +	u8 reserved; + +	/* TODO move sta to the end for 3680 */ +	/* Context of the station being added in HW +	 *  Add a STA entry for "itself" - +	 * +	 *  On AP  - Add the AP itself in an "STA context" +	 * +	 *  On STA - Add the AP to which this STA is joining in an +	 *  "STA context" +	 */ +	struct wcn36xx_hal_config_sta_params sta; +	/* SSID of the BSS */ +	struct wcn36xx_hal_mac_ssid ssid; + +	/* HAL should update the existing BSS entry, if this flag is set. +	 * UMAC will set this flag in case of reassoc, where we want to +	 * resue the the old BSSID and still return success 0 = Add, 1 = +	 * Update */ +	u8 action; + +	/* MAC Rate Set */ +	struct wcn36xx_hal_rate_set rateset; + +	/* Enable/Disable HT capabilities of the BSS */ +	u8 ht; + +	/* Enable/Disable OBSS protection */ +	u8 obss_prot_enabled; + +	/* RMF enabled/disabled */ +	u8 rmf; + +	/* HT Operating Mode operating mode of the 802.11n STA */ +	enum wcn36xx_hal_ht_operating_mode ht_oper_mode; + +	/* Dual CTS Protection: 0 - Unused, 1 - Used */ +	u8 dual_cts_protection; + +	/* Probe Response Max retries */ +	u8 max_probe_resp_retry_limit; + +	/* To Enable Hidden ssid */ +	u8 hidden_ssid; + +	/* To Enable Disable FW Proxy Probe Resp */ +	u8 proxy_probe_resp; + +	/* Boolean to indicate if EDCA params are valid. UMAC might not +	 * have valid EDCA params or might not desire to apply EDCA params +	 * during config BSS. 0 implies Not Valid ; Non-Zero implies +	 * valid */ +	u8 edca_params_valid; + +	/* EDCA Parameters for Best Effort Access Category */ +	struct wcn36xx_hal_edca_param_record acbe; + +	/* EDCA Parameters forBackground Access Category */ +	struct wcn36xx_hal_edca_param_record acbk; + +	/* EDCA Parameters for Video Access Category */ +	struct wcn36xx_hal_edca_param_record acvi; + +	/* EDCA Parameters for Voice Access Category */ +	struct wcn36xx_hal_edca_param_record acvo; + +	/* Ext Bss Config Msg if set */ +	u8 ext_set_sta_key_param_valid; + +	/* SetStaKeyParams for ext bss msg */ +	struct wcn36xx_hal_set_sta_key_params ext_set_sta_key_param; + +	/* Persona for the BSS can be STA,AP,GO,CLIENT value same as enum +	 * wcn36xx_hal_con_mode */ +	u8 wcn36xx_hal_persona; + +	u8 spectrum_mgt_enable; + +	/* HAL fills in the tx power used for mgmt frames in txMgmtPower */ +	s8 tx_mgmt_power; + +	/* maxTxPower has max power to be used after applying the power +	 * constraint if any */ +	s8 max_tx_power; +} __packed; + +struct wcn36xx_hal_config_bss_req_msg { +	struct wcn36xx_hal_msg_header header; +	struct wcn36xx_hal_config_bss_params bss_params; +} __packed; + +struct wcn36xx_hal_config_bss_params_v1 { +	/* BSSID */ +	u8 bssid[ETH_ALEN]; + +	/* Self Mac Address */ +	u8 self_mac_addr[ETH_ALEN]; + +	/* BSS type */ +	enum wcn36xx_hal_bss_type bss_type; + +	/* Operational Mode: AP =0, STA = 1 */ +	u8 oper_mode; + +	/* Network Type */ +	enum wcn36xx_hal_nw_type nw_type; + +	/* Used to classify PURE_11G/11G_MIXED to program MTU */ +	u8 short_slot_time_supported; + +	/* Co-exist with 11a STA */ +	u8 lla_coexist; + +	/* Co-exist with 11b STA */ +	u8 llb_coexist; + +	/* Co-exist with 11g STA */ +	u8 llg_coexist; + +	/* Coexistence with 11n STA */ +	u8 ht20_coexist; + +	/* Non GF coexist flag */ +	u8 lln_non_gf_coexist; + +	/* TXOP protection support */ +	u8 lsig_tx_op_protection_full_support; + +	/* RIFS mode */ +	u8 rifs_mode; + +	/* Beacon Interval in TU */ +	u16 beacon_interval; + +	/* DTIM period */ +	u8 dtim_period; + +	/* TX Width Set: 0 - 20 MHz only, 1 - 20/40 MHz */ +	u8 tx_channel_width_set; + +	/* Operating channel */ +	u8 oper_channel; + +	/* Extension channel for channel bonding */ +	u8 ext_channel; + +	/* Reserved to align next field on a dword boundary */ +	u8 reserved; + +	/* SSID of the BSS */ +	struct wcn36xx_hal_mac_ssid ssid; + +	/* HAL should update the existing BSS entry, if this flag is set. +	 * UMAC will set this flag in case of reassoc, where we want to +	 * resue the the old BSSID and still return success 0 = Add, 1 = +	 * Update */ +	u8 action; + +	/* MAC Rate Set */ +	struct wcn36xx_hal_rate_set rateset; + +	/* Enable/Disable HT capabilities of the BSS */ +	u8 ht; + +	/* Enable/Disable OBSS protection */ +	u8 obss_prot_enabled; + +	/* RMF enabled/disabled */ +	u8 rmf; + +	/* HT Operating Mode operating mode of the 802.11n STA */ +	enum wcn36xx_hal_ht_operating_mode ht_oper_mode; + +	/* Dual CTS Protection: 0 - Unused, 1 - Used */ +	u8 dual_cts_protection; + +	/* Probe Response Max retries */ +	u8 max_probe_resp_retry_limit; + +	/* To Enable Hidden ssid */ +	u8 hidden_ssid; + +	/* To Enable Disable FW Proxy Probe Resp */ +	u8 proxy_probe_resp; + +	/* Boolean to indicate if EDCA params are valid. UMAC might not +	 * have valid EDCA params or might not desire to apply EDCA params +	 * during config BSS. 0 implies Not Valid ; Non-Zero implies +	 * valid */ +	u8 edca_params_valid; + +	/* EDCA Parameters for Best Effort Access Category */ +	struct wcn36xx_hal_edca_param_record acbe; + +	/* EDCA Parameters forBackground Access Category */ +	struct wcn36xx_hal_edca_param_record acbk; + +	/* EDCA Parameters for Video Access Category */ +	struct wcn36xx_hal_edca_param_record acvi; + +	/* EDCA Parameters for Voice Access Category */ +	struct wcn36xx_hal_edca_param_record acvo; + +	/* Ext Bss Config Msg if set */ +	u8 ext_set_sta_key_param_valid; + +	/* SetStaKeyParams for ext bss msg */ +	struct wcn36xx_hal_set_sta_key_params ext_set_sta_key_param; + +	/* Persona for the BSS can be STA,AP,GO,CLIENT value same as enum +	 * wcn36xx_hal_con_mode */ +	u8 wcn36xx_hal_persona; + +	u8 spectrum_mgt_enable; + +	/* HAL fills in the tx power used for mgmt frames in txMgmtPower */ +	s8 tx_mgmt_power; + +	/* maxTxPower has max power to be used after applying the power +	 * constraint if any */ +	s8 max_tx_power; + +	/* Context of the station being added in HW +	 *  Add a STA entry for "itself" - +	 * +	 *  On AP  - Add the AP itself in an "STA context" +	 * +	 *  On STA - Add the AP to which this STA is joining in an +	 *  "STA context" +	 */ +	struct wcn36xx_hal_config_sta_params_v1 sta; +} __packed; + +struct wcn36xx_hal_config_bss_req_msg_v1 { +	struct wcn36xx_hal_msg_header header; +	struct wcn36xx_hal_config_bss_params_v1 bss_params; +} __packed; + +struct wcn36xx_hal_config_bss_rsp_params { +	/* Success or Failure */ +	u32 status; + +	/* BSS index allocated by HAL */ +	u8 bss_index; + +	/* DPU descriptor index for PTK */ +	u8 dpu_desc_index; + +	/* PTK DPU signature */ +	u8 ucast_dpu_signature; + +	/* DPU descriptor index for GTK */ +	u8 bcast_dpu_desc_indx; + +	/* GTK DPU signature */ +	u8 bcast_dpu_signature; + +	/* DPU descriptor for IGTK */ +	u8 mgmt_dpu_desc_index; + +	/* IGTK DPU signature */ +	u8 mgmt_dpu_signature; + +	/* Station Index for BSS entry */ +	u8 bss_sta_index; + +	/* Self station index for this BSS */ +	u8 bss_self_sta_index; + +	/* Bcast station for buffering bcast frames in AP role */ +	u8 bss_bcast_sta_idx; + +	/* MAC Address of STA(PEER/SELF) in staContext of configBSSReq */ +	u8 mac[ETH_ALEN]; + +	/* HAL fills in the tx power used for mgmt frames in this field. */ +	s8 tx_mgmt_power; + +} __packed; + +struct wcn36xx_hal_config_bss_rsp_msg { +	struct wcn36xx_hal_msg_header header; +	struct wcn36xx_hal_config_bss_rsp_params bss_rsp_params; +} __packed; + +struct wcn36xx_hal_delete_bss_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* BSS index to be deleted */ +	u8 bss_index; + +} __packed; + +struct wcn36xx_hal_delete_bss_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Success or Failure */ +	u32 status; + +	/* BSS index that has been deleted */ +	u8 bss_index; + +} __packed; + +struct wcn36xx_hal_join_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Indicates the BSSID to which STA is going to associate */ +	u8 bssid[ETH_ALEN]; + +	/* Indicates the channel to switch to. */ +	u8 channel; + +	/* Self STA MAC */ +	u8 self_sta_mac_addr[ETH_ALEN]; + +	/* Local power constraint */ +	u8 local_power_constraint; + +	/* Secondary channel offset */ +	enum phy_chan_bond_state secondary_channel_offset; + +	/* link State */ +	enum wcn36xx_hal_link_state link_state; + +	/* Max TX power */ +	s8 max_tx_power; +} __packed; + +struct wcn36xx_hal_join_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; + +	/* HAL fills in the tx power used for mgmt frames in this field */ +	u8 tx_mgmt_power; +} __packed; + +struct post_assoc_req_msg { +	struct wcn36xx_hal_msg_header header; + +	struct wcn36xx_hal_config_sta_params sta_params; +	struct wcn36xx_hal_config_bss_params bss_params; +}; + +struct post_assoc_rsp_msg { +	struct wcn36xx_hal_msg_header header; +	struct config_sta_rsp_params sta_rsp_params; +	struct wcn36xx_hal_config_bss_rsp_params bss_rsp_params; +}; + +/* This is used to create a set of WEP keys for a given BSS. */ +struct wcn36xx_hal_set_bss_key_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* BSS Index of the BSS */ +	u8 bss_idx; + +	/* Encryption Type used with peer */ +	enum ani_ed_type enc_type; + +	/* Number of keys */ +	u8 num_keys; + +	/* Array of keys. */ +	struct wcn36xx_hal_keys keys[WCN36XX_HAL_MAC_MAX_NUM_OF_DEFAULT_KEYS]; + +	/* Control for Replay Count, 1= Single TID based replay count on Tx +	 * 0 = Per TID based replay count on TX */ +	u8 single_tid_rc; +} __packed; + +/* tagged version of set bss key */ +struct wcn36xx_hal_set_bss_key_req_msg_tagged { +	struct wcn36xx_hal_set_bss_key_req_msg Msg; +	u32 tag; +} __packed; + +struct wcn36xx_hal_set_bss_key_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +} __packed; + +/* + * This is used  configure the key information on a given station. + * When the sec_type is WEP40 or WEP104, the def_wep_idx is used to locate + * a preconfigured key from a BSS the station assoicated with; otherwise + * a new key descriptor is created based on the key field. + */ +struct wcn36xx_hal_set_sta_key_req_msg { +	struct wcn36xx_hal_msg_header header; +	struct wcn36xx_hal_set_sta_key_params set_sta_key_params; +} __packed; + +struct wcn36xx_hal_set_sta_key_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +} __packed; + +struct wcn36xx_hal_remove_bss_key_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* BSS Index of the BSS */ +	u8 bss_idx; + +	/* Encryption Type used with peer */ +	enum ani_ed_type enc_type; + +	/* Key Id */ +	u8 key_id; + +	/* STATIC/DYNAMIC. Used in Nullifying in Key Descriptors for +	 * Static/Dynamic keys */ +	enum ani_wep_type wep_type; +} __packed; + +struct wcn36xx_hal_remove_bss_key_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +} __packed; + +/* + * This is used by PE to Remove the key information on a given station. + */ +struct wcn36xx_hal_remove_sta_key_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* STA Index */ +	u16 sta_idx; + +	/* Encryption Type used with peer */ +	enum ani_ed_type enc_type; + +	/* Key Id */ +	u8 key_id; + +	/* Whether to invalidate the Broadcast key or Unicast key. In case +	 * of WEP, the same key is used for both broadcast and unicast. */ +	u8 unicast; + +} __packed; + +struct wcn36xx_hal_remove_sta_key_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/*success or failure */ +	u32 status; + +} __packed; + +#ifdef FEATURE_OEM_DATA_SUPPORT + +#ifndef OEM_DATA_REQ_SIZE +#define OEM_DATA_REQ_SIZE 134 +#endif + +#ifndef OEM_DATA_RSP_SIZE +#define OEM_DATA_RSP_SIZE 1968 +#endif + +struct start_oem_data_req_msg { +	struct wcn36xx_hal_msg_header header; + +	u32 status; +	tSirMacAddr self_mac_addr; +	u8 oem_data_req[OEM_DATA_REQ_SIZE]; + +}; + +struct start_oem_data_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 oem_data_rsp[OEM_DATA_RSP_SIZE]; +}; + +#endif + +struct wcn36xx_hal_switch_channel_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Channel number */ +	u8 channel_number; + +	/* Local power constraint */ +	u8 local_power_constraint; + +	/* Secondary channel offset */ +	enum phy_chan_bond_state secondary_channel_offset; + +	/* HAL fills in the tx power used for mgmt frames in this field. */ +	u8 tx_mgmt_power; + +	/* Max TX power */ +	u8 max_tx_power; + +	/* Self STA MAC */ +	u8 self_sta_mac_addr[ETH_ALEN]; + +	/* VO WIFI comment: BSSID needed to identify session. As the +	 * request has power constraints, this should be applied only to +	 * that session Since MTU timing and EDCA are sessionized, this +	 * struct needs to be sessionized and bssid needs to be out of the +	 * VOWifi feature flag V IMP: Keep bssId field at the end of this +	 * msg. It is used to mantain backward compatbility by way of +	 * ignoring if using new host/old FW or old host/new FW since it is +	 * at the end of this struct +	 */ +	u8 bssid[ETH_ALEN]; +} __packed; + +struct wcn36xx_hal_switch_channel_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Status */ +	u32 status; + +	/* Channel number - same as in request */ +	u8 channel_number; + +	/* HAL fills in the tx power used for mgmt frames in this field */ +	u8 tx_mgmt_power; + +	/* BSSID needed to identify session - same as in request */ +	u8 bssid[ETH_ALEN]; + +} __packed; + +struct update_edca_params_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/*BSS Index */ +	u16 bss_index; + +	/* Best Effort */ +	struct wcn36xx_hal_edca_param_record acbe; + +	/* Background */ +	struct wcn36xx_hal_edca_param_record acbk; + +	/* Video */ +	struct wcn36xx_hal_edca_param_record acvi; + +	/* Voice */ +	struct wcn36xx_hal_edca_param_record acvo; +}; + +struct update_edca_params_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +}; + +struct dpu_stats_params { +	/* Index of STA to which the statistics */ +	u16 sta_index; + +	/* Encryption mode */ +	u8 enc_mode; + +	/* status */ +	u32 status; + +	/* Statistics */ +	u32 send_blocks; +	u32 recv_blocks; +	u32 replays; +	u8 mic_error_cnt; +	u32 prot_excl_cnt; +	u16 format_err_cnt; +	u16 un_decryptable_cnt; +	u32 decrypt_err_cnt; +	u32 decrypt_ok_cnt; +}; + +struct wcn36xx_hal_stats_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Valid STA Idx for per STA stats request */ +	u32 sta_id; + +	/* Categories of stats requested as specified in eHalStatsMask */ +	u32 stats_mask; +}; + +struct ani_summary_stats_info { +	/* Total number of packets(per AC) that were successfully +	 * transmitted with retries */ +	u32 retry_cnt[4]; + +	/* The number of MSDU packets and MMPDU frames per AC that the +	 * 802.11 station successfully transmitted after more than one +	 * retransmission attempt */ +	u32 multiple_retry_cnt[4]; + +	/* Total number of packets(per AC) that were successfully +	 * transmitted (with and without retries, including multi-cast, +	 * broadcast) */ +	u32 tx_frm_cnt[4]; + +	/* Total number of packets that were successfully received (after +	 * appropriate filter rules including multi-cast, broadcast) */ +	u32 rx_frm_cnt; + +	/* Total number of duplicate frames received successfully */ +	u32 frm_dup_cnt; + +	/* Total number packets(per AC) failed to transmit */ +	u32 fail_cnt[4]; + +	/* Total number of RTS/CTS sequence failures for transmission of a +	 * packet */ +	u32 rts_fail_cnt; + +	/* Total number packets failed transmit because of no ACK from the +	 * remote entity */ +	u32 ack_fail_cnt; + +	/* Total number of RTS/CTS sequence success for transmission of a +	 * packet */ +	u32 rts_succ_cnt; + +	/* The sum of the receive error count and dropped-receive-buffer +	 * error count. HAL will provide this as a sum of (FCS error) + +	 * (Fail get BD/PDU in HW) */ +	u32 rx_discard_cnt; + +	/* +	 * The receive error count. HAL will provide the RxP FCS error +	 * global counter. */ +	u32 rx_error_cnt; + +	/* The sum of the transmit-directed byte count, transmit-multicast +	 * byte count and transmit-broadcast byte count. HAL will sum TPE +	 * UC/MC/BCAST global counters to provide this. */ +	u32 tx_byte_cnt; +}; + +/* defines tx_rate_flags */ +enum tx_rate_info { +	/* Legacy rates */ +	HAL_TX_RATE_LEGACY = 0x1, + +	/* HT20 rates */ +	HAL_TX_RATE_HT20 = 0x2, + +	/* HT40 rates */ +	HAL_TX_RATE_HT40 = 0x4, + +	/* Rate with Short guard interval */ +	HAL_TX_RATE_SGI = 0x8, + +	/* Rate with Long guard interval */ +	HAL_TX_RATE_LGI = 0x10 +}; + +struct ani_global_class_a_stats_info { +	/* The number of MPDU frames received by the 802.11 station for +	 * MSDU packets or MMPDU frames */ +	u32 rx_frag_cnt; + +	/* The number of MPDU frames received by the 802.11 station for +	 * MSDU packets or MMPDU frames when a promiscuous packet filter +	 * was enabled */ +	u32 promiscuous_rx_frag_cnt; + +	/* The receiver input sensitivity referenced to a FER of 8% at an +	 * MPDU length of 1024 bytes at the antenna connector. Each element +	 * of the array shall correspond to a supported rate and the order +	 * shall be the same as the supporteRates parameter. */ +	u32 rx_input_sensitivity; + +	/* The maximum transmit power in dBm upto one decimal. for eg: if +	 * it is 10.5dBm, the value would be 105 */ +	u32 max_pwr; + +	/* Number of times the receiver failed to synchronize with the +	 * incoming signal after detecting the sync in the preamble of the +	 * transmitted PLCP protocol data unit. */ +	u32 sync_fail_cnt; + +	/* Legacy transmit rate, in units of 500 kbit/sec, for the most +	 * recently transmitted frame */ +	u32 tx_rate; + +	/* mcs index for HT20 and HT40 rates */ +	u32 mcs_index; + +	/* to differentiate between HT20 and HT40 rates; short and long +	 * guard interval */ +	u32 tx_rate_flags; +}; + +struct ani_global_security_stats { +	/* The number of unencrypted received MPDU frames that the MAC +	 * layer discarded when the IEEE 802.11 dot11ExcludeUnencrypted +	 * management information base (MIB) object is enabled */ +	u32 rx_wep_unencrypted_frm_cnt; + +	/* The number of received MSDU packets that that the 802.11 station +	 * discarded because of MIC failures */ +	u32 rx_mic_fail_cnt; + +	/* The number of encrypted MPDU frames that the 802.11 station +	 * failed to decrypt because of a TKIP ICV error */ +	u32 tkip_icv_err; + +	/* The number of received MPDU frames that the 802.11 discarded +	 * because of an invalid AES-CCMP format */ +	u32 aes_ccmp_format_err; + +	/* The number of received MPDU frames that the 802.11 station +	 * discarded because of the AES-CCMP replay protection procedure */ +	u32 aes_ccmp_replay_cnt; + +	/* The number of received MPDU frames that the 802.11 station +	 * discarded because of errors detected by the AES-CCMP decryption +	 * algorithm */ +	u32 aes_ccmp_decrpt_err; + +	/* The number of encrypted MPDU frames received for which a WEP +	 * decryption key was not available on the 802.11 station */ +	u32 wep_undecryptable_cnt; + +	/* The number of encrypted MPDU frames that the 802.11 station +	 * failed to decrypt because of a WEP ICV error */ +	u32 wep_icv_err; + +	/* The number of received encrypted packets that the 802.11 station +	 * successfully decrypted */ +	u32 rx_decrypt_succ_cnt; + +	/* The number of encrypted packets that the 802.11 station failed +	 * to decrypt */ +	u32 rx_decrypt_fail_cnt; +}; + +struct ani_global_class_b_stats_info { +	struct ani_global_security_stats uc_stats; +	struct ani_global_security_stats mc_bc_stats; +}; + +struct ani_global_class_c_stats_info { +	/* This counter shall be incremented for a received A-MSDU frame +	 * with the stations MAC address in the address 1 field or an +	 * A-MSDU frame with a group address in the address 1 field */ +	u32 rx_amsdu_cnt; + +	/* This counter shall be incremented when the MAC receives an AMPDU +	 * from the PHY */ +	u32 rx_ampdu_cnt; + +	/* This counter shall be incremented when a Frame is transmitted +	 * only on the primary channel */ +	u32 tx_20_frm_cnt; + +	/* This counter shall be incremented when a Frame is received only +	 * on the primary channel */ +	u32 rx_20_frm_cnt; + +	/* This counter shall be incremented by the number of MPDUs +	 * received in the A-MPDU when an A-MPDU is received */ +	u32 rx_mpdu_in_ampdu_cnt; + +	/* This counter shall be incremented when an MPDU delimiter has a +	 * CRC error when this is the first CRC error in the received AMPDU +	 * or when the previous delimiter has been decoded correctly */ +	u32 ampdu_delimiter_crc_err; +}; + +struct ani_per_sta_stats_info { +	/* The number of MPDU frames that the 802.11 station transmitted +	 * and acknowledged through a received 802.11 ACK frame */ +	u32 tx_frag_cnt[4]; + +	/* This counter shall be incremented when an A-MPDU is transmitted */ +	u32 tx_ampdu_cnt; + +	/* This counter shall increment by the number of MPDUs in the AMPDU +	 * when an A-MPDU is transmitted */ +	u32 tx_mpdu_in_ampdu_cnt; +}; + +struct wcn36xx_hal_stats_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Success or Failure */ +	u32 status; + +	/* STA Idx */ +	u32 sta_index; + +	/* Categories of STATS being returned as per eHalStatsMask */ +	u32 stats_mask; + +	/* message type is same as the request type */ +	u16 msg_type; + +	/* length of the entire request, includes the pStatsBuf length too */ +	u16 msg_len; +}; + +struct wcn36xx_hal_set_link_state_req_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 bssid[ETH_ALEN]; +	enum wcn36xx_hal_link_state state; +	u8 self_mac_addr[ETH_ALEN]; + +} __packed; + +struct set_link_state_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +}; + +/* TSPEC Params */ +struct wcn36xx_hal_ts_info_tfc { +#ifndef ANI_LITTLE_BIT_ENDIAN +	u16 ackPolicy:2; +	u16 userPrio:3; +	u16 psb:1; +	u16 aggregation:1; +	u16 accessPolicy:2; +	u16 direction:2; +	u16 tsid:4; +	u16 trafficType:1; +#else +	u16 trafficType:1; +	u16 tsid:4; +	u16 direction:2; +	u16 accessPolicy:2; +	u16 aggregation:1; +	u16 psb:1; +	u16 userPrio:3; +	u16 ackPolicy:2; +#endif +}; + +/* Flag to schedule the traffic type */ +struct wcn36xx_hal_ts_info_sch { +#ifndef ANI_LITTLE_BIT_ENDIAN +	u8 rsvd:7; +	u8 schedule:1; +#else +	u8 schedule:1; +	u8 rsvd:7; +#endif +}; + +/* Traffic and scheduling info */ +struct wcn36xx_hal_ts_info { +	struct wcn36xx_hal_ts_info_tfc traffic; +	struct wcn36xx_hal_ts_info_sch schedule; +}; + +/* Information elements */ +struct wcn36xx_hal_tspec_ie { +	u8 type; +	u8 length; +	struct wcn36xx_hal_ts_info ts_info; +	u16 nom_msdu_size; +	u16 max_msdu_size; +	u32 min_svc_interval; +	u32 max_svc_interval; +	u32 inact_interval; +	u32 suspend_interval; +	u32 svc_start_time; +	u32 min_data_rate; +	u32 mean_data_rate; +	u32 peak_data_rate; +	u32 max_burst_sz; +	u32 delay_bound; +	u32 min_phy_rate; +	u16 surplus_bw; +	u16 medium_time; +}; + +struct add_ts_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Station Index */ +	u16 sta_index; + +	/* TSPEC handler uniquely identifying a TSPEC for a STA in a BSS */ +	u16 tspec_index; + +	/* To program TPE with required parameters */ +	struct wcn36xx_hal_tspec_ie tspec; + +	/* U-APSD Flags: 1b per AC.  Encoded as follows: +	   b7 b6 b5 b4 b3 b2 b1 b0 = +	   X  X  X  X  BE BK VI VO */ +	u8 uapsd; + +	/* These parameters are for all the access categories */ + +	/* Service Interval */ +	u32 service_interval[WCN36XX_HAL_MAX_AC]; + +	/* Suspend Interval */ +	u32 suspend_interval[WCN36XX_HAL_MAX_AC]; + +	/* Delay Interval */ +	u32 delay_interval[WCN36XX_HAL_MAX_AC]; +}; + +struct add_rs_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +}; + +struct del_ts_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Station Index */ +	u16 sta_index; + +	/* TSPEC identifier uniquely identifying a TSPEC for a STA in a BSS */ +	u16 tspec_index; + +	/* To lookup station id using the mac address */ +	u8 bssid[ETH_ALEN]; +}; + +struct del_ts_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +}; + +/* End of TSpec Parameters */ + +/* Start of BLOCK ACK related Parameters */ + +struct wcn36xx_hal_add_ba_session_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Station Index */ +	u16 sta_index; + +	/* Peer MAC Address */ +	u8 mac_addr[ETH_ALEN]; + +	/* ADDBA Action Frame dialog token +	   HAL will not interpret this object */ +	u8 dialog_token; + +	/* TID for which the BA is being setup +	   This identifies the TC or TS of interest */ +	u8 tid; + +	/* 0 - Delayed BA (Not supported) +	   1 - Immediate BA */ +	u8 policy; + +	/* Indicates the number of buffers for this TID (baTID) +	   NOTE - This is the requested buffer size. When this +	   is processed by HAL and subsequently by HDD, it is +	   possible that HDD may change this buffer size. Any +	   change in the buffer size should be noted by PE and +	   advertized appropriately in the ADDBA response */ +	u16 buffer_size; + +	/* BA timeout in TU's 0 means no timeout will occur */ +	u16 timeout; + +	/* b0..b3 - Fragment Number - Always set to 0 +	   b4..b15 - Starting Sequence Number of first MSDU +	   for which this BA is setup */ +	u16 ssn; + +	/* ADDBA direction +	   1 - Originator +	   0 - Recipient */ +	u8 direction; +} __packed; + +struct wcn36xx_hal_add_ba_session_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; + +	/* Dialog token */ +	u8 dialog_token; + +	/* TID for which the BA session has been setup */ +	u8 ba_tid; + +	/* BA Buffer Size allocated for the current BA session */ +	u8 ba_buffer_size; + +	u8 ba_session_id; + +	/* Reordering Window buffer */ +	u8 win_size; + +	/* Station Index to id the sta */ +	u8 sta_index; + +	/* Starting Sequence Number */ +	u16 ssn; +} __packed; + +struct wcn36xx_hal_add_ba_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Session Id */ +	u8 session_id; + +	/* Reorder Window Size */ +	u8 win_size; +/* Old FW 1.2.2.4 does not support this*/ +#ifdef FEATURE_ON_CHIP_REORDERING +	u8 reordering_done_on_chip; +#endif +} __packed; + +struct wcn36xx_hal_add_ba_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; + +	/* Dialog token */ +	u8 dialog_token; +} __packed; + +struct add_ba_info { +	u16 ba_enable:1; +	u16 starting_seq_num:12; +	u16 reserved:3; +}; + +struct wcn36xx_hal_trigger_ba_rsp_candidate { +	u8 sta_addr[ETH_ALEN]; +	struct add_ba_info ba_info[STACFG_MAX_TC]; +} __packed; + +struct wcn36xx_hal_trigger_ba_req_candidate { +	u8 sta_index; +	u8 tid_bitmap; +} __packed; + +struct wcn36xx_hal_trigger_ba_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Session Id */ +	u8 session_id; + +	/* baCandidateCnt is followed by trigger BA +	 * Candidate List(tTriggerBaCandidate) +	 */ +	u16 candidate_cnt; + +} __packed; + +struct wcn36xx_hal_trigger_ba_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* TO SUPPORT BT-AMP */ +	u8 bssid[ETH_ALEN]; + +	/* success or failure */ +	u32 status; + +	/* baCandidateCnt is followed by trigger BA +	 * Rsp Candidate List(tTriggerRspBaCandidate) +	 */ +	u16 candidate_cnt; +} __packed; + +struct wcn36xx_hal_del_ba_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Station Index */ +	u16 sta_index; + +	/* TID for which the BA session is being deleted */ +	u8 tid; + +	/* DELBA direction +	   1 - Originator +	   0 - Recipient */ +	u8 direction; +} __packed; + +struct wcn36xx_hal_del_ba_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +} __packed; + +struct tsm_stats_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Traffic Id */ +	u8 tid; + +	u8 bssid[ETH_ALEN]; +}; + +struct tsm_stats_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/*success or failure */ +	u32 status; + +	/* Uplink Packet Queue delay */ +	u16 uplink_pkt_queue_delay; + +	/* Uplink Packet Queue delay histogram */ +	u16 uplink_pkt_queue_delay_hist[4]; + +	/* Uplink Packet Transmit delay */ +	u32 uplink_pkt_tx_delay; + +	/* Uplink Packet loss */ +	u16 uplink_pkt_loss; + +	/* Uplink Packet count */ +	u16 uplink_pkt_count; + +	/* Roaming count */ +	u8 roaming_count; + +	/* Roaming Delay */ +	u16 roaming_delay; +}; + +struct set_key_done_msg { +	struct wcn36xx_hal_msg_header header; + +	/*bssid of the keys */ +	u8 bssidx; +	u8 enc_type; +}; + +struct wcn36xx_hal_nv_img_download_req_msg { +	/* Note: The length specified in wcn36xx_hal_nv_img_download_req_msg +	 * messages should be +	 * header.len = sizeof(wcn36xx_hal_nv_img_download_req_msg) + +	 * nv_img_buffer_size */ +	struct wcn36xx_hal_msg_header header; + +	/* Fragment sequence number of the NV Image. Note that NV Image +	 * might not fit into one message due to size limitation of the SMD +	 * channel FIFO. UMAC can hence choose to chop the NV blob into +	 * multiple fragments starting with seqeunce number 0, 1, 2 etc. +	 * The last fragment MUST be indicated by marking the +	 * isLastFragment field to 1. Note that all the NV blobs would be +	 * concatenated together by HAL without any padding bytes in +	 * between.*/ +	u16 frag_number; + +	/* Is this the last fragment? When set to 1 it indicates that no +	 * more fragments will be sent by UMAC and HAL can concatenate all +	 * the NV blobs rcvd & proceed with the parsing. HAL would generate +	 * a WCN36XX_HAL_DOWNLOAD_NV_RSP to the WCN36XX_HAL_DOWNLOAD_NV_REQ +	 * after it receives each fragment */ +	u16 last_fragment; + +	/* NV Image size (number of bytes) */ +	u32 nv_img_buffer_size; + +	/* Following the 'nv_img_buffer_size', there should be +	 * nv_img_buffer_size bytes of NV Image i.e. +	 * u8[nv_img_buffer_size] */ +} __packed; + +struct wcn36xx_hal_nv_img_download_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Success or Failure. HAL would generate a +	 * WCN36XX_HAL_DOWNLOAD_NV_RSP after each fragment */ +	u32 status; +} __packed; + +struct wcn36xx_hal_nv_store_ind { +	/* Note: The length specified in tHalNvStoreInd messages should be +	 * header.msgLen = sizeof(tHalNvStoreInd) + nvBlobSize */ +	struct wcn36xx_hal_msg_header header; + +	/* NV Item */ +	u32 table_id; + +	/* Size of NV Blob */ +	u32 nv_blob_size; + +	/* Following the 'nvBlobSize', there should be nvBlobSize bytes of +	 * NV blob i.e. u8[nvBlobSize] */ +}; + +/* End of Block Ack Related Parameters */ + +#define WCN36XX_HAL_CIPHER_SEQ_CTR_SIZE 6 + +/* Definition for MIC failure indication MAC reports this each time a MIC + * failure occures on Rx TKIP packet + */ +struct mic_failure_ind_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 bssid[ETH_ALEN]; + +	/* address used to compute MIC */ +	u8 src_addr[ETH_ALEN]; + +	/* transmitter address */ +	u8 ta_addr[ETH_ALEN]; + +	u8 dst_addr[ETH_ALEN]; + +	u8 multicast; + +	/* first byte of IV */ +	u8 iv1; + +	/* second byte of IV */ +	u8 key_id; + +	/* sequence number */ +	u8 tsc[WCN36XX_HAL_CIPHER_SEQ_CTR_SIZE]; + +	/* receive address */ +	u8 rx_addr[ETH_ALEN]; +}; + +struct update_vht_op_mode_req_msg { +	struct wcn36xx_hal_msg_header header; + +	u16 op_mode; +	u16 sta_id; +}; + +struct update_vht_op_mode_params_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	u32 status; +}; + +struct update_beacon_req_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 bss_index; + +	/* shortPreamble mode. HAL should update all the STA rates when it +	 * receives this message */ +	u8 short_preamble; + +	/* short Slot time. */ +	u8 short_slot_time; + +	/* Beacon Interval */ +	u16 beacon_interval; + +	/* Protection related */ +	u8 lla_coexist; +	u8 llb_coexist; +	u8 llg_coexist; +	u8 ht20_coexist; +	u8 lln_non_gf_coexist; +	u8 lsig_tx_op_protection_full_support; +	u8 rifs_mode; + +	u16 param_change_bitmap; +}; + +struct update_beacon_rsp_msg { +	struct wcn36xx_hal_msg_header header; +	u32 status; +}; + +struct wcn36xx_hal_send_beacon_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* length of the template. */ +	u32 beacon_length; + +	/* Beacon data. */ +	u8 beacon[BEACON_TEMPLATE_SIZE]; + +	u8 bssid[ETH_ALEN]; + +	/* TIM IE offset from the beginning of the template. */ +	u32 tim_ie_offset; + +	/* P2P IE offset from the begining of the template */ +	u16 p2p_ie_offset; +} __packed; + +struct send_beacon_rsp_msg { +	struct wcn36xx_hal_msg_header header; +	u32 status; +} __packed; + +struct enable_radar_req_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 bssid[ETH_ALEN]; +	u8 channel; +}; + +struct enable_radar_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Link Parameters */ +	u8 bssid[ETH_ALEN]; + +	/* success or failure */ +	u32 status; +}; + +struct radar_detect_intr_ind_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 radar_det_channel; +}; + +struct radar_detect_ind_msg { +	struct wcn36xx_hal_msg_header header; + +	/* channel number in which the RADAR detected */ +	u8 channel_number; + +	/* RADAR pulse width in usecond */ +	u16 radar_pulse_width; + +	/* Number of RADAR pulses */ +	u16 num_radar_pulse; +}; + +struct wcn36xx_hal_get_tpc_report_req_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 sta[ETH_ALEN]; +	u8 dialog_token; +	u8 txpower; +}; + +struct wcn36xx_hal_get_tpc_report_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +}; + +struct wcn36xx_hal_send_probe_resp_req_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 probe_resp_template[BEACON_TEMPLATE_SIZE]; +	u32 probe_resp_template_len; +	u32 proxy_probe_req_valid_ie_bmap[8]; +	u8 bssid[ETH_ALEN]; +}; + +struct send_probe_resp_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +}; + +struct send_unknown_frame_rx_ind_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +}; + +struct wcn36xx_hal_delete_sta_context_ind_msg { +	struct wcn36xx_hal_msg_header header; + +	u16 aid; +	u16 sta_id; + +	/* TO SUPPORT BT-AMP */ +	u8 bssid[ETH_ALEN]; + +	/* HAL copies bssid from the sta table. */ +	u8 addr2[ETH_ALEN]; + +	/* To unify the keepalive / unknown A2 / tim-based disa */ +	u16 reason_code; +} __packed; + +struct indicate_del_sta { +	struct wcn36xx_hal_msg_header header; +	u8 aid; +	u8 sta_index; +	u8 bss_index; +	u8 reason_code; +	u32 status; +}; + +struct bt_amp_event_msg { +	struct wcn36xx_hal_msg_header header; + +	enum bt_amp_event_type btAmpEventType; +}; + +struct bt_amp_event_rsp { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +}; + +struct tl_hal_flush_ac_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Station Index. originates from HAL */ +	u8 sta_id; + +	/* TID for which the transmit queue is being flushed */ +	u8 tid; +}; + +struct tl_hal_flush_ac_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Station Index. originates from HAL */ +	u8 sta_id; + +	/* TID for which the transmit queue is being flushed */ +	u8 tid; + +	/* success or failure */ +	u32 status; +}; + +struct wcn36xx_hal_enter_imps_req_msg { +	struct wcn36xx_hal_msg_header header; +}; + +struct wcn36xx_hal_exit_imps_req { +	struct wcn36xx_hal_msg_header header; +}; + +struct wcn36xx_hal_enter_bmps_req_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 bss_index; + +	/* TBTT value derived from the last beacon */ +#ifndef BUILD_QWPTTSTATIC +	u64 tbtt; +#endif +	u8 dtim_count; + +	/* DTIM period given to HAL during association may not be valid, if +	 * association is based on ProbeRsp instead of beacon. */ +	u8 dtim_period; + +	/* For CCX and 11R Roaming */ +	u32 rssi_filter_period; + +	u32 num_beacon_per_rssi_average; +	u8 rssi_filter_enable; +} __packed; + +struct wcn36xx_hal_exit_bmps_req_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 send_data_null; +	u8 bss_index; +} __packed; + +struct wcn36xx_hal_missed_beacon_ind_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 bss_index; +} __packed; + +/* Beacon Filtering data structures */ + +/* The above structure would be followed by multiple of below mentioned + * structure + */ +struct beacon_filter_ie { +	u8 element_id; +	u8 check_ie_presence; +	u8 offset; +	u8 value; +	u8 bitmask; +	u8 ref; +}; + +struct wcn36xx_hal_add_bcn_filter_req_msg { +	struct wcn36xx_hal_msg_header header; + +	u16 capability_info; +	u16 capability_mask; +	u16 beacon_interval; +	u16 ie_num; +	u8 bss_index; +	u8 reserved; +}; + +struct wcn36xx_hal_rem_bcn_filter_req { +	struct wcn36xx_hal_msg_header header; + +	u8 ie_Count; +	u8 rem_ie_id[1]; +}; + +#define WCN36XX_HAL_IPV4_ARP_REPLY_OFFLOAD                  0 +#define WCN36XX_HAL_IPV6_NEIGHBOR_DISCOVERY_OFFLOAD         1 +#define WCN36XX_HAL_IPV6_NS_OFFLOAD                         2 +#define WCN36XX_HAL_IPV6_ADDR_LEN                           16 +#define WCN36XX_HAL_OFFLOAD_DISABLE                         0 +#define WCN36XX_HAL_OFFLOAD_ENABLE                          1 +#define WCN36XX_HAL_OFFLOAD_BCAST_FILTER_ENABLE             0x2 +#define WCN36XX_HAL_OFFLOAD_ARP_AND_BCAST_FILTER_ENABLE	\ +	(HAL_OFFLOAD_ENABLE|HAL_OFFLOAD_BCAST_FILTER_ENABLE) + +struct wcn36xx_hal_ns_offload_params { +	u8 src_ipv6_addr[WCN36XX_HAL_IPV6_ADDR_LEN]; +	u8 self_ipv6_addr[WCN36XX_HAL_IPV6_ADDR_LEN]; + +	/* Only support 2 possible Network Advertisement IPv6 address */ +	u8 target_ipv6_addr1[WCN36XX_HAL_IPV6_ADDR_LEN]; +	u8 target_ipv6_addr2[WCN36XX_HAL_IPV6_ADDR_LEN]; + +	u8 self_addr[ETH_ALEN]; +	u8 src_ipv6_addr_valid:1; +	u8 target_ipv6_addr1_valid:1; +	u8 target_ipv6_addr2_valid:1; +	u8 reserved1:5; + +	/* make it DWORD aligned */ +	u8 reserved2; + +	/* slot index for this offload */ +	u32 slot_index; +	u8 bss_index; +}; + +struct wcn36xx_hal_host_offload_req { +	u8 offload_Type; + +	/* enable or disable */ +	u8 enable; + +	union { +		u8 host_ipv4_addr[4]; +		u8 host_ipv6_addr[WCN36XX_HAL_IPV6_ADDR_LEN]; +	} u; +}; + +struct wcn36xx_hal_host_offload_req_msg { +	struct wcn36xx_hal_msg_header header; +	struct wcn36xx_hal_host_offload_req host_offload_params; +	struct wcn36xx_hal_ns_offload_params ns_offload_params; +}; + +/* Packet Types. */ +#define WCN36XX_HAL_KEEP_ALIVE_NULL_PKT              1 +#define WCN36XX_HAL_KEEP_ALIVE_UNSOLICIT_ARP_RSP     2 + +/* Enable or disable keep alive */ +#define WCN36XX_HAL_KEEP_ALIVE_DISABLE   0 +#define WCN36XX_HAL_KEEP_ALIVE_ENABLE    1 +#define WCN36XX_KEEP_ALIVE_TIME_PERIOD	 30 /* unit: s */ + +/* Keep Alive request. */ +struct wcn36xx_hal_keep_alive_req_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 packet_type; +	u32 time_period; +	u8 host_ipv4_addr[WCN36XX_HAL_IPV4_ADDR_LEN]; +	u8 dest_ipv4_addr[WCN36XX_HAL_IPV4_ADDR_LEN]; +	u8 dest_addr[ETH_ALEN]; +	u8 bss_index; +} __packed; + +struct wcn36xx_hal_rssi_threshold_req_msg { +	struct wcn36xx_hal_msg_header header; + +	s8 threshold1:8; +	s8 threshold2:8; +	s8 threshold3:8; +	u8 thres1_pos_notify:1; +	u8 thres1_neg_notify:1; +	u8 thres2_pos_notify:1; +	u8 thres2_neg_notify:1; +	u8 thres3_pos_notify:1; +	u8 thres3_neg_notify:1; +	u8 reserved10:2; +}; + +struct wcn36xx_hal_enter_uapsd_req_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 bk_delivery:1; +	u8 be_delivery:1; +	u8 vi_delivery:1; +	u8 vo_delivery:1; +	u8 bk_trigger:1; +	u8 be_trigger:1; +	u8 vi_trigger:1; +	u8 vo_trigger:1; +	u8 bss_index; +}; + +struct wcn36xx_hal_exit_uapsd_req_msg { +	struct wcn36xx_hal_msg_header header; +	u8 bss_index; +}; + +#define WCN36XX_HAL_WOWL_BCAST_PATTERN_MAX_SIZE 128 +#define WCN36XX_HAL_WOWL_BCAST_MAX_NUM_PATTERNS 16 + +struct wcn36xx_hal_wowl_add_bcast_ptrn_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Pattern ID */ +	u8 id; + +	/* Pattern byte offset from beginning of the 802.11 packet to start +	 * of the wake-up pattern */ +	u8 byte_Offset; + +	/* Non-Zero Pattern size */ +	u8 size; + +	/* Pattern */ +	u8 pattern[WCN36XX_HAL_WOWL_BCAST_PATTERN_MAX_SIZE]; + +	/* Non-zero pattern mask size */ +	u8 mask_size; + +	/* Pattern mask */ +	u8 mask[WCN36XX_HAL_WOWL_BCAST_PATTERN_MAX_SIZE]; + +	/* Extra pattern */ +	u8 extra[WCN36XX_HAL_WOWL_BCAST_PATTERN_MAX_SIZE]; + +	/* Extra pattern mask */ +	u8 mask_extra[WCN36XX_HAL_WOWL_BCAST_PATTERN_MAX_SIZE]; + +	u8 bss_index; +}; + +struct wcn36xx_hal_wow_del_bcast_ptrn_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Pattern ID of the wakeup pattern to be deleted */ +	u8 id; +	u8 bss_index; +}; + +struct wcn36xx_hal_wowl_enter_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Enables/disables magic packet filtering */ +	u8 magic_packet_enable; + +	/* Magic pattern */ +	u8 magic_pattern[ETH_ALEN]; + +	/* Enables/disables packet pattern filtering in firmware. Enabling +	 * this flag enables broadcast pattern matching in Firmware. If +	 * unicast pattern matching is also desired, +	 * ucUcastPatternFilteringEnable flag must be set tot true as well +	 */ +	u8 pattern_filtering_enable; + +	/* Enables/disables unicast packet pattern filtering. This flag +	 * specifies whether we want to do pattern match on unicast packets +	 * as well and not just broadcast packets. This flag has no effect +	 * if the ucPatternFilteringEnable (main controlling flag) is set +	 * to false +	 */ +	u8 ucast_pattern_filtering_enable; + +	/* This configuration is valid only when magicPktEnable=1. It +	 * requests hardware to wake up when it receives the Channel Switch +	 * Action Frame. +	 */ +	u8 wow_channel_switch_receive; + +	/* This configuration is valid only when magicPktEnable=1. It +	 * requests hardware to wake up when it receives the +	 * Deauthentication Frame. +	 */ +	u8 wow_deauth_receive; + +	/* This configuration is valid only when magicPktEnable=1. It +	 * requests hardware to wake up when it receives the Disassociation +	 * Frame. +	 */ +	u8 wow_disassoc_receive; + +	/* This configuration is valid only when magicPktEnable=1. It +	 * requests hardware to wake up when it has missed consecutive +	 * beacons. This is a hardware register configuration (NOT a +	 * firmware configuration). +	 */ +	u8 wow_max_missed_beacons; + +	/* This configuration is valid only when magicPktEnable=1. This is +	 * a timeout value in units of microsec. It requests hardware to +	 * unconditionally wake up after it has stayed in WoWLAN mode for +	 * some time. Set 0 to disable this feature. +	 */ +	u8 wow_max_sleep; + +	/* This configuration directs the WoW packet filtering to look for +	 * EAP-ID requests embedded in EAPOL frames and use this as a wake +	 * source. +	 */ +	u8 wow_eap_id_request_enable; + +	/* This configuration directs the WoW packet filtering to look for +	 * EAPOL-4WAY requests and use this as a wake source. +	 */ +	u8 wow_eapol_4way_enable; + +	/* This configuration allows a host wakeup on an network scan +	 * offload match. +	 */ +	u8 wow_net_scan_offload_match; + +	/* This configuration allows a host wakeup on any GTK rekeying +	 * error. +	 */ +	u8 wow_gtk_rekey_error; + +	/* This configuration allows a host wakeup on BSS connection loss. +	 */ +	u8 wow_bss_connection_loss; + +	u8 bss_index; +}; + +struct wcn36xx_hal_wowl_exit_req_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 bss_index; +}; + +struct wcn36xx_hal_get_rssi_req_msg { +	struct wcn36xx_hal_msg_header header; +}; + +struct wcn36xx_hal_get_roam_rssi_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Valid STA Idx for per STA stats request */ +	u32 sta_id; +}; + +struct wcn36xx_hal_set_uapsd_ac_params_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* STA index */ +	u8 sta_idx; + +	/* Access Category */ +	u8 ac; + +	/* User Priority */ +	u8 up; + +	/* Service Interval */ +	u32 service_interval; + +	/* Suspend Interval */ +	u32 suspend_interval; + +	/* Delay Interval */ +	u32 delay_interval; +}; + +struct wcn36xx_hal_configure_rxp_filter_req_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 set_mcst_bcst_filter_setting; +	u8 set_mcst_bcst_filter; +}; + +struct wcn36xx_hal_enter_imps_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +}; + +struct wcn36xx_hal_exit_imps_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +}; + +struct wcn36xx_hal_enter_bmps_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; + +	u8 bss_index; +} __packed; + +struct wcn36xx_hal_exit_bmps_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; + +	u8 bss_index; +} __packed; + +struct wcn36xx_hal_enter_uapsd_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; + +	u8 bss_index; +}; + +struct wcn36xx_hal_exit_uapsd_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; + +	u8 bss_index; +}; + +struct wcn36xx_hal_rssi_notification_ind_msg { +	struct wcn36xx_hal_msg_header header; + +	u32 rssi_thres1_pos_cross:1; +	u32 rssi_thres1_neg_cross:1; +	u32 rssi_thres2_pos_cross:1; +	u32 rssi_thres2_neg_cross:1; +	u32 rssi_thres3_pos_cross:1; +	u32 rssi_thres3_neg_cross:1; +	u32 avg_rssi:8; +	u32 reserved:18; + +}; + +struct wcn36xx_hal_get_rssio_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +	s8 rssi; + +}; + +struct wcn36xx_hal_get_roam_rssi_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; + +	u8 sta_id; +	s8 rssi; +}; + +struct wcn36xx_hal_wowl_enter_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +	u8 bss_index; +}; + +struct wcn36xx_hal_wowl_exit_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +	u8 bss_index; +}; + +struct wcn36xx_hal_add_bcn_filter_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +}; + +struct wcn36xx_hal_rem_bcn_filter_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +}; + +struct wcn36xx_hal_add_wowl_bcast_ptrn_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +	u8 bss_index; +}; + +struct wcn36xx_hal_del_wowl_bcast_ptrn_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +	u8 bss_index; +}; + +struct wcn36xx_hal_host_offload_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +}; + +struct wcn36xx_hal_keep_alive_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +}; + +struct wcn36xx_hal_set_rssi_thresh_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +}; + +struct wcn36xx_hal_set_uapsd_ac_params_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +}; + +struct wcn36xx_hal_configure_rxp_filter_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +}; + +struct set_max_tx_pwr_req { +	struct wcn36xx_hal_msg_header header; + +	/* BSSID is needed to identify which session issued this request. +	 * As the request has power constraints, this should be applied +	 * only to that session */ +	u8 bssid[ETH_ALEN]; + +	u8 self_addr[ETH_ALEN]; + +	/* In request, power == MaxTx power to be used. */ +	u8 power; +}; + +struct set_max_tx_pwr_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* power == tx power used for management frames */ +	u8 power; + +	/* success or failure */ +	u32 status; +}; + +struct set_tx_pwr_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* TX Power in milli watts */ +	u32 tx_power; + +	u8 bss_index; +}; + +struct set_tx_pwr_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +}; + +struct get_tx_pwr_req_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 sta_id; +}; + +struct get_tx_pwr_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; + +	/* TX Power in milli watts */ +	u32 tx_power; +}; + +struct set_p2p_gonoa_req_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 opp_ps; +	u32 ct_window; +	u8 count; +	u32 duration; +	u32 interval; +	u32 single_noa_duration; +	u8 ps_selection; +}; + +struct set_p2p_gonoa_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +}; + +struct wcn36xx_hal_add_sta_self_req { +	struct wcn36xx_hal_msg_header header; + +	u8 self_addr[ETH_ALEN]; +	u32 status; +} __packed; + +struct wcn36xx_hal_add_sta_self_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; + +	/* Self STA Index */ +	u8 self_sta_index; + +	/* DPU Index (IGTK, PTK, GTK all same) */ +	u8 dpu_index; + +	/* DPU Signature */ +	u8 dpu_signature; +} __packed; + +struct wcn36xx_hal_del_sta_self_req_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 self_addr[ETH_ALEN]; +} __packed; + +struct wcn36xx_hal_del_sta_self_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/*success or failure */ +	u32 status; + +	u8 self_addr[ETH_ALEN]; +} __packed; + +struct aggr_add_ts_req { +	struct wcn36xx_hal_msg_header header; + +	/* Station Index */ +	u16 sta_idx; + +	/* TSPEC handler uniquely identifying a TSPEC for a STA in a BSS. +	 * This will carry the bitmap with the bit positions representing +	 * different AC.s */ +	u16 tspec_index; + +	/* Tspec info per AC To program TPE with required parameters */ +	struct wcn36xx_hal_tspec_ie tspec[WCN36XX_HAL_MAX_AC]; + +	/* U-APSD Flags: 1b per AC.  Encoded as follows: +	   b7 b6 b5 b4 b3 b2 b1 b0 = +	   X  X  X  X  BE BK VI VO */ +	u8 uapsd; + +	/* These parameters are for all the access categories */ + +	/* Service Interval */ +	u32 service_interval[WCN36XX_HAL_MAX_AC]; + +	/* Suspend Interval */ +	u32 suspend_interval[WCN36XX_HAL_MAX_AC]; + +	/* Delay Interval */ +	u32 delay_interval[WCN36XX_HAL_MAX_AC]; +}; + +struct aggr_add_ts_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status0; + +	/* FIXME PRIMA for future use for 11R */ +	u32 status1; +}; + +struct wcn36xx_hal_configure_apps_cpu_wakeup_state_req_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 is_apps_cpu_awake; +}; + +struct wcn36xx_hal_configure_apps_cpu_wakeup_state_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +}; + +struct wcn36xx_hal_dump_cmd_req_msg { +	struct wcn36xx_hal_msg_header header; + +	u32 arg1; +	u32 arg2; +	u32 arg3; +	u32 arg4; +	u32 arg5; +} __packed; + +struct wcn36xx_hal_dump_cmd_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; + +	/* Length of the responce message */ +	u32 rsp_length; + +	/* FIXME: Currently considering the the responce will be less than +	 * 100bytes */ +	u8 rsp_buffer[DUMPCMD_RSP_BUFFER]; +} __packed; + +#define WLAN_COEX_IND_DATA_SIZE (4) +#define WLAN_COEX_IND_TYPE_DISABLE_HB_MONITOR (0) +#define WLAN_COEX_IND_TYPE_ENABLE_HB_MONITOR (1) + +struct coex_ind_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Coex Indication Type */ +	u32 type; + +	/* Coex Indication Data */ +	u32 data[WLAN_COEX_IND_DATA_SIZE]; +}; + +struct wcn36xx_hal_tx_compl_ind_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Tx Complete Indication Success or Failure */ +	u32 status; +}; + +struct wcn36xx_hal_wlan_host_suspend_ind_msg { +	struct wcn36xx_hal_msg_header header; + +	u32 configured_mcst_bcst_filter_setting; +	u32 active_session_count; +}; + +struct wcn36xx_hal_wlan_exclude_unencrpted_ind_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 dot11_exclude_unencrypted; +	u8 bssid[ETH_ALEN]; +}; + +struct noa_attr_ind_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 index; +	u8 opp_ps_flag; +	u16 ctwin; + +	u16 noa1_interval_count; +	u16 bss_index; +	u32 noa1_duration; +	u32 noa1_interval; +	u32 noa1_starttime; + +	u16 noa2_interval_count; +	u16 reserved2; +	u32 noa2_duration; +	u32 noa2_interval; +	u32 noa2_start_time; + +	u32 status; +}; + +struct noa_start_ind_msg { +	struct wcn36xx_hal_msg_header header; + +	u32 status; +	u32 bss_index; +}; + +struct wcn36xx_hal_wlan_host_resume_req_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 configured_mcst_bcst_filter_setting; +}; + +struct wcn36xx_hal_host_resume_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +}; + +struct wcn36xx_hal_del_ba_ind_msg { +	struct wcn36xx_hal_msg_header header; + +	u16 sta_idx; + +	/* Peer MAC Address, whose BA session has timed out */ +	u8 peer_addr[ETH_ALEN]; + +	/* TID for which a BA session timeout is being triggered */ +	u8 ba_tid; + +	/* DELBA direction +	 * 1 - Originator +	 * 0 - Recipient +	 */ +	u8 direction; + +	u32 reason_code; + +	/* TO SUPPORT BT-AMP */ +	u8 bssid[ETH_ALEN]; +}; + +/* PNO Messages */ + +/* Max number of channels that a network can be found on */ +#define WCN36XX_HAL_PNO_MAX_NETW_CHANNELS  26 + +/* Max number of channels that a network can be found on */ +#define WCN36XX_HAL_PNO_MAX_NETW_CHANNELS_EX  60 + +/* Maximum numbers of networks supported by PNO */ +#define WCN36XX_HAL_PNO_MAX_SUPP_NETWORKS  16 + +/* The number of scan time intervals that can be programmed into PNO */ +#define WCN36XX_HAL_PNO_MAX_SCAN_TIMERS    10 + +/* Maximum size of the probe template */ +#define WCN36XX_HAL_PNO_MAX_PROBE_SIZE     450 + +/* Type of PNO enabling: + * + * Immediate - scanning will start immediately and PNO procedure will be + * repeated based on timer + * + * Suspend - scanning will start at suspend + * + * Resume - scanning will start on system resume + */ +enum pno_mode { +	PNO_MODE_IMMEDIATE, +	PNO_MODE_ON_SUSPEND, +	PNO_MODE_ON_RESUME, +	PNO_MODE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE +}; + +/* Authentication type */ +enum auth_type { +	AUTH_TYPE_ANY = 0, +	AUTH_TYPE_OPEN_SYSTEM = 1, + +	/* Upper layer authentication types */ +	AUTH_TYPE_WPA = 2, +	AUTH_TYPE_WPA_PSK = 3, + +	AUTH_TYPE_RSN = 4, +	AUTH_TYPE_RSN_PSK = 5, +	AUTH_TYPE_FT_RSN = 6, +	AUTH_TYPE_FT_RSN_PSK = 7, +	AUTH_TYPE_WAPI_WAI_CERTIFICATE = 8, +	AUTH_TYPE_WAPI_WAI_PSK = 9, + +	AUTH_TYPE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE +}; + +/* Encryption type */ +enum ed_type { +	ED_ANY = 0, +	ED_NONE = 1, +	ED_WEP = 2, +	ED_TKIP = 3, +	ED_CCMP = 4, +	ED_WPI = 5, + +	ED_TYPE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE +}; + +/* SSID broadcast  type */ +enum ssid_bcast_type { +	BCAST_UNKNOWN = 0, +	BCAST_NORMAL = 1, +	BCAST_HIDDEN = 2, + +	BCAST_TYPE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE +}; + +/* The network description for which PNO will have to look for */ +struct network_type { +	/* SSID of the BSS */ +	struct wcn36xx_hal_mac_ssid ssid; + +	/* Authentication type for the network */ +	enum auth_type authentication; + +	/* Encryption type for the network */ +	enum ed_type encryption; + +	/* Indicate the channel on which the Network can be found 0 - if +	 * all channels */ +	u8 channel_count; +	u8 channels[WCN36XX_HAL_PNO_MAX_NETW_CHANNELS]; + +	/* Indicates the RSSI threshold for the network to be considered */ +	u8 rssi_threshold; +}; + +struct scan_timer { +	/* How much it should wait */ +	u32 value; + +	/* How many times it should repeat that wait value 0 - keep using +	 * this timer until PNO is disabled */ +	u32 repeat; + +	/* e.g: 2 3 4 0 - it will wait 2s between consecutive scans for 3 +	 * times - after that it will wait 4s between consecutive scans +	 * until disabled */ +}; + +/* The network parameters to be sent to the PNO algorithm */ +struct scan_timers_type { +	/* set to 0 if you wish for PNO to use its default telescopic timer */ +	u8 count; + +	/* A set value represents the amount of time that PNO will wait +	 * between two consecutive scan procedures If the desired is for a +	 * uniform timer that fires always at the exact same interval - one +	 * single value is to be set If there is a desire for a more +	 * complex - telescopic like timer multiple values can be set - +	 * once PNO reaches the end of the array it will continue scanning +	 * at intervals presented by the last value */ +	struct scan_timer values[WCN36XX_HAL_PNO_MAX_SCAN_TIMERS]; +}; + +/* Preferred network list request */ +struct set_pref_netw_list_req { +	struct wcn36xx_hal_msg_header header; + +	/* Enable PNO */ +	u32 enable; + +	/* Immediate,  On Suspend,   On Resume */ +	enum pno_mode mode; + +	/* Number of networks sent for PNO */ +	u32 networks_count; + +	/* The networks that PNO needs to look for */ +	struct network_type networks[WCN36XX_HAL_PNO_MAX_SUPP_NETWORKS]; + +	/* The scan timers required for PNO */ +	struct scan_timers_type scan_timers; + +	/* Probe template for 2.4GHz band */ +	u16 band_24g_probe_size; +	u8 band_24g_probe_template[WCN36XX_HAL_PNO_MAX_PROBE_SIZE]; + +	/* Probe template for 5GHz band */ +	u16 band_5g_probe_size; +	u8 band_5g_probe_template[WCN36XX_HAL_PNO_MAX_PROBE_SIZE]; +}; + +/* The network description for which PNO will have to look for */ +struct network_type_new { +	/* SSID of the BSS */ +	struct wcn36xx_hal_mac_ssid ssid; + +	/* Authentication type for the network */ +	enum auth_type authentication; + +	/* Encryption type for the network */ +	enum ed_type encryption; + +	/* SSID broadcast type, normal, hidden or unknown */ +	enum ssid_bcast_type bcast_network_type; + +	/* Indicate the channel on which the Network can be found 0 - if +	 * all channels */ +	u8 channel_count; +	u8 channels[WCN36XX_HAL_PNO_MAX_NETW_CHANNELS]; + +	/* Indicates the RSSI threshold for the network to be considered */ +	u8 rssi_threshold; +}; + +/* Preferred network list request new */ +struct set_pref_netw_list_req_new { +	struct wcn36xx_hal_msg_header header; + +	/* Enable PNO */ +	u32 enable; + +	/* Immediate,  On Suspend,   On Resume */ +	enum pno_mode mode; + +	/* Number of networks sent for PNO */ +	u32 networks_count; + +	/* The networks that PNO needs to look for */ +	struct network_type_new networks[WCN36XX_HAL_PNO_MAX_SUPP_NETWORKS]; + +	/* The scan timers required for PNO */ +	struct scan_timers_type scan_timers; + +	/* Probe template for 2.4GHz band */ +	u16 band_24g_probe_size; +	u8 band_24g_probe_template[WCN36XX_HAL_PNO_MAX_PROBE_SIZE]; + +	/* Probe template for 5GHz band */ +	u16 band_5g_probe_size; +	u8 band_5g_probe_template[WCN36XX_HAL_PNO_MAX_PROBE_SIZE]; +}; + +/* Preferred network list response */ +struct set_pref_netw_list_resp { +	struct wcn36xx_hal_msg_header header; + +	/* status of the request - just to indicate that PNO has +	 * acknowledged the request and will start scanning */ +	u32 status; +}; + +/* Preferred network found indication */ +struct pref_netw_found_ind { + +	struct wcn36xx_hal_msg_header header; + +	/* Network that was found with the highest RSSI */ +	struct wcn36xx_hal_mac_ssid ssid; + +	/* Indicates the RSSI */ +	u8 rssi; +}; + +/* RSSI Filter request */ +struct set_rssi_filter_req { +	struct wcn36xx_hal_msg_header header; + +	/* RSSI Threshold */ +	u8 rssi_threshold; +}; + +/* Set RSSI filter resp */ +struct set_rssi_filter_resp { +	struct wcn36xx_hal_msg_header header; + +	/* status of the request */ +	u32 status; +}; + +/* Update scan params - sent from host to PNO to be used during PNO + * scanningx */ +struct wcn36xx_hal_update_scan_params_req { + +	struct wcn36xx_hal_msg_header header; + +	/* Host setting for 11d */ +	u8 dot11d_enabled; + +	/* Lets PNO know that host has determined the regulatory domain */ +	u8 dot11d_resolved; + +	/* Channels on which PNO is allowed to scan */ +	u8 channel_count; +	u8 channels[WCN36XX_HAL_PNO_MAX_NETW_CHANNELS]; + +	/* Minimum channel time */ +	u16 active_min_ch_time; + +	/* Maximum channel time */ +	u16 active_max_ch_time; + +	/* Minimum channel time */ +	u16 passive_min_ch_time; + +	/* Maximum channel time */ +	u16 passive_max_ch_time; + +	/* Cb State */ +	enum phy_chan_bond_state state; +} __packed; + +/* Update scan params - sent from host to PNO to be used during PNO + * scanningx */ +struct update_scan_params_req_ex { + +	struct wcn36xx_hal_msg_header header; + +	/* Host setting for 11d */ +	u8 dot11d_enabled; + +	/* Lets PNO know that host has determined the regulatory domain */ +	u8 dot11d_resolved; + +	/* Channels on which PNO is allowed to scan */ +	u8 channel_count; +	u8 channels[WCN36XX_HAL_PNO_MAX_NETW_CHANNELS_EX]; + +	/* Minimum channel time */ +	u16 active_min_ch_time; + +	/* Maximum channel time */ +	u16 active_max_ch_time; + +	/* Minimum channel time */ +	u16 passive_min_ch_time; + +	/* Maximum channel time */ +	u16 passive_max_ch_time; + +	/* Cb State */ +	enum phy_chan_bond_state state; +}; + +/* Update scan params - sent from host to PNO to be used during PNO + * scanningx */ +struct wcn36xx_hal_update_scan_params_resp { + +	struct wcn36xx_hal_msg_header header; + +	/* status of the request */ +	u32 status; +} __packed; + +struct wcn36xx_hal_set_tx_per_tracking_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* 0: disable, 1:enable */ +	u8 tx_per_tracking_enable; + +	/* Check period, unit is sec. */ +	u8 tx_per_tracking_period; + +	/* (Fail TX packet)/(Total TX packet) ratio, the unit is 10%. */ +	u8 tx_per_tracking_ratio; + +	/* A watermark of check number, once the tx packet exceed this +	 * number, we do the check, default is 5 */ +	u32 tx_per_tracking_watermark; +}; + +struct wcn36xx_hal_set_tx_per_tracking_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; + +}; + +struct tx_per_hit_ind_msg { +	struct wcn36xx_hal_msg_header header; +}; + +/* Packet Filtering Definitions Begin */ +#define    WCN36XX_HAL_PROTOCOL_DATA_LEN                  8 +#define    WCN36XX_HAL_MAX_NUM_MULTICAST_ADDRESS        240 +#define    WCN36XX_HAL_MAX_NUM_FILTERS                   20 +#define    WCN36XX_HAL_MAX_CMP_PER_FILTER                10 + +enum wcn36xx_hal_receive_packet_filter_type { +	HAL_RCV_FILTER_TYPE_INVALID, +	HAL_RCV_FILTER_TYPE_FILTER_PKT, +	HAL_RCV_FILTER_TYPE_BUFFER_PKT, +	HAL_RCV_FILTER_TYPE_MAX_ENUM_SIZE +}; + +enum wcn36xx_hal_rcv_pkt_flt_protocol_type { +	HAL_FILTER_PROTO_TYPE_INVALID, +	HAL_FILTER_PROTO_TYPE_MAC, +	HAL_FILTER_PROTO_TYPE_ARP, +	HAL_FILTER_PROTO_TYPE_IPV4, +	HAL_FILTER_PROTO_TYPE_IPV6, +	HAL_FILTER_PROTO_TYPE_UDP, +	HAL_FILTER_PROTO_TYPE_MAX +}; + +enum wcn36xx_hal_rcv_pkt_flt_cmp_flag_type { +	HAL_FILTER_CMP_TYPE_INVALID, +	HAL_FILTER_CMP_TYPE_EQUAL, +	HAL_FILTER_CMP_TYPE_MASK_EQUAL, +	HAL_FILTER_CMP_TYPE_NOT_EQUAL, +	HAL_FILTER_CMP_TYPE_MAX +}; + +struct wcn36xx_hal_rcv_pkt_filter_params { +	u8 protocol_layer; +	u8 cmp_flag; + +	/* Length of the data to compare */ +	u16 data_length; + +	/* from start of the respective frame header */ +	u8 data_offset; + +	/* Reserved field */ +	u8 reserved; + +	/* Data to compare */ +	u8 compare_data[WCN36XX_HAL_PROTOCOL_DATA_LEN]; + +	/* Mask to be applied on the received packet data before compare */ +	u8 data_mask[WCN36XX_HAL_PROTOCOL_DATA_LEN]; +}; + +struct wcn36xx_hal_sessionized_rcv_pkt_filter_cfg_type { +	u8 id; +	u8 type; +	u8 params_count; +	u32 coleasce_time; +	u8 bss_index; +	struct wcn36xx_hal_rcv_pkt_filter_params params[1]; +}; + +struct wcn36xx_hal_set_rcv_pkt_filter_req_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 id; +	u8 type; +	u8 params_count; +	u32 coalesce_time; +	struct wcn36xx_hal_rcv_pkt_filter_params params[1]; +}; + +struct wcn36xx_hal_rcv_flt_mc_addr_list_type { +	/* from start of the respective frame header */ +	u8 data_offset; + +	u32 mc_addr_count; +	u8 mc_addr[ETH_ALEN][WCN36XX_HAL_MAX_NUM_MULTICAST_ADDRESS]; +	u8 bss_index; +}; + +struct wcn36xx_hal_set_pkt_filter_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; + +	u8 bss_index; +}; + +struct wcn36xx_hal_rcv_flt_pkt_match_cnt_req_msg { +	struct wcn36xx_hal_msg_header header; + +	u8 bss_index; +}; + +struct wcn36xx_hal_rcv_flt_pkt_match_cnt { +	u8 id; +	u32 match_cnt; +}; + +struct wcn36xx_hal_rcv_flt_pkt_match_cnt_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Success or Failure */ +	u32 status; + +	u32 match_count; +	struct wcn36xx_hal_rcv_flt_pkt_match_cnt +		matches[WCN36XX_HAL_MAX_NUM_FILTERS]; +	u8 bss_index; +}; + +struct wcn36xx_hal_rcv_flt_pkt_clear_param { +	/* only valid for response message */ +	u32 status; +	u8 id; +	u8 bss_index; +}; + +struct wcn36xx_hal_rcv_flt_pkt_clear_req_msg { +	struct wcn36xx_hal_msg_header header; +	struct wcn36xx_hal_rcv_flt_pkt_clear_param param; +}; + +struct wcn36xx_hal_rcv_flt_pkt_clear_rsp_msg { +	struct wcn36xx_hal_msg_header header; +	struct wcn36xx_hal_rcv_flt_pkt_clear_param param; +}; + +struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_req_msg { +	struct wcn36xx_hal_msg_header header; +	struct wcn36xx_hal_rcv_flt_mc_addr_list_type mc_addr_list; +}; + +struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_rsp_msg { +	struct wcn36xx_hal_msg_header header; +	u32 status; +	u8 bss_index; +}; + +/* Packet Filtering Definitions End */ + +struct wcn36xx_hal_set_power_params_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/*  Ignore DTIM */ +	u32 ignore_dtim; + +	/* DTIM Period */ +	u32 dtim_period; + +	/* Listen Interval */ +	u32 listen_interval; + +	/* Broadcast Multicast Filter  */ +	u32 bcast_mcast_filter; + +	/* Beacon Early Termination */ +	u32 enable_bet; + +	/* Beacon Early Termination Interval */ +	u32 bet_interval; +} __packed; + +struct wcn36xx_hal_set_power_params_resp { + +	struct wcn36xx_hal_msg_header header; + +	/* status of the request */ +	u32 status; +} __packed; + +/* Capability bitmap exchange definitions and macros starts */ + +enum place_holder_in_cap_bitmap { +	MCC = 0, +	P2P = 1, +	DOT11AC = 2, +	SLM_SESSIONIZATION = 3, +	DOT11AC_OPMODE = 4, +	SAP32STA = 5, +	TDLS = 6, +	P2P_GO_NOA_DECOUPLE_INIT_SCAN = 7, +	WLANACTIVE_OFFLOAD = 8, +	BEACON_OFFLOAD = 9, +	SCAN_OFFLOAD = 10, +	ROAM_OFFLOAD = 11, +	BCN_MISS_OFFLOAD = 12, +	STA_POWERSAVE = 13, +	STA_ADVANCED_PWRSAVE = 14, +	AP_UAPSD = 15, +	AP_DFS = 16, +	BLOCKACK = 17, +	PHY_ERR = 18, +	BCN_FILTER = 19, +	RTT = 20, +	RATECTRL = 21, +	WOW = 22, +	MAX_FEATURE_SUPPORTED = 128, +}; + +#define WCN36XX_HAL_CAPS_SIZE 4 + +struct wcn36xx_hal_feat_caps_msg { + +	struct wcn36xx_hal_msg_header header; + +	u32 feat_caps[WCN36XX_HAL_CAPS_SIZE]; +} __packed; + +/* status codes to help debug rekey failures */ +enum gtk_rekey_status { +	WCN36XX_HAL_GTK_REKEY_STATUS_SUCCESS = 0, + +	/* rekey detected, but not handled */ +	WCN36XX_HAL_GTK_REKEY_STATUS_NOT_HANDLED = 1, + +	/* MIC check error on M1 */ +	WCN36XX_HAL_GTK_REKEY_STATUS_MIC_ERROR = 2, + +	/* decryption error on M1  */ +	WCN36XX_HAL_GTK_REKEY_STATUS_DECRYPT_ERROR = 3, + +	/* M1 replay detected */ +	WCN36XX_HAL_GTK_REKEY_STATUS_REPLAY_ERROR = 4, + +	/* missing GTK key descriptor in M1 */ +	WCN36XX_HAL_GTK_REKEY_STATUS_MISSING_KDE = 5, + +	/* missing iGTK key descriptor in M1 */ +	WCN36XX_HAL_GTK_REKEY_STATUS_MISSING_IGTK_KDE = 6, + +	/* key installation error */ +	WCN36XX_HAL_GTK_REKEY_STATUS_INSTALL_ERROR = 7, + +	/* iGTK key installation error */ +	WCN36XX_HAL_GTK_REKEY_STATUS_IGTK_INSTALL_ERROR = 8, + +	/* GTK rekey M2 response TX error */ +	WCN36XX_HAL_GTK_REKEY_STATUS_RESP_TX_ERROR = 9, + +	/* non-specific general error */ +	WCN36XX_HAL_GTK_REKEY_STATUS_GEN_ERROR = 255 +}; + +/* wake reason types */ +enum wake_reason_type { +	WCN36XX_HAL_WAKE_REASON_NONE = 0, + +	/* magic packet match */ +	WCN36XX_HAL_WAKE_REASON_MAGIC_PACKET = 1, + +	/* host defined pattern match */ +	WCN36XX_HAL_WAKE_REASON_PATTERN_MATCH = 2, + +	/* EAP-ID frame detected */ +	WCN36XX_HAL_WAKE_REASON_EAPID_PACKET = 3, + +	/* start of EAPOL 4-way handshake detected */ +	WCN36XX_HAL_WAKE_REASON_EAPOL4WAY_PACKET = 4, + +	/* network scan offload match */ +	WCN36XX_HAL_WAKE_REASON_NETSCAN_OFFL_MATCH = 5, + +	/* GTK rekey status wakeup (see status) */ +	WCN36XX_HAL_WAKE_REASON_GTK_REKEY_STATUS = 6, + +	/* BSS connection lost */ +	WCN36XX_HAL_WAKE_REASON_BSS_CONN_LOST = 7, +}; + +/* +  Wake Packet which is saved at tWakeReasonParams.DataStart +  This data is sent for any wake reasons that involve a packet-based wakeup : + +  WCN36XX_HAL_WAKE_REASON_TYPE_MAGIC_PACKET +  WCN36XX_HAL_WAKE_REASON_TYPE_PATTERN_MATCH +  WCN36XX_HAL_WAKE_REASON_TYPE_EAPID_PACKET +  WCN36XX_HAL_WAKE_REASON_TYPE_EAPOL4WAY_PACKET +  WCN36XX_HAL_WAKE_REASON_TYPE_GTK_REKEY_STATUS + +  The information is provided to the host for auditing and debug purposes + +*/ + +/* Wake reason indication */ +struct wcn36xx_hal_wake_reason_ind { +	struct wcn36xx_hal_msg_header header; + +	/* see tWakeReasonType */ +	u32 reason; + +	/* argument specific to the reason type */ +	u32 reason_arg; + +	/* length of optional data stored in this message, in case HAL +	 * truncates the data (i.e. data packets) this length will be less +	 * than the actual length */ +	u32 stored_data_len; + +	/* actual length of data */ +	u32 actual_data_len; + +	/* variable length start of data (length == storedDataLen) see +	 * specific wake type */ +	u8 data_start[1]; + +	u32 bss_index:8; +	u32 reserved:24; +}; + +#define WCN36XX_HAL_GTK_KEK_BYTES 16 +#define WCN36XX_HAL_GTK_KCK_BYTES 16 + +#define WCN36XX_HAL_GTK_OFFLOAD_FLAGS_DISABLE (1 << 0) + +#define GTK_SET_BSS_KEY_TAG  0x1234AA55 + +struct wcn36xx_hal_gtk_offload_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* optional flags */ +	u32 flags; + +	/* Key confirmation key */ +	u8 kck[WCN36XX_HAL_GTK_KCK_BYTES]; + +	/* key encryption key */ +	u8 kek[WCN36XX_HAL_GTK_KEK_BYTES]; + +	/* replay counter */ +	u64 key_replay_counter; + +	u8 bss_index; +}; + +struct wcn36xx_hal_gtk_offload_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; + +	u8 bss_index; +}; + +struct wcn36xx_hal_gtk_offload_get_info_req_msg { +	struct wcn36xx_hal_msg_header header; +	u8 bss_index; +}; + +struct wcn36xx_hal_gtk_offload_get_info_rsp_msg { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; + +	/* last rekey status when the rekey was offloaded */ +	u32 last_rekey_status; + +	/* current replay counter value */ +	u64 key_replay_counter; + +	/* total rekey attempts */ +	u32 total_rekey_count; + +	/* successful GTK rekeys */ +	u32 gtk_rekey_count; + +	/* successful iGTK rekeys */ +	u32 igtk_rekey_count; + +	u8 bss_index; +}; + +struct dhcp_info { +	/* Indicates the device mode which indicates about the DHCP activity */ +	u8 device_mode; + +	u8 addr[ETH_ALEN]; +}; + +struct dhcp_ind_status { +	struct wcn36xx_hal_msg_header header; + +	/* success or failure */ +	u32 status; +}; + +/* + *   Thermal Mitigation mode of operation. + * + *  WCN36XX_HAL_THERMAL_MITIGATION_MODE_0 - Based on AMPDU disabling aggregation + * + *  WCN36XX_HAL_THERMAL_MITIGATION_MODE_1 - Based on AMPDU disabling aggregation + *  and reducing transmit power + * + *  WCN36XX_HAL_THERMAL_MITIGATION_MODE_2 - Not supported */ +enum wcn36xx_hal_thermal_mitigation_mode_type { +	HAL_THERMAL_MITIGATION_MODE_INVALID = -1, +	HAL_THERMAL_MITIGATION_MODE_0, +	HAL_THERMAL_MITIGATION_MODE_1, +	HAL_THERMAL_MITIGATION_MODE_2, +	HAL_THERMAL_MITIGATION_MODE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE, +}; + + +/* + *   Thermal Mitigation level. + * Note the levels are incremental i.e WCN36XX_HAL_THERMAL_MITIGATION_LEVEL_2 = + * WCN36XX_HAL_THERMAL_MITIGATION_LEVEL_0 + + * WCN36XX_HAL_THERMAL_MITIGATION_LEVEL_1 + * + * WCN36XX_HAL_THERMAL_MITIGATION_LEVEL_0 - lowest level of thermal mitigation. + * This level indicates normal mode of operation + * + * WCN36XX_HAL_THERMAL_MITIGATION_LEVEL_1 - 1st level of thermal mitigation + * + * WCN36XX_HAL_THERMAL_MITIGATION_LEVEL_2 - 2nd level of thermal mitigation + * + * WCN36XX_HAL_THERMAL_MITIGATION_LEVEL_3 - 3rd level of thermal mitigation + * + * WCN36XX_HAL_THERMAL_MITIGATION_LEVEL_4 - 4th level of thermal mitigation + */ +enum wcn36xx_hal_thermal_mitigation_level_type { +	HAL_THERMAL_MITIGATION_LEVEL_INVALID = -1, +	HAL_THERMAL_MITIGATION_LEVEL_0, +	HAL_THERMAL_MITIGATION_LEVEL_1, +	HAL_THERMAL_MITIGATION_LEVEL_2, +	HAL_THERMAL_MITIGATION_LEVEL_3, +	HAL_THERMAL_MITIGATION_LEVEL_4, +	HAL_THERMAL_MITIGATION_LEVEL_MAX = WCN36XX_HAL_MAX_ENUM_SIZE, +}; + + +/* WCN36XX_HAL_SET_THERMAL_MITIGATION_REQ */ +struct set_thermal_mitigation_req_msg { +	struct wcn36xx_hal_msg_header header; + +	/* Thermal Mitigation Operation Mode */ +	enum wcn36xx_hal_thermal_mitigation_mode_type mode; + +	/* Thermal Mitigation Level */ +	enum wcn36xx_hal_thermal_mitigation_level_type level; +}; + +struct set_thermal_mitigation_resp { + +	struct wcn36xx_hal_msg_header header; + +	/* status of the request */ +	u32 status; +}; + +/* Per STA Class B Statistics. Class B statistics are STA TX/RX stats + * provided to FW from Host via periodic messages */ +struct stats_class_b_ind { +	struct wcn36xx_hal_msg_header header; + +	/* Duration over which this stats was collected */ +	u32 duration; + +	/* Per STA Stats */ + +	/* TX stats */ +	u32 tx_bytes_pushed; +	u32 tx_packets_pushed; + +	/* RX stats */ +	u32 rx_bytes_rcvd; +	u32 rx_packets_rcvd; +	u32 rx_time_total; +}; + +#endif /* _HAL_H_ */ diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c new file mode 100644 index 00000000000..4ab5370ab7a --- /dev/null +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -0,0 +1,1099 @@ +/* + * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com> + * + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/module.h> +#include <linux/firmware.h> +#include <linux/platform_device.h> +#include "wcn36xx.h" + +unsigned int wcn36xx_dbg_mask; +module_param_named(debug_mask, wcn36xx_dbg_mask, uint, 0644); +MODULE_PARM_DESC(debug_mask, "Debugging mask"); + +#define CHAN2G(_freq, _idx) { \ +	.band = IEEE80211_BAND_2GHZ, \ +	.center_freq = (_freq), \ +	.hw_value = (_idx), \ +	.max_power = 25, \ +} + +#define CHAN5G(_freq, _idx) { \ +	.band = IEEE80211_BAND_5GHZ, \ +	.center_freq = (_freq), \ +	.hw_value = (_idx), \ +	.max_power = 25, \ +} + +/* The wcn firmware expects channel values to matching + * their mnemonic values. So use these for .hw_value. */ +static struct ieee80211_channel wcn_2ghz_channels[] = { +	CHAN2G(2412, 1), /* Channel 1 */ +	CHAN2G(2417, 2), /* Channel 2 */ +	CHAN2G(2422, 3), /* Channel 3 */ +	CHAN2G(2427, 4), /* Channel 4 */ +	CHAN2G(2432, 5), /* Channel 5 */ +	CHAN2G(2437, 6), /* Channel 6 */ +	CHAN2G(2442, 7), /* Channel 7 */ +	CHAN2G(2447, 8), /* Channel 8 */ +	CHAN2G(2452, 9), /* Channel 9 */ +	CHAN2G(2457, 10), /* Channel 10 */ +	CHAN2G(2462, 11), /* Channel 11 */ +	CHAN2G(2467, 12), /* Channel 12 */ +	CHAN2G(2472, 13), /* Channel 13 */ +	CHAN2G(2484, 14)  /* Channel 14 */ + +}; + +static struct ieee80211_channel wcn_5ghz_channels[] = { +	CHAN5G(5180, 36), +	CHAN5G(5200, 40), +	CHAN5G(5220, 44), +	CHAN5G(5240, 48), +	CHAN5G(5260, 52), +	CHAN5G(5280, 56), +	CHAN5G(5300, 60), +	CHAN5G(5320, 64), +	CHAN5G(5500, 100), +	CHAN5G(5520, 104), +	CHAN5G(5540, 108), +	CHAN5G(5560, 112), +	CHAN5G(5580, 116), +	CHAN5G(5600, 120), +	CHAN5G(5620, 124), +	CHAN5G(5640, 128), +	CHAN5G(5660, 132), +	CHAN5G(5700, 140), +	CHAN5G(5745, 149), +	CHAN5G(5765, 153), +	CHAN5G(5785, 157), +	CHAN5G(5805, 161), +	CHAN5G(5825, 165) +}; + +#define RATE(_bitrate, _hw_rate, _flags) { \ +	.bitrate        = (_bitrate),                   \ +	.flags          = (_flags),                     \ +	.hw_value       = (_hw_rate),                   \ +	.hw_value_short = (_hw_rate)  \ +} + +static struct ieee80211_rate wcn_2ghz_rates[] = { +	RATE(10, HW_RATE_INDEX_1MBPS, 0), +	RATE(20, HW_RATE_INDEX_2MBPS, IEEE80211_RATE_SHORT_PREAMBLE), +	RATE(55, HW_RATE_INDEX_5_5MBPS, IEEE80211_RATE_SHORT_PREAMBLE), +	RATE(110, HW_RATE_INDEX_11MBPS, IEEE80211_RATE_SHORT_PREAMBLE), +	RATE(60, HW_RATE_INDEX_6MBPS, 0), +	RATE(90, HW_RATE_INDEX_9MBPS, 0), +	RATE(120, HW_RATE_INDEX_12MBPS, 0), +	RATE(180, HW_RATE_INDEX_18MBPS, 0), +	RATE(240, HW_RATE_INDEX_24MBPS, 0), +	RATE(360, HW_RATE_INDEX_36MBPS, 0), +	RATE(480, HW_RATE_INDEX_48MBPS, 0), +	RATE(540, HW_RATE_INDEX_54MBPS, 0) +}; + +static struct ieee80211_rate wcn_5ghz_rates[] = { +	RATE(60, HW_RATE_INDEX_6MBPS, 0), +	RATE(90, HW_RATE_INDEX_9MBPS, 0), +	RATE(120, HW_RATE_INDEX_12MBPS, 0), +	RATE(180, HW_RATE_INDEX_18MBPS, 0), +	RATE(240, HW_RATE_INDEX_24MBPS, 0), +	RATE(360, HW_RATE_INDEX_36MBPS, 0), +	RATE(480, HW_RATE_INDEX_48MBPS, 0), +	RATE(540, HW_RATE_INDEX_54MBPS, 0) +}; + +static struct ieee80211_supported_band wcn_band_2ghz = { +	.channels	= wcn_2ghz_channels, +	.n_channels	= ARRAY_SIZE(wcn_2ghz_channels), +	.bitrates	= wcn_2ghz_rates, +	.n_bitrates	= ARRAY_SIZE(wcn_2ghz_rates), +	.ht_cap		= { +		.cap =	IEEE80211_HT_CAP_GRN_FLD | +			IEEE80211_HT_CAP_SGI_20 | +			IEEE80211_HT_CAP_DSSSCCK40 | +			IEEE80211_HT_CAP_LSIG_TXOP_PROT, +		.ht_supported = true, +		.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, +		.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, +		.mcs = { +			.rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +			.rx_highest = cpu_to_le16(72), +			.tx_params = IEEE80211_HT_MCS_TX_DEFINED, +		} +	} +}; + +static struct ieee80211_supported_band wcn_band_5ghz = { +	.channels	= wcn_5ghz_channels, +	.n_channels	= ARRAY_SIZE(wcn_5ghz_channels), +	.bitrates	= wcn_5ghz_rates, +	.n_bitrates	= ARRAY_SIZE(wcn_5ghz_rates), +	.ht_cap		= { +		.cap =	IEEE80211_HT_CAP_GRN_FLD | +			IEEE80211_HT_CAP_SGI_20 | +			IEEE80211_HT_CAP_DSSSCCK40 | +			IEEE80211_HT_CAP_LSIG_TXOP_PROT | +			IEEE80211_HT_CAP_SGI_40 | +			IEEE80211_HT_CAP_SUP_WIDTH_20_40, +		.ht_supported = true, +		.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, +		.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, +		.mcs = { +			.rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +			.rx_highest = cpu_to_le16(72), +			.tx_params = IEEE80211_HT_MCS_TX_DEFINED, +		} +	} +}; + +#ifdef CONFIG_PM + +static const struct wiphy_wowlan_support wowlan_support = { +	.flags = WIPHY_WOWLAN_ANY +}; + +#endif + +static inline u8 get_sta_index(struct ieee80211_vif *vif, +			       struct wcn36xx_sta *sta_priv) +{ +	return NL80211_IFTYPE_STATION == vif->type ? +	       sta_priv->bss_sta_index : +	       sta_priv->sta_index; +} + +static const char * const wcn36xx_caps_names[] = { +	"MCC",				/* 0 */ +	"P2P",				/* 1 */ +	"DOT11AC",			/* 2 */ +	"SLM_SESSIONIZATION",		/* 3 */ +	"DOT11AC_OPMODE",		/* 4 */ +	"SAP32STA",			/* 5 */ +	"TDLS",				/* 6 */ +	"P2P_GO_NOA_DECOUPLE_INIT_SCAN",/* 7 */ +	"WLANACTIVE_OFFLOAD",		/* 8 */ +	"BEACON_OFFLOAD",		/* 9 */ +	"SCAN_OFFLOAD",			/* 10 */ +	"ROAM_OFFLOAD",			/* 11 */ +	"BCN_MISS_OFFLOAD",		/* 12 */ +	"STA_POWERSAVE",		/* 13 */ +	"STA_ADVANCED_PWRSAVE",		/* 14 */ +	"AP_UAPSD",			/* 15 */ +	"AP_DFS",			/* 16 */ +	"BLOCKACK",			/* 17 */ +	"PHY_ERR",			/* 18 */ +	"BCN_FILTER",			/* 19 */ +	"RTT",				/* 20 */ +	"RATECTRL",			/* 21 */ +	"WOW"				/* 22 */ +}; + +static const char *wcn36xx_get_cap_name(enum place_holder_in_cap_bitmap x) +{ +	if (x >= ARRAY_SIZE(wcn36xx_caps_names)) +		return "UNKNOWN"; +	return wcn36xx_caps_names[x]; +} + +static void wcn36xx_feat_caps_info(struct wcn36xx *wcn) +{ +	int i; + +	for (i = 0; i < MAX_FEATURE_SUPPORTED; i++) { +		if (get_feat_caps(wcn->fw_feat_caps, i)) +			wcn36xx_info("FW Cap %s\n", wcn36xx_get_cap_name(i)); +	} +} + +static void wcn36xx_detect_chip_version(struct wcn36xx *wcn) +{ +	if (get_feat_caps(wcn->fw_feat_caps, DOT11AC)) { +		wcn36xx_info("Chip is 3680\n"); +		wcn->chip_version = WCN36XX_CHIP_3680; +	} else { +		wcn36xx_info("Chip is 3660\n"); +		wcn->chip_version = WCN36XX_CHIP_3660; +	} +} + +static int wcn36xx_start(struct ieee80211_hw *hw) +{ +	struct wcn36xx *wcn = hw->priv; +	int ret; + +	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac start\n"); + +	/* SMD initialization */ +	ret = wcn36xx_smd_open(wcn); +	if (ret) { +		wcn36xx_err("Failed to open smd channel: %d\n", ret); +		goto out_err; +	} + +	/* Allocate memory pools for Mgmt BD headers and Data BD headers */ +	ret = wcn36xx_dxe_allocate_mem_pools(wcn); +	if (ret) { +		wcn36xx_err("Failed to alloc DXE mempool: %d\n", ret); +		goto out_smd_close; +	} + +	ret = wcn36xx_dxe_alloc_ctl_blks(wcn); +	if (ret) { +		wcn36xx_err("Failed to alloc DXE ctl blocks: %d\n", ret); +		goto out_free_dxe_pool; +	} + +	wcn->hal_buf = kmalloc(WCN36XX_HAL_BUF_SIZE, GFP_KERNEL); +	if (!wcn->hal_buf) { +		wcn36xx_err("Failed to allocate smd buf\n"); +		ret = -ENOMEM; +		goto out_free_dxe_ctl; +	} + +	ret = wcn36xx_smd_load_nv(wcn); +	if (ret) { +		wcn36xx_err("Failed to push NV to chip\n"); +		goto out_free_smd_buf; +	} + +	ret = wcn36xx_smd_start(wcn); +	if (ret) { +		wcn36xx_err("Failed to start chip\n"); +		goto out_free_smd_buf; +	} + +	if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) { +		ret = wcn36xx_smd_feature_caps_exchange(wcn); +		if (ret) +			wcn36xx_warn("Exchange feature caps failed\n"); +		else +			wcn36xx_feat_caps_info(wcn); +	} + +	wcn36xx_detect_chip_version(wcn); + +	/* DMA channel initialization */ +	ret = wcn36xx_dxe_init(wcn); +	if (ret) { +		wcn36xx_err("DXE init failed\n"); +		goto out_smd_stop; +	} + +	wcn36xx_debugfs_init(wcn); + +	INIT_LIST_HEAD(&wcn->vif_list); +	return 0; + +out_smd_stop: +	wcn36xx_smd_stop(wcn); +out_free_smd_buf: +	kfree(wcn->hal_buf); +out_free_dxe_pool: +	wcn36xx_dxe_free_mem_pools(wcn); +out_free_dxe_ctl: +	wcn36xx_dxe_free_ctl_blks(wcn); +out_smd_close: +	wcn36xx_smd_close(wcn); +out_err: +	return ret; +} + +static void wcn36xx_stop(struct ieee80211_hw *hw) +{ +	struct wcn36xx *wcn = hw->priv; + +	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac stop\n"); + +	wcn36xx_debugfs_exit(wcn); +	wcn36xx_smd_stop(wcn); +	wcn36xx_dxe_deinit(wcn); +	wcn36xx_smd_close(wcn); + +	wcn36xx_dxe_free_mem_pools(wcn); +	wcn36xx_dxe_free_ctl_blks(wcn); + +	kfree(wcn->hal_buf); +} + +static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed) +{ +	struct wcn36xx *wcn = hw->priv; +	struct ieee80211_vif *vif = NULL; +	struct wcn36xx_vif *tmp; + +	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac config changed 0x%08x\n", changed); + +	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { +		int ch = WCN36XX_HW_CHANNEL(wcn); +		wcn36xx_dbg(WCN36XX_DBG_MAC, "wcn36xx_config channel switch=%d\n", +			    ch); +		list_for_each_entry(tmp, &wcn->vif_list, list) { +			vif = container_of((void *)tmp, +					   struct ieee80211_vif, +					   drv_priv); +			wcn36xx_smd_switch_channel(wcn, vif, ch); +		} +	} + +	return 0; +} + +#define WCN36XX_SUPPORTED_FILTERS (0) + +static void wcn36xx_configure_filter(struct ieee80211_hw *hw, +				     unsigned int changed, +				     unsigned int *total, u64 multicast) +{ +	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac configure filter\n"); + +	*total &= WCN36XX_SUPPORTED_FILTERS; +} + +static void wcn36xx_tx(struct ieee80211_hw *hw, +		       struct ieee80211_tx_control *control, +		       struct sk_buff *skb) +{ +	struct wcn36xx *wcn = hw->priv; +	struct wcn36xx_sta *sta_priv = NULL; + +	if (control->sta) +		sta_priv = (struct wcn36xx_sta *)control->sta->drv_priv; + +	if (wcn36xx_start_tx(wcn, sta_priv, skb)) +		ieee80211_free_txskb(wcn->hw, skb); +} + +static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, +			   struct ieee80211_vif *vif, +			   struct ieee80211_sta *sta, +			   struct ieee80211_key_conf *key_conf) +{ +	struct wcn36xx *wcn = hw->priv; +	struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; +	struct wcn36xx_sta *sta_priv = vif_priv->sta; +	int ret = 0; +	u8 key[WLAN_MAX_KEY_LEN]; + +	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac80211 set key\n"); +	wcn36xx_dbg(WCN36XX_DBG_MAC, "Key: cmd=0x%x algo:0x%x, id:%d, len:%d flags 0x%x\n", +		    cmd, key_conf->cipher, key_conf->keyidx, +		    key_conf->keylen, key_conf->flags); +	wcn36xx_dbg_dump(WCN36XX_DBG_MAC, "KEY: ", +			 key_conf->key, +			 key_conf->keylen); + +	switch (key_conf->cipher) { +	case WLAN_CIPHER_SUITE_WEP40: +		vif_priv->encrypt_type = WCN36XX_HAL_ED_WEP40; +		break; +	case WLAN_CIPHER_SUITE_WEP104: +		vif_priv->encrypt_type = WCN36XX_HAL_ED_WEP40; +		break; +	case WLAN_CIPHER_SUITE_CCMP: +		vif_priv->encrypt_type = WCN36XX_HAL_ED_CCMP; +		break; +	case WLAN_CIPHER_SUITE_TKIP: +		vif_priv->encrypt_type = WCN36XX_HAL_ED_TKIP; +		break; +	default: +		wcn36xx_err("Unsupported key type 0x%x\n", +			      key_conf->cipher); +		ret = -EOPNOTSUPP; +		goto out; +	} + +	switch (cmd) { +	case SET_KEY: +		if (WCN36XX_HAL_ED_TKIP == vif_priv->encrypt_type) { +			/* +			 * Supplicant is sending key in the wrong order: +			 * Temporal Key (16 b) - TX MIC (8 b) - RX MIC (8 b) +			 * but HW expects it to be in the order as described in +			 * IEEE 802.11 spec (see chapter 11.7) like this: +			 * Temporal Key (16 b) - RX MIC (8 b) - TX MIC (8 b) +			 */ +			memcpy(key, key_conf->key, 16); +			memcpy(key + 16, key_conf->key + 24, 8); +			memcpy(key + 24, key_conf->key + 16, 8); +		} else { +			memcpy(key, key_conf->key, key_conf->keylen); +		} + +		if (IEEE80211_KEY_FLAG_PAIRWISE & key_conf->flags) { +			sta_priv->is_data_encrypted = true; +			/* Reconfigure bss with encrypt_type */ +			if (NL80211_IFTYPE_STATION == vif->type) +				wcn36xx_smd_config_bss(wcn, +						       vif, +						       sta, +						       sta->addr, +						       true); + +			wcn36xx_smd_set_stakey(wcn, +				vif_priv->encrypt_type, +				key_conf->keyidx, +				key_conf->keylen, +				key, +				get_sta_index(vif, sta_priv)); +		} else { +			wcn36xx_smd_set_bsskey(wcn, +				vif_priv->encrypt_type, +				key_conf->keyidx, +				key_conf->keylen, +				key); +			if ((WLAN_CIPHER_SUITE_WEP40 == key_conf->cipher) || +			    (WLAN_CIPHER_SUITE_WEP104 == key_conf->cipher)) { +				sta_priv->is_data_encrypted = true; +				wcn36xx_smd_set_stakey(wcn, +					vif_priv->encrypt_type, +					key_conf->keyidx, +					key_conf->keylen, +					key, +					get_sta_index(vif, sta_priv)); +			} +		} +		break; +	case DISABLE_KEY: +		if (!(IEEE80211_KEY_FLAG_PAIRWISE & key_conf->flags)) { +			wcn36xx_smd_remove_bsskey(wcn, +				vif_priv->encrypt_type, +				key_conf->keyidx); +		} else { +			sta_priv->is_data_encrypted = false; +			/* do not remove key if disassociated */ +			if (sta_priv->aid) +				wcn36xx_smd_remove_stakey(wcn, +					vif_priv->encrypt_type, +					key_conf->keyidx, +					get_sta_index(vif, sta_priv)); +		} +		break; +	default: +		wcn36xx_err("Unsupported key cmd 0x%x\n", cmd); +		ret = -EOPNOTSUPP; +		goto out; +		break; +	} + +out: +	return ret; +} + +static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw) +{ +	struct wcn36xx *wcn = hw->priv; + +	wcn36xx_smd_init_scan(wcn, HAL_SYS_MODE_SCAN); +	wcn36xx_smd_start_scan(wcn); +} + +static void wcn36xx_sw_scan_complete(struct ieee80211_hw *hw) +{ +	struct wcn36xx *wcn = hw->priv; + +	wcn36xx_smd_end_scan(wcn); +	wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN); +} + +static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta, +					 enum ieee80211_band band) +{ +	int i, size; +	u16 *rates_table; +	struct wcn36xx_sta *sta_priv = (struct wcn36xx_sta *)sta->drv_priv; +	u32 rates = sta->supp_rates[band]; + +	memset(&sta_priv->supported_rates, 0, +		sizeof(sta_priv->supported_rates)); +	sta_priv->supported_rates.op_rate_mode = STA_11n; + +	size = ARRAY_SIZE(sta_priv->supported_rates.dsss_rates); +	rates_table = sta_priv->supported_rates.dsss_rates; +	if (band == IEEE80211_BAND_2GHZ) { +		for (i = 0; i < size; i++) { +			if (rates & 0x01) { +				rates_table[i] = wcn_2ghz_rates[i].hw_value; +				rates = rates >> 1; +			} +		} +	} + +	size = ARRAY_SIZE(sta_priv->supported_rates.ofdm_rates); +	rates_table = sta_priv->supported_rates.ofdm_rates; +	for (i = 0; i < size; i++) { +		if (rates & 0x01) { +			rates_table[i] = wcn_5ghz_rates[i].hw_value; +			rates = rates >> 1; +		} +	} + +	if (sta->ht_cap.ht_supported) { +		BUILD_BUG_ON(sizeof(sta->ht_cap.mcs.rx_mask) > +			sizeof(sta_priv->supported_rates.supported_mcs_set)); +		memcpy(sta_priv->supported_rates.supported_mcs_set, +		       sta->ht_cap.mcs.rx_mask, +		       sizeof(sta->ht_cap.mcs.rx_mask)); +	} +} +void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates *rates) +{ +	u16 ofdm_rates[WCN36XX_HAL_NUM_OFDM_RATES] = { +		HW_RATE_INDEX_6MBPS, +		HW_RATE_INDEX_9MBPS, +		HW_RATE_INDEX_12MBPS, +		HW_RATE_INDEX_18MBPS, +		HW_RATE_INDEX_24MBPS, +		HW_RATE_INDEX_36MBPS, +		HW_RATE_INDEX_48MBPS, +		HW_RATE_INDEX_54MBPS +	}; +	u16 dsss_rates[WCN36XX_HAL_NUM_DSSS_RATES] = { +		HW_RATE_INDEX_1MBPS, +		HW_RATE_INDEX_2MBPS, +		HW_RATE_INDEX_5_5MBPS, +		HW_RATE_INDEX_11MBPS +	}; + +	rates->op_rate_mode = STA_11n; +	memcpy(rates->dsss_rates, dsss_rates, +		sizeof(*dsss_rates) * WCN36XX_HAL_NUM_DSSS_RATES); +	memcpy(rates->ofdm_rates, ofdm_rates, +		sizeof(*ofdm_rates) * WCN36XX_HAL_NUM_OFDM_RATES); +	rates->supported_mcs_set[0] = 0xFF; +} +static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, +				     struct ieee80211_vif *vif, +				     struct ieee80211_bss_conf *bss_conf, +				     u32 changed) +{ +	struct wcn36xx *wcn = hw->priv; +	struct sk_buff *skb = NULL; +	u16 tim_off, tim_len; +	enum wcn36xx_hal_link_state link_state; +	struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; + +	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss info changed vif %p changed 0x%08x\n", +		    vif, changed); + +	if (changed & BSS_CHANGED_BEACON_INFO) { +		wcn36xx_dbg(WCN36XX_DBG_MAC, +			    "mac bss changed dtim period %d\n", +			    bss_conf->dtim_period); + +		vif_priv->dtim_period = bss_conf->dtim_period; +	} + +	if (changed & BSS_CHANGED_PS) { +		wcn36xx_dbg(WCN36XX_DBG_MAC, +			    "mac bss PS set %d\n", +			    bss_conf->ps); +		if (bss_conf->ps) { +			wcn36xx_pmc_enter_bmps_state(wcn, vif); +		} else { +			wcn36xx_pmc_exit_bmps_state(wcn, vif); +		} +	} + +	if (changed & BSS_CHANGED_BSSID) { +		wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss changed_bssid %pM\n", +			    bss_conf->bssid); + +		if (!is_zero_ether_addr(bss_conf->bssid)) { +			vif_priv->is_joining = true; +			vif_priv->bss_index = 0xff; +			wcn36xx_smd_join(wcn, bss_conf->bssid, +					 vif->addr, WCN36XX_HW_CHANNEL(wcn)); +			wcn36xx_smd_config_bss(wcn, vif, NULL, +					       bss_conf->bssid, false); +		} else { +			vif_priv->is_joining = false; +			wcn36xx_smd_delete_bss(wcn, vif); +		} +	} + +	if (changed & BSS_CHANGED_SSID) { +		wcn36xx_dbg(WCN36XX_DBG_MAC, +			    "mac bss changed ssid\n"); +		wcn36xx_dbg_dump(WCN36XX_DBG_MAC, "ssid ", +				 bss_conf->ssid, bss_conf->ssid_len); + +		vif_priv->ssid.length = bss_conf->ssid_len; +		memcpy(&vif_priv->ssid.ssid, +		       bss_conf->ssid, +		       bss_conf->ssid_len); +	} + +	if (changed & BSS_CHANGED_ASSOC) { +		vif_priv->is_joining = false; +		if (bss_conf->assoc) { +			struct ieee80211_sta *sta; +			struct wcn36xx_sta *sta_priv; + +			wcn36xx_dbg(WCN36XX_DBG_MAC, +				    "mac assoc bss %pM vif %pM AID=%d\n", +				     bss_conf->bssid, +				     vif->addr, +				     bss_conf->aid); + +			rcu_read_lock(); +			sta = ieee80211_find_sta(vif, bss_conf->bssid); +			if (!sta) { +				wcn36xx_err("sta %pM is not found\n", +					      bss_conf->bssid); +				rcu_read_unlock(); +				goto out; +			} +			sta_priv = (struct wcn36xx_sta *)sta->drv_priv; + +			wcn36xx_update_allowed_rates(sta, WCN36XX_BAND(wcn)); + +			wcn36xx_smd_set_link_st(wcn, bss_conf->bssid, +				vif->addr, +				WCN36XX_HAL_LINK_POSTASSOC_STATE); +			wcn36xx_smd_config_bss(wcn, vif, sta, +					       bss_conf->bssid, +					       true); +			sta_priv->aid = bss_conf->aid; +			/* +			 * config_sta must be called from  because this is the +			 * place where AID is available. +			 */ +			wcn36xx_smd_config_sta(wcn, vif, sta); +			rcu_read_unlock(); +		} else { +			wcn36xx_dbg(WCN36XX_DBG_MAC, +				    "disassociated bss %pM vif %pM AID=%d\n", +				    bss_conf->bssid, +				    vif->addr, +				    bss_conf->aid); +			wcn36xx_smd_set_link_st(wcn, +						bss_conf->bssid, +						vif->addr, +						WCN36XX_HAL_LINK_IDLE_STATE); +		} +	} + +	if (changed & BSS_CHANGED_AP_PROBE_RESP) { +		wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss changed ap probe resp\n"); +		skb = ieee80211_proberesp_get(hw, vif); +		if (!skb) { +			wcn36xx_err("failed to alloc probereq skb\n"); +			goto out; +		} + +		wcn36xx_smd_update_proberesp_tmpl(wcn, vif, skb); +		dev_kfree_skb(skb); +	} + +	if (changed & BSS_CHANGED_BEACON_ENABLED || +	    changed & BSS_CHANGED_BEACON) { +		wcn36xx_dbg(WCN36XX_DBG_MAC, +			    "mac bss changed beacon enabled %d\n", +			    bss_conf->enable_beacon); + +		if (bss_conf->enable_beacon) { +			vif_priv->dtim_period = bss_conf->dtim_period; +			vif_priv->bss_index = 0xff; +			wcn36xx_smd_config_bss(wcn, vif, NULL, +					       vif->addr, false); +			skb = ieee80211_beacon_get_tim(hw, vif, &tim_off, +						       &tim_len); +			if (!skb) { +				wcn36xx_err("failed to alloc beacon skb\n"); +				goto out; +			} +			wcn36xx_smd_send_beacon(wcn, vif, skb, tim_off, 0); +			dev_kfree_skb(skb); + +			if (vif->type == NL80211_IFTYPE_ADHOC || +			    vif->type == NL80211_IFTYPE_MESH_POINT) +				link_state = WCN36XX_HAL_LINK_IBSS_STATE; +			else +				link_state = WCN36XX_HAL_LINK_AP_STATE; + +			wcn36xx_smd_set_link_st(wcn, vif->addr, vif->addr, +						link_state); +		} else { +			wcn36xx_smd_set_link_st(wcn, vif->addr, vif->addr, +						WCN36XX_HAL_LINK_IDLE_STATE); +			wcn36xx_smd_delete_bss(wcn, vif); +		} +	} +out: +	return; +} + +/* this is required when using IEEE80211_HW_HAS_RATE_CONTROL */ +static int wcn36xx_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ +	struct wcn36xx *wcn = hw->priv; +	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac set RTS threshold %d\n", value); + +	wcn36xx_smd_update_cfg(wcn, WCN36XX_HAL_CFG_RTS_THRESHOLD, value); +	return 0; +} + +static void wcn36xx_remove_interface(struct ieee80211_hw *hw, +				     struct ieee80211_vif *vif) +{ +	struct wcn36xx *wcn = hw->priv; +	struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; +	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac remove interface vif %p\n", vif); + +	list_del(&vif_priv->list); +	wcn36xx_smd_delete_sta_self(wcn, vif->addr); +} + +static int wcn36xx_add_interface(struct ieee80211_hw *hw, +				 struct ieee80211_vif *vif) +{ +	struct wcn36xx *wcn = hw->priv; +	struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; + +	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac add interface vif %p type %d\n", +		    vif, vif->type); + +	if (!(NL80211_IFTYPE_STATION == vif->type || +	      NL80211_IFTYPE_AP == vif->type || +	      NL80211_IFTYPE_ADHOC == vif->type || +	      NL80211_IFTYPE_MESH_POINT == vif->type)) { +		wcn36xx_warn("Unsupported interface type requested: %d\n", +			     vif->type); +		return -EOPNOTSUPP; +	} + +	list_add(&vif_priv->list, &wcn->vif_list); +	wcn36xx_smd_add_sta_self(wcn, vif); + +	return 0; +} + +static int wcn36xx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +			   struct ieee80211_sta *sta) +{ +	struct wcn36xx *wcn = hw->priv; +	struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; +	struct wcn36xx_sta *sta_priv = (struct wcn36xx_sta *)sta->drv_priv; +	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta add vif %p sta %pM\n", +		    vif, sta->addr); + +	vif_priv->sta = sta_priv; +	sta_priv->vif = vif_priv; +	/* +	 * For STA mode HW will be configured on BSS_CHANGED_ASSOC because +	 * at this stage AID is not available yet. +	 */ +	if (NL80211_IFTYPE_STATION != vif->type) { +		wcn36xx_update_allowed_rates(sta, WCN36XX_BAND(wcn)); +		sta_priv->aid = sta->aid; +		wcn36xx_smd_config_sta(wcn, vif, sta); +	} +	return 0; +} + +static int wcn36xx_sta_remove(struct ieee80211_hw *hw, +			      struct ieee80211_vif *vif, +			      struct ieee80211_sta *sta) +{ +	struct wcn36xx *wcn = hw->priv; +	struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; +	struct wcn36xx_sta *sta_priv = (struct wcn36xx_sta *)sta->drv_priv; + +	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta remove vif %p sta %pM index %d\n", +		    vif, sta->addr, sta_priv->sta_index); + +	wcn36xx_smd_delete_sta(wcn, sta_priv->sta_index); +	vif_priv->sta = NULL; +	sta_priv->vif = NULL; +	return 0; +} + +#ifdef CONFIG_PM + +static int wcn36xx_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wow) +{ +	struct wcn36xx *wcn = hw->priv; + +	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac suspend\n"); + +	flush_workqueue(wcn->hal_ind_wq); +	wcn36xx_smd_set_power_params(wcn, true); +	return 0; +} + +static int wcn36xx_resume(struct ieee80211_hw *hw) +{ +	struct wcn36xx *wcn = hw->priv; + +	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac resume\n"); + +	flush_workqueue(wcn->hal_ind_wq); +	wcn36xx_smd_set_power_params(wcn, false); +	return 0; +} + +#endif + +static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, +		    struct ieee80211_vif *vif, +		    enum ieee80211_ampdu_mlme_action action, +		    struct ieee80211_sta *sta, u16 tid, u16 *ssn, +		    u8 buf_size) +{ +	struct wcn36xx *wcn = hw->priv; +	struct wcn36xx_sta *sta_priv = NULL; + +	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n", +		    action, tid); + +	sta_priv = (struct wcn36xx_sta *)sta->drv_priv; + +	switch (action) { +	case IEEE80211_AMPDU_RX_START: +		sta_priv->tid = tid; +		wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 0, +			get_sta_index(vif, sta_priv)); +		wcn36xx_smd_add_ba(wcn); +		wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv)); +		ieee80211_start_tx_ba_session(sta, tid, 0); +		break; +	case IEEE80211_AMPDU_RX_STOP: +		wcn36xx_smd_del_ba(wcn, tid, get_sta_index(vif, sta_priv)); +		break; +	case IEEE80211_AMPDU_TX_START: +		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); +		break; +	case IEEE80211_AMPDU_TX_OPERATIONAL: +		wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 1, +			get_sta_index(vif, sta_priv)); +		break; +	case IEEE80211_AMPDU_TX_STOP_FLUSH: +	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: +	case IEEE80211_AMPDU_TX_STOP_CONT: +		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); +		break; +	default: +		wcn36xx_err("Unknown AMPDU action\n"); +	} + +	return 0; +} + +static const struct ieee80211_ops wcn36xx_ops = { +	.start			= wcn36xx_start, +	.stop			= wcn36xx_stop, +	.add_interface		= wcn36xx_add_interface, +	.remove_interface	= wcn36xx_remove_interface, +#ifdef CONFIG_PM +	.suspend		= wcn36xx_suspend, +	.resume			= wcn36xx_resume, +#endif +	.config			= wcn36xx_config, +	.configure_filter       = wcn36xx_configure_filter, +	.tx			= wcn36xx_tx, +	.set_key		= wcn36xx_set_key, +	.sw_scan_start		= wcn36xx_sw_scan_start, +	.sw_scan_complete	= wcn36xx_sw_scan_complete, +	.bss_info_changed	= wcn36xx_bss_info_changed, +	.set_rts_threshold	= wcn36xx_set_rts_threshold, +	.sta_add		= wcn36xx_sta_add, +	.sta_remove		= wcn36xx_sta_remove, +	.ampdu_action		= wcn36xx_ampdu_action, +}; + +static int wcn36xx_init_ieee80211(struct wcn36xx *wcn) +{ +	int ret = 0; + +	static const u32 cipher_suites[] = { +		WLAN_CIPHER_SUITE_WEP40, +		WLAN_CIPHER_SUITE_WEP104, +		WLAN_CIPHER_SUITE_TKIP, +		WLAN_CIPHER_SUITE_CCMP, +	}; + +	wcn->hw->flags = IEEE80211_HW_SIGNAL_DBM | +		IEEE80211_HW_HAS_RATE_CONTROL | +		IEEE80211_HW_SUPPORTS_PS | +		IEEE80211_HW_CONNECTION_MONITOR | +		IEEE80211_HW_AMPDU_AGGREGATION | +		IEEE80211_HW_TIMING_BEACON_ONLY; + +	wcn->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | +		BIT(NL80211_IFTYPE_AP) | +		BIT(NL80211_IFTYPE_ADHOC) | +		BIT(NL80211_IFTYPE_MESH_POINT); + +	wcn->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wcn_band_2ghz; +	wcn->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wcn_band_5ghz; + +	wcn->hw->wiphy->cipher_suites = cipher_suites; +	wcn->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + +	wcn->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; + +#ifdef CONFIG_PM +	wcn->hw->wiphy->wowlan = &wowlan_support; +#endif + +	wcn->hw->max_listen_interval = 200; + +	wcn->hw->queues = 4; + +	SET_IEEE80211_DEV(wcn->hw, wcn->dev); + +	wcn->hw->sta_data_size = sizeof(struct wcn36xx_sta); +	wcn->hw->vif_data_size = sizeof(struct wcn36xx_vif); + +	return ret; +} + +static int wcn36xx_platform_get_resources(struct wcn36xx *wcn, +					  struct platform_device *pdev) +{ +	struct resource *res; +	/* Set TX IRQ */ +	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, +					   "wcnss_wlantx_irq"); +	if (!res) { +		wcn36xx_err("failed to get tx_irq\n"); +		return -ENOENT; +	} +	wcn->tx_irq = res->start; + +	/* Set RX IRQ */ +	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, +					   "wcnss_wlanrx_irq"); +	if (!res) { +		wcn36xx_err("failed to get rx_irq\n"); +		return -ENOENT; +	} +	wcn->rx_irq = res->start; + +	/* Map the memory */ +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, +						 "wcnss_mmio"); +	if (!res) { +		wcn36xx_err("failed to get mmio\n"); +		return -ENOENT; +	} +	wcn->mmio = ioremap(res->start, resource_size(res)); +	if (!wcn->mmio) { +		wcn36xx_err("failed to map io memory\n"); +		return -ENOMEM; +	} +	return 0; +} + +static int wcn36xx_probe(struct platform_device *pdev) +{ +	struct ieee80211_hw *hw; +	struct wcn36xx *wcn; +	int ret; +	u8 addr[ETH_ALEN]; + +	wcn36xx_dbg(WCN36XX_DBG_MAC, "platform probe\n"); + +	hw = ieee80211_alloc_hw(sizeof(struct wcn36xx), &wcn36xx_ops); +	if (!hw) { +		wcn36xx_err("failed to alloc hw\n"); +		ret = -ENOMEM; +		goto out_err; +	} +	platform_set_drvdata(pdev, hw); +	wcn = hw->priv; +	wcn->hw = hw; +	wcn->dev = &pdev->dev; +	wcn->ctrl_ops = pdev->dev.platform_data; + +	mutex_init(&wcn->hal_mutex); + +	if (!wcn->ctrl_ops->get_hw_mac(addr)) { +		wcn36xx_info("mac address: %pM\n", addr); +		SET_IEEE80211_PERM_ADDR(wcn->hw, addr); +	} + +	ret = wcn36xx_platform_get_resources(wcn, pdev); +	if (ret) +		goto out_wq; + +	wcn36xx_init_ieee80211(wcn); +	ret = ieee80211_register_hw(wcn->hw); +	if (ret) +		goto out_unmap; + +	return 0; + +out_unmap: +	iounmap(wcn->mmio); +out_wq: +	ieee80211_free_hw(hw); +out_err: +	return ret; +} +static int wcn36xx_remove(struct platform_device *pdev) +{ +	struct ieee80211_hw *hw = platform_get_drvdata(pdev); +	struct wcn36xx *wcn = hw->priv; +	wcn36xx_dbg(WCN36XX_DBG_MAC, "platform remove\n"); + +	release_firmware(wcn->nv); +	mutex_destroy(&wcn->hal_mutex); + +	ieee80211_unregister_hw(hw); +	iounmap(wcn->mmio); +	ieee80211_free_hw(hw); + +	return 0; +} +static const struct platform_device_id wcn36xx_platform_id_table[] = { +	{ +		.name = "wcn36xx", +		.driver_data = 0 +	}, +	{} +}; +MODULE_DEVICE_TABLE(platform, wcn36xx_platform_id_table); + +static struct platform_driver wcn36xx_driver = { +	.probe      = wcn36xx_probe, +	.remove     = wcn36xx_remove, +	.driver         = { +		.name   = "wcn36xx", +		.owner  = THIS_MODULE, +	}, +	.id_table    = wcn36xx_platform_id_table, +}; + +static int __init wcn36xx_init(void) +{ +	platform_driver_register(&wcn36xx_driver); +	return 0; +} +module_init(wcn36xx_init); + +static void __exit wcn36xx_exit(void) +{ +	platform_driver_unregister(&wcn36xx_driver); +} +module_exit(wcn36xx_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com"); +MODULE_FIRMWARE(WLAN_NV_FILE); diff --git a/drivers/net/wireless/ath/wcn36xx/pmc.c b/drivers/net/wireless/ath/wcn36xx/pmc.c new file mode 100644 index 00000000000..28b515c81b0 --- /dev/null +++ b/drivers/net/wireless/ath/wcn36xx/pmc.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com> + * + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include "wcn36xx.h" + +int wcn36xx_pmc_enter_bmps_state(struct wcn36xx *wcn, +				 struct ieee80211_vif *vif) +{ +	int ret = 0; +	struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; +	/* TODO: Make sure the TX chain clean */ +	ret = wcn36xx_smd_enter_bmps(wcn, vif); +	if (!ret) { +		wcn36xx_dbg(WCN36XX_DBG_PMC, "Entered BMPS\n"); +		vif_priv->pw_state = WCN36XX_BMPS; +	} else { +		/* +		 * One of the reasons why HW will not enter BMPS is because +		 * driver is trying to enter bmps before first beacon was +		 * received just after auth complete +		 */ +		wcn36xx_err("Can not enter BMPS!\n"); +	} +	return ret; +} + +int wcn36xx_pmc_exit_bmps_state(struct wcn36xx *wcn, +				struct ieee80211_vif *vif) +{ +	struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; + +	if (WCN36XX_BMPS != vif_priv->pw_state) { +		wcn36xx_err("Not in BMPS mode, no need to exit from BMPS mode!\n"); +		return -EINVAL; +	} +	wcn36xx_smd_exit_bmps(wcn, vif); +	vif_priv->pw_state = WCN36XX_FULL_POWER; +	return 0; +} + +int wcn36xx_enable_keep_alive_null_packet(struct wcn36xx *wcn, +					  struct ieee80211_vif *vif) +{ +	wcn36xx_dbg(WCN36XX_DBG_PMC, "%s\n", __func__); +	return wcn36xx_smd_keep_alive_req(wcn, vif, +					  WCN36XX_HAL_KEEP_ALIVE_NULL_PKT); +} diff --git a/drivers/net/wireless/ath/wcn36xx/pmc.h b/drivers/net/wireless/ath/wcn36xx/pmc.h new file mode 100644 index 00000000000..f72ed68b5a0 --- /dev/null +++ b/drivers/net/wireless/ath/wcn36xx/pmc.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com> + * + * 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 _WCN36XX_PMC_H_ +#define _WCN36XX_PMC_H_ + +struct wcn36xx; + +enum wcn36xx_power_state { +	WCN36XX_FULL_POWER, +	WCN36XX_BMPS +}; + +int wcn36xx_pmc_enter_bmps_state(struct wcn36xx *wcn, +				 struct ieee80211_vif *vif); +int wcn36xx_pmc_exit_bmps_state(struct wcn36xx *wcn, +				struct ieee80211_vif *vif); +int wcn36xx_enable_keep_alive_null_packet(struct wcn36xx *wcn, +					  struct ieee80211_vif *vif); +#endif	/* _WCN36XX_PMC_H_ */ diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c new file mode 100644 index 00000000000..63986931829 --- /dev/null +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -0,0 +1,2166 @@ +/* + * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com> + * + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/etherdevice.h> +#include <linux/firmware.h> +#include <linux/bitops.h> +#include "smd.h" + +static int put_cfg_tlv_u32(struct wcn36xx *wcn, size_t *len, u32 id, u32 value) +{ +	struct wcn36xx_hal_cfg *entry; +	u32 *val; + +	if (*len + sizeof(*entry) + sizeof(u32) >= WCN36XX_HAL_BUF_SIZE) { +		wcn36xx_err("Not enough room for TLV entry\n"); +		return -ENOMEM; +	} + +	entry = (struct wcn36xx_hal_cfg *) (wcn->hal_buf + *len); +	entry->id = id; +	entry->len = sizeof(u32); +	entry->pad_bytes = 0; +	entry->reserve = 0; + +	val = (u32 *) (entry + 1); +	*val = value; + +	*len += sizeof(*entry) + sizeof(u32); + +	return 0; +} + +static void wcn36xx_smd_set_bss_nw_type(struct wcn36xx *wcn, +		struct ieee80211_sta *sta, +		struct wcn36xx_hal_config_bss_params *bss_params) +{ +	if (IEEE80211_BAND_5GHZ == WCN36XX_BAND(wcn)) +		bss_params->nw_type = WCN36XX_HAL_11A_NW_TYPE; +	else if (sta && sta->ht_cap.ht_supported) +		bss_params->nw_type = WCN36XX_HAL_11N_NW_TYPE; +	else if (sta && (sta->supp_rates[IEEE80211_BAND_2GHZ] & 0x7f)) +		bss_params->nw_type = WCN36XX_HAL_11G_NW_TYPE; +	else +		bss_params->nw_type = WCN36XX_HAL_11B_NW_TYPE; +} + +static inline u8 is_cap_supported(unsigned long caps, unsigned long flag) +{ +	return caps & flag ? 1 : 0; +} +static void wcn36xx_smd_set_bss_ht_params(struct ieee80211_vif *vif, +		struct ieee80211_sta *sta, +		struct wcn36xx_hal_config_bss_params *bss_params) +{ +	if (sta && sta->ht_cap.ht_supported) { +		unsigned long caps = sta->ht_cap.cap; +		bss_params->ht = sta->ht_cap.ht_supported; +		bss_params->tx_channel_width_set = is_cap_supported(caps, +			IEEE80211_HT_CAP_SUP_WIDTH_20_40); +		bss_params->lsig_tx_op_protection_full_support = +			is_cap_supported(caps, +					 IEEE80211_HT_CAP_LSIG_TXOP_PROT); + +		bss_params->ht_oper_mode = vif->bss_conf.ht_operation_mode; +		bss_params->lln_non_gf_coexist = +			!!(vif->bss_conf.ht_operation_mode & +			   IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); +		/* IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT */ +		bss_params->dual_cts_protection = 0; +		/* IEEE80211_HT_OP_MODE_PROTECTION_20MHZ */ +		bss_params->ht20_coexist = 0; +	} +} + +static void wcn36xx_smd_set_sta_ht_params(struct ieee80211_sta *sta, +		struct wcn36xx_hal_config_sta_params *sta_params) +{ +	if (sta->ht_cap.ht_supported) { +		unsigned long caps = sta->ht_cap.cap; +		sta_params->ht_capable = sta->ht_cap.ht_supported; +		sta_params->tx_channel_width_set = is_cap_supported(caps, +			IEEE80211_HT_CAP_SUP_WIDTH_20_40); +		sta_params->lsig_txop_protection = is_cap_supported(caps, +			IEEE80211_HT_CAP_LSIG_TXOP_PROT); + +		sta_params->max_ampdu_size = sta->ht_cap.ampdu_factor; +		sta_params->max_ampdu_density = sta->ht_cap.ampdu_density; +		sta_params->max_amsdu_size = is_cap_supported(caps, +			IEEE80211_HT_CAP_MAX_AMSDU); +		sta_params->sgi_20Mhz = is_cap_supported(caps, +			IEEE80211_HT_CAP_SGI_20); +		sta_params->sgi_40mhz =	is_cap_supported(caps, +			IEEE80211_HT_CAP_SGI_40); +		sta_params->green_field_capable = is_cap_supported(caps, +			IEEE80211_HT_CAP_GRN_FLD); +		sta_params->delayed_ba_support = is_cap_supported(caps, +			IEEE80211_HT_CAP_DELAY_BA); +		sta_params->dsss_cck_mode_40mhz = is_cap_supported(caps, +			IEEE80211_HT_CAP_DSSSCCK40); +	} +} + +static void wcn36xx_smd_set_sta_default_ht_params( +		struct wcn36xx_hal_config_sta_params *sta_params) +{ +	sta_params->ht_capable = 1; +	sta_params->tx_channel_width_set = 1; +	sta_params->lsig_txop_protection = 1; +	sta_params->max_ampdu_size = 3; +	sta_params->max_ampdu_density = 5; +	sta_params->max_amsdu_size = 0; +	sta_params->sgi_20Mhz = 1; +	sta_params->sgi_40mhz = 1; +	sta_params->green_field_capable = 1; +	sta_params->delayed_ba_support = 0; +	sta_params->dsss_cck_mode_40mhz = 1; +} + +static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn, +		struct ieee80211_vif *vif, +		struct ieee80211_sta *sta, +		struct wcn36xx_hal_config_sta_params *sta_params) +{ +	struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv; +	struct wcn36xx_sta *priv_sta = NULL; +	if (vif->type == NL80211_IFTYPE_ADHOC || +	    vif->type == NL80211_IFTYPE_AP || +	    vif->type == NL80211_IFTYPE_MESH_POINT) { +		sta_params->type = 1; +		sta_params->sta_index = 0xFF; +	} else { +		sta_params->type = 0; +		sta_params->sta_index = 1; +	} + +	sta_params->listen_interval = WCN36XX_LISTEN_INTERVAL(wcn); + +	/* +	 * In STA mode ieee80211_sta contains bssid and ieee80211_vif +	 * contains our mac address. In  AP mode we are bssid so vif +	 * contains bssid and ieee80211_sta contains mac. +	 */ +	if (NL80211_IFTYPE_STATION == vif->type) +		memcpy(&sta_params->mac, vif->addr, ETH_ALEN); +	else +		memcpy(&sta_params->bssid, vif->addr, ETH_ALEN); + +	sta_params->encrypt_type = priv_vif->encrypt_type; +	sta_params->short_preamble_supported = +		!(WCN36XX_FLAGS(wcn) & +		  IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE); + +	sta_params->rifs_mode = 0; +	sta_params->rmf = 0; +	sta_params->action = 0; +	sta_params->uapsd = 0; +	sta_params->mimo_ps = WCN36XX_HAL_HT_MIMO_PS_STATIC; +	sta_params->max_ampdu_duration = 0; +	sta_params->bssid_index = priv_vif->bss_index; +	sta_params->p2p = 0; + +	if (sta) { +		priv_sta = (struct wcn36xx_sta *)sta->drv_priv; +		if (NL80211_IFTYPE_STATION == vif->type) +			memcpy(&sta_params->bssid, sta->addr, ETH_ALEN); +		else +			memcpy(&sta_params->mac, sta->addr, ETH_ALEN); +		sta_params->wmm_enabled = sta->wme; +		sta_params->max_sp_len = sta->max_sp; +		sta_params->aid = priv_sta->aid; +		wcn36xx_smd_set_sta_ht_params(sta, sta_params); +		memcpy(&sta_params->supported_rates, &priv_sta->supported_rates, +			sizeof(priv_sta->supported_rates)); +	} else { +		wcn36xx_set_default_rates(&sta_params->supported_rates); +		wcn36xx_smd_set_sta_default_ht_params(sta_params); +	} +} + +static int wcn36xx_smd_send_and_wait(struct wcn36xx *wcn, size_t len) +{ +	int ret = 0; +	unsigned long start; +	wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "HAL >>> ", wcn->hal_buf, len); + +	init_completion(&wcn->hal_rsp_compl); +	start = jiffies; +	ret = wcn->ctrl_ops->tx(wcn->hal_buf, len); +	if (ret) { +		wcn36xx_err("HAL TX failed\n"); +		goto out; +	} +	if (wait_for_completion_timeout(&wcn->hal_rsp_compl, +		msecs_to_jiffies(HAL_MSG_TIMEOUT)) <= 0) { +		wcn36xx_err("Timeout! No SMD response in %dms\n", +			    HAL_MSG_TIMEOUT); +		ret = -ETIME; +		goto out; +	} +	wcn36xx_dbg(WCN36XX_DBG_SMD, "SMD command completed in %dms", +		    jiffies_to_msecs(jiffies - start)); +out: +	return ret; +} + +#define INIT_HAL_MSG(msg_body, type) \ +	do {								\ +		memset(&msg_body, 0, sizeof(msg_body));			\ +		msg_body.header.msg_type = type;			\ +		msg_body.header.msg_version = WCN36XX_HAL_MSG_VERSION0; \ +		msg_body.header.len = sizeof(msg_body);			\ +	} while (0)							\ + +#define PREPARE_HAL_BUF(send_buf, msg_body) \ +	do {							\ +		memset(send_buf, 0, msg_body.header.len);	\ +		memcpy(send_buf, &msg_body, sizeof(msg_body));	\ +	} while (0)						\ + +static int wcn36xx_smd_rsp_status_check(void *buf, size_t len) +{ +	struct wcn36xx_fw_msg_status_rsp *rsp; + +	if (len < sizeof(struct wcn36xx_hal_msg_header) + +	    sizeof(struct wcn36xx_fw_msg_status_rsp)) +		return -EIO; + +	rsp = (struct wcn36xx_fw_msg_status_rsp *) +		(buf + sizeof(struct wcn36xx_hal_msg_header)); + +	if (WCN36XX_FW_MSG_RESULT_SUCCESS != rsp->status) +		return rsp->status; + +	return 0; +} + +int wcn36xx_smd_load_nv(struct wcn36xx *wcn) +{ +	struct nv_data *nv_d; +	struct wcn36xx_hal_nv_img_download_req_msg msg_body; +	int fw_bytes_left; +	int ret; +	u16 fm_offset = 0; + +	if (!wcn->nv) { +		ret = request_firmware(&wcn->nv, WLAN_NV_FILE, wcn->dev); +		if (ret) { +			wcn36xx_err("Failed to load nv file %s: %d\n", +				      WLAN_NV_FILE, ret); +			goto out; +		} +	} + +	nv_d = (struct nv_data *)wcn->nv->data; +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_DOWNLOAD_NV_REQ); + +	msg_body.header.len += WCN36XX_NV_FRAGMENT_SIZE; + +	msg_body.frag_number = 0; +	/* hal_buf must be protected with  mutex */ +	mutex_lock(&wcn->hal_mutex); + +	do { +		fw_bytes_left = wcn->nv->size - fm_offset - 4; +		if (fw_bytes_left > WCN36XX_NV_FRAGMENT_SIZE) { +			msg_body.last_fragment = 0; +			msg_body.nv_img_buffer_size = WCN36XX_NV_FRAGMENT_SIZE; +		} else { +			msg_body.last_fragment = 1; +			msg_body.nv_img_buffer_size = fw_bytes_left; + +			/* Do not forget update general message len */ +			msg_body.header.len = sizeof(msg_body) + fw_bytes_left; + +		} + +		/* Add load NV request message header */ +		memcpy(wcn->hal_buf, &msg_body,	sizeof(msg_body)); + +		/* Add NV body itself */ +		memcpy(wcn->hal_buf + sizeof(msg_body), +		       &nv_d->table + fm_offset, +		       msg_body.nv_img_buffer_size); + +		ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +		if (ret) +			goto out_unlock; +		ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, +						   wcn->hal_rsp_len); +		if (ret) { +			wcn36xx_err("hal_load_nv response failed err=%d\n", +				    ret); +			goto out_unlock; +		} +		msg_body.frag_number++; +		fm_offset += WCN36XX_NV_FRAGMENT_SIZE; + +	} while (msg_body.last_fragment != 1); + +out_unlock: +	mutex_unlock(&wcn->hal_mutex); +out:	return ret; +} + +static int wcn36xx_smd_start_rsp(struct wcn36xx *wcn, void *buf, size_t len) +{ +	struct wcn36xx_hal_mac_start_rsp_msg *rsp; + +	if (len < sizeof(*rsp)) +		return -EIO; + +	rsp = (struct wcn36xx_hal_mac_start_rsp_msg *)buf; + +	if (WCN36XX_FW_MSG_RESULT_SUCCESS != rsp->start_rsp_params.status) +		return -EIO; + +	memcpy(wcn->crm_version, rsp->start_rsp_params.crm_version, +	       WCN36XX_HAL_VERSION_LENGTH); +	memcpy(wcn->wlan_version, rsp->start_rsp_params.wlan_version, +	       WCN36XX_HAL_VERSION_LENGTH); + +	/* null terminate the strings, just in case */ +	wcn->crm_version[WCN36XX_HAL_VERSION_LENGTH] = '\0'; +	wcn->wlan_version[WCN36XX_HAL_VERSION_LENGTH] = '\0'; + +	wcn->fw_revision = rsp->start_rsp_params.version.revision; +	wcn->fw_version = rsp->start_rsp_params.version.version; +	wcn->fw_minor = rsp->start_rsp_params.version.minor; +	wcn->fw_major = rsp->start_rsp_params.version.major; + +	wcn36xx_info("firmware WLAN version '%s' and CRM version '%s'\n", +		     wcn->wlan_version, wcn->crm_version); + +	wcn36xx_info("firmware API %u.%u.%u.%u, %u stations, %u bssids\n", +		     wcn->fw_major, wcn->fw_minor, +		     wcn->fw_version, wcn->fw_revision, +		     rsp->start_rsp_params.stations, +		     rsp->start_rsp_params.bssids); + +	return 0; +} + +int wcn36xx_smd_start(struct wcn36xx *wcn) +{ +	struct wcn36xx_hal_mac_start_req_msg msg_body; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_REQ); + +	msg_body.params.type = DRIVER_TYPE_PRODUCTION; +	msg_body.params.len = 0; + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	wcn36xx_dbg(WCN36XX_DBG_HAL, "hal start type %d\n", +		    msg_body.params.type); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_start failed\n"); +		goto out; +	} + +	ret = wcn36xx_smd_start_rsp(wcn, wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_start response failed err=%d\n", ret); +		goto out; +	} + +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +int wcn36xx_smd_stop(struct wcn36xx *wcn) +{ +	struct wcn36xx_hal_mac_stop_req_msg msg_body; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_STOP_REQ); + +	msg_body.stop_req_params.reason = HAL_STOP_TYPE_RF_KILL; + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_stop failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_stop response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +int wcn36xx_smd_init_scan(struct wcn36xx *wcn, enum wcn36xx_hal_sys_mode mode) +{ +	struct wcn36xx_hal_init_scan_req_msg msg_body; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_INIT_SCAN_REQ); + +	msg_body.mode = mode; + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	wcn36xx_dbg(WCN36XX_DBG_HAL, "hal init scan mode %d\n", msg_body.mode); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_init_scan failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_init_scan response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +int wcn36xx_smd_start_scan(struct wcn36xx *wcn) +{ +	struct wcn36xx_hal_start_scan_req_msg msg_body; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_SCAN_REQ); + +	msg_body.scan_channel = WCN36XX_HW_CHANNEL(wcn); + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	wcn36xx_dbg(WCN36XX_DBG_HAL, "hal start scan channel %d\n", +		    msg_body.scan_channel); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_start_scan failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_start_scan response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +int wcn36xx_smd_end_scan(struct wcn36xx *wcn) +{ +	struct wcn36xx_hal_end_scan_req_msg msg_body; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_END_SCAN_REQ); + +	msg_body.scan_channel = WCN36XX_HW_CHANNEL(wcn); + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	wcn36xx_dbg(WCN36XX_DBG_HAL, "hal end scan channel %d\n", +		    msg_body.scan_channel); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_end_scan failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_end_scan response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +int wcn36xx_smd_finish_scan(struct wcn36xx *wcn, +			    enum wcn36xx_hal_sys_mode mode) +{ +	struct wcn36xx_hal_finish_scan_req_msg msg_body; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_FINISH_SCAN_REQ); + +	msg_body.mode = mode; + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	wcn36xx_dbg(WCN36XX_DBG_HAL, "hal finish scan mode %d\n", +		    msg_body.mode); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_finish_scan failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_finish_scan response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +static int wcn36xx_smd_switch_channel_rsp(void *buf, size_t len) +{ +	struct wcn36xx_hal_switch_channel_rsp_msg *rsp; +	int ret = 0; + +	ret = wcn36xx_smd_rsp_status_check(buf, len); +	if (ret) +		return ret; +	rsp = (struct wcn36xx_hal_switch_channel_rsp_msg *)buf; +	wcn36xx_dbg(WCN36XX_DBG_HAL, "channel switched to: %d, status: %d\n", +		    rsp->channel_number, rsp->status); +	return ret; +} + +int wcn36xx_smd_switch_channel(struct wcn36xx *wcn, +			       struct ieee80211_vif *vif, int ch) +{ +	struct wcn36xx_hal_switch_channel_req_msg msg_body; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_CH_SWITCH_REQ); + +	msg_body.channel_number = (u8)ch; +	msg_body.tx_mgmt_power = 0xbf; +	msg_body.max_tx_power = 0xbf; +	memcpy(msg_body.self_sta_mac_addr, vif->addr, ETH_ALEN); + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_switch_channel failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_switch_channel_rsp(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_switch_channel response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +static int wcn36xx_smd_update_scan_params_rsp(void *buf, size_t len) +{ +	struct wcn36xx_hal_update_scan_params_resp *rsp; + +	rsp = (struct wcn36xx_hal_update_scan_params_resp *)buf; + +	/* Remove the PNO version bit */ +	rsp->status &= (~(WCN36XX_FW_MSG_PNO_VERSION_MASK)); + +	if (WCN36XX_FW_MSG_RESULT_SUCCESS != rsp->status) { +		wcn36xx_warn("error response from update scan\n"); +		return rsp->status; +	} + +	return 0; +} + +int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn) +{ +	struct wcn36xx_hal_update_scan_params_req msg_body; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_UPDATE_SCAN_PARAM_REQ); + +	msg_body.dot11d_enabled	= 0; +	msg_body.dot11d_resolved = 0; +	msg_body.channel_count = 26; +	msg_body.active_min_ch_time = 60; +	msg_body.active_max_ch_time = 120; +	msg_body.passive_min_ch_time = 60; +	msg_body.passive_max_ch_time = 110; +	msg_body.state = 0; + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	wcn36xx_dbg(WCN36XX_DBG_HAL, +		    "hal update scan params channel_count %d\n", +		    msg_body.channel_count); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_update_scan_params failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_update_scan_params_rsp(wcn->hal_buf, +						 wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_update_scan_params response failed err=%d\n", +			    ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +static int wcn36xx_smd_add_sta_self_rsp(struct wcn36xx *wcn, +					struct ieee80211_vif *vif, +					void *buf, +					size_t len) +{ +	struct wcn36xx_hal_add_sta_self_rsp_msg *rsp; +	struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv; + +	if (len < sizeof(*rsp)) +		return -EINVAL; + +	rsp = (struct wcn36xx_hal_add_sta_self_rsp_msg *)buf; + +	if (rsp->status != WCN36XX_FW_MSG_RESULT_SUCCESS) { +		wcn36xx_warn("hal add sta self failure: %d\n", +			     rsp->status); +		return rsp->status; +	} + +	wcn36xx_dbg(WCN36XX_DBG_HAL, +		    "hal add sta self status %d self_sta_index %d dpu_index %d\n", +		    rsp->status, rsp->self_sta_index, rsp->dpu_index); + +	priv_vif->self_sta_index = rsp->self_sta_index; +	priv_vif->self_dpu_desc_index = rsp->dpu_index; + +	return 0; +} + +int wcn36xx_smd_add_sta_self(struct wcn36xx *wcn, struct ieee80211_vif *vif) +{ +	struct wcn36xx_hal_add_sta_self_req msg_body; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_ADD_STA_SELF_REQ); + +	memcpy(&msg_body.self_addr, vif->addr, ETH_ALEN); + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	wcn36xx_dbg(WCN36XX_DBG_HAL, +		    "hal add sta self self_addr %pM status %d\n", +		    msg_body.self_addr, msg_body.status); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_add_sta_self failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_add_sta_self_rsp(wcn, +					   vif, +					   wcn->hal_buf, +					   wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_add_sta_self response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +int wcn36xx_smd_delete_sta_self(struct wcn36xx *wcn, u8 *addr) +{ +	struct wcn36xx_hal_del_sta_self_req_msg msg_body; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_DEL_STA_SELF_REQ); + +	memcpy(&msg_body.self_addr, addr, ETH_ALEN); + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_delete_sta_self failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_delete_sta_self response failed err=%d\n", +			    ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +int wcn36xx_smd_delete_sta(struct wcn36xx *wcn, u8 sta_index) +{ +	struct wcn36xx_hal_delete_sta_req_msg msg_body; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_DELETE_STA_REQ); + +	msg_body.sta_index = sta_index; + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	wcn36xx_dbg(WCN36XX_DBG_HAL, +		    "hal delete sta sta_index %d\n", +		    msg_body.sta_index); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_delete_sta failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_delete_sta response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +static int wcn36xx_smd_join_rsp(void *buf, size_t len) +{ +	struct wcn36xx_hal_join_rsp_msg *rsp; + +	if (wcn36xx_smd_rsp_status_check(buf, len)) +		return -EIO; + +	rsp = (struct wcn36xx_hal_join_rsp_msg *)buf; + +	wcn36xx_dbg(WCN36XX_DBG_HAL, +		    "hal rsp join status %d tx_mgmt_power %d\n", +		    rsp->status, rsp->tx_mgmt_power); + +	return 0; +} + +int wcn36xx_smd_join(struct wcn36xx *wcn, const u8 *bssid, u8 *vif, u8 ch) +{ +	struct wcn36xx_hal_join_req_msg msg_body; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_JOIN_REQ); + +	memcpy(&msg_body.bssid, bssid, ETH_ALEN); +	memcpy(&msg_body.self_sta_mac_addr, vif, ETH_ALEN); +	msg_body.channel = ch; + +	if (conf_is_ht40_minus(&wcn->hw->conf)) +		msg_body.secondary_channel_offset = +			PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; +	else if (conf_is_ht40_plus(&wcn->hw->conf)) +		msg_body.secondary_channel_offset = +			PHY_DOUBLE_CHANNEL_LOW_PRIMARY; +	else +		msg_body.secondary_channel_offset = +			PHY_SINGLE_CHANNEL_CENTERED; + +	msg_body.link_state = WCN36XX_HAL_LINK_PREASSOC_STATE; + +	msg_body.max_tx_power = 0xbf; +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	wcn36xx_dbg(WCN36XX_DBG_HAL, +		    "hal join req bssid %pM self_sta_mac_addr %pM channel %d link_state %d\n", +		    msg_body.bssid, msg_body.self_sta_mac_addr, +		    msg_body.channel, msg_body.link_state); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_join failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_join_rsp(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_join response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +int wcn36xx_smd_set_link_st(struct wcn36xx *wcn, const u8 *bssid, +			    const u8 *sta_mac, +			    enum wcn36xx_hal_link_state state) +{ +	struct wcn36xx_hal_set_link_state_req_msg msg_body; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_SET_LINK_ST_REQ); + +	memcpy(&msg_body.bssid, bssid, ETH_ALEN); +	memcpy(&msg_body.self_mac_addr, sta_mac, ETH_ALEN); +	msg_body.state = state; + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	wcn36xx_dbg(WCN36XX_DBG_HAL, +		    "hal set link state bssid %pM self_mac_addr %pM state %d\n", +		    msg_body.bssid, msg_body.self_mac_addr, msg_body.state); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_set_link_st failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_set_link_st response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +static void wcn36xx_smd_convert_sta_to_v1(struct wcn36xx *wcn, +			const struct wcn36xx_hal_config_sta_params *orig, +			struct wcn36xx_hal_config_sta_params_v1 *v1) +{ +	/* convert orig to v1 format */ +	memcpy(&v1->bssid, orig->bssid, ETH_ALEN); +	memcpy(&v1->mac, orig->mac, ETH_ALEN); +	v1->aid = orig->aid; +	v1->type = orig->type; +	v1->listen_interval = orig->listen_interval; +	v1->ht_capable = orig->ht_capable; + +	v1->max_ampdu_size = orig->max_ampdu_size; +	v1->max_ampdu_density = orig->max_ampdu_density; +	v1->sgi_40mhz = orig->sgi_40mhz; +	v1->sgi_20Mhz = orig->sgi_20Mhz; + +	memcpy(&v1->supported_rates, &orig->supported_rates, +	       sizeof(orig->supported_rates)); +	v1->sta_index = orig->sta_index; +} + +static int wcn36xx_smd_config_sta_rsp(struct wcn36xx *wcn, +				      struct ieee80211_sta *sta, +				      void *buf, +				      size_t len) +{ +	struct wcn36xx_hal_config_sta_rsp_msg *rsp; +	struct config_sta_rsp_params *params; +	struct wcn36xx_sta *sta_priv = (struct wcn36xx_sta *)sta->drv_priv; + +	if (len < sizeof(*rsp)) +		return -EINVAL; + +	rsp = (struct wcn36xx_hal_config_sta_rsp_msg *)buf; +	params = &rsp->params; + +	if (params->status != WCN36XX_FW_MSG_RESULT_SUCCESS) { +		wcn36xx_warn("hal config sta response failure: %d\n", +			     params->status); +		return -EIO; +	} + +	sta_priv->sta_index = params->sta_index; +	sta_priv->dpu_desc_index = params->dpu_index; +	sta_priv->ucast_dpu_sign = params->uc_ucast_sig; + +	wcn36xx_dbg(WCN36XX_DBG_HAL, +		    "hal config sta rsp status %d sta_index %d bssid_index %d uc_ucast_sig %d p2p %d\n", +		    params->status, params->sta_index, params->bssid_index, +		    params->uc_ucast_sig, params->p2p); + +	return 0; +} + +static int wcn36xx_smd_config_sta_v1(struct wcn36xx *wcn, +		     const struct wcn36xx_hal_config_sta_req_msg *orig) +{ +	struct wcn36xx_hal_config_sta_req_msg_v1 msg_body; +	struct wcn36xx_hal_config_sta_params_v1 *sta = &msg_body.sta_params; + +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_CONFIG_STA_REQ); + +	wcn36xx_smd_convert_sta_to_v1(wcn, &orig->sta_params, +				      &msg_body.sta_params); + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	wcn36xx_dbg(WCN36XX_DBG_HAL, +		    "hal config sta v1 action %d sta_index %d bssid_index %d bssid %pM type %d mac %pM aid %d\n", +		    sta->action, sta->sta_index, sta->bssid_index, +		    sta->bssid, sta->type, sta->mac, sta->aid); + +	return wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +} + +int wcn36xx_smd_config_sta(struct wcn36xx *wcn, struct ieee80211_vif *vif, +			   struct ieee80211_sta *sta) +{ +	struct wcn36xx_hal_config_sta_req_msg msg; +	struct wcn36xx_hal_config_sta_params *sta_params; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg, WCN36XX_HAL_CONFIG_STA_REQ); + +	sta_params = &msg.sta_params; + +	wcn36xx_smd_set_sta_params(wcn, vif, sta, sta_params); + +	if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) { +		ret = wcn36xx_smd_config_sta_v1(wcn, &msg); +	} else { +		PREPARE_HAL_BUF(wcn->hal_buf, msg); + +		wcn36xx_dbg(WCN36XX_DBG_HAL, +			    "hal config sta action %d sta_index %d bssid_index %d bssid %pM type %d mac %pM aid %d\n", +			    sta_params->action, sta_params->sta_index, +			    sta_params->bssid_index, sta_params->bssid, +			    sta_params->type, sta_params->mac, sta_params->aid); + +		ret = wcn36xx_smd_send_and_wait(wcn, msg.header.len); +	} +	if (ret) { +		wcn36xx_err("Sending hal_config_sta failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_config_sta_rsp(wcn, +					 sta, +					 wcn->hal_buf, +					 wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_config_sta response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +static int wcn36xx_smd_config_bss_v1(struct wcn36xx *wcn, +			const struct wcn36xx_hal_config_bss_req_msg *orig) +{ +	struct wcn36xx_hal_config_bss_req_msg_v1 msg_body; +	struct wcn36xx_hal_config_bss_params_v1 *bss = &msg_body.bss_params; +	struct wcn36xx_hal_config_sta_params_v1 *sta = &bss->sta; + +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_CONFIG_BSS_REQ); + +	/* convert orig to v1 */ +	memcpy(&msg_body.bss_params.bssid, +	       &orig->bss_params.bssid, ETH_ALEN); +	memcpy(&msg_body.bss_params.self_mac_addr, +	       &orig->bss_params.self_mac_addr, ETH_ALEN); + +	msg_body.bss_params.bss_type = orig->bss_params.bss_type; +	msg_body.bss_params.oper_mode = orig->bss_params.oper_mode; +	msg_body.bss_params.nw_type = orig->bss_params.nw_type; + +	msg_body.bss_params.short_slot_time_supported = +		orig->bss_params.short_slot_time_supported; +	msg_body.bss_params.lla_coexist = orig->bss_params.lla_coexist; +	msg_body.bss_params.llb_coexist = orig->bss_params.llb_coexist; +	msg_body.bss_params.llg_coexist = orig->bss_params.llg_coexist; +	msg_body.bss_params.ht20_coexist = orig->bss_params.ht20_coexist; +	msg_body.bss_params.lln_non_gf_coexist = +		orig->bss_params.lln_non_gf_coexist; + +	msg_body.bss_params.lsig_tx_op_protection_full_support = +		orig->bss_params.lsig_tx_op_protection_full_support; +	msg_body.bss_params.rifs_mode = orig->bss_params.rifs_mode; +	msg_body.bss_params.beacon_interval = orig->bss_params.beacon_interval; +	msg_body.bss_params.dtim_period = orig->bss_params.dtim_period; +	msg_body.bss_params.tx_channel_width_set = +		orig->bss_params.tx_channel_width_set; +	msg_body.bss_params.oper_channel = orig->bss_params.oper_channel; +	msg_body.bss_params.ext_channel = orig->bss_params.ext_channel; + +	msg_body.bss_params.reserved = orig->bss_params.reserved; + +	memcpy(&msg_body.bss_params.ssid, +	       &orig->bss_params.ssid, +	       sizeof(orig->bss_params.ssid)); + +	msg_body.bss_params.action = orig->bss_params.action; +	msg_body.bss_params.rateset = orig->bss_params.rateset; +	msg_body.bss_params.ht = orig->bss_params.ht; +	msg_body.bss_params.obss_prot_enabled = +		orig->bss_params.obss_prot_enabled; +	msg_body.bss_params.rmf = orig->bss_params.rmf; +	msg_body.bss_params.ht_oper_mode = orig->bss_params.ht_oper_mode; +	msg_body.bss_params.dual_cts_protection = +		orig->bss_params.dual_cts_protection; + +	msg_body.bss_params.max_probe_resp_retry_limit = +		orig->bss_params.max_probe_resp_retry_limit; +	msg_body.bss_params.hidden_ssid = orig->bss_params.hidden_ssid; +	msg_body.bss_params.proxy_probe_resp = +		orig->bss_params.proxy_probe_resp; +	msg_body.bss_params.edca_params_valid = +		orig->bss_params.edca_params_valid; + +	memcpy(&msg_body.bss_params.acbe, +	       &orig->bss_params.acbe, +	       sizeof(orig->bss_params.acbe)); +	memcpy(&msg_body.bss_params.acbk, +	       &orig->bss_params.acbk, +	       sizeof(orig->bss_params.acbk)); +	memcpy(&msg_body.bss_params.acvi, +	       &orig->bss_params.acvi, +	       sizeof(orig->bss_params.acvi)); +	memcpy(&msg_body.bss_params.acvo, +	       &orig->bss_params.acvo, +	       sizeof(orig->bss_params.acvo)); + +	msg_body.bss_params.ext_set_sta_key_param_valid = +		orig->bss_params.ext_set_sta_key_param_valid; + +	memcpy(&msg_body.bss_params.ext_set_sta_key_param, +	       &orig->bss_params.ext_set_sta_key_param, +	       sizeof(orig->bss_params.acvo)); + +	msg_body.bss_params.wcn36xx_hal_persona = +		orig->bss_params.wcn36xx_hal_persona; +	msg_body.bss_params.spectrum_mgt_enable = +		orig->bss_params.spectrum_mgt_enable; +	msg_body.bss_params.tx_mgmt_power = orig->bss_params.tx_mgmt_power; +	msg_body.bss_params.max_tx_power = orig->bss_params.max_tx_power; + +	wcn36xx_smd_convert_sta_to_v1(wcn, &orig->bss_params.sta, +				      &msg_body.bss_params.sta); + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	wcn36xx_dbg(WCN36XX_DBG_HAL, +		    "hal config bss v1 bssid %pM self_mac_addr %pM bss_type %d oper_mode %d nw_type %d\n", +		    bss->bssid, bss->self_mac_addr, bss->bss_type, +		    bss->oper_mode, bss->nw_type); + +	wcn36xx_dbg(WCN36XX_DBG_HAL, +		    "- sta bssid %pM action %d sta_index %d bssid_index %d aid %d type %d mac %pM\n", +		    sta->bssid, sta->action, sta->sta_index, +		    sta->bssid_index, sta->aid, sta->type, sta->mac); + +	return wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +} + + +static int wcn36xx_smd_config_bss_rsp(struct wcn36xx *wcn, +				      struct ieee80211_vif *vif, +				      void *buf, +				      size_t len) +{ +	struct wcn36xx_hal_config_bss_rsp_msg *rsp; +	struct wcn36xx_hal_config_bss_rsp_params *params; +	struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv; + +	if (len < sizeof(*rsp)) +		return -EINVAL; + +	rsp = (struct wcn36xx_hal_config_bss_rsp_msg *)buf; +	params = &rsp->bss_rsp_params; + +	if (params->status != WCN36XX_FW_MSG_RESULT_SUCCESS) { +		wcn36xx_warn("hal config bss response failure: %d\n", +			     params->status); +		return -EIO; +	} + +	wcn36xx_dbg(WCN36XX_DBG_HAL, +		    "hal config bss rsp status %d bss_idx %d dpu_desc_index %d" +		    " sta_idx %d self_idx %d bcast_idx %d mac %pM" +		    " power %d ucast_dpu_signature %d\n", +		    params->status, params->bss_index, params->dpu_desc_index, +		    params->bss_sta_index, params->bss_self_sta_index, +		    params->bss_bcast_sta_idx, params->mac, +		    params->tx_mgmt_power, params->ucast_dpu_signature); + +	priv_vif->bss_index = params->bss_index; + +	if (priv_vif->sta) { +		priv_vif->sta->bss_sta_index =  params->bss_sta_index; +		priv_vif->sta->bss_dpu_desc_index = params->dpu_desc_index; +	} + +	priv_vif->self_ucast_dpu_sign = params->ucast_dpu_signature; + +	return 0; +} + +int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif, +			   struct ieee80211_sta *sta, const u8 *bssid, +			   bool update) +{ +	struct wcn36xx_hal_config_bss_req_msg msg; +	struct wcn36xx_hal_config_bss_params *bss; +	struct wcn36xx_hal_config_sta_params *sta_params; +	struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg, WCN36XX_HAL_CONFIG_BSS_REQ); + +	bss = &msg.bss_params; +	sta_params = &bss->sta; + +	WARN_ON(is_zero_ether_addr(bssid)); + +	memcpy(&bss->bssid, bssid, ETH_ALEN); + +	memcpy(bss->self_mac_addr, vif->addr, ETH_ALEN); + +	if (vif->type == NL80211_IFTYPE_STATION) { +		bss->bss_type = WCN36XX_HAL_INFRASTRUCTURE_MODE; + +		/* STA */ +		bss->oper_mode = 1; +		bss->wcn36xx_hal_persona = WCN36XX_HAL_STA_MODE; +	} else if (vif->type == NL80211_IFTYPE_AP || +		   vif->type == NL80211_IFTYPE_MESH_POINT) { +		bss->bss_type = WCN36XX_HAL_INFRA_AP_MODE; + +		/* AP */ +		bss->oper_mode = 0; +		bss->wcn36xx_hal_persona = WCN36XX_HAL_STA_SAP_MODE; +	} else if (vif->type == NL80211_IFTYPE_ADHOC) { +		bss->bss_type = WCN36XX_HAL_IBSS_MODE; + +		/* STA */ +		bss->oper_mode = 1; +	} else { +		wcn36xx_warn("Unknown type for bss config: %d\n", vif->type); +	} + +	if (vif->type == NL80211_IFTYPE_STATION) +		wcn36xx_smd_set_bss_nw_type(wcn, sta, bss); +	else +		bss->nw_type = WCN36XX_HAL_11N_NW_TYPE; + +	bss->short_slot_time_supported = vif->bss_conf.use_short_slot; +	bss->lla_coexist = 0; +	bss->llb_coexist = 0; +	bss->llg_coexist = 0; +	bss->rifs_mode = 0; +	bss->beacon_interval = vif->bss_conf.beacon_int; +	bss->dtim_period = vif_priv->dtim_period; + +	wcn36xx_smd_set_bss_ht_params(vif, sta, bss); + +	bss->oper_channel = WCN36XX_HW_CHANNEL(wcn); + +	if (conf_is_ht40_minus(&wcn->hw->conf)) +		bss->ext_channel = IEEE80211_HT_PARAM_CHA_SEC_BELOW; +	else if (conf_is_ht40_plus(&wcn->hw->conf)) +		bss->ext_channel = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; +	else +		bss->ext_channel = IEEE80211_HT_PARAM_CHA_SEC_NONE; + +	bss->reserved = 0; +	wcn36xx_smd_set_sta_params(wcn, vif, sta, sta_params); + +	/* wcn->ssid is only valid in AP and IBSS mode */ +	bss->ssid.length = vif_priv->ssid.length; +	memcpy(bss->ssid.ssid, vif_priv->ssid.ssid, vif_priv->ssid.length); + +	bss->obss_prot_enabled = 0; +	bss->rmf = 0; +	bss->max_probe_resp_retry_limit = 0; +	bss->hidden_ssid = vif->bss_conf.hidden_ssid; +	bss->proxy_probe_resp = 0; +	bss->edca_params_valid = 0; + +	/* FIXME: set acbe, acbk, acvi and acvo */ + +	bss->ext_set_sta_key_param_valid = 0; + +	/* FIXME: set ext_set_sta_key_param */ + +	bss->spectrum_mgt_enable = 0; +	bss->tx_mgmt_power = 0; +	bss->max_tx_power = WCN36XX_MAX_POWER(wcn); + +	bss->action = update; + +	wcn36xx_dbg(WCN36XX_DBG_HAL, +		    "hal config bss bssid %pM self_mac_addr %pM bss_type %d oper_mode %d nw_type %d\n", +		    bss->bssid, bss->self_mac_addr, bss->bss_type, +		    bss->oper_mode, bss->nw_type); + +	wcn36xx_dbg(WCN36XX_DBG_HAL, +		    "- sta bssid %pM action %d sta_index %d bssid_index %d aid %d type %d mac %pM\n", +		    sta_params->bssid, sta_params->action, +		    sta_params->sta_index, sta_params->bssid_index, +		    sta_params->aid, sta_params->type, +		    sta_params->mac); + +	if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) { +		ret = wcn36xx_smd_config_bss_v1(wcn, &msg); +	} else { +		PREPARE_HAL_BUF(wcn->hal_buf, msg); + +		ret = wcn36xx_smd_send_and_wait(wcn, msg.header.len); +	} +	if (ret) { +		wcn36xx_err("Sending hal_config_bss failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_config_bss_rsp(wcn, +					 vif, +					 wcn->hal_buf, +					 wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_config_bss response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +int wcn36xx_smd_delete_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif) +{ +	struct wcn36xx_hal_delete_bss_req_msg msg_body; +	struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_DELETE_BSS_REQ); + +	msg_body.bss_index = priv_vif->bss_index; + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	wcn36xx_dbg(WCN36XX_DBG_HAL, "hal delete bss %d\n", msg_body.bss_index); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_delete_bss failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_delete_bss response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct ieee80211_vif *vif, +			    struct sk_buff *skb_beacon, u16 tim_off, +			    u16 p2p_off) +{ +	struct wcn36xx_hal_send_beacon_req_msg msg_body; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_SEND_BEACON_REQ); + +	/* TODO need to find out why this is needed? */ +	msg_body.beacon_length = skb_beacon->len + 6; + +	if (BEACON_TEMPLATE_SIZE > msg_body.beacon_length) { +		memcpy(&msg_body.beacon, &skb_beacon->len, sizeof(u32)); +		memcpy(&(msg_body.beacon[4]), skb_beacon->data, +		       skb_beacon->len); +	} else { +		wcn36xx_err("Beacon is to big: beacon size=%d\n", +			      msg_body.beacon_length); +		ret = -ENOMEM; +		goto out; +	} +	memcpy(msg_body.bssid, vif->addr, ETH_ALEN); + +	/* TODO need to find out why this is needed? */ +	if (vif->type == NL80211_IFTYPE_MESH_POINT) +		/* mesh beacon don't need this, so push further down */ +		msg_body.tim_ie_offset = 256; +	else +		msg_body.tim_ie_offset = tim_off+4; +	msg_body.p2p_ie_offset = p2p_off; +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	wcn36xx_dbg(WCN36XX_DBG_HAL, +		    "hal send beacon beacon_length %d\n", +		    msg_body.beacon_length); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_send_beacon failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_send_beacon response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +int wcn36xx_smd_update_proberesp_tmpl(struct wcn36xx *wcn, +				      struct ieee80211_vif *vif, +				      struct sk_buff *skb) +{ +	struct wcn36xx_hal_send_probe_resp_req_msg msg; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg, WCN36XX_HAL_UPDATE_PROBE_RSP_TEMPLATE_REQ); + +	if (skb->len > BEACON_TEMPLATE_SIZE) { +		wcn36xx_warn("probe response template is too big: %d\n", +			     skb->len); +		ret = -E2BIG; +		goto out; +	} + +	msg.probe_resp_template_len = skb->len; +	memcpy(&msg.probe_resp_template, skb->data, skb->len); + +	memcpy(msg.bssid, vif->addr, ETH_ALEN); + +	PREPARE_HAL_BUF(wcn->hal_buf, msg); + +	wcn36xx_dbg(WCN36XX_DBG_HAL, +		    "hal update probe rsp len %d bssid %pM\n", +		    msg.probe_resp_template_len, msg.bssid); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_update_proberesp_tmpl failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_update_proberesp_tmpl response failed err=%d\n", +			    ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +int wcn36xx_smd_set_stakey(struct wcn36xx *wcn, +			   enum ani_ed_type enc_type, +			   u8 keyidx, +			   u8 keylen, +			   u8 *key, +			   u8 sta_index) +{ +	struct wcn36xx_hal_set_sta_key_req_msg msg_body; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_SET_STAKEY_REQ); + +	msg_body.set_sta_key_params.sta_index = sta_index; +	msg_body.set_sta_key_params.enc_type = enc_type; + +	msg_body.set_sta_key_params.key[0].id = keyidx; +	msg_body.set_sta_key_params.key[0].unicast = 1; +	msg_body.set_sta_key_params.key[0].direction = WCN36XX_HAL_TX_RX; +	msg_body.set_sta_key_params.key[0].pae_role = 0; +	msg_body.set_sta_key_params.key[0].length = keylen; +	memcpy(msg_body.set_sta_key_params.key[0].key, key, keylen); +	msg_body.set_sta_key_params.single_tid_rc = 1; + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_set_stakey failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_set_stakey response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +int wcn36xx_smd_set_bsskey(struct wcn36xx *wcn, +			   enum ani_ed_type enc_type, +			   u8 keyidx, +			   u8 keylen, +			   u8 *key) +{ +	struct wcn36xx_hal_set_bss_key_req_msg msg_body; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_SET_BSSKEY_REQ); +	msg_body.bss_idx = 0; +	msg_body.enc_type = enc_type; +	msg_body.num_keys = 1; +	msg_body.keys[0].id = keyidx; +	msg_body.keys[0].unicast = 0; +	msg_body.keys[0].direction = WCN36XX_HAL_RX_ONLY; +	msg_body.keys[0].pae_role = 0; +	msg_body.keys[0].length = keylen; +	memcpy(msg_body.keys[0].key, key, keylen); + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_set_bsskey failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_set_bsskey response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +int wcn36xx_smd_remove_stakey(struct wcn36xx *wcn, +			      enum ani_ed_type enc_type, +			      u8 keyidx, +			      u8 sta_index) +{ +	struct wcn36xx_hal_remove_sta_key_req_msg msg_body; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_RMV_STAKEY_REQ); + +	msg_body.sta_idx = sta_index; +	msg_body.enc_type = enc_type; +	msg_body.key_id = keyidx; + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_remove_stakey failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_remove_stakey response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +int wcn36xx_smd_remove_bsskey(struct wcn36xx *wcn, +			      enum ani_ed_type enc_type, +			      u8 keyidx) +{ +	struct wcn36xx_hal_remove_bss_key_req_msg msg_body; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_RMV_BSSKEY_REQ); +	msg_body.bss_idx = 0; +	msg_body.enc_type = enc_type; +	msg_body.key_id = keyidx; + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_remove_bsskey failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_remove_bsskey response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +int wcn36xx_smd_enter_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif) +{ +	struct wcn36xx_hal_enter_bmps_req_msg msg_body; +	struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_ENTER_BMPS_REQ); + +	msg_body.bss_index = vif_priv->bss_index; +	msg_body.tbtt = vif->bss_conf.sync_tsf; +	msg_body.dtim_period = vif_priv->dtim_period; + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_enter_bmps failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_enter_bmps response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +int wcn36xx_smd_exit_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif) +{ +	struct wcn36xx_hal_enter_bmps_req_msg msg_body; +	struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_EXIT_BMPS_REQ); + +	msg_body.bss_index = vif_priv->bss_index; + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_exit_bmps failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_exit_bmps response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} +int wcn36xx_smd_set_power_params(struct wcn36xx *wcn, bool ignore_dtim) +{ +	struct wcn36xx_hal_set_power_params_req_msg msg_body; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_SET_POWER_PARAMS_REQ); + +	/* +	 * When host is down ignore every second dtim +	 */ +	if (ignore_dtim) { +		msg_body.ignore_dtim = 1; +		msg_body.dtim_period = 2; +	} +	msg_body.listen_interval = WCN36XX_LISTEN_INTERVAL(wcn); + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_set_power_params failed\n"); +		goto out; +	} + +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} +/* Notice: This function should be called after associated, or else it + * will be invalid + */ +int wcn36xx_smd_keep_alive_req(struct wcn36xx *wcn, +			       struct ieee80211_vif *vif, +			       int packet_type) +{ +	struct wcn36xx_hal_keep_alive_req_msg msg_body; +	struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_KEEP_ALIVE_REQ); + +	if (packet_type == WCN36XX_HAL_KEEP_ALIVE_NULL_PKT) { +		msg_body.bss_index = vif_priv->bss_index; +		msg_body.packet_type = WCN36XX_HAL_KEEP_ALIVE_NULL_PKT; +		msg_body.time_period = WCN36XX_KEEP_ALIVE_TIME_PERIOD; +	} else if (packet_type == WCN36XX_HAL_KEEP_ALIVE_UNSOLICIT_ARP_RSP) { +		/* TODO: it also support ARP response type */ +	} else { +		wcn36xx_warn("unknow keep alive packet type %d\n", packet_type); +		ret = -EINVAL; +		goto out; +	} + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_keep_alive failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_keep_alive response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +int wcn36xx_smd_dump_cmd_req(struct wcn36xx *wcn, u32 arg1, u32 arg2, +			     u32 arg3, u32 arg4, u32 arg5) +{ +	struct wcn36xx_hal_dump_cmd_req_msg msg_body; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_DUMP_COMMAND_REQ); + +	msg_body.arg1 = arg1; +	msg_body.arg2 = arg2; +	msg_body.arg3 = arg3; +	msg_body.arg4 = arg4; +	msg_body.arg5 = arg5; + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_dump_cmd failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_dump_cmd response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +void set_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap) +{ +	int arr_idx, bit_idx; + +	if (cap < 0 || cap > 127) { +		wcn36xx_warn("error cap idx %d\n", cap); +		return; +	} + +	arr_idx = cap / 32; +	bit_idx = cap % 32; +	bitmap[arr_idx] |= (1 << bit_idx); +} + +int get_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap) +{ +	int arr_idx, bit_idx; +	int ret = 0; + +	if (cap < 0 || cap > 127) { +		wcn36xx_warn("error cap idx %d\n", cap); +		return -EINVAL; +	} + +	arr_idx = cap / 32; +	bit_idx = cap % 32; +	ret = (bitmap[arr_idx] & (1 << bit_idx)) ? 1 : 0; +	return ret; +} + +void clear_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap) +{ +	int arr_idx, bit_idx; + +	if (cap < 0 || cap > 127) { +		wcn36xx_warn("error cap idx %d\n", cap); +		return; +	} + +	arr_idx = cap / 32; +	bit_idx = cap % 32; +	bitmap[arr_idx] &= ~(1 << bit_idx); +} + +int wcn36xx_smd_feature_caps_exchange(struct wcn36xx *wcn) +{ +	struct wcn36xx_hal_feat_caps_msg msg_body, *rsp; +	int ret = 0, i; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_REQ); + +	set_feat_caps(msg_body.feat_caps, STA_POWERSAVE); + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_feature_caps_exchange failed\n"); +		goto out; +	} +	if (wcn->hal_rsp_len != sizeof(*rsp)) { +		wcn36xx_err("Invalid hal_feature_caps_exchange response"); +		goto out; +	} + +	rsp = (struct wcn36xx_hal_feat_caps_msg *) wcn->hal_buf; + +	for (i = 0; i < WCN36XX_HAL_CAPS_SIZE; i++) +		wcn->fw_feat_caps[i] = rsp->feat_caps[i]; +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn, +		struct ieee80211_sta *sta, +		u16 tid, +		u16 *ssn, +		u8 direction, +		u8 sta_index) +{ +	struct wcn36xx_hal_add_ba_session_req_msg msg_body; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_ADD_BA_SESSION_REQ); + +	msg_body.sta_index = sta_index; +	memcpy(&msg_body.mac_addr, sta->addr, ETH_ALEN); +	msg_body.dialog_token = 0x10; +	msg_body.tid = tid; + +	/* Immediate BA because Delayed BA is not supported */ +	msg_body.policy = 1; +	msg_body.buffer_size = WCN36XX_AGGR_BUFFER_SIZE; +	msg_body.timeout = 0; +	if (ssn) +		msg_body.ssn = *ssn; +	msg_body.direction = direction; + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_add_ba_session failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_add_ba_session response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +int wcn36xx_smd_add_ba(struct wcn36xx *wcn) +{ +	struct wcn36xx_hal_add_ba_req_msg msg_body; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_ADD_BA_REQ); + +	msg_body.session_id = 0; +	msg_body.win_size = WCN36XX_AGGR_BUFFER_SIZE; + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_add_ba failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_add_ba response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 sta_index) +{ +	struct wcn36xx_hal_del_ba_req_msg msg_body; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_DEL_BA_REQ); + +	msg_body.sta_index = sta_index; +	msg_body.tid = tid; +	msg_body.direction = 0; +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_del_ba failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_del_ba response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index) +{ +	struct wcn36xx_hal_trigger_ba_req_msg msg_body; +	struct wcn36xx_hal_trigger_ba_req_candidate *candidate; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_TRIGGER_BA_REQ); + +	msg_body.session_id = 0; +	msg_body.candidate_cnt = 1; +	msg_body.header.len += sizeof(*candidate); +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	candidate = (struct wcn36xx_hal_trigger_ba_req_candidate *) +		(wcn->hal_buf + sizeof(msg_body)); +	candidate->sta_index = sta_index; +	candidate->tid_bitmap = 1; + +	ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); +	if (ret) { +		wcn36xx_err("Sending hal_trigger_ba failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_trigger_ba response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} + +static int wcn36xx_smd_tx_compl_ind(struct wcn36xx *wcn, void *buf, size_t len) +{ +	struct wcn36xx_hal_tx_compl_ind_msg *rsp = buf; + +	if (len != sizeof(*rsp)) { +		wcn36xx_warn("Bad TX complete indication\n"); +		return -EIO; +	} + +	wcn36xx_dxe_tx_ack_ind(wcn, rsp->status); + +	return 0; +} + +static int wcn36xx_smd_missed_beacon_ind(struct wcn36xx *wcn, +					 void *buf, +					 size_t len) +{ +	struct wcn36xx_hal_missed_beacon_ind_msg *rsp = buf; +	struct ieee80211_vif *vif = NULL; +	struct wcn36xx_vif *tmp; + +	/* Old FW does not have bss index */ +	if (wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) { +		list_for_each_entry(tmp, &wcn->vif_list, list) { +			wcn36xx_dbg(WCN36XX_DBG_HAL, "beacon missed bss_index %d\n", +				    tmp->bss_index); +			vif = container_of((void *)tmp, +						 struct ieee80211_vif, +						 drv_priv); +			ieee80211_connection_loss(vif); +		} +		return 0; +	} + +	if (len != sizeof(*rsp)) { +		wcn36xx_warn("Corrupted missed beacon indication\n"); +		return -EIO; +	} + +	list_for_each_entry(tmp, &wcn->vif_list, list) { +		if (tmp->bss_index == rsp->bss_index) { +			wcn36xx_dbg(WCN36XX_DBG_HAL, "beacon missed bss_index %d\n", +				    rsp->bss_index); +			vif = container_of((void *)tmp, +						 struct ieee80211_vif, +						 drv_priv); +			ieee80211_connection_loss(vif); +			return 0; +		} +	} + +	wcn36xx_warn("BSS index %d not found\n", rsp->bss_index); +	return -ENOENT; +} + +static int wcn36xx_smd_delete_sta_context_ind(struct wcn36xx *wcn, +					      void *buf, +					      size_t len) +{ +	struct wcn36xx_hal_delete_sta_context_ind_msg *rsp = buf; +	struct wcn36xx_vif *tmp; +	struct ieee80211_sta *sta = NULL; + +	if (len != sizeof(*rsp)) { +		wcn36xx_warn("Corrupted delete sta indication\n"); +		return -EIO; +	} + +	list_for_each_entry(tmp, &wcn->vif_list, list) { +		if (sta && (tmp->sta->sta_index == rsp->sta_id)) { +			sta = container_of((void *)tmp->sta, +						 struct ieee80211_sta, +						 drv_priv); +			wcn36xx_dbg(WCN36XX_DBG_HAL, +				    "delete station indication %pM index %d\n", +				    rsp->addr2, +				    rsp->sta_id); +			ieee80211_report_low_ack(sta, 0); +			return 0; +		} +	} + +	wcn36xx_warn("STA with addr %pM and index %d not found\n", +		     rsp->addr2, +		     rsp->sta_id); +	return -ENOENT; +} + +int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value) +{ +	struct wcn36xx_hal_update_cfg_req_msg msg_body, *body; +	size_t len; +	int ret = 0; + +	mutex_lock(&wcn->hal_mutex); +	INIT_HAL_MSG(msg_body, WCN36XX_HAL_UPDATE_CFG_REQ); + +	PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + +	body = (struct wcn36xx_hal_update_cfg_req_msg *) wcn->hal_buf; +	len = msg_body.header.len; + +	put_cfg_tlv_u32(wcn, &len, cfg_id, value); +	body->header.len = len; +	body->len = len - sizeof(*body); + +	ret = wcn36xx_smd_send_and_wait(wcn, body->header.len); +	if (ret) { +		wcn36xx_err("Sending hal_update_cfg failed\n"); +		goto out; +	} +	ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); +	if (ret) { +		wcn36xx_err("hal_update_cfg response failed err=%d\n", ret); +		goto out; +	} +out: +	mutex_unlock(&wcn->hal_mutex); +	return ret; +} +static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len) +{ +	struct wcn36xx_hal_msg_header *msg_header = buf; +	struct wcn36xx_hal_ind_msg *msg_ind; +	wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "SMD <<< ", buf, len); + +	switch (msg_header->msg_type) { +	case WCN36XX_HAL_START_RSP: +	case WCN36XX_HAL_CONFIG_STA_RSP: +	case WCN36XX_HAL_CONFIG_BSS_RSP: +	case WCN36XX_HAL_ADD_STA_SELF_RSP: +	case WCN36XX_HAL_STOP_RSP: +	case WCN36XX_HAL_DEL_STA_SELF_RSP: +	case WCN36XX_HAL_DELETE_STA_RSP: +	case WCN36XX_HAL_INIT_SCAN_RSP: +	case WCN36XX_HAL_START_SCAN_RSP: +	case WCN36XX_HAL_END_SCAN_RSP: +	case WCN36XX_HAL_FINISH_SCAN_RSP: +	case WCN36XX_HAL_DOWNLOAD_NV_RSP: +	case WCN36XX_HAL_DELETE_BSS_RSP: +	case WCN36XX_HAL_SEND_BEACON_RSP: +	case WCN36XX_HAL_SET_LINK_ST_RSP: +	case WCN36XX_HAL_UPDATE_PROBE_RSP_TEMPLATE_RSP: +	case WCN36XX_HAL_SET_BSSKEY_RSP: +	case WCN36XX_HAL_SET_STAKEY_RSP: +	case WCN36XX_HAL_RMV_STAKEY_RSP: +	case WCN36XX_HAL_RMV_BSSKEY_RSP: +	case WCN36XX_HAL_ENTER_BMPS_RSP: +	case WCN36XX_HAL_SET_POWER_PARAMS_RSP: +	case WCN36XX_HAL_EXIT_BMPS_RSP: +	case WCN36XX_HAL_KEEP_ALIVE_RSP: +	case WCN36XX_HAL_DUMP_COMMAND_RSP: +	case WCN36XX_HAL_ADD_BA_SESSION_RSP: +	case WCN36XX_HAL_ADD_BA_RSP: +	case WCN36XX_HAL_DEL_BA_RSP: +	case WCN36XX_HAL_TRIGGER_BA_RSP: +	case WCN36XX_HAL_UPDATE_CFG_RSP: +	case WCN36XX_HAL_JOIN_RSP: +	case WCN36XX_HAL_UPDATE_SCAN_PARAM_RSP: +	case WCN36XX_HAL_CH_SWITCH_RSP: +	case WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_RSP: +		memcpy(wcn->hal_buf, buf, len); +		wcn->hal_rsp_len = len; +		complete(&wcn->hal_rsp_compl); +		break; + +	case WCN36XX_HAL_OTA_TX_COMPL_IND: +	case WCN36XX_HAL_MISSED_BEACON_IND: +	case WCN36XX_HAL_DELETE_STA_CONTEXT_IND: +		msg_ind = kmalloc(sizeof(*msg_ind), GFP_KERNEL); +		if (!msg_ind) +			goto nomem; +		msg_ind->msg_len = len; +		msg_ind->msg = kmemdup(buf, len, GFP_KERNEL); +		if (!msg_ind->msg) { +			kfree(msg_ind); +nomem: +			/* +			 * FIXME: Do something smarter then just +			 * printing an error. +			 */ +			wcn36xx_err("Run out of memory while handling SMD_EVENT (%d)\n", +				    msg_header->msg_type); +			break; +		} +		mutex_lock(&wcn->hal_ind_mutex); +		list_add_tail(&msg_ind->list, &wcn->hal_ind_queue); +		queue_work(wcn->hal_ind_wq, &wcn->hal_ind_work); +		mutex_unlock(&wcn->hal_ind_mutex); +		wcn36xx_dbg(WCN36XX_DBG_HAL, "indication arrived\n"); +		break; +	default: +		wcn36xx_err("SMD_EVENT (%d) not supported\n", +			      msg_header->msg_type); +	} +} +static void wcn36xx_ind_smd_work(struct work_struct *work) +{ +	struct wcn36xx *wcn = +		container_of(work, struct wcn36xx, hal_ind_work); +	struct wcn36xx_hal_msg_header *msg_header; +	struct wcn36xx_hal_ind_msg *hal_ind_msg; + +	mutex_lock(&wcn->hal_ind_mutex); + +	hal_ind_msg = list_first_entry(&wcn->hal_ind_queue, +				       struct wcn36xx_hal_ind_msg, +				       list); + +	msg_header = (struct wcn36xx_hal_msg_header *)hal_ind_msg->msg; + +	switch (msg_header->msg_type) { +	case WCN36XX_HAL_OTA_TX_COMPL_IND: +		wcn36xx_smd_tx_compl_ind(wcn, +					 hal_ind_msg->msg, +					 hal_ind_msg->msg_len); +		break; +	case WCN36XX_HAL_MISSED_BEACON_IND: +		wcn36xx_smd_missed_beacon_ind(wcn, +					      hal_ind_msg->msg, +					      hal_ind_msg->msg_len); +		break; +	case WCN36XX_HAL_DELETE_STA_CONTEXT_IND: +		wcn36xx_smd_delete_sta_context_ind(wcn, +						   hal_ind_msg->msg, +						   hal_ind_msg->msg_len); +		break; +	default: +		wcn36xx_err("SMD_EVENT (%d) not supported\n", +			      msg_header->msg_type); +	} +	list_del(wcn->hal_ind_queue.next); +	kfree(hal_ind_msg->msg); +	kfree(hal_ind_msg); +	mutex_unlock(&wcn->hal_ind_mutex); +} +int wcn36xx_smd_open(struct wcn36xx *wcn) +{ +	int ret = 0; +	wcn->hal_ind_wq = create_freezable_workqueue("wcn36xx_smd_ind"); +	if (!wcn->hal_ind_wq) { +		wcn36xx_err("failed to allocate wq\n"); +		ret = -ENOMEM; +		goto out; +	} +	INIT_WORK(&wcn->hal_ind_work, wcn36xx_ind_smd_work); +	INIT_LIST_HEAD(&wcn->hal_ind_queue); +	mutex_init(&wcn->hal_ind_mutex); + +	ret = wcn->ctrl_ops->open(wcn, wcn36xx_smd_rsp_process); +	if (ret) { +		wcn36xx_err("failed to open control channel\n"); +		goto free_wq; +	} + +	return ret; + +free_wq: +	destroy_workqueue(wcn->hal_ind_wq); +out: +	return ret; +} + +void wcn36xx_smd_close(struct wcn36xx *wcn) +{ +	wcn->ctrl_ops->close(); +	destroy_workqueue(wcn->hal_ind_wq); +	mutex_destroy(&wcn->hal_ind_mutex); +} diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h new file mode 100644 index 00000000000..008d03423db --- /dev/null +++ b/drivers/net/wireless/ath/wcn36xx/smd.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com> + * + * 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 _SMD_H_ +#define _SMD_H_ + +#include "wcn36xx.h" + +/* Max shared size is 4k but we take less.*/ +#define WCN36XX_NV_FRAGMENT_SIZE			3072 + +#define WCN36XX_HAL_BUF_SIZE				4096 + +#define HAL_MSG_TIMEOUT 500 +#define WCN36XX_SMSM_WLAN_TX_ENABLE			0x00000400 +#define WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY		0x00000200 +/* The PNO version info be contained in the rsp msg */ +#define WCN36XX_FW_MSG_PNO_VERSION_MASK			0x8000 + +enum wcn36xx_fw_msg_result { +	WCN36XX_FW_MSG_RESULT_SUCCESS			= 0, +	WCN36XX_FW_MSG_RESULT_SUCCESS_SYNC		= 1, + +	WCN36XX_FW_MSG_RESULT_MEM_FAIL			= 5, +}; + +/******************************/ +/* SMD requests and responses */ +/******************************/ +struct wcn36xx_fw_msg_status_rsp { +	u32	status; +} __packed; + +struct wcn36xx_hal_ind_msg { +	struct list_head list; +	u8 *msg; +	size_t msg_len; +}; + +struct wcn36xx; + +int wcn36xx_smd_open(struct wcn36xx *wcn); +void wcn36xx_smd_close(struct wcn36xx *wcn); + +int wcn36xx_smd_load_nv(struct wcn36xx *wcn); +int wcn36xx_smd_start(struct wcn36xx *wcn); +int wcn36xx_smd_stop(struct wcn36xx *wcn); +int wcn36xx_smd_init_scan(struct wcn36xx *wcn, enum wcn36xx_hal_sys_mode mode); +int wcn36xx_smd_start_scan(struct wcn36xx *wcn); +int wcn36xx_smd_end_scan(struct wcn36xx *wcn); +int wcn36xx_smd_finish_scan(struct wcn36xx *wcn, +			    enum wcn36xx_hal_sys_mode mode); +int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn); +int wcn36xx_smd_add_sta_self(struct wcn36xx *wcn, struct ieee80211_vif *vif); +int wcn36xx_smd_delete_sta_self(struct wcn36xx *wcn, u8 *addr); +int wcn36xx_smd_delete_sta(struct wcn36xx *wcn, u8 sta_index); +int wcn36xx_smd_join(struct wcn36xx *wcn, const u8 *bssid, u8 *vif, u8 ch); +int wcn36xx_smd_set_link_st(struct wcn36xx *wcn, const u8 *bssid, +			    const u8 *sta_mac, +			    enum wcn36xx_hal_link_state state); +int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif, +			   struct ieee80211_sta *sta, const u8 *bssid, +			   bool update); +int wcn36xx_smd_delete_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif); +int wcn36xx_smd_config_sta(struct wcn36xx *wcn, struct ieee80211_vif *vif, +			   struct ieee80211_sta *sta); +int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct ieee80211_vif *vif, +			    struct sk_buff *skb_beacon, u16 tim_off, +			    u16 p2p_off); +int wcn36xx_smd_switch_channel(struct wcn36xx *wcn, +			       struct ieee80211_vif *vif, int ch); +int wcn36xx_smd_update_proberesp_tmpl(struct wcn36xx *wcn, +				      struct ieee80211_vif *vif, +				      struct sk_buff *skb); +int wcn36xx_smd_set_stakey(struct wcn36xx *wcn, +			   enum ani_ed_type enc_type, +			   u8 keyidx, +			   u8 keylen, +			   u8 *key, +			   u8 sta_index); +int wcn36xx_smd_set_bsskey(struct wcn36xx *wcn, +			   enum ani_ed_type enc_type, +			   u8 keyidx, +			   u8 keylen, +			   u8 *key); +int wcn36xx_smd_remove_stakey(struct wcn36xx *wcn, +			      enum ani_ed_type enc_type, +			      u8 keyidx, +			      u8 sta_index); +int wcn36xx_smd_remove_bsskey(struct wcn36xx *wcn, +			      enum ani_ed_type enc_type, +			      u8 keyidx); +int wcn36xx_smd_enter_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif); +int wcn36xx_smd_exit_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif); +int wcn36xx_smd_set_power_params(struct wcn36xx *wcn, bool ignore_dtim); +int wcn36xx_smd_keep_alive_req(struct wcn36xx *wcn, +			       struct ieee80211_vif *vif, +			       int packet_type); +int wcn36xx_smd_dump_cmd_req(struct wcn36xx *wcn, u32 arg1, u32 arg2, +			     u32 arg3, u32 arg4, u32 arg5); +int wcn36xx_smd_feature_caps_exchange(struct wcn36xx *wcn); +void set_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap); +int get_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap); +void clear_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap); + +int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn, +		struct ieee80211_sta *sta, +		u16 tid, +		u16 *ssn, +		u8 direction, +		u8 sta_index); +int wcn36xx_smd_add_ba(struct wcn36xx *wcn); +int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 sta_index); +int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index); + +int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value); +#endif	/* _SMD_H_ */ diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c new file mode 100644 index 00000000000..32bb26a0db2 --- /dev/null +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com> + * + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include "txrx.h" + +static inline int get_rssi0(struct wcn36xx_rx_bd *bd) +{ +	return 100 - ((bd->phy_stat0 >> 24) & 0xff); +} + +int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) +{ +	struct ieee80211_rx_status status; +	struct ieee80211_hdr *hdr; +	struct wcn36xx_rx_bd *bd; +	u16 fc, sn; + +	/* +	 * All fields must be 0, otherwise it can lead to +	 * unexpected consequences. +	 */ +	memset(&status, 0, sizeof(status)); + +	bd = (struct wcn36xx_rx_bd *)skb->data; +	buff_to_be((u32 *)bd, sizeof(*bd)/sizeof(u32)); +	wcn36xx_dbg_dump(WCN36XX_DBG_RX_DUMP, +			 "BD   <<< ", (char *)bd, +			 sizeof(struct wcn36xx_rx_bd)); + +	skb_put(skb, bd->pdu.mpdu_header_off + bd->pdu.mpdu_len); +	skb_pull(skb, bd->pdu.mpdu_header_off); + +	status.mactime = 10; +	status.freq = WCN36XX_CENTER_FREQ(wcn); +	status.band = WCN36XX_BAND(wcn); +	status.signal = -get_rssi0(bd); +	status.antenna = 1; +	status.rate_idx = 1; +	status.flag = 0; +	status.rx_flags = 0; +	status.flag |= RX_FLAG_IV_STRIPPED | +		       RX_FLAG_MMIC_STRIPPED | +		       RX_FLAG_DECRYPTED; + +	wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%x\n", status.flag); + +	memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); + +	hdr = (struct ieee80211_hdr *) skb->data; +	fc = __le16_to_cpu(hdr->frame_control); +	sn = IEEE80211_SEQ_TO_SN(__le16_to_cpu(hdr->seq_ctrl)); + +	if (ieee80211_is_beacon(hdr->frame_control)) { +		wcn36xx_dbg(WCN36XX_DBG_BEACON, "beacon skb %p len %d fc %04x sn %d\n", +			    skb, skb->len, fc, sn); +		wcn36xx_dbg_dump(WCN36XX_DBG_BEACON_DUMP, "SKB <<< ", +				 (char *)skb->data, skb->len); +	} else { +		wcn36xx_dbg(WCN36XX_DBG_RX, "rx skb %p len %d fc %04x sn %d\n", +			    skb, skb->len, fc, sn); +		wcn36xx_dbg_dump(WCN36XX_DBG_RX_DUMP, "SKB <<< ", +				 (char *)skb->data, skb->len); +	} + +	ieee80211_rx_irqsafe(wcn->hw, skb); + +	return 0; +} + +static void wcn36xx_set_tx_pdu(struct wcn36xx_tx_bd *bd, +			       u32 mpdu_header_len, +			       u32 len, +			       u16 tid) +{ +	bd->pdu.mpdu_header_len = mpdu_header_len; +	bd->pdu.mpdu_header_off = sizeof(*bd); +	bd->pdu.mpdu_data_off = bd->pdu.mpdu_header_len + +		bd->pdu.mpdu_header_off; +	bd->pdu.mpdu_len = len; +	bd->pdu.tid = tid; +} + +static inline struct wcn36xx_vif *get_vif_by_addr(struct wcn36xx *wcn, +						  u8 *addr) +{ +	struct wcn36xx_vif *vif_priv = NULL; +	struct ieee80211_vif *vif = NULL; +	list_for_each_entry(vif_priv, &wcn->vif_list, list) { +			vif = container_of((void *)vif_priv, +				   struct ieee80211_vif, +				   drv_priv); +			if (memcmp(vif->addr, addr, ETH_ALEN) == 0) +				return vif_priv; +	} +	wcn36xx_warn("vif %pM not found\n", addr); +	return NULL; +} +static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, +				struct wcn36xx *wcn, +				struct wcn36xx_vif **vif_priv, +				struct wcn36xx_sta *sta_priv, +				struct ieee80211_hdr *hdr, +				bool bcast) +{ +	struct ieee80211_vif *vif = NULL; +	struct wcn36xx_vif *__vif_priv = NULL; +	bd->bd_rate = WCN36XX_BD_RATE_DATA; + +	/* +	 * For not unicast frames mac80211 will not set sta pointer so use +	 * self_sta_index instead. +	 */ +	if (sta_priv) { +		__vif_priv = sta_priv->vif; +		vif = container_of((void *)__vif_priv, +				   struct ieee80211_vif, +				   drv_priv); + +		bd->dpu_sign = sta_priv->ucast_dpu_sign; +		if (vif->type == NL80211_IFTYPE_STATION) { +			bd->sta_index = sta_priv->bss_sta_index; +			bd->dpu_desc_idx = sta_priv->bss_dpu_desc_index; +		} else if (vif->type == NL80211_IFTYPE_AP || +			   vif->type == NL80211_IFTYPE_ADHOC || +			   vif->type == NL80211_IFTYPE_MESH_POINT) { +			bd->sta_index = sta_priv->sta_index; +			bd->dpu_desc_idx = sta_priv->dpu_desc_index; +		} +	} else { +		__vif_priv = get_vif_by_addr(wcn, hdr->addr2); +		bd->sta_index = __vif_priv->self_sta_index; +		bd->dpu_desc_idx = __vif_priv->self_dpu_desc_index; +		bd->dpu_sign = __vif_priv->self_ucast_dpu_sign; +	} + +	if (ieee80211_is_nullfunc(hdr->frame_control) || +	   (sta_priv && !sta_priv->is_data_encrypted)) +		bd->dpu_ne = 1; + +	if (bcast) { +		bd->ub = 1; +		bd->ack_policy = 1; +	} +	*vif_priv = __vif_priv; +} + +static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd, +				struct wcn36xx *wcn, +				struct wcn36xx_vif **vif_priv, +				struct ieee80211_hdr *hdr, +				bool bcast) +{ +	struct wcn36xx_vif *__vif_priv = +		get_vif_by_addr(wcn, hdr->addr2); +	bd->sta_index = __vif_priv->self_sta_index; +	bd->dpu_desc_idx = __vif_priv->self_dpu_desc_index; +	bd->dpu_ne = 1; + +	/* default rate for unicast */ +	if (ieee80211_is_mgmt(hdr->frame_control)) +		bd->bd_rate = (WCN36XX_BAND(wcn) == IEEE80211_BAND_5GHZ) ? +			WCN36XX_BD_RATE_CTRL : +			WCN36XX_BD_RATE_MGMT; +	else if (ieee80211_is_ctl(hdr->frame_control)) +		bd->bd_rate = WCN36XX_BD_RATE_CTRL; +	else +		wcn36xx_warn("frame control type unknown\n"); + +	/* +	 * In joining state trick hardware that probe is sent as +	 * unicast even if address is broadcast. +	 */ +	if (__vif_priv->is_joining && +	    ieee80211_is_probe_req(hdr->frame_control)) +		bcast = false; + +	if (bcast) { +		/* broadcast */ +		bd->ub = 1; +		/* No ack needed not unicast */ +		bd->ack_policy = 1; +		bd->queue_id = WCN36XX_TX_B_WQ_ID; +	} else +		bd->queue_id = WCN36XX_TX_U_WQ_ID; +	*vif_priv = __vif_priv; +} + +int wcn36xx_start_tx(struct wcn36xx *wcn, +		     struct wcn36xx_sta *sta_priv, +		     struct sk_buff *skb) +{ +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; +	struct wcn36xx_vif *vif_priv = NULL; +	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); +	unsigned long flags; +	bool is_low = ieee80211_is_data(hdr->frame_control); +	bool bcast = is_broadcast_ether_addr(hdr->addr1) || +		is_multicast_ether_addr(hdr->addr1); +	struct wcn36xx_tx_bd *bd = wcn36xx_dxe_get_next_bd(wcn, is_low); + +	if (!bd) { +		/* +		 * TX DXE are used in pairs. One for the BD and one for the +		 * actual frame. The BD DXE's has a preallocated buffer while +		 * the skb ones does not. If this isn't true something is really +		 * wierd. TODO: Recover from this situation +		 */ + +		wcn36xx_err("bd address may not be NULL for BD DXE\n"); +		return -EINVAL; +	} + +	memset(bd, 0, sizeof(*bd)); + +	wcn36xx_dbg(WCN36XX_DBG_TX, +		    "tx skb %p len %d fc %04x sn %d %s %s\n", +		    skb, skb->len, __le16_to_cpu(hdr->frame_control), +		    IEEE80211_SEQ_TO_SN(__le16_to_cpu(hdr->seq_ctrl)), +		    is_low ? "low" : "high", bcast ? "bcast" : "ucast"); + +	wcn36xx_dbg_dump(WCN36XX_DBG_TX_DUMP, "", skb->data, skb->len); + +	bd->dpu_rf = WCN36XX_BMU_WQ_TX; + +	bd->tx_comp = info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS; +	if (bd->tx_comp) { +		wcn36xx_dbg(WCN36XX_DBG_DXE, "TX_ACK status requested\n"); +		spin_lock_irqsave(&wcn->dxe_lock, flags); +		if (wcn->tx_ack_skb) { +			spin_unlock_irqrestore(&wcn->dxe_lock, flags); +			wcn36xx_warn("tx_ack_skb already set\n"); +			return -EINVAL; +		} + +		wcn->tx_ack_skb = skb; +		spin_unlock_irqrestore(&wcn->dxe_lock, flags); + +		/* Only one at a time is supported by fw. Stop the TX queues +		 * until the ack status gets back. +		 * +		 * TODO: Add watchdog in case FW does not answer +		 */ +		ieee80211_stop_queues(wcn->hw); +	} + +	/* Data frames served first*/ +	if (is_low) { +		wcn36xx_set_tx_data(bd, wcn, &vif_priv, sta_priv, hdr, bcast); +		wcn36xx_set_tx_pdu(bd, +			   ieee80211_is_data_qos(hdr->frame_control) ? +			   sizeof(struct ieee80211_qos_hdr) : +			   sizeof(struct ieee80211_hdr_3addr), +			   skb->len, sta_priv ? sta_priv->tid : 0); +	} else { +		/* MGMT and CTRL frames are handeld here*/ +		wcn36xx_set_tx_mgmt(bd, wcn, &vif_priv, hdr, bcast); +		wcn36xx_set_tx_pdu(bd, +			   ieee80211_is_data_qos(hdr->frame_control) ? +			   sizeof(struct ieee80211_qos_hdr) : +			   sizeof(struct ieee80211_hdr_3addr), +			   skb->len, WCN36XX_TID); +	} + +	buff_to_be((u32 *)bd, sizeof(*bd)/sizeof(u32)); +	bd->tx_bd_sign = 0xbdbdbdbd; + +	return wcn36xx_dxe_tx_frame(wcn, vif_priv, skb, is_low); +} diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.h b/drivers/net/wireless/ath/wcn36xx/txrx.h new file mode 100644 index 00000000000..bbfbcf808c7 --- /dev/null +++ b/drivers/net/wireless/ath/wcn36xx/txrx.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com> + * + * 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 <linux/etherdevice.h> +#include "wcn36xx.h" + +/* TODO describe all properties */ +#define WCN36XX_802_11_HEADER_LEN	24 +#define WCN36XX_BMU_WQ_TX		25 +#define WCN36XX_TID			7 +/* broadcast wq ID */ +#define WCN36XX_TX_B_WQ_ID		0xA +#define WCN36XX_TX_U_WQ_ID		0x9 +/* bd_rate */ +#define WCN36XX_BD_RATE_DATA 0 +#define WCN36XX_BD_RATE_MGMT 2 +#define WCN36XX_BD_RATE_CTRL 3 + +struct wcn36xx_pdu { +	u32	dpu_fb:8; +	u32	adu_fb:8; +	u32	pdu_id:16; + +	/* 0x04*/ +	u32	tail_pdu_idx:16; +	u32	head_pdu_idx:16; + +	/* 0x08*/ +	u32	pdu_count:7; +	u32	mpdu_data_off:9; +	u32	mpdu_header_off:8; +	u32	mpdu_header_len:8; + +	/* 0x0c*/ +	u32	reserved4:8; +	u32	tid:4; +	u32	reserved3:4; +	u32	mpdu_len:16; +}; + +struct wcn36xx_rx_bd { +	u32	bdt:2; +	u32	ft:1; +	u32	dpu_ne:1; +	u32	rx_key_id:3; +	u32	ub:1; +	u32	rmf:1; +	u32	uma_bypass:1; +	u32	csr11:1; +	u32	reserved0:1; +	u32	scan_learn:1; +	u32	rx_ch:4; +	u32	rtsf:1; +	u32	bsf:1; +	u32	a2hf:1; +	u32	st_auf:1; +	u32	dpu_sign:3; +	u32	dpu_rf:8; + +	struct wcn36xx_pdu pdu; + +	/* 0x14*/ +	u32	addr3:8; +	u32	addr2:8; +	u32	addr1:8; +	u32	dpu_desc_idx:8; + +	/* 0x18*/ +	u32	rxp_flags:23; +	u32	rate_id:9; + +	u32	phy_stat0; +	u32	phy_stat1; + +	/* 0x24 */ +	u32	rx_times; + +	u32	pmi_cmd[6]; + +	/* 0x40 */ +	u32	reserved7:4; +	u32	reorder_slot_id:6; +	u32	reorder_fwd_id:6; +	u32	reserved6:12; +	u32	reorder_code:4; + +	/* 0x44 */ +	u32	exp_seq_num:12; +	u32	cur_seq_num:12; +	u32	fr_type_subtype:8; + +	/* 0x48 */ +	u32	msdu_size:16; +	u32	sub_fr_id:4; +	u32	proc_order:4; +	u32	reserved9:4; +	u32	aef:1; +	u32	lsf:1; +	u32	esf:1; +	u32	asf:1; +}; + +struct wcn36xx_tx_bd { +	u32	bdt:2; +	u32	ft:1; +	u32	dpu_ne:1; +	u32	fw_tx_comp:1; +	u32	tx_comp:1; +	u32	reserved1:1; +	u32	ub:1; +	u32	rmf:1; +	u32	reserved0:12; +	u32	dpu_sign:3; +	u32	dpu_rf:8; + +	struct wcn36xx_pdu pdu; + +	/* 0x14*/ +	u32	reserved5:7; +	u32	queue_id:5; +	u32	bd_rate:2; +	u32	ack_policy:2; +	u32	sta_index:8; +	u32	dpu_desc_idx:8; + +	u32	tx_bd_sign; +	u32	reserved6; +	u32	dxe_start_time; +	u32	dxe_end_time; + +	/*u32	tcp_udp_start_off:10; +	u32	header_cks:16; +	u32	reserved7:6;*/ +}; + +struct wcn36xx_sta; +struct wcn36xx; + +int  wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb); +int wcn36xx_start_tx(struct wcn36xx *wcn, +		     struct wcn36xx_sta *sta_priv, +		     struct sk_buff *skb); + +#endif	/* _TXRX_H_ */ diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h new file mode 100644 index 00000000000..f0fb81dfd17 --- /dev/null +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com> + * + * 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 _WCN36XX_H_ +#define _WCN36XX_H_ + +#include <linux/completion.h> +#include <linux/printk.h> +#include <linux/spinlock.h> +#include <net/mac80211.h> + +#include "hal.h" +#include "smd.h" +#include "txrx.h" +#include "dxe.h" +#include "pmc.h" +#include "debug.h" + +#define WLAN_NV_FILE               "wlan/prima/WCNSS_qcom_wlan_nv.bin" +#define WCN36XX_AGGR_BUFFER_SIZE 64 + +extern unsigned int wcn36xx_dbg_mask; + +enum wcn36xx_debug_mask { +	WCN36XX_DBG_DXE		= 0x00000001, +	WCN36XX_DBG_DXE_DUMP	= 0x00000002, +	WCN36XX_DBG_SMD		= 0x00000004, +	WCN36XX_DBG_SMD_DUMP	= 0x00000008, +	WCN36XX_DBG_RX		= 0x00000010, +	WCN36XX_DBG_RX_DUMP	= 0x00000020, +	WCN36XX_DBG_TX		= 0x00000040, +	WCN36XX_DBG_TX_DUMP	= 0x00000080, +	WCN36XX_DBG_HAL		= 0x00000100, +	WCN36XX_DBG_HAL_DUMP	= 0x00000200, +	WCN36XX_DBG_MAC		= 0x00000400, +	WCN36XX_DBG_BEACON	= 0x00000800, +	WCN36XX_DBG_BEACON_DUMP	= 0x00001000, +	WCN36XX_DBG_PMC		= 0x00002000, +	WCN36XX_DBG_PMC_DUMP	= 0x00004000, +	WCN36XX_DBG_ANY		= 0xffffffff, +}; + +#define wcn36xx_err(fmt, arg...)				\ +	printk(KERN_ERR pr_fmt("ERROR " fmt), ##arg) + +#define wcn36xx_warn(fmt, arg...)				\ +	printk(KERN_WARNING pr_fmt("WARNING " fmt), ##arg) + +#define wcn36xx_info(fmt, arg...)		\ +	printk(KERN_INFO pr_fmt(fmt), ##arg) + +#define wcn36xx_dbg(mask, fmt, arg...) do {			\ +	if (wcn36xx_dbg_mask & mask)					\ +		printk(KERN_DEBUG pr_fmt(fmt), ##arg);	\ +} while (0) + +#define wcn36xx_dbg_dump(mask, prefix_str, buf, len) do {	\ +	if (wcn36xx_dbg_mask & mask)					\ +		print_hex_dump(KERN_DEBUG, pr_fmt(prefix_str),	\ +			       DUMP_PREFIX_OFFSET, 32, 1,	\ +			       buf, len, false);		\ +} while (0) + +#define WCN36XX_HW_CHANNEL(__wcn) (__wcn->hw->conf.chandef.chan->hw_value) +#define WCN36XX_BAND(__wcn) (__wcn->hw->conf.chandef.chan->band) +#define WCN36XX_CENTER_FREQ(__wcn) (__wcn->hw->conf.chandef.chan->center_freq) +#define WCN36XX_LISTEN_INTERVAL(__wcn) (__wcn->hw->conf.listen_interval) +#define WCN36XX_FLAGS(__wcn) (__wcn->hw->flags) +#define WCN36XX_MAX_POWER(__wcn) (__wcn->hw->conf.chandef.chan->max_power) + +static inline void buff_to_be(u32 *buf, size_t len) +{ +	int i; +	for (i = 0; i < len; i++) +		buf[i] = cpu_to_be32(buf[i]); +} + +struct nv_data { +	int	is_valid; +	u8	table; +}; + +/* Interface for platform control path + * + * @open: hook must be called when wcn36xx wants to open control channel. + * @tx: sends a buffer. + */ +struct wcn36xx_platform_ctrl_ops { +	int (*open)(void *drv_priv, void *rsp_cb); +	void (*close)(void); +	int (*tx)(char *buf, size_t len); +	int (*get_hw_mac)(u8 *addr); +	int (*smsm_change_state)(u32 clear_mask, u32 set_mask); +}; + +/** + * struct wcn36xx_vif - holds VIF related fields + * + * @bss_index: bss_index is initially set to 0xFF. bss_index is received from + * HW after first config_bss call and must be used in delete_bss and + * enter/exit_bmps. + */ +struct wcn36xx_vif { +	struct list_head list; +	struct wcn36xx_sta *sta; +	u8 dtim_period; +	enum ani_ed_type encrypt_type; +	bool is_joining; +	struct wcn36xx_hal_mac_ssid ssid; + +	/* Power management */ +	enum wcn36xx_power_state pw_state; + +	u8 bss_index; +	/* Returned from WCN36XX_HAL_ADD_STA_SELF_RSP */ +	u8 self_sta_index; +	u8 self_dpu_desc_index; +	u8 self_ucast_dpu_sign; +}; + +/** + * struct wcn36xx_sta - holds STA related fields + * + * @tid: traffic ID that is used during AMPDU and in TX BD. + * @sta_index: STA index is returned from HW after config_sta call and is + * used in both SMD channel and TX BD. + * @dpu_desc_index: DPU descriptor index is returned from HW after config_sta + * call and is used in TX BD. + * @bss_sta_index: STA index is returned from HW after config_bss call and is + * used in both SMD channel and TX BD. See table bellow when it is used. + * @bss_dpu_desc_index: DPU descriptor index is returned from HW after + * config_bss call and is used in TX BD. + * ______________________________________________ + * |		  |	STA	|	AP	| + * |______________|_____________|_______________| + * |    TX BD     |bss_sta_index|   sta_index   | + * |______________|_____________|_______________| + * |all SMD calls |bss_sta_index|   sta_index	| + * |______________|_____________|_______________| + * |smd_delete_sta|  sta_index  |   sta_index	| + * |______________|_____________|_______________| + */ +struct wcn36xx_sta { +	struct wcn36xx_vif *vif; +	u16 aid; +	u16 tid; +	u8 sta_index; +	u8 dpu_desc_index; +	u8 ucast_dpu_sign; +	u8 bss_sta_index; +	u8 bss_dpu_desc_index; +	bool is_data_encrypted; +	/* Rates */ +	struct wcn36xx_hal_supported_rates supported_rates; +}; +struct wcn36xx_dxe_ch; +struct wcn36xx { +	struct ieee80211_hw	*hw; +	struct device		*dev; +	struct list_head	vif_list; + +	const struct firmware	*nv; + +	u8			fw_revision; +	u8			fw_version; +	u8			fw_minor; +	u8			fw_major; +	u32			fw_feat_caps[WCN36XX_HAL_CAPS_SIZE]; +	u32			chip_version; + +	/* extra byte for the NULL termination */ +	u8			crm_version[WCN36XX_HAL_VERSION_LENGTH + 1]; +	u8			wlan_version[WCN36XX_HAL_VERSION_LENGTH + 1]; + +	/* IRQs */ +	int			tx_irq; +	int			rx_irq; +	void __iomem		*mmio; + +	struct wcn36xx_platform_ctrl_ops *ctrl_ops; +	/* +	 * smd_buf must be protected with smd_mutex to garantee +	 * that all messages are sent one after another +	 */ +	u8			*hal_buf; +	size_t			hal_rsp_len; +	struct mutex		hal_mutex; +	struct completion	hal_rsp_compl; +	struct workqueue_struct	*hal_ind_wq; +	struct work_struct	hal_ind_work; +	struct mutex		hal_ind_mutex; +	struct list_head	hal_ind_queue; + +	/* DXE channels */ +	struct wcn36xx_dxe_ch	dxe_tx_l_ch;	/* TX low */ +	struct wcn36xx_dxe_ch	dxe_tx_h_ch;	/* TX high */ +	struct wcn36xx_dxe_ch	dxe_rx_l_ch;	/* RX low */ +	struct wcn36xx_dxe_ch	dxe_rx_h_ch;	/* RX high */ + +	/* For synchronization of DXE resources from BH, IRQ and WQ contexts */ +	spinlock_t	dxe_lock; +	bool                    queues_stopped; + +	/* Memory pools */ +	struct wcn36xx_dxe_mem_pool mgmt_mem_pool; +	struct wcn36xx_dxe_mem_pool data_mem_pool; + +	struct sk_buff		*tx_ack_skb; + +#ifdef CONFIG_WCN36XX_DEBUGFS +	/* Debug file system entry */ +	struct wcn36xx_dfs_entry    dfs; +#endif /* CONFIG_WCN36XX_DEBUGFS */ + +}; + +#define WCN36XX_CHIP_3660	0 +#define WCN36XX_CHIP_3680	1 + +static inline bool wcn36xx_is_fw_version(struct wcn36xx *wcn, +					 u8 major, +					 u8 minor, +					 u8 version, +					 u8 revision) +{ +	return (wcn->fw_major == major && +		wcn->fw_minor == minor && +		wcn->fw_version == version && +		wcn->fw_revision == revision); +} +void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates *rates); + +#endif	/* _WCN36XX_H_ */ diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile index 990dd42ae79..c7a3465fd02 100644 --- a/drivers/net/wireless/ath/wil6210/Makefile +++ b/drivers/net/wireless/ath/wil6210/Makefile @@ -9,6 +9,7 @@ wil6210-y += wmi.o  wil6210-y += interrupt.o  wil6210-y += txrx.o  wil6210-y += debug.o +wil6210-y += rx_reorder.o  wil6210-$(CONFIG_WIL6210_TRACING) += trace.o  # for tracing framework to find trace.h diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 61c302a6bde..820d4ebd932 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -104,41 +104,125 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type)  	return -EOPNOTSUPP;  } -static int wil_cfg80211_get_station(struct wiphy *wiphy, -				    struct net_device *ndev, -				    u8 *mac, struct station_info *sinfo) +static int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, +			      struct station_info *sinfo)  { -	struct wil6210_priv *wil = wiphy_to_wil(wiphy); -	int rc;  	struct wmi_notify_req_cmd cmd = { -		.cid = 0, +		.cid = cid,  		.interval_usec = 0,  	}; +	struct { +		struct wil6210_mbox_hdr_wmi wmi; +		struct wmi_notify_req_done_event evt; +	} __packed reply; +	struct wil_net_stats *stats = &wil->sta[cid].stats; +	int rc; -	if (memcmp(mac, wil->dst_addr[0], ETH_ALEN)) -		return -ENOENT; - -	/* WMI_NOTIFY_REQ_DONE_EVENTID handler fills wil->stats.bf_mcs */  	rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd), -		      WMI_NOTIFY_REQ_DONE_EVENTID, NULL, 0, 20); +		      WMI_NOTIFY_REQ_DONE_EVENTID, &reply, sizeof(reply), 20);  	if (rc)  		return rc; +	wil_dbg_wmi(wil, "Link status for CID %d: {\n" +		    "  MCS %d TSF 0x%016llx\n" +		    "  BF status 0x%08x SNR 0x%08x SQI %d%%\n" +		    "  Tx Tpt %d goodput %d Rx goodput %d\n" +		    "  Sectors(rx:tx) my %d:%d peer %d:%d\n""}\n", +		    cid, le16_to_cpu(reply.evt.bf_mcs), +		    le64_to_cpu(reply.evt.tsf), reply.evt.status, +		    le32_to_cpu(reply.evt.snr_val), +		    reply.evt.sqi, +		    le32_to_cpu(reply.evt.tx_tpt), +		    le32_to_cpu(reply.evt.tx_goodput), +		    le32_to_cpu(reply.evt.rx_goodput), +		    le16_to_cpu(reply.evt.my_rx_sector), +		    le16_to_cpu(reply.evt.my_tx_sector), +		    le16_to_cpu(reply.evt.other_rx_sector), +		    le16_to_cpu(reply.evt.other_tx_sector)); +  	sinfo->generation = wil->sinfo_gen; -	sinfo->filled |= STATION_INFO_TX_BITRATE; +	sinfo->filled = STATION_INFO_RX_BYTES | +			STATION_INFO_TX_BYTES | +			STATION_INFO_RX_PACKETS | +			STATION_INFO_TX_PACKETS | +			STATION_INFO_RX_BITRATE | +			STATION_INFO_TX_BITRATE | +			STATION_INFO_RX_DROP_MISC | +			STATION_INFO_TX_FAILED; +  	sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; -	sinfo->txrate.mcs = wil->stats.bf_mcs; -	sinfo->filled |= STATION_INFO_RX_BITRATE; +	sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs);  	sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; -	sinfo->rxrate.mcs = wil->stats.last_mcs_rx; +	sinfo->rxrate.mcs = stats->last_mcs_rx; +	sinfo->rx_bytes = stats->rx_bytes; +	sinfo->rx_packets = stats->rx_packets; +	sinfo->rx_dropped_misc = stats->rx_dropped; +	sinfo->tx_bytes = stats->tx_bytes; +	sinfo->tx_packets = stats->tx_packets; +	sinfo->tx_failed = stats->tx_errors;  	if (test_bit(wil_status_fwconnected, &wil->status)) {  		sinfo->filled |= STATION_INFO_SIGNAL; -		sinfo->signal = 12; /* TODO: provide real value */ +		sinfo->signal = reply.evt.sqi;  	} -	return 0; +	return rc; +} + +static int wil_cfg80211_get_station(struct wiphy *wiphy, +				    struct net_device *ndev, +				    const u8 *mac, struct station_info *sinfo) +{ +	struct wil6210_priv *wil = wiphy_to_wil(wiphy); +	int rc; + +	int cid = wil_find_cid(wil, mac); + +	wil_dbg_misc(wil, "%s(%pM) CID %d\n", __func__, mac, cid); +	if (cid < 0) +		return cid; + +	rc = wil_cid_fill_sinfo(wil, cid, sinfo); + +	return rc; +} + +/* + * Find @idx-th active STA for station dump. + */ +static int wil_find_cid_by_idx(struct wil6210_priv *wil, int idx) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { +		if (wil->sta[i].status == wil_sta_unused) +			continue; +		if (idx == 0) +			return i; +		idx--; +	} + +	return -ENOENT; +} + +static int wil_cfg80211_dump_station(struct wiphy *wiphy, +				     struct net_device *dev, int idx, +				     u8 *mac, struct station_info *sinfo) +{ +	struct wil6210_priv *wil = wiphy_to_wil(wiphy); +	int rc; +	int cid = wil_find_cid_by_idx(wil, idx); + +	if (cid < 0) +		return -ENOENT; + +	memcpy(mac, wil->sta[cid].addr, ETH_ALEN); +	wil_dbg_misc(wil, "%s(%pM) CID %d\n", __func__, mac, cid); + +	rc = wil_cid_fill_sinfo(wil, cid, sinfo); + +	return rc;  }  static int wil_cfg80211_change_iface(struct wiphy *wiphy, @@ -181,6 +265,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,  		u16 chnl[4];  	} __packed cmd;  	uint i, n; +	int rc;  	if (wil->scan_request) {  		wil_err(wil, "Already scanning\n"); @@ -198,11 +283,12 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,  	/* FW don't support scan after connection attempt */  	if (test_bit(wil_status_dontscan, &wil->status)) { -		wil_err(wil, "Scan after connect attempt not supported\n"); +		wil_err(wil, "Can't scan now\n");  		return -EBUSY;  	}  	wil->scan_request = request; +	mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO);  	memset(&cmd, 0, sizeof(cmd));  	cmd.cmd.num_channels = 0; @@ -221,8 +307,13 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,  			     request->channels[i]->center_freq);  	} -	return wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + +	rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +  			cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0])); + +	if (rc) +		wil->scan_request = NULL; + +	return rc;  }  static int wil_cfg80211_connect(struct wiphy *wiphy, @@ -237,6 +328,10 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,  	int ch;  	int rc = 0; +	if (test_bit(wil_status_fwconnecting, &wil->status) || +	    test_bit(wil_status_fwconnected, &wil->status)) +		return -EALREADY; +  	bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,  			       sme->ssid, sme->ssid_len,  			       WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); @@ -316,12 +411,9 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,  	}  	conn.channel = ch - 1; -	memcpy(conn.bssid, bss->bssid, 6); -	memcpy(conn.dst_mac, bss->bssid, 6); -	/* -	 * FW don't support scan after connection attempt -	 */ -	set_bit(wil_status_dontscan, &wil->status); +	memcpy(conn.bssid, bss->bssid, ETH_ALEN); +	memcpy(conn.dst_mac, bss->bssid, ETH_ALEN); +  	set_bit(wil_status_fwconnecting, &wil->status);  	rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn)); @@ -330,7 +422,6 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,  		mod_timer(&wil->connect_timer,  			  jiffies + msecs_to_jiffies(2000));  	} else { -		clear_bit(wil_status_dontscan, &wil->status);  		clear_bit(wil_status_fwconnecting, &wil->status);  	} @@ -352,6 +443,40 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy,  	return rc;  } +static int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, +				struct wireless_dev *wdev, +				struct cfg80211_mgmt_tx_params *params, +				u64 *cookie) +{ +	const u8 *buf = params->buf; +	size_t len = params->len; +	struct wil6210_priv *wil = wiphy_to_wil(wiphy); +	int rc; +	struct ieee80211_mgmt *mgmt_frame = (void *)buf; +	struct wmi_sw_tx_req_cmd *cmd; +	struct { +		struct wil6210_mbox_hdr_wmi wmi; +		struct wmi_sw_tx_complete_event evt; +	} __packed evt; + +	cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL); +	if (!cmd) +		return -ENOMEM; + +	memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN); +	cmd->len = cpu_to_le16(len); +	memcpy(cmd->payload, buf, len); + +	rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, sizeof(*cmd) + len, +		      WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000); +	if (rc == 0) +		rc = evt.evt.status; + +	kfree(cmd); + +	return rc; +} +  static int wil_cfg80211_set_channel(struct wiphy *wiphy,  				    struct cfg80211_chan_def *chandef)  { @@ -402,6 +527,41 @@ static int wil_cfg80211_set_default_key(struct wiphy *wiphy,  	return 0;  } +static int wil_remain_on_channel(struct wiphy *wiphy, +				 struct wireless_dev *wdev, +				 struct ieee80211_channel *chan, +				 unsigned int duration, +				 u64 *cookie) +{ +	struct wil6210_priv *wil = wiphy_to_wil(wiphy); +	int rc; + +	/* TODO: handle duration */ +	wil_info(wil, "%s(%d, %d ms)\n", __func__, chan->center_freq, duration); + +	rc = wmi_set_channel(wil, chan->hw_value); +	if (rc) +		return rc; + +	rc = wmi_rxon(wil, true); + +	return rc; +} + +static int wil_cancel_remain_on_channel(struct wiphy *wiphy, +					struct wireless_dev *wdev, +					u64 cookie) +{ +	struct wil6210_priv *wil = wiphy_to_wil(wiphy); +	int rc; + +	wil_info(wil, "%s()\n", __func__); + +	rc = wmi_rxon(wil, false); + +	return rc; +} +  static int wil_fix_bcon(struct wil6210_priv *wil,  			struct cfg80211_beacon_data *bcon)  { @@ -450,18 +610,20 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,  	if (wil_fix_bcon(wil, bcon))  		wil_dbg_misc(wil, "Fixed bcon\n"); +	mutex_lock(&wil->mutex); +  	rc = wil_reset(wil);  	if (rc) -		return rc; +		goto out;  	/* Rx VRING. */  	rc = wil_rx_init(wil);  	if (rc) -		return rc; +		goto out;  	rc = wmi_set_ssid(wil, info->ssid_len, info->ssid);  	if (rc) -		return rc; +		goto out;  	/* MAC address - pre-requisite for other commands */  	wmi_set_mac_address(wil, ndev->dev_addr); @@ -485,11 +647,13 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,  	rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype,  			   channel->hw_value);  	if (rc) -		return rc; +		goto out;  	netif_carrier_on(ndev); +out: +	mutex_unlock(&wil->mutex);  	return rc;  } @@ -499,17 +663,36 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,  	int rc = 0;  	struct wil6210_priv *wil = wiphy_to_wil(wiphy); +	mutex_lock(&wil->mutex); +  	rc = wmi_pcp_stop(wil); +	mutex_unlock(&wil->mutex);  	return rc;  } +static int wil_cfg80211_del_station(struct wiphy *wiphy, +				    struct net_device *dev, const u8 *mac) +{ +	struct wil6210_priv *wil = wiphy_to_wil(wiphy); + +	mutex_lock(&wil->mutex); +	wil6210_disconnect(wil, mac); +	mutex_unlock(&wil->mutex); + +	return 0; +} +  static struct cfg80211_ops wil_cfg80211_ops = {  	.scan = wil_cfg80211_scan,  	.connect = wil_cfg80211_connect,  	.disconnect = wil_cfg80211_disconnect,  	.change_virtual_intf = wil_cfg80211_change_iface,  	.get_station = wil_cfg80211_get_station, +	.dump_station = wil_cfg80211_dump_station, +	.remain_on_channel = wil_remain_on_channel, +	.cancel_remain_on_channel = wil_cancel_remain_on_channel, +	.mgmt_tx = wil_cfg80211_mgmt_tx,  	.set_monitor_channel = wil_cfg80211_set_channel,  	.add_key = wil_cfg80211_add_key,  	.del_key = wil_cfg80211_del_key, @@ -517,6 +700,7 @@ static struct cfg80211_ops wil_cfg80211_ops = {  	/* AP mode */  	.start_ap = wil_cfg80211_start_ap,  	.stop_ap = wil_cfg80211_stop_ap, +	.del_station = wil_cfg80211_del_station,  };  static void wil_wiphy_init(struct wiphy *wiphy) @@ -542,7 +726,7 @@ static void wil_wiphy_init(struct wiphy *wiphy)  	wiphy->bands[IEEE80211_BAND_60GHZ] = &wil_band_60ghz;  	/* TODO: figure this out */ -	wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; +	wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;  	wiphy->cipher_suites = wil_cipher_suites;  	wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites); diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 1caa31992a7..8d4bc4bfb66 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -26,14 +26,16 @@  /* Nasty hack. Better have per device instances */  static u32 mem_addr;  static u32 dbg_txdesc_index; +static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */  static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, -			    const char *name, struct vring *vring) +			    const char *name, struct vring *vring, +			    char _s, char _h)  {  	void __iomem *x = wmi_addr(wil, vring->hwtail);  	seq_printf(s, "VRING %s = {\n", name); -	seq_printf(s, "  pa     = 0x%016llx\n", (unsigned long long)vring->pa); +	seq_printf(s, "  pa     = %pad\n", &vring->pa);  	seq_printf(s, "  va     = 0x%p\n", vring->va);  	seq_printf(s, "  size   = %d\n", vring->size);  	seq_printf(s, "  swtail = %d\n", vring->swtail); @@ -50,8 +52,8 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,  			volatile struct vring_tx_desc *d = &vring->va[i].tx;  			if ((i % 64) == 0 && (i != 0))  				seq_printf(s, "\n"); -			seq_printf(s, "%s", (d->dma.status & BIT(0)) ? -					"S" : (vring->ctx[i].skb ? "H" : "h")); +			seq_printf(s, "%c", (d->dma.status & BIT(0)) ? +					_s : (vring->ctx[i].skb ? _h : 'h'));  		}  		seq_printf(s, "\n");  	} @@ -63,14 +65,19 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data)  	uint i;  	struct wil6210_priv *wil = s->private; -	wil_print_vring(s, wil, "rx", &wil->vring_rx); +	wil_print_vring(s, wil, "rx", &wil->vring_rx, 'S', '_');  	for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {  		struct vring *vring = &(wil->vring_tx[i]);  		if (vring->va) { +			int cid = wil->vring2cid_tid[i][0]; +			int tid = wil->vring2cid_tid[i][1];  			char name[10];  			snprintf(name, sizeof(name), "tx_%2d", i); -			wil_print_vring(s, wil, name, vring); + +			seq_printf(s, "\n%pM CID %d TID %d\n", +				   wil->sta[cid].addr, cid, tid); +			wil_print_vring(s, wil, name, vring, '_', 'H');  		}  	} @@ -390,57 +397,98 @@ static const struct file_operations fops_reset = {  	.write = wil_write_file_reset,  	.open  = simple_open,  }; -/*---------Tx descriptor------------*/ +static void wil_seq_hexdump(struct seq_file *s, void *p, int len, +			    const char *prefix) +{ +	char printbuf[16 * 3 + 2]; +	int i = 0; +	while (i < len) { +		int l = min(len - i, 16); +		hex_dump_to_buffer(p + i, l, 16, 1, printbuf, +				   sizeof(printbuf), false); +		seq_printf(s, "%s%s\n", prefix, printbuf); +		i += l; +	} +} + +static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb) +{ +	int i = 0; +	int len = skb_headlen(skb); +	void *p = skb->data; +	int nr_frags = skb_shinfo(skb)->nr_frags; + +	seq_printf(s, "    len = %d\n", len); +	wil_seq_hexdump(s, p, len, "      : "); + +	if (nr_frags) { +		seq_printf(s, "    nr_frags = %d\n", nr_frags); +		for (i = 0; i < nr_frags; i++) { +			const struct skb_frag_struct *frag = +					&skb_shinfo(skb)->frags[i]; + +			len = skb_frag_size(frag); +			p = skb_frag_address_safe(frag); +			seq_printf(s, "    [%2d] : len = %d\n", i, len); +			wil_seq_hexdump(s, p, len, "      : "); +		} +	} +} + +/*---------Tx/Rx descriptor------------*/  static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)  {  	struct wil6210_priv *wil = s->private; -	struct vring *vring = &(wil->vring_tx[0]); +	struct vring *vring; +	bool tx = (dbg_vring_index < WIL6210_MAX_TX_RINGS); +	if (tx) +		vring = &(wil->vring_tx[dbg_vring_index]); +	else +		vring = &wil->vring_rx;  	if (!vring->va) { -		seq_printf(s, "No Tx VRING\n"); +		if (tx) +			seq_printf(s, "No Tx[%2d] VRING\n", dbg_vring_index); +		else +			seq_puts(s, "No Rx VRING\n");  		return 0;  	}  	if (dbg_txdesc_index < vring->size) { +		/* use struct vring_tx_desc for Rx as well, +		 * only field used, .dma.length, is the same +		 */  		volatile struct vring_tx_desc *d =  				&(vring->va[dbg_txdesc_index].tx);  		volatile u32 *u = (volatile u32 *)d;  		struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb; -		seq_printf(s, "Tx[%3d] = {\n", dbg_txdesc_index); +		if (tx) +			seq_printf(s, "Tx[%2d][%3d] = {\n", dbg_vring_index, +				   dbg_txdesc_index); +		else +			seq_printf(s, "Rx[%3d] = {\n", dbg_txdesc_index);  		seq_printf(s, "  MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",  			   u[0], u[1], u[2], u[3]);  		seq_printf(s, "  DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n",  			   u[4], u[5], u[6], u[7]); -		seq_printf(s, "  SKB = %p\n", skb); +		seq_printf(s, "  SKB = 0x%p\n", skb);  		if (skb) { -			char printbuf[16 * 3 + 2]; -			int i = 0; -			int len = le16_to_cpu(d->dma.length); -			void *p = skb->data; - -			if (len != skb_headlen(skb)) { -				seq_printf(s, "!!! len: desc = %d skb = %d\n", -					   len, skb_headlen(skb)); -				len = min_t(int, len, skb_headlen(skb)); -			} - -			seq_printf(s, "    len = %d\n", len); - -			while (i < len) { -				int l = min(len - i, 16); -				hex_dump_to_buffer(p + i, l, 16, 1, printbuf, -						   sizeof(printbuf), false); -				seq_printf(s, "      : %s\n", printbuf); -				i += l; -			} +			skb_get(skb); +			wil_seq_print_skb(s, skb); +			kfree_skb(skb);  		}  		seq_printf(s, "}\n");  	} else { -		seq_printf(s, "TxDesc index (%d) >= size (%d)\n", -			   dbg_txdesc_index, vring->size); +		if (tx) +			seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n", +				   dbg_vring_index, dbg_txdesc_index, +				   vring->size); +		else +			seq_printf(s, "RxDesc index (%d) >= size (%d)\n", +				   dbg_txdesc_index, vring->size);  	}  	return 0; @@ -570,6 +618,69 @@ static const struct file_operations fops_temp = {  	.llseek		= seq_lseek,  }; +/*---------Station matrix------------*/ +static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) +{ +	int i; +	u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size; +	seq_printf(s, "0x%03x [", r->head_seq_num); +	for (i = 0; i < r->buf_size; i++) { +		if (i == index) +			seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|'); +		else +			seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_'); +	} +	seq_puts(s, "]\n"); +} + +static int wil_sta_debugfs_show(struct seq_file *s, void *data) +{ +	struct wil6210_priv *wil = s->private; +	int i, tid; + +	for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { +		struct wil_sta_info *p = &wil->sta[i]; +		char *status = "unknown"; +		switch (p->status) { +		case wil_sta_unused: +			status = "unused   "; +			break; +		case wil_sta_conn_pending: +			status = "pending  "; +			break; +		case wil_sta_connected: +			status = "connected"; +			break; +		} +		seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status, +			   (p->data_port_open ? " data_port_open" : "")); + +		if (p->status == wil_sta_connected) { +			for (tid = 0; tid < WIL_STA_TID_NUM; tid++) { +				struct wil_tid_ampdu_rx *r = p->tid_rx[tid]; +				if (r) { +					seq_printf(s, "[%2d] ", tid); +					wil_print_rxtid(s, r); +				} +			} +		} +	} + +	return 0; +} + +static int wil_sta_seq_open(struct inode *inode, struct file *file) +{ +	return single_open(file, wil_sta_debugfs_show, inode->i_private); +} + +static const struct file_operations fops_sta = { +	.open		= wil_sta_seq_open, +	.release	= single_release, +	.read		= seq_read, +	.llseek		= seq_lseek, +}; +  /*----------------*/  int wil6210_debugfs_init(struct wil6210_priv *wil)  { @@ -581,9 +692,13 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)  	debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox);  	debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring); -	debugfs_create_file("txdesc", S_IRUGO, dbg, wil, &fops_txdesc); -	debugfs_create_u32("txdesc_index", S_IRUGO | S_IWUSR, dbg, +	debugfs_create_file("stations", S_IRUGO, dbg, wil, &fops_sta); +	debugfs_create_file("desc", S_IRUGO, dbg, wil, &fops_txdesc); +	debugfs_create_u32("desc_index", S_IRUGO | S_IWUSR, dbg,  			   &dbg_txdesc_index); +	debugfs_create_u32("vring_index", S_IRUGO | S_IWUSR, dbg, +			   &dbg_vring_index); +  	debugfs_create_file("bf", S_IRUGO, dbg, wil, &fops_bf);  	debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid);  	debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg, diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 8205d3e4ab6..73593aa3cd9 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -156,6 +156,19 @@ void wil6210_enable_irq(struct wil6210_priv *wil)  	iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) +  		  offsetof(struct RGF_ICR, ICC)); +	/* interrupt moderation parameters */ +	if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { +		/* disable interrupt moderation for monitor +		 * to get better timestamp precision +		 */ +		iowrite32(0, wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL)); +	} else { +		iowrite32(WIL6210_ITR_TRSH, +			  wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_TRSH)); +		iowrite32(BIT_DMA_ITR_CNT_CRL_EN, +			  wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL)); +	} +  	wil6210_unmask_irq_pseudo(wil);  	wil6210_unmask_irq_tx(wil);  	wil6210_unmask_irq_rx(wil); @@ -182,8 +195,12 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)  	if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) {  		wil_dbg_irq(wil, "RX done\n");  		isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE; -		wil_dbg_txrx(wil, "NAPI schedule\n"); -		napi_schedule(&wil->napi_rx); +		if (test_bit(wil_status_reset_done, &wil->status)) { +			wil_dbg_txrx(wil, "NAPI(Rx) schedule\n"); +			napi_schedule(&wil->napi_rx); +		} else { +			wil_err(wil, "Got Rx interrupt while in reset\n"); +		}  	}  	if (isr) @@ -213,10 +230,15 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)  	if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) {  		wil_dbg_irq(wil, "TX done\n"); -		napi_schedule(&wil->napi_tx);  		isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE;  		/* clear also all VRING interrupts */  		isr &= ~(BIT(25) - 1UL); +		if (test_bit(wil_status_reset_done, &wil->status)) { +			wil_dbg_txrx(wil, "NAPI(Tx) schedule\n"); +			napi_schedule(&wil->napi_tx); +		} else { +			wil_err(wil, "Got Tx interrupt while in reset\n"); +		}  	}  	if (isr) @@ -306,6 +328,7 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)  	if (isr & ISR_MISC_FW_ERROR) {  		wil_notify_fw_error(wil);  		isr &= ~ISR_MISC_FW_ERROR; +		wil_fw_error_recovery(wil);  	}  	if (isr & ISR_MISC_MBOX_EVT) { @@ -315,7 +338,7 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)  	}  	if (isr) -		wil_err(wil, "un-handled MISC ISR bits 0x%08x\n", isr); +		wil_dbg_irq(wil, "un-handled MISC ISR bits 0x%08x\n", isr);  	wil->isr_misc = 0; @@ -480,6 +503,23 @@ free0:  	return rc;  } +/* can't use wil_ioread32_and_clear because ICC value is not ser yet */ +static inline void wil_clear32(void __iomem *addr) +{ +	u32 x = ioread32(addr); + +	iowrite32(x, addr); +} + +void wil6210_clear_irq(struct wil6210_priv *wil) +{ +	wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) + +		    offsetof(struct RGF_ICR, ICR)); +	wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) + +		    offsetof(struct RGF_ICR, ICR)); +	wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + +		    offsetof(struct RGF_ICR, ICR)); +}  int wil6210_init_irq(struct wil6210_priv *wil, int irq)  { diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 0a2844c48a6..11e6d9d22ea 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -16,8 +16,14 @@  #include <linux/moduleparam.h>  #include <linux/if_arp.h> +#include <linux/etherdevice.h>  #include "wil6210.h" +#include "txrx.h" + +static bool no_fw_recovery; +module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(no_fw_recovery, " disable FW error recovery");  /*   * Due to a hardware issue, @@ -52,29 +58,74 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,  		__raw_writel(*s++, d++);  } -static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid) +static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)  {  	uint i; -	struct net_device *ndev = wil_to_ndev(wil); +	struct wil_sta_info *sta = &wil->sta[cid]; -	wil_dbg_misc(wil, "%s()\n", __func__); +	sta->data_port_open = false; +	if (sta->status != wil_sta_unused) { +		wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING); +		sta->status = wil_sta_unused; +	} -	wil_link_off(wil); -	if (test_bit(wil_status_fwconnected, &wil->status)) { -		clear_bit(wil_status_fwconnected, &wil->status); -		cfg80211_disconnected(ndev, -				      WLAN_STATUS_UNSPECIFIED_FAILURE, -				      NULL, 0, GFP_KERNEL); -	} else if (test_bit(wil_status_fwconnecting, &wil->status)) { -		cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, -					WLAN_STATUS_UNSPECIFIED_FAILURE, -					GFP_KERNEL); +	for (i = 0; i < WIL_STA_TID_NUM; i++) { +		struct wil_tid_ampdu_rx *r = sta->tid_rx[i]; +		sta->tid_rx[i] = NULL; +		wil_tid_ampdu_rx_free(wil, r); +	} +	for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { +		if (wil->vring2cid_tid[i][0] == cid) +			wil_vring_fini_tx(wil, i);  	} -	clear_bit(wil_status_fwconnecting, &wil->status); -	for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) -		wil_vring_fini_tx(wil, i); +	memset(&sta->stats, 0, sizeof(sta->stats)); +} -	clear_bit(wil_status_dontscan, &wil->status); +static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid) +{ +	int cid = -ENOENT; +	struct net_device *ndev = wil_to_ndev(wil); +	struct wireless_dev *wdev = wil->wdev; + +	might_sleep(); +	if (bssid) { +		cid = wil_find_cid(wil, bssid); +		wil_dbg_misc(wil, "%s(%pM, CID %d)\n", __func__, bssid, cid); +	} else { +		wil_dbg_misc(wil, "%s(all)\n", __func__); +	} + +	if (cid >= 0) /* disconnect 1 peer */ +		wil_disconnect_cid(wil, cid); +	else /* disconnect all */ +		for (cid = 0; cid < WIL6210_MAX_CID; cid++) +			wil_disconnect_cid(wil, cid); + +	/* link state */ +	switch (wdev->iftype) { +	case NL80211_IFTYPE_STATION: +	case NL80211_IFTYPE_P2P_CLIENT: +		wil_link_off(wil); +		if (test_bit(wil_status_fwconnected, &wil->status)) { +			clear_bit(wil_status_fwconnected, &wil->status); +			cfg80211_disconnected(ndev, +					      WLAN_STATUS_UNSPECIFIED_FAILURE, +					      NULL, 0, GFP_KERNEL); +		} else if (test_bit(wil_status_fwconnecting, &wil->status)) { +			cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, +						WLAN_STATUS_UNSPECIFIED_FAILURE, +						GFP_KERNEL); +		} +		clear_bit(wil_status_fwconnecting, &wil->status); +		break; +	default: +		/* AP-like interface and monitor: +		 * never scan, always connected +		 */ +		if (bssid) +			cfg80211_del_sta(ndev, bssid, GFP_KERNEL); +		break; +	}  }  static void wil_disconnect_worker(struct work_struct *work) @@ -82,7 +133,9 @@ static void wil_disconnect_worker(struct work_struct *work)  	struct wil6210_priv *wil = container_of(work,  			struct wil6210_priv, disconnect_worker); +	mutex_lock(&wil->mutex);  	_wil6210_disconnect(wil, NULL); +	mutex_unlock(&wil->mutex);  }  static void wil_connect_timer_fn(ulong x) @@ -97,12 +150,82 @@ static void wil_connect_timer_fn(ulong x)  	schedule_work(&wil->disconnect_worker);  } +static void wil_scan_timer_fn(ulong x) +{ +	struct wil6210_priv *wil = (void *)x; + +	clear_bit(wil_status_fwready, &wil->status); +	wil_err(wil, "Scan timeout detected, start fw error recovery\n"); +	schedule_work(&wil->fw_error_worker); +} + +static void wil_fw_error_worker(struct work_struct *work) +{ +	struct wil6210_priv *wil = container_of(work, +			struct wil6210_priv, fw_error_worker); +	struct wireless_dev *wdev = wil->wdev; + +	wil_dbg_misc(wil, "fw error worker\n"); + +	if (no_fw_recovery) +		return; + +	/* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO +	 * passed since last recovery attempt +	 */ +	if (time_is_after_jiffies(wil->last_fw_recovery + +				  WIL6210_FW_RECOVERY_TO)) +		wil->recovery_count++; +	else +		wil->recovery_count = 1; /* fw was alive for a long time */ + +	if (wil->recovery_count > WIL6210_FW_RECOVERY_RETRIES) { +		wil_err(wil, "too many recovery attempts (%d), giving up\n", +			wil->recovery_count); +		return; +	} + +	wil->last_fw_recovery = jiffies; + +	mutex_lock(&wil->mutex); +	switch (wdev->iftype) { +	case NL80211_IFTYPE_STATION: +	case NL80211_IFTYPE_P2P_CLIENT: +	case NL80211_IFTYPE_MONITOR: +		wil_info(wil, "fw error recovery started (try %d)...\n", +			 wil->recovery_count); +		wil_reset(wil); + +		/* need to re-allocate Rx ring after reset */ +		wil_rx_init(wil); +		break; +	case NL80211_IFTYPE_AP: +	case NL80211_IFTYPE_P2P_GO: +		/* recovery in these modes is done by upper layers */ +		break; +	default: +		break; +	} +	mutex_unlock(&wil->mutex); +} + +static int wil_find_free_vring(struct wil6210_priv *wil) +{ +	int i; +	for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { +		if (!wil->vring_tx[i].va) +			return i; +	} +	return -EINVAL; +} +  static void wil_connect_worker(struct work_struct *work)  {  	int rc;  	struct wil6210_priv *wil = container_of(work, struct wil6210_priv,  						connect_worker);  	int cid = wil->pending_connect_cid; +	int ringid = wil_find_free_vring(wil);  	if (cid < 0) {  		wil_err(wil, "No connection pending\n"); @@ -111,16 +234,22 @@ static void wil_connect_worker(struct work_struct *work)  	wil_dbg_wmi(wil, "Configure for connection CID %d\n", cid); -	rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE, cid, 0); +	rc = wil_vring_init_tx(wil, ringid, WIL6210_TX_RING_SIZE, cid, 0);  	wil->pending_connect_cid = -1; -	if (rc == 0) +	if (rc == 0) { +		wil->sta[cid].status = wil_sta_connected;  		wil_link_on(wil); +	} else { +		wil->sta[cid].status = wil_sta_unused; +	}  }  int wil_priv_init(struct wil6210_priv *wil)  {  	wil_dbg_misc(wil, "%s()\n", __func__); +	memset(wil->sta, 0, sizeof(wil->sta)); +  	mutex_init(&wil->mutex);  	mutex_init(&wil->wmi_mutex); @@ -128,10 +257,12 @@ int wil_priv_init(struct wil6210_priv *wil)  	wil->pending_connect_cid = -1;  	setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil); +	setup_timer(&wil->scan_timer, wil_scan_timer_fn, (ulong)wil);  	INIT_WORK(&wil->connect_worker, wil_connect_worker);  	INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);  	INIT_WORK(&wil->wmi_event_worker, wmi_event_worker); +	INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);  	INIT_LIST_HEAD(&wil->pending_wmi_ev);  	spin_lock_init(&wil->wmi_ev_lock); @@ -146,10 +277,12 @@ int wil_priv_init(struct wil6210_priv *wil)  		return -EAGAIN;  	} +	wil->last_fw_recovery = jiffies; +  	return 0;  } -void wil6210_disconnect(struct wil6210_priv *wil, void *bssid) +void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)  {  	del_timer_sync(&wil->connect_timer);  	_wil6210_disconnect(wil, bssid); @@ -157,8 +290,12 @@ void wil6210_disconnect(struct wil6210_priv *wil, void *bssid)  void wil_priv_deinit(struct wil6210_priv *wil)  { +	del_timer_sync(&wil->scan_timer);  	cancel_work_sync(&wil->disconnect_worker); +	cancel_work_sync(&wil->fw_error_worker); +	mutex_lock(&wil->mutex);  	wil6210_disconnect(wil, NULL); +	mutex_unlock(&wil->mutex);  	wmi_event_flush(wil);  	destroy_workqueue(wil->wmi_wq_conn);  	destroy_workqueue(wil->wmi_wq); @@ -166,40 +303,78 @@ void wil_priv_deinit(struct wil6210_priv *wil)  static void wil_target_reset(struct wil6210_priv *wil)  { +	int delay = 0; +	u32 hw_state; +	u32 rev_id; +  	wil_dbg_misc(wil, "Resetting...\n"); +	/* register read */ +#define R(a) ioread32(wil->csr + HOSTADDR(a))  	/* register write */  #define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a))  	/* register set = read, OR, write */ -#define S(a, v) iowrite32(ioread32(wil->csr + HOSTADDR(a)) | v, \ -		wil->csr + HOSTADDR(a)) +#define S(a, v) W(a, R(a) | v) +	/* register clear = read, AND with inverted, write */ +#define C(a, v) W(a, R(a) & ~v) +	wil->hw_version = R(RGF_USER_FW_REV_ID); +	rev_id = wil->hw_version & 0xff;  	/* hpal_perst_from_pad_src_n_mask */  	S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6));  	/* car_perst_rst_src_n_mask */  	S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(7)); +	wmb(); /* order is important here */  	W(RGF_USER_MAC_CPU_0,  BIT(1)); /* mac_cpu_man_rst */  	W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */ +	wmb(); /* order is important here */  	W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);  	W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);  	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000170);  	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00); +	wmb(); /* order is important here */  	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0);  	W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0);  	W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0);  	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); +	wmb(); /* order is important here */  	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001); -	W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080); +	if (rev_id == 1) { +		W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080); +	} else { +		W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8)); +		W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); +	}  	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); +	wmb(); /* order is important here */ -	wil_dbg_misc(wil, "Reset completed\n"); +	/* wait until device ready */ +	do { +		msleep(1); +		hw_state = R(RGF_USER_HW_MACHINE_STATE); +		if (delay++ > 100) { +			wil_err(wil, "Reset not completed, hw_state 0x%08x\n", +				hw_state); +			return; +		} +	} while (hw_state != HW_MACHINE_BOOT_DONE); +	if (rev_id == 2) +		W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8)); + +	C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); +	wmb(); /* order is important here */ + +	wil_dbg_misc(wil, "Reset completed in %d ms\n", delay); + +#undef R  #undef W  #undef S +#undef C  }  void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) @@ -219,8 +394,8 @@ static int wil_wait_for_fw_ready(struct wil6210_priv *wil)  		wil_err(wil, "Firmware not ready\n");  		return -ETIME;  	} else { -		wil_dbg_misc(wil, "FW ready after %d ms\n", -			     jiffies_to_msecs(to-left)); +		wil_info(wil, "FW ready after %d ms. HW version 0x%08x\n", +			 jiffies_to_msecs(to-left), wil->hw_version);  	}  	return 0;  } @@ -234,11 +409,25 @@ int wil_reset(struct wil6210_priv *wil)  {  	int rc; +	WARN_ON(!mutex_is_locked(&wil->mutex)); +  	cancel_work_sync(&wil->disconnect_worker);  	wil6210_disconnect(wil, NULL); +	wil->status = 0; /* prevent NAPI from being scheduled */ +	if (test_bit(wil_status_napi_en, &wil->status)) { +		napi_synchronize(&wil->napi_rx); +	} + +	if (wil->scan_request) { +		wil_dbg_misc(wil, "Abort scan_request 0x%p\n", +			     wil->scan_request); +		del_timer_sync(&wil->scan_timer); +		cfg80211_scan_done(wil->scan_request, true); +		wil->scan_request = NULL; +	} +  	wil6210_disable_irq(wil); -	wil->status = 0;  	wmi_event_flush(wil); @@ -248,9 +437,11 @@ int wil_reset(struct wil6210_priv *wil)  	/* TODO: put MAC in reset */  	wil_target_reset(wil); +	wil_rx_fini(wil); +  	/* init after reset */  	wil->pending_connect_cid = -1; -	INIT_COMPLETION(wil->wmi_ready); +	reinit_completion(&wil->wmi_ready);  	/* TODO: release MAC reset */  	wil6210_enable_irq(wil); @@ -261,6 +452,11 @@ int wil_reset(struct wil6210_priv *wil)  	return rc;  } +void wil_fw_error_recovery(struct wil6210_priv *wil) +{ +	wil_dbg_misc(wil, "starting fw error recovery\n"); +	schedule_work(&wil->fw_error_worker); +}  void wil_link_on(struct wil6210_priv *wil)  { @@ -288,6 +484,8 @@ static int __wil_up(struct wil6210_priv *wil)  	struct wireless_dev *wdev = wil->wdev;  	int rc; +	WARN_ON(!mutex_is_locked(&wil->mutex)); +  	rc = wil_reset(wil);  	if (rc)  		return rc; @@ -329,6 +527,7 @@ static int __wil_up(struct wil6210_priv *wil)  	napi_enable(&wil->napi_rx);  	napi_enable(&wil->napi_tx); +	set_bit(wil_status_napi_en, &wil->status);  	return 0;  } @@ -346,10 +545,14 @@ int wil_up(struct wil6210_priv *wil)  static int __wil_down(struct wil6210_priv *wil)  { +	WARN_ON(!mutex_is_locked(&wil->mutex)); + +	clear_bit(wil_status_napi_en, &wil->status);  	napi_disable(&wil->napi_rx);  	napi_disable(&wil->napi_tx);  	if (wil->scan_request) { +		del_timer_sync(&wil->scan_timer);  		cfg80211_scan_done(wil->scan_request, true);  		wil->scan_request = NULL;  	} @@ -370,3 +573,19 @@ int wil_down(struct wil6210_priv *wil)  	return rc;  } + +int wil_find_cid(struct wil6210_priv *wil, const u8 *mac) +{ +	int i; +	int rc = -ENOENT; + +	for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { +		if ((wil->sta[i].status != wil_sta_unused) && +		    ether_addr_equal(wil->sta[i].addr, mac)) { +			rc = i; +			break; +		} +	} + +	return rc; +} diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 717178f09aa..106b6dcb773 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -32,12 +32,26 @@ static int wil_stop(struct net_device *ndev)  	return wil_down(wil);  } +static int wil_change_mtu(struct net_device *ndev, int new_mtu) +{ +	struct wil6210_priv *wil = ndev_to_wil(ndev); + +	if (new_mtu < 68 || new_mtu > IEEE80211_MAX_DATA_LEN_DMG) +		return -EINVAL; + +	wil_dbg_misc(wil, "change MTU %d -> %d\n", ndev->mtu, new_mtu); +	ndev->mtu = new_mtu; + +	return 0; +} +  static const struct net_device_ops wil_netdev_ops = {  	.ndo_open		= wil_open,  	.ndo_stop		= wil_stop,  	.ndo_start_xmit		= wil_start_xmit,  	.ndo_set_mac_address	= eth_mac_addr,  	.ndo_validate_addr	= eth_validate_addr, +	.ndo_change_mtu		= wil_change_mtu,  };  static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget) @@ -127,8 +141,9 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)  	ndev->netdev_ops = &wil_netdev_ops;  	ndev->ieee80211_ptr = wdev; -	ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM; -	ndev->features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM; +	ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM | +			    NETIF_F_SG | NETIF_F_GRO; +	ndev->features |= ndev->hw_features;  	SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));  	wdev->netdev = ndev; diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index eb1dc7ad80f..1e2e07b9d13 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -41,36 +41,36 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)  	switch (use_msi) {  	case 3:  	case 1: +		wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi); +		break;  	case 0: +		wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n");  		break;  	default: -		wil_err(wil, "Invalid use_msi=%d, default to 1\n", -			use_msi); +		wil_err(wil, "Invalid use_msi=%d, default to 1\n", use_msi);  		use_msi = 1;  	} -	wil->n_msi = use_msi; -	if (wil->n_msi) { -		wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi); -		rc = pci_enable_msi_block(pdev, wil->n_msi); -		if (rc && (wil->n_msi == 3)) { -			wil_err(wil, "3 MSI mode failed, try 1 MSI\n"); -			wil->n_msi = 1; -			rc = pci_enable_msi_block(pdev, wil->n_msi); -		} -		if (rc) { -			wil_err(wil, "pci_enable_msi failed, use INTx\n"); -			wil->n_msi = 0; -		} -	} else { -		wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n"); + +	if (use_msi == 3 && pci_enable_msi_range(pdev, 3, 3) < 0) { +		wil_err(wil, "3 MSI mode failed, try 1 MSI\n"); +		use_msi = 1; +	} + +	if (use_msi == 1 && pci_enable_msi(pdev)) { +		wil_err(wil, "pci_enable_msi failed, use INTx\n"); +		use_msi = 0;  	} +	wil->n_msi = use_msi; +  	rc = wil6210_init_irq(wil, pdev->irq);  	if (rc)  		goto stop_master;  	/* need reset here to obtain MAC */ +	mutex_lock(&wil->mutex);  	rc = wil_reset(wil); +	mutex_unlock(&wil->mutex);  	if (rc)  		goto release_irq; @@ -138,7 +138,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)  		goto err_release_reg;  	}  	/* rollback to err_iounmap */ -	dev_info(&pdev->dev, "CSR at %pR -> %p\n", &pdev->resource[0], csr); +	dev_info(&pdev->dev, "CSR at %pR -> 0x%p\n", &pdev->resource[0], csr);  	wil = wil_if_alloc(dev, csr);  	if (IS_ERR(wil)) { @@ -151,6 +151,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)  	pci_set_drvdata(pdev, wil);  	wil->pdev = pdev; +	wil6210_clear_irq(wil);  	/* FW should raise IRQ when ready */  	rc = wil_if_pcie_enable(wil);  	if (rc) { @@ -197,7 +198,6 @@ static void wil_pcie_remove(struct pci_dev *pdev)  	pci_iounmap(pdev, wil->csr);  	pci_release_region(pdev, 0);  	pci_disable_device(pdev); -	pci_set_drvdata(pdev, NULL);  }  static DEFINE_PCI_DEVICE_TABLE(wil6210_pcie_ids) = { diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c new file mode 100644 index 00000000000..747ae127587 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -0,0 +1,201 @@ +#include "wil6210.h" +#include "txrx.h" + +#define SEQ_MODULO 0x1000 +#define SEQ_MASK   0xfff + +static inline int seq_less(u16 sq1, u16 sq2) +{ +	return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1); +} + +static inline u16 seq_inc(u16 sq) +{ +	return (sq + 1) & SEQ_MASK; +} + +static inline u16 seq_sub(u16 sq1, u16 sq2) +{ +	return (sq1 - sq2) & SEQ_MASK; +} + +static inline int reorder_index(struct wil_tid_ampdu_rx *r, u16 seq) +{ +	return seq_sub(seq, r->ssn) % r->buf_size; +} + +static void wil_release_reorder_frame(struct wil6210_priv *wil, +				      struct wil_tid_ampdu_rx *r, +				      int index) +{ +	struct net_device *ndev = wil_to_ndev(wil); +	struct sk_buff *skb = r->reorder_buf[index]; + +	if (!skb) +		goto no_frame; + +	/* release the frame from the reorder ring buffer */ +	r->stored_mpdu_num--; +	r->reorder_buf[index] = NULL; +	wil_netif_rx_any(skb, ndev); + +no_frame: +	r->head_seq_num = seq_inc(r->head_seq_num); +} + +static void wil_release_reorder_frames(struct wil6210_priv *wil, +				       struct wil_tid_ampdu_rx *r, +				       u16 hseq) +{ +	int index; + +	/* note: this function is never called with +	 * hseq preceding r->head_seq_num, i.e it is always true +	 * !seq_less(hseq, r->head_seq_num) +	 * and thus on loop exit it should be +	 * r->head_seq_num == hseq +	 */ +	while (seq_less(r->head_seq_num, hseq) && r->stored_mpdu_num) { +		index = reorder_index(r, r->head_seq_num); +		wil_release_reorder_frame(wil, r, index); +	} +	r->head_seq_num = hseq; +} + +static void wil_reorder_release(struct wil6210_priv *wil, +				struct wil_tid_ampdu_rx *r) +{ +	int index = reorder_index(r, r->head_seq_num); + +	while (r->reorder_buf[index]) { +		wil_release_reorder_frame(wil, r, index); +		index = reorder_index(r, r->head_seq_num); +	} +} + +void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) +{ +	struct net_device *ndev = wil_to_ndev(wil); +	struct vring_rx_desc *d = wil_skb_rxdesc(skb); +	int tid = wil_rxdesc_tid(d); +	int cid = wil_rxdesc_cid(d); +	int mid = wil_rxdesc_mid(d); +	u16 seq = wil_rxdesc_seq(d); +	struct wil_sta_info *sta = &wil->sta[cid]; +	struct wil_tid_ampdu_rx *r = sta->tid_rx[tid]; +	u16 hseq; +	int index; + +	wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x\n", +		     mid, cid, tid, seq); + +	if (!r) { +		wil_netif_rx_any(skb, ndev); +		return; +	} + +	hseq = r->head_seq_num; + +	spin_lock(&r->reorder_lock); + +	/** Due to the race between WMI events, where BACK establishment +	 * reported, and data Rx, few packets may be pass up before reorder +	 * buffer get allocated. Catch up by pretending SSN is what we +	 * see in the 1-st Rx packet +	 */ +	if (r->first_time) { +		r->first_time = false; +		if (seq != r->head_seq_num) { +			wil_err(wil, "Error: 1-st frame with wrong sequence" +				" %d, should be %d. Fixing...\n", seq, +				r->head_seq_num); +			r->head_seq_num = seq; +			r->ssn = seq; +		} +	} + +	/* frame with out of date sequence number */ +	if (seq_less(seq, r->head_seq_num)) { +		dev_kfree_skb(skb); +		goto out; +	} + +	/* +	 * If frame the sequence number exceeds our buffering window +	 * size release some previous frames to make room for this one. +	 */ +	if (!seq_less(seq, r->head_seq_num + r->buf_size)) { +		hseq = seq_inc(seq_sub(seq, r->buf_size)); +		/* release stored frames up to new head to stack */ +		wil_release_reorder_frames(wil, r, hseq); +	} + +	/* Now the new frame is always in the range of the reordering buffer */ + +	index = reorder_index(r, seq); + +	/* check if we already stored this frame */ +	if (r->reorder_buf[index]) { +		dev_kfree_skb(skb); +		goto out; +	} + +	/* +	 * If the current MPDU is in the right order and nothing else +	 * is stored we can process it directly, no need to buffer it. +	 * If it is first but there's something stored, we may be able +	 * to release frames after this one. +	 */ +	if (seq == r->head_seq_num && r->stored_mpdu_num == 0) { +		r->head_seq_num = seq_inc(r->head_seq_num); +		wil_netif_rx_any(skb, ndev); +		goto out; +	} + +	/* put the frame in the reordering buffer */ +	r->reorder_buf[index] = skb; +	r->reorder_time[index] = jiffies; +	r->stored_mpdu_num++; +	wil_reorder_release(wil, r); + +out: +	spin_unlock(&r->reorder_lock); +} + +struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, +						int size, u16 ssn) +{ +	struct wil_tid_ampdu_rx *r = kzalloc(sizeof(*r), GFP_KERNEL); +	if (!r) +		return NULL; + +	r->reorder_buf = +		kcalloc(size, sizeof(struct sk_buff *), GFP_KERNEL); +	r->reorder_time = +		kcalloc(size, sizeof(unsigned long), GFP_KERNEL); +	if (!r->reorder_buf || !r->reorder_time) { +		kfree(r->reorder_buf); +		kfree(r->reorder_time); +		kfree(r); +		return NULL; +	} + +	spin_lock_init(&r->reorder_lock); +	r->ssn = ssn; +	r->head_seq_num = ssn; +	r->buf_size = size; +	r->stored_mpdu_num = 0; +	r->first_time = true; +	return r; +} + +void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, +			   struct wil_tid_ampdu_rx *r) +{ +	if (!r) +		return; +	wil_release_reorder_frames(wil, r, r->head_seq_num + r->buf_size); +	kfree(r->reorder_buf); +	kfree(r->reorder_time); +	kfree(r); +} diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index d505b2676a7..0784ef3d4ce 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -21,6 +21,7 @@  #include <linux/ip.h>  #include <linux/ipv6.h>  #include <net/ipv6.h> +#include <linux/prefetch.h>  #include "wil6210.h"  #include "wmi.h" @@ -63,6 +64,22 @@ static inline int wil_vring_avail_tx(struct vring *vring)  	return vring->size - used - 1;  } +/** + * wil_vring_wmark_low - low watermark for available descriptor space + */ +static inline int wil_vring_wmark_low(struct vring *vring) +{ +	return vring->size/8; +} + +/** + * wil_vring_wmark_high - high watermark for available descriptor space + */ +static inline int wil_vring_wmark_high(struct vring *vring) +{ +	return vring->size/4; +} +  static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring)  {  	struct device *dev = wil_to_dev(wil); @@ -97,12 +114,29 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring)  		_d->dma.status = TX_DMA_STATUS_DU;  	} -	wil_dbg_misc(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size, -		     vring->va, (unsigned long long)vring->pa, vring->ctx); +	wil_dbg_misc(wil, "vring[%d] 0x%p:%pad 0x%p\n", vring->size, +		     vring->va, &vring->pa, vring->ctx);  	return 0;  } +static void wil_txdesc_unmap(struct device *dev, struct vring_tx_desc *d, +			     struct wil_ctx *ctx) +{ +	dma_addr_t pa = wil_desc_addr(&d->dma.addr); +	u16 dmalen = le16_to_cpu(d->dma.length); +	switch (ctx->mapped_as) { +	case wil_mapped_as_single: +		dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE); +		break; +	case wil_mapped_as_page: +		dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE); +		break; +	default: +		break; +	} +} +  static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring,  			   int tx)  { @@ -121,15 +155,7 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring,  			ctx = &vring->ctx[vring->swtail];  			*d = *_d; -			pa = wil_desc_addr(&d->dma.addr); -			dmalen = le16_to_cpu(d->dma.length); -			if (vring->ctx[vring->swtail].mapped_as_page) { -				dma_unmap_page(dev, pa, dmalen, -					       DMA_TO_DEVICE); -			} else { -				dma_unmap_single(dev, pa, dmalen, -						 DMA_TO_DEVICE); -			} +			wil_txdesc_unmap(dev, d, ctx);  			if (ctx->skb)  				dev_kfree_skb_any(ctx->skb);  			vring->swtail = wil_vring_next_tail(vring); @@ -343,6 +369,9 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,  	u16 dmalen;  	u8 ftype;  	u8 ds_bits; +	int cid; +	struct wil_net_stats *stats; +  	BUILD_BUG_ON(sizeof(struct vring_rx_desc) > sizeof(skb->cb)); @@ -377,11 +406,15 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,  	}  	skb_trim(skb, dmalen); +	prefetch(skb->data); +  	wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1,  			  skb->data, skb_headlen(skb), false); - -	wil->stats.last_mcs_rx = wil_rxdesc_mcs(d); +	cid = wil_rxdesc_cid(d); +	stats = &wil->sta[cid].stats; +	stats->last_mcs_rx = wil_rxdesc_mcs(d); +	wil->stats.last_mcs_rx = stats->last_mcs_rx;  	/* use radiotap header only if required */  	if (ndev->type == ARPHRD_IEEE80211_RADIOTAP) @@ -469,21 +502,28 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count)   * Pass Rx packet to the netif. Update statistics.   * Called in softirq context (NAPI poll).   */ -static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) +void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)  { -	int rc; +	gro_result_t rc; +	struct wil6210_priv *wil = ndev_to_wil(ndev);  	unsigned int len = skb->len; +	struct vring_rx_desc *d = wil_skb_rxdesc(skb); +	int cid = wil_rxdesc_cid(d); +	struct wil_net_stats *stats = &wil->sta[cid].stats;  	skb_orphan(skb); -	rc = netif_receive_skb(skb); +	rc = napi_gro_receive(&wil->napi_rx, skb); -	if (likely(rc == NET_RX_SUCCESS)) { +	if (unlikely(rc == GRO_DROP)) { +		ndev->stats.rx_dropped++; +		stats->rx_dropped++; +		wil_dbg_txrx(wil, "Rx drop %d bytes\n", len); +	} else {  		ndev->stats.rx_packets++; +		stats->rx_packets++;  		ndev->stats.rx_bytes += len; - -	} else { -		ndev->stats.rx_dropped++; +		stats->rx_bytes += len;  	}  } @@ -512,12 +552,18 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota)  			skb->ip_summed = CHECKSUM_UNNECESSARY;  			skb->pkt_type = PACKET_OTHERHOST;  			skb->protocol = htons(ETH_P_802_2); - +			wil_netif_rx_any(skb, ndev);  		} else { +			struct ethhdr *eth = (void *)skb->data; +  			skb->protocol = eth_type_trans(skb, ndev); + +			if (is_unicast_ether_addr(eth->h_dest)) +				wil_rx_reorder(wil, skb); +			else +				wil_netif_rx_any(skb, ndev);  		} -		wil_netif_rx_any(skb, ndev);  	}  	wil_rx_refill(wil, v->size);  } @@ -527,6 +573,11 @@ int wil_rx_init(struct wil6210_priv *wil)  	struct vring *vring = &wil->vring_rx;  	int rc; +	if (vring->va) { +		wil_err(wil, "Rx ring already allocated\n"); +		return -EINVAL; +	} +  	vring->size = WIL6210_RX_RING_SIZE;  	rc = wil_vring_alloc(wil, vring);  	if (rc) @@ -567,7 +618,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,  				.ring_size = cpu_to_le16(size),  			},  			.ringid = id, -			.cidxtid = (cid & 0xf) | ((tid & 0xf) << 4), +			.cidxtid = mk_cidxtid(cid, tid),  			.encap_trans_type = WMI_VRING_ENC_TYPE_802_3,  			.mac_ctrl = 0,  			.to_resolution = 0, @@ -583,6 +634,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,  		struct wmi_vring_cfg_done_event cmd;  	} __packed reply;  	struct vring *vring = &wil->vring_tx[id]; +	struct vring_tx_data *txdata = &wil->vring_tx_data[id];  	if (vring->va) {  		wil_err(wil, "Tx ring [%d] already allocated\n", id); @@ -590,11 +642,15 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,  		goto out;  	} +	memset(txdata, 0, sizeof(*txdata));  	vring->size = size;  	rc = wil_vring_alloc(wil, vring);  	if (rc)  		goto out; +	wil->vring2cid_tid[id][0] = cid; +	wil->vring2cid_tid[id][1] = tid; +  	cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);  	rc = wmi_call(wil, WMI_VRING_CFG_CMDID, &cmd, sizeof(cmd), @@ -610,6 +666,8 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,  	}  	vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr); +	txdata->enabled = 1; +  	return 0;   out_free:  	wil_vring_free(wil, vring, 1); @@ -622,23 +680,116 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)  {  	struct vring *vring = &wil->vring_tx[id]; +	WARN_ON(!mutex_is_locked(&wil->mutex)); +  	if (!vring->va)  		return; +	/* make sure NAPI won't touch this vring */ +	wil->vring_tx_data[id].enabled = 0; +	if (test_bit(wil_status_napi_en, &wil->status)) +		napi_synchronize(&wil->napi_tx); +  	wil_vring_free(wil, vring, 1);  }  static struct vring *wil_find_tx_vring(struct wil6210_priv *wil,  				       struct sk_buff *skb)  { -	struct vring *v = &wil->vring_tx[0]; +	int i; +	struct ethhdr *eth = (void *)skb->data; +	int cid = wil_find_cid(wil, eth->h_dest); + +	if (cid < 0) +		return NULL; -	if (v->va) -		return v; +	if (!wil->sta[cid].data_port_open && +	    (skb->protocol != cpu_to_be16(ETH_P_PAE))) +		return NULL; + +	/* TODO: fix for multiple TID */ +	for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) { +		if (wil->vring2cid_tid[i][0] == cid) { +			struct vring *v = &wil->vring_tx[i]; +			wil_dbg_txrx(wil, "%s(%pM) -> [%d]\n", +				     __func__, eth->h_dest, i); +			if (v->va) { +				return v; +			} else { +				wil_dbg_txrx(wil, "vring[%d] not valid\n", i); +				return NULL; +			} +		} +	}  	return NULL;  } +static void wil_set_da_for_vring(struct wil6210_priv *wil, +				 struct sk_buff *skb, int vring_index) +{ +	struct ethhdr *eth = (void *)skb->data; +	int cid = wil->vring2cid_tid[vring_index][0]; +	memcpy(eth->h_dest, wil->sta[cid].addr, ETH_ALEN); +} + +static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, +			struct sk_buff *skb); +/* + * Find 1-st vring and return it; set dest address for this vring in skb + * duplicate skb and send it to other active vrings + */ +static struct vring *wil_tx_bcast(struct wil6210_priv *wil, +				       struct sk_buff *skb) +{ +	struct vring *v, *v2; +	struct sk_buff *skb2; +	int i; +	u8 cid; + +	/* find 1-st vring eligible for data */ +	for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { +		v = &wil->vring_tx[i]; +		if (!v->va) +			continue; + +		cid = wil->vring2cid_tid[i][0]; +		if (!wil->sta[cid].data_port_open) +			continue; + +		goto found; +	} + +	wil_err(wil, "Tx while no vrings active?\n"); + +	return NULL; + +found: +	wil_dbg_txrx(wil, "BCAST -> ring %d\n", i); +	wil_set_da_for_vring(wil, skb, i); + +	/* find other active vrings and duplicate skb for each */ +	for (i++; i < WIL6210_MAX_TX_RINGS; i++) { +		v2 = &wil->vring_tx[i]; +		if (!v2->va) +			continue; +		cid = wil->vring2cid_tid[i][0]; +		if (!wil->sta[cid].data_port_open) +			continue; + +		skb2 = skb_copy(skb, GFP_ATOMIC); +		if (skb2) { +			wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i); +			wil_set_da_for_vring(wil, skb2, i); +			wil_tx_vring(wil, v2, skb2); +		} else { +			wil_err(wil, "skb_copy failed\n"); +		} +	} + +	return v; +} +  static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len,  			   int vring_index)  { @@ -664,6 +815,13 @@ static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len,  	return 0;  } +static inline +void wil_tx_desc_set_nr_frags(struct vring_tx_desc *d, int nr_frags) +{ +	d->mac.d[2] |= ((nr_frags + 1) << +		       MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS); +} +  static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil,  				struct vring_tx_desc *d,  				struct sk_buff *skb) @@ -673,9 +831,12 @@ static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil,  	if (skb->ip_summed != CHECKSUM_PARTIAL)  		return 0; +	d->dma.b11 = ETH_HLEN; /* MAC header length */ +  	switch (skb->protocol) {  	case cpu_to_be16(ETH_P_IP):  		protocol = ip_hdr(skb)->protocol; +		d->dma.b11 |= BIT(DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_POS);  		break;  	case cpu_to_be16(ETH_P_IPV6):  		protocol = ipv6_hdr(skb)->nexthdr; @@ -701,8 +862,6 @@ static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil,  	}  	d->dma.ip_length = skb_network_header_len(skb); -	d->dma.b11 = ETH_HLEN; /* MAC header length */ -	d->dma.b11 |= BIT(DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_POS);  	/* Enable TCP/UDP checksum */  	d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_POS);  	/* Calculate pseudo-header */ @@ -727,8 +886,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,  	wil_dbg_txrx(wil, "%s()\n", __func__); -	if (avail < vring->size/8) -		netif_tx_stop_all_queues(wil_to_ndev(wil));  	if (avail < 1 + nr_frags) {  		wil_err(wil, "Tx ring full. No space for %d fragments\n",  			1 + nr_frags); @@ -736,19 +893,17 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,  	}  	_d = &(vring->va[i].tx); -	/* FIXME FW can accept only unicast frames for the peer */ -	memcpy(skb->data, wil->dst_addr[vring_index], ETH_ALEN); -  	pa = dma_map_single(dev, skb->data,  			skb_headlen(skb), DMA_TO_DEVICE); -	wil_dbg_txrx(wil, "Tx skb %d bytes %p -> %#08llx\n", skb_headlen(skb), -		     skb->data, (unsigned long long)pa); +	wil_dbg_txrx(wil, "Tx skb %d bytes 0x%p -> %pad\n", skb_headlen(skb), +		     skb->data, &pa);  	wil_hex_dump_txrx("Tx ", DUMP_PREFIX_OFFSET, 16, 1,  			  skb->data, skb_headlen(skb), false);  	if (unlikely(dma_mapping_error(dev, pa)))  		return -EINVAL; +	vring->ctx[i].mapped_as = wil_mapped_as_single;  	/* 1-st segment */  	wil_tx_desc_map(d, pa, skb_headlen(skb), vring_index);  	/* Process TCP/UDP checksum offloading */ @@ -758,8 +913,8 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,  		goto dma_error;  	} -	d->mac.d[2] |= ((nr_frags + 1) << -		       MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS); +	vring->ctx[i].nr_frags = nr_frags; +	wil_tx_desc_set_nr_frags(d, nr_frags);  	if (nr_frags)  		*_d = *d; @@ -774,8 +929,13 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,  				DMA_TO_DEVICE);  		if (unlikely(dma_mapping_error(dev, pa)))  			goto dma_error; +		vring->ctx[i].mapped_as = wil_mapped_as_page;  		wil_tx_desc_map(d, pa, len, vring_index); -		vring->ctx[i].mapped_as_page = 1; +		/* no need to check return code - +		 * if it succeeded for 1-st descriptor, +		 * it will succeed here too +		 */ +		wil_tx_desc_offload_cksum_set(wil, d, skb);  		*_d = *d;  	}  	/* for the last seg only */ @@ -804,7 +964,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,  	/* unmap what we have mapped */  	nr_frags = f + 1; /* frags mapped + one for skb head */  	for (f = 0; f < nr_frags; f++) { -		u16 dmalen;  		struct wil_ctx *ctx;  		i = (swhead + f) % vring->size; @@ -812,12 +971,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,  		_d = &(vring->va[i].tx);  		*d = *_d;  		_d->dma.status = TX_DMA_STATUS_DU; -		pa = wil_desc_addr(&d->dma.addr); -		dmalen = le16_to_cpu(d->dma.length); -		if (ctx->mapped_as_page) -			dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE); -		else -			dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE); +		wil_txdesc_unmap(dev, d, ctx);  		if (ctx->skb)  			dev_kfree_skb_any(ctx->skb); @@ -832,12 +986,17 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,  netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)  {  	struct wil6210_priv *wil = ndev_to_wil(ndev); +	struct ethhdr *eth = (void *)skb->data;  	struct vring *vring; +	static bool pr_once_fw;  	int rc;  	wil_dbg_txrx(wil, "%s()\n", __func__);  	if (!test_bit(wil_status_fwready, &wil->status)) { -		wil_err(wil, "FW not ready\n"); +		if (!pr_once_fw) { +			wil_err(wil, "FW not ready\n"); +			pr_once_fw = true; +		}  		goto drop;  	}  	if (!test_bit(wil_status_fwconnected, &wil->status)) { @@ -848,16 +1007,25 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)  		wil_err(wil, "Xmit in monitor mode not supported\n");  		goto drop;  	} +	pr_once_fw = false;  	/* find vring */ -	vring = wil_find_tx_vring(wil, skb); +	if (is_unicast_ether_addr(eth->h_dest)) { +		vring = wil_find_tx_vring(wil, skb); +	} else { +		vring = wil_tx_bcast(wil, skb); +	}  	if (!vring) { -		wil_err(wil, "No Tx VRING available\n"); +		wil_err(wil, "No Tx VRING found for %pM\n", eth->h_dest);  		goto drop;  	}  	/* set up vring entry */  	rc = wil_tx_vring(wil, vring, skb); +	/* do we still have enough room in the vring? */ +	if (wil_vring_avail_tx(vring) < wil_vring_wmark_low(vring)) +		netif_tx_stop_all_queues(wil_to_ndev(wil)); +  	switch (rc) {  	case 0:  		/* statistics will be updated on the tx_complete */ @@ -887,66 +1055,84 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)  	struct net_device *ndev = wil_to_ndev(wil);  	struct device *dev = wil_to_dev(wil);  	struct vring *vring = &wil->vring_tx[ringid]; +	struct vring_tx_data *txdata = &wil->vring_tx_data[ringid];  	int done = 0; +	int cid = wil->vring2cid_tid[ringid][0]; +	struct wil_net_stats *stats = &wil->sta[cid].stats; +	volatile struct vring_tx_desc *_d;  	if (!vring->va) {  		wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid);  		return 0;  	} +	if (!txdata->enabled) { +		wil_info(wil, "Tx irq[%d]: vring disabled\n", ringid); +		return 0; +	} +  	wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid);  	while (!wil_vring_is_empty(vring)) { -		volatile struct vring_tx_desc *_d = -					      &vring->va[vring->swtail].tx; -		struct vring_tx_desc dd, *d = ⅆ -		dma_addr_t pa; -		u16 dmalen; +		int new_swtail;  		struct wil_ctx *ctx = &vring->ctx[vring->swtail]; -		struct sk_buff *skb = ctx->skb; - -		*d = *_d; +		/** +		 * For the fragmented skb, HW will set DU bit only for the +		 * last fragment. look for it +		 */ +		int lf = (vring->swtail + ctx->nr_frags) % vring->size; +		/* TODO: check we are not past head */ -		if (!(d->dma.status & TX_DMA_STATUS_DU)) +		_d = &vring->va[lf].tx; +		if (!(_d->dma.status & TX_DMA_STATUS_DU))  			break; -		dmalen = le16_to_cpu(d->dma.length); -		trace_wil6210_tx_done(ringid, vring->swtail, dmalen, -				      d->dma.error); -		wil_dbg_txrx(wil, -			     "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n", -			     vring->swtail, dmalen, d->dma.status, -			     d->dma.error); -		wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4, -				  (const void *)d, sizeof(*d), false); - -		pa = wil_desc_addr(&d->dma.addr); -		if (ctx->mapped_as_page) -			dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE); -		else -			dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE); - -		if (skb) { -			if (d->dma.error == 0) { -				ndev->stats.tx_packets++; -				ndev->stats.tx_bytes += skb->len; -			} else { -				ndev->stats.tx_errors++; -			} +		new_swtail = (lf + 1) % vring->size; +		while (vring->swtail != new_swtail) { +			struct vring_tx_desc dd, *d = ⅆ +			u16 dmalen; +			struct wil_ctx *ctx = &vring->ctx[vring->swtail]; +			struct sk_buff *skb = ctx->skb; +			_d = &vring->va[vring->swtail].tx; + +			*d = *_d; + +			dmalen = le16_to_cpu(d->dma.length); +			trace_wil6210_tx_done(ringid, vring->swtail, dmalen, +					      d->dma.error); +			wil_dbg_txrx(wil, +				     "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n", +				     vring->swtail, dmalen, d->dma.status, +				     d->dma.error); +			wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4, +					  (const void *)d, sizeof(*d), false); + +			wil_txdesc_unmap(dev, d, ctx); + +			if (skb) { +				if (d->dma.error == 0) { +					ndev->stats.tx_packets++; +					stats->tx_packets++; +					ndev->stats.tx_bytes += skb->len; +					stats->tx_bytes += skb->len; +				} else { +					ndev->stats.tx_errors++; +					stats->tx_errors++; +				} -			dev_kfree_skb_any(skb); +				dev_kfree_skb_any(skb); +			} +			memset(ctx, 0, sizeof(*ctx)); +			/* There is no need to touch HW descriptor: +			 * - ststus bit TX_DMA_STATUS_DU is set by design, +			 *   so hardware will not try to process this desc., +			 * - rest of descriptor will be initialized on Tx. +			 */ +			vring->swtail = wil_vring_next_tail(vring); +			done++;  		} -		memset(ctx, 0, sizeof(*ctx)); -		/* -		 * There is no need to touch HW descriptor: -		 * - ststus bit TX_DMA_STATUS_DU is set by design, -		 *   so hardware will not try to process this desc., -		 * - rest of descriptor will be initialized on Tx. -		 */ -		vring->swtail = wil_vring_next_tail(vring); -		done++;  	} -	if (wil_vring_avail_tx(vring) > vring->size/4) +	if (wil_vring_avail_tx(vring) > wil_vring_wmark_high(vring))  		netif_tx_wake_all_queues(wil_to_ndev(wil));  	return done; diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index b3828279204..bc5706a4f00 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -436,4 +436,11 @@ static inline struct vring_rx_desc *wil_skb_rxdesc(struct sk_buff *skb)  	return (void *)skb->cb;  } +void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev); +void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb); +struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, +						int size, u16 ssn); +void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, +			   struct wil_tid_ampdu_rx *r); +  #endif /* WIL6210_TXRX_H */ diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index c4a51638736..e25edc52398 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -35,10 +35,14 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)  #define WIL6210_MEM_SIZE (2*1024*1024UL)  #define WIL6210_RX_RING_SIZE	(128) -#define WIL6210_TX_RING_SIZE	(128) +#define WIL6210_TX_RING_SIZE	(512)  #define WIL6210_MAX_TX_RINGS	(24) /* HW limit */  #define WIL6210_MAX_CID		(8) /* HW limit */  #define WIL6210_NAPI_BUDGET	(16) /* arbitrary */ +#define WIL6210_ITR_TRSH	(10000) /* arbitrary - about 15 IRQs/msec */ +#define WIL6210_FW_RECOVERY_RETRIES	(5) /* try to recover this many times */ +#define WIL6210_FW_RECOVERY_TO	msecs_to_jiffies(5000) +#define WIL6210_SCAN_TO		msecs_to_jiffies(10000)  /* Hardware definitions begin */ @@ -73,23 +77,21 @@ struct RGF_ICR {  } __packed;  /* registers - FW addresses */ -#define RGF_USER_USER_SCRATCH_PAD	(0x8802bc) -#define RGF_USER_USER_ICR		(0x880b4c) /* struct RGF_ICR */ -	#define BIT_USER_USER_ICR_SW_INT_2	BIT(18) -#define RGF_USER_CLKS_CTL_SW_RST_MASK_0	(0x880b14) -#define RGF_USER_MAC_CPU_0		(0x8801fc) +#define RGF_USER_HW_MACHINE_STATE	(0x8801dc) +	#define HW_MACHINE_BOOT_DONE	(0x3fffffd)  #define RGF_USER_USER_CPU_0		(0x8801e0) +#define RGF_USER_MAC_CPU_0		(0x8801fc) +#define RGF_USER_USER_SCRATCH_PAD	(0x8802bc) +#define RGF_USER_FW_REV_ID		(0x880a8c) /* chip revision */ +#define RGF_USER_CLKS_CTL_0		(0x880abc) +	#define BIT_USER_CLKS_RST_PWGD	BIT(11) /* reset on "power good" */  #define RGF_USER_CLKS_CTL_SW_RST_VEC_0	(0x880b04)  #define RGF_USER_CLKS_CTL_SW_RST_VEC_1	(0x880b08)  #define RGF_USER_CLKS_CTL_SW_RST_VEC_2	(0x880b0c)  #define RGF_USER_CLKS_CTL_SW_RST_VEC_3	(0x880b10) - -#define RGF_DMA_PSEUDO_CAUSE		(0x881c68) -#define RGF_DMA_PSEUDO_CAUSE_MASK_SW	(0x881c6c) -#define RGF_DMA_PSEUDO_CAUSE_MASK_FW	(0x881c70) -	#define BIT_DMA_PSEUDO_CAUSE_RX		BIT(0) -	#define BIT_DMA_PSEUDO_CAUSE_TX		BIT(1) -	#define BIT_DMA_PSEUDO_CAUSE_MISC	BIT(2) +#define RGF_USER_CLKS_CTL_SW_RST_MASK_0	(0x880b14) +#define RGF_USER_USER_ICR		(0x880b4c) /* struct RGF_ICR */ +	#define BIT_USER_USER_ICR_SW_INT_2	BIT(18)  #define RGF_DMA_EP_TX_ICR		(0x881bb4) /* struct RGF_ICR */  	#define BIT_DMA_EP_TX_ICR_TX_DONE	BIT(0) @@ -104,13 +106,22 @@ struct RGF_ICR {  /* Interrupt moderation control */  #define RGF_DMA_ITR_CNT_TRSH		(0x881c5c)  #define RGF_DMA_ITR_CNT_DATA		(0x881c60) -#define RGF_DMA_ITR_CNT_CRL		(0x881C64) +#define RGF_DMA_ITR_CNT_CRL		(0x881c64)  	#define BIT_DMA_ITR_CNT_CRL_EN		BIT(0)  	#define BIT_DMA_ITR_CNT_CRL_EXT_TICK	BIT(1)  	#define BIT_DMA_ITR_CNT_CRL_FOREVER	BIT(2)  	#define BIT_DMA_ITR_CNT_CRL_CLR		BIT(3)  	#define BIT_DMA_ITR_CNT_CRL_REACH_TRSH	BIT(4) +#define RGF_DMA_PSEUDO_CAUSE		(0x881c68) +#define RGF_DMA_PSEUDO_CAUSE_MASK_SW	(0x881c6c) +#define RGF_DMA_PSEUDO_CAUSE_MASK_FW	(0x881c70) +	#define BIT_DMA_PSEUDO_CAUSE_RX		BIT(0) +	#define BIT_DMA_PSEUDO_CAUSE_TX		BIT(1) +	#define BIT_DMA_PSEUDO_CAUSE_MISC	BIT(2) + +#define RGF_PCIE_LOS_COUNTER_CTL	(0x882dc4) +  /* popular locations */  #define HOST_MBOX   HOSTADDR(RGF_USER_USER_SCRATCH_PAD)  #define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \ @@ -124,6 +135,31 @@ struct RGF_ICR {  /* Hardware definitions end */ +/** + * mk_cidxtid - construct @cidxtid field + * @cid: CID value + * @tid: TID value + * + * @cidxtid field encoded as bits 0..3 - CID; 4..7 - TID + */ +static inline u8 mk_cidxtid(u8 cid, u8 tid) +{ +	return ((tid & 0xf) << 4) | (cid & 0xf); +} + +/** + * parse_cidxtid - parse @cidxtid field + * @cid: store CID value here + * @tid: store TID value here + * + * @cidxtid field encoded as bits 0..3 - CID; 4..7 - TID + */ +static inline void parse_cidxtid(u8 cidxtid, u8 *cid, u8 *tid) +{ +	*cid = cidxtid & 0xf; +	*tid = (cidxtid >> 4) & 0xf; +} +  struct wil6210_mbox_ring {  	u32 base;  	u16 entry_size; /* max. size of mbox entry, incl. all headers */ @@ -183,12 +219,19 @@ struct pending_wmi_event {  	} __packed event;  }; +enum { /* for wil_ctx.mapped_as */ +	wil_mapped_as_none = 0, +	wil_mapped_as_single = 1, +	wil_mapped_as_page = 2, +}; +  /**   * struct wil_ctx - software context for Vring descriptor   */  struct wil_ctx {  	struct sk_buff *skb; -	u8 mapped_as_page:1; +	u8 nr_frags; +	u8 mapped_as;  };  union vring_desc; @@ -203,6 +246,14 @@ struct vring {  	struct wil_ctx *ctx; /* ctx[size] - software context */  }; +/** + * Additional data for Tx Vring + */ +struct vring_tx_data { +	int enabled; + +}; +  enum { /* for wil6210_priv.status */  	wil_status_fwready = 0,  	wil_status_fwconnecting, @@ -210,10 +261,52 @@ enum { /* for wil6210_priv.status */  	wil_status_dontscan,  	wil_status_reset_done,  	wil_status_irqen, /* FIXME: interrupts enabled - for debug */ +	wil_status_napi_en, /* NAPI enabled protected by wil->mutex */  };  struct pci_dev; +/** + * struct tid_ampdu_rx - TID aggregation information (Rx). + * + * @reorder_buf: buffer to reorder incoming aggregated MPDUs + * @reorder_time: jiffies when skb was added + * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) + * @reorder_timer: releases expired frames from the reorder buffer. + * @last_rx: jiffies of last rx activity + * @head_seq_num: head sequence number in reordering buffer. + * @stored_mpdu_num: number of MPDUs in reordering buffer + * @ssn: Starting Sequence Number expected to be aggregated. + * @buf_size: buffer size for incoming A-MPDUs + * @timeout: reset timer value (in TUs). + * @dialog_token: dialog token for aggregation session + * @rcu_head: RCU head used for freeing this struct + * @reorder_lock: serializes access to reorder buffer, see below. + * + * This structure's lifetime is managed by RCU, assignments to + * the array holding it must hold the aggregation mutex. + * + * The @reorder_lock is used to protect the members of this + * struct, except for @timeout, @buf_size and @dialog_token, + * which are constant across the lifetime of the struct (the + * dialog token being used only for debugging). + */ +struct wil_tid_ampdu_rx { +	spinlock_t reorder_lock; /* see above */ +	struct sk_buff **reorder_buf; +	unsigned long *reorder_time; +	struct timer_list session_timer; +	struct timer_list reorder_timer; +	unsigned long last_rx; +	u16 head_seq_num; +	u16 stored_mpdu_num; +	u16 ssn; +	u16 buf_size; +	u16 timeout; +	u8 dialog_token; +	bool first_time; /* is it 1-st time this buffer used? */ +}; +  struct wil6210_stats {  	u64 tsf;  	u32 snr; @@ -225,6 +318,43 @@ struct wil6210_stats {  	u16 peer_tx_sector;  }; +enum wil_sta_status { +	wil_sta_unused = 0, +	wil_sta_conn_pending = 1, +	wil_sta_connected = 2, +}; + +#define WIL_STA_TID_NUM (16) + +struct wil_net_stats { +	unsigned long	rx_packets; +	unsigned long	tx_packets; +	unsigned long	rx_bytes; +	unsigned long	tx_bytes; +	unsigned long	tx_errors; +	unsigned long	rx_dropped; +	u16 last_mcs_rx; +}; + +/** + * struct wil_sta_info - data for peer + * + * Peer identified by its CID (connection ID) + * NIC performs beam forming for each peer; + * if no beam forming done, frame exchange is not + * possible. + */ +struct wil_sta_info { +	u8 addr[ETH_ALEN]; +	enum wil_sta_status status; +	struct wil_net_stats stats; +	bool data_port_open; /* can send any data, not only EAPOL */ +	/* Rx BACK */ +	struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM]; +	unsigned long tid_rx_timer_expired[BITS_TO_LONGS(WIL_STA_TID_NUM)]; +	unsigned long tid_rx_stop_requested[BITS_TO_LONGS(WIL_STA_TID_NUM)]; +}; +  struct wil6210_priv {  	struct pci_dev *pdev;  	int n_msi; @@ -232,7 +362,10 @@ struct wil6210_priv {  	void __iomem *csr;  	ulong status;  	u32 fw_version; +	u32 hw_version;  	u8 n_mids; /* number of additional MIDs as reported by FW */ +	int recovery_count; /* num of FW recovery attempts in a short time */ +	unsigned long last_fw_recovery; /* jiffies of last fw recovery */  	/* profile */  	u32 monitor_flags;  	u32 secure_pcp; /* create secure PCP? */ @@ -252,7 +385,9 @@ struct wil6210_priv {  	struct workqueue_struct *wmi_wq_conn; /* for connect worker */  	struct work_struct connect_worker;  	struct work_struct disconnect_worker; +	struct work_struct fw_error_worker;	/* for FW error recovery */  	struct timer_list connect_timer; +	struct timer_list scan_timer; /* detect scan timeout */  	int pending_connect_cid;  	struct list_head pending_wmi_ev;  	/* @@ -266,7 +401,9 @@ struct wil6210_priv {  	/* DMA related */  	struct vring vring_rx;  	struct vring vring_tx[WIL6210_MAX_TX_RINGS]; -	u8 dst_addr[WIL6210_MAX_TX_RINGS][ETH_ALEN]; +	struct vring_tx_data vring_tx_data[WIL6210_MAX_TX_RINGS]; +	u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */ +	struct wil_sta_info sta[WIL6210_MAX_CID];  	/* scan */  	struct cfg80211_scan_request *scan_request; @@ -328,11 +465,13 @@ void wil_if_remove(struct wil6210_priv *wil);  int wil_priv_init(struct wil6210_priv *wil);  void wil_priv_deinit(struct wil6210_priv *wil);  int wil_reset(struct wil6210_priv *wil); +void wil_fw_error_recovery(struct wil6210_priv *wil);  void wil_link_on(struct wil6210_priv *wil);  void wil_link_off(struct wil6210_priv *wil);  int wil_up(struct wil6210_priv *wil);  int wil_down(struct wil6210_priv *wil);  void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); +int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);  void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr);  void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr); @@ -356,8 +495,11 @@ int wmi_echo(struct wil6210_priv *wil);  int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie);  int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring);  int wmi_p2p_cfg(struct wil6210_priv *wil, int channel); +int wmi_rxon(struct wil6210_priv *wil, bool on);  int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r); +int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason); +void wil6210_clear_irq(struct wil6210_priv *wil);  int wil6210_init_irq(struct wil6210_priv *wil, int irq);  void wil6210_fini_irq(struct wil6210_priv *wil, int irq);  void wil6210_disable_irq(struct wil6210_priv *wil); @@ -372,7 +514,7 @@ void wil_wdev_free(struct wil6210_priv *wil);  int wmi_set_mac_address(struct wil6210_priv *wil, void *addr);  int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan);  int wmi_pcp_stop(struct wil6210_priv *wil); -void wil6210_disconnect(struct wil6210_priv *wil, void *bssid); +void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid);  int wil_rx_init(struct wil6210_priv *wil);  void wil_rx_fini(struct wil6210_priv *wil); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 063963ee422..6cc0e182cc7 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -192,7 +192,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)  	might_sleep();  	if (!test_bit(wil_status_fwready, &wil->status)) { -		wil_err(wil, "FW not ready\n"); +		wil_err(wil, "WMI: cannot send command while FW not ready\n");  		return -EAGAIN;  	} @@ -276,8 +276,8 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)  	wil->fw_version = le32_to_cpu(evt->sw_version);  	wil->n_mids = evt->numof_additional_mids; -	wil_dbg_wmi(wil, "FW ver. %d; MAC %pM; %d MID's\n", wil->fw_version, -		    evt->mac, wil->n_mids); +	wil_info(wil, "FW ver. %d; MAC %pM; %d MID's\n", wil->fw_version, +		 evt->mac, wil->n_mids);  	if (!is_valid_ether_addr(ndev->dev_addr)) {  		memcpy(ndev->dev_addr, evt->mac, ETH_ALEN); @@ -290,7 +290,7 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)  static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d,  			     int len)  { -	wil_dbg_wmi(wil, "WMI: FW ready\n"); +	wil_dbg_wmi(wil, "WMI: got FW ready event\n");  	set_bit(wil_status_fwready, &wil->status);  	/* reuse wmi_ready for the firmware ready indication */ @@ -307,14 +307,14 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)  	u32 freq = ieee80211_channel_to_frequency(ch_no,  			IEEE80211_BAND_60GHZ);  	struct ieee80211_channel *channel = ieee80211_get_channel(wiphy, freq); -	/* TODO convert LE to CPU */ -	s32 signal = 0; /* TODO */ +	s32 signal = data->info.sqi;  	__le16 fc = rx_mgmt_frame->frame_control;  	u32 d_len = le32_to_cpu(data->info.len);  	u16 d_status = le16_to_cpu(data->info.status); -	wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d\n", -		    data->info.channel, data->info.mcs, data->info.snr); +	wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d SQI %d%%\n", +		    data->info.channel, data->info.mcs, data->info.snr, +		    data->info.sqi);  	wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len,  		    le16_to_cpu(fc));  	wil_dbg_wmi(wil, "qid %d mid %d cid %d\n", @@ -348,9 +348,10 @@ static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id,  {  	if (wil->scan_request) {  		struct wmi_scan_complete_event *data = d; -		bool aborted = (data->status != 0); +		bool aborted = (data->status != WMI_SCAN_SUCCESS);  		wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", data->status); +		del_timer_sync(&wil->scan_timer);  		cfg80211_scan_done(wil->scan_request, aborted);  		wil->scan_request = NULL;  	} else { @@ -384,6 +385,11 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)  			evt->assoc_req_len, evt->assoc_resp_len);  		return;  	} +	if (evt->cid >= WIL6210_MAX_CID) { +		wil_err(wil, "Connect CID invalid : %d\n", evt->cid); +		return; +	} +  	ch = evt->channel + 1;  	wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n",  		    evt->bssid, ch, evt->cid); @@ -439,7 +445,8 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)  	/* FIXME FW can transmit only ucast frames to peer */  	/* FIXME real ring_id instead of hard coded 0 */ -	memcpy(wil->dst_addr[0], evt->bssid, ETH_ALEN); +	memcpy(wil->sta[evt->cid].addr, evt->bssid, ETH_ALEN); +	wil->sta[evt->cid].status = wil_sta_conn_pending;  	wil->pending_connect_cid = evt->cid;  	queue_work(wil->wmi_wq_conn, &wil->connect_worker); @@ -456,7 +463,9 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,  	wil->sinfo_gen++; +	mutex_lock(&wil->mutex);  	wil6210_disconnect(wil, evt->bssid); +	mutex_unlock(&wil->mutex);  }  static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) @@ -476,11 +485,11 @@ static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len)  	wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector);  	wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector);  	wil_dbg_wmi(wil, "Link status, MCS %d TSF 0x%016llx\n" -		    "BF status 0x%08x SNR 0x%08x\n" +		    "BF status 0x%08x SNR 0x%08x SQI %d%%\n"  		    "Tx Tpt %d goodput %d Rx goodput %d\n"  		    "Sectors(rx:tx) my %d:%d peer %d:%d\n",  		    wil->stats.bf_mcs, wil->stats.tsf, evt->status, -		    wil->stats.snr, le32_to_cpu(evt->tx_tpt), +		    wil->stats.snr, evt->sqi, le32_to_cpu(evt->tx_tpt),  		    le32_to_cpu(evt->tx_goodput), le32_to_cpu(evt->rx_goodput),  		    wil->stats.my_rx_sector, wil->stats.my_tx_sector,  		    wil->stats.peer_rx_sector, wil->stats.peer_tx_sector); @@ -499,10 +508,16 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,  	int sz = eapol_len + ETH_HLEN;  	struct sk_buff *skb;  	struct ethhdr *eth; +	int cid; +	struct wil_net_stats *stats = NULL;  	wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len,  		    evt->src_mac); +	cid = wil_find_cid(wil, evt->src_mac); +	if (cid >= 0) +		stats = &wil->sta[cid].stats; +  	if (eapol_len > 196) { /* TODO: revisit size limit */  		wil_err(wil, "EAPOL too large\n");  		return; @@ -513,6 +528,7 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,  		wil_err(wil, "Failed to allocate skb\n");  		return;  	} +  	eth = (struct ethhdr *)skb_put(skb, ETH_HLEN);  	memcpy(eth->h_dest, ndev->dev_addr, ETH_ALEN);  	memcpy(eth->h_source, evt->src_mac, ETH_ALEN); @@ -521,9 +537,15 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,  	skb->protocol = eth_type_trans(skb, ndev);  	if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) {  		ndev->stats.rx_packets++; -		ndev->stats.rx_bytes += skb->len; +		ndev->stats.rx_bytes += sz; +		if (stats) { +			stats->rx_packets++; +			stats->rx_bytes += sz; +		}  	} else {  		ndev->stats.rx_dropped++; +		if (stats) +			stats->rx_dropped++;  	}  } @@ -531,9 +553,16 @@ static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len)  {  	struct net_device *ndev = wil_to_ndev(wil);  	struct wmi_data_port_open_event *evt = d; +	u8 cid = evt->cid; + +	wil_dbg_wmi(wil, "Link UP for CID %d\n", cid); -	wil_dbg_wmi(wil, "Link UP for CID %d\n", evt->cid); +	if (cid >= ARRAY_SIZE(wil->sta)) { +		wil_err(wil, "Link UP for invalid CID %d\n", cid); +		return; +	} +	wil->sta[cid].data_port_open = true;  	netif_carrier_on(ndev);  } @@ -541,10 +570,17 @@ static void wmi_evt_linkdown(struct wil6210_priv *wil, int id, void *d, int len)  {  	struct net_device *ndev = wil_to_ndev(wil);  	struct wmi_wbe_link_down_event *evt = d; +	u8 cid = evt->cid;  	wil_dbg_wmi(wil, "Link DOWN for CID %d, reason %d\n", -		    evt->cid, le32_to_cpu(evt->reason)); +		    cid, le32_to_cpu(evt->reason)); +	if (cid >= ARRAY_SIZE(wil->sta)) { +		wil_err(wil, "Link DOWN for invalid CID %d\n", cid); +		return; +	} + +	wil->sta[cid].data_port_open = false;  	netif_carrier_off(ndev);  } @@ -552,10 +588,42 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,  			      int len)  {  	struct wmi_vring_ba_status_event *evt = d; +	struct wil_sta_info *sta; +	uint i, cid; + +	/* TODO: use Rx BA status, not Tx one */  	wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n", -		    evt->ringid, evt->status ? "N/A" : "OK", evt->agg_wsize, -		    __le16_to_cpu(evt->ba_timeout)); +		    evt->ringid, +		    evt->status == WMI_BA_AGREED ? "OK" : "N/A", +		    evt->agg_wsize, __le16_to_cpu(evt->ba_timeout)); + +	if (evt->ringid >= WIL6210_MAX_TX_RINGS) { +		wil_err(wil, "invalid ring id %d\n", evt->ringid); +		return; +	} + +	cid = wil->vring2cid_tid[evt->ringid][0]; +	if (cid >= WIL6210_MAX_CID) { +		wil_err(wil, "invalid CID %d for vring %d\n", cid, evt->ringid); +		return; +	} + +	sta = &wil->sta[cid]; +	if (sta->status == wil_sta_unused) { +		wil_err(wil, "CID %d unused\n", cid); +		return; +	} + +	wil_dbg_wmi(wil, "BACK for CID %d %pM\n", cid, sta->addr); +	for (i = 0; i < WIL_STA_TID_NUM; i++) { +		struct wil_tid_ampdu_rx *r = sta->tid_rx[i]; +		sta->tid_rx[i] = NULL; +		wil_tid_ampdu_rx_free(wil, r); +		if ((evt->status == WMI_BA_AGREED) && evt->agg_wsize) +			sta->tid_rx[i] = wil_tid_ampdu_rx_alloc(wil, +						evt->agg_wsize, 0); +	}  }  static const struct { @@ -591,21 +659,27 @@ void wmi_recv_cmd(struct wil6210_priv *wil)  	u8 *cmd;  	void __iomem *src;  	ulong flags; +	unsigned n;  	if (!test_bit(wil_status_reset_done, &wil->status)) {  		wil_err(wil, "Reset not completed\n");  		return;  	} -	for (;;) { +	for (n = 0;; n++) {  		u16 len;  		r->head = ioread32(wil->csr + HOST_MBOX +  				   offsetof(struct wil6210_mbox_ctl, rx.head)); -		if (r->tail == r->head) +		if (r->tail == r->head) { +			if (n == 0) +				wil_dbg_wmi(wil, "No events?\n");  			return; +		} -		/* read cmd from tail */ +		wil_dbg_wmi(wil, "Mbox head %08x tail %08x\n", +			    r->head, r->tail); +		/* read cmd descriptor from tail */  		wil_memcpy_fromio_32(&d_tail, wil->csr + HOSTADDR(r->tail),  				     sizeof(struct wil6210_mbox_ring_desc));  		if (d_tail.sync == 0) { @@ -613,13 +687,18 @@ void wmi_recv_cmd(struct wil6210_priv *wil)  			return;  		} +		/* read cmd header from descriptor */  		if (0 != wmi_read_hdr(wil, d_tail.addr, &hdr)) {  			wil_err(wil, "Mbox evt at 0x%08x?\n",  				le32_to_cpu(d_tail.addr));  			return;  		} -  		len = le16_to_cpu(hdr.len); +		wil_dbg_wmi(wil, "Mbox evt %04x %04x %04x %02x\n", +			    le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type), +			    hdr.flags); + +		/* read cmd buffer from descriptor */  		src = wmi_buffer(wil, d_tail.addr) +  		      sizeof(struct wil6210_mbox_hdr);  		evt = kmalloc(ALIGN(offsetof(struct pending_wmi_event, @@ -635,9 +714,6 @@ void wmi_recv_cmd(struct wil6210_priv *wil)  		iowrite32(0, wil->csr + HOSTADDR(r->tail) +  			  offsetof(struct wil6210_mbox_ring_desc, sync));  		/* indicate */ -		wil_dbg_wmi(wil, "Mbox evt %04x %04x %04x %02x\n", -			    le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type), -			    hdr.flags);  		if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) &&  		    (len >= sizeof(struct wil6210_mbox_hdr_wmi))) {  			struct wil6210_mbox_hdr_wmi *wmi = &evt->event.wmi; @@ -667,6 +743,8 @@ void wmi_recv_cmd(struct wil6210_priv *wil)  			wil_dbg_wmi(wil, "queue_work -> %d\n", q);  		}  	} +	if (n > 1) +		wil_dbg_wmi(wil, "%s -> %d events processed\n", __func__, n);  }  int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, @@ -735,6 +813,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan)  		.network_type = wmi_nettype,  		.disable_sec_offload = 1,  		.channel = chan - 1, +		.pcp_max_assoc_sta = WIL6210_MAX_CID,  	};  	struct {  		struct wil6210_mbox_hdr_wmi wmi; @@ -893,6 +972,38 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)  	return rc;  } +/** + * wmi_rxon - turn radio on/off + * @on:		turn on if true, off otherwise + * + * Only switch radio. Channel should be set separately. + * No timeout for rxon - radio turned on forever unless some other call + * turns it off + */ +int wmi_rxon(struct wil6210_priv *wil, bool on) +{ +	int rc; +	struct { +		struct wil6210_mbox_hdr_wmi wmi; +		struct wmi_listen_started_event evt; +	} __packed reply; + +	wil_info(wil, "%s(%s)\n", __func__, on ? "on" : "off"); + +	if (on) { +		rc = wmi_call(wil, WMI_START_LISTEN_CMDID, NULL, 0, +			      WMI_LISTEN_STARTED_EVENTID, +			      &reply, sizeof(reply), 100); +		if ((rc == 0) && (reply.evt.status != WMI_FW_STATUS_SUCCESS)) +			rc = -EINVAL; +	} else { +		rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, NULL, 0, +			      WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 20); +	} + +	return rc; +} +  int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)  {  	struct wireless_dev *wdev = wil->wdev; @@ -906,6 +1017,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)  		},  		.mid = 0, /* TODO - what is it? */  		.decap_trans_type = WMI_DECAP_TYPE_802_3, +		.reorder_type = WMI_RX_SW_REORDER,  	};  	struct {  		struct wil6210_mbox_hdr_wmi wmi; @@ -973,6 +1085,18 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r)  	return 0;  } +int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason) +{ +	struct wmi_disconnect_sta_cmd cmd = { +		.disconnect_reason = cpu_to_le16(reason), +	}; +	memcpy(cmd.dst_mac, mac, ETH_ALEN); + +	wil_dbg_wmi(wil, "%s(%pM, reason %d)\n", __func__, mac, reason); + +	return wmi_send(wil, WMI_DISCONNECT_STA_CMDID, &cmd, sizeof(cmd)); +} +  void wmi_event_flush(struct wil6210_priv *wil)  {  	struct pending_wmi_event *evt, *t; diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 50b8528394f..17334c85286 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -28,7 +28,7 @@  #define __WILOCITY_WMI_H__  /* General */ - +#define WILOCITY_MAX_ASSOC_STA (8)  #define WMI_MAC_LEN		(6)  #define WMI_PROX_RANGE_NUM	(3) @@ -219,15 +219,6 @@ struct wmi_disconnect_sta_cmd {  	__le16 disconnect_reason;  } __packed; -/* - * WMI_RECONNECT_CMDID - */ -struct wmi_reconnect_cmd { -	u8 channel;			/* hint */ -	u8 reserved; -	u8 bssid[WMI_MAC_LEN];		/* mandatory if set */ -} __packed; -  /*   * WMI_SET_PMK_CMDID @@ -296,11 +287,13 @@ enum wmi_scan_type {  	WMI_LONG_SCAN		= 0,  	WMI_SHORT_SCAN		= 1,  	WMI_PBC_SCAN		= 2, +	WMI_ACTIVE_SCAN		= 3, +	WMI_DIRECT_SCAN		= 4,  };  struct wmi_start_scan_cmd { -	u8 reserved[8]; - +	u8 direct_scan_mac_addr[6]; +	u8 reserved[2];  	__le32 home_dwell_time;	/* Max duration in the home channel(ms) */  	__le32 force_scan_interval;	/* Time interval between scans (ms)*/  	u8 scan_type;		/* wmi_scan_type */ @@ -332,6 +325,7 @@ struct wmi_probed_ssid_cmd {  	u8 ssid[WMI_MAX_SSID_LEN];  } __packed; +  /*   * WMI_SET_APPIE_CMDID   * Add Application specified IE to a management frame @@ -427,7 +421,7 @@ struct wmi_bcon_ctrl_cmd {  	__le16 frag_num;  	__le64 ss_mask;  	u8 network_type; -	u8 reserved; +	u8 pcp_max_assoc_sta;  	u8 disable_sec_offload;  	u8 disable_sec;  } __packed; @@ -450,7 +444,7 @@ enum wmi_port_role {  struct wmi_port_allocate_cmd {  	u8 mac[WMI_MAC_LEN];  	u8 port_role; -	u8 midid; +	u8 mid;  } __packed;  /* @@ -467,6 +461,7 @@ struct wmi_delete_port_cmd {  enum wmi_discovery_mode {  	WMI_DISCOVERY_MODE_NON_OFFLOAD	= 0,  	WMI_DISCOVERY_MODE_OFFLOAD	= 1, +	WMI_DISCOVERY_MODE_PEER2PEER	= 2,  };  struct wmi_p2p_cfg_cmd { @@ -493,7 +488,8 @@ struct wmi_power_mgmt_cfg_cmd {   */  struct wmi_pcp_start_cmd {  	__le16 bcon_interval; -	u8 reserved0[10]; +	u8 pcp_max_assoc_sta; +	u8 reserved0[9];  	u8 network_type;  	u8 channel;  	u8 disable_sec_offload; @@ -857,6 +853,7 @@ enum wmi_event_id {  	WMI_RF_MGMT_STATUS_EVENTID		= 0x1853,  	WMI_BF_SM_MGMT_DONE_EVENTID		= 0x1838,  	WMI_RX_MGMT_PACKET_EVENTID		= 0x1840, +	WMI_TX_MGMT_PACKET_EVENTID		= 0x1841,  	/* Performance monitoring events */  	WMI_DATA_PORT_OPEN_EVENTID		= 0x1860, @@ -1040,16 +1037,23 @@ enum wmi_disconnect_reason {  struct wmi_disconnect_event {  	__le16 protocol_reason_status;	/* reason code, see 802.11 spec. */  	u8 bssid[WMI_MAC_LEN];		/* set if known */ -	u8 disconnect_reason;		/* see wmi_disconnect_reason_e */ -	u8 assoc_resp_len; -	u8 assoc_info[0]; +	u8 disconnect_reason;		/* see wmi_disconnect_reason */ +	u8 assoc_resp_len;		/* not in use */ +	u8 assoc_info[0];		/* not in use */  } __packed;  /*   * WMI_SCAN_COMPLETE_EVENTID   */ +enum scan_status { +	WMI_SCAN_SUCCESS	= 0, +	WMI_SCAN_FAILED		= 1, +	WMI_SCAN_ABORTED	= 2, +	WMI_SCAN_REJECTED	= 3, +}; +  struct wmi_scan_complete_event { -	__le32 status; +	__le32 status;	/* scan_status */  } __packed;  /* @@ -1256,6 +1260,14 @@ struct wmi_rx_mgmt_info {  	u8 channel;	/* From Radio MNGR */  } __packed; + +/* + * WMI_TX_MGMT_PACKET_EVENTID + */ +struct wmi_tx_mgmt_packet_event { +	u8 payload[0]; +} __packed; +  struct wmi_rx_mgmt_packet_event {  	struct wmi_rx_mgmt_info info;  	u8 payload[0];  | 
