diff options
Diffstat (limited to 'drivers/net/wireless/ti/wlcore')
24 files changed, 698 insertions, 381 deletions
diff --git a/drivers/net/wireless/ti/wlcore/acx.c b/drivers/net/wireless/ti/wlcore/acx.c index 7a970cd9c55..b924ceadc02 100644 --- a/drivers/net/wireless/ti/wlcore/acx.c +++ b/drivers/net/wireless/ti/wlcore/acx.c @@ -162,7 +162,8 @@ int wl1271_acx_mem_map(struct wl1271 *wl, struct acx_header *mem_map,  	wl1271_debug(DEBUG_ACX, "acx mem map"); -	ret = wl1271_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); +	ret = wl1271_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, +				     sizeof(struct acx_header), len);  	if (ret < 0)  		return ret; @@ -357,7 +358,8 @@ int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, struct wl12xx_vif *wlvif,  	struct acx_beacon_filter_option *beacon_filter = NULL;  	int ret = 0; -	wl1271_debug(DEBUG_ACX, "acx beacon filter opt"); +	wl1271_debug(DEBUG_ACX, "acx beacon filter opt enable=%d", +		     enable_filter);  	if (enable_filter &&  	    wl->conf.conn.bcn_filt_mode == CONF_BCN_FILT_MODE_DISABLED) @@ -722,6 +724,7 @@ int wl1271_acx_statistics(struct wl1271 *wl, void *stats)  	wl1271_debug(DEBUG_ACX, "acx statistics");  	ret = wl1271_cmd_interrogate(wl, ACX_STATISTICS, stats, +				     sizeof(struct acx_header),  				     wl->stats.fw_stats_len);  	if (ret < 0) {  		wl1271_warning("acx statistics failed: %d", ret); @@ -1470,8 +1473,8 @@ int wl12xx_acx_tsf_info(struct wl1271 *wl, struct wl12xx_vif *wlvif,  	tsf_info->role_id = wlvif->role_id; -	ret = wl1271_cmd_interrogate(wl, ACX_TSF_INFO, -				     tsf_info, sizeof(*tsf_info)); +	ret = wl1271_cmd_interrogate(wl, ACX_TSF_INFO, tsf_info, +				sizeof(struct acx_header), sizeof(*tsf_info));  	if (ret < 0) {  		wl1271_warning("acx tsf info interrogate failed");  		goto out; @@ -1589,7 +1592,8 @@ out:  	return ret;  } -int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr) +int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, +				    struct wl12xx_vif *wlvif, u8 *addr)  {  	struct wl1271_acx_inconnection_sta *acx = NULL;  	int ret; @@ -1601,6 +1605,7 @@ int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr)  		return -ENOMEM;  	memcpy(acx->addr, addr, ETH_ALEN); +	acx->role_id = wlvif->role_id;  	ret = wl1271_cmd_configure(wl, ACX_UPDATE_INCONNECTION_STA_LIST,  				   acx, sizeof(*acx)); @@ -1752,7 +1757,7 @@ int wlcore_acx_average_rssi(struct wl1271 *wl, struct wl12xx_vif *wlvif,  	acx->role_id = wlvif->role_id;  	ret = wl1271_cmd_interrogate(wl, ACX_ROAMING_STATISTICS_TBL, -				     acx, sizeof(*acx)); +				     acx, sizeof(*acx), sizeof(*acx));  	if (ret	< 0) {  		wl1271_warning("acx roaming statistics failed: %d", ret);  		ret = -ENOMEM; diff --git a/drivers/net/wireless/ti/wlcore/acx.h b/drivers/net/wireless/ti/wlcore/acx.h index 6dcfad9b047..954d57ec98f 100644 --- a/drivers/net/wireless/ti/wlcore/acx.h +++ b/drivers/net/wireless/ti/wlcore/acx.h @@ -824,7 +824,8 @@ struct wl1271_acx_inconnection_sta {  	struct acx_header header;  	u8 addr[ETH_ALEN]; -	u8 padding1[2]; +	u8 role_id; +	u8 padding;  } __packed;  /* @@ -1118,7 +1119,8 @@ int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,  			       bool enable);  int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl, struct wl12xx_vif *wlvif);  int wl12xx_acx_config_ps(struct wl1271 *wl, struct wl12xx_vif *wlvif); -int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); +int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, +				    struct wl12xx_vif *wlvif, u8 *addr);  int wl1271_acx_fm_coex(struct wl1271 *wl);  int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl);  int wl12xx_acx_config_hangover(struct wl1271 *wl); diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index c9e060795d1..40dc30f4faa 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -60,7 +60,8 @@ static int __wlcore_cmd_send(struct wl1271 *wl, u16 id, void *buf,  	u16 status;  	u16 poll_count = 0; -	if (WARN_ON(unlikely(wl->state == WLCORE_STATE_RESTARTING))) +	if (unlikely(wl->state == WLCORE_STATE_RESTARTING && +		     id != CMD_STOP_FWLOGGER))  		return -EIO;  	cmd = buf; @@ -311,8 +312,8 @@ static int wlcore_get_new_session_id(struct wl1271 *wl, u8 hlid)  int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)  {  	unsigned long flags; -	u8 link = find_first_zero_bit(wl->links_map, WL12XX_MAX_LINKS); -	if (link >= WL12XX_MAX_LINKS) +	u8 link = find_first_zero_bit(wl->links_map, wl->num_links); +	if (link >= wl->num_links)  		return -EBUSY;  	wl->session_ids[link] = wlcore_get_new_session_id(wl, link); @@ -323,9 +324,14 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)  	__set_bit(link, wlvif->links_map);  	spin_unlock_irqrestore(&wl->wl_lock, flags); -	/* take the last "freed packets" value from the current FW status */ -	wl->links[link].prev_freed_pkts = -			wl->fw_status_2->counters.tx_lnk_free_pkts[link]; +	/* +	 * take the last "freed packets" value from the current FW status. +	 * on recovery, we might not have fw_status yet, and +	 * tx_lnk_free_pkts will be NULL. check for it. +	 */ +	if (wl->fw_status->counters.tx_lnk_free_pkts) +		wl->links[link].prev_freed_pkts = +			wl->fw_status->counters.tx_lnk_free_pkts[link];  	wl->links[link].wlvif = wlvif;  	/* @@ -845,7 +851,8 @@ EXPORT_SYMBOL_GPL(wl1271_cmd_test);   * @buf: buffer for the response, including all headers, must work with dma   * @len: length of buf   */ -int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len) +int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, +			   size_t cmd_len, size_t res_len)  {  	struct acx_header *acx = buf;  	int ret; @@ -854,10 +861,10 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len)  	acx->id = cpu_to_le16(id); -	/* payload length, does not include any headers */ -	acx->len = cpu_to_le16(len - sizeof(*acx)); +	/* response payload length, does not include any headers */ +	acx->len = cpu_to_le16(res_len - sizeof(*acx)); -	ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx), len); +	ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, cmd_len, res_len);  	if (ret < 0)  		wl1271_error("INTERROGATE command failed"); @@ -1126,6 +1133,8 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,  	u16 template_id_2_4 = wl->scan_templ_id_2_4;  	u16 template_id_5 = wl->scan_templ_id_5; +	wl1271_debug(DEBUG_SCAN, "build probe request band %d", band); +  	skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len,  				     ie_len);  	if (!skb) { @@ -1135,8 +1144,6 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,  	if (ie_len)  		memcpy(skb_put(skb, ie_len), ie, ie_len); -	wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); -  	if (sched_scan &&  	    (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL)) {  		template_id_2_4 = wl->sched_scan_templ_id_2_4; @@ -1172,7 +1179,7 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,  	if (!skb)  		goto out; -	wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len); +	wl1271_debug(DEBUG_SCAN, "set ap probe request template");  	rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]);  	if (wlvif->band == IEEE80211_BAND_2GHZ) @@ -1525,6 +1532,7 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,  	cmd->sp_len = sta->max_sp;  	cmd->wmm = sta->wme ? 1 : 0;  	cmd->session_id = wl->session_ids[hlid]; +	cmd->role_id = wlvif->role_id;  	for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++)  		if (sta->wme && (sta->uapsd_queues & BIT(i))) @@ -1561,7 +1569,8 @@ out:  	return ret;  } -int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid) +int wl12xx_cmd_remove_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif, +			   u8 hlid)  {  	struct wl12xx_cmd_remove_peer *cmd;  	int ret; @@ -1579,6 +1588,7 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid)  	/* We never send a deauth, mac80211 is in charge of this */  	cmd->reason_opcode = 0;  	cmd->send_deauth_flag = 0; +	cmd->role_id = wlvif->role_id;  	ret = wl1271_cmd_send(wl, CMD_REMOVE_PEER, cmd, sizeof(*cmd), 0);  	if (ret < 0) { @@ -1607,33 +1617,43 @@ out:  static int wlcore_get_reg_conf_ch_idx(enum ieee80211_band band, u16 ch)  { -	int idx = -1; - +	/* +	 * map the given band/channel to the respective predefined +	 * bit expected by the fw +	 */  	switch (band) { -	case IEEE80211_BAND_5GHZ: -		if (ch >= 8 && ch <= 16) -			idx = ((ch-8)/4 + 18); -		else if (ch >= 34 && ch <= 64) -			idx = ((ch-34)/2 + 3 + 18); -		else if (ch >= 100 && ch <= 140) -			idx = ((ch-100)/4 + 15 + 18); -		else if (ch >= 149 && ch <= 165) -			idx = ((ch-149)/4 + 26 + 18); -		else -			idx = -1; -		break;  	case IEEE80211_BAND_2GHZ: +		/* channels 1..14 are mapped to 0..13 */  		if (ch >= 1 && ch <= 14) -			idx = ch - 1; -		else -			idx = -1; +			return ch - 1; +		break; +	case IEEE80211_BAND_5GHZ: +		switch (ch) { +		case 8 ... 16: +			/* channels 8,12,16 are mapped to 18,19,20 */ +			return 18 + (ch-8)/4; +		case 34 ... 48: +			/* channels 34,36..48 are mapped to 21..28 */ +			return 21 + (ch-34)/2; +		case 52 ... 64: +			/* channels 52,56..64 are mapped to 29..32 */ +			return 29 + (ch-52)/4; +		case 100 ... 140: +			/* channels 100,104..140 are mapped to 33..43 */ +			return 33 + (ch-100)/4; +		case 149 ... 165: +			/* channels 149,153..165 are mapped to 44..48 */ +			return 44 + (ch-149)/4; +		default: +			break; +		}  		break;  	default: -		wl1271_error("get reg conf ch idx - unknown band: %d", -			     (int)band); +		break;  	} -	return idx; +	wl1271_error("%s: unknown band/channel: %d/%d", __func__, band, ch); +	return -1;  }  void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel, @@ -1646,7 +1666,7 @@ void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel,  	ch_bit_idx = wlcore_get_reg_conf_ch_idx(band, channel); -	if (ch_bit_idx > 0 && ch_bit_idx <= WL1271_MAX_CHANNELS) +	if (ch_bit_idx >= 0 && ch_bit_idx <= WL1271_MAX_CHANNELS)  		set_bit(ch_bit_idx, (long *)wl->reg_ch_conf_pending);  } @@ -1676,7 +1696,7 @@ int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl)  			if (channel->flags & (IEEE80211_CHAN_DISABLED |  					      IEEE80211_CHAN_RADAR | -					      IEEE80211_CHAN_PASSIVE_SCAN)) +					      IEEE80211_CHAN_NO_IR))  				continue;  			ch_bit_idx = wlcore_get_reg_conf_ch_idx(b, ch); diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h index fd34123047c..b084830a61c 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.h +++ b/drivers/net/wireless/ti/wlcore/cmd.h @@ -45,7 +45,8 @@ int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif,  		     enum ieee80211_band band, int channel);  int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif);  int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); -int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); +int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, +			   size_t cmd_len, size_t res_len);  int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);  int wlcore_cmd_configure_failsafe(struct wl1271 *wl, u16 id, void *buf,  				  size_t len, unsigned long valid_rets); @@ -87,7 +88,8 @@ int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id,  int wl12xx_croc(struct wl1271 *wl, u8 role_id);  int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,  			struct ieee80211_sta *sta, u8 hlid); -int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid); +int wl12xx_cmd_remove_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif, +			   u8 hlid);  void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel,  				     enum ieee80211_band band);  int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl); @@ -205,7 +207,7 @@ enum cmd_templ {  #define WL1271_COMMAND_TIMEOUT     2000  #define WL1271_CMD_TEMPL_DFLT_SIZE 252  #define WL1271_CMD_TEMPL_MAX_SIZE  512 -#define WL1271_EVENT_TIMEOUT       1500 +#define WL1271_EVENT_TIMEOUT       5000  struct wl1271_cmd_header {  	__le16 id; @@ -593,6 +595,8 @@ struct wl12xx_cmd_add_peer {  	u8 sp_len;  	u8 wmm;  	u8 session_id; +	u8 role_id; +	u8 padding[3];  } __packed;  struct wl12xx_cmd_remove_peer { @@ -601,7 +605,7 @@ struct wl12xx_cmd_remove_peer {  	u8 hlid;  	u8 reason_opcode;  	u8 send_deauth_flag; -	u8 padding1; +	u8 role_id;  } __packed;  /* diff --git a/drivers/net/wireless/ti/wlcore/conf.h b/drivers/net/wireless/ti/wlcore/conf.h index 2b96ff82134..40995c42bef 100644 --- a/drivers/net/wireless/ti/wlcore/conf.h +++ b/drivers/net/wireless/ti/wlcore/conf.h @@ -1274,6 +1274,9 @@ struct conf_rx_streaming_settings {  	u8 always;  } __packed; +#define CONF_FWLOG_MIN_MEM_BLOCKS	2 +#define CONF_FWLOG_MAX_MEM_BLOCKS	16 +  struct conf_fwlog {  	/* Continuous or on-demand */  	u8 mode; @@ -1281,7 +1284,7 @@ struct conf_fwlog {  	/*  	 * Number of memory blocks dedicated for the FW logger  	 * -	 * Range: 1-3, or 0 to disable the FW logger +	 * Range: 2-16, or 0 to disable the FW logger  	 */  	u8 mem_blocks; diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c index e17630c2a84..89893c71702 100644 --- a/drivers/net/wireless/ti/wlcore/debugfs.c +++ b/drivers/net/wireless/ti/wlcore/debugfs.c @@ -437,6 +437,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,  	int res = 0;  	ssize_t ret;  	char *buf; +	struct wl12xx_vif *wlvif;  #define DRIVER_STATE_BUF_LEN 1024 @@ -450,12 +451,28 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,  	(res += scnprintf(buf + res, DRIVER_STATE_BUF_LEN - res,\  			  #x " = " fmt "\n", wl->x)) +#define DRIVER_STATE_PRINT_GENERIC(x, fmt, args...)   \ +	(res += scnprintf(buf + res, DRIVER_STATE_BUF_LEN - res,\ +			  #x " = " fmt "\n", args)) +  #define DRIVER_STATE_PRINT_LONG(x) DRIVER_STATE_PRINT(x, "%ld")  #define DRIVER_STATE_PRINT_INT(x)  DRIVER_STATE_PRINT(x, "%d")  #define DRIVER_STATE_PRINT_STR(x)  DRIVER_STATE_PRINT(x, "%s")  #define DRIVER_STATE_PRINT_LHEX(x) DRIVER_STATE_PRINT(x, "0x%lx")  #define DRIVER_STATE_PRINT_HEX(x)  DRIVER_STATE_PRINT(x, "0x%x") +	wl12xx_for_each_wlvif_sta(wl, wlvif) { +		if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) +			continue; + +		DRIVER_STATE_PRINT_GENERIC(channel, "%d (%s)", wlvif->channel, +					   wlvif->p2p ? "P2P-CL" : "STA"); +	} + +	wl12xx_for_each_wlvif_ap(wl, wlvif) +		DRIVER_STATE_PRINT_GENERIC(channel, "%d (%s)", wlvif->channel, +					   wlvif->p2p ? "P2P-GO" : "AP"); +  	DRIVER_STATE_PRINT_INT(tx_blocks_available);  	DRIVER_STATE_PRINT_INT(tx_allocated_blocks);  	DRIVER_STATE_PRINT_INT(tx_allocated_pkts[0]); @@ -474,7 +491,6 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,  	DRIVER_STATE_PRINT_INT(tx_blocks_freed);  	DRIVER_STATE_PRINT_INT(rx_counter);  	DRIVER_STATE_PRINT_INT(state); -	DRIVER_STATE_PRINT_INT(channel);  	DRIVER_STATE_PRINT_INT(band);  	DRIVER_STATE_PRINT_INT(power_level);  	DRIVER_STATE_PRINT_INT(sg_enabled); diff --git a/drivers/net/wireless/ti/wlcore/debugfs.h b/drivers/net/wireless/ti/wlcore/debugfs.h index f7381dd6900..0f2cfb0d2a9 100644 --- a/drivers/net/wireless/ti/wlcore/debugfs.h +++ b/drivers/net/wireless/ti/wlcore/debugfs.h @@ -57,7 +57,7 @@ static const struct file_operations name## _ops = {			\  					    wl, &name## _ops);		\  		if (!entry || IS_ERR(entry))				\  			goto err;					\ -	} while (0); +	} while (0)  #define DEBUGFS_ADD_PREFIX(prefix, name, parent)			\ @@ -66,7 +66,7 @@ static const struct file_operations name## _ops = {			\  				    wl, &prefix## _## name## _ops);	\  		if (!entry || IS_ERR(entry))				\  			goto err;					\ -	} while (0); +	} while (0)  #define DEBUGFS_FWSTATS_FILE(sub, name, fmt, struct_type)		\  static ssize_t sub## _ ##name## _read(struct file *file,		\ diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c index 67f61689b49..16d10281798 100644 --- a/drivers/net/wireless/ti/wlcore/event.c +++ b/drivers/net/wireless/ti/wlcore/event.c @@ -67,7 +67,7 @@ static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif)  		u8 hlid;  		struct wl1271_link *lnk;  		for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, -				 WL12XX_MAX_LINKS) { +				 wl->num_links) {  			lnk = &wl->links[hlid];  			if (!lnk->ba_bitmap)  				continue; @@ -158,6 +158,11 @@ EXPORT_SYMBOL_GPL(wlcore_event_channel_switch);  void wlcore_event_dummy_packet(struct wl1271 *wl)  { +	if (wl->plt) { +		wl1271_info("Got DUMMY_PACKET event in PLT mode.  FW bug, ignoring."); +		return; +	} +  	wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");  	wl1271_tx_dummy_packet(wl);  } @@ -172,7 +177,7 @@ static void wlcore_disconnect_sta(struct wl1271 *wl, unsigned long sta_bitmap)  	const u8 *addr;  	int h; -	for_each_set_bit(h, &sta_bitmap, WL12XX_MAX_LINKS) { +	for_each_set_bit(h, &sta_bitmap, wl->num_links) {  		bool found = false;  		/* find the ap vif connected to this sta */  		wl12xx_for_each_wlvif_ap(wl, wlvif) { @@ -266,6 +271,7 @@ int wl1271_event_unmask(struct wl1271 *wl)  {  	int ret; +	wl1271_debug(DEBUG_EVENT, "unmasking event_mask 0x%x", wl->event_mask);  	ret = wl1271_acx_event_mbox_mask(wl, ~(wl->event_mask));  	if (ret < 0)  		return ret; diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h index 7fd260c02a0..1555ff97005 100644 --- a/drivers/net/wireless/ti/wlcore/hw_ops.h +++ b/drivers/net/wireless/ti/wlcore/hw_ops.h @@ -106,6 +106,15 @@ wlcore_hw_init_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif)  	return 0;  } +static inline void +wlcore_hw_convert_fw_status(struct wl1271 *wl, void *raw_fw_status, +			    struct wl_fw_status *fw_status) +{ +	BUG_ON(!wl->ops->convert_fw_status); + +	wl->ops->convert_fw_status(wl, raw_fw_status, fw_status); +} +  static inline u32  wlcore_hw_sta_get_ap_rate_mask(struct wl1271 *wl, struct wl12xx_vif *wlvif)  { @@ -222,6 +231,15 @@ wlcore_hw_set_peer_cap(struct wl1271 *wl,  	return 0;  } +static inline u32 +wlcore_hw_convert_hwaddr(struct wl1271 *wl, u32 hwaddr) +{ +	if (!wl->ops->convert_hwaddr) +		BUG_ON(1); + +	return wl->ops->convert_hwaddr(wl, hwaddr); +} +  static inline bool  wlcore_hw_lnk_high_prio(struct wl1271 *wl, u8 hlid,  			struct wl1271_link *lnk) diff --git a/drivers/net/wireless/ti/wlcore/init.c b/drivers/net/wireless/ti/wlcore/init.c index 5c6f11e157d..199e9412086 100644 --- a/drivers/net/wireless/ti/wlcore/init.c +++ b/drivers/net/wireless/ti/wlcore/init.c @@ -287,8 +287,8 @@ static int wl1271_init_sta_beacon_filter(struct wl1271 *wl,  	if (ret < 0)  		return ret; -	/* enable beacon filtering */ -	ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true); +	/* disable beacon filtering until we get the first beacon */ +	ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);  	if (ret < 0)  		return ret; @@ -462,7 +462,7 @@ int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif)  	 * If the basic rates contain OFDM rates, use OFDM only  	 * rates for unicast TX as well. Else use all supported rates.  	 */ -	if ((wlvif->basic_rate_set & CONF_TX_OFDM_RATES)) +	if (wl->ofdm_only_ap && (wlvif->basic_rate_set & CONF_TX_OFDM_RATES))  		supported_rates = CONF_TX_OFDM_RATES;  	else  		supported_rates = CONF_TX_ENABLED_RATES; @@ -571,6 +571,12 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)  		ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);  		if (ret < 0)  			return ret; + +		/* unmask ap events */ +		wl->event_mask |= wl->ap_event_mask; +		ret = wl1271_event_unmask(wl); +		if (ret < 0) +			return ret;  	/* first STA, no APs */  	} else if (wl->sta_count == 0 && wl->ap_count == 0 && !is_ap) {  		u8 sta_auth = wl->conf.conn.sta_sleep_auth; diff --git a/drivers/net/wireless/ti/wlcore/io.h b/drivers/net/wireless/ti/wlcore/io.h index af7d9f9b3b4..0305729d098 100644 --- a/drivers/net/wireless/ti/wlcore/io.h +++ b/drivers/net/wireless/ti/wlcore/io.h @@ -60,7 +60,9 @@ static inline int __must_check wlcore_raw_write(struct wl1271 *wl, int addr,  {  	int ret; -	if (test_bit(WL1271_FLAG_IO_FAILED, &wl->flags)) +	if (test_bit(WL1271_FLAG_IO_FAILED, &wl->flags) || +	    WARN_ON((test_bit(WL1271_FLAG_IN_ELP, &wl->flags) && +		     addr != HW_ACCESS_ELP_CTRL_REG)))  		return -EIO;  	ret = wl->if_ops->write(wl->dev, addr, buf, len, fixed); @@ -76,7 +78,9 @@ static inline int __must_check wlcore_raw_read(struct wl1271 *wl, int addr,  {  	int ret; -	if (test_bit(WL1271_FLAG_IO_FAILED, &wl->flags)) +	if (test_bit(WL1271_FLAG_IO_FAILED, &wl->flags) || +	    WARN_ON((test_bit(WL1271_FLAG_IN_ELP, &wl->flags) && +		     addr != HW_ACCESS_ELP_CTRL_REG)))  		return -EIO;  	ret = wl->if_ops->read(wl->dev, addr, buf, len, fixed); @@ -165,8 +169,8 @@ static inline int __must_check wlcore_read_hwaddr(struct wl1271 *wl, int hwaddr,  	int physical;  	int addr; -	/* Addresses are stored internally as addresses to 32 bytes blocks */ -	addr = hwaddr << 5; +	/* Convert from FW internal address which is chip arch dependent */ +	addr = wl->ops->convert_hwaddr(wl, hwaddr);  	physical = wlcore_translate_addr(wl, addr); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 38995f90040..3d6028e6275 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -44,6 +44,7 @@  #define WL1271_BOOT_RETRIES 3  static char *fwlog_param; +static int fwlog_mem_blocks = -1;  static int bug_on_recovery = -1;  static int no_recovery     = -1; @@ -90,8 +91,7 @@ static void wl1271_reg_notify(struct wiphy *wiphy,  			continue;  		if (ch->flags & IEEE80211_CHAN_RADAR) -			ch->flags |= IEEE80211_CHAN_NO_IBSS | -				     IEEE80211_CHAN_PASSIVE_SCAN; +			ch->flags |= IEEE80211_CHAN_NO_IR;  	} @@ -291,6 +291,18 @@ static void wlcore_adjust_conf(struct wl1271 *wl)  {  	/* Adjust settings according to optional module parameters */ +	/* Firmware Logger params */ +	if (fwlog_mem_blocks != -1) { +		if (fwlog_mem_blocks >= CONF_FWLOG_MIN_MEM_BLOCKS && +		    fwlog_mem_blocks <= CONF_FWLOG_MAX_MEM_BLOCKS) { +			wl->conf.fwlog.mem_blocks = fwlog_mem_blocks; +		} else { +			wl1271_error( +				"Illegal fwlog_mem_blocks=%d using default %d", +				fwlog_mem_blocks, wl->conf.fwlog.mem_blocks); +		} +	} +  	if (fwlog_param) {  		if (!strcmp(fwlog_param, "continuous")) {  			wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS; @@ -333,24 +345,24 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,  	 * Start high-level PS if the STA is asleep with enough blocks in FW.  	 * Make an exception if this is the only connected link. In this  	 * case FW-memory congestion is less of a problem. -	 * Note that a single connected STA means 3 active links, since we must -	 * account for the global and broadcast AP links. The "fw_ps" check -	 * assures us the third link is a STA connected to the AP. Otherwise -	 * the FW would not set the PSM bit. +	 * Note that a single connected STA means 2*ap_count + 1 active links, +	 * since we must account for the global and broadcast AP links +	 * for each AP. The "fw_ps" check assures us the other link is a STA +	 * connected to the AP. Otherwise the FW would not set the PSM bit.  	 */ -	else if (wl->active_link_count > 3 && fw_ps && +	else if (wl->active_link_count > (wl->ap_count*2 + 1) && fw_ps &&  		 tx_pkts >= WL1271_PS_STA_MAX_PACKETS)  		wl12xx_ps_link_start(wl, wlvif, hlid, true);  }  static void wl12xx_irq_update_links_status(struct wl1271 *wl,  					   struct wl12xx_vif *wlvif, -					   struct wl_fw_status_2 *status) +					   struct wl_fw_status *status)  {  	u32 cur_fw_ps_map;  	u8 hlid; -	cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap); +	cur_fw_ps_map = status->link_ps_bitmap;  	if (wl->ap_fw_ps_map != cur_fw_ps_map) {  		wl1271_debug(DEBUG_PSM,  			     "link ps prev 0x%x cur 0x%x changed 0x%x", @@ -360,77 +372,73 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl,  		wl->ap_fw_ps_map = cur_fw_ps_map;  	} -	for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) +	for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, wl->num_links)  		wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,  					    wl->links[hlid].allocated_pkts);  } -static int wlcore_fw_status(struct wl1271 *wl, -			    struct wl_fw_status_1 *status_1, -			    struct wl_fw_status_2 *status_2) +static int wlcore_fw_status(struct wl1271 *wl, struct wl_fw_status *status)  {  	struct wl12xx_vif *wlvif;  	struct timespec ts;  	u32 old_tx_blk_count = wl->tx_blocks_available;  	int avail, freed_blocks;  	int i; -	size_t status_len;  	int ret;  	struct wl1271_link *lnk; -	status_len = WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) + -		sizeof(*status_2) + wl->fw_status_priv_len; - -	ret = wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, status_1, -				   status_len, false); +	ret = wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, +				   wl->raw_fw_status, +				   wl->fw_status_len, false);  	if (ret < 0)  		return ret; +	wlcore_hw_convert_fw_status(wl, wl->raw_fw_status, wl->fw_status); +  	wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "  		     "drv_rx_counter = %d, tx_results_counter = %d)", -		     status_1->intr, -		     status_1->fw_rx_counter, -		     status_1->drv_rx_counter, -		     status_1->tx_results_counter); +		     status->intr, +		     status->fw_rx_counter, +		     status->drv_rx_counter, +		     status->tx_results_counter);  	for (i = 0; i < NUM_TX_QUEUES; i++) {  		/* prevent wrap-around in freed-packets counter */  		wl->tx_allocated_pkts[i] -= -				(status_2->counters.tx_released_pkts[i] - +				(status->counters.tx_released_pkts[i] -  				wl->tx_pkts_freed[i]) & 0xff; -		wl->tx_pkts_freed[i] = status_2->counters.tx_released_pkts[i]; +		wl->tx_pkts_freed[i] = status->counters.tx_released_pkts[i];  	} -	for_each_set_bit(i, wl->links_map, WL12XX_MAX_LINKS) { +	for_each_set_bit(i, wl->links_map, wl->num_links) {  		u8 diff;  		lnk = &wl->links[i];  		/* prevent wrap-around in freed-packets counter */ -		diff = (status_2->counters.tx_lnk_free_pkts[i] - +		diff = (status->counters.tx_lnk_free_pkts[i] -  		       lnk->prev_freed_pkts) & 0xff;  		if (diff == 0)  			continue;  		lnk->allocated_pkts -= diff; -		lnk->prev_freed_pkts = status_2->counters.tx_lnk_free_pkts[i]; +		lnk->prev_freed_pkts = status->counters.tx_lnk_free_pkts[i];  		/* accumulate the prev_freed_pkts counter */  		lnk->total_freed_pkts += diff;  	}  	/* prevent wrap-around in total blocks counter */ -	if (likely(wl->tx_blocks_freed <= -		   le32_to_cpu(status_2->total_released_blks))) -		freed_blocks = le32_to_cpu(status_2->total_released_blks) - +	if (likely(wl->tx_blocks_freed <= status->total_released_blks)) +		freed_blocks = status->total_released_blks -  			       wl->tx_blocks_freed;  	else  		freed_blocks = 0x100000000LL - wl->tx_blocks_freed + -			       le32_to_cpu(status_2->total_released_blks); +			       status->total_released_blks; -	wl->tx_blocks_freed = le32_to_cpu(status_2->total_released_blks); +	wl->tx_blocks_freed = status->total_released_blks;  	wl->tx_allocated_blocks -= freed_blocks; @@ -446,7 +454,7 @@ static int wlcore_fw_status(struct wl1271 *wl,  			cancel_delayed_work(&wl->tx_watchdog_work);  	} -	avail = le32_to_cpu(status_2->tx_total) - wl->tx_allocated_blocks; +	avail = status->tx_total - wl->tx_allocated_blocks;  	/*  	 * The FW might change the total number of TX memblocks before @@ -465,15 +473,15 @@ static int wlcore_fw_status(struct wl1271 *wl,  	/* for AP update num of allocated TX blocks per link and ps status */  	wl12xx_for_each_wlvif_ap(wl, wlvif) { -		wl12xx_irq_update_links_status(wl, wlvif, status_2); +		wl12xx_irq_update_links_status(wl, wlvif, status);  	}  	/* update the host-chipset time offset */  	getnstimeofday(&ts);  	wl->time_offset = (timespec_to_ns(&ts) >> 10) - -		(s64)le32_to_cpu(status_2->fw_localtime); +		(s64)(status->fw_localtime); -	wl->fw_fast_lnk_map = le32_to_cpu(status_2->link_fast_bitmap); +	wl->fw_fast_lnk_map = status->link_fast_bitmap;  	return 0;  } @@ -535,15 +543,15 @@ static int wlcore_irq_locked(struct wl1271 *wl)  		 * wl1271_ps_elp_wakeup cannot be called concurrently.  		 */  		clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); -		smp_mb__after_clear_bit(); +		smp_mb__after_atomic(); -		ret = wlcore_fw_status(wl, wl->fw_status_1, wl->fw_status_2); +		ret = wlcore_fw_status(wl, wl->fw_status);  		if (ret < 0)  			goto out;  		wlcore_hw_tx_immediate_compl(wl); -		intr = le32_to_cpu(wl->fw_status_1->intr); +		intr = wl->fw_status->intr;  		intr &= WLCORE_ALL_INTR_MASK;  		if (!intr) {  			done = true; @@ -572,7 +580,7 @@ static int wlcore_irq_locked(struct wl1271 *wl)  		if (likely(intr & WL1271_ACX_INTR_DATA)) {  			wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); -			ret = wlcore_rx(wl, wl->fw_status_1); +			ret = wlcore_rx(wl, wl->fw_status);  			if (ret < 0)  				goto out; @@ -774,12 +782,14 @@ out:  void wl12xx_queue_recovery_work(struct wl1271 *wl)  { -	WARN_ON(!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)); -  	/* Avoid a recursive recovery */  	if (wl->state == WLCORE_STATE_ON) { +		WARN_ON(!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, +				  &wl->flags)); +  		wl->state = WLCORE_STATE_RESTARTING;  		set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags); +		wl1271_ps_elp_wakeup(wl);  		wlcore_disable_interrupts_nosync(wl);  		ieee80211_queue_work(wl->hw, &wl->recovery_work);  	} @@ -787,19 +797,10 @@ void wl12xx_queue_recovery_work(struct wl1271 *wl)  size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)  { -	size_t len = 0; - -	/* The FW log is a length-value list, find where the log end */ -	while (len < maxlen) { -		if (memblock[len] == 0) -			break; -		if (len + memblock[len] + 1 > maxlen) -			break; -		len += memblock[len] + 1; -	} +	size_t len;  	/* Make sure we have enough room */ -	len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size)); +	len = min_t(size_t, maxlen, PAGE_SIZE - wl->fwlog_size);  	/* Fill the FW log file, consumed by the sysfs fwlog entry */  	memcpy(wl->fwlog + wl->fwlog_size, memblock, len); @@ -808,10 +809,9 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)  	return len;  } -#define WLCORE_FW_LOG_END 0x2000000 -  static void wl12xx_read_fwlog_panic(struct wl1271 *wl)  { +	struct wlcore_partition_set part, old_part;  	u32 addr;  	u32 offset;  	u32 end_of_log; @@ -824,7 +824,7 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)  	wl1271_info("Reading FW panic log"); -	block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL); +	block = kmalloc(wl->fw_mem_block_size, GFP_KERNEL);  	if (!block)  		return; @@ -840,27 +840,41 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)  		wl12xx_cmd_stop_fwlog(wl);  	/* Read the first memory block address */ -	ret = wlcore_fw_status(wl, wl->fw_status_1, wl->fw_status_2); +	ret = wlcore_fw_status(wl, wl->fw_status);  	if (ret < 0)  		goto out; -	addr = le32_to_cpu(wl->fw_status_2->log_start_addr); +	addr = wl->fw_status->log_start_addr;  	if (!addr)  		goto out;  	if (wl->conf.fwlog.mode == WL12XX_FWLOG_CONTINUOUS) {  		offset = sizeof(addr) + sizeof(struct wl1271_rx_descriptor); -		end_of_log = WLCORE_FW_LOG_END; +		end_of_log = wl->fwlog_end;  	} else {  		offset = sizeof(addr);  		end_of_log = addr;  	} +	old_part = wl->curr_part; +	memset(&part, 0, sizeof(part)); +  	/* Traverse the memory blocks linked list */  	do { -		memset(block, 0, WL12XX_HW_BLOCK_SIZE); -		ret = wlcore_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE, -					 false); +		part.mem.start = wlcore_hw_convert_hwaddr(wl, addr); +		part.mem.size  = PAGE_SIZE; + +		ret = wlcore_set_partition(wl, &part); +		if (ret < 0) { +			wl1271_error("%s: set_partition start=0x%X size=%d", +				__func__, part.mem.start, part.mem.size); +			goto out; +		} + +		memset(block, 0, wl->fw_mem_block_size); +		ret = wlcore_read_hwaddr(wl, addr, block, +					wl->fw_mem_block_size, false); +  		if (ret < 0)  			goto out; @@ -871,8 +885,9 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)  		 * on demand mode and is equal to 0x2000000 in continuous mode.  		 */  		addr = le32_to_cpup((__le32 *)block); +  		if (!wl12xx_copy_fwlog(wl, block + offset, -				       WL12XX_HW_BLOCK_SIZE - offset)) +					wl->fw_mem_block_size - offset))  			break;  	} while (addr && (addr != end_of_log)); @@ -880,6 +895,7 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)  out:  	kfree(block); +	wlcore_set_partition(wl, &old_part);  }  static void wlcore_print_recovery(struct wl1271 *wl) @@ -924,7 +940,8 @@ static void wl1271_recovery_work(struct work_struct *work)  		goto out_unlock;  	if (!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)) { -		wl12xx_read_fwlog_panic(wl); +		if (wl->conf.fwlog.output == WL12XX_FWLOG_OUTPUT_HOST) +			wl12xx_read_fwlog_panic(wl);  		wlcore_print_recovery(wl);  	} @@ -970,23 +987,23 @@ static int wlcore_fw_wakeup(struct wl1271 *wl)  static int wl1271_setup(struct wl1271 *wl)  { -	wl->fw_status_1 = kzalloc(WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) + -				  sizeof(*wl->fw_status_2) + -				  wl->fw_status_priv_len, GFP_KERNEL); -	if (!wl->fw_status_1) -		return -ENOMEM; +	wl->raw_fw_status = kzalloc(wl->fw_status_len, GFP_KERNEL); +	if (!wl->raw_fw_status) +		goto err; -	wl->fw_status_2 = (struct wl_fw_status_2 *) -				(((u8 *) wl->fw_status_1) + -				WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc)); +	wl->fw_status = kzalloc(sizeof(*wl->fw_status), GFP_KERNEL); +	if (!wl->fw_status) +		goto err;  	wl->tx_res_if = kzalloc(sizeof(*wl->tx_res_if), GFP_KERNEL); -	if (!wl->tx_res_if) { -		kfree(wl->fw_status_1); -		return -ENOMEM; -	} +	if (!wl->tx_res_if) +		goto err;  	return 0; +err: +	kfree(wl->fw_status); +	kfree(wl->raw_fw_status); +	return -ENOMEM;  }  static int wl12xx_set_power_on(struct wl1271 *wl) @@ -1062,7 +1079,8 @@ int wl1271_plt_start(struct wl1271 *wl, const enum plt_mode plt_mode)  	static const char* const PLT_MODE[] = {  		"PLT_OFF",  		"PLT_ON", -		"PLT_FEM_DETECT" +		"PLT_FEM_DETECT", +		"PLT_CHIP_AWAKE"  	};  	int ret; @@ -1088,9 +1106,11 @@ int wl1271_plt_start(struct wl1271 *wl, const enum plt_mode plt_mode)  		if (ret < 0)  			goto power_off; -		ret = wl->ops->plt_init(wl); -		if (ret < 0) -			goto power_off; +		if (plt_mode != PLT_CHIP_AWAKE) { +			ret = wl->ops->plt_init(wl); +			if (ret < 0) +				goto power_off; +		}  		wl->state = WLCORE_STATE_ON;  		wl1271_notice("firmware booted in PLT mode %s (%s)", @@ -1396,7 +1416,7 @@ void wl1271_rx_filter_free(struct wl12xx_rx_filter *filter)  int wl1271_rx_filter_alloc_field(struct wl12xx_rx_filter *filter,  				 u16 offset, u8 flags, -				 u8 *pattern, u8 len) +				 const u8 *pattern, u8 len)  {  	struct wl12xx_rx_filter_field *field; @@ -1744,6 +1764,12 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,  	flush_work(&wl->tx_work);  	flush_delayed_work(&wl->elp_work); +	/* +	 * Cancel the watchdog even if above tx_flush failed. We will detect +	 * it on resume anyway. +	 */ +	cancel_delayed_work(&wl->tx_watchdog_work); +  	return 0;  } @@ -1801,6 +1827,13 @@ static int wl1271_op_resume(struct ieee80211_hw *hw)  out:  	wl->wow_enabled = false; + +	/* +	 * Set a flag to re-init the watchdog on the first Tx after resume. +	 * That way we avoid possible conditions where Tx-complete interrupts +	 * fail to arrive and we perform a spurious recovery. +	 */ +	set_bit(WL1271_FLAG_REINIT_TX_WDOG, &wl->flags);  	mutex_unlock(&wl->mutex);  	return 0; @@ -1891,6 +1924,7 @@ static void wlcore_op_stop_locked(struct wl1271 *wl)  	memset(wl->links_map, 0, sizeof(wl->links_map));  	memset(wl->roc_map, 0, sizeof(wl->roc_map));  	memset(wl->session_ids, 0, sizeof(wl->session_ids)); +	memset(wl->rx_filter_enabled, 0, sizeof(wl->rx_filter_enabled));  	wl->active_sta_count = 0;  	wl->active_link_count = 0; @@ -1915,9 +1949,10 @@ static void wlcore_op_stop_locked(struct wl1271 *wl)  	wl1271_debugfs_reset(wl); -	kfree(wl->fw_status_1); -	wl->fw_status_1 = NULL; -	wl->fw_status_2 = NULL; +	kfree(wl->raw_fw_status); +	wl->raw_fw_status = NULL; +	kfree(wl->fw_status); +	wl->fw_status = NULL;  	kfree(wl->tx_res_if);  	wl->tx_res_if = NULL;  	kfree(wl->target_mem_map); @@ -1925,8 +1960,10 @@ static void wlcore_op_stop_locked(struct wl1271 *wl)  	/*  	 * FW channels must be re-calibrated after recovery, -	 * clear the last Reg-Domain channel configuration. +	 * save current Reg-Domain channel configuration and clear it.  	 */ +	memcpy(wl->reg_ch_conf_pending, wl->reg_ch_conf_last, +	       sizeof(wl->reg_ch_conf_pending));  	memset(wl->reg_ch_conf_last, 0, sizeof(wl->reg_ch_conf_last));  } @@ -2008,6 +2045,47 @@ out:  	mutex_unlock(&wl->mutex);  } +static void wlcore_pending_auth_complete_work(struct work_struct *work) +{ +	struct delayed_work *dwork; +	struct wl1271 *wl; +	struct wl12xx_vif *wlvif; +	unsigned long time_spare; +	int ret; + +	dwork = container_of(work, struct delayed_work, work); +	wlvif = container_of(dwork, struct wl12xx_vif, +			     pending_auth_complete_work); +	wl = wlvif->wl; + +	mutex_lock(&wl->mutex); + +	if (unlikely(wl->state != WLCORE_STATE_ON)) +		goto out; + +	/* +	 * Make sure a second really passed since the last auth reply. Maybe +	 * a second auth reply arrived while we were stuck on the mutex. +	 * Check for a little less than the timeout to protect from scheduler +	 * irregularities. +	 */ +	time_spare = jiffies + +			msecs_to_jiffies(WLCORE_PEND_AUTH_ROC_TIMEOUT - 50); +	if (!time_after(time_spare, wlvif->pending_auth_reply_time)) +		goto out; + +	ret = wl1271_ps_elp_wakeup(wl); +	if (ret < 0) +		goto out; + +	/* cancel the ROC if active */ +	wlcore_update_inconn_sta(wl, wlvif, NULL, false); + +	wl1271_ps_elp_sleep(wl); +out: +	mutex_unlock(&wl->mutex); +} +  static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)  {  	u8 policy = find_first_zero_bit(wl->rate_policies_map, @@ -2159,6 +2237,8 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)  			  wlcore_channel_switch_work);  	INIT_DELAYED_WORK(&wlvif->connection_loss_work,  			  wlcore_connection_loss_work); +	INIT_DELAYED_WORK(&wlvif->pending_auth_complete_work, +			  wlcore_pending_auth_complete_work);  	INIT_LIST_HEAD(&wlvif->list);  	setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer, @@ -2376,6 +2456,11 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,  	int ret = 0;  	u8 role_type; +	if (wl->plt) { +		wl1271_error("Adding Interface not allowed while in PLT mode"); +		return -EBUSY; +	} +  	vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |  			     IEEE80211_VIF_SUPPORTS_CQM_RSSI; @@ -2498,10 +2583,8 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,  		ieee80211_scan_completed(wl->hw, true);  	} -	if (wl->sched_vif == wlvif) { -		ieee80211_sched_scan_stopped(wl->hw); +	if (wl->sched_vif == wlvif)  		wl->sched_vif = NULL; -	}  	if (wl->roc_vif == vif) {  		wl->roc_vif = NULL; @@ -2572,6 +2655,12 @@ deinit:  	    !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags))  		goto unlock; +	if (wl->ap_count == 0 && is_ap) { +		/* mask ap events */ +		wl->event_mask &= ~wl->ap_event_mask; +		wl1271_event_unmask(wl); +	} +  	if (wl->ap_count == 0 && is_ap && wl->sta_count) {  		u8 sta_auth = wl->conf.conn.sta_sleep_auth;  		/* Configure for power according to debugfs */ @@ -2590,6 +2679,7 @@ unlock:  	cancel_work_sync(&wlvif->rx_streaming_disable_work);  	cancel_delayed_work_sync(&wlvif->connection_loss_work);  	cancel_delayed_work_sync(&wlvif->channel_switch_work); +	cancel_delayed_work_sync(&wlvif->pending_auth_complete_work);  	mutex_lock(&wl->mutex);  } @@ -2851,6 +2941,11 @@ static int wlcore_unset_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif)  		ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);  		if (ret < 0)  			return ret; + +		/* disable beacon filtering */ +		ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false); +		if (ret < 0) +			return ret;  	}  	if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) { @@ -2875,6 +2970,25 @@ static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)  	wlvif->rate_set = wlvif->basic_rate_set;  } +static void wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif, +				   bool idle) +{ +	bool cur_idle = !test_bit(WLVIF_FLAG_ACTIVE, &wlvif->flags); + +	if (idle == cur_idle) +		return; + +	if (idle) { +		clear_bit(WLVIF_FLAG_ACTIVE, &wlvif->flags); +	} else { +		/* The current firmware only supports sched_scan in idle */ +		if (wl->sched_vif == wlvif) +			wl->ops->sched_scan_stop(wl, wlvif); + +		set_bit(WLVIF_FLAG_ACTIVE, &wlvif->flags); +	} +} +  static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,  			     struct ieee80211_conf *conf, u32 changed)  { @@ -3364,6 +3478,10 @@ static void wl1271_op_set_default_key_idx(struct ieee80211_hw *hw,  	wl1271_debug(DEBUG_MAC80211, "mac80211 set default key idx %d",  		     key_idx); +	/* we don't handle unsetting of default key */ +	if (key_idx == -1) +		return; +  	mutex_lock(&wl->mutex);  	if (unlikely(wl->state != WLCORE_STATE_ON)) { @@ -3550,8 +3668,8 @@ out:  	return ret;  } -static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw, -				      struct ieee80211_vif *vif) +static int wl1271_op_sched_scan_stop(struct ieee80211_hw *hw, +				     struct ieee80211_vif *vif)  {  	struct wl1271 *wl = hw->priv;  	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); @@ -3573,6 +3691,8 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,  	wl1271_ps_elp_sleep(wl);  out:  	mutex_unlock(&wl->mutex); + +	return 0;  }  static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) @@ -3969,6 +4089,13 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,  			}  		} else {  			if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) { +				/* +				 * AP might be in ROC in case we have just +				 * sent auth reply. handle it. +				 */ +				if (test_bit(wlvif->role_id, wl->roc_map)) +					wl12xx_croc(wl, wlvif->role_id); +  				ret = wl12xx_cmd_role_stop_ap(wl, wlvif);  				if (ret < 0)  					goto out; @@ -4120,6 +4247,9 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,  		do_join = true;  	} +	if (changed & BSS_CHANGED_IDLE && !is_ibss) +		wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle); +  	if (changed & BSS_CHANGED_CQM) {  		bool enable = false;  		if (bss_conf->cqm_rssi_thold) @@ -4189,6 +4319,13 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,  		}  	} +	if ((changed & BSS_CHANGED_BEACON_INFO) && bss_conf->dtim_period) { +		/* enable beacon filtering */ +		ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true); +		if (ret < 0) +			goto out; +	} +  	ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);  	if (ret < 0)  		goto out; @@ -4348,6 +4485,16 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,  	if (ret < 0)  		goto out; +	if ((changed & BSS_CHANGED_TXPOWER) && +	    bss_conf->txpower != wlvif->power_level) { + +		ret = wl1271_acx_tx_power(wl, wlvif, bss_conf->txpower); +		if (ret < 0) +			goto out; + +		wlvif->power_level = bss_conf->txpower; +	} +  	if (is_ap)  		wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);  	else @@ -4532,7 +4679,7 @@ static int wl1271_allocate_sta(struct wl1271 *wl,  	int ret; -	if (wl->active_sta_count >= AP_MAX_STATIONS) { +	if (wl->active_sta_count >= wl->max_ap_stations) {  		wl1271_warning("could not allocate HLID - too much stations");  		return -EBUSY;  	} @@ -4635,7 +4782,7 @@ static int wl12xx_sta_remove(struct wl1271 *wl,  	if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))  		return -EINVAL; -	ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid); +	ret = wl12xx_cmd_remove_peer(wl, wlvif, wl_sta->hlid);  	if (ret < 0)  		return ret; @@ -4656,29 +4803,49 @@ static void wlcore_roc_if_possible(struct wl1271 *wl,  	wl12xx_roc(wl, wlvif, wlvif->role_id, wlvif->band, wlvif->channel);  } -static void wlcore_update_inconn_sta(struct wl1271 *wl, -				     struct wl12xx_vif *wlvif, -				     struct wl1271_station *wl_sta, -				     bool in_connection) +/* + * when wl_sta is NULL, we treat this call as if coming from a + * pending auth reply. + * wl->mutex must be taken and the FW must be awake when the call + * takes place. + */ +void wlcore_update_inconn_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, +			      struct wl1271_station *wl_sta, bool in_conn)  { -	if (in_connection) { -		if (WARN_ON(wl_sta->in_connection)) +	if (in_conn) { +		if (WARN_ON(wl_sta && wl_sta->in_connection))  			return; -		wl_sta->in_connection = true; -		if (!wlvif->inconn_count++) + +		if (!wlvif->ap_pending_auth_reply && +		    !wlvif->inconn_count)  			wlcore_roc_if_possible(wl, wlvif); + +		if (wl_sta) { +			wl_sta->in_connection = true; +			wlvif->inconn_count++; +		} else { +			wlvif->ap_pending_auth_reply = true; +		}  	} else { -		if (!wl_sta->in_connection) +		if (wl_sta && !wl_sta->in_connection) +			return; + +		if (WARN_ON(!wl_sta && !wlvif->ap_pending_auth_reply))  			return; -		wl_sta->in_connection = false; -		wlvif->inconn_count--; -		if (WARN_ON(wlvif->inconn_count < 0)) +		if (WARN_ON(wl_sta && !wlvif->inconn_count))  			return; -		if (!wlvif->inconn_count) -			if (test_bit(wlvif->role_id, wl->roc_map)) -				wl12xx_croc(wl, wlvif->role_id); +		if (wl_sta) { +			wl_sta->in_connection = false; +			wlvif->inconn_count--; +		} else { +			wlvif->ap_pending_auth_reply = false; +		} + +		if (!wlvif->inconn_count && !wlvif->ap_pending_auth_reply && +		    test_bit(wlvif->role_id, wl->roc_map)) +			wl12xx_croc(wl, wlvif->role_id);  	}  } @@ -5017,7 +5184,8 @@ out:  	mutex_unlock(&wl->mutex);  } -static void wlcore_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +static void wlcore_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +			    u32 queues, bool drop)  {  	struct wl1271 *wl = hw->priv; @@ -5313,10 +5481,7 @@ static struct ieee80211_rate wl1271_rates_5ghz[] = {  /* 5 GHz band channels for WL1273 */  static struct ieee80211_channel wl1271_channels_5ghz[] = { -	{ .hw_value = 7, .center_freq = 5035, .max_power = WLCORE_MAX_TXPWR },  	{ .hw_value = 8, .center_freq = 5040, .max_power = WLCORE_MAX_TXPWR }, -	{ .hw_value = 9, .center_freq = 5045, .max_power = WLCORE_MAX_TXPWR }, -	{ .hw_value = 11, .center_freq = 5055, .max_power = WLCORE_MAX_TXPWR },  	{ .hw_value = 12, .center_freq = 5060, .max_power = WLCORE_MAX_TXPWR },  	{ .hw_value = 16, .center_freq = 5080, .max_power = WLCORE_MAX_TXPWR },  	{ .hw_value = 34, .center_freq = 5170, .max_power = WLCORE_MAX_TXPWR }, @@ -5543,28 +5708,6 @@ static void wl1271_unregister_hw(struct wl1271 *wl)  } -static const struct ieee80211_iface_limit wlcore_iface_limits[] = { -	{ -		.max = 3, -		.types = BIT(NL80211_IFTYPE_STATION), -	}, -	{ -		.max = 1, -		.types = BIT(NL80211_IFTYPE_AP) | -			 BIT(NL80211_IFTYPE_P2P_GO) | -			 BIT(NL80211_IFTYPE_P2P_CLIENT), -	}, -}; - -static struct ieee80211_iface_combination -wlcore_iface_combinations[] = { -	{ -	  .max_interfaces = 3, -	  .limits = wlcore_iface_limits, -	  .n_limits = ARRAY_SIZE(wlcore_iface_limits), -	}, -}; -  static int wl1271_init_ieee80211(struct wl1271 *wl)  {  	int i; @@ -5584,7 +5727,6 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)  	/* unit us */  	/* FIXME: find a proper value */ -	wl->hw->channel_change_time = 10000;  	wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;  	wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | @@ -5598,7 +5740,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)  		IEEE80211_HW_AP_LINK_PS |  		IEEE80211_HW_AMPDU_AGGREGATION |  		IEEE80211_HW_TX_AMPDU_SETUP_IN_HW | -		IEEE80211_HW_QUEUE_CONTROL; +		IEEE80211_HW_QUEUE_CONTROL | +		IEEE80211_HW_CHANCTX_STA_CSA;  	wl->hw->wiphy->cipher_suites = cipher_suites;  	wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); @@ -5686,10 +5829,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)  		NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;  	/* allowed interface combinations */ -	wlcore_iface_combinations[0].num_different_channels = wl->num_channels; -	wl->hw->wiphy->iface_combinations = wlcore_iface_combinations; -	wl->hw->wiphy->n_iface_combinations = -		ARRAY_SIZE(wlcore_iface_combinations); +	wl->hw->wiphy->iface_combinations = wl->iface_combinations; +	wl->hw->wiphy->n_iface_combinations = wl->n_iface_combinations;  	SET_IEEE80211_DEV(wl->hw, wl->dev); @@ -5709,8 +5850,6 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,  	int i, j, ret;  	unsigned int order; -	BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS); -  	hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);  	if (!hw) {  		wl1271_error("could not alloc ieee80211_hw"); @@ -5732,8 +5871,12 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,  	wl->hw = hw; +	/* +	 * wl->num_links is not configured yet, so just use WLCORE_MAX_LINKS. +	 * we don't allocate any additional resource here, so that's fine. +	 */  	for (i = 0; i < NUM_TX_QUEUES; i++) -		for (j = 0; j < WL12XX_MAX_LINKS; j++) +		for (j = 0; j < WLCORE_MAX_LINKS; j++)  			skb_queue_head_init(&wl->links[j].tx_queue[i]);  	skb_queue_head_init(&wl->deferred_rx_queue); @@ -5876,7 +6019,8 @@ int wlcore_free_hw(struct wl1271 *wl)  	kfree(wl->nvs);  	wl->nvs = NULL; -	kfree(wl->fw_status_1); +	kfree(wl->raw_fw_status); +	kfree(wl->fw_status);  	kfree(wl->tx_res_if);  	destroy_workqueue(wl->freezable_wq); @@ -5896,14 +6040,20 @@ static const struct wiphy_wowlan_support wlcore_wowlan_support = {  };  #endif +static irqreturn_t wlcore_hardirq(int irq, void *cookie) +{ +	return IRQ_WAKE_THREAD; +} +  static void wlcore_nvs_cb(const struct firmware *fw, void *context)  {  	struct wl1271 *wl = context;  	struct platform_device *pdev = wl->pdev; -	struct wlcore_platdev_data *pdev_data = pdev->dev.platform_data; +	struct wlcore_platdev_data *pdev_data = dev_get_platdata(&pdev->dev);  	struct wl12xx_platform_data *pdata = pdev_data->pdata;  	unsigned long irqflags;  	int ret; +	irq_handler_t hardirq_fn = NULL;  	if (fw) {  		wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL); @@ -5932,12 +6082,14 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)  	wl->platform_quirks = pdata->platform_quirks;  	wl->if_ops = pdev_data->if_ops; -	if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) +	if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) {  		irqflags = IRQF_TRIGGER_RISING; -	else +		hardirq_fn = wlcore_hardirq; +	} else {  		irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; +	} -	ret = request_threaded_irq(wl->irq, NULL, wlcore_irq, +	ret = request_threaded_irq(wl->irq, hardirq_fn, wlcore_irq,  				   irqflags, pdev->name, wl);  	if (ret < 0) {  		wl1271_error("request_irq() failed: %d", ret); @@ -6046,6 +6198,9 @@ module_param_named(fwlog, fwlog_param, charp, 0);  MODULE_PARM_DESC(fwlog,  		 "FW logger options: continuous, ondemand, dbgpins or disable"); +module_param(fwlog_mem_blocks, int, S_IRUSR | S_IWUSR); +MODULE_PARM_DESC(fwlog_mem_blocks, "fwlog mem_blocks"); +  module_param(bug_on_recovery, int, S_IRUSR | S_IWUSR);  MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery"); diff --git a/drivers/net/wireless/ti/wlcore/ps.c b/drivers/net/wireless/ti/wlcore/ps.c index 98066d40c2a..b52516eed7b 100644 --- a/drivers/net/wireless/ti/wlcore/ps.c +++ b/drivers/net/wireless/ti/wlcore/ps.c @@ -83,6 +83,10 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)  	struct wl12xx_vif *wlvif;  	u32 timeout; +	/* We do not enter elp sleep in PLT mode */ +	if (wl->plt) +		return; +  	if (wl->sleep_auth != WL1271_PSM_ELP)  		return; @@ -276,7 +280,11 @@ void wl12xx_ps_link_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,  	struct ieee80211_sta *sta;  	struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); -	if (test_bit(hlid, &wl->ap_ps_map)) +	if (WARN_ON_ONCE(wlvif->bss_type != BSS_TYPE_AP_BSS)) +		return; + +	if (!test_bit(hlid, wlvif->ap.sta_hlid_map) || +	    test_bit(hlid, &wl->ap_ps_map))  		return;  	wl1271_debug(DEBUG_PSM, "start mac80211 PSM on hlid %d pkts %d " diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c index 6791a1a6afb..e125974285c 100644 --- a/drivers/net/wireless/ti/wlcore/rx.c +++ b/drivers/net/wireless/ti/wlcore/rx.c @@ -203,9 +203,9 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,  	return is_data;  } -int wlcore_rx(struct wl1271 *wl, struct wl_fw_status_1 *status) +int wlcore_rx(struct wl1271 *wl, struct wl_fw_status *status)  { -	unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; +	unsigned long active_hlids[BITS_TO_LONGS(WLCORE_MAX_LINKS)] = {0};  	u32 buf_size;  	u32 fw_rx_counter = status->fw_rx_counter % wl->num_rx_desc;  	u32 drv_rx_counter = wl->rx_counter % wl->num_rx_desc; @@ -263,12 +263,12 @@ int wlcore_rx(struct wl1271 *wl, struct wl_fw_status_1 *status)  						  wl->aggr_buf + pkt_offset,  						  pkt_len, rx_align,  						  &hlid) == 1) { -				if (hlid < WL12XX_MAX_LINKS) +				if (hlid < wl->num_links)  					__set_bit(hlid, active_hlids);  				else  					WARN(1, -					     "hlid exceeded WL12XX_MAX_LINKS " -					     "(%d)\n", hlid); +					     "hlid (%d) exceeded MAX_LINKS\n", +					     hlid);  			}  			wl->rx_counter++; @@ -302,7 +302,7 @@ int wl1271_rx_filter_enable(struct wl1271 *wl,  {  	int ret; -	if (wl->rx_filter_enabled[index] == enable) { +	if (!!test_bit(index, wl->rx_filter_enabled) == enable) {  		wl1271_warning("Request to enable an already "  			     "enabled rx filter %d", index);  		return 0; @@ -316,7 +316,10 @@ int wl1271_rx_filter_enable(struct wl1271 *wl,  		return ret;  	} -	wl->rx_filter_enabled[index] = enable; +	if (enable) +		__set_bit(index, wl->rx_filter_enabled); +	else +		__clear_bit(index, wl->rx_filter_enabled);  	return 0;  } @@ -326,7 +329,7 @@ int wl1271_rx_filter_clear_all(struct wl1271 *wl)  	int i, ret = 0;  	for (i = 0; i < WL1271_MAX_RX_FILTERS; i++) { -		if (!wl->rx_filter_enabled[i]) +		if (!test_bit(i, wl->rx_filter_enabled))  			continue;  		ret = wl1271_rx_filter_enable(wl, i, 0, NULL);  		if (ret) diff --git a/drivers/net/wireless/ti/wlcore/rx.h b/drivers/net/wireless/ti/wlcore/rx.h index 3363f60fb7d..a3b1618db27 100644 --- a/drivers/net/wireless/ti/wlcore/rx.h +++ b/drivers/net/wireless/ti/wlcore/rx.h @@ -142,7 +142,7 @@ struct wl1271_rx_descriptor {  	u8  reserved;  } __packed; -int wlcore_rx(struct wl1271 *wl, struct wl_fw_status_1 *status); +int wlcore_rx(struct wl1271 *wl, struct wl_fw_status *status);  u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);  int wl1271_rx_filter_enable(struct wl1271 *wl,  			    int index, bool enable, diff --git a/drivers/net/wireless/ti/wlcore/scan.c b/drivers/net/wireless/ti/wlcore/scan.c index f407101e525..1e3d51cd673 100644 --- a/drivers/net/wireless/ti/wlcore/scan.c +++ b/drivers/net/wireless/ti/wlcore/scan.c @@ -92,9 +92,31 @@ out:  static void wlcore_started_vifs_iter(void *data, u8 *mac,  				     struct ieee80211_vif *vif)  { +	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); +	bool active = false;  	int *count = (int *)data; -	if (!vif->bss_conf.idle) +	/* +	 * count active interfaces according to interface type. +	 * checking only bss_conf.idle is bad for some cases, e.g. +	 * we don't want to count sta in p2p_find as active interface. +	 */ +	switch (wlvif->bss_type) { +	case BSS_TYPE_STA_BSS: +		if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) +			active = true; +		break; + +	case BSS_TYPE_AP_BSS: +		if (wlvif->wl->active_sta_count > 0) +			active = true; +		break; + +	default: +		break; +	} + +	if (active)  		(*count)++;  } @@ -166,26 +188,14 @@ wlcore_scan_get_channels(struct wl1271 *wl,  		flags = req_channels[i]->flags;  		if (force_passive) -			flags |= IEEE80211_CHAN_PASSIVE_SCAN; +			flags |= IEEE80211_CHAN_NO_IR;  		if ((req_channels[i]->band == band) &&  		    !(flags & IEEE80211_CHAN_DISABLED) &&  		    (!!(flags & IEEE80211_CHAN_RADAR) == radar) &&  		    /* if radar is set, we ignore the passive flag */  		    (radar || -		     !!(flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive)) { -			wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", -				     req_channels[i]->band, -				     req_channels[i]->center_freq); -			wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X", -				     req_channels[i]->hw_value, -				     req_channels[i]->flags); -			wl1271_debug(DEBUG_SCAN, "max_power %d", -				     req_channels[i]->max_power); -			wl1271_debug(DEBUG_SCAN, "min_dwell_time %d max dwell time %d", -				     min_dwell_time_active, -				     max_dwell_time_active); - +		     !!(flags & IEEE80211_CHAN_NO_IR) == passive)) {  			if (flags & IEEE80211_CHAN_RADAR) {  				channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS; @@ -208,7 +218,7 @@ wlcore_scan_get_channels(struct wl1271 *wl,  			    (band == IEEE80211_BAND_2GHZ) &&  			    (channels[j].channel >= 12) &&  			    (channels[j].channel <= 14) && -			    (flags & IEEE80211_CHAN_PASSIVE_SCAN) && +			    (flags & IEEE80211_CHAN_NO_IR) &&  			    !force_passive) {  				/* pactive channels treated as DFS */  				channels[j].flags = SCAN_CHANNEL_FLAGS_DFS; @@ -222,6 +232,17 @@ wlcore_scan_get_channels(struct wl1271 *wl,  					     *n_pactive_ch);  			} +			wl1271_debug(DEBUG_SCAN, "freq %d, ch. %d, flags 0x%x, power %d, min/max_dwell %d/%d%s%s", +				     req_channels[i]->center_freq, +				     req_channels[i]->hw_value, +				     req_channels[i]->flags, +				     req_channels[i]->max_power, +				     min_dwell_time_active, +				     max_dwell_time_active, +				     flags & IEEE80211_CHAN_RADAR ? +					", DFS" : "", +				     flags & IEEE80211_CHAN_NO_IR ? +					", NO-IR" : "");  			j++;  		}  	} @@ -364,7 +385,7 @@ wlcore_scan_sched_scan_ssid_list(struct wl1271 *wl,  	struct cfg80211_ssid *ssids = req->ssids;  	int ret = 0, type, i, j, n_match_ssids = 0; -	wl1271_debug(DEBUG_CMD, "cmd sched scan ssid list"); +	wl1271_debug((DEBUG_CMD | DEBUG_SCAN), "cmd sched scan ssid list");  	/* count the match sets that contain SSIDs */  	for (i = 0; i < req->n_match_sets; i++) @@ -442,8 +463,6 @@ wlcore_scan_sched_scan_ssid_list(struct wl1271 *wl,  		}  	} -	wl1271_dump(DEBUG_SCAN, "SSID_LIST: ", cmd, sizeof(*cmd)); -  	ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_SSID_CFG, cmd,  			      sizeof(*cmd), 0);  	if (ret < 0) { diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index 29ef2492951..d3dd7bfdf3f 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -217,7 +217,7 @@ static struct wl1271_if_operations sdio_ops = {  static int wl1271_probe(struct sdio_func *func,  				  const struct sdio_device_id *id)  { -	struct wlcore_platdev_data *pdev_data; +	struct wlcore_platdev_data pdev_data;  	struct wl12xx_sdio_glue *glue;  	struct resource res[1];  	mmc_pm_flag_t mmcflags; @@ -228,16 +228,13 @@ static int wl1271_probe(struct sdio_func *func,  	if (func->num != 0x02)  		return -ENODEV; -	pdev_data = kzalloc(sizeof(*pdev_data), GFP_KERNEL); -	if (!pdev_data) -		goto out; - -	pdev_data->if_ops = &sdio_ops; +	memset(&pdev_data, 0x00, sizeof(pdev_data)); +	pdev_data.if_ops = &sdio_ops;  	glue = kzalloc(sizeof(*glue), GFP_KERNEL);  	if (!glue) {  		dev_err(&func->dev, "can't allocate glue\n"); -		goto out_free_pdev_data; +		goto out;  	}  	glue->dev = &func->dev; @@ -248,9 +245,9 @@ static int wl1271_probe(struct sdio_func *func,  	/* Use block mode for transferring over one block size of data */  	func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; -	pdev_data->pdata = wl12xx_get_platform_data(); -	if (IS_ERR(pdev_data->pdata)) { -		ret = PTR_ERR(pdev_data->pdata); +	pdev_data.pdata = wl12xx_get_platform_data(); +	if (IS_ERR(pdev_data.pdata)) { +		ret = PTR_ERR(pdev_data.pdata);  		dev_err(glue->dev, "missing wlan platform data: %d\n", ret);  		goto out_free_glue;  	} @@ -260,7 +257,7 @@ static int wl1271_probe(struct sdio_func *func,  	dev_dbg(glue->dev, "sdio PM caps = 0x%x\n", mmcflags);  	if (mmcflags & MMC_PM_KEEP_POWER) -		pdev_data->pdata->pwr_in_suspend = true; +		pdev_data.pdata->pwr_in_suspend = true;  	sdio_set_drvdata(func, glue); @@ -289,7 +286,7 @@ static int wl1271_probe(struct sdio_func *func,  	memset(res, 0x00, sizeof(res)); -	res[0].start = pdev_data->pdata->irq; +	res[0].start = pdev_data.pdata->irq;  	res[0].flags = IORESOURCE_IRQ;  	res[0].name = "irq"; @@ -299,8 +296,8 @@ static int wl1271_probe(struct sdio_func *func,  		goto out_dev_put;  	} -	ret = platform_device_add_data(glue->core, pdev_data, -				       sizeof(*pdev_data)); +	ret = platform_device_add_data(glue->core, &pdev_data, +				       sizeof(pdev_data));  	if (ret) {  		dev_err(glue->dev, "can't add platform data\n");  		goto out_dev_put; @@ -319,9 +316,6 @@ out_dev_put:  out_free_glue:  	kfree(glue); -out_free_pdev_data: -	kfree(pdev_data); -  out:  	return ret;  } diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index 1b0cd98e35f..392c882b28f 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -24,11 +24,12 @@  #include <linux/interrupt.h>  #include <linux/irq.h>  #include <linux/module.h> +#include <linux/slab.h> +#include <linux/swab.h>  #include <linux/crc7.h>  #include <linux/spi/spi.h>  #include <linux/wl12xx.h>  #include <linux/platform_device.h> -#include <linux/slab.h>  #include "wlcore.h"  #include "wl12xx_80211.h" @@ -110,18 +111,16 @@ static void wl12xx_spi_reset(struct device *child)  static void wl12xx_spi_init(struct device *child)  {  	struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); -	u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd;  	struct spi_transfer t;  	struct spi_message m; +	u8 *cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); -	cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);  	if (!cmd) {  		dev_err(child->parent,  			"could not allocate cmd for spi init\n");  		return;  	} -	memset(crc, 0, sizeof(crc));  	memset(&t, 0, sizeof(t));  	spi_message_init(&m); @@ -129,30 +128,29 @@ static void wl12xx_spi_init(struct device *child)  	 * Set WSPI_INIT_COMMAND  	 * the data is being send from the MSB to LSB  	 */ -	cmd[2] = 0xff; -	cmd[3] = 0xff; -	cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX; -	cmd[0] = 0; -	cmd[7] = 0; -	cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3; -	cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN; +	cmd[0] = 0xff; +	cmd[1] = 0xff; +	cmd[2] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX; +	cmd[3] = 0; +	cmd[4] = 0; +	cmd[5] = HW_ACCESS_WSPI_INIT_CMD_MASK << 3; +	cmd[5] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN; + +	cmd[6] = WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS +		| WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS;  	if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0) -		cmd[5] |=  WSPI_INIT_CMD_DIS_FIXEDBUSY; +		cmd[6] |= WSPI_INIT_CMD_DIS_FIXEDBUSY;  	else -		cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY; - -	cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS -		| WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS; - -	crc[0] = cmd[1]; -	crc[1] = cmd[0]; -	crc[2] = cmd[7]; -	crc[3] = cmd[6]; -	crc[4] = cmd[5]; +		cmd[6] |= WSPI_INIT_CMD_EN_FIXEDBUSY; -	cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; -	cmd[4] |= WSPI_INIT_CMD_END; +	cmd[7] = crc7_be(0, cmd+2, WSPI_INIT_CMD_CRC_LEN) | WSPI_INIT_CMD_END; +	/* +	 * The above is the logical order; it must actually be stored +	 * in the buffer byte-swapped. +	 */ +	__swab32s((u32 *)cmd); +	__swab32s((u32 *)cmd+1);  	t.tx_buf = cmd;  	t.len = WSPI_INIT_CMD_LEN; @@ -211,7 +209,7 @@ static int __must_check wl12xx_spi_raw_read(struct device *child, int addr,  	u32 chunk_len;  	while (len > 0) { -		chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len); +		chunk_len = min_t(size_t, WSPI_MAX_CHUNK_SIZE, len);  		cmd = &wl->buffer_cmd;  		busy_buf = wl->buffer_busyword; @@ -285,7 +283,7 @@ static int __must_check wl12xx_spi_raw_write(struct device *child, int addr,  	cmd = &commands[0];  	i = 0;  	while (len > 0) { -		chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len); +		chunk_len = min_t(size_t, WSPI_MAX_CHUNK_SIZE, len);  		*cmd = 0;  		*cmd |= WSPI_CMD_WRITE; @@ -327,27 +325,25 @@ static struct wl1271_if_operations spi_ops = {  static int wl1271_probe(struct spi_device *spi)  {  	struct wl12xx_spi_glue *glue; -	struct wlcore_platdev_data *pdev_data; +	struct wlcore_platdev_data pdev_data;  	struct resource res[1];  	int ret = -ENOMEM; -	pdev_data = kzalloc(sizeof(*pdev_data), GFP_KERNEL); -	if (!pdev_data) -		goto out; +	memset(&pdev_data, 0x00, sizeof(pdev_data)); -	pdev_data->pdata = spi->dev.platform_data; -	if (!pdev_data->pdata) { +	pdev_data.pdata = dev_get_platdata(&spi->dev); +	if (!pdev_data.pdata) {  		dev_err(&spi->dev, "no platform data\n");  		ret = -ENODEV; -		goto out_free_pdev_data; +		goto out;  	} -	pdev_data->if_ops = &spi_ops; +	pdev_data.if_ops = &spi_ops;  	glue = kzalloc(sizeof(*glue), GFP_KERNEL);  	if (!glue) {  		dev_err(&spi->dev, "can't allocate glue\n"); -		goto out_free_pdev_data; +		goto out;  	}  	glue->dev = &spi->dev; @@ -385,8 +381,8 @@ static int wl1271_probe(struct spi_device *spi)  		goto out_dev_put;  	} -	ret = platform_device_add_data(glue->core, pdev_data, -				       sizeof(*pdev_data)); +	ret = platform_device_add_data(glue->core, &pdev_data, +				       sizeof(pdev_data));  	if (ret) {  		dev_err(glue->dev, "can't add platform data\n");  		goto out_dev_put; @@ -406,9 +402,6 @@ out_dev_put:  out_free_glue:  	kfree(glue); -out_free_pdev_data: -	kfree(pdev_data); -  out:  	return ret;  } diff --git a/drivers/net/wireless/ti/wlcore/sysfs.c b/drivers/net/wireless/ti/wlcore/sysfs.c index 8e583497940..24dd288d680 100644 --- a/drivers/net/wireless/ti/wlcore/sysfs.c +++ b/drivers/net/wireless/ti/wlcore/sysfs.c @@ -152,7 +152,7 @@ static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,  	}  	/* Seeking is not supported - old logs are not kept. Disregard pos. */ -	len = min(count, (size_t)wl->fwlog_size); +	len = min_t(size_t, count, wl->fwlog_size);  	wl->fwlog_size -= len;  	memcpy(buffer, wl->fwlog, len); diff --git a/drivers/net/wireless/ti/wlcore/testmode.c b/drivers/net/wireless/ti/wlcore/testmode.c index 527590f2adf..ddad58f614d 100644 --- a/drivers/net/wireless/ti/wlcore/testmode.c +++ b/drivers/net/wireless/ti/wlcore/testmode.c @@ -179,7 +179,8 @@ static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[])  		goto out_sleep;  	} -	ret = wl1271_cmd_interrogate(wl, ie_id, cmd, sizeof(*cmd)); +	ret = wl1271_cmd_interrogate(wl, ie_id, cmd, +				     sizeof(struct acx_header), sizeof(*cmd));  	if (ret < 0) {  		wl1271_warning("testmode cmd interrogate failed: %d", ret);  		goto out_free; @@ -297,7 +298,8 @@ static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[])  		ret = wl1271_plt_stop(wl);  		break;  	case PLT_ON: -		ret = wl1271_plt_start(wl, PLT_ON); +	case PLT_CHIP_AWAKE: +		ret = wl1271_plt_start(wl, val);  		break;  	case PLT_FEM_DETECT:  		ret = wl1271_tm_detect_fem(wl, tb); @@ -361,6 +363,7 @@ int wl1271_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  {  	struct wl1271 *wl = hw->priv;  	struct nlattr *tb[WL1271_TM_ATTR_MAX + 1]; +	u32 nla_cmd;  	int err;  	err = nla_parse(tb, WL1271_TM_ATTR_MAX, data, len, wl1271_tm_policy); @@ -370,7 +373,14 @@ int wl1271_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  	if (!tb[WL1271_TM_ATTR_CMD_ID])  		return -EINVAL; -	switch (nla_get_u32(tb[WL1271_TM_ATTR_CMD_ID])) { +	nla_cmd = nla_get_u32(tb[WL1271_TM_ATTR_CMD_ID]); + +	/* Only SET_PLT_MODE is allowed in case of mode PLT_CHIP_AWAKE */ +	if (wl->plt_mode == PLT_CHIP_AWAKE && +	    nla_cmd != WL1271_TM_CMD_SET_PLT_MODE) +		return -EOPNOTSUPP; + +	switch (nla_cmd) {  	case WL1271_TM_CMD_TEST:  		return wl1271_tm_cmd_test(wl, tb);  	case WL1271_TM_CMD_INTERROGATE: diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c index 7e93fe63a2c..40b43115f83 100644 --- a/drivers/net/wireless/ti/wlcore/tx.c +++ b/drivers/net/wireless/ti/wlcore/tx.c @@ -86,19 +86,34 @@ void wl1271_free_tx_id(struct wl1271 *wl, int id)  EXPORT_SYMBOL(wl1271_free_tx_id);  static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, +						 struct wl12xx_vif *wlvif,  						 struct sk_buff *skb)  {  	struct ieee80211_hdr *hdr; +	hdr = (struct ieee80211_hdr *)(skb->data + +				       sizeof(struct wl1271_tx_hw_descr)); +	if (!ieee80211_is_auth(hdr->frame_control)) +		return; +  	/*  	 * add the station to the known list before transmitting the  	 * authentication response. this way it won't get de-authed by FW  	 * when transmitting too soon.  	 */ -	hdr = (struct ieee80211_hdr *)(skb->data + -				       sizeof(struct wl1271_tx_hw_descr)); -	if (ieee80211_is_auth(hdr->frame_control)) -		wl1271_acx_set_inconnection_sta(wl, hdr->addr1); +	wl1271_acx_set_inconnection_sta(wl, wlvif, hdr->addr1); + +	/* +	 * ROC for 1 second on the AP channel for completing the connection. +	 * Note the ROC will be continued by the update_sta_state callbacks +	 * once the station reaches the associated state. +	 */ +	wlcore_update_inconn_sta(wl, wlvif, NULL, true); +	wlvif->pending_auth_reply_time = jiffies; +	cancel_delayed_work(&wlvif->pending_auth_complete_work); +	ieee80211_queue_delayed_work(wl->hw, +				&wlvif->pending_auth_complete_work, +				msecs_to_jiffies(WLCORE_PEND_AUTH_ROC_TIMEOUT));  }  static void wl1271_tx_regulate_link(struct wl1271 *wl, @@ -119,12 +134,12 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl,  	 * into high-level PS and clean out its TX queues.  	 * Make an exception if this is the only connected link. In this  	 * case FW-memory congestion is less of a problem. -	 * Note that a single connected STA means 3 active links, since we must -	 * account for the global and broadcast AP links. The "fw_ps" check -	 * assures us the third link is a STA connected to the AP. Otherwise -	 * the FW would not set the PSM bit. +	 * Note that a single connected STA means 2*ap_count + 1 active links, +	 * since we must account for the global and broadcast AP links +	 * for each AP. The "fw_ps" check assures us the other link is a STA +	 * connected to the AP. Otherwise the FW would not set the PSM bit.  	 */ -	if (wl->active_link_count > 3 && fw_ps && +	if (wl->active_link_count > (wl->ap_count*2 + 1) && fw_ps &&  	    tx_pkts >= WL1271_PS_STA_MAX_PACKETS)  		wl12xx_ps_link_start(wl, wlvif, hlid, true);  } @@ -219,8 +234,13 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,  		wl->tx_blocks_available -= total_blocks;  		wl->tx_allocated_blocks += total_blocks; -		/* If the FW was empty before, arm the Tx watchdog */ -		if (wl->tx_allocated_blocks == total_blocks) +		/* +		 * If the FW was empty before, arm the Tx watchdog. Also do +		 * this on the first Tx after resume, as we always cancel the +		 * watchdog on suspend. +		 */ +		if (wl->tx_allocated_blocks == total_blocks || +		    test_and_clear_bit(WL1271_FLAG_REINIT_TX_WDOG, &wl->flags))  			wl12xx_rearm_tx_watchdog_locked(wl);  		ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); @@ -342,6 +362,10 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,  	    ieee80211_has_protected(frame_control))  		tx_attr |= TX_HW_ATTR_HOST_ENCRYPT; +	/* send EAPOL frames as voice */ +	if (control->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO) +		tx_attr |= TX_HW_ATTR_EAPOL_FRAME; +  	desc->tx_attr = cpu_to_le16(tx_attr);  	wlcore_hw_set_tx_desc_csum(wl, desc, skb); @@ -386,7 +410,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,  		is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) ||  			 (cipher == WLAN_CIPHER_SUITE_WEP104); -		if (WARN_ON(is_wep && wlvif->default_key != idx)) { +		if (WARN_ON(is_wep && wlvif && wlvif->default_key != idx)) {  			ret = wl1271_set_default_wep_key(wl, wlvif, idx);  			if (ret < 0)  				return ret; @@ -404,7 +428,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,  	wl1271_tx_fill_hdr(wl, wlvif, skb, extra, info, hlid);  	if (!is_dummy && wlvif && wlvif->bss_type == BSS_TYPE_AP_BSS) { -		wl1271_tx_ap_update_inconnection_sta(wl, skb); +		wl1271_tx_ap_update_inconnection_sta(wl, wlvif, skb);  		wl1271_tx_regulate_link(wl, wlvif, hlid);  	} @@ -545,11 +569,11 @@ static struct sk_buff *wlcore_vif_dequeue_high_prio(struct wl1271 *wl,  	int i, h, start_hlid;  	/* start from the link after the last one */ -	start_hlid = (wlvif->last_tx_hlid + 1) % WL12XX_MAX_LINKS; +	start_hlid = (wlvif->last_tx_hlid + 1) % wl->num_links;  	/* dequeue according to AC, round robin on each link */ -	for (i = 0; i < WL12XX_MAX_LINKS; i++) { -		h = (start_hlid + i) % WL12XX_MAX_LINKS; +	for (i = 0; i < wl->num_links; i++) { +		h = (start_hlid + i) % wl->num_links;  		/* only consider connected stations */  		if (!test_bit(h, wlvif->links_map)) @@ -673,8 +697,8 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct wl12xx_vif *wlvif,  		skb_queue_head(&wl->links[hlid].tx_queue[q], skb);  		/* make sure we dequeue the same packet next time */ -		wlvif->last_tx_hlid = (hlid + WL12XX_MAX_LINKS - 1) % -				      WL12XX_MAX_LINKS; +		wlvif->last_tx_hlid = (hlid + wl->num_links - 1) % +				      wl->num_links;  	}  	spin_lock_irqsave(&wl->wl_lock, flags); @@ -707,7 +731,7 @@ void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids)  	timeout = wl->conf.rx_streaming.duration;  	wl12xx_for_each_wlvif_sta(wl, wlvif) {  		bool found = false; -		for_each_set_bit(hlid, active_hlids, WL12XX_MAX_LINKS) { +		for_each_set_bit(hlid, active_hlids, wl->num_links) {  			if (test_bit(hlid, wlvif->links_map)) {  				found  = true;  				break; @@ -744,7 +768,7 @@ int wlcore_tx_work_locked(struct wl1271 *wl)  	struct wl1271_tx_hw_descr *desc;  	u32 buf_offset = 0, last_len = 0;  	bool sent_packets = false; -	unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; +	unsigned long active_hlids[BITS_TO_LONGS(WLCORE_MAX_LINKS)] = {0};  	int ret = 0;  	int bus_ret = 0;  	u8 hlid; @@ -1046,7 +1070,7 @@ void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif)  	int i;  	/* TX failure */ -	for_each_set_bit(i, wlvif->links_map, WL12XX_MAX_LINKS) { +	for_each_set_bit(i, wlvif->links_map, wl->num_links) {  		if (wlvif->bss_type == BSS_TYPE_AP_BSS &&  		    i != wlvif->ap.bcast_hlid && i != wlvif->ap.global_hlid) {  			/* this calls wl12xx_free_link */ @@ -1070,7 +1094,7 @@ void wl12xx_tx_reset(struct wl1271 *wl)  	/* only reset the queues if something bad happened */  	if (wl1271_tx_total_queue_count(wl) != 0) { -		for (i = 0; i < WL12XX_MAX_LINKS; i++) +		for (i = 0; i < wl->num_links; i++)  			wl1271_tx_reset_link_queues(wl, i);  		for (i = 0; i < NUM_TX_QUEUES; i++) @@ -1163,7 +1187,7 @@ void wl1271_tx_flush(struct wl1271 *wl)  		       WL1271_TX_FLUSH_TIMEOUT / 1000);  	/* forcibly flush all Tx buffers on our queues */ -	for (i = 0; i < WL12XX_MAX_LINKS; i++) +	for (i = 0; i < wl->num_links; i++)  		wl1271_tx_reset_link_queues(wl, i);  out_wake: diff --git a/drivers/net/wireless/ti/wlcore/tx.h b/drivers/net/wireless/ti/wlcore/tx.h index 55aa4acf910..79cb3ff8b71 100644 --- a/drivers/net/wireless/ti/wlcore/tx.h +++ b/drivers/net/wireless/ti/wlcore/tx.h @@ -37,6 +37,7 @@  #define TX_HW_ATTR_TX_CMPLT_REQ          BIT(12)  #define TX_HW_ATTR_TX_DUMMY_REQ          BIT(13)  #define TX_HW_ATTR_HOST_ENCRYPT          BIT(14) +#define TX_HW_ATTR_EAPOL_FRAME           BIT(15)  #define TX_HW_ATTR_OFST_SAVE_RETRIES     0  #define TX_HW_ATTR_OFST_HEADER_PAD       1 @@ -56,6 +57,9 @@  /* Used for management frames and dummy packets */  #define WL1271_TID_MGMT 7 +/* stop a ROC for pending authentication reply after this time (ms) */ +#define WLCORE_PEND_AUTH_ROC_TIMEOUT     1000 +  struct wl127x_tx_mem {  	/*  	 * Number of extra memory blocks to allocate for this packet diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index 0034979e97c..95a54504f0c 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -73,6 +73,8 @@ struct wlcore_ops {  	void (*tx_immediate_compl)(struct wl1271 *wl);  	int (*hw_init)(struct wl1271 *wl);  	int (*init_vif)(struct wl1271 *wl, struct wl12xx_vif *wlvif); +	void (*convert_fw_status)(struct wl1271 *wl, void *raw_fw_status, +				  struct wl_fw_status *fw_status);  	u32 (*sta_get_ap_rate_mask)(struct wl1271 *wl,  				    struct wl12xx_vif *wlvif);  	int (*get_pg_ver)(struct wl1271 *wl, s8 *ver); @@ -110,6 +112,7 @@ struct wlcore_ops {  			    struct ieee80211_sta_ht_cap *ht_cap,  			    bool allow_ht_operation,  			    u32 rate_set, u8 hlid); +	u32 (*convert_hwaddr)(struct wl1271 *wl, u32 hwaddr);  	bool (*lnk_high_prio)(struct wl1271 *wl, u8 hlid,  			      struct wl1271_link *lnk);  	bool (*lnk_low_prio)(struct wl1271 *wl, u8 hlid, @@ -219,7 +222,7 @@ struct wl1271 {  	int channel;  	u8 system_hlid; -	unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)]; +	unsigned long links_map[BITS_TO_LONGS(WLCORE_MAX_LINKS)];  	unsigned long roles_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)];  	unsigned long roc_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)];  	unsigned long rate_policies_map[ @@ -227,7 +230,7 @@ struct wl1271 {  	unsigned long klv_templates_map[  			BITS_TO_LONGS(WLCORE_MAX_KLV_TEMPLATES)]; -	u8 session_ids[WL12XX_MAX_LINKS]; +	u8 session_ids[WLCORE_MAX_LINKS];  	struct list_head wlvif_list; @@ -290,6 +293,12 @@ struct wl1271 {  	/* Number of valid bytes in the FW log buffer */  	ssize_t fwlog_size; +	/* FW log end marker */ +	u32 fwlog_end; + +	/* FW memory block size */ +	u32 fw_mem_block_size; +  	/* Sysfs FW log entry readers wait queue */  	wait_queue_head_t fwlog_waitq; @@ -307,6 +316,8 @@ struct wl1271 {  	/* The mbox event mask */  	u32 event_mask; +	/* events to unmask only when ap interface is up */ +	u32 ap_event_mask;  	/* Mailbox pointers */  	u32 mbox_size; @@ -337,8 +348,8 @@ struct wl1271 {  	u32 buffer_cmd;  	u32 buffer_busyword[WL1271_BUSY_WORD_CNT]; -	struct wl_fw_status_1 *fw_status_1; -	struct wl_fw_status_2 *fw_status_2; +	void *raw_fw_status; +	struct wl_fw_status *fw_status;  	struct wl1271_tx_hw_res_if *tx_res_if;  	/* Current chipset configuration */ @@ -367,7 +378,7 @@ struct wl1271 {  	 * AP-mode - links indexed by HLID. The global and broadcast links  	 * are always active.  	 */ -	struct wl1271_link links[WL12XX_MAX_LINKS]; +	struct wl1271_link links[WLCORE_MAX_LINKS];  	/* number of currently active links */  	int active_link_count; @@ -396,6 +407,9 @@ struct wl1271 {  	/* AP-mode - number of currently connected stations */  	int active_sta_count; +	/* Flag determining whether AP should broadcast OFDM-only rates */ +	bool ofdm_only_ap; +  	/* last wlvif we transmitted from */  	struct wl12xx_vif *last_wlvif; @@ -425,6 +439,10 @@ struct wl1271 {  	u32 num_tx_desc;  	/* number of RX descriptors the HW supports. */  	u32 num_rx_desc; +	/* number of links the HW supports */ +	u8 num_links; +	/* max stations a single AP can support */ +	u8 max_ap_stations;  	/* translate HW Tx rates to standard rate-indices */  	const u8 **band_rate_to_idx; @@ -439,10 +457,11 @@ struct wl1271 {  	struct ieee80211_sta_ht_cap ht_cap[WLCORE_NUM_BANDS];  	/* size of the private FW status data */ +	size_t fw_status_len;  	size_t fw_status_priv_len;  	/* RX Data filter rule state - enabled/disabled */ -	bool rx_filter_enabled[WL1271_MAX_RX_FILTERS]; +	unsigned long rx_filter_enabled[BITS_TO_LONGS(WL1271_MAX_RX_FILTERS)];  	/* size of the private static data */  	size_t static_data_priv_len; @@ -467,8 +486,9 @@ struct wl1271 {  	struct completion nvs_loading_complete; -	/* number of concurrent channels the HW supports */ -	u32 num_channels; +	/* interface combinations supported by the hw */ +	const struct ieee80211_iface_combination *iface_combinations; +	u8 n_iface_combinations;  };  int wlcore_probe(struct wl1271 *wl, struct platform_device *pdev); @@ -481,6 +501,8 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,  		   struct ieee80211_sta *sta,  		   struct ieee80211_key_conf *key_conf);  void wlcore_regdomain_config(struct wl1271 *wl); +void wlcore_update_inconn_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, +			      struct wl1271_station *wl_sta, bool in_conn);  static inline void  wlcore_set_ht_cap(struct wl1271 *wl, enum ieee80211_band band, diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h index e5e146435fe..c2c34a84ff3 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h @@ -58,10 +58,15 @@  #define WL1271_DEFAULT_DTIM_PERIOD 1  #define WL12XX_MAX_ROLES           4 -#define WL12XX_MAX_LINKS           12  #define WL12XX_INVALID_ROLE_ID     0xff  #define WL12XX_INVALID_LINK_ID     0xff +/* + * max number of links allowed by all HWs. + * this is NOT the actual max links supported by the current hw. + */ +#define WLCORE_MAX_LINKS 16 +  /* the driver supports the 2.4Ghz and 5Ghz bands */  #define WLCORE_NUM_BANDS           2 @@ -118,72 +123,58 @@ struct wl1271_chip {  #define NUM_TX_QUEUES              4 -#define AP_MAX_STATIONS            8 - -struct wl_fw_packet_counters { -	/* Cumulative counter of released packets per AC */ -	u8 tx_released_pkts[NUM_TX_QUEUES]; - -	/* Cumulative counter of freed packets per HLID */ -	u8 tx_lnk_free_pkts[WL12XX_MAX_LINKS]; - -	/* Cumulative counter of released Voice memory blocks */ -	u8 tx_voice_released_blks; - -	/* Tx rate of the last transmitted packet */ -	u8 tx_last_rate; - -	u8 padding[2]; -} __packed; - -/* FW status registers */ -struct wl_fw_status_1 { -	__le32 intr; +struct wl_fw_status { +	u32 intr;  	u8  fw_rx_counter;  	u8  drv_rx_counter; -	u8  reserved;  	u8  tx_results_counter; -	__le32 rx_pkt_descs[0]; -} __packed; - -/* - * Each HW arch has a different number of Rx descriptors. - * The length of the status depends on it, since it holds an array - * of descriptors. - */ -#define WLCORE_FW_STATUS_1_LEN(num_rx_desc) \ -		(sizeof(struct wl_fw_status_1) + \ -		(sizeof(((struct wl_fw_status_1 *)0)->rx_pkt_descs[0])) * \ -		num_rx_desc) +	__le32 *rx_pkt_descs; -struct wl_fw_status_2 { -	__le32 fw_localtime; +	u32 fw_localtime;  	/*  	 * A bitmap (where each bit represents a single HLID)  	 * to indicate if the station is in PS mode.  	 */ -	__le32 link_ps_bitmap; +	u32 link_ps_bitmap;  	/*  	 * A bitmap (where each bit represents a single HLID) to indicate  	 * if the station is in Fast mode  	 */ -	__le32 link_fast_bitmap; +	u32 link_fast_bitmap;  	/* Cumulative counter of total released mem blocks since FW-reset */ -	__le32 total_released_blks; +	u32 total_released_blks;  	/* Size (in Memory Blocks) of TX pool */ -	__le32 tx_total; +	u32 tx_total; -	struct wl_fw_packet_counters counters; +	struct { +		/* +		 * Cumulative counter of released packets per AC +		 * (length of the array is NUM_TX_QUEUES) +		 */ +		u8 *tx_released_pkts; + +		/* +		 * Cumulative counter of freed packets per HLID +		 * (length of the array is wl->num_links) +		 */ +		u8 *tx_lnk_free_pkts; + +		/* Cumulative counter of released Voice memory blocks */ +		u8 tx_voice_released_blks; -	__le32 log_start_addr; +		/* Tx rate of the last transmitted packet */ +		u8 tx_last_rate; +	} counters; + +	u32 log_start_addr;  	/* Private status to be used by the lower drivers */ -	u8 priv[0]; -} __packed; +	void *priv; +};  #define WL1271_MAX_CHANNELS 64  struct wl1271_scan { @@ -240,6 +231,7 @@ enum wl12xx_flags {  	WL1271_FLAG_VIF_CHANGE_IN_PROGRESS,  	WL1271_FLAG_INTENDED_FW_RECOVERY,  	WL1271_FLAG_IO_FAILED, +	WL1271_FLAG_REINIT_TX_WDOG,  };  enum wl12xx_vif_flags { @@ -255,6 +247,7 @@ enum wl12xx_vif_flags {  	WLVIF_FLAG_CS_PROGRESS,  	WLVIF_FLAG_AP_PROBE_RESP_SET,  	WLVIF_FLAG_IN_USE, +	WLVIF_FLAG_ACTIVE,  };  struct wl12xx_vif; @@ -307,6 +300,7 @@ enum plt_mode {  	PLT_OFF = 0,  	PLT_ON = 1,  	PLT_FEM_DETECT = 2, +	PLT_CHIP_AWAKE = 3  };  struct wl12xx_rx_filter_field { @@ -366,7 +360,7 @@ struct wl12xx_vif {  			/* HLIDs bitmap of associated stations */  			unsigned long sta_hlid_map[BITS_TO_LONGS( -							WL12XX_MAX_LINKS)]; +							WLCORE_MAX_LINKS)];  			/* recoreded keys - set here before AP startup */  			struct wl1271_ap_key *recorded_keys[MAX_NUM_KEYS]; @@ -383,7 +377,7 @@ struct wl12xx_vif {  	/* counters of packets per AC, across all links in the vif */  	int tx_queue_count[NUM_TX_QUEUES]; -	unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)]; +	unsigned long links_map[BITS_TO_LONGS(WLCORE_MAX_LINKS)];  	u8 ssid[IEEE80211_MAX_SSID_LEN + 1];  	u8 ssid_len; @@ -456,6 +450,15 @@ struct wl12xx_vif {  	 */  	int hw_queue_base; +	/* do we have a pending auth reply? (and ROC) */ +	bool ap_pending_auth_reply; + +	/* time when we sent the pending auth reply */ +	unsigned long pending_auth_reply_time; + +	/* work for canceling ROC after pending auth reply */ +	struct delayed_work pending_auth_complete_work; +  	/*  	 * This struct must be last!  	 * data that has to be saved acrossed reconfigs (e.g. recovery) @@ -509,8 +512,8 @@ int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif);  void wl12xx_queue_recovery_work(struct wl1271 *wl);  size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen);  int wl1271_rx_filter_alloc_field(struct wl12xx_rx_filter *filter, -					u16 offset, u8 flags, -					u8 *pattern, u8 len); +				 u16 offset, u8 flags, +				 const u8 *pattern, u8 len);  void wl1271_rx_filter_free(struct wl12xx_rx_filter *filter);  struct wl12xx_rx_filter *wl1271_rx_filter_alloc(void);  int wl1271_rx_filter_get_fields_size(struct wl12xx_rx_filter *filter); @@ -539,6 +542,4 @@ void wl1271_rx_filter_flatten_fields(struct wl12xx_rx_filter *filter,  #define HW_HT_RATES_OFFSET	16  #define HW_MIMO_RATES_OFFSET	24 -#define WL12XX_HW_BLOCK_SIZE	256 -  #endif /* __WLCORE_I_H__ */  | 
