diff options
| author | John W. Linville <linville@tuxdriver.com> | 2012-11-16 14:08:14 -0500 | 
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2012-11-16 14:08:14 -0500 | 
| commit | 1e5023c7cc11158f74a637aa92897da954572a25 (patch) | |
| tree | a0b2234b331abf9b2c80dbce20a018d537e541a6 | |
| parent | dfbebe14428803402293d9a8bf1efef7221d8b78 (diff) | |
| parent | ff7e68670c49b6404acc4fce6ca90d6c89ef0efe (diff) | |
| download | olio-linux-3.10-1e5023c7cc11158f74a637aa92897da954572a25.tar.xz olio-linux-3.10-1e5023c7cc11158f74a637aa92897da954572a25.zip  | |
Merge branch 'for-linville' of git://github.com/kvalo/ath6kl
| -rw-r--r-- | drivers/net/wireless/ath/ath6kl/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath6kl/Makefile | 1 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath6kl/cfg80211.c | 370 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath6kl/cfg80211.h | 1 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath6kl/core.c | 21 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath6kl/core.h | 69 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath6kl/debug.h | 1 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath6kl/hif.c | 6 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath6kl/htc_mbox.c | 13 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath6kl/htc_pipe.c | 14 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath6kl/init.c | 92 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath6kl/main.c | 55 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath6kl/recovery.c | 160 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath6kl/sdio.c | 27 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath6kl/txrx.c | 47 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath6kl/usb.c | 32 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath6kl/wmi.c | 279 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath6kl/wmi.h | 78 | 
18 files changed, 990 insertions, 285 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/Kconfig b/drivers/net/wireless/ath/ath6kl/Kconfig index d755a5e7ed2..26c4b722085 100644 --- a/drivers/net/wireless/ath/ath6kl/Kconfig +++ b/drivers/net/wireless/ath/ath6kl/Kconfig @@ -30,3 +30,12 @@ config ATH6KL_DEBUG  	depends on ATH6KL  	---help---  	  Enables debug support + +config ATH6KL_REGDOMAIN +	bool "Atheros ath6kl regdomain support" +	depends on ATH6KL +	depends on CFG80211_CERTIFICATION_ONUS +	---help--- +	  Enabling this makes it possible to change the regdomain in +	  the firmware. This can be only enabled if regulatory requirements +	  are taken into account. diff --git a/drivers/net/wireless/ath/ath6kl/Makefile b/drivers/net/wireless/ath/ath6kl/Makefile index 8cae8886f17..cab0ec0d538 100644 --- a/drivers/net/wireless/ath/ath6kl/Makefile +++ b/drivers/net/wireless/ath/ath6kl/Makefile @@ -34,6 +34,7 @@ ath6kl_core-y += main.o  ath6kl_core-y += txrx.o  ath6kl_core-y += wmi.o  ath6kl_core-y += core.o +ath6kl_core-y += recovery.o  ath6kl_core-$(CONFIG_NL80211_TESTMODE) += testmode.o  obj-$(CONFIG_ATH6KL_SDIO) += ath6kl_sdio.o diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index d615f9f7506..83d8c5eabbe 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -147,15 +147,15 @@ static bool __ath6kl_cfg80211_sscan_stop(struct ath6kl_vif *vif)  {  	struct ath6kl *ar = vif->ar; -	if (ar->state != ATH6KL_STATE_SCHED_SCAN) +	if (!test_and_clear_bit(SCHED_SCANNING, &vif->flags))  		return false;  	del_timer_sync(&vif->sched_scan_timer); -	ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, -					   ATH6KL_HOST_MODE_AWAKE); +	if (ar->state == ATH6KL_STATE_RECOVERY) +		return true; -	ar->state = ATH6KL_STATE_ON; +	ath6kl_wmi_enable_sched_scan_cmd(ar->wmi, vif->fw_vif_idx, false);  	return true;  } @@ -369,17 +369,13 @@ static int ath6kl_nliftype_to_drv_iftype(enum nl80211_iftype type, u8 *nw_type)  {  	switch (type) {  	case NL80211_IFTYPE_STATION: +	case NL80211_IFTYPE_P2P_CLIENT:  		*nw_type = INFRA_NETWORK;  		break;  	case NL80211_IFTYPE_ADHOC:  		*nw_type = ADHOC_NETWORK;  		break;  	case NL80211_IFTYPE_AP: -		*nw_type = AP_NETWORK; -		break; -	case NL80211_IFTYPE_P2P_CLIENT: -		*nw_type = INFRA_NETWORK; -		break;  	case NL80211_IFTYPE_P2P_GO:  		*nw_type = AP_NETWORK;  		break; @@ -1031,30 +1027,15 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy,  	vif->scan_req = request; -	if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, -		     ar->fw_capabilities)) { -		/* -		 * If capable of doing P2P mgmt operations using -		 * station interface, send additional information like -		 * supported rates to advertise and xmit rates for -		 * probe requests -		 */ -		ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx, -						WMI_LONG_SCAN, force_fg_scan, -						false, 0, -						ATH6KL_FG_SCAN_INTERVAL, -						n_channels, channels, -						request->no_cck, -						request->rates); -	} else { -		ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, -						WMI_LONG_SCAN, force_fg_scan, -						false, 0, -						ATH6KL_FG_SCAN_INTERVAL, -						n_channels, channels); -	} +	ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx, +				       WMI_LONG_SCAN, force_fg_scan, +				       false, 0, +				       ATH6KL_FG_SCAN_INTERVAL, +				       n_channels, channels, +				       request->no_cck, +				       request->rates);  	if (ret) { -		ath6kl_err("wmi_startscan_cmd failed\n"); +		ath6kl_err("failed to start scan: %d\n", ret);  		vif->scan_req = NULL;  	} @@ -1888,7 +1869,7 @@ static int ath6kl_wow_usr(struct ath6kl *ar, struct ath6kl_vif *vif,  			  struct cfg80211_wowlan *wow, u32 *filter)  {  	int ret, pos; -	u8 mask[WOW_MASK_SIZE]; +	u8 mask[WOW_PATTERN_SIZE];  	u16 i;  	/* Configure the patterns that we received from the user. */ @@ -2106,33 +2087,16 @@ static int ath6kl_cfg80211_host_sleep(struct ath6kl *ar, struct ath6kl_vif *vif)  	return ret;  } -static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) +static int ath6kl_wow_suspend_vif(struct ath6kl_vif *vif, +				  struct cfg80211_wowlan *wow, u32 *filter)  { +	struct ath6kl *ar = vif->ar;  	struct in_device *in_dev;  	struct in_ifaddr *ifa; -	struct ath6kl_vif *vif;  	int ret; -	u32 filter = 0;  	u16 i, bmiss_time; -	u8 index = 0;  	__be32 ips[MAX_IP_ADDRS]; - -	/* The FW currently can't support multi-vif WoW properly. */ -	if (ar->num_vif > 1) -		return -EIO; - -	vif = ath6kl_vif_first(ar); -	if (!vif) -		return -EIO; - -	if (!ath6kl_cfg80211_ready(vif)) -		return -EIO; - -	if (!test_bit(CONNECTED, &vif->flags)) -		return -ENOTCONN; - -	if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST)) -		return -EINVAL; +	u8 index = 0;  	if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags) &&  	    test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER, @@ -2154,7 +2118,7 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)  	 * the user.  	 */  	if (wow) -		ret = ath6kl_wow_usr(ar, vif, wow, &filter); +		ret = ath6kl_wow_usr(ar, vif, wow, filter);  	else if (vif->nw_type == AP_NETWORK)  		ret = ath6kl_wow_ap(ar, vif);  	else @@ -2189,12 +2153,10 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)  			return ret;  	} -	ar->state = ATH6KL_STATE_SUSPENDING; -  	/* Setup own IP addr for ARP agent. */  	in_dev = __in_dev_get_rtnl(vif->ndev);  	if (!in_dev) -		goto skip_arp; +		return 0;  	ifa = in_dev->ifa_list;  	memset(&ips, 0, sizeof(ips)); @@ -2217,41 +2179,61 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)  		return ret;  	} -skip_arp: -	ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx, +	return ret; +} + +static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) +{ +	struct ath6kl_vif *first_vif, *vif; +	int ret = 0; +	u32 filter = 0; +	bool connected = false; + +	/* enter / leave wow suspend on first vif always */ +	first_vif = ath6kl_vif_first(ar); +	if (WARN_ON(unlikely(!first_vif)) || +	    !ath6kl_cfg80211_ready(first_vif)) +		return -EIO; + +	if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST)) +		return -EINVAL; + +	/* install filters for each connected vif */ +	spin_lock_bh(&ar->list_lock); +	list_for_each_entry(vif, &ar->vif_list, list) { +		if (!test_bit(CONNECTED, &vif->flags) || +		    !ath6kl_cfg80211_ready(vif)) +			continue; +		connected = true; + +		ret = ath6kl_wow_suspend_vif(vif, wow, &filter); +		if (ret) +			break; +	} +	spin_unlock_bh(&ar->list_lock); + +	if (!connected) +		return -ENOTCONN; +	else if (ret) +		return ret; + +	ar->state = ATH6KL_STATE_SUSPENDING; + +	ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, first_vif->fw_vif_idx,  					  ATH6KL_WOW_MODE_ENABLE,  					  filter,  					  WOW_HOST_REQ_DELAY);  	if (ret)  		return ret; -	ret = ath6kl_cfg80211_host_sleep(ar, vif); -	if (ret) -		return ret; - -	return 0; +	return ath6kl_cfg80211_host_sleep(ar, first_vif);  } -static int ath6kl_wow_resume(struct ath6kl *ar) +static int ath6kl_wow_resume_vif(struct ath6kl_vif *vif)  { -	struct ath6kl_vif *vif; +	struct ath6kl *ar = vif->ar;  	int ret; -	vif = ath6kl_vif_first(ar); -	if (!vif) -		return -EIO; - -	ar->state = ATH6KL_STATE_RESUMING; - -	ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, -						 ATH6KL_HOST_MODE_AWAKE); -	if (ret) { -		ath6kl_warn("Failed to configure host sleep mode for wow resume: %d\n", -			    ret); -		ar->state = ATH6KL_STATE_WOW; -		return ret; -	} -  	if (vif->nw_type != AP_NETWORK) {  		ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,  						0, 0, 0, 0, 0, 0, 3, 0, 0, 0); @@ -2269,13 +2251,11 @@ static int ath6kl_wow_resume(struct ath6kl *ar)  			return ret;  	} -	ar->state = ATH6KL_STATE_ON; -  	if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags) &&  	    test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,  		     ar->fw_capabilities)) {  		ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, -					vif->fw_vif_idx, true); +						  vif->fw_vif_idx, true);  		if (ret)  			return ret;  	} @@ -2285,6 +2265,48 @@ static int ath6kl_wow_resume(struct ath6kl *ar)  	return 0;  } +static int ath6kl_wow_resume(struct ath6kl *ar) +{ +	struct ath6kl_vif *vif; +	int ret; + +	vif = ath6kl_vif_first(ar); +	if (WARN_ON(unlikely(!vif)) || +	    !ath6kl_cfg80211_ready(vif)) +		return -EIO; + +	ar->state = ATH6KL_STATE_RESUMING; + +	ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, +						 ATH6KL_HOST_MODE_AWAKE); +	if (ret) { +		ath6kl_warn("Failed to configure host sleep mode for wow resume: %d\n", +			    ret); +		goto cleanup; +	} + +	spin_lock_bh(&ar->list_lock); +	list_for_each_entry(vif, &ar->vif_list, list) { +		if (!test_bit(CONNECTED, &vif->flags) || +		    !ath6kl_cfg80211_ready(vif)) +			continue; +		ret = ath6kl_wow_resume_vif(vif); +		if (ret) +			break; +	} +	spin_unlock_bh(&ar->list_lock); + +	if (ret) +		goto cleanup; + +	ar->state = ATH6KL_STATE_ON; +	return 0; + +cleanup: +	ar->state = ATH6KL_STATE_WOW; +	return ret; +} +  static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar)  {  	struct ath6kl_vif *vif; @@ -2421,13 +2443,6 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,  		break; -	case ATH6KL_CFG_SUSPEND_SCHED_SCAN: -		/* -		 * Nothing needed for schedule scan, firmware is already in -		 * wow mode and sleeping most of the time. -		 */ -		break; -  	default:  		break;  	} @@ -2475,9 +2490,6 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar)  		}  		break; -	case ATH6KL_STATE_SCHED_SCAN: -		break; -  	default:  		break;  	} @@ -2494,14 +2506,23 @@ static int __ath6kl_cfg80211_suspend(struct wiphy *wiphy,  {  	struct ath6kl *ar = wiphy_priv(wiphy); +	ath6kl_recovery_suspend(ar); +  	return ath6kl_hif_suspend(ar, wow);  }  static int __ath6kl_cfg80211_resume(struct wiphy *wiphy)  {  	struct ath6kl *ar = wiphy_priv(wiphy); +	int err; + +	err = ath6kl_hif_resume(ar); +	if (err) +		return err; + +	ath6kl_recovery_resume(ar); -	return ath6kl_hif_resume(ar); +	return 0;  }  /* @@ -2738,6 +2759,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,  	int res;  	int i, ret;  	u16 rsn_capab = 0; +	int inactivity_timeout = 0;  	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__); @@ -2874,8 +2896,15 @@ 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) +			inactivity_timeout = DIV_ROUND_UP(inactivity_timeout, +							  60); +  		res = ath6kl_wmi_set_inact_period(ar->wmi, vif->fw_vif_idx, -						  info->inactivity_timeout); +						  inactivity_timeout);  		if (res < 0)  			return res;  	} @@ -2897,6 +2926,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,  					    WLAN_EID_RSN, WMI_RSN_IE_CAPB,  					    (const u8 *) &rsn_capab,  					    sizeof(rsn_capab)); +		vif->rsn_capab = rsn_capab;  		if (res < 0)  			return res;  	} @@ -3210,7 +3240,7 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,  	struct ath6kl *ar = ath6kl_priv(dev);  	struct ath6kl_vif *vif = netdev_priv(dev);  	u16 interval; -	int ret; +	int ret, rssi_thold;  	if (ar->state != ATH6KL_STATE_ON)  		return -EIO; @@ -3218,10 +3248,6 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,  	if (vif->sme_state != SME_DISCONNECTED)  		return -EBUSY; -	/* The FW currently can't support multi-vif WoW properly. */ -	if (ar->num_vif > 1) -		return -EIO; -  	ath6kl_cfg80211_scan_complete_event(vif, true);  	ret = ath6kl_set_probed_ssids(ar, vif, request->ssids, @@ -3243,6 +3269,23 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,  			return ret;  	} +	if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD, +		     ar->fw_capabilities)) { +		if (request->rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF) +			rssi_thold = 0; +		else if (request->rssi_thold < -127) +			rssi_thold = -127; +		else +			rssi_thold = request->rssi_thold; + +		ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx, +						     rssi_thold); +		if (ret) { +			ath6kl_err("failed to set RSSI threshold for scan\n"); +			return ret; +		} +	} +  	/* fw uses seconds, also make sure that it's >0 */  	interval = max_t(u16, 1, request->interval / 1000); @@ -3250,15 +3293,6 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,  				  interval, interval,  				  vif->bg_scan_period, 0, 0, 0, 3, 0, 0, 0); -	ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx, -					  ATH6KL_WOW_MODE_ENABLE, -					  WOW_FILTER_SSID, -					  WOW_HOST_REQ_DELAY); -	if (ret) { -		ath6kl_warn("Failed to enable wow with ssid filter: %d\n", ret); -		return ret; -	} -  	/* this also clears IE in fw if it's not set */  	ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,  				       WMI_FRAME_PROBE_REQ, @@ -3269,17 +3303,13 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,  		return ret;  	} -	ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, -						 ATH6KL_HOST_MODE_ASLEEP); -	if (ret) { -		ath6kl_warn("Failed to enable host sleep mode for sched scan: %d\n", -			    ret); +	ret = ath6kl_wmi_enable_sched_scan_cmd(ar->wmi, vif->fw_vif_idx, true); +	if (ret)  		return ret; -	} -	ar->state = ATH6KL_STATE_SCHED_SCAN; +	set_bit(SCHED_SCANNING, &vif->flags); -	return ret; +	return 0;  }  static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy, @@ -3308,6 +3338,27 @@ static int ath6kl_cfg80211_set_bitrate(struct wiphy *wiphy,  					   mask);  } +static int ath6kl_cfg80211_set_txe_config(struct wiphy *wiphy, +					  struct net_device *dev, +					  u32 rate, u32 pkts, u32 intvl) +{ +	struct ath6kl *ar = ath6kl_priv(dev); +	struct ath6kl_vif *vif = netdev_priv(dev); + +	if (vif->nw_type != INFRA_NETWORK || +	    !test_bit(ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY, ar->fw_capabilities)) +		return -EOPNOTSUPP; + +	if (vif->sme_state != SME_CONNECTED) +		return -ENOTCONN; + +	/* save this since the firmware won't report the interval */ +	vif->txe_intvl = intvl; + +	return ath6kl_wmi_set_txe_notify(ar->wmi, vif->fw_vif_idx, +					 rate, pkts, intvl); +} +  static const struct ieee80211_txrx_stypes  ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {  	[NL80211_IFTYPE_STATION] = { @@ -3374,6 +3425,7 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {  	.sched_scan_start = ath6kl_cfg80211_sscan_start,  	.sched_scan_stop = ath6kl_cfg80211_sscan_stop,  	.set_bitrate_mask = ath6kl_cfg80211_set_bitrate, +	.set_cqm_txe_config = ath6kl_cfg80211_set_txe_config,  };  void ath6kl_cfg80211_stop(struct ath6kl_vif *vif) @@ -3394,16 +3446,22 @@ void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)  		break;  	} -	if (test_bit(CONNECTED, &vif->flags) || -	    test_bit(CONNECT_PEND, &vif->flags)) +	if (vif->ar->state != ATH6KL_STATE_RECOVERY && +	    (test_bit(CONNECTED, &vif->flags) || +	    test_bit(CONNECT_PEND, &vif->flags)))  		ath6kl_wmi_disconnect_cmd(vif->ar->wmi, vif->fw_vif_idx);  	vif->sme_state = SME_DISCONNECTED;  	clear_bit(CONNECTED, &vif->flags);  	clear_bit(CONNECT_PEND, &vif->flags); +	/* Stop netdev queues, needed during recovery */ +	netif_stop_queue(vif->ndev); +	netif_carrier_off(vif->ndev); +  	/* disable scanning */ -	if (ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF, +	if (vif->ar->state != ATH6KL_STATE_RECOVERY && +	    ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF,  				      0, 0, 0, 0, 0, 0, 0, 0, 0) != 0)  		ath6kl_warn("failed to disable scan during stop\n"); @@ -3415,7 +3473,7 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar)  	struct ath6kl_vif *vif;  	vif = ath6kl_vif_first(ar); -	if (!vif) { +	if (!vif && ar->state != ATH6KL_STATE_RECOVERY) {  		/* save the current power mode before enabling power save */  		ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode; @@ -3433,6 +3491,56 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar)  		ath6kl_cfg80211_stop(vif);  } +static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy, +				      struct regulatory_request *request) +{ +	struct ath6kl *ar = wiphy_priv(wiphy); +	u32 rates[IEEE80211_NUM_BANDS]; +	int ret, i; + +	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, +		   "cfg reg_notify %c%c%s%s initiator %d hint_type %d\n", +		   request->alpha2[0], request->alpha2[1], +		   request->intersect ? " intersect" : "", +		   request->processed ? " processed" : "", +		   request->initiator, request->user_reg_hint_type); + +	/* +	 * As firmware is not able intersect regdoms, we can only listen to +	 * cellular hints. +	 */ +	if (request->user_reg_hint_type != NL80211_USER_REG_HINT_CELL_BASE) +		return -EOPNOTSUPP; + +	ret = ath6kl_wmi_set_regdomain_cmd(ar->wmi, request->alpha2); +	if (ret) { +		ath6kl_err("failed to set regdomain: %d\n", ret); +		return ret; +	} + +	/* +	 * Firmware will apply the regdomain change only after a scan is +	 * issued and it will send a WMI_REGDOMAIN_EVENTID when it has been +	 * changed. +	 */ + +	for (i = 0; i < IEEE80211_NUM_BANDS; i++) +		if (wiphy->bands[i]) +			rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1; + + +	ret = ath6kl_wmi_beginscan_cmd(ar->wmi, 0, WMI_LONG_SCAN, false, +				       false, 0, ATH6KL_FG_SCAN_INTERVAL, +				       0, NULL, false, rates); +	if (ret) { +		ath6kl_err("failed to start scan for a regdomain change: %d\n", +			   ret); +		return ret; +	} + +	return 0; +} +  static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif)  {  	vif->aggr_cntxt = aggr_init(vif); @@ -3505,9 +3613,13 @@ struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name,  	vif->htcap[IEEE80211_BAND_5GHZ].ht_enable = true;  	memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); -	if (fw_vif_idx != 0) +	if (fw_vif_idx != 0) {  		ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) |  				     0x2; +		if (test_bit(ATH6KL_FW_CAPABILITY_CUSTOM_MAC_ADDR, +			     ar->fw_capabilities)) +			ndev->dev_addr[4] ^= 0x80; +	}  	init_netdev(ndev); @@ -3561,6 +3673,12 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)  					  BIT(NL80211_IFTYPE_P2P_CLIENT);  	} +	if (config_enabled(CONFIG_ATH6KL_REGDOMAIN) && +	    test_bit(ATH6KL_FW_CAPABILITY_REGDOMAIN, ar->fw_capabilities)) { +		wiphy->reg_notifier = ath6kl_cfg80211_reg_notify; +		ar->wiphy->features |= NL80211_FEATURE_CELL_BASE_REG_HINTS; +	} +  	/* max num of ssids that can be probed during scanning */  	wiphy->max_scan_ssids = MAX_PROBED_SSIDS; @@ -3606,7 +3724,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)  		ath6kl_band_5ghz.ht_cap.ht_supported = false;  	} -	if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES) { +	if (ar->hw.flags & ATH6KL_HW_64BIT_RATES) {  		ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;  		ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;  		ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff; @@ -3645,7 +3763,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)  			    WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |  			    WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; -	if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities)) +	if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, ar->fw_capabilities))  		ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;  	if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT, diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h index 780f77775a9..e5e70f3a8ca 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.h +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h @@ -22,7 +22,6 @@ enum ath6kl_cfg_suspend_mode {  	ATH6KL_CFG_SUSPEND_DEEPSLEEP,  	ATH6KL_CFG_SUSPEND_CUTPOWER,  	ATH6KL_CFG_SUSPEND_WOW, -	ATH6KL_CFG_SUSPEND_SCHED_SCAN,  };  struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name, diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index 82c4dd2a960..4b46adbe8c9 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -33,6 +33,8 @@ static unsigned int wow_mode;  static unsigned int uart_debug;  static unsigned int ath6kl_p2p;  static unsigned int testmode; +static unsigned int recovery_enable; +static unsigned int heart_beat_poll;  module_param(debug_mask, uint, 0644);  module_param(suspend_mode, uint, 0644); @@ -40,6 +42,12 @@ module_param(wow_mode, uint, 0644);  module_param(uart_debug, uint, 0644);  module_param(ath6kl_p2p, uint, 0644);  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");  void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb)  { @@ -202,6 +210,17 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type)  	ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n",  		   __func__, wdev->netdev->name, wdev->netdev, ar); +	ar->fw_recovery.enable = !!recovery_enable; +	if (!ar->fw_recovery.enable) +		return ret; + +	if (heart_beat_poll && +	    test_bit(ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL, +		     ar->fw_capabilities)) +		ar->fw_recovery.hb_poll = heart_beat_poll; + +	ath6kl_recovery_init(ar); +  	return ret;  err_rxbuf_cleanup: @@ -291,6 +310,8 @@ void ath6kl_core_cleanup(struct ath6kl *ar)  {  	ath6kl_hif_power_off(ar); +	ath6kl_recovery_cleanup(ar); +  	destroy_workqueue(ar->ath6kl_wq);  	if (ar->htc_target) diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index cec49a31029..189d8faf8c8 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -115,6 +115,27 @@ enum ath6kl_fw_capability {  	 */  	ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST, +	/* Firmware supports filtering BSS results by RSSI */ +	ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD, + +	/* FW sets mac_addr[4] ^= 0x80 for newly created interfaces */ +	ATH6KL_FW_CAPABILITY_CUSTOM_MAC_ADDR, + +	/* Firmware supports TX error rate notification */ +	ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY, + +	/* supports WMI_SET_REGDOMAIN_CMDID command */ +	ATH6KL_FW_CAPABILITY_REGDOMAIN, + +	/* Firmware supports sched scan decoupled from host sleep */ +	ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, + +	/* +	 * Firmware capability for hang detection through heart beat +	 * challenge messages. +	 */ +	ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL, +  	/* this needs to be last */  	ATH6KL_FW_CAPABILITY_MAX,  }; @@ -128,11 +149,15 @@ struct ath6kl_fw_ie {  };  enum ath6kl_hw_flags { -	ATH6KL_HW_FLAG_64BIT_RATES	= BIT(0), +	ATH6KL_HW_64BIT_RATES		= BIT(0), +	ATH6KL_HW_AP_INACTIVITY_MINS	= BIT(1), +	ATH6KL_HW_MAP_LP_ENDPOINT	= BIT(2), +	ATH6KL_HW_SDIO_CRC_ERROR_WAR	= BIT(3),  };  #define ATH6KL_FW_API2_FILE "fw-2.bin"  #define ATH6KL_FW_API3_FILE "fw-3.bin" +#define ATH6KL_FW_API4_FILE "fw-4.bin"  /* AR6003 1.0 definitions */  #define AR6003_HW_1_0_VERSION                 0x300002ba @@ -186,6 +211,13 @@ enum ath6kl_hw_flags {  #define AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE \  	AR6004_HW_1_2_FW_DIR "/bdata.bin" +/* AR6004 1.3 definitions */ +#define AR6004_HW_1_3_VERSION			0x31c8088a +#define AR6004_HW_1_3_FW_DIR			"ath6k/AR6004/hw1.3" +#define AR6004_HW_1_3_FIRMWARE_FILE		"fw.ram.bin" +#define AR6004_HW_1_3_BOARD_DATA_FILE		"ath6k/AR6004/hw1.3/bdata.bin" +#define AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE	"ath6k/AR6004/hw1.3/bdata.bin" +  /* Per STA data, used in AP mode */  #define STA_PS_AWAKE		BIT(0)  #define	STA_PS_SLEEP		BIT(1) @@ -536,6 +568,7 @@ enum ath6kl_vif_state {  	HOST_SLEEP_MODE_CMD_PROCESSED,  	NETDEV_MCAST_ALL_ON,  	NETDEV_MCAST_ALL_OFF, +	SCHED_SCANNING,  };  struct ath6kl_vif { @@ -580,11 +613,13 @@ struct ath6kl_vif {  	u16 assoc_bss_beacon_int;  	u16 listen_intvl_t;  	u16 bmiss_time_t; +	u32 txe_intvl;  	u16 bg_scan_period;  	u8 assoc_bss_dtim_period;  	struct net_device_stats net_stats;  	struct target_stats target_stats;  	struct wmi_connect_cmd profile; +	u16 rsn_capab;  	struct list_head mc_filter;  }; @@ -609,6 +644,7 @@ enum ath6kl_dev_state {  	SKIP_SCAN,  	ROAM_TBL_PEND,  	FIRST_BOOT, +	RECOVERY_CLEANUP,  };  enum ath6kl_state { @@ -619,7 +655,16 @@ enum ath6kl_state {  	ATH6KL_STATE_DEEPSLEEP,  	ATH6KL_STATE_CUTPOWER,  	ATH6KL_STATE_WOW, -	ATH6KL_STATE_SCHED_SCAN, +	ATH6KL_STATE_RECOVERY, +}; + +/* Fw error recovery */ +#define ATH6KL_HB_RESP_MISS_THRES	5 + +enum ath6kl_fw_err { +	ATH6KL_FW_ASSERT, +	ATH6KL_FW_HB_RESP_FAILURE, +	ATH6KL_FW_EP_FULL,  };  struct ath6kl { @@ -679,6 +724,7 @@ struct ath6kl {  	struct ath6kl_req_key ap_mode_bkey;  	struct sk_buff_head mcastpsq;  	u32 want_ch_switch; +	u16 last_ch;  	/*  	 * FIXME: protects access to mcastpsq but is actually useless as @@ -764,6 +810,17 @@ struct ath6kl {  	bool wiphy_registered; +	struct ath6kl_fw_recovery { +		struct work_struct recovery_work; +		unsigned long err_reason; +		unsigned long hb_poll; +		struct timer_list hb_timer; +		u32 seq_num; +		bool hb_pending; +		u8 hb_misscnt; +		bool enable; +	} fw_recovery; +  #ifdef CONFIG_ATH6KL_DEBUG  	struct {  		struct sk_buff_head fwlog_queue; @@ -899,4 +956,12 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type);  void ath6kl_core_cleanup(struct ath6kl *ar);  void ath6kl_core_destroy(struct ath6kl *ar); +/* Fw error recovery */ +void ath6kl_init_hw_restart(struct ath6kl *ar); +void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason); +void ath6kl_recovery_hb_event(struct ath6kl *ar, u32 cookie); +void ath6kl_recovery_init(struct ath6kl *ar); +void ath6kl_recovery_cleanup(struct ath6kl *ar); +void ath6kl_recovery_suspend(struct ath6kl *ar); +void ath6kl_recovery_resume(struct ath6kl *ar);  #endif /* CORE_H */ diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h index 49639d8266c..f97cd4ead54 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.h +++ b/drivers/net/wireless/ath/ath6kl/debug.h @@ -44,6 +44,7 @@ enum ATH6K_DEBUG_MASK {  	ATH6KL_DBG_SUSPEND	= BIT(20),  	ATH6KL_DBG_USB		= BIT(21),  	ATH6KL_DBG_USB_BULK	= BIT(22), +	ATH6KL_DBG_RECOVERY	= BIT(23),  	ATH6KL_DBG_ANY	        = 0xffffffff  /* enable all logs */  }; diff --git a/drivers/net/wireless/ath/ath6kl/hif.c b/drivers/net/wireless/ath/ath6kl/hif.c index 9e47c4a138a..a6b614421fa 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.c +++ b/drivers/net/wireless/ath/ath6kl/hif.c @@ -136,6 +136,7 @@ static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev)  	ath6kl_hif_dump_fw_crash(dev->ar);  	ath6kl_read_fwlogs(dev->ar); +	ath6kl_recovery_err_notify(dev->ar, ATH6KL_FW_ASSERT);  	return ret;  } @@ -693,11 +694,6 @@ int ath6kl_hif_setup(struct ath6kl_device *dev)  	ath6kl_dbg(ATH6KL_DBG_HIF, "hif block size %d mbox addr 0x%x\n",  		   dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr); -	/* usb doesn't support enabling interrupts */ -	/* FIXME: remove check once USB support is implemented */ -	if (dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) -		return 0; -  	status = ath6kl_hif_disable_intrs(dev);  fail_setup: diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c index cd0e1ba410d..fbb78dfe078 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c +++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c @@ -2492,7 +2492,8 @@ static int ath6kl_htc_mbox_conn_service(struct htc_target *target,  		max_msg_sz = le16_to_cpu(resp_msg->max_msg_sz);  	} -	if (assigned_ep >= ENDPOINT_MAX || !max_msg_sz) { +	if (WARN_ON_ONCE(assigned_ep == ENDPOINT_UNUSED || +			 assigned_ep >= ENDPOINT_MAX || !max_msg_sz)) {  		status = -ENOMEM;  		goto fail_tx;  	} @@ -2655,12 +2656,6 @@ static int ath6kl_htc_mbox_wait_target(struct htc_target *target)  	struct htc_service_connect_resp resp;  	int status; -	/* FIXME: remove once USB support is implemented */ -	if (target->dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) { -		ath6kl_err("HTC doesn't support USB yet. Patience!\n"); -		return -EOPNOTSUPP; -	} -  	/* we should be getting 1 control message that the target is ready */  	packet = htc_wait_for_ctrl_msg(target); @@ -2890,9 +2885,7 @@ static void ath6kl_htc_mbox_cleanup(struct htc_target *target)  {  	struct htc_packet *packet, *tmp_packet; -	/* FIXME: remove check once USB support is implemented */ -	if (target->dev->ar->hif_type != ATH6KL_HIF_TYPE_USB) -		ath6kl_hif_cleanup_scatter(target->dev->ar); +	ath6kl_hif_cleanup_scatter(target->dev->ar);  	list_for_each_entry_safe(packet, tmp_packet,  				 &target->free_ctrl_txbuf, list) { diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c index f9626c72369..ba6bd497b78 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c +++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c @@ -374,9 +374,8 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target,  				packet = list_first_entry(txq,  							  struct htc_packet,  							  list); -				list_del(&packet->list); -				/* insert into local queue */ -				list_add_tail(&packet->list, &send_queue); +				/* move to local queue */ +				list_move_tail(&packet->list, &send_queue);  			}  			/* @@ -399,11 +398,10 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target,  					 * for cleanup */  				} else {  					/* callback wants to keep this packet, -					 * remove from caller's queue */ -					list_del(&packet->list); -					/* put it in the send queue */ -					list_add_tail(&packet->list, -						      &send_queue); +					 * move from caller's queue to the send +					 * queue */ +					list_move_tail(&packet->list, +						       &send_queue);  				}  			} diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index f90b5db741c..f21fa322e5c 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -42,7 +42,7 @@ static const struct ath6kl_hw hw_list[] = {  		.reserved_ram_size		= 6912,  		.refclk_hz			= 26000000,  		.uarttx_pin			= 8, -		.flags				= 0, +		.flags				= ATH6KL_HW_SDIO_CRC_ERROR_WAR,  		/* hw2.0 needs override address hardcoded */  		.app_start_override_addr	= 0x944C00, @@ -68,7 +68,7 @@ static const struct ath6kl_hw hw_list[] = {  		.refclk_hz			= 26000000,  		.uarttx_pin			= 8,  		.testscript_addr		= 0x57ef74, -		.flags				= 0, +		.flags				= ATH6KL_HW_SDIO_CRC_ERROR_WAR,  		.fw = {  			.dir		= AR6003_HW_2_1_1_FW_DIR, @@ -93,7 +93,8 @@ static const struct ath6kl_hw hw_list[] = {  		.board_addr			= 0x433900,  		.refclk_hz			= 26000000,  		.uarttx_pin			= 11, -		.flags				= ATH6KL_HW_FLAG_64BIT_RATES, +		.flags				= ATH6KL_HW_64BIT_RATES | +						  ATH6KL_HW_AP_INACTIVITY_MINS,  		.fw = {  			.dir		= AR6004_HW_1_0_FW_DIR, @@ -113,8 +114,8 @@ static const struct ath6kl_hw hw_list[] = {  		.board_addr			= 0x43d400,  		.refclk_hz			= 40000000,  		.uarttx_pin			= 11, -		.flags				= ATH6KL_HW_FLAG_64BIT_RATES, - +		.flags				= ATH6KL_HW_64BIT_RATES | +						  ATH6KL_HW_AP_INACTIVITY_MINS,  		.fw = {  			.dir		= AR6004_HW_1_1_FW_DIR,  			.fw		= AR6004_HW_1_1_FIRMWARE_FILE, @@ -133,7 +134,8 @@ static const struct ath6kl_hw hw_list[] = {  		.board_addr			= 0x435c00,  		.refclk_hz			= 40000000,  		.uarttx_pin			= 11, -		.flags				= ATH6KL_HW_FLAG_64BIT_RATES, +		.flags				= ATH6KL_HW_64BIT_RATES | +						  ATH6KL_HW_AP_INACTIVITY_MINS,  		.fw = {  			.dir		= AR6004_HW_1_2_FW_DIR, @@ -142,6 +144,28 @@ static const struct ath6kl_hw hw_list[] = {  		.fw_board		= AR6004_HW_1_2_BOARD_DATA_FILE,  		.fw_default_board	= AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE,  	}, +	{ +		.id				= AR6004_HW_1_3_VERSION, +		.name				= "ar6004 hw 1.3", +		.dataset_patch_addr		= 0x437860, +		.app_load_addr			= 0x1234, +		.board_ext_data_addr		= 0x437000, +		.reserved_ram_size		= 7168, +		.board_addr			= 0x436400, +		.refclk_hz                      = 40000000, +		.uarttx_pin                     = 11, +		.flags				= ATH6KL_HW_64BIT_RATES | +						  ATH6KL_HW_AP_INACTIVITY_MINS | +						  ATH6KL_HW_MAP_LP_ENDPOINT, + +		.fw = { +			.dir            = AR6004_HW_1_3_FW_DIR, +			.fw             = AR6004_HW_1_3_FIRMWARE_FILE, +		}, + +		.fw_board               = AR6004_HW_1_3_BOARD_DATA_FILE, +		.fw_default_board       = AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE, +	},  };  /* @@ -337,7 +361,7 @@ static int ath6kl_init_service_ep(struct ath6kl *ar)  	if (ath6kl_connectservice(ar, &connect, "WMI DATA BK"))  		return -EIO; -	/* connect to Video service, map this to to HI PRI */ +	/* connect to Video service, map this to HI PRI */  	connect.svc_id = WMI_DATA_VI_SVC;  	if (ath6kl_connectservice(ar, &connect, "WMI DATA VI"))  		return -EIO; @@ -1088,6 +1112,12 @@ int ath6kl_init_fetch_firmwares(struct ath6kl *ar)  	if (ret)  		return ret; +	ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API4_FILE); +	if (ret == 0) { +		ar->fw_api = 4; +		goto out; +	} +  	ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API3_FILE);  	if (ret == 0) {  		ar->fw_api = 3; @@ -1401,8 +1431,7 @@ static int ath6kl_init_upload(struct ath6kl *ar)  		return status;  	/* WAR to avoid SDIO CRC err */ -	if (ar->version.target_ver == AR6003_HW_2_0_VERSION || -	    ar->version.target_ver == AR6003_HW_2_1_1_VERSION) { +	if (ar->hw.flags & ATH6KL_HW_SDIO_CRC_ERROR_WAR) {  		ath6kl_err("temporary war to avoid sdio crc error\n");  		param = 0x28; @@ -1520,7 +1549,7 @@ static const char *ath6kl_init_get_hif_name(enum ath6kl_hif_type type)  	return NULL;  } -int ath6kl_init_hw_start(struct ath6kl *ar) +static int __ath6kl_init_hw_start(struct ath6kl *ar)  {  	long timeleft;  	int ret, i; @@ -1616,8 +1645,6 @@ int ath6kl_init_hw_start(struct ath6kl *ar)  			goto err_htc_stop;  	} -	ar->state = ATH6KL_STATE_ON; -  	return 0;  err_htc_stop: @@ -1630,7 +1657,18 @@ err_power_off:  	return ret;  } -int ath6kl_init_hw_stop(struct ath6kl *ar) +int ath6kl_init_hw_start(struct ath6kl *ar) +{ +	int err; + +	err = __ath6kl_init_hw_start(ar); +	if (err) +		return err; +	ar->state = ATH6KL_STATE_ON; +	return 0; +} + +static int __ath6kl_init_hw_stop(struct ath6kl *ar)  {  	int ret; @@ -1646,11 +1684,37 @@ int ath6kl_init_hw_stop(struct ath6kl *ar)  	if (ret)  		ath6kl_warn("failed to power off hif: %d\n", ret); -	ar->state = ATH6KL_STATE_OFF; +	return 0; +} +int ath6kl_init_hw_stop(struct ath6kl *ar) +{ +	int err; + +	err = __ath6kl_init_hw_stop(ar); +	if (err) +		return err; +	ar->state = ATH6KL_STATE_OFF;  	return 0;  } +void ath6kl_init_hw_restart(struct ath6kl *ar) +{ +	clear_bit(WMI_READY, &ar->flag); + +	ath6kl_cfg80211_stop_all(ar); + +	if (__ath6kl_init_hw_stop(ar)) { +		ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Failed to stop during fw error recovery\n"); +		return; +	} + +	if (__ath6kl_init_hw_start(ar)) { +		ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Failed to restart during fw error recovery\n"); +		return; +	} +} +  /* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */  void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready)  { diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index c189e28e86a..bd50b6b7b49 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -293,13 +293,17 @@ int ath6kl_read_fwlogs(struct ath6kl *ar)  	}  	address = TARG_VTOP(ar->target_type, debug_hdr_addr); -	ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr)); +	ret = ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr)); +	if (ret) +		goto out;  	address = TARG_VTOP(ar->target_type,  			    le32_to_cpu(debug_hdr.dbuf_addr));  	firstbuf = address;  	dropped = le32_to_cpu(debug_hdr.dropped); -	ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf)); +	ret = ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf)); +	if (ret) +		goto out;  	loop = 100; @@ -322,7 +326,8 @@ int ath6kl_read_fwlogs(struct ath6kl *ar)  		address = TARG_VTOP(ar->target_type,  				    le32_to_cpu(debug_buf.next)); -		ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf)); +		ret = ath6kl_diag_read(ar, address, &debug_buf, +				       sizeof(debug_buf));  		if (ret)  			goto out; @@ -436,12 +441,9 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel)  		break;  	} -	if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) { -		ar->want_ch_switch &= ~(1 << vif->fw_vif_idx); +	if (ar->last_ch != channel)  		/* we actually don't know the phymode, default to HT20 */ -		ath6kl_cfg80211_ch_switch_notify(vif, channel, -						 WMI_11G_HT20); -	} +		ath6kl_cfg80211_ch_switch_notify(vif, channel, WMI_11G_HT20);  	ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, NONE_BSS_FILTER, 0);  	set_bit(CONNECTED, &vif->flags); @@ -606,6 +608,18 @@ static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel)  	switch (vif->nw_type) {  	case AP_NETWORK: +		/* +		 * reconfigure any saved RSN IE capabilites in the beacon / +		 * probe response to stay in sync with the supplicant. +		 */ +		if (vif->rsn_capab && +		    test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE, +			     ar->fw_capabilities)) +			ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx, +					      WLAN_EID_RSN, WMI_RSN_IE_CAPB, +					      (const u8 *) &vif->rsn_capab, +					      sizeof(vif->rsn_capab)); +  		return ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx,  						    &vif->profile);  	default: @@ -628,6 +642,9 @@ static void ath6kl_check_ch_switch(struct ath6kl *ar, u16 channel)  		if (ar->want_ch_switch & (1 << vif->fw_vif_idx))  			res = ath6kl_commit_ch_switch(vif, channel); +		/* if channel switch failed, oh well we tried */ +		ar->want_ch_switch &= ~(1 << vif->fw_vif_idx); +  		if (res)  			ath6kl_err("channel switch failed nw_type %d res %d\n",  				   vif->nw_type, res); @@ -981,8 +998,25 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid,  	if (vif->nw_type == AP_NETWORK) {  		/* disconnect due to other STA vif switching channels */  		if (reason == BSS_DISCONNECTED && -		    prot_reason_status == WMI_AP_REASON_STA_ROAM) +		    prot_reason_status == WMI_AP_REASON_STA_ROAM) {  			ar->want_ch_switch |= 1 << vif->fw_vif_idx; +			/* bail back to this channel if STA vif fails connect */ +			ar->last_ch = le16_to_cpu(vif->profile.ch); +		} + +		if (prot_reason_status == WMI_AP_REASON_MAX_STA) { +			/* send max client reached notification to user space */ +			cfg80211_conn_failed(vif->ndev, bssid, +					     NL80211_CONN_FAIL_MAX_CLIENTS, +					     GFP_KERNEL); +		} + +		if (prot_reason_status == WMI_AP_REASON_ACL) { +			/* send blocked client notification to user space */ +			cfg80211_conn_failed(vif->ndev, bssid, +					     NL80211_CONN_FAIL_BLOCKED_CLIENT, +					     GFP_KERNEL); +		}  		if (!ath6kl_remove_sta(ar, bssid, prot_reason_status))  			return; @@ -1041,6 +1075,9 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid,  		}  	} +	/* restart disconnected concurrent vifs waiting for new channel */ +	ath6kl_check_ch_switch(ar, ar->last_ch); +  	/* update connect & link status atomically */  	spin_lock_bh(&vif->if_lock);  	clear_bit(CONNECTED, &vif->flags); diff --git a/drivers/net/wireless/ath/ath6kl/recovery.c b/drivers/net/wireless/ath/ath6kl/recovery.c new file mode 100644 index 00000000000..3a8d5e97dc8 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/recovery.c @@ -0,0 +1,160 @@ +/* + * 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 "core.h" +#include "cfg80211.h" +#include "debug.h" + +static void ath6kl_recovery_work(struct work_struct *work) +{ +	struct ath6kl *ar = container_of(work, struct ath6kl, +					 fw_recovery.recovery_work); + +	ar->state = ATH6KL_STATE_RECOVERY; + +	del_timer_sync(&ar->fw_recovery.hb_timer); + +	ath6kl_init_hw_restart(ar); + +	ar->state = ATH6KL_STATE_ON; +	clear_bit(WMI_CTRL_EP_FULL, &ar->flag); + +	ar->fw_recovery.err_reason = 0; + +	if (ar->fw_recovery.hb_poll) +		mod_timer(&ar->fw_recovery.hb_timer, jiffies + +			  msecs_to_jiffies(ar->fw_recovery.hb_poll)); +} + +void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason) +{ +	if (!ar->fw_recovery.enable) +		return; + +	ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Fw error detected, reason:%d\n", +		   reason); + +	set_bit(reason, &ar->fw_recovery.err_reason); + +	if (!test_bit(RECOVERY_CLEANUP, &ar->flag) && +	    ar->state != ATH6KL_STATE_RECOVERY) +		queue_work(ar->ath6kl_wq, &ar->fw_recovery.recovery_work); +} + +void ath6kl_recovery_hb_event(struct ath6kl *ar, u32 cookie) +{ +	if (cookie == ar->fw_recovery.seq_num) +		ar->fw_recovery.hb_pending = false; +} + +static void ath6kl_recovery_hb_timer(unsigned long data) +{ +	struct ath6kl *ar = (struct ath6kl *) data; +	int err; + +	if (test_bit(RECOVERY_CLEANUP, &ar->flag) || +	    (ar->state == ATH6KL_STATE_RECOVERY)) +		return; + +	if (ar->fw_recovery.hb_pending) +		ar->fw_recovery.hb_misscnt++; +	else +		ar->fw_recovery.hb_misscnt = 0; + +	if (ar->fw_recovery.hb_misscnt > ATH6KL_HB_RESP_MISS_THRES) { +		ar->fw_recovery.hb_misscnt = 0; +		ar->fw_recovery.seq_num = 0; +		ar->fw_recovery.hb_pending = false; +		ath6kl_recovery_err_notify(ar, ATH6KL_FW_HB_RESP_FAILURE); +		return; +	} + +	ar->fw_recovery.seq_num++; +	ar->fw_recovery.hb_pending = true; + +	err = ath6kl_wmi_get_challenge_resp_cmd(ar->wmi, +						ar->fw_recovery.seq_num, 0); +	if (err) +		ath6kl_warn("Failed to send hb challenge request, err:%d\n", +			    err); + +	mod_timer(&ar->fw_recovery.hb_timer, jiffies + +		  msecs_to_jiffies(ar->fw_recovery.hb_poll)); +} + +void ath6kl_recovery_init(struct ath6kl *ar) +{ +	struct ath6kl_fw_recovery *recovery = &ar->fw_recovery; + +	clear_bit(RECOVERY_CLEANUP, &ar->flag); +	INIT_WORK(&recovery->recovery_work, ath6kl_recovery_work); +	recovery->seq_num = 0; +	recovery->hb_misscnt = 0; +	ar->fw_recovery.hb_pending = false; +	ar->fw_recovery.hb_timer.function = ath6kl_recovery_hb_timer; +	ar->fw_recovery.hb_timer.data = (unsigned long) ar; +	init_timer_deferrable(&ar->fw_recovery.hb_timer); + +	if (ar->fw_recovery.hb_poll) +		mod_timer(&ar->fw_recovery.hb_timer, jiffies + +			  msecs_to_jiffies(ar->fw_recovery.hb_poll)); +} + +void ath6kl_recovery_cleanup(struct ath6kl *ar) +{ +	if (!ar->fw_recovery.enable) +		return; + +	set_bit(RECOVERY_CLEANUP, &ar->flag); + +	del_timer_sync(&ar->fw_recovery.hb_timer); +	cancel_work_sync(&ar->fw_recovery.recovery_work); +} + +void ath6kl_recovery_suspend(struct ath6kl *ar) +{ +	if (!ar->fw_recovery.enable) +		return; + +	ath6kl_recovery_cleanup(ar); + +	if (!ar->fw_recovery.err_reason) +		return; + +	/* Process pending fw error detection */ +	ar->fw_recovery.err_reason = 0; +	WARN_ON(ar->state != ATH6KL_STATE_ON); +	ar->state = ATH6KL_STATE_RECOVERY; +	ath6kl_init_hw_restart(ar); +	ar->state = ATH6KL_STATE_ON; +} + +void ath6kl_recovery_resume(struct ath6kl *ar) +{ +	if (!ar->fw_recovery.enable) +		return; + +	clear_bit(RECOVERY_CLEANUP, &ar->flag); + +	if (!ar->fw_recovery.hb_poll) +		return; + +	ar->fw_recovery.hb_pending = false; +	ar->fw_recovery.seq_num = 0; +	ar->fw_recovery.hb_misscnt = 0; +	mod_timer(&ar->fw_recovery.hb_timer, +		  jiffies + msecs_to_jiffies(ar->fw_recovery.hb_poll)); +} diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 05b95405f7b..d111980d44c 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -709,7 +709,7 @@ static int ath6kl_sdio_enable_scatter(struct ath6kl *ar)  {  	struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);  	struct htc_target *target = ar->htc_target; -	int ret; +	int ret = 0;  	bool virt_scat = false;  	if (ar_sdio->scatter_enabled) @@ -844,22 +844,6 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)  	bool try_deepsleep = false;  	int ret; -	if (ar->state == ATH6KL_STATE_SCHED_SCAN) { -		ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sched scan is in progress\n"); - -		ret = ath6kl_set_sdio_pm_caps(ar); -		if (ret) -			goto cut_pwr; - -		ret =  ath6kl_cfg80211_suspend(ar, -					       ATH6KL_CFG_SUSPEND_SCHED_SCAN, -					       NULL); -		if (ret) -			goto cut_pwr; - -		return 0; -	} -  	if (ar->suspend_mode == WLAN_POWER_STATE_WOW ||  	    (!ar->suspend_mode && wow)) { @@ -942,14 +926,14 @@ static int ath6kl_sdio_resume(struct ath6kl *ar)  	case ATH6KL_STATE_WOW:  		break; -	case ATH6KL_STATE_SCHED_SCAN: -		break; -  	case ATH6KL_STATE_SUSPENDING:  		break;  	case ATH6KL_STATE_RESUMING:  		break; + +	case ATH6KL_STATE_RECOVERY: +		break;  	}  	ath6kl_cfg80211_resume(ar); @@ -1462,3 +1446,6 @@ MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);  MODULE_FIRMWARE(AR6004_HW_1_2_FW_DIR "/" AR6004_HW_1_2_FIRMWARE_FILE);  MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE);  MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6004_HW_1_3_FW_DIR "/" AR6004_HW_1_3_FIRMWARE_FILE); +MODULE_FIRMWARE(AR6004_HW_1_3_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE); diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index 7dfa0fd86d7..78b36928657 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -288,8 +288,16 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb,  	int status = 0;  	struct ath6kl_cookie *cookie = NULL; -	if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW)) +	if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW)) { +		dev_kfree_skb(skb);  		return -EACCES; +	} + +	if (WARN_ON_ONCE(eid == ENDPOINT_UNUSED || +			 eid >= ENDPOINT_MAX)) { +		status = -EINVAL; +		goto fail_ctrl_tx; +	}  	spin_lock_bh(&ar->lock); @@ -591,6 +599,7 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,  		 */  		set_bit(WMI_CTRL_EP_FULL, &ar->flag);  		ath6kl_err("wmi ctrl ep is full\n"); +		ath6kl_recovery_err_notify(ar, ATH6KL_FW_EP_FULL);  		return action;  	} @@ -695,22 +704,31 @@ void ath6kl_tx_complete(struct htc_target *target,  					  list);  		list_del(&packet->list); +		if (WARN_ON_ONCE(packet->endpoint == ENDPOINT_UNUSED || +				 packet->endpoint >= ENDPOINT_MAX)) +			continue; +  		ath6kl_cookie = (struct ath6kl_cookie *)packet->pkt_cntxt; -		if (!ath6kl_cookie) -			goto fatal; +		if (WARN_ON_ONCE(!ath6kl_cookie)) +			continue;  		status = packet->status;  		skb = ath6kl_cookie->skb;  		eid = packet->endpoint;  		map_no = ath6kl_cookie->map_no; -		if (!skb || !skb->data) -			goto fatal; +		if (WARN_ON_ONCE(!skb || !skb->data)) { +			dev_kfree_skb(skb); +			ath6kl_free_cookie(ar, ath6kl_cookie); +			continue; +		}  		__skb_queue_tail(&skb_queue, skb); -		if (!status && (packet->act_len != skb->len)) -			goto fatal; +		if (WARN_ON_ONCE(!status && (packet->act_len != skb->len))) { +			ath6kl_free_cookie(ar, ath6kl_cookie); +			continue; +		}  		ar->tx_pending[eid]--; @@ -792,11 +810,6 @@ void ath6kl_tx_complete(struct htc_target *target,  		wake_up(&ar->event_wq);  	return; - -fatal: -	WARN_ON(1); -	spin_unlock_bh(&ar->lock); -	return;  }  void ath6kl_tx_data_cleanup(struct ath6kl *ar) @@ -885,8 +898,11 @@ void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint)  			break;  		packet = (struct htc_packet *) skb->head; -		if (!IS_ALIGNED((unsigned long) skb->data, 4)) +		if (!IS_ALIGNED((unsigned long) skb->data, 4)) { +			size_t len = skb_headlen(skb);  			skb->data = PTR_ALIGN(skb->data - 4, 4); +			skb_set_tail_pointer(skb, len); +		}  		set_htc_rxpkt_info(packet, skb, skb->data,  				   ATH6KL_BUFFER_SIZE, endpoint);  		packet->skb = skb; @@ -908,8 +924,11 @@ void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count)  			return;  		packet = (struct htc_packet *) skb->head; -		if (!IS_ALIGNED((unsigned long) skb->data, 4)) +		if (!IS_ALIGNED((unsigned long) skb->data, 4)) { +			size_t len = skb_headlen(skb);  			skb->data = PTR_ALIGN(skb->data - 4, 4); +			skb_set_tail_pointer(skb, len); +		}  		set_htc_rxpkt_info(packet, skb, skb->data,  				   ATH6KL_AMSDU_BUFFER_SIZE, 0);  		packet->skb = skb; diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index 3740c3d6ab8..62bcc0d5bc2 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -185,9 +185,10 @@ static int ath6kl_usb_alloc_pipe_resources(struct ath6kl_usb_pipe *pipe,  	for (i = 0; i < urb_cnt; i++) {  		urb_context = kzalloc(sizeof(struct ath6kl_urb_context),  				      GFP_KERNEL); -		if (urb_context == NULL) -			/* FIXME: set status to -ENOMEM */ -			break; +		if (urb_context == NULL) { +			status = -ENOMEM; +			goto fail_alloc_pipe_resources; +		}  		urb_context->pipe = pipe; @@ -204,6 +205,7 @@ static int ath6kl_usb_alloc_pipe_resources(struct ath6kl_usb_pipe *pipe,  		   pipe->logical_pipe_num, pipe->usb_pipe_handle,  		   pipe->urb_alloc); +fail_alloc_pipe_resources:  	return status;  } @@ -803,7 +805,11 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id,  		*dl_pipe = ATH6KL_USB_PIPE_RX_DATA;  		break;  	case WMI_DATA_VI_SVC: -		*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP; + +		if (ar->hw.flags & ATH6KL_HW_MAP_LP_ENDPOINT) +			*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP; +		else +			*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP;  		/*  		* Disable rxdata2 directly, it will be enabled  		* if FW enable rxdata2 @@ -811,7 +817,11 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id,  		*dl_pipe = ATH6KL_USB_PIPE_RX_DATA;  		break;  	case WMI_DATA_VO_SVC: -		*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_HP; + +		if (ar->hw.flags & ATH6KL_HW_MAP_LP_ENDPOINT) +			*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP; +		else +			*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP;  		/*  		* Disable rxdata2 directly, it will be enabled  		* if FW enable rxdata2 @@ -1196,7 +1206,14 @@ static struct usb_driver ath6kl_usb_driver = {  static int ath6kl_usb_init(void)  { -	usb_register(&ath6kl_usb_driver); +	int ret; + +	ret = usb_register(&ath6kl_usb_driver); +	if (ret) { +		ath6kl_err("usb registration failed: %d\n", ret); +		return ret; +	} +  	return 0;  } @@ -1220,3 +1237,6 @@ MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);  MODULE_FIRMWARE(AR6004_HW_1_2_FIRMWARE_FILE);  MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE);  MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6004_HW_1_3_FW_DIR "/" AR6004_HW_1_3_FIRMWARE_FILE); +MODULE_FIRMWARE(AR6004_HW_1_3_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index c30ab4b11d6..55ccf977033 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -936,8 +936,12 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len)  		regpair = ath6kl_get_regpair((u16) reg_code);  		country = ath6kl_regd_find_country_by_rd((u16) reg_code); -		ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n", -			   regpair->regDmnEnum); +		if (regpair) +			ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n", +				   regpair->regDmnEnum); +		else +			ath6kl_warn("Regpair not found reg_code 0x%0x\n", +				    reg_code);  	}  	if (country && wmi->parent_dev->wiphy_registered) { @@ -1116,7 +1120,7 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,  	 * the timer would not ever fire if the scan interval is short  	 * enough.  	 */ -	if (ar->state == ATH6KL_STATE_SCHED_SCAN && +	if (test_bit(SCHED_SCANNING, &vif->flags) &&  	    !timer_pending(&vif->sched_scan_timer)) {  		mod_timer(&vif->sched_scan_timer, jiffies +  			  msecs_to_jiffies(ATH6KL_SCHED_SCAN_RESULT_DELAY)); @@ -1170,6 +1174,9 @@ static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len)  		rate = RATE_AUTO;  	} else {  		index = reply->rate_index & 0x7f; +		if (WARN_ON_ONCE(index > (RATE_MCS_7_40 + 1))) +			return -EINVAL; +  		sgi = (reply->rate_index & 0x80) ? 1 : 0;  		rate = wmi_rate_tbl[index][sgi];  	} @@ -1531,6 +1538,68 @@ static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len,  	return 0;  } +static int ath6kl_wmi_txe_notify_event_rx(struct wmi *wmi, u8 *datap, int len, +					  struct ath6kl_vif *vif) +{ +	struct wmi_txe_notify_event *ev; +	u32 rate, pkts; + +	if (len < sizeof(*ev)) +		return -EINVAL; + +	if (vif->sme_state != SME_CONNECTED) +		return -ENOTCONN; + +	ev = (struct wmi_txe_notify_event *) datap; +	rate = le32_to_cpu(ev->rate); +	pkts = le32_to_cpu(ev->pkts); + +	ath6kl_dbg(ATH6KL_DBG_WMI, "TXE notify event: peer %pM rate %d% pkts %d intvl %ds\n", +		   vif->bssid, rate, pkts, vif->txe_intvl); + +	cfg80211_cqm_txe_notify(vif->ndev, vif->bssid, pkts, +				rate, vif->txe_intvl, GFP_KERNEL); + +	return 0; +} + +int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx, +			      u32 rate, u32 pkts, u32 intvl) +{ +	struct sk_buff *skb; +	struct wmi_txe_notify_cmd *cmd; + +	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); +	if (!skb) +		return -ENOMEM; + +	cmd = (struct wmi_txe_notify_cmd *) skb->data; +	cmd->rate = cpu_to_le32(rate); +	cmd->pkts = cpu_to_le32(pkts); +	cmd->intvl = cpu_to_le32(intvl); + +	return ath6kl_wmi_cmd_send(wmi, idx, skb, WMI_SET_TXE_NOTIFY_CMDID, +				   NO_SYNC_WMIFLAG); +} + +int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi) +{ +	struct sk_buff *skb; +	struct wmi_set_rssi_filter_cmd *cmd; +	int ret; + +	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); +	if (!skb) +		return -ENOMEM; + +	cmd = (struct wmi_set_rssi_filter_cmd *) skb->data; +	cmd->rssi = rssi; + +	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_RSSI_FILTER_CMDID, +				  NO_SYNC_WMIFLAG); +	return ret; +} +  static int ath6kl_wmi_send_snr_threshold_params(struct wmi *wmi,  			struct wmi_snr_threshold_params_cmd *snr_cmd)  { @@ -1677,8 +1746,11 @@ int ath6kl_wmi_cmd_send(struct wmi *wmi, u8 if_idx, struct sk_buff *skb,  	int ret;  	u16 info1; -	if (WARN_ON(skb == NULL || (if_idx > (wmi->parent_dev->vif_max - 1)))) +	if (WARN_ON(skb == NULL || +		    (if_idx > (wmi->parent_dev->vif_max - 1)))) { +		dev_kfree_skb(skb);  		return -EINVAL; +	}  	ath6kl_dbg(ATH6KL_DBG_WMI, "wmi tx id %d len %d flag %d\n",  		   cmd_id, skb->len, sync_flag); @@ -1833,6 +1905,59 @@ int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx)  	return ret;  } +/* ath6kl_wmi_start_scan_cmd is to be deprecated. Use + * ath6kl_wmi_begin_scan_cmd instead. The new function supports P2P + * mgmt operations using station interface. + */ +static int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx, +				    enum wmi_scan_type scan_type, +				    u32 force_fgscan, u32 is_legacy, +				    u32 home_dwell_time, +				    u32 force_scan_interval, +				    s8 num_chan, u16 *ch_list) +{ +	struct sk_buff *skb; +	struct wmi_start_scan_cmd *sc; +	s8 size; +	int i, ret; + +	size = sizeof(struct wmi_start_scan_cmd); + +	if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN)) +		return -EINVAL; + +	if (num_chan > WMI_MAX_CHANNELS) +		return -EINVAL; + +	if (num_chan) +		size += sizeof(u16) * (num_chan - 1); + +	skb = ath6kl_wmi_get_new_buf(size); +	if (!skb) +		return -ENOMEM; + +	sc = (struct wmi_start_scan_cmd *) skb->data; +	sc->scan_type = scan_type; +	sc->force_fg_scan = cpu_to_le32(force_fgscan); +	sc->is_legacy = cpu_to_le32(is_legacy); +	sc->home_dwell_time = cpu_to_le32(home_dwell_time); +	sc->force_scan_intvl = cpu_to_le32(force_scan_interval); +	sc->num_ch = num_chan; + +	for (i = 0; i < num_chan; i++) +		sc->ch_list[i] = cpu_to_le16(ch_list[i]); + +	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_START_SCAN_CMDID, +				  NO_SYNC_WMIFLAG); + +	return ret; +} + +/* + * beginscan supports (compared to old startscan) P2P mgmt operations using + * station interface, send additional information like supported rates to + * advertise and xmit rates for probe requests + */  int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,  			     enum wmi_scan_type scan_type,  			     u32 force_fgscan, u32 is_legacy, @@ -1848,6 +1973,15 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,  	int num_rates;  	u32 ratemask; +	if (!test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, +		      ar->fw_capabilities)) { +		return ath6kl_wmi_startscan_cmd(wmi, if_idx, +						scan_type, force_fgscan, +						is_legacy, home_dwell_time, +						force_scan_interval, +						num_chan, ch_list); +	} +  	size = sizeof(struct wmi_begin_scan_cmd);  	if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN)) @@ -1900,50 +2034,24 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,  	return ret;  } -/* ath6kl_wmi_start_scan_cmd is to be deprecated. Use - * ath6kl_wmi_begin_scan_cmd instead. The new function supports P2P - * mgmt operations using station interface. - */ -int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx, -			     enum wmi_scan_type scan_type, -			     u32 force_fgscan, u32 is_legacy, -			     u32 home_dwell_time, u32 force_scan_interval, -			     s8 num_chan, u16 *ch_list) +int ath6kl_wmi_enable_sched_scan_cmd(struct wmi *wmi, u8 if_idx, bool enable)  {  	struct sk_buff *skb; -	struct wmi_start_scan_cmd *sc; -	s8 size; -	int i, ret; - -	size = sizeof(struct wmi_start_scan_cmd); - -	if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN)) -		return -EINVAL; - -	if (num_chan > WMI_MAX_CHANNELS) -		return -EINVAL; - -	if (num_chan) -		size += sizeof(u16) * (num_chan - 1); +	struct wmi_enable_sched_scan_cmd *sc; +	int ret; -	skb = ath6kl_wmi_get_new_buf(size); +	skb = ath6kl_wmi_get_new_buf(sizeof(*sc));  	if (!skb)  		return -ENOMEM; -	sc = (struct wmi_start_scan_cmd *) skb->data; -	sc->scan_type = scan_type; -	sc->force_fg_scan = cpu_to_le32(force_fgscan); -	sc->is_legacy = cpu_to_le32(is_legacy); -	sc->home_dwell_time = cpu_to_le32(home_dwell_time); -	sc->force_scan_intvl = cpu_to_le32(force_scan_interval); -	sc->num_ch = num_chan; - -	for (i = 0; i < num_chan; i++) -		sc->ch_list[i] = cpu_to_le16(ch_list[i]); +	ath6kl_dbg(ATH6KL_DBG_WMI, "%s scheduled scan on vif %d\n", +		   enable ? "enabling" : "disabling", if_idx); +	sc = (struct wmi_enable_sched_scan_cmd *) skb->data; +	sc->enable = enable ? 1 : 0; -	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_START_SCAN_CMDID, +	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, +				  WMI_ENABLE_SCHED_SCAN_CMDID,  				  NO_SYNC_WMIFLAG); -  	return ret;  } @@ -2275,8 +2383,10 @@ static int ath6kl_wmi_data_sync_send(struct wmi *wmi, struct sk_buff *skb,  	struct wmi_data_hdr *data_hdr;  	int ret; -	if (WARN_ON(skb == NULL || ep_id == wmi->ep_id)) +	if (WARN_ON(skb == NULL || ep_id == wmi->ep_id)) { +		dev_kfree_skb(skb);  		return -EINVAL; +	}  	skb_push(skb, sizeof(struct wmi_data_hdr)); @@ -2313,10 +2423,8 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx)  	spin_unlock_bh(&wmi->lock);  	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); -	if (!skb) { -		ret = -ENOMEM; -		goto free_skb; -	} +	if (!skb) +		return -ENOMEM;  	cmd = (struct wmi_sync_cmd *) skb->data; @@ -2339,7 +2447,7 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx)  	 * then do not send the Synchronize cmd on the control ep  	 */  	if (ret) -		goto free_skb; +		goto free_cmd_skb;  	/*  	 * Send sync cmd followed by sync data messages on all @@ -2349,15 +2457,12 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx)  				  NO_SYNC_WMIFLAG);  	if (ret) -		goto free_skb; - -	/* cmd buffer sent, we no longer own it */ -	skb = NULL; +		goto free_data_skb;  	for (index = 0; index < num_pri_streams; index++) {  		if (WARN_ON(!data_sync_bufs[index].skb)) -			break; +			goto free_data_skb;  		ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev,  					       data_sync_bufs[index]. @@ -2366,17 +2471,20 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx)  		    ath6kl_wmi_data_sync_send(wmi, data_sync_bufs[index].skb,  					      ep_id, if_idx); -		if (ret) -			break; -  		data_sync_bufs[index].skb = NULL; + +		if (ret) +			goto free_data_skb;  	} -free_skb: +	return 0; + +free_cmd_skb:  	/* free up any resources left over (possibly due to an error) */  	if (skb)  		dev_kfree_skb(skb); +free_data_skb:  	for (index = 0; index < num_pri_streams; index++) {  		if (data_sync_bufs[index].skb != NULL) {  			dev_kfree_skb((struct sk_buff *)data_sync_bufs[index]. @@ -2618,11 +2726,13 @@ static int ath6kl_set_bitrate_mask64(struct wmi *wmi, u8 if_idx,  {  	struct sk_buff *skb;  	int ret, mode, band; -	u64 mcsrate, ratemask[IEEE80211_NUM_BANDS]; +	u64 mcsrate, ratemask[ATH6KL_NUM_BANDS];  	struct wmi_set_tx_select_rates64_cmd *cmd;  	memset(&ratemask, 0, sizeof(ratemask)); -	for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + +	/* only check 2.4 and 5 GHz bands, skip the rest */ +	for (band = 0; band <= IEEE80211_BAND_5GHZ; band++) {  		/* copy legacy rate mask */  		ratemask[band] = mask->control[band].legacy;  		if (band == IEEE80211_BAND_5GHZ) @@ -2668,11 +2778,13 @@ static int ath6kl_set_bitrate_mask32(struct wmi *wmi, u8 if_idx,  {  	struct sk_buff *skb;  	int ret, mode, band; -	u32 mcsrate, ratemask[IEEE80211_NUM_BANDS]; +	u32 mcsrate, ratemask[ATH6KL_NUM_BANDS];  	struct wmi_set_tx_select_rates32_cmd *cmd;  	memset(&ratemask, 0, sizeof(ratemask)); -	for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + +	/* only check 2.4 and 5 GHz bands, skip the rest */ +	for (band = 0; band <= IEEE80211_BAND_5GHZ; band++) {  		/* copy legacy rate mask */  		ratemask[band] = mask->control[band].legacy;  		if (band == IEEE80211_BAND_5GHZ) @@ -2716,7 +2828,7 @@ int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx,  {  	struct ath6kl *ar = wmi->parent_dev; -	if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES) +	if (ar->hw.flags & ATH6KL_HW_64BIT_RATES)  		return ath6kl_set_bitrate_mask64(wmi, if_idx, mask);  	else  		return ath6kl_set_bitrate_mask32(wmi, if_idx, mask); @@ -3139,12 +3251,40 @@ int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enhance)  	return ret;  } +int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2) +{ +	struct sk_buff *skb; +	struct wmi_set_regdomain_cmd *cmd; + +	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); +	if (!skb) +		return -ENOMEM; + +	cmd = (struct wmi_set_regdomain_cmd *) skb->data; +	memcpy(cmd->iso_name, alpha2, 2); + +	return ath6kl_wmi_cmd_send(wmi, 0, skb, +				   WMI_SET_REGDOMAIN_CMDID, +				   NO_SYNC_WMIFLAG); +} +  s32 ath6kl_wmi_get_rate(s8 rate_index)  { +	u8 sgi = 0; +  	if (rate_index == RATE_AUTO)  		return 0; -	return wmi_rate_tbl[(u32) rate_index][0]; +	/* SGI is stored as the MSB of the rate_index */ +	if (rate_index & RATE_INDEX_MSB) { +		rate_index &= RATE_INDEX_WITHOUT_SGI_MASK; +		sgi = 1; +	} + +	if (WARN_ON(rate_index > RATE_MCS_7_40)) +		rate_index = RATE_MCS_7_40; + +	return wmi_rate_tbl[(u32) rate_index][sgi];  }  static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap, @@ -3634,6 +3774,19 @@ int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout)  				   NO_SYNC_WMIFLAG);  } +static void ath6kl_wmi_hb_challenge_resp_event(struct wmi *wmi, u8 *datap, +					       int len) +{ +	struct wmix_hb_challenge_resp_cmd *cmd; + +	if (len < sizeof(struct wmix_hb_challenge_resp_cmd)) +		return; + +	cmd = (struct wmix_hb_challenge_resp_cmd *) datap; +	ath6kl_recovery_hb_event(wmi->parent_dev, +				 le32_to_cpu(cmd->cookie)); +} +  static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb)  {  	struct wmix_cmd_hdr *cmd; @@ -3658,6 +3811,7 @@ static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb)  	switch (id) {  	case WMIX_HB_CHALLENGE_RESP_EVENTID:  		ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event hb challenge resp\n"); +		ath6kl_wmi_hb_challenge_resp_event(wmi, datap, len);  		break;  	case WMIX_DBGLOG_EVENTID:  		ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event dbglog len %d\n", len); @@ -3750,6 +3904,9 @@ static int ath6kl_wmi_proc_events_vif(struct wmi *wmi, u16 if_idx, u16 cmd_id,  	case WMI_RX_ACTION_EVENTID:  		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n");  		return ath6kl_wmi_rx_action_event_rx(wmi, datap, len, vif); +	case WMI_TXE_NOTIFY_EVENTID: +		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TXE_NOTIFY_EVENTID\n"); +		return ath6kl_wmi_txe_notify_event_rx(wmi, datap, len, vif);  	default:  		ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", cmd_id);  		return -EINVAL; diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 43339aca585..98b1755e67f 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -48,7 +48,7 @@  #define A_BAND_24GHZ           0  #define A_BAND_5GHZ            1 -#define A_NUM_BANDS            2 +#define ATH6KL_NUM_BANDS       2  /* in ms */  #define WMI_IMPLICIT_PSTREAM_INACTIVITY_INT 5000 @@ -628,6 +628,20 @@ enum wmi_cmd_id {  	WMI_SET_MCASTRATE,  	WMI_STA_BMISS_ENHANCE_CMDID, + +	WMI_SET_REGDOMAIN_CMDID, + +	WMI_SET_RSSI_FILTER_CMDID, + +	WMI_SET_KEEP_ALIVE_EXT, + +	WMI_VOICE_DETECTION_ENABLE_CMDID, + +	WMI_SET_TXE_NOTIFY_CMDID, + +	WMI_SET_RECOVERY_TEST_PARAMETER_CMDID, /*0xf094*/ + +	WMI_ENABLE_SCHED_SCAN_CMDID,  };  enum wmi_mgmt_frame_type { @@ -843,7 +857,7 @@ struct wmi_begin_scan_cmd {  	u8 scan_type;  	/* Supported rates to advertise in the probe request frames */ -	struct wmi_supp_rates supp_rates[IEEE80211_NUM_BANDS]; +	struct wmi_supp_rates supp_rates[ATH6KL_NUM_BANDS];  	/* how many channels follow */  	u8 num_ch; @@ -941,6 +955,11 @@ struct wmi_scan_params_cmd {  	__le32 max_dfsch_act_time;  } __packed; +/* WMI_ENABLE_SCHED_SCAN_CMDID */ +struct wmi_enable_sched_scan_cmd { +	u8 enable; +} __packed; +  /* WMI_SET_BSS_FILTER_CMDID */  enum wmi_bss_filter {  	/* no beacons forwarded */ @@ -1032,6 +1051,11 @@ struct wmi_sta_bmiss_enhance_cmd {  	u8 enable;  } __packed; +struct wmi_set_regdomain_cmd { +	u8 length; +	u8 iso_name[2]; +} __packed; +  /* WMI_SET_POWER_MODE_CMDID */  enum wmi_power_mode {  	REC_POWER = 0x01, @@ -1276,6 +1300,11 @@ struct wmi_snr_threshold_params_cmd {  	u8 reserved[3];  } __packed; +/* Don't report BSSs with signal (RSSI) below this threshold */ +struct wmi_set_rssi_filter_cmd { +	s8 rssi; +} __packed; +  enum wmi_preamble_policy {  	WMI_IGNORE_BARKER_IN_ERP = 0,  	WMI_FOLLOW_BARKER_IN_ERP, @@ -1455,6 +1484,20 @@ enum wmi_event_id {  	WMI_P2P_CAPABILITIES_EVENTID,  	WMI_RX_ACTION_EVENTID,  	WMI_P2P_INFO_EVENTID, + +	/* WPS Events */ +	WMI_WPS_GET_STATUS_EVENTID, +	WMI_WPS_PROFILE_EVENTID, + +	/* more P2P events */ +	WMI_NOA_INFO_EVENTID, +	WMI_OPPPS_INFO_EVENTID, +	WMI_PORT_STATUS_EVENTID, + +	/* 802.11w */ +	WMI_GET_RSN_CAP_EVENTID, + +	WMI_TXE_NOTIFY_EVENTID,  };  struct wmi_ready_event_2 { @@ -1749,6 +1792,9 @@ struct rx_stats {  	a_sle32 ucast_rate;  } __packed; +#define RATE_INDEX_WITHOUT_SGI_MASK     0x7f +#define RATE_INDEX_MSB     0x80 +  struct tkip_ccmp_stats {  	__le32 tkip_local_mic_fail;  	__le32 tkip_cnter_measures_invoked; @@ -2019,7 +2065,6 @@ struct wmi_set_ie_cmd {  #define WOW_MAX_FILTERS_PER_LIST 4  #define WOW_PATTERN_SIZE	 64 -#define WOW_MASK_SIZE		 64  #define MAC_MAX_FILTERS_PER_LIST 4 @@ -2028,7 +2073,7 @@ struct wow_filter {  	u8 wow_filter_id;  	u8 wow_filter_size;  	u8 wow_filter_offset; -	u8 wow_filter_mask[WOW_MASK_SIZE]; +	u8 wow_filter_mask[WOW_PATTERN_SIZE];  	u8 wow_filter_pattern[WOW_PATTERN_SIZE];  } __packed; @@ -2087,6 +2132,19 @@ struct wmi_del_wow_pattern_cmd {  	__le16 filter_id;  } __packed; +/* WMI_SET_TXE_NOTIFY_CMDID */ +struct wmi_txe_notify_cmd { +	__le32 rate; +	__le32 pkts; +	__le32 intvl; +} __packed; + +/* WMI_TXE_NOTIFY_EVENTID */ +struct wmi_txe_notify_event { +	__le32 rate; +	__le32 pkts; +} __packed; +  /* WMI_SET_AKMP_PARAMS_CMD */  struct wmi_pmkid { @@ -2505,11 +2563,6 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, u8 if_idx,  int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 if_idx, u8 *bssid,  			     u16 channel);  int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx); -int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx, -			     enum wmi_scan_type scan_type, -			     u32 force_fgscan, u32 is_legacy, -			     u32 home_dwell_time, u32 force_scan_interval, -			     s8 num_chan, u16 *ch_list);  int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,  			     enum wmi_scan_type scan_type, @@ -2517,6 +2570,7 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,  			     u32 home_dwell_time, u32 force_scan_interval,  			     s8 num_chan, u16 *ch_list, u32 no_cck,  			     u32 *rates); +int ath6kl_wmi_enable_sched_scan_cmd(struct wmi *wmi, u8 if_idx, bool enable);  int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u8 if_idx, u16 fg_start_sec,  			      u16 fg_end_sec, u16 bg_sec, @@ -2592,6 +2646,7 @@ int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,  				   const u8 *mask);  int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,  				   u16 list_id, u16 filter_id); +int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi);  int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi);  int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period);  int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid); @@ -2600,6 +2655,9 @@ int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on);  int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx,  					u8 *filter, bool add_filter);  int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enable); +int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx, +			      u32 rate, u32 pkts, u32 intvl); +int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2);  /* AP mode uAPSD */  int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable); @@ -2658,6 +2716,8 @@ int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout);  void ath6kl_wmi_sscan_timer(unsigned long ptr); +int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source); +  struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx);  void *ath6kl_wmi_init(struct ath6kl *devt);  void ath6kl_wmi_shutdown(struct wmi *wmi);  |