Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Conflicts: drivers/net/wireless/iwlwifi/dvm/tx.c drivers/net/wireless/ti/wlcore/sdio.c drivers/net/wireless/ti/wlcore/spi.c
This commit is contained in:
		
				commit
				
					
						98d5fac233
					
				
			
		
					 189 changed files with 12404 additions and 3253 deletions
				
			
		|  | @ -309,7 +309,7 @@ static struct omap2_hsmmc_info mmc[] = { | ||||||
| 		.gpio_wp	= 63, | 		.gpio_wp	= 63, | ||||||
| 		.deferred	= true, | 		.deferred	= true, | ||||||
| 	}, | 	}, | ||||||
| #ifdef CONFIG_WL12XX_PLATFORM_DATA | #ifdef CONFIG_WILINK_PLATFORM_DATA | ||||||
| 	{ | 	{ | ||||||
| 		.name		= "wl1271", | 		.name		= "wl1271", | ||||||
| 		.mmc		= 2, | 		.mmc		= 2, | ||||||
|  | @ -450,7 +450,7 @@ static struct regulator_init_data omap3evm_vio = { | ||||||
| 	.consumer_supplies	= omap3evm_vio_supply, | 	.consumer_supplies	= omap3evm_vio_supply, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_WL12XX_PLATFORM_DATA | #ifdef CONFIG_WILINK_PLATFORM_DATA | ||||||
| 
 | 
 | ||||||
| #define OMAP3EVM_WLAN_PMENA_GPIO	(150) | #define OMAP3EVM_WLAN_PMENA_GPIO	(150) | ||||||
| #define OMAP3EVM_WLAN_IRQ_GPIO		(149) | #define OMAP3EVM_WLAN_IRQ_GPIO		(149) | ||||||
|  | @ -563,7 +563,7 @@ static struct omap_board_mux omap35x_board_mux[] __initdata = { | ||||||
| 				OMAP_PIN_OFF_NONE), | 				OMAP_PIN_OFF_NONE), | ||||||
| 	OMAP3_MUX(GPMC_WAIT2, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP | | 	OMAP3_MUX(GPMC_WAIT2, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP | | ||||||
| 				OMAP_PIN_OFF_NONE), | 				OMAP_PIN_OFF_NONE), | ||||||
| #ifdef CONFIG_WL12XX_PLATFORM_DATA | #ifdef CONFIG_WILINK_PLATFORM_DATA | ||||||
| 	/* WLAN IRQ - GPIO 149 */ | 	/* WLAN IRQ - GPIO 149 */ | ||||||
| 	OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT), | 	OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT), | ||||||
| 
 | 
 | ||||||
|  | @ -601,7 +601,7 @@ static struct omap_board_mux omap36x_board_mux[] __initdata = { | ||||||
| 	OMAP3_MUX(SYS_BOOT4, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), | 	OMAP3_MUX(SYS_BOOT4, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), | ||||||
| 	OMAP3_MUX(SYS_BOOT5, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), | 	OMAP3_MUX(SYS_BOOT5, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), | ||||||
| 	OMAP3_MUX(SYS_BOOT6, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), | 	OMAP3_MUX(SYS_BOOT6, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), | ||||||
| #ifdef CONFIG_WL12XX_PLATFORM_DATA | #ifdef CONFIG_WILINK_PLATFORM_DATA | ||||||
| 	/* WLAN IRQ - GPIO 149 */ | 	/* WLAN IRQ - GPIO 149 */ | ||||||
| 	OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT), | 	OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT), | ||||||
| 
 | 
 | ||||||
|  | @ -637,7 +637,7 @@ static struct gpio omap3_evm_ehci_gpios[] __initdata = { | ||||||
| 
 | 
 | ||||||
| static void __init omap3_evm_wl12xx_init(void) | static void __init omap3_evm_wl12xx_init(void) | ||||||
| { | { | ||||||
| #ifdef CONFIG_WL12XX_PLATFORM_DATA | #ifdef CONFIG_WILINK_PLATFORM_DATA | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	/* WL12xx WLAN Init */ | 	/* WL12xx WLAN Init */ | ||||||
|  |  | ||||||
|  | @ -1613,6 +1613,10 @@ ath5k_hw_update_noise_floor(struct ath5k_hw *ah) | ||||||
| 	ah->ah_cal_mask |= AR5K_CALIBRATION_NF; | 	ah->ah_cal_mask |= AR5K_CALIBRATION_NF; | ||||||
| 
 | 
 | ||||||
| 	ee_mode = ath5k_eeprom_mode_from_channel(ah->ah_current_channel); | 	ee_mode = ath5k_eeprom_mode_from_channel(ah->ah_current_channel); | ||||||
|  | 	if (WARN_ON(ee_mode < 0)) { | ||||||
|  | 		ah->ah_cal_mask &= ~AR5K_CALIBRATION_NF; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	/* completed NF calibration, test threshold */ | 	/* completed NF calibration, test threshold */ | ||||||
| 	nf = ath5k_hw_read_measured_noise_floor(ah); | 	nf = ath5k_hw_read_measured_noise_floor(ah); | ||||||
|  |  | ||||||
|  | @ -985,6 +985,8 @@ ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	ee_mode = ath5k_eeprom_mode_from_channel(channel); | 	ee_mode = ath5k_eeprom_mode_from_channel(channel); | ||||||
|  | 	if (WARN_ON(ee_mode < 0)) | ||||||
|  | 		return; | ||||||
| 
 | 
 | ||||||
| 	/* Adjust power delta for channel 14 */ | 	/* Adjust power delta for channel 14 */ | ||||||
| 	if (channel->center_freq == 2484) | 	if (channel->center_freq == 2484) | ||||||
|  |  | ||||||
|  | @ -427,6 +427,30 @@ static bool ath6kl_is_tx_pending(struct ath6kl *ar) | ||||||
| 	return ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0; | 	return ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, | ||||||
|  | 					      bool enable) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  | 
 | ||||||
|  | 	if (WARN_ON(!test_bit(WMI_READY, &vif->ar->flag))) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	if (vif->nw_type != INFRA_NETWORK) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	if (!test_bit(ATH6KL_FW_CAPABILITY_BMISS_ENHANCE, | ||||||
|  | 		      vif->ar->fw_capabilities)) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s fw bmiss enhance\n", | ||||||
|  | 		   enable ? "enable" : "disable"); | ||||||
|  | 
 | ||||||
|  | 	err = ath6kl_wmi_sta_bmiss_enhance_cmd(vif->ar->wmi, | ||||||
|  | 					       vif->fw_vif_idx, enable); | ||||||
|  | 	if (err) | ||||||
|  | 		ath6kl_err("failed to %s enhanced bmiss detection: %d\n", | ||||||
|  | 			   enable ? "enable" : "disable", err); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | ||||||
| 				   struct cfg80211_connect_params *sme) | 				   struct cfg80211_connect_params *sme) | ||||||
|  | @ -616,13 +640,13 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | ||||||
| 					vif->req_bssid, vif->ch_hint, | 					vif->req_bssid, vif->ch_hint, | ||||||
| 					ar->connect_ctrl_flags, nw_subtype); | 					ar->connect_ctrl_flags, nw_subtype); | ||||||
| 
 | 
 | ||||||
|  | 	if (sme->bg_scan_period == 0) { | ||||||
| 		/* disable background scan if period is 0 */ | 		/* disable background scan if period is 0 */ | ||||||
| 	if (sme->bg_scan_period == 0) |  | ||||||
| 		sme->bg_scan_period = 0xffff; | 		sme->bg_scan_period = 0xffff; | ||||||
| 
 | 	} else if (sme->bg_scan_period == -1) { | ||||||
| 		/* configure default value if not specified */ | 		/* configure default value if not specified */ | ||||||
| 	if (sme->bg_scan_period == -1) |  | ||||||
| 		sme->bg_scan_period = DEFAULT_BG_SCAN_PERIOD; | 		sme->bg_scan_period = DEFAULT_BG_SCAN_PERIOD; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0, | 	ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0, | ||||||
| 				  sme->bg_scan_period, 0, 0, 0, 3, 0, 0, 0); | 				  sme->bg_scan_period, 0, 0, 0, 3, 0, 0, 0); | ||||||
|  | @ -767,7 +791,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, | ||||||
| 		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n", | 		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n", | ||||||
| 			   nw_type & ADHOC_CREATOR ? "creator" : "joiner"); | 			   nw_type & ADHOC_CREATOR ? "creator" : "joiner"); | ||||||
| 		cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL); | 		cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL); | ||||||
| 		cfg80211_put_bss(bss); | 		cfg80211_put_bss(ar->wiphy, bss); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -778,7 +802,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, | ||||||
| 					assoc_req_ie, assoc_req_len, | 					assoc_req_ie, assoc_req_len, | ||||||
| 					assoc_resp_ie, assoc_resp_len, | 					assoc_resp_ie, assoc_resp_len, | ||||||
| 					WLAN_STATUS_SUCCESS, GFP_KERNEL); | 					WLAN_STATUS_SUCCESS, GFP_KERNEL); | ||||||
| 		cfg80211_put_bss(bss); | 		cfg80211_put_bss(ar->wiphy, bss); | ||||||
| 	} else if (vif->sme_state == SME_CONNECTED) { | 	} else if (vif->sme_state == SME_CONNECTED) { | ||||||
| 		/* inform roam event to cfg80211 */ | 		/* inform roam event to cfg80211 */ | ||||||
| 		cfg80211_roamed_bss(vif->ndev, bss, assoc_req_ie, assoc_req_len, | 		cfg80211_roamed_bss(vif->ndev, bss, assoc_req_ie, assoc_req_len, | ||||||
|  | @ -1454,10 +1478,10 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy, | ||||||
| 		return -EIO; | 		return -EIO; | ||||||
| 
 | 
 | ||||||
| 	if (pmgmt) { | 	if (pmgmt) { | ||||||
| 		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__); | 		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__); | ||||||
| 		mode.pwr_mode = REC_POWER; | 		mode.pwr_mode = REC_POWER; | ||||||
| 	} else { | 	} else { | ||||||
| 		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__); | 		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__); | ||||||
| 		mode.pwr_mode = MAX_PERF_POWER; | 		mode.pwr_mode = MAX_PERF_POWER; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -1509,7 +1533,7 @@ static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy, | ||||||
| 	list_del(&vif->list); | 	list_del(&vif->list); | ||||||
| 	spin_unlock_bh(&ar->list_lock); | 	spin_unlock_bh(&ar->list_lock); | ||||||
| 
 | 
 | ||||||
| 	ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag)); | 	ath6kl_cfg80211_vif_stop(vif, test_bit(WMI_READY, &ar->flag)); | ||||||
| 
 | 
 | ||||||
| 	ath6kl_cfg80211_vif_cleanup(vif); | 	ath6kl_cfg80211_vif_cleanup(vif); | ||||||
| 
 | 
 | ||||||
|  | @ -1559,17 +1583,13 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy, | ||||||
| set_iface_type: | set_iface_type: | ||||||
| 	switch (type) { | 	switch (type) { | ||||||
| 	case NL80211_IFTYPE_STATION: | 	case NL80211_IFTYPE_STATION: | ||||||
|  | 	case NL80211_IFTYPE_P2P_CLIENT: | ||||||
| 		vif->next_mode = INFRA_NETWORK; | 		vif->next_mode = INFRA_NETWORK; | ||||||
| 		break; | 		break; | ||||||
| 	case NL80211_IFTYPE_ADHOC: | 	case NL80211_IFTYPE_ADHOC: | ||||||
| 		vif->next_mode = ADHOC_NETWORK; | 		vif->next_mode = ADHOC_NETWORK; | ||||||
| 		break; | 		break; | ||||||
| 	case NL80211_IFTYPE_AP: | 	case NL80211_IFTYPE_AP: | ||||||
| 		vif->next_mode = AP_NETWORK; |  | ||||||
| 		break; |  | ||||||
| 	case NL80211_IFTYPE_P2P_CLIENT: |  | ||||||
| 		vif->next_mode = INFRA_NETWORK; |  | ||||||
| 		break; |  | ||||||
| 	case NL80211_IFTYPE_P2P_GO: | 	case NL80211_IFTYPE_P2P_GO: | ||||||
| 		vif->next_mode = AP_NETWORK; | 		vif->next_mode = AP_NETWORK; | ||||||
| 		break; | 		break; | ||||||
|  | @ -1778,14 +1798,14 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev, | ||||||
| 
 | 
 | ||||||
| 	if (vif->target_stats.rx_byte) { | 	if (vif->target_stats.rx_byte) { | ||||||
| 		sinfo->rx_bytes = vif->target_stats.rx_byte; | 		sinfo->rx_bytes = vif->target_stats.rx_byte; | ||||||
| 		sinfo->filled |= STATION_INFO_RX_BYTES; | 		sinfo->filled |= STATION_INFO_RX_BYTES64; | ||||||
| 		sinfo->rx_packets = vif->target_stats.rx_pkt; | 		sinfo->rx_packets = vif->target_stats.rx_pkt; | ||||||
| 		sinfo->filled |= STATION_INFO_RX_PACKETS; | 		sinfo->filled |= STATION_INFO_RX_PACKETS; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (vif->target_stats.tx_byte) { | 	if (vif->target_stats.tx_byte) { | ||||||
| 		sinfo->tx_bytes = vif->target_stats.tx_byte; | 		sinfo->tx_bytes = vif->target_stats.tx_byte; | ||||||
| 		sinfo->filled |= STATION_INFO_TX_BYTES; | 		sinfo->filled |= STATION_INFO_TX_BYTES64; | ||||||
| 		sinfo->tx_packets = vif->target_stats.tx_pkt; | 		sinfo->tx_packets = vif->target_stats.tx_pkt; | ||||||
| 		sinfo->filled |= STATION_INFO_TX_PACKETS; | 		sinfo->filled |= STATION_INFO_TX_PACKETS; | ||||||
| 	} | 	} | ||||||
|  | @ -2673,30 +2693,6 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif, | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, bool enable) |  | ||||||
| { |  | ||||||
| 	int err; |  | ||||||
| 
 |  | ||||||
| 	if (WARN_ON(!test_bit(WMI_READY, &vif->ar->flag))) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	if (vif->nw_type != INFRA_NETWORK) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	if (!test_bit(ATH6KL_FW_CAPABILITY_BMISS_ENHANCE, |  | ||||||
| 		      vif->ar->fw_capabilities)) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s fw bmiss enhance\n", |  | ||||||
| 		   enable ? "enable" : "disable"); |  | ||||||
| 
 |  | ||||||
| 	err = ath6kl_wmi_sta_bmiss_enhance_cmd(vif->ar->wmi, |  | ||||||
| 					       vif->fw_vif_idx, enable); |  | ||||||
| 	if (err) |  | ||||||
| 		ath6kl_err("failed to %s enhanced bmiss detection: %d\n", |  | ||||||
| 			   enable ? "enable" : "disable", err); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon, | static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon, | ||||||
| 				u8 *rsn_capab) | 				u8 *rsn_capab) | ||||||
| { | { | ||||||
|  | @ -2776,9 +2772,11 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, | ||||||
| 
 | 
 | ||||||
| 	ar->ap_mode_bkey.valid = false; | 	ar->ap_mode_bkey.valid = false; | ||||||
| 
 | 
 | ||||||
| 	/* TODO:
 | 	ret = ath6kl_wmi_ap_set_beacon_intvl_cmd(ar->wmi, vif->fw_vif_idx, | ||||||
| 	 * info->interval | 						 info->beacon_interval); | ||||||
| 	 */ | 
 | ||||||
|  | 	if (ret) | ||||||
|  | 		ath6kl_warn("Failed to set beacon interval: %d\n", ret); | ||||||
| 
 | 
 | ||||||
| 	ret = ath6kl_wmi_ap_set_dtim_cmd(ar->wmi, vif->fw_vif_idx, | 	ret = ath6kl_wmi_ap_set_dtim_cmd(ar->wmi, vif->fw_vif_idx, | ||||||
| 					 info->dtim_period); | 					 info->dtim_period); | ||||||
|  | @ -3557,6 +3555,37 @@ static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void ath6kl_cfg80211_vif_stop(struct ath6kl_vif *vif, bool wmi_ready) | ||||||
|  | { | ||||||
|  | 	static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | ||||||
|  | 	bool discon_issued; | ||||||
|  | 
 | ||||||
|  | 	netif_stop_queue(vif->ndev); | ||||||
|  | 
 | ||||||
|  | 	clear_bit(WLAN_ENABLED, &vif->flags); | ||||||
|  | 
 | ||||||
|  | 	if (wmi_ready) { | ||||||
|  | 		discon_issued = test_bit(CONNECTED, &vif->flags) || | ||||||
|  | 				test_bit(CONNECT_PEND, &vif->flags); | ||||||
|  | 		ath6kl_disconnect(vif); | ||||||
|  | 		del_timer(&vif->disconnect_timer); | ||||||
|  | 
 | ||||||
|  | 		if (discon_issued) | ||||||
|  | 			ath6kl_disconnect_event(vif, DISCONNECT_CMD, | ||||||
|  | 						(vif->nw_type & AP_NETWORK) ? | ||||||
|  | 						bcast_mac : vif->bssid, | ||||||
|  | 						0, NULL, 0); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (vif->scan_req) { | ||||||
|  | 		cfg80211_scan_done(vif->scan_req, true); | ||||||
|  | 		vif->scan_req = NULL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* need to clean up enhanced bmiss detection fw state */ | ||||||
|  | 	ath6kl_cfg80211_sta_bmiss_enhance(vif, false); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif) | void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif) | ||||||
| { | { | ||||||
| 	struct ath6kl *ar = vif->ar; | 	struct ath6kl *ar = vif->ar; | ||||||
|  |  | ||||||
|  | @ -61,7 +61,5 @@ void ath6kl_cfg80211_cleanup(struct ath6kl *ar); | ||||||
| 
 | 
 | ||||||
| struct ath6kl *ath6kl_cfg80211_create(void); | struct ath6kl *ath6kl_cfg80211_create(void); | ||||||
| void ath6kl_cfg80211_destroy(struct ath6kl *ar); | void ath6kl_cfg80211_destroy(struct ath6kl *ar); | ||||||
| /* TODO: remove this once ath6kl_vif_cleanup() is moved to cfg80211.c */ |  | ||||||
| void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, bool enable); |  | ||||||
| 
 | 
 | ||||||
| #endif /* ATH6KL_CFG80211_H */ | #endif /* ATH6KL_CFG80211_H */ | ||||||
|  |  | ||||||
|  | @ -940,7 +940,7 @@ void ath6kl_reset_device(struct ath6kl *ar, u32 target_type, | ||||||
| 			 bool wait_fot_compltn, bool cold_reset); | 			 bool wait_fot_compltn, bool cold_reset); | ||||||
| void ath6kl_init_control_info(struct ath6kl_vif *vif); | void ath6kl_init_control_info(struct ath6kl_vif *vif); | ||||||
| struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar); | struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar); | ||||||
| void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready); | void ath6kl_cfg80211_vif_stop(struct ath6kl_vif *vif, bool wmi_ready); | ||||||
| int ath6kl_init_hw_start(struct ath6kl *ar); | int ath6kl_init_hw_start(struct ath6kl *ar); | ||||||
| int ath6kl_init_hw_stop(struct ath6kl *ar); | int ath6kl_init_hw_stop(struct ath6kl *ar); | ||||||
| int ath6kl_init_fetch_firmwares(struct ath6kl *ar); | int ath6kl_init_fetch_firmwares(struct ath6kl *ar); | ||||||
|  |  | ||||||
|  | @ -509,9 +509,7 @@ static void destroy_htc_txctrl_packet(struct htc_packet *packet) | ||||||
| { | { | ||||||
| 	struct sk_buff *skb; | 	struct sk_buff *skb; | ||||||
| 	skb = packet->skb; | 	skb = packet->skb; | ||||||
| 	if (skb != NULL) |  | ||||||
| 	dev_kfree_skb(skb); | 	dev_kfree_skb(skb); | ||||||
| 
 |  | ||||||
| 	kfree(packet); | 	kfree(packet); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -969,6 +967,22 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb, | ||||||
| 	u16 payload_len; | 	u16 payload_len; | ||||||
| 	int status = 0; | 	int status = 0; | ||||||
| 
 | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * ar->htc_target can be NULL due to a race condition that can occur | ||||||
|  | 	 * during driver initialization(we do 'ath6kl_hif_power_on' before | ||||||
|  | 	 * initializing 'ar->htc_target' via 'ath6kl_htc_create'). | ||||||
|  | 	 * 'ath6kl_hif_power_on' assigns 'ath6kl_recv_complete' as | ||||||
|  | 	 * usb_complete_t/callback function for 'usb_fill_bulk_urb'. | ||||||
|  | 	 * Thus the possibility of ar->htc_target being NULL | ||||||
|  | 	 * via ath6kl_recv_complete -> ath6kl_usb_io_comp_work. | ||||||
|  | 	 */ | ||||||
|  | 	if (WARN_ON_ONCE(!target)) { | ||||||
|  | 		ath6kl_err("Target not yet initialized\n"); | ||||||
|  | 		status = -EINVAL; | ||||||
|  | 		goto free_skb; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 	netdata = skb->data; | 	netdata = skb->data; | ||||||
| 	netlen = skb->len; | 	netlen = skb->len; | ||||||
| 
 | 
 | ||||||
|  | @ -1054,6 +1068,7 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb, | ||||||
| 
 | 
 | ||||||
| 		dev_kfree_skb(skb); | 		dev_kfree_skb(skb); | ||||||
| 		skb = NULL; | 		skb = NULL; | ||||||
|  | 
 | ||||||
| 		goto free_skb; | 		goto free_skb; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -1089,7 +1104,6 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb, | ||||||
| 	skb = NULL; | 	skb = NULL; | ||||||
| 
 | 
 | ||||||
| free_skb: | free_skb: | ||||||
| 	if (skb != NULL) |  | ||||||
| 	dev_kfree_skb(skb); | 	dev_kfree_skb(skb); | ||||||
| 
 | 
 | ||||||
| 	return status; | 	return status; | ||||||
|  | @ -1184,7 +1198,7 @@ static void reset_endpoint_states(struct htc_target *target) | ||||||
| 		INIT_LIST_HEAD(&ep->pipe.tx_lookup_queue); | 		INIT_LIST_HEAD(&ep->pipe.tx_lookup_queue); | ||||||
| 		INIT_LIST_HEAD(&ep->rx_bufq); | 		INIT_LIST_HEAD(&ep->rx_bufq); | ||||||
| 		ep->target = target; | 		ep->target = target; | ||||||
| 		ep->pipe.tx_credit_flow_enabled = (bool) 1; /* FIXME */ | 		ep->pipe.tx_credit_flow_enabled = true; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1715,38 +1715,6 @@ void ath6kl_init_hw_restart(struct ath6kl *ar) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */ |  | ||||||
| void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready) |  | ||||||
| { |  | ||||||
| 	static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; |  | ||||||
| 	bool discon_issued; |  | ||||||
| 
 |  | ||||||
| 	netif_stop_queue(vif->ndev); |  | ||||||
| 
 |  | ||||||
| 	clear_bit(WLAN_ENABLED, &vif->flags); |  | ||||||
| 
 |  | ||||||
| 	if (wmi_ready) { |  | ||||||
| 		discon_issued = test_bit(CONNECTED, &vif->flags) || |  | ||||||
| 				test_bit(CONNECT_PEND, &vif->flags); |  | ||||||
| 		ath6kl_disconnect(vif); |  | ||||||
| 		del_timer(&vif->disconnect_timer); |  | ||||||
| 
 |  | ||||||
| 		if (discon_issued) |  | ||||||
| 			ath6kl_disconnect_event(vif, DISCONNECT_CMD, |  | ||||||
| 						(vif->nw_type & AP_NETWORK) ? |  | ||||||
| 						bcast_mac : vif->bssid, |  | ||||||
| 						0, NULL, 0); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (vif->scan_req) { |  | ||||||
| 		cfg80211_scan_done(vif->scan_req, true); |  | ||||||
| 		vif->scan_req = NULL; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* need to clean up enhanced bmiss detection fw state */ |  | ||||||
| 	ath6kl_cfg80211_sta_bmiss_enhance(vif, false); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ath6kl_stop_txrx(struct ath6kl *ar) | void ath6kl_stop_txrx(struct ath6kl *ar) | ||||||
| { | { | ||||||
| 	struct ath6kl_vif *vif, *tmp_vif; | 	struct ath6kl_vif *vif, *tmp_vif; | ||||||
|  | @ -1766,7 +1734,7 @@ void ath6kl_stop_txrx(struct ath6kl *ar) | ||||||
| 	list_for_each_entry_safe(vif, tmp_vif, &ar->vif_list, list) { | 	list_for_each_entry_safe(vif, tmp_vif, &ar->vif_list, list) { | ||||||
| 		list_del(&vif->list); | 		list_del(&vif->list); | ||||||
| 		spin_unlock_bh(&ar->list_lock); | 		spin_unlock_bh(&ar->list_lock); | ||||||
| 		ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag)); | 		ath6kl_cfg80211_vif_stop(vif, test_bit(WMI_READY, &ar->flag)); | ||||||
| 		rtnl_lock(); | 		rtnl_lock(); | ||||||
| 		ath6kl_cfg80211_vif_cleanup(vif); | 		ath6kl_cfg80211_vif_cleanup(vif); | ||||||
| 		rtnl_unlock(); | 		rtnl_unlock(); | ||||||
|  | @ -1801,8 +1769,6 @@ void ath6kl_stop_txrx(struct ath6kl *ar) | ||||||
| 		   "attempting to reset target on instance destroy\n"); | 		   "attempting to reset target on instance destroy\n"); | ||||||
| 	ath6kl_reset_device(ar, ar->target_type, true, true); | 	ath6kl_reset_device(ar, ar->target_type, true, true); | ||||||
| 
 | 
 | ||||||
| 	clear_bit(WLAN_ENABLED, &ar->flag); |  | ||||||
| 
 |  | ||||||
| 	up(&ar->sem); | 	up(&ar->sem); | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(ath6kl_stop_txrx); | EXPORT_SYMBOL(ath6kl_stop_txrx); | ||||||
|  |  | ||||||
|  | @ -159,10 +159,8 @@ static void ath6kl_usb_free_urb_to_pipe(struct ath6kl_usb_pipe *pipe, | ||||||
| 
 | 
 | ||||||
| static void ath6kl_usb_cleanup_recv_urb(struct ath6kl_urb_context *urb_context) | static void ath6kl_usb_cleanup_recv_urb(struct ath6kl_urb_context *urb_context) | ||||||
| { | { | ||||||
| 	if (urb_context->skb != NULL) { |  | ||||||
| 	dev_kfree_skb(urb_context->skb); | 	dev_kfree_skb(urb_context->skb); | ||||||
| 	urb_context->skb = NULL; | 	urb_context->skb = NULL; | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	ath6kl_usb_free_urb_to_pipe(urb_context->pipe, urb_context); | 	ath6kl_usb_free_urb_to_pipe(urb_context->pipe, urb_context); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -751,6 +751,23 @@ int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid) | ||||||
| 				   NO_SYNC_WMIFLAG); | 				   NO_SYNC_WMIFLAG); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | int ath6kl_wmi_ap_set_beacon_intvl_cmd(struct wmi *wmi, u8 if_idx, | ||||||
|  | 				       u32 beacon_intvl) | ||||||
|  | { | ||||||
|  | 	struct sk_buff *skb; | ||||||
|  | 	struct set_beacon_int_cmd *cmd; | ||||||
|  | 
 | ||||||
|  | 	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||||||
|  | 	if (!skb) | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 
 | ||||||
|  | 	cmd = (struct set_beacon_int_cmd *) skb->data; | ||||||
|  | 
 | ||||||
|  | 	cmd->beacon_intvl = cpu_to_le32(beacon_intvl); | ||||||
|  | 	return ath6kl_wmi_cmd_send(wmi, if_idx, skb, | ||||||
|  | 				   WMI_SET_BEACON_INT_CMDID, NO_SYNC_WMIFLAG); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period) | int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period) | ||||||
| { | { | ||||||
| 	struct sk_buff *skb; | 	struct sk_buff *skb; | ||||||
|  | @ -1108,7 +1125,7 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len, | ||||||
| 	kfree(mgmt); | 	kfree(mgmt); | ||||||
| 	if (bss == NULL) | 	if (bss == NULL) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 	cfg80211_put_bss(bss); | 	cfg80211_put_bss(ar->wiphy, bss); | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Firmware doesn't return any event when scheduled scan has | 	 * Firmware doesn't return any event when scheduled scan has | ||||||
|  | @ -2480,16 +2497,11 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx) | ||||||
| 
 | 
 | ||||||
| free_cmd_skb: | free_cmd_skb: | ||||||
| 	/* free up any resources left over (possibly due to an error) */ | 	/* free up any resources left over (possibly due to an error) */ | ||||||
| 	if (skb) |  | ||||||
| 	dev_kfree_skb(skb); | 	dev_kfree_skb(skb); | ||||||
| 
 | 
 | ||||||
| free_data_skb: | free_data_skb: | ||||||
| 	for (index = 0; index < num_pri_streams; index++) { | 	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].skb); | ||||||
| 			dev_kfree_skb((struct sk_buff *)data_sync_bufs[index]. |  | ||||||
| 				      skb); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1660,6 +1660,10 @@ struct roam_ctrl_cmd { | ||||||
| 	u8 roam_ctrl; | 	u8 roam_ctrl; | ||||||
| } __packed; | } __packed; | ||||||
| 
 | 
 | ||||||
|  | struct set_beacon_int_cmd { | ||||||
|  | 	__le32 beacon_intvl; | ||||||
|  | } __packed; | ||||||
|  | 
 | ||||||
| struct set_dtim_cmd { | struct set_dtim_cmd { | ||||||
| 	__le32 dtim_period; | 	__le32 dtim_period; | ||||||
| } __packed; | } __packed; | ||||||
|  | @ -2649,6 +2653,8 @@ int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, | ||||||
| int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi); | 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_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_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period); | ||||||
|  | int ath6kl_wmi_ap_set_beacon_intvl_cmd(struct wmi *wmi, u8 if_idx, | ||||||
|  | 				       u32 beacon_interval); | ||||||
| int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid); | int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid); | ||||||
| int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode); | int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode); | ||||||
| int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on); | int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on); | ||||||
|  |  | ||||||
|  | @ -389,6 +389,7 @@ struct ath_beacon_config { | ||||||
| 	u16 bmiss_timeout; | 	u16 bmiss_timeout; | ||||||
| 	u8 dtim_count; | 	u8 dtim_count; | ||||||
| 	bool enable_beacon; | 	bool enable_beacon; | ||||||
|  | 	bool ibss_creator; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct ath_beacon { | struct ath_beacon { | ||||||
|  |  | ||||||
|  | @ -407,11 +407,16 @@ void ath9k_beacon_tasklet(unsigned long data) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, u32 intval) | /*
 | ||||||
|  |  * Both nexttbtt and intval have to be in usecs. | ||||||
|  |  */ | ||||||
|  | static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, | ||||||
|  | 			      u32 intval, bool reset_tsf) | ||||||
| { | { | ||||||
| 	struct ath_hw *ah = sc->sc_ah; | 	struct ath_hw *ah = sc->sc_ah; | ||||||
| 
 | 
 | ||||||
| 	ath9k_hw_disable_interrupts(ah); | 	ath9k_hw_disable_interrupts(ah); | ||||||
|  | 	if (reset_tsf) | ||||||
| 		ath9k_hw_reset_tsf(ah); | 		ath9k_hw_reset_tsf(ah); | ||||||
| 	ath9k_beaconq_config(sc); | 	ath9k_beaconq_config(sc); | ||||||
| 	ath9k_hw_beaconinit(ah, nexttbtt, intval); | 	ath9k_hw_beaconinit(ah, nexttbtt, intval); | ||||||
|  | @ -442,10 +447,12 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc, | ||||||
| 	else | 	else | ||||||
| 		ah->imask &= ~ATH9K_INT_SWBA; | 		ah->imask &= ~ATH9K_INT_SWBA; | ||||||
| 
 | 
 | ||||||
| 	ath_dbg(common, BEACON, "AP nexttbtt: %u intval: %u conf_intval: %u\n", | 	ath_dbg(common, BEACON, | ||||||
|  | 		"AP (%s) nexttbtt: %u intval: %u conf_intval: %u\n", | ||||||
|  | 		(conf->enable_beacon) ? "Enable" : "Disable", | ||||||
| 		nexttbtt, intval, conf->beacon_interval); | 		nexttbtt, intval, conf->beacon_interval); | ||||||
| 
 | 
 | ||||||
| 	ath9k_beacon_init(sc, nexttbtt, intval); | 	ath9k_beacon_init(sc, nexttbtt, intval, true); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -586,17 +593,45 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc, | ||||||
| 	ath9k_reset_beacon_status(sc); | 	ath9k_reset_beacon_status(sc); | ||||||
| 
 | 
 | ||||||
| 	intval = TU_TO_USEC(conf->beacon_interval); | 	intval = TU_TO_USEC(conf->beacon_interval); | ||||||
|  | 
 | ||||||
|  | 	if (conf->ibss_creator) { | ||||||
| 		nexttbtt = intval; | 		nexttbtt = intval; | ||||||
|  | 	} else { | ||||||
|  | 		u32 tbtt, offset, tsftu; | ||||||
|  | 		u64 tsf; | ||||||
|  | 
 | ||||||
|  | 		/*
 | ||||||
|  | 		 * Pull nexttbtt forward to reflect the current | ||||||
|  | 		 * sync'd TSF. | ||||||
|  | 		 */ | ||||||
|  | 		tsf = ath9k_hw_gettsf64(ah); | ||||||
|  | 		tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE; | ||||||
|  | 		offset = tsftu % conf->beacon_interval; | ||||||
|  | 		tbtt = tsftu - offset; | ||||||
|  | 		if (offset) | ||||||
|  | 			tbtt += conf->beacon_interval; | ||||||
|  | 
 | ||||||
|  | 		nexttbtt = TU_TO_USEC(tbtt); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	if (conf->enable_beacon) | 	if (conf->enable_beacon) | ||||||
| 		ah->imask |= ATH9K_INT_SWBA; | 		ah->imask |= ATH9K_INT_SWBA; | ||||||
| 	else | 	else | ||||||
| 		ah->imask &= ~ATH9K_INT_SWBA; | 		ah->imask &= ~ATH9K_INT_SWBA; | ||||||
| 
 | 
 | ||||||
| 	ath_dbg(common, BEACON, "IBSS nexttbtt: %u intval: %u conf_intval: %u\n", | 	ath_dbg(common, BEACON, | ||||||
|  | 		"IBSS (%s) nexttbtt: %u intval: %u conf_intval: %u\n", | ||||||
|  | 		(conf->enable_beacon) ? "Enable" : "Disable", | ||||||
| 		nexttbtt, intval, conf->beacon_interval); | 		nexttbtt, intval, conf->beacon_interval); | ||||||
| 
 | 
 | ||||||
| 	ath9k_beacon_init(sc, nexttbtt, intval); | 	ath9k_beacon_init(sc, nexttbtt, intval, conf->ibss_creator); | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Set the global 'beacon has been configured' flag for the | ||||||
|  | 	 * joiner case in IBSS mode. | ||||||
|  | 	 */ | ||||||
|  | 	if (!conf->ibss_creator && conf->enable_beacon) | ||||||
|  | 		set_bit(SC_OP_BEACONS, &sc->sc_flags); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) | bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) | ||||||
|  | @ -639,6 +674,7 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc, | ||||||
| 	cur_conf->dtim_period = bss_conf->dtim_period; | 	cur_conf->dtim_period = bss_conf->dtim_period; | ||||||
| 	cur_conf->listen_interval = 1; | 	cur_conf->listen_interval = 1; | ||||||
| 	cur_conf->dtim_count = 1; | 	cur_conf->dtim_count = 1; | ||||||
|  | 	cur_conf->ibss_creator = bss_conf->ibss_creator; | ||||||
| 	cur_conf->bmiss_timeout = | 	cur_conf->bmiss_timeout = | ||||||
| 		ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; | 		ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; | ||||||
| 
 | 
 | ||||||
|  | @ -666,12 +702,17 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, | ||||||
| { | { | ||||||
| 	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | 	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | ||||||
| 	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; | 	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; | ||||||
|  | 	unsigned long flags; | ||||||
|  | 	bool skip_beacon = false; | ||||||
| 
 | 
 | ||||||
| 	if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { | 	if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { | ||||||
| 		ath9k_cache_beacon_config(sc, bss_conf); | 		ath9k_cache_beacon_config(sc, bss_conf); | ||||||
| 		ath9k_set_beacon(sc); | 		ath9k_set_beacon(sc); | ||||||
| 		set_bit(SC_OP_BEACONS, &sc->sc_flags); | 		set_bit(SC_OP_BEACONS, &sc->sc_flags); | ||||||
| 	} else { | 		return; | ||||||
|  | 
 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Take care of multiple interfaces when | 	 * Take care of multiple interfaces when | ||||||
| 	 * enabling/disabling SWBA. | 	 * enabling/disabling SWBA. | ||||||
|  | @ -686,15 +727,35 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Configure the HW beacon registers only when we have a valid | ||||||
|  | 	 * beacon interval. | ||||||
|  | 	 */ | ||||||
| 	if (cur_conf->beacon_interval) { | 	if (cur_conf->beacon_interval) { | ||||||
|  | 		/*
 | ||||||
|  | 		 * If we are joining an existing IBSS network, start beaconing | ||||||
|  | 		 * only after a TSF-sync has taken place. Ensure that this | ||||||
|  | 		 * happens by setting the appropriate flags. | ||||||
|  | 		 */ | ||||||
|  | 		if ((changed & BSS_CHANGED_IBSS) && !bss_conf->ibss_creator && | ||||||
|  | 		    bss_conf->enable_beacon) { | ||||||
|  | 			spin_lock_irqsave(&sc->sc_pm_lock, flags); | ||||||
|  | 			sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; | ||||||
|  | 			spin_unlock_irqrestore(&sc->sc_pm_lock, flags); | ||||||
|  | 			skip_beacon = true; | ||||||
|  | 		} else { | ||||||
| 			ath9k_set_beacon(sc); | 			ath9k_set_beacon(sc); | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 			if (cur_conf->enable_beacon) | 		/*
 | ||||||
|  | 		 * Do not set the SC_OP_BEACONS flag for IBSS joiner mode | ||||||
|  | 		 * here, it is done in ath9k_beacon_config_adhoc(). | ||||||
|  | 		 */ | ||||||
|  | 		if (cur_conf->enable_beacon && !skip_beacon) | ||||||
| 			set_bit(SC_OP_BEACONS, &sc->sc_flags); | 			set_bit(SC_OP_BEACONS, &sc->sc_flags); | ||||||
| 		else | 		else | ||||||
| 			clear_bit(SC_OP_BEACONS, &sc->sc_flags); | 			clear_bit(SC_OP_BEACONS, &sc->sc_flags); | ||||||
| 	} | 	} | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ath9k_set_beacon(struct ath_softc *sc) | void ath9k_set_beacon(struct ath_softc *sc) | ||||||
|  |  | ||||||
|  | @ -320,27 +320,24 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, | ||||||
| 			    struct ieee80211_vif *vif) | 			    struct ieee80211_vif *vif) | ||||||
| { | { | ||||||
| 	struct ath_node *an; | 	struct ath_node *an; | ||||||
| 	u8 density; |  | ||||||
| 	an = (struct ath_node *)sta->drv_priv; | 	an = (struct ath_node *)sta->drv_priv; | ||||||
| 
 | 
 | ||||||
| 	an->sc = sc; | 	an->sc = sc; | ||||||
| 	an->sta = sta; | 	an->sta = sta; | ||||||
| 	an->vif = vif; | 	an->vif = vif; | ||||||
| 
 | 
 | ||||||
| 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { |  | ||||||
| 	ath_tx_node_init(sc, an); | 	ath_tx_node_init(sc, an); | ||||||
|  | 
 | ||||||
|  | 	if (sta->ht_cap.ht_supported) { | ||||||
| 		an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + | 		an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + | ||||||
| 				     sta->ht_cap.ampdu_factor); | 				     sta->ht_cap.ampdu_factor); | ||||||
| 		density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density); | 		an->mpdudensity = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density); | ||||||
| 		an->mpdudensity = density; |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) | static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) | ||||||
| { | { | ||||||
| 	struct ath_node *an = (struct ath_node *)sta->drv_priv; | 	struct ath_node *an = (struct ath_node *)sta->drv_priv; | ||||||
| 
 |  | ||||||
| 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) |  | ||||||
| 	ath_tx_node_cleanup(sc, an); | 	ath_tx_node_cleanup(sc, an); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1204,7 +1204,7 @@ static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta) | ||||||
| 			caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG; | 			caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG; | ||||||
| 		else if (sta->ht_cap.mcs.rx_mask[1]) | 		else if (sta->ht_cap.mcs.rx_mask[1]) | ||||||
| 			caps |= WLAN_RC_DS_FLAG; | 			caps |= WLAN_RC_DS_FLAG; | ||||||
| 		if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { | 		if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) { | ||||||
| 			caps |= WLAN_RC_40_FLAG; | 			caps |= WLAN_RC_40_FLAG; | ||||||
| 			if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) | 			if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) | ||||||
| 				caps |= WLAN_RC_SGI_FLAG; | 				caps |= WLAN_RC_SGI_FLAG; | ||||||
|  |  | ||||||
|  | @ -533,7 +533,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) | ||||||
| 	if (sc->ps_flags & PS_BEACON_SYNC) { | 	if (sc->ps_flags & PS_BEACON_SYNC) { | ||||||
| 		sc->ps_flags &= ~PS_BEACON_SYNC; | 		sc->ps_flags &= ~PS_BEACON_SYNC; | ||||||
| 		ath_dbg(common, PS, | 		ath_dbg(common, PS, | ||||||
| 			"Reconfigure Beacon timers based on timestamp from the AP\n"); | 			"Reconfigure beacon timers based on synchronized timestamp\n"); | ||||||
| 		ath9k_set_beacon(sc); | 		ath9k_set_beacon(sc); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1233,7 +1233,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, | ||||||
| 	 * in HT IBSS when a beacon with HT-info is received after the station | 	 * in HT IBSS when a beacon with HT-info is received after the station | ||||||
| 	 * has already been added. | 	 * has already been added. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { | 	if (sta->ht_cap.ht_supported) { | ||||||
| 		an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + | 		an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + | ||||||
| 				     sta->ht_cap.ampdu_factor); | 				     sta->ht_cap.ampdu_factor); | ||||||
| 		density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density); | 		density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density); | ||||||
|  | @ -1904,8 +1904,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb, | ||||||
| 	struct ath_buf *bf; | 	struct ath_buf *bf; | ||||||
| 	u8 tidno; | 	u8 tidno; | ||||||
| 
 | 
 | ||||||
| 	if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && txctl->an && | 	if (txctl->an && ieee80211_is_data_qos(hdr->frame_control)) { | ||||||
| 		ieee80211_is_data_qos(hdr->frame_control)) { |  | ||||||
| 		tidno = ieee80211_get_qos_ctl(hdr)[0] & | 		tidno = ieee80211_get_qos_ctl(hdr)[0] & | ||||||
| 			IEEE80211_QOS_CTL_TID_MASK; | 			IEEE80211_QOS_CTL_TID_MASK; | ||||||
| 		tid = ATH_AN_2_TID(txctl->an, tidno); | 		tid = ATH_AN_2_TID(txctl->an, tidno); | ||||||
|  |  | ||||||
|  | @ -1853,7 +1853,7 @@ void *carl9170_alloc(size_t priv_size) | ||||||
| 		     IEEE80211_HW_REPORTS_TX_ACK_STATUS | | 		     IEEE80211_HW_REPORTS_TX_ACK_STATUS | | ||||||
| 		     IEEE80211_HW_SUPPORTS_PS | | 		     IEEE80211_HW_SUPPORTS_PS | | ||||||
| 		     IEEE80211_HW_PS_NULLFUNC_STACK | | 		     IEEE80211_HW_PS_NULLFUNC_STACK | | ||||||
| 		     IEEE80211_HW_NEED_DTIM_PERIOD | | 		     IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC | | ||||||
| 		     IEEE80211_HW_SIGNAL_DBM; | 		     IEEE80211_HW_SIGNAL_DBM; | ||||||
| 
 | 
 | ||||||
| 	if (!modparam_noht) { | 	if (!modparam_noht) { | ||||||
|  |  | ||||||
|  | @ -341,7 +341,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  out: |  out: | ||||||
| 	cfg80211_put_bss(bss); | 	cfg80211_put_bss(wiphy, bss); | ||||||
| 
 | 
 | ||||||
| 	return rc; | 	return rc; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -338,7 +338,7 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) | ||||||
| 		if (bss) { | 		if (bss) { | ||||||
| 			wil_dbg_wmi(wil, "Added BSS %pM\n", | 			wil_dbg_wmi(wil, "Added BSS %pM\n", | ||||||
| 				    rx_mgmt_frame->bssid); | 				    rx_mgmt_frame->bssid); | ||||||
| 			cfg80211_put_bss(bss); | 			cfg80211_put_bss(wiphy, bss); | ||||||
| 		} else { | 		} else { | ||||||
| 			wil_err(wil, "cfg80211_inform_bss() failed\n"); | 			wil_err(wil, "cfg80211_inform_bss() failed\n"); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -26,6 +26,7 @@ brcmfmac-objs += \ | ||||||
| 		wl_cfg80211.o \
 | 		wl_cfg80211.o \
 | ||||||
| 		fwil.o \
 | 		fwil.o \
 | ||||||
| 		fweh.o \
 | 		fweh.o \
 | ||||||
|  | 		p2p.o \
 | ||||||
| 		dhd_cdc.o \
 | 		dhd_cdc.o \
 | ||||||
| 		dhd_common.o \
 | 		dhd_common.o \
 | ||||||
| 		dhd_linux.o | 		dhd_linux.o | ||||||
|  |  | ||||||
|  | @ -72,6 +72,7 @@ | ||||||
| #define BRCMF_C_SET_WSEC			134 | #define BRCMF_C_SET_WSEC			134 | ||||||
| #define BRCMF_C_GET_PHY_NOISE			135 | #define BRCMF_C_GET_PHY_NOISE			135 | ||||||
| #define BRCMF_C_GET_BSS_INFO			136 | #define BRCMF_C_GET_BSS_INFO			136 | ||||||
|  | #define BRCMF_C_SET_SCB_TIMEOUT			158 | ||||||
| #define BRCMF_C_GET_PHYLIST			180 | #define BRCMF_C_GET_PHYLIST			180 | ||||||
| #define BRCMF_C_SET_SCAN_CHANNEL_TIME		185 | #define BRCMF_C_SET_SCAN_CHANNEL_TIME		185 | ||||||
| #define BRCMF_C_SET_SCAN_UNASSOC_TIME		187 | #define BRCMF_C_SET_SCAN_UNASSOC_TIME		187 | ||||||
|  | @ -149,6 +150,7 @@ | ||||||
| #define BRCMF_E_REASON_MINTXRATE		9 | #define BRCMF_E_REASON_MINTXRATE		9 | ||||||
| #define BRCMF_E_REASON_TXFAIL			10 | #define BRCMF_E_REASON_TXFAIL			10 | ||||||
| 
 | 
 | ||||||
|  | #define BRCMF_E_REASON_LINK_BSSCFG_DIS		4 | ||||||
| #define BRCMF_E_REASON_FAST_ROAM_FAILED		5 | #define BRCMF_E_REASON_FAST_ROAM_FAILED		5 | ||||||
| #define BRCMF_E_REASON_DIRECTED_ROAM		6 | #define BRCMF_E_REASON_DIRECTED_ROAM		6 | ||||||
| #define BRCMF_E_REASON_TSPEC_REJECTED		7 | #define BRCMF_E_REASON_TSPEC_REJECTED		7 | ||||||
|  | @ -375,6 +377,28 @@ struct brcmf_join_params { | ||||||
| 	struct brcmf_assoc_params_le params_le; | 	struct brcmf_assoc_params_le params_le; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /* scan params for extended join */ | ||||||
|  | struct brcmf_join_scan_params_le { | ||||||
|  | 	u8 scan_type;		/* 0 use default, active or passive scan */ | ||||||
|  | 	__le32 nprobes;		/* -1 use default, nr of probes per channel */ | ||||||
|  | 	__le32 active_time;	/* -1 use default, dwell time per channel for
 | ||||||
|  | 				 * active scanning | ||||||
|  | 				 */ | ||||||
|  | 	__le32 passive_time;	/* -1 use default, dwell time per channel
 | ||||||
|  | 				 * for passive scanning | ||||||
|  | 				 */ | ||||||
|  | 	__le32 home_time;	/* -1 use default, dwell time for the home
 | ||||||
|  | 				 * channel between channel scans | ||||||
|  | 				 */ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* extended join params */ | ||||||
|  | struct brcmf_ext_join_params_le { | ||||||
|  | 	struct brcmf_ssid_le ssid_le;	/* {0, ""}: wildcard scan */ | ||||||
|  | 	struct brcmf_join_scan_params_le scan_le; | ||||||
|  | 	struct brcmf_assoc_params_le assoc_le; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| struct brcmf_wsec_key { | struct brcmf_wsec_key { | ||||||
| 	u32 index;		/* key index */ | 	u32 index;		/* key index */ | ||||||
| 	u32 len;		/* key length */ | 	u32 len;		/* key length */ | ||||||
|  | @ -451,6 +475,19 @@ struct brcmf_sta_info_le { | ||||||
| 	__le32	rx_decrypt_failures;	/* # of packet decrypted failed */ | 	__le32	rx_decrypt_failures;	/* # of packet decrypted failed */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * WLC_E_PROBRESP_MSG | ||||||
|  |  * WLC_E_P2P_PROBREQ_MSG | ||||||
|  |  * WLC_E_ACTION_FRAME_RX | ||||||
|  |  */ | ||||||
|  | struct brcmf_rx_mgmt_data { | ||||||
|  | 	__be16	version; | ||||||
|  | 	__be16	chanspec; | ||||||
|  | 	__be32	rssi; | ||||||
|  | 	__be32	mactime; | ||||||
|  | 	__be32	rate; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| /* Bus independent dongle command */ | /* Bus independent dongle command */ | ||||||
| struct brcmf_dcmd { | struct brcmf_dcmd { | ||||||
| 	uint cmd;		/* common dongle cmd definition */ | 	uint cmd;		/* common dongle cmd definition */ | ||||||
|  | @ -489,9 +526,6 @@ struct brcmf_pub { | ||||||
| 	struct mutex proto_block; | 	struct mutex proto_block; | ||||||
| 	unsigned char proto_buf[BRCMF_DCMD_MAXLEN]; | 	unsigned char proto_buf[BRCMF_DCMD_MAXLEN]; | ||||||
| 
 | 
 | ||||||
| 	atomic_t pend_8021x_cnt; |  | ||||||
| 	wait_queue_head_t pend_8021x_wait; |  | ||||||
| 
 |  | ||||||
| 	struct brcmf_fweh_info fweh; | 	struct brcmf_fweh_info fweh; | ||||||
| #ifdef DEBUG | #ifdef DEBUG | ||||||
| 	struct dentry *dbgfs_dir; | 	struct dentry *dbgfs_dir; | ||||||
|  | @ -515,9 +549,11 @@ struct brcmf_cfg80211_vif; | ||||||
|  * @vif: points to cfg80211 specific interface information. |  * @vif: points to cfg80211 specific interface information. | ||||||
|  * @ndev: associated network device. |  * @ndev: associated network device. | ||||||
|  * @stats: interface specific network statistics. |  * @stats: interface specific network statistics. | ||||||
|  * @idx: interface index in device firmware. |  * @ifidx: interface index in device firmware. | ||||||
|  * @bssidx: index of bss associated with this interface. |  * @bssidx: index of bss associated with this interface. | ||||||
|  * @mac_addr: assigned mac address. |  * @mac_addr: assigned mac address. | ||||||
|  |  * @pend_8021x_cnt: tracks outstanding number of 802.1x frames. | ||||||
|  |  * @pend_8021x_wait: used for signalling change in count. | ||||||
|  */ |  */ | ||||||
| struct brcmf_if { | struct brcmf_if { | ||||||
| 	struct brcmf_pub *drvr; | 	struct brcmf_pub *drvr; | ||||||
|  | @ -526,9 +562,11 @@ struct brcmf_if { | ||||||
| 	struct net_device_stats stats; | 	struct net_device_stats stats; | ||||||
| 	struct work_struct setmacaddr_work; | 	struct work_struct setmacaddr_work; | ||||||
| 	struct work_struct multicast_work; | 	struct work_struct multicast_work; | ||||||
| 	int idx; | 	int ifidx; | ||||||
| 	s32 bssidx; | 	s32 bssidx; | ||||||
| 	u8 mac_addr[ETH_ALEN]; | 	u8 mac_addr[ETH_ALEN]; | ||||||
|  | 	atomic_t pend_8021x_cnt; | ||||||
|  | 	wait_queue_head_t pend_8021x_wait; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -547,9 +585,10 @@ extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, | ||||||
| extern int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx, | extern int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx, | ||||||
| 			       struct sk_buff *rxp); | 			       struct sk_buff *rxp); | ||||||
| 
 | 
 | ||||||
| extern int brcmf_net_attach(struct brcmf_if *ifp); | extern int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked); | ||||||
| extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, | extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, | ||||||
| 				     s32 bssidx, char *name, u8 *mac_addr); | 				     s32 ifidx, char *name, u8 *mac_addr); | ||||||
| extern void brcmf_del_if(struct brcmf_pub *drvr, int ifidx); | extern void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx); | ||||||
|  | extern u32 brcmf_get_chip_info(struct brcmf_if *ifp); | ||||||
| 
 | 
 | ||||||
| #endif				/* _BRCMF_H_ */ | #endif				/* _BRCMF_H_ */ | ||||||
|  |  | ||||||
|  | @ -24,18 +24,6 @@ enum brcmf_bus_state { | ||||||
| 	BRCMF_BUS_DATA		/* Ready for frame transfers */ | 	BRCMF_BUS_DATA		/* Ready for frame transfers */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct dngl_stats { |  | ||||||
| 	unsigned long rx_packets;	/* total packets received */ |  | ||||||
| 	unsigned long tx_packets;	/* total packets transmitted */ |  | ||||||
| 	unsigned long rx_bytes;	/* total bytes received */ |  | ||||||
| 	unsigned long tx_bytes;	/* total bytes transmitted */ |  | ||||||
| 	unsigned long rx_errors;	/* bad packets received */ |  | ||||||
| 	unsigned long tx_errors;	/* packet transmit problems */ |  | ||||||
| 	unsigned long rx_dropped;	/* packets dropped by dongle */ |  | ||||||
| 	unsigned long tx_dropped;	/* packets dropped by dongle */ |  | ||||||
| 	unsigned long multicast;	/* multicast packets received */ |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct brcmf_bus_dcmd { | struct brcmf_bus_dcmd { | ||||||
| 	char *name; | 	char *name; | ||||||
| 	char *param; | 	char *param; | ||||||
|  | @ -72,11 +60,12 @@ struct brcmf_bus_ops { | ||||||
|  * @drvr: public driver information. |  * @drvr: public driver information. | ||||||
|  * @state: operational state of the bus interface. |  * @state: operational state of the bus interface. | ||||||
|  * @maxctl: maximum size for rxctl request message. |  * @maxctl: maximum size for rxctl request message. | ||||||
|  * @drvr_up: indicates driver up/down status. |  | ||||||
|  * @tx_realloc: number of tx packets realloced for headroom. |  * @tx_realloc: number of tx packets realloced for headroom. | ||||||
|  * @dstats: dongle-based statistical data. |  * @dstats: dongle-based statistical data. | ||||||
|  * @align: alignment requirement for the bus. |  * @align: alignment requirement for the bus. | ||||||
|  * @dcmd_list: bus/device specific dongle initialization commands. |  * @dcmd_list: bus/device specific dongle initialization commands. | ||||||
|  |  * @chip: device identifier of the dongle chip. | ||||||
|  |  * @chiprev: revision of the dongle chip. | ||||||
|  */ |  */ | ||||||
| struct brcmf_bus { | struct brcmf_bus { | ||||||
| 	union { | 	union { | ||||||
|  | @ -87,10 +76,10 @@ struct brcmf_bus { | ||||||
| 	struct brcmf_pub *drvr; | 	struct brcmf_pub *drvr; | ||||||
| 	enum brcmf_bus_state state; | 	enum brcmf_bus_state state; | ||||||
| 	uint maxctl; | 	uint maxctl; | ||||||
| 	bool drvr_up; |  | ||||||
| 	unsigned long tx_realloc; | 	unsigned long tx_realloc; | ||||||
| 	struct dngl_stats dstats; |  | ||||||
| 	u8 align; | 	u8 align; | ||||||
|  | 	u32 chip; | ||||||
|  | 	u32 chiprev; | ||||||
| 	struct list_head dcmd_list; | 	struct list_head dcmd_list; | ||||||
| 
 | 
 | ||||||
| 	struct brcmf_bus_ops *ops; | 	struct brcmf_bus_ops *ops; | ||||||
|  |  | ||||||
|  | @ -303,6 +303,14 @@ int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx, | ||||||
| 		brcmf_err("rx data ifnum out of range (%d)\n", *ifidx); | 		brcmf_err("rx data ifnum out of range (%d)\n", *ifidx); | ||||||
| 		return -EBADE; | 		return -EBADE; | ||||||
| 	} | 	} | ||||||
|  | 	/* The ifidx is the idx to map to matching netdev/ifp. When receiving
 | ||||||
|  | 	 * events this is easy because it contains the bssidx which maps | ||||||
|  | 	 * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd. | ||||||
|  | 	 * bssidx 1 is used for p2p0 and no data can be received or | ||||||
|  | 	 * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0 | ||||||
|  | 	 */ | ||||||
|  | 	if (*ifidx) | ||||||
|  | 		(*ifidx)++; | ||||||
| 
 | 
 | ||||||
| 	if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != | 	if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != | ||||||
| 	    BDC_PROTO_VER) { | 	    BDC_PROTO_VER) { | ||||||
|  |  | ||||||
|  | @ -26,6 +26,8 @@ | ||||||
| #include "dhd_bus.h" | #include "dhd_bus.h" | ||||||
| #include "dhd_proto.h" | #include "dhd_proto.h" | ||||||
| #include "dhd_dbg.h" | #include "dhd_dbg.h" | ||||||
|  | #include "fwil_types.h" | ||||||
|  | #include "p2p.h" | ||||||
| #include "wl_cfg80211.h" | #include "wl_cfg80211.h" | ||||||
| #include "fwil.h" | #include "fwil.h" | ||||||
| 
 | 
 | ||||||
|  | @ -40,6 +42,12 @@ MODULE_LICENSE("Dual BSD/GPL"); | ||||||
| int brcmf_msg_level; | int brcmf_msg_level; | ||||||
| module_param(brcmf_msg_level, int, 0); | module_param(brcmf_msg_level, int, 0); | ||||||
| 
 | 
 | ||||||
|  | /* P2P0 enable */ | ||||||
|  | static int brcmf_p2p_enable; | ||||||
|  | #ifdef CONFIG_BRCMDBG | ||||||
|  | module_param_named(p2pon, brcmf_p2p_enable, int, 0); | ||||||
|  | MODULE_PARM_DESC(p2pon, "enable p2p management functionality"); | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx) | char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx) | ||||||
| { | { | ||||||
|  | @ -70,9 +78,10 @@ static void _brcmf_set_multicast_list(struct work_struct *work) | ||||||
| 	u32 buflen; | 	u32 buflen; | ||||||
| 	s32 err; | 	s32 err; | ||||||
| 
 | 
 | ||||||
| 	brcmf_dbg(TRACE, "enter\n"); |  | ||||||
| 
 |  | ||||||
| 	ifp = container_of(work, struct brcmf_if, multicast_work); | 	ifp = container_of(work, struct brcmf_if, multicast_work); | ||||||
|  | 
 | ||||||
|  | 	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); | ||||||
|  | 
 | ||||||
| 	ndev = ifp->ndev; | 	ndev = ifp->ndev; | ||||||
| 
 | 
 | ||||||
| 	/* Determine initial value of allmulti flag */ | 	/* Determine initial value of allmulti flag */ | ||||||
|  | @ -129,9 +138,10 @@ _brcmf_set_mac_address(struct work_struct *work) | ||||||
| 	struct brcmf_if *ifp; | 	struct brcmf_if *ifp; | ||||||
| 	s32 err; | 	s32 err; | ||||||
| 
 | 
 | ||||||
| 	brcmf_dbg(TRACE, "enter\n"); |  | ||||||
| 
 |  | ||||||
| 	ifp = container_of(work, struct brcmf_if, setmacaddr_work); | 	ifp = container_of(work, struct brcmf_if, setmacaddr_work); | ||||||
|  | 
 | ||||||
|  | 	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); | ||||||
|  | 
 | ||||||
| 	err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr, | 	err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr, | ||||||
| 				       ETH_ALEN); | 				       ETH_ALEN); | ||||||
| 	if (err < 0) { | 	if (err < 0) { | ||||||
|  | @ -168,7 +178,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, | ||||||
| 	struct brcmf_pub *drvr = ifp->drvr; | 	struct brcmf_pub *drvr = ifp->drvr; | ||||||
| 	struct ethhdr *eh; | 	struct ethhdr *eh; | ||||||
| 
 | 
 | ||||||
| 	brcmf_dbg(TRACE, "Enter\n"); | 	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); | ||||||
| 
 | 
 | ||||||
| 	/* Can the device send data? */ | 	/* Can the device send data? */ | ||||||
| 	if (drvr->bus_if->state != BRCMF_BUS_DATA) { | 	if (drvr->bus_if->state != BRCMF_BUS_DATA) { | ||||||
|  | @ -179,8 +189,8 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, | ||||||
| 		goto done; | 		goto done; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (!drvr->iflist[ifp->idx]) { | 	if (!drvr->iflist[ifp->bssidx]) { | ||||||
| 		brcmf_err("bad ifidx %d\n", ifp->idx); | 		brcmf_err("bad ifidx %d\n", ifp->bssidx); | ||||||
| 		netif_stop_queue(ndev); | 		netif_stop_queue(ndev); | ||||||
| 		dev_kfree_skb(skb); | 		dev_kfree_skb(skb); | ||||||
| 		ret = -ENODEV; | 		ret = -ENODEV; | ||||||
|  | @ -192,14 +202,14 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, | ||||||
| 		struct sk_buff *skb2; | 		struct sk_buff *skb2; | ||||||
| 
 | 
 | ||||||
| 		brcmf_dbg(INFO, "%s: insufficient headroom\n", | 		brcmf_dbg(INFO, "%s: insufficient headroom\n", | ||||||
| 			  brcmf_ifname(drvr, ifp->idx)); | 			  brcmf_ifname(drvr, ifp->bssidx)); | ||||||
| 		drvr->bus_if->tx_realloc++; | 		drvr->bus_if->tx_realloc++; | ||||||
| 		skb2 = skb_realloc_headroom(skb, drvr->hdrlen); | 		skb2 = skb_realloc_headroom(skb, drvr->hdrlen); | ||||||
| 		dev_kfree_skb(skb); | 		dev_kfree_skb(skb); | ||||||
| 		skb = skb2; | 		skb = skb2; | ||||||
| 		if (skb == NULL) { | 		if (skb == NULL) { | ||||||
| 			brcmf_err("%s: skb_realloc_headroom failed\n", | 			brcmf_err("%s: skb_realloc_headroom failed\n", | ||||||
| 				  brcmf_ifname(drvr, ifp->idx)); | 				  brcmf_ifname(drvr, ifp->bssidx)); | ||||||
| 			ret = -ENOMEM; | 			ret = -ENOMEM; | ||||||
| 			goto done; | 			goto done; | ||||||
| 		} | 		} | ||||||
|  | @ -217,19 +227,21 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, | ||||||
| 	if (is_multicast_ether_addr(eh->h_dest)) | 	if (is_multicast_ether_addr(eh->h_dest)) | ||||||
| 		drvr->tx_multicast++; | 		drvr->tx_multicast++; | ||||||
| 	if (ntohs(eh->h_proto) == ETH_P_PAE) | 	if (ntohs(eh->h_proto) == ETH_P_PAE) | ||||||
| 		atomic_inc(&drvr->pend_8021x_cnt); | 		atomic_inc(&ifp->pend_8021x_cnt); | ||||||
| 
 | 
 | ||||||
| 	/* If the protocol uses a data header, apply it */ | 	/* If the protocol uses a data header, apply it */ | ||||||
| 	brcmf_proto_hdrpush(drvr, ifp->idx, skb); | 	brcmf_proto_hdrpush(drvr, ifp->ifidx, skb); | ||||||
| 
 | 
 | ||||||
| 	/* Use bus module to send data frame */ | 	/* Use bus module to send data frame */ | ||||||
| 	ret =  brcmf_bus_txdata(drvr->bus_if, skb); | 	ret =  brcmf_bus_txdata(drvr->bus_if, skb); | ||||||
| 
 | 
 | ||||||
| done: | done: | ||||||
| 	if (ret) | 	if (ret) { | ||||||
| 		drvr->bus_if->dstats.tx_dropped++; | 		ifp->stats.tx_dropped++; | ||||||
| 	else | 	} else { | ||||||
| 		drvr->bus_if->dstats.tx_packets++; | 		ifp->stats.tx_packets++; | ||||||
|  | 		ifp->stats.tx_bytes += skb->len; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Return ok: we always eat the packet */ | 	/* Return ok: we always eat the packet */ | ||||||
| 	return NETDEV_TX_OK; | 	return NETDEV_TX_OK; | ||||||
|  | @ -270,12 +282,13 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) | ||||||
| 	skb_queue_walk_safe(skb_list, skb, pnext) { | 	skb_queue_walk_safe(skb_list, skb, pnext) { | ||||||
| 		skb_unlink(skb, skb_list); | 		skb_unlink(skb, skb_list); | ||||||
| 
 | 
 | ||||||
| 		/* process and remove protocol-specific header
 | 		/* process and remove protocol-specific header */ | ||||||
| 		 */ |  | ||||||
| 		ret = brcmf_proto_hdrpull(drvr, &ifidx, skb); | 		ret = brcmf_proto_hdrpull(drvr, &ifidx, skb); | ||||||
| 		if (ret < 0) { | 		ifp = drvr->iflist[ifidx]; | ||||||
| 			if (ret != -ENODATA) | 
 | ||||||
| 				bus_if->dstats.rx_errors++; | 		if (ret || !ifp || !ifp->ndev) { | ||||||
|  | 			if ((ret != -ENODATA) && ifp) | ||||||
|  | 				ifp->stats.rx_errors++; | ||||||
| 			brcmu_pkt_buf_free_skb(skb); | 			brcmu_pkt_buf_free_skb(skb); | ||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
|  | @ -295,21 +308,11 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) | ||||||
| 		eth = skb->data; | 		eth = skb->data; | ||||||
| 		len = skb->len; | 		len = skb->len; | ||||||
| 
 | 
 | ||||||
| 		ifp = drvr->iflist[ifidx]; |  | ||||||
| 		if (ifp == NULL) |  | ||||||
| 			ifp = drvr->iflist[0]; |  | ||||||
| 
 |  | ||||||
| 		if (!ifp || !ifp->ndev || |  | ||||||
| 		    ifp->ndev->reg_state != NETREG_REGISTERED) { |  | ||||||
| 			brcmu_pkt_buf_free_skb(skb); |  | ||||||
| 			continue; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		skb->dev = ifp->ndev; | 		skb->dev = ifp->ndev; | ||||||
| 		skb->protocol = eth_type_trans(skb, skb->dev); | 		skb->protocol = eth_type_trans(skb, skb->dev); | ||||||
| 
 | 
 | ||||||
| 		if (skb->pkt_type == PACKET_MULTICAST) | 		if (skb->pkt_type == PACKET_MULTICAST) | ||||||
| 			bus_if->dstats.multicast++; | 			ifp->stats.multicast++; | ||||||
| 
 | 
 | ||||||
| 		skb->data = eth; | 		skb->data = eth; | ||||||
| 		skb->len = len; | 		skb->len = len; | ||||||
|  | @ -325,8 +328,13 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) | ||||||
| 			ifp->ndev->last_rx = jiffies; | 			ifp->ndev->last_rx = jiffies; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		bus_if->dstats.rx_bytes += skb->len; | 		if (!(ifp->ndev->flags & IFF_UP)) { | ||||||
| 		bus_if->dstats.rx_packets++;	/* Local count */ | 			brcmu_pkt_buf_free_skb(skb); | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		ifp->stats.rx_bytes += skb->len; | ||||||
|  | 		ifp->stats.rx_packets++; | ||||||
| 
 | 
 | ||||||
| 		if (in_interrupt()) | 		if (in_interrupt()) | ||||||
| 			netif_rx(skb); | 			netif_rx(skb); | ||||||
|  | @ -348,36 +356,31 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success) | ||||||
| 	u16 type; | 	u16 type; | ||||||
| 	struct brcmf_bus *bus_if = dev_get_drvdata(dev); | 	struct brcmf_bus *bus_if = dev_get_drvdata(dev); | ||||||
| 	struct brcmf_pub *drvr = bus_if->drvr; | 	struct brcmf_pub *drvr = bus_if->drvr; | ||||||
|  | 	struct brcmf_if *ifp; | ||||||
| 
 | 
 | ||||||
| 	brcmf_proto_hdrpull(drvr, &ifidx, txp); | 	brcmf_proto_hdrpull(drvr, &ifidx, txp); | ||||||
| 
 | 
 | ||||||
|  | 	ifp = drvr->iflist[ifidx]; | ||||||
|  | 	if (!ifp) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
| 	eh = (struct ethhdr *)(txp->data); | 	eh = (struct ethhdr *)(txp->data); | ||||||
| 	type = ntohs(eh->h_proto); | 	type = ntohs(eh->h_proto); | ||||||
| 
 | 
 | ||||||
| 	if (type == ETH_P_PAE) { | 	if (type == ETH_P_PAE) { | ||||||
| 		atomic_dec(&drvr->pend_8021x_cnt); | 		atomic_dec(&ifp->pend_8021x_cnt); | ||||||
| 		if (waitqueue_active(&drvr->pend_8021x_wait)) | 		if (waitqueue_active(&ifp->pend_8021x_wait)) | ||||||
| 			wake_up(&drvr->pend_8021x_wait); | 			wake_up(&ifp->pend_8021x_wait); | ||||||
| 	} | 	} | ||||||
|  | 	if (!success) | ||||||
|  | 		ifp->stats.tx_errors++; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev) | static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev) | ||||||
| { | { | ||||||
| 	struct brcmf_if *ifp = netdev_priv(ndev); | 	struct brcmf_if *ifp = netdev_priv(ndev); | ||||||
| 	struct brcmf_bus *bus_if = ifp->drvr->bus_if; |  | ||||||
| 
 | 
 | ||||||
| 	brcmf_dbg(TRACE, "Enter\n"); | 	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); | ||||||
| 
 |  | ||||||
| 	/* Copy dongle stats to net device stats */ |  | ||||||
| 	ifp->stats.rx_packets = bus_if->dstats.rx_packets; |  | ||||||
| 	ifp->stats.tx_packets = bus_if->dstats.tx_packets; |  | ||||||
| 	ifp->stats.rx_bytes = bus_if->dstats.rx_bytes; |  | ||||||
| 	ifp->stats.tx_bytes = bus_if->dstats.tx_bytes; |  | ||||||
| 	ifp->stats.rx_errors = bus_if->dstats.rx_errors; |  | ||||||
| 	ifp->stats.tx_errors = bus_if->dstats.tx_errors; |  | ||||||
| 	ifp->stats.rx_dropped = bus_if->dstats.rx_dropped; |  | ||||||
| 	ifp->stats.tx_dropped = bus_if->dstats.tx_dropped; |  | ||||||
| 	ifp->stats.multicast = bus_if->dstats.multicast; |  | ||||||
| 
 | 
 | ||||||
| 	return &ifp->stats; | 	return &ifp->stats; | ||||||
| } | } | ||||||
|  | @ -431,7 +434,7 @@ static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr) | ||||||
| 	u32 toe_cmpnt, csum_dir; | 	u32 toe_cmpnt, csum_dir; | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	brcmf_dbg(TRACE, "Enter\n"); | 	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); | ||||||
| 
 | 
 | ||||||
| 	/* all ethtool calls start with a cmd word */ | 	/* all ethtool calls start with a cmd word */ | ||||||
| 	if (copy_from_user(&cmd, uaddr, sizeof(u32))) | 	if (copy_from_user(&cmd, uaddr, sizeof(u32))) | ||||||
|  | @ -454,13 +457,7 @@ static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr) | ||||||
| 			sprintf(info.driver, "dhd"); | 			sprintf(info.driver, "dhd"); | ||||||
| 			strcpy(info.version, BRCMF_VERSION_STR); | 			strcpy(info.version, BRCMF_VERSION_STR); | ||||||
| 		} | 		} | ||||||
| 
 | 		/* report dongle driver type */ | ||||||
| 		/* otherwise, require dongle to be up */ |  | ||||||
| 		else if (!drvr->bus_if->drvr_up) { |  | ||||||
| 			brcmf_err("dongle is not up\n"); |  | ||||||
| 			return -ENODEV; |  | ||||||
| 		} |  | ||||||
| 		/* finally, report dongle driver type */ |  | ||||||
| 		else | 		else | ||||||
| 			sprintf(info.driver, "wl"); | 			sprintf(info.driver, "wl"); | ||||||
| 
 | 
 | ||||||
|  | @ -534,9 +531,9 @@ static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr, | ||||||
| 	struct brcmf_if *ifp = netdev_priv(ndev); | 	struct brcmf_if *ifp = netdev_priv(ndev); | ||||||
| 	struct brcmf_pub *drvr = ifp->drvr; | 	struct brcmf_pub *drvr = ifp->drvr; | ||||||
| 
 | 
 | ||||||
| 	brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifp->idx, cmd); | 	brcmf_dbg(TRACE, "Enter, idx=%d, cmd=0x%04x\n", ifp->bssidx, cmd); | ||||||
| 
 | 
 | ||||||
| 	if (!drvr->iflist[ifp->idx]) | 	if (!drvr->iflist[ifp->bssidx]) | ||||||
| 		return -1; | 		return -1; | ||||||
| 
 | 
 | ||||||
| 	if (cmd == SIOCETHTOOL) | 	if (cmd == SIOCETHTOOL) | ||||||
|  | @ -548,17 +545,12 @@ static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr, | ||||||
| static int brcmf_netdev_stop(struct net_device *ndev) | static int brcmf_netdev_stop(struct net_device *ndev) | ||||||
| { | { | ||||||
| 	struct brcmf_if *ifp = netdev_priv(ndev); | 	struct brcmf_if *ifp = netdev_priv(ndev); | ||||||
| 	struct brcmf_pub *drvr = ifp->drvr; |  | ||||||
| 
 | 
 | ||||||
| 	brcmf_dbg(TRACE, "Enter\n"); | 	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); | ||||||
| 
 |  | ||||||
| 	if (drvr->bus_if->drvr_up == 0) |  | ||||||
| 		return 0; |  | ||||||
| 
 | 
 | ||||||
| 	brcmf_cfg80211_down(ndev); | 	brcmf_cfg80211_down(ndev); | ||||||
| 
 | 
 | ||||||
| 	/* Set state and stop OS transmissions */ | 	/* Set state and stop OS transmissions */ | ||||||
| 	drvr->bus_if->drvr_up = false; |  | ||||||
| 	netif_stop_queue(ndev); | 	netif_stop_queue(ndev); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  | @ -572,7 +564,7 @@ static int brcmf_netdev_open(struct net_device *ndev) | ||||||
| 	u32 toe_ol; | 	u32 toe_ol; | ||||||
| 	s32 ret = 0; | 	s32 ret = 0; | ||||||
| 
 | 
 | ||||||
| 	brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx); | 	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); | ||||||
| 
 | 
 | ||||||
| 	/* If bus is not ready, can't continue */ | 	/* If bus is not ready, can't continue */ | ||||||
| 	if (bus_if->state != BRCMF_BUS_DATA) { | 	if (bus_if->state != BRCMF_BUS_DATA) { | ||||||
|  | @ -580,9 +572,7 @@ static int brcmf_netdev_open(struct net_device *ndev) | ||||||
| 		return -EAGAIN; | 		return -EAGAIN; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	atomic_set(&drvr->pend_8021x_cnt, 0); | 	atomic_set(&ifp->pend_8021x_cnt, 0); | ||||||
| 
 |  | ||||||
| 	memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN); |  | ||||||
| 
 | 
 | ||||||
| 	/* Get current TOE mode from dongle */ | 	/* Get current TOE mode from dongle */ | ||||||
| 	if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0 | 	if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0 | ||||||
|  | @ -593,7 +583,6 @@ static int brcmf_netdev_open(struct net_device *ndev) | ||||||
| 
 | 
 | ||||||
| 	/* Allow transmit calls */ | 	/* Allow transmit calls */ | ||||||
| 	netif_start_queue(ndev); | 	netif_start_queue(ndev); | ||||||
| 	drvr->bus_if->drvr_up = true; |  | ||||||
| 	if (brcmf_cfg80211_up(ndev)) { | 	if (brcmf_cfg80211_up(ndev)) { | ||||||
| 		brcmf_err("failed to bring up cfg80211\n"); | 		brcmf_err("failed to bring up cfg80211\n"); | ||||||
| 		return -1; | 		return -1; | ||||||
|  | @ -612,29 +601,18 @@ static const struct net_device_ops brcmf_netdev_ops_pri = { | ||||||
| 	.ndo_set_rx_mode = brcmf_netdev_set_multicast_list | 	.ndo_set_rx_mode = brcmf_netdev_set_multicast_list | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct net_device_ops brcmf_netdev_ops_virt = { | int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked) | ||||||
| 	.ndo_open = brcmf_cfg80211_up, |  | ||||||
| 	.ndo_stop = brcmf_cfg80211_down, |  | ||||||
| 	.ndo_get_stats = brcmf_netdev_get_stats, |  | ||||||
| 	.ndo_do_ioctl = brcmf_netdev_ioctl_entry, |  | ||||||
| 	.ndo_start_xmit = brcmf_netdev_start_xmit, |  | ||||||
| 	.ndo_set_mac_address = brcmf_netdev_set_mac_address, |  | ||||||
| 	.ndo_set_rx_mode = brcmf_netdev_set_multicast_list |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| int brcmf_net_attach(struct brcmf_if *ifp) |  | ||||||
| { | { | ||||||
| 	struct brcmf_pub *drvr = ifp->drvr; | 	struct brcmf_pub *drvr = ifp->drvr; | ||||||
| 	struct net_device *ndev; | 	struct net_device *ndev; | ||||||
|  | 	s32 err; | ||||||
| 
 | 
 | ||||||
| 	brcmf_dbg(TRACE, "ifidx %d mac %pM\n", ifp->idx, ifp->mac_addr); | 	brcmf_dbg(TRACE, "Enter, idx=%d mac=%pM\n", ifp->bssidx, | ||||||
|  | 		  ifp->mac_addr); | ||||||
| 	ndev = ifp->ndev; | 	ndev = ifp->ndev; | ||||||
| 
 | 
 | ||||||
| 	/* set appropriate operations */ | 	/* set appropriate operations */ | ||||||
| 	if (!ifp->idx) |  | ||||||
| 	ndev->netdev_ops = &brcmf_netdev_ops_pri; | 	ndev->netdev_ops = &brcmf_netdev_ops_pri; | ||||||
| 	else |  | ||||||
| 		ndev->netdev_ops = &brcmf_netdev_ops_virt; |  | ||||||
| 
 | 
 | ||||||
| 	ndev->hard_header_len = ETH_HLEN + drvr->hdrlen; | 	ndev->hard_header_len = ETH_HLEN + drvr->hdrlen; | ||||||
| 	ndev->ethtool_ops = &brcmf_ethtool_ops; | 	ndev->ethtool_ops = &brcmf_ethtool_ops; | ||||||
|  | @ -645,7 +623,14 @@ int brcmf_net_attach(struct brcmf_if *ifp) | ||||||
| 	/* set the mac address */ | 	/* set the mac address */ | ||||||
| 	memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN); | 	memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN); | ||||||
| 
 | 
 | ||||||
| 	if (register_netdev(ndev) != 0) { | 	INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address); | ||||||
|  | 	INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list); | ||||||
|  | 
 | ||||||
|  | 	if (rtnl_locked) | ||||||
|  | 		err = register_netdevice(ndev); | ||||||
|  | 	else | ||||||
|  | 		err = register_netdev(ndev); | ||||||
|  | 	if (err != 0) { | ||||||
| 		brcmf_err("couldn't register the net device\n"); | 		brcmf_err("couldn't register the net device\n"); | ||||||
| 		goto fail; | 		goto fail; | ||||||
| 	} | 	} | ||||||
|  | @ -659,16 +644,78 @@ fail: | ||||||
| 	return -EBADE; | 	return -EBADE; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx, | static int brcmf_net_p2p_open(struct net_device *ndev) | ||||||
| 			      char *name, u8 *addr_mask) | { | ||||||
|  | 	brcmf_dbg(TRACE, "Enter\n"); | ||||||
|  | 
 | ||||||
|  | 	return brcmf_cfg80211_up(ndev); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int brcmf_net_p2p_stop(struct net_device *ndev) | ||||||
|  | { | ||||||
|  | 	brcmf_dbg(TRACE, "Enter\n"); | ||||||
|  | 
 | ||||||
|  | 	return brcmf_cfg80211_down(ndev); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int brcmf_net_p2p_do_ioctl(struct net_device *ndev, | ||||||
|  | 				  struct ifreq *ifr, int cmd) | ||||||
|  | { | ||||||
|  | 	brcmf_dbg(TRACE, "Enter\n"); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static netdev_tx_t brcmf_net_p2p_start_xmit(struct sk_buff *skb, | ||||||
|  | 					    struct net_device *ndev) | ||||||
|  | { | ||||||
|  | 	if (skb) | ||||||
|  | 		dev_kfree_skb_any(skb); | ||||||
|  | 
 | ||||||
|  | 	return NETDEV_TX_OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static const struct net_device_ops brcmf_netdev_ops_p2p = { | ||||||
|  | 	.ndo_open = brcmf_net_p2p_open, | ||||||
|  | 	.ndo_stop = brcmf_net_p2p_stop, | ||||||
|  | 	.ndo_do_ioctl = brcmf_net_p2p_do_ioctl, | ||||||
|  | 	.ndo_start_xmit = brcmf_net_p2p_start_xmit | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static int brcmf_net_p2p_attach(struct brcmf_if *ifp) | ||||||
|  | { | ||||||
|  | 	struct net_device *ndev; | ||||||
|  | 
 | ||||||
|  | 	brcmf_dbg(TRACE, "Enter, idx=%d mac=%pM\n", ifp->bssidx, | ||||||
|  | 		  ifp->mac_addr); | ||||||
|  | 	ndev = ifp->ndev; | ||||||
|  | 
 | ||||||
|  | 	ndev->netdev_ops = &brcmf_netdev_ops_p2p; | ||||||
|  | 
 | ||||||
|  | 	/* set the mac address */ | ||||||
|  | 	memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN); | ||||||
|  | 
 | ||||||
|  | 	if (register_netdev(ndev) != 0) { | ||||||
|  | 		brcmf_err("couldn't register the p2p net device\n"); | ||||||
|  | 		goto fail; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | 
 | ||||||
|  | fail: | ||||||
|  | 	return -EBADE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, | ||||||
|  | 			      char *name, u8 *mac_addr) | ||||||
| { | { | ||||||
| 	struct brcmf_if *ifp; | 	struct brcmf_if *ifp; | ||||||
| 	struct net_device *ndev; | 	struct net_device *ndev; | ||||||
| 	int i; |  | ||||||
| 
 | 
 | ||||||
| 	brcmf_dbg(TRACE, "idx %d\n", ifidx); | 	brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifidx); | ||||||
| 
 | 
 | ||||||
| 	ifp = drvr->iflist[ifidx]; | 	ifp = drvr->iflist[bssidx]; | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Delete the existing interface before overwriting it | 	 * Delete the existing interface before overwriting it | ||||||
| 	 * in case we missed the BRCMF_E_IF_DEL event. | 	 * in case we missed the BRCMF_E_IF_DEL event. | ||||||
|  | @ -680,7 +727,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx, | ||||||
| 			netif_stop_queue(ifp->ndev); | 			netif_stop_queue(ifp->ndev); | ||||||
| 			unregister_netdev(ifp->ndev); | 			unregister_netdev(ifp->ndev); | ||||||
| 			free_netdev(ifp->ndev); | 			free_netdev(ifp->ndev); | ||||||
| 			drvr->iflist[ifidx] = NULL; | 			drvr->iflist[bssidx] = NULL; | ||||||
| 		} else { | 		} else { | ||||||
| 			brcmf_err("ignore IF event\n"); | 			brcmf_err("ignore IF event\n"); | ||||||
| 			return ERR_PTR(-EINVAL); | 			return ERR_PTR(-EINVAL); | ||||||
|  | @ -697,16 +744,15 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx, | ||||||
| 	ifp = netdev_priv(ndev); | 	ifp = netdev_priv(ndev); | ||||||
| 	ifp->ndev = ndev; | 	ifp->ndev = ndev; | ||||||
| 	ifp->drvr = drvr; | 	ifp->drvr = drvr; | ||||||
| 	drvr->iflist[ifidx] = ifp; | 	drvr->iflist[bssidx] = ifp; | ||||||
| 	ifp->idx = ifidx; | 	ifp->ifidx = ifidx; | ||||||
| 	ifp->bssidx = bssidx; | 	ifp->bssidx = bssidx; | ||||||
| 
 | 
 | ||||||
| 	INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address); |  | ||||||
| 	INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list); |  | ||||||
| 
 | 
 | ||||||
| 	if (addr_mask != NULL) | 	init_waitqueue_head(&ifp->pend_8021x_wait); | ||||||
| 		for (i = 0; i < ETH_ALEN; i++) | 
 | ||||||
| 			ifp->mac_addr[i] = drvr->mac[i] ^ addr_mask[i]; | 	if (mac_addr != NULL) | ||||||
|  | 		memcpy(ifp->mac_addr, mac_addr, ETH_ALEN); | ||||||
| 
 | 
 | ||||||
| 	brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n", | 	brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n", | ||||||
| 		  current->pid, ifp->ndev->name, ifp->mac_addr); | 		  current->pid, ifp->ndev->name, ifp->mac_addr); | ||||||
|  | @ -714,19 +760,18 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx, | ||||||
| 	return ifp; | 	return ifp; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void brcmf_del_if(struct brcmf_pub *drvr, int ifidx) | void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx) | ||||||
| { | { | ||||||
| 	struct brcmf_if *ifp; | 	struct brcmf_if *ifp; | ||||||
| 
 | 
 | ||||||
| 	brcmf_dbg(TRACE, "idx %d\n", ifidx); | 	ifp = drvr->iflist[bssidx]; | ||||||
| 
 |  | ||||||
| 	ifp = drvr->iflist[ifidx]; |  | ||||||
| 	if (!ifp) { | 	if (!ifp) { | ||||||
| 		brcmf_err("Null interface\n"); | 		brcmf_err("Null interface, idx=%d\n", bssidx); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
|  | 	brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifp->ifidx); | ||||||
| 	if (ifp->ndev) { | 	if (ifp->ndev) { | ||||||
| 		if (ifidx == 0) { | 		if (bssidx == 0) { | ||||||
| 			if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { | 			if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { | ||||||
| 				rtnl_lock(); | 				rtnl_lock(); | ||||||
| 				brcmf_netdev_stop(ifp->ndev); | 				brcmf_netdev_stop(ifp->ndev); | ||||||
|  | @ -736,12 +781,14 @@ void brcmf_del_if(struct brcmf_pub *drvr, int ifidx) | ||||||
| 			netif_stop_queue(ifp->ndev); | 			netif_stop_queue(ifp->ndev); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { | ||||||
| 			cancel_work_sync(&ifp->setmacaddr_work); | 			cancel_work_sync(&ifp->setmacaddr_work); | ||||||
| 			cancel_work_sync(&ifp->multicast_work); | 			cancel_work_sync(&ifp->multicast_work); | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		unregister_netdev(ifp->ndev); | 		unregister_netdev(ifp->ndev); | ||||||
| 		drvr->iflist[ifidx] = NULL; | 		drvr->iflist[bssidx] = NULL; | ||||||
| 		if (ifidx == 0) | 		if (bssidx == 0) | ||||||
| 			brcmf_cfg80211_detach(drvr->config); | 			brcmf_cfg80211_detach(drvr->config); | ||||||
| 		free_netdev(ifp->ndev); | 		free_netdev(ifp->ndev); | ||||||
| 	} | 	} | ||||||
|  | @ -781,8 +828,6 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev) | ||||||
| 
 | 
 | ||||||
| 	INIT_LIST_HEAD(&drvr->bus_if->dcmd_list); | 	INIT_LIST_HEAD(&drvr->bus_if->dcmd_list); | ||||||
| 
 | 
 | ||||||
| 	init_waitqueue_head(&drvr->pend_8021x_wait); |  | ||||||
| 
 |  | ||||||
| 	return ret; | 	return ret; | ||||||
| 
 | 
 | ||||||
| fail: | fail: | ||||||
|  | @ -797,6 +842,7 @@ int brcmf_bus_start(struct device *dev) | ||||||
| 	struct brcmf_bus *bus_if = dev_get_drvdata(dev); | 	struct brcmf_bus *bus_if = dev_get_drvdata(dev); | ||||||
| 	struct brcmf_pub *drvr = bus_if->drvr; | 	struct brcmf_pub *drvr = bus_if->drvr; | ||||||
| 	struct brcmf_if *ifp; | 	struct brcmf_if *ifp; | ||||||
|  | 	struct brcmf_if *p2p_ifp; | ||||||
| 
 | 
 | ||||||
| 	brcmf_dbg(TRACE, "\n"); | 	brcmf_dbg(TRACE, "\n"); | ||||||
| 
 | 
 | ||||||
|  | @ -812,6 +858,13 @@ int brcmf_bus_start(struct device *dev) | ||||||
| 	if (IS_ERR(ifp)) | 	if (IS_ERR(ifp)) | ||||||
| 		return PTR_ERR(ifp); | 		return PTR_ERR(ifp); | ||||||
| 
 | 
 | ||||||
|  | 	if (brcmf_p2p_enable) | ||||||
|  | 		p2p_ifp = brcmf_add_if(drvr, 1, 0, "p2p%d", NULL); | ||||||
|  | 	else | ||||||
|  | 		p2p_ifp = NULL; | ||||||
|  | 	if (IS_ERR(p2p_ifp)) | ||||||
|  | 		p2p_ifp = NULL; | ||||||
|  | 
 | ||||||
| 	/* signal bus ready */ | 	/* signal bus ready */ | ||||||
| 	bus_if->state = BRCMF_BUS_DATA; | 	bus_if->state = BRCMF_BUS_DATA; | ||||||
| 
 | 
 | ||||||
|  | @ -830,16 +883,22 @@ int brcmf_bus_start(struct device *dev) | ||||||
| 	if (ret < 0) | 	if (ret < 0) | ||||||
| 		goto fail; | 		goto fail; | ||||||
| 
 | 
 | ||||||
| 	ret = brcmf_net_attach(ifp); | 	ret = brcmf_net_attach(ifp, false); | ||||||
| fail: | fail: | ||||||
| 	if (ret < 0) { | 	if (ret < 0) { | ||||||
| 		brcmf_err("failed: %d\n", ret); | 		brcmf_err("failed: %d\n", ret); | ||||||
| 		if (drvr->config) | 		if (drvr->config) | ||||||
| 			brcmf_cfg80211_detach(drvr->config); | 			brcmf_cfg80211_detach(drvr->config); | ||||||
| 		free_netdev(drvr->iflist[0]->ndev); | 		free_netdev(ifp->ndev); | ||||||
| 		drvr->iflist[0] = NULL; | 		drvr->iflist[0] = NULL; | ||||||
|  | 		if (p2p_ifp) { | ||||||
|  | 			free_netdev(p2p_ifp->ndev); | ||||||
|  | 			drvr->iflist[1] = NULL; | ||||||
|  | 		} | ||||||
| 		return ret; | 		return ret; | ||||||
| 	} | 	} | ||||||
|  | 	if ((brcmf_p2p_enable) && (p2p_ifp)) | ||||||
|  | 		brcmf_net_p2p_attach(p2p_ifp); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | @ -865,12 +924,13 @@ void brcmf_dev_reset(struct device *dev) | ||||||
| 	if (drvr == NULL) | 	if (drvr == NULL) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
|  | 	if (drvr->iflist[0]) | ||||||
| 		brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1); | 		brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void brcmf_detach(struct device *dev) | void brcmf_detach(struct device *dev) | ||||||
| { | { | ||||||
| 	int i; | 	s32 i; | ||||||
| 	struct brcmf_bus *bus_if = dev_get_drvdata(dev); | 	struct brcmf_bus *bus_if = dev_get_drvdata(dev); | ||||||
| 	struct brcmf_pub *drvr = bus_if->drvr; | 	struct brcmf_pub *drvr = bus_if->drvr; | ||||||
| 
 | 
 | ||||||
|  | @ -897,19 +957,18 @@ void brcmf_detach(struct device *dev) | ||||||
| 	kfree(drvr); | 	kfree(drvr); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int brcmf_get_pend_8021x_cnt(struct brcmf_pub *drvr) | static int brcmf_get_pend_8021x_cnt(struct brcmf_if *ifp) | ||||||
| { | { | ||||||
| 	return atomic_read(&drvr->pend_8021x_cnt); | 	return atomic_read(&ifp->pend_8021x_cnt); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int brcmf_netdev_wait_pend8021x(struct net_device *ndev) | int brcmf_netdev_wait_pend8021x(struct net_device *ndev) | ||||||
| { | { | ||||||
| 	struct brcmf_if *ifp = netdev_priv(ndev); | 	struct brcmf_if *ifp = netdev_priv(ndev); | ||||||
| 	struct brcmf_pub *drvr = ifp->drvr; |  | ||||||
| 	int err; | 	int err; | ||||||
| 
 | 
 | ||||||
| 	err = wait_event_timeout(drvr->pend_8021x_wait, | 	err = wait_event_timeout(ifp->pend_8021x_wait, | ||||||
| 				 !brcmf_get_pend_8021x_cnt(drvr), | 				 !brcmf_get_pend_8021x_cnt(ifp), | ||||||
| 				 msecs_to_jiffies(MAX_WAIT_FOR_8021X_TX)); | 				 msecs_to_jiffies(MAX_WAIT_FOR_8021X_TX)); | ||||||
| 
 | 
 | ||||||
| 	WARN_ON(!err); | 	WARN_ON(!err); | ||||||
|  | @ -917,6 +976,16 @@ int brcmf_netdev_wait_pend8021x(struct net_device *ndev) | ||||||
| 	return !err; | 	return !err; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * return chip id and rev of the device encoded in u32. | ||||||
|  |  */ | ||||||
|  | u32 brcmf_get_chip_info(struct brcmf_if *ifp) | ||||||
|  | { | ||||||
|  | 	struct brcmf_bus *bus = ifp->drvr->bus_if; | ||||||
|  | 
 | ||||||
|  | 	return bus->chip << 4 | bus->chiprev; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void brcmf_driver_init(struct work_struct *work) | static void brcmf_driver_init(struct work_struct *work) | ||||||
| { | { | ||||||
| 	brcmf_debugfs_init(); | 	brcmf_debugfs_init(); | ||||||
|  |  | ||||||
|  | @ -1096,7 +1096,6 @@ static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, | ||||||
| 	if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL && | 	if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL && | ||||||
| 	    type != BRCMF_SDIO_FT_SUPER) { | 	    type != BRCMF_SDIO_FT_SUPER) { | ||||||
| 		brcmf_err("HW header length too long\n"); | 		brcmf_err("HW header length too long\n"); | ||||||
| 		bus->sdiodev->bus_if->dstats.rx_errors++; |  | ||||||
| 		bus->sdcnt.rx_toolong++; | 		bus->sdcnt.rx_toolong++; | ||||||
| 		brcmf_sdbrcm_rxfail(bus, false, false); | 		brcmf_sdbrcm_rxfail(bus, false, false); | ||||||
| 		rd->len = 0; | 		rd->len = 0; | ||||||
|  | @ -1298,7 +1297,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) | ||||||
| 		if (errcode < 0) { | 		if (errcode < 0) { | ||||||
| 			brcmf_err("glom read of %d bytes failed: %d\n", | 			brcmf_err("glom read of %d bytes failed: %d\n", | ||||||
| 				  dlen, errcode); | 				  dlen, errcode); | ||||||
| 			bus->sdiodev->bus_if->dstats.rx_errors++; |  | ||||||
| 
 | 
 | ||||||
| 			sdio_claim_host(bus->sdiodev->func[1]); | 			sdio_claim_host(bus->sdiodev->func[1]); | ||||||
| 			if (bus->glomerr++ < 3) { | 			if (bus->glomerr++ < 3) { | ||||||
|  | @ -1477,7 +1475,6 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff) | ||||||
| 	if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) { | 	if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) { | ||||||
| 		brcmf_err("%d-byte control read exceeds %d-byte buffer\n", | 		brcmf_err("%d-byte control read exceeds %d-byte buffer\n", | ||||||
| 			  rdlen, bus->sdiodev->bus_if->maxctl); | 			  rdlen, bus->sdiodev->bus_if->maxctl); | ||||||
| 		bus->sdiodev->bus_if->dstats.rx_errors++; |  | ||||||
| 		brcmf_sdbrcm_rxfail(bus, false, false); | 		brcmf_sdbrcm_rxfail(bus, false, false); | ||||||
| 		goto done; | 		goto done; | ||||||
| 	} | 	} | ||||||
|  | @ -1485,7 +1482,6 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff) | ||||||
| 	if ((len - doff) > bus->sdiodev->bus_if->maxctl) { | 	if ((len - doff) > bus->sdiodev->bus_if->maxctl) { | ||||||
| 		brcmf_err("%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n", | 		brcmf_err("%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n", | ||||||
| 			  len, len - doff, bus->sdiodev->bus_if->maxctl); | 			  len, len - doff, bus->sdiodev->bus_if->maxctl); | ||||||
| 		bus->sdiodev->bus_if->dstats.rx_errors++; |  | ||||||
| 		bus->sdcnt.rx_toolong++; | 		bus->sdcnt.rx_toolong++; | ||||||
| 		brcmf_sdbrcm_rxfail(bus, false, false); | 		brcmf_sdbrcm_rxfail(bus, false, false); | ||||||
| 		goto done; | 		goto done; | ||||||
|  | @ -1633,7 +1629,6 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) | ||||||
| 		if (!pkt) { | 		if (!pkt) { | ||||||
| 			/* Give up on data, request rtx of events */ | 			/* Give up on data, request rtx of events */ | ||||||
| 			brcmf_err("brcmu_pkt_buf_get_skb failed\n"); | 			brcmf_err("brcmu_pkt_buf_get_skb failed\n"); | ||||||
| 			bus->sdiodev->bus_if->dstats.rx_dropped++; |  | ||||||
| 			brcmf_sdbrcm_rxfail(bus, false, | 			brcmf_sdbrcm_rxfail(bus, false, | ||||||
| 					    RETRYCHAN(rd->channel)); | 					    RETRYCHAN(rd->channel)); | ||||||
| 			sdio_release_host(bus->sdiodev->func[1]); | 			sdio_release_host(bus->sdiodev->func[1]); | ||||||
|  | @ -1651,7 +1646,6 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) | ||||||
| 			brcmf_err("read %d bytes from channel %d failed: %d\n", | 			brcmf_err("read %d bytes from channel %d failed: %d\n", | ||||||
| 				  rd->len, rd->channel, sdret); | 				  rd->len, rd->channel, sdret); | ||||||
| 			brcmu_pkt_buf_free_skb(pkt); | 			brcmu_pkt_buf_free_skb(pkt); | ||||||
| 			bus->sdiodev->bus_if->dstats.rx_errors++; |  | ||||||
| 			sdio_claim_host(bus->sdiodev->func[1]); | 			sdio_claim_host(bus->sdiodev->func[1]); | ||||||
| 			brcmf_sdbrcm_rxfail(bus, true, | 			brcmf_sdbrcm_rxfail(bus, true, | ||||||
| 					    RETRYCHAN(rd->channel)); | 					    RETRYCHAN(rd->channel)); | ||||||
|  | @ -1939,10 +1933,6 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) | ||||||
| 		datalen = pkt->len - SDPCM_HDRLEN; | 		datalen = pkt->len - SDPCM_HDRLEN; | ||||||
| 
 | 
 | ||||||
| 		ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true); | 		ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true); | ||||||
| 		if (ret) |  | ||||||
| 			bus->sdiodev->bus_if->dstats.tx_errors++; |  | ||||||
| 		else |  | ||||||
| 			bus->sdiodev->bus_if->dstats.tx_bytes += datalen; |  | ||||||
| 
 | 
 | ||||||
| 		/* In poll mode, need to check for other events */ | 		/* In poll mode, need to check for other events */ | ||||||
| 		if (!bus->intr && cnt) { | 		if (!bus->intr && cnt) { | ||||||
|  | @ -1961,8 +1951,7 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Deflow-control stack if needed */ | 	/* Deflow-control stack if needed */ | ||||||
| 	if (bus->sdiodev->bus_if->drvr_up && | 	if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) && | ||||||
| 	    (bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) && |  | ||||||
| 	    bus->txoff && (pktq_len(&bus->txq) < TXLOW)) { | 	    bus->txoff && (pktq_len(&bus->txq) < TXLOW)) { | ||||||
| 		bus->txoff = false; | 		bus->txoff = false; | ||||||
| 		brcmf_txflowblock(bus->sdiodev->dev, false); | 		brcmf_txflowblock(bus->sdiodev->dev, false); | ||||||
|  | @ -2709,9 +2698,10 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus, | ||||||
| 	 * address of sdpcm_shared structure | 	 * address of sdpcm_shared structure | ||||||
| 	 */ | 	 */ | ||||||
| 	sdio_claim_host(bus->sdiodev->func[1]); | 	sdio_claim_host(bus->sdiodev->func[1]); | ||||||
|  | 	brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); | ||||||
| 	rv = brcmf_sdbrcm_membytes(bus, false, shaddr, | 	rv = brcmf_sdbrcm_membytes(bus, false, shaddr, | ||||||
| 				   (u8 *)&addr_le, 4); | 				   (u8 *)&addr_le, 4); | ||||||
| 	sdio_claim_host(bus->sdiodev->func[1]); | 	sdio_release_host(bus->sdiodev->func[1]); | ||||||
| 	if (rv < 0) | 	if (rv < 0) | ||||||
| 		return rv; | 		return rv; | ||||||
| 
 | 
 | ||||||
|  | @ -2730,10 +2720,8 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Read hndrte_shared structure */ | 	/* Read hndrte_shared structure */ | ||||||
| 	sdio_claim_host(bus->sdiodev->func[1]); |  | ||||||
| 	rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le, | 	rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le, | ||||||
| 				   sizeof(struct sdpcm_shared_le)); | 				   sizeof(struct sdpcm_shared_le)); | ||||||
| 	sdio_release_host(bus->sdiodev->func[1]); |  | ||||||
| 	if (rv < 0) | 	if (rv < 0) | ||||||
| 		return rv; | 		return rv; | ||||||
| 
 | 
 | ||||||
|  | @ -2835,14 +2823,12 @@ static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh, | ||||||
| 	if ((sh->flags & SDPCM_SHARED_TRAP) == 0) | 	if ((sh->flags & SDPCM_SHARED_TRAP) == 0) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	sdio_claim_host(bus->sdiodev->func[1]); |  | ||||||
| 	error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr, | 	error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr, | ||||||
| 				      sizeof(struct brcmf_trap_info)); | 				      sizeof(struct brcmf_trap_info)); | ||||||
| 	if (error < 0) | 	if (error < 0) | ||||||
| 		return error; | 		return error; | ||||||
| 
 | 
 | ||||||
| 	nbytes = brcmf_sdio_dump_console(bus, sh, data, count); | 	nbytes = brcmf_sdio_dump_console(bus, sh, data, count); | ||||||
| 	sdio_release_host(bus->sdiodev->func[1]); |  | ||||||
| 	if (nbytes < 0) | 	if (nbytes < 0) | ||||||
| 		return nbytes; | 		return nbytes; | ||||||
| 
 | 
 | ||||||
|  | @ -3307,9 +3293,6 @@ static int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus) | ||||||
| { | { | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	if (bus->sdiodev->bus_if->drvr_up) |  | ||||||
| 		return -EISCONN; |  | ||||||
| 
 |  | ||||||
| 	ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME, | 	ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME, | ||||||
| 			       &bus->sdiodev->func[2]->dev); | 			       &bus->sdiodev->func[2]->dev); | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
|  | @ -3940,6 +3923,8 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) | ||||||
| 	/* Assign bus interface call back */ | 	/* Assign bus interface call back */ | ||||||
| 	bus->sdiodev->bus_if->dev = bus->sdiodev->dev; | 	bus->sdiodev->bus_if->dev = bus->sdiodev->dev; | ||||||
| 	bus->sdiodev->bus_if->ops = &brcmf_sdio_bus_ops; | 	bus->sdiodev->bus_if->ops = &brcmf_sdio_bus_ops; | ||||||
|  | 	bus->sdiodev->bus_if->chip = bus->ci->chip; | ||||||
|  | 	bus->sdiodev->bus_if->chiprev = bus->ci->chiprev; | ||||||
| 
 | 
 | ||||||
| 	/* Attach to the brcmf/OS/network interface */ | 	/* Attach to the brcmf/OS/network interface */ | ||||||
| 	ret = brcmf_attach(SDPCM_RESERVE, bus->sdiodev->dev); | 	ret = brcmf_attach(SDPCM_RESERVE, bus->sdiodev->dev); | ||||||
|  |  | ||||||
|  | @ -189,24 +189,24 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ifp = drvr->iflist[ifevent->ifidx]; | 	ifp = drvr->iflist[ifevent->bssidx]; | ||||||
| 
 | 
 | ||||||
| 	if (ifevent->action == BRCMF_E_IF_ADD) { | 	if (ifevent->action == BRCMF_E_IF_ADD) { | ||||||
| 		brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname, | 		brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname, | ||||||
| 			  emsg->addr); | 			  emsg->addr); | ||||||
| 		ifp = brcmf_add_if(drvr, ifevent->ifidx, ifevent->bssidx, | 		ifp = brcmf_add_if(drvr, ifevent->bssidx, ifevent->ifidx, | ||||||
| 				   emsg->ifname, emsg->addr); | 				   emsg->ifname, emsg->addr); | ||||||
| 		if (IS_ERR(ifp)) | 		if (IS_ERR(ifp)) | ||||||
| 			return; | 			return; | ||||||
| 
 | 
 | ||||||
| 		if (!drvr->fweh.evt_handler[BRCMF_E_IF]) | 		if (!drvr->fweh.evt_handler[BRCMF_E_IF]) | ||||||
| 			err = brcmf_net_attach(ifp); | 			err = brcmf_net_attach(ifp, false); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data); | 	err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data); | ||||||
| 
 | 
 | ||||||
| 	if (ifevent->action == BRCMF_E_IF_DEL) | 	if (ifevent->action == BRCMF_E_IF_DEL) | ||||||
| 		brcmf_del_if(drvr, ifevent->ifidx); | 		brcmf_del_if(drvr, ifevent->bssidx); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -250,8 +250,6 @@ static void brcmf_fweh_event_worker(struct work_struct *work) | ||||||
| 	drvr = container_of(fweh, struct brcmf_pub, fweh); | 	drvr = container_of(fweh, struct brcmf_pub, fweh); | ||||||
| 
 | 
 | ||||||
| 	while ((event = brcmf_fweh_dequeue_event(fweh))) { | 	while ((event = brcmf_fweh_dequeue_event(fweh))) { | ||||||
| 		ifp = drvr->iflist[event->ifidx]; |  | ||||||
| 
 |  | ||||||
| 		brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM\n", | 		brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM\n", | ||||||
| 			  brcmf_fweh_event_name(event->code), event->code, | 			  brcmf_fweh_event_name(event->code), event->code, | ||||||
| 			  event->emsg.ifidx, event->emsg.bsscfgidx, | 			  event->emsg.ifidx, event->emsg.bsscfgidx, | ||||||
|  | @ -283,6 +281,7 @@ static void brcmf_fweh_event_worker(struct work_struct *work) | ||||||
| 			goto event_free; | 			goto event_free; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		ifp = drvr->iflist[emsg.bsscfgidx]; | ||||||
| 		err = brcmf_fweh_call_event_handler(ifp, event->code, &emsg, | 		err = brcmf_fweh_call_event_handler(ifp, event->code, &emsg, | ||||||
| 						    event->data); | 						    event->data); | ||||||
| 		if (err) { | 		if (err) { | ||||||
|  |  | ||||||
|  | @ -83,6 +83,7 @@ struct brcmf_event; | ||||||
| 	BRCMF_ENUM_DEF(MULTICAST_DECODE_ERROR, 51) \ | 	BRCMF_ENUM_DEF(MULTICAST_DECODE_ERROR, 51) \ | ||||||
| 	BRCMF_ENUM_DEF(TRACE, 52) \ | 	BRCMF_ENUM_DEF(TRACE, 52) \ | ||||||
| 	BRCMF_ENUM_DEF(IF, 54) \ | 	BRCMF_ENUM_DEF(IF, 54) \ | ||||||
|  | 	BRCMF_ENUM_DEF(P2P_DISC_LISTEN_COMPLETE, 55) \ | ||||||
| 	BRCMF_ENUM_DEF(RSSI, 56) \ | 	BRCMF_ENUM_DEF(RSSI, 56) \ | ||||||
| 	BRCMF_ENUM_DEF(PFN_SCAN_COMPLETE, 57) \ | 	BRCMF_ENUM_DEF(PFN_SCAN_COMPLETE, 57) \ | ||||||
| 	BRCMF_ENUM_DEF(EXTLOG_MSG, 58) \ | 	BRCMF_ENUM_DEF(EXTLOG_MSG, 58) \ | ||||||
|  | @ -96,8 +97,11 @@ struct brcmf_event; | ||||||
| 	BRCMF_ENUM_DEF(DFS_AP_RESUME, 66) \ | 	BRCMF_ENUM_DEF(DFS_AP_RESUME, 66) \ | ||||||
| 	BRCMF_ENUM_DEF(ESCAN_RESULT, 69) \ | 	BRCMF_ENUM_DEF(ESCAN_RESULT, 69) \ | ||||||
| 	BRCMF_ENUM_DEF(ACTION_FRAME_OFF_CHAN_COMPLETE, 70) \ | 	BRCMF_ENUM_DEF(ACTION_FRAME_OFF_CHAN_COMPLETE, 70) \ | ||||||
|  | 	BRCMF_ENUM_DEF(PROBERESP_MSG, 71) \ | ||||||
|  | 	BRCMF_ENUM_DEF(P2P_PROBEREQ_MSG, 72) \ | ||||||
| 	BRCMF_ENUM_DEF(DCS_REQUEST, 73) \ | 	BRCMF_ENUM_DEF(DCS_REQUEST, 73) \ | ||||||
| 	BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) | 	BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \ | ||||||
|  | 	BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75) | ||||||
| 
 | 
 | ||||||
| #define BRCMF_ENUM_DEF(id, val) \ | #define BRCMF_ENUM_DEF(id, val) \ | ||||||
| 	BRCMF_E_##id = (val), | 	BRCMF_E_##id = (val), | ||||||
|  |  | ||||||
|  | @ -45,9 +45,10 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set) | ||||||
| 	if (data != NULL) | 	if (data != NULL) | ||||||
| 		len = min_t(uint, len, BRCMF_DCMD_MAXLEN); | 		len = min_t(uint, len, BRCMF_DCMD_MAXLEN); | ||||||
| 	if (set) | 	if (set) | ||||||
| 		err = brcmf_proto_cdc_set_dcmd(drvr, ifp->idx, cmd, data, len); | 		err = brcmf_proto_cdc_set_dcmd(drvr, ifp->ifidx, cmd, data, | ||||||
|  | 					       len); | ||||||
| 	else | 	else | ||||||
| 		err = brcmf_proto_cdc_query_dcmd(drvr, ifp->idx, cmd, data, | 		err = brcmf_proto_cdc_query_dcmd(drvr, ifp->ifidx, cmd, data, | ||||||
| 						 len); | 						 len); | ||||||
| 
 | 
 | ||||||
| 	if (err >= 0) | 	if (err >= 0) | ||||||
|  | @ -100,6 +101,7 @@ brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data) | ||||||
| 	__le32 data_le = cpu_to_le32(data); | 	__le32 data_le = cpu_to_le32(data); | ||||||
| 
 | 
 | ||||||
| 	mutex_lock(&ifp->drvr->proto_block); | 	mutex_lock(&ifp->drvr->proto_block); | ||||||
|  | 	brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, data); | ||||||
| 	err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true); | 	err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true); | ||||||
| 	mutex_unlock(&ifp->drvr->proto_block); | 	mutex_unlock(&ifp->drvr->proto_block); | ||||||
| 
 | 
 | ||||||
|  | @ -116,6 +118,7 @@ brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data) | ||||||
| 	err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false); | 	err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false); | ||||||
| 	mutex_unlock(&ifp->drvr->proto_block); | 	mutex_unlock(&ifp->drvr->proto_block); | ||||||
| 	*data = le32_to_cpu(data_le); | 	*data = le32_to_cpu(data_le); | ||||||
|  | 	brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, *data); | ||||||
| 
 | 
 | ||||||
| 	return err; | 	return err; | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										66
									
								
								drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,66 @@ | ||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2012 Broadcom Corporation | ||||||
|  |  * | ||||||
|  |  * Permission to use, copy, modify, and/or distribute this software for any | ||||||
|  |  * purpose with or without fee is hereby granted, provided that the above | ||||||
|  |  * copyright notice and this permission notice appear in all copies. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||||
|  |  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||||
|  |  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||||||
|  |  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||||
|  |  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||||||
|  |  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||||||
|  |  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #ifndef FWIL_TYPES_H_ | ||||||
|  | #define FWIL_TYPES_H_ | ||||||
|  | 
 | ||||||
|  | #include <linux/if_ether.h> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #define BRCMF_FIL_ACTION_FRAME_SIZE	1800 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | enum brcmf_fil_p2p_if_types { | ||||||
|  | 	BRCMF_FIL_P2P_IF_CLIENT, | ||||||
|  | 	BRCMF_FIL_P2P_IF_GO, | ||||||
|  | 	BRCMF_FIL_P2P_IF_DYNBCN_GO, | ||||||
|  | 	BRCMF_FIL_P2P_IF_DEV, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct brcmf_fil_p2p_if_le { | ||||||
|  | 	u8 addr[ETH_ALEN]; | ||||||
|  | 	__le16 type; | ||||||
|  | 	__le16 chspec; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct brcmf_fil_chan_info_le { | ||||||
|  | 	__le32 hw_channel; | ||||||
|  | 	__le32 target_channel; | ||||||
|  | 	__le32 scan_channel; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct brcmf_fil_action_frame_le { | ||||||
|  | 	u8	da[ETH_ALEN]; | ||||||
|  | 	__le16	len; | ||||||
|  | 	__le32	packet_id; | ||||||
|  | 	u8	data[BRCMF_FIL_ACTION_FRAME_SIZE]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct brcmf_fil_af_params_le { | ||||||
|  | 	__le32					channel; | ||||||
|  | 	__le32					dwell_time; | ||||||
|  | 	u8					bssid[ETH_ALEN]; | ||||||
|  | 	u8					pad[2]; | ||||||
|  | 	struct brcmf_fil_action_frame_le	action_frame; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct brcmf_fil_bss_enable_le { | ||||||
|  | 	__le32 bsscfg_idx; | ||||||
|  | 	__le32 enable; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #endif /* FWIL_TYPES_H_ */ | ||||||
							
								
								
									
										2277
									
								
								drivers/net/wireless/brcm80211/brcmfmac/p2p.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2277
									
								
								drivers/net/wireless/brcm80211/brcmfmac/p2p.c
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										183
									
								
								drivers/net/wireless/brcm80211/brcmfmac/p2p.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								drivers/net/wireless/brcm80211/brcmfmac/p2p.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,183 @@ | ||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2012 Broadcom Corporation | ||||||
|  |  * | ||||||
|  |  * Permission to use, copy, modify, and/or distribute this software for any | ||||||
|  |  * purpose with or without fee is hereby granted, provided that the above | ||||||
|  |  * copyright notice and this permission notice appear in all copies. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||||
|  |  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||||
|  |  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||||||
|  |  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||||
|  |  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||||||
|  |  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||||||
|  |  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||||
|  |  */ | ||||||
|  | #ifndef WL_CFGP2P_H_ | ||||||
|  | #define WL_CFGP2P_H_ | ||||||
|  | 
 | ||||||
|  | #include <net/cfg80211.h> | ||||||
|  | 
 | ||||||
|  | struct brcmf_cfg80211_info; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * enum p2p_bss_type - different type of BSS configurations. | ||||||
|  |  * | ||||||
|  |  * @P2PAPI_BSSCFG_PRIMARY: maps to driver's primary bsscfg. | ||||||
|  |  * @P2PAPI_BSSCFG_DEVICE: maps to driver's P2P device discovery bsscfg. | ||||||
|  |  * @P2PAPI_BSSCFG_CONNECTION: maps to driver's P2P connection bsscfg. | ||||||
|  |  * @P2PAPI_BSSCFG_MAX: used for range checking. | ||||||
|  |  */ | ||||||
|  | enum p2p_bss_type { | ||||||
|  | 	P2PAPI_BSSCFG_PRIMARY, /* maps to driver's primary bsscfg */ | ||||||
|  | 	P2PAPI_BSSCFG_DEVICE, /* maps to driver's P2P device discovery bsscfg */ | ||||||
|  | 	P2PAPI_BSSCFG_CONNECTION, /* maps to driver's P2P connection bsscfg */ | ||||||
|  | 	P2PAPI_BSSCFG_MAX | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct p2p_bss - peer-to-peer bss related information. | ||||||
|  |  * | ||||||
|  |  * @vif: virtual interface of this P2P bss. | ||||||
|  |  * @private_data: TBD | ||||||
|  |  */ | ||||||
|  | struct p2p_bss { | ||||||
|  | 	struct brcmf_cfg80211_vif *vif; | ||||||
|  | 	void *private_data; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * enum brcmf_p2p_status - P2P specific dongle status. | ||||||
|  |  * | ||||||
|  |  * @BRCMF_P2P_STATUS_IF_ADD: peer-to-peer vif add sent to dongle. | ||||||
|  |  * @BRCMF_P2P_STATUS_IF_DEL: NOT-USED? | ||||||
|  |  * @BRCMF_P2P_STATUS_IF_DELETING: peer-to-peer vif delete sent to dongle. | ||||||
|  |  * @BRCMF_P2P_STATUS_IF_CHANGING: peer-to-peer vif change sent to dongle. | ||||||
|  |  * @BRCMF_P2P_STATUS_IF_CHANGED: peer-to-peer vif change completed on dongle. | ||||||
|  |  * @BRCMF_P2P_STATUS_ACTION_TX_COMPLETED: action frame tx completed. | ||||||
|  |  * @BRCMF_P2P_STATUS_ACTION_TX_NOACK: action frame tx not acked. | ||||||
|  |  * @BRCMF_P2P_STATUS_GO_NEG_PHASE: P2P GO negotiation ongoing. | ||||||
|  |  * @BRCMF_P2P_STATUS_DISCOVER_LISTEN: P2P listen, remaining on channel. | ||||||
|  |  * @BRCMF_P2P_STATUS_SENDING_ACT_FRAME: In the process of sending action frame. | ||||||
|  |  * @BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN: extra listen time for af tx. | ||||||
|  |  * @BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME: waiting for action frame response. | ||||||
|  |  * @BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL: search channel for AF active. | ||||||
|  |  */ | ||||||
|  | enum brcmf_p2p_status { | ||||||
|  | 	BRCMF_P2P_STATUS_ENABLED, | ||||||
|  | 	BRCMF_P2P_STATUS_IF_ADD, | ||||||
|  | 	BRCMF_P2P_STATUS_IF_DEL, | ||||||
|  | 	BRCMF_P2P_STATUS_IF_DELETING, | ||||||
|  | 	BRCMF_P2P_STATUS_IF_CHANGING, | ||||||
|  | 	BRCMF_P2P_STATUS_IF_CHANGED, | ||||||
|  | 	BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, | ||||||
|  | 	BRCMF_P2P_STATUS_ACTION_TX_NOACK, | ||||||
|  | 	BRCMF_P2P_STATUS_GO_NEG_PHASE, | ||||||
|  | 	BRCMF_P2P_STATUS_DISCOVER_LISTEN, | ||||||
|  | 	BRCMF_P2P_STATUS_SENDING_ACT_FRAME, | ||||||
|  | 	BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN, | ||||||
|  | 	BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, | ||||||
|  | 	BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct afx_hdl - action frame off channel storage. | ||||||
|  |  * | ||||||
|  |  * @afx_work: worker thread for searching channel | ||||||
|  |  * @act_frm_scan: thread synchronizing struct. | ||||||
|  |  * @is_active: channel searching active. | ||||||
|  |  * @peer_chan: current channel. | ||||||
|  |  * @is_listen: sets mode for afx worker. | ||||||
|  |  * @my_listen_chan: this peers listen channel. | ||||||
|  |  * @peer_listen_chan: remote peers listen channel. | ||||||
|  |  * @tx_dst_addr: mac address where tx af should be sent to. | ||||||
|  |  */ | ||||||
|  | struct afx_hdl { | ||||||
|  | 	struct work_struct afx_work; | ||||||
|  | 	struct completion act_frm_scan; | ||||||
|  | 	bool is_active; | ||||||
|  | 	s32 peer_chan; | ||||||
|  | 	bool is_listen; | ||||||
|  | 	u16 my_listen_chan; | ||||||
|  | 	u16 peer_listen_chan; | ||||||
|  | 	u8 tx_dst_addr[ETH_ALEN]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct brcmf_p2p_info - p2p specific driver information. | ||||||
|  |  * | ||||||
|  |  * @cfg: driver private data for cfg80211 interface. | ||||||
|  |  * @status: status of P2P (see enum brcmf_p2p_status). | ||||||
|  |  * @dev_addr: P2P device address. | ||||||
|  |  * @int_addr: P2P interface address. | ||||||
|  |  * @bss_idx: informate for P2P bss types. | ||||||
|  |  * @listen_timer: timer for @WL_P2P_DISC_ST_LISTEN discover state. | ||||||
|  |  * @ssid: ssid for P2P GO. | ||||||
|  |  * @listen_channel: channel for @WL_P2P_DISC_ST_LISTEN discover state. | ||||||
|  |  * @remain_on_channel: contains copy of struct used by cfg80211. | ||||||
|  |  * @remain_on_channel_cookie: cookie counter for remain on channel cmd | ||||||
|  |  * @next_af_subtype: expected action frame subtype. | ||||||
|  |  * @send_af_done: indication that action frame tx is complete. | ||||||
|  |  * @afx_hdl: action frame search handler info. | ||||||
|  |  * @af_sent_channel: channel action frame is sent. | ||||||
|  |  * @af_tx_sent_jiffies: jiffies time when af tx was transmitted. | ||||||
|  |  * @wait_next_af: thread synchronizing struct. | ||||||
|  |  * @gon_req_action: about to send go negotiation requets frame. | ||||||
|  |  * @block_gon_req_tx: drop tx go negotiation requets frame. | ||||||
|  |  */ | ||||||
|  | struct brcmf_p2p_info { | ||||||
|  | 	struct brcmf_cfg80211_info *cfg; | ||||||
|  | 	unsigned long status; | ||||||
|  | 	u8 dev_addr[ETH_ALEN]; | ||||||
|  | 	u8 int_addr[ETH_ALEN]; | ||||||
|  | 	struct p2p_bss bss_idx[P2PAPI_BSSCFG_MAX]; | ||||||
|  | 	struct timer_list listen_timer; | ||||||
|  | 	struct brcmf_ssid ssid; | ||||||
|  | 	u8 listen_channel; | ||||||
|  | 	struct ieee80211_channel remain_on_channel; | ||||||
|  | 	u32 remain_on_channel_cookie; | ||||||
|  | 	u8 next_af_subtype; | ||||||
|  | 	struct completion send_af_done; | ||||||
|  | 	struct afx_hdl afx_hdl; | ||||||
|  | 	u32 af_sent_channel; | ||||||
|  | 	unsigned long af_tx_sent_jiffies; | ||||||
|  | 	struct completion wait_next_af; | ||||||
|  | 	bool gon_req_action; | ||||||
|  | 	bool block_gon_req_tx; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg); | ||||||
|  | void brcmf_p2p_detach(struct brcmf_p2p_info *p2p); | ||||||
|  | struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, | ||||||
|  | 				       enum nl80211_iftype type, u32 *flags, | ||||||
|  | 				       struct vif_params *params); | ||||||
|  | int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev); | ||||||
|  | int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg, | ||||||
|  | 		       enum brcmf_fil_p2p_if_types if_type); | ||||||
|  | int brcmf_p2p_start_device(struct wiphy *wiphy, struct wireless_dev *wdev); | ||||||
|  | void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev); | ||||||
|  | int brcmf_p2p_scan_prep(struct wiphy *wiphy, | ||||||
|  | 			struct cfg80211_scan_request *request, | ||||||
|  | 			struct brcmf_cfg80211_vif *vif); | ||||||
|  | int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, | ||||||
|  | 				struct ieee80211_channel *channel, | ||||||
|  | 				unsigned int duration, u64 *cookie); | ||||||
|  | int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp, | ||||||
|  | 				     const struct brcmf_event_msg *e, | ||||||
|  | 				     void *data); | ||||||
|  | void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp); | ||||||
|  | int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, | ||||||
|  | 				     const struct brcmf_event_msg *e, | ||||||
|  | 				     void *data); | ||||||
|  | int brcmf_p2p_notify_action_tx_complete(struct brcmf_if *ifp, | ||||||
|  | 					const struct brcmf_event_msg *e, | ||||||
|  | 					void *data); | ||||||
|  | bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg, | ||||||
|  | 				 struct net_device *ndev, | ||||||
|  | 				 struct brcmf_fil_af_params_le *af_params); | ||||||
|  | bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg, | ||||||
|  | 					   struct brcmf_bss_info_le *bi); | ||||||
|  | s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp, | ||||||
|  | 					  const struct brcmf_event_msg *e, | ||||||
|  | 					  void *data); | ||||||
|  | #endif /* WL_CFGP2P_H_ */ | ||||||
|  | @ -420,10 +420,6 @@ static void brcmf_usb_tx_complete(struct urb *urb) | ||||||
| 	brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status, | 	brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status, | ||||||
| 		  req->skb); | 		  req->skb); | ||||||
| 	brcmf_usb_del_fromq(devinfo, req); | 	brcmf_usb_del_fromq(devinfo, req); | ||||||
| 	if (urb->status == 0) |  | ||||||
| 		devinfo->bus_pub.bus->dstats.tx_packets++; |  | ||||||
| 	else |  | ||||||
| 		devinfo->bus_pub.bus->dstats.tx_errors++; |  | ||||||
| 
 | 
 | ||||||
| 	brcmf_txcomplete(devinfo->dev, req->skb, urb->status == 0); | 	brcmf_txcomplete(devinfo->dev, req->skb, urb->status == 0); | ||||||
| 
 | 
 | ||||||
|  | @ -450,10 +446,7 @@ static void brcmf_usb_rx_complete(struct urb *urb) | ||||||
| 	req->skb = NULL; | 	req->skb = NULL; | ||||||
| 
 | 
 | ||||||
| 	/* zero lenght packets indicate usb "failure". Do not refill */ | 	/* zero lenght packets indicate usb "failure". Do not refill */ | ||||||
| 	if (urb->status == 0 && urb->actual_length) { | 	if (urb->status != 0 || !urb->actual_length) { | ||||||
| 		devinfo->bus_pub.bus->dstats.rx_packets++; |  | ||||||
| 	} else { |  | ||||||
| 		devinfo->bus_pub.bus->dstats.rx_errors++; |  | ||||||
| 		brcmu_pkt_buf_free_skb(skb); | 		brcmu_pkt_buf_free_skb(skb); | ||||||
| 		brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL); | 		brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL); | ||||||
| 		return; | 		return; | ||||||
|  | @ -1256,6 +1249,8 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo) | ||||||
| 	bus->bus_priv.usb = bus_pub; | 	bus->bus_priv.usb = bus_pub; | ||||||
| 	dev_set_drvdata(dev, bus); | 	dev_set_drvdata(dev, bus); | ||||||
| 	bus->ops = &brcmf_usb_bus_ops; | 	bus->ops = &brcmf_usb_bus_ops; | ||||||
|  | 	bus->chip = bus_pub->devid; | ||||||
|  | 	bus->chiprev = bus_pub->chiprev; | ||||||
| 
 | 
 | ||||||
| 	/* Attach to the common driver interface */ | 	/* Attach to the common driver interface */ | ||||||
| 	ret = brcmf_attach(0, dev); | 	ret = brcmf_attach(0, dev); | ||||||
|  |  | ||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -41,6 +41,38 @@ | ||||||
| #define WL_AUTH_SHARED_KEY		1	/* d11 shared authentication */ | #define WL_AUTH_SHARED_KEY		1	/* d11 shared authentication */ | ||||||
| #define IE_MAX_LEN			512 | #define IE_MAX_LEN			512 | ||||||
| 
 | 
 | ||||||
|  | /* IE TLV processing */ | ||||||
|  | #define TLV_LEN_OFF			1	/* length offset */ | ||||||
|  | #define TLV_HDR_LEN			2	/* header length */ | ||||||
|  | #define TLV_BODY_OFF			2	/* body offset */ | ||||||
|  | #define TLV_OUI_LEN			3	/* oui id length */ | ||||||
|  | 
 | ||||||
|  | /* 802.11 Mgmt Packet flags */ | ||||||
|  | #define BRCMF_VNDR_IE_BEACON_FLAG	0x1 | ||||||
|  | #define BRCMF_VNDR_IE_PRBRSP_FLAG	0x2 | ||||||
|  | #define BRCMF_VNDR_IE_ASSOCRSP_FLAG	0x4 | ||||||
|  | #define BRCMF_VNDR_IE_AUTHRSP_FLAG	0x8 | ||||||
|  | #define BRCMF_VNDR_IE_PRBREQ_FLAG	0x10 | ||||||
|  | #define BRCMF_VNDR_IE_ASSOCREQ_FLAG	0x20 | ||||||
|  | /* vendor IE in IW advertisement protocol ID field */ | ||||||
|  | #define BRCMF_VNDR_IE_IWAPID_FLAG	0x40 | ||||||
|  | /* allow custom IE id */ | ||||||
|  | #define BRCMF_VNDR_IE_CUSTOM_FLAG	0x100 | ||||||
|  | 
 | ||||||
|  | /* P2P Action Frames flags (spec ordered) */ | ||||||
|  | #define BRCMF_VNDR_IE_GONREQ_FLAG     0x001000 | ||||||
|  | #define BRCMF_VNDR_IE_GONRSP_FLAG     0x002000 | ||||||
|  | #define BRCMF_VNDR_IE_GONCFM_FLAG     0x004000 | ||||||
|  | #define BRCMF_VNDR_IE_INVREQ_FLAG     0x008000 | ||||||
|  | #define BRCMF_VNDR_IE_INVRSP_FLAG     0x010000 | ||||||
|  | #define BRCMF_VNDR_IE_DISREQ_FLAG     0x020000 | ||||||
|  | #define BRCMF_VNDR_IE_DISRSP_FLAG     0x040000 | ||||||
|  | #define BRCMF_VNDR_IE_PRDREQ_FLAG     0x080000 | ||||||
|  | #define BRCMF_VNDR_IE_PRDRSP_FLAG     0x100000 | ||||||
|  | 
 | ||||||
|  | #define BRCMF_VNDR_IE_P2PAF_SHIFT	12 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * enum brcmf_scan_status - dongle scan status |  * enum brcmf_scan_status - dongle scan status | ||||||
|  * |  * | ||||||
|  | @ -52,11 +84,19 @@ enum brcmf_scan_status { | ||||||
| 	BRCMF_SCAN_STATUS_ABORT, | 	BRCMF_SCAN_STATUS_ABORT, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /* wi-fi mode */ | /**
 | ||||||
|  |  * enum wl_mode - driver mode of virtual interface. | ||||||
|  |  * | ||||||
|  |  * @WL_MODE_BSS: connects to BSS. | ||||||
|  |  * @WL_MODE_IBSS: operate as ad-hoc. | ||||||
|  |  * @WL_MODE_AP: operate as access-point. | ||||||
|  |  * @WL_MODE_P2P: provide P2P discovery. | ||||||
|  |  */ | ||||||
| enum wl_mode { | enum wl_mode { | ||||||
| 	WL_MODE_BSS, | 	WL_MODE_BSS, | ||||||
| 	WL_MODE_IBSS, | 	WL_MODE_IBSS, | ||||||
| 	WL_MODE_AP | 	WL_MODE_AP, | ||||||
|  | 	WL_MODE_P2P | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /* dongle configuration */ | /* dongle configuration */ | ||||||
|  | @ -108,6 +148,7 @@ struct brcmf_cfg80211_profile { | ||||||
|  * @BRCMF_VIF_STATUS_READY: ready for operation. |  * @BRCMF_VIF_STATUS_READY: ready for operation. | ||||||
|  * @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress. |  * @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress. | ||||||
|  * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully. |  * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully. | ||||||
|  |  * @BRCMF_VIF_STATUS_DISCONNECTING: disconnect/disable in progress. | ||||||
|  * @BRCMF_VIF_STATUS_AP_CREATING: interface configured for AP operation. |  * @BRCMF_VIF_STATUS_AP_CREATING: interface configured for AP operation. | ||||||
|  * @BRCMF_VIF_STATUS_AP_CREATED: AP operation started. |  * @BRCMF_VIF_STATUS_AP_CREATED: AP operation started. | ||||||
|  */ |  */ | ||||||
|  | @ -115,6 +156,7 @@ enum brcmf_vif_status { | ||||||
| 	BRCMF_VIF_STATUS_READY, | 	BRCMF_VIF_STATUS_READY, | ||||||
| 	BRCMF_VIF_STATUS_CONNECTING, | 	BRCMF_VIF_STATUS_CONNECTING, | ||||||
| 	BRCMF_VIF_STATUS_CONNECTED, | 	BRCMF_VIF_STATUS_CONNECTED, | ||||||
|  | 	BRCMF_VIF_STATUS_DISCONNECTING, | ||||||
| 	BRCMF_VIF_STATUS_AP_CREATING, | 	BRCMF_VIF_STATUS_AP_CREATING, | ||||||
| 	BRCMF_VIF_STATUS_AP_CREATED | 	BRCMF_VIF_STATUS_AP_CREATED | ||||||
| }; | }; | ||||||
|  | @ -122,16 +164,22 @@ enum brcmf_vif_status { | ||||||
| /**
 | /**
 | ||||||
|  * struct vif_saved_ie - holds saved IEs for a virtual interface. |  * struct vif_saved_ie - holds saved IEs for a virtual interface. | ||||||
|  * |  * | ||||||
|  |  * @probe_req_ie: IE info for probe request. | ||||||
|  * @probe_res_ie: IE info for probe response. |  * @probe_res_ie: IE info for probe response. | ||||||
|  * @beacon_ie: IE info for beacon frame. |  * @beacon_ie: IE info for beacon frame. | ||||||
|  |  * @probe_req_ie_len: IE info length for probe request. | ||||||
|  * @probe_res_ie_len: IE info length for probe response. |  * @probe_res_ie_len: IE info length for probe response. | ||||||
|  * @beacon_ie_len: IE info length for beacon frame. |  * @beacon_ie_len: IE info length for beacon frame. | ||||||
|  */ |  */ | ||||||
| struct vif_saved_ie { | struct vif_saved_ie { | ||||||
|  | 	u8  probe_req_ie[IE_MAX_LEN]; | ||||||
| 	u8  probe_res_ie[IE_MAX_LEN]; | 	u8  probe_res_ie[IE_MAX_LEN]; | ||||||
| 	u8  beacon_ie[IE_MAX_LEN]; | 	u8  beacon_ie[IE_MAX_LEN]; | ||||||
|  | 	u8  assoc_req_ie[IE_MAX_LEN]; | ||||||
|  | 	u32 probe_req_ie_len; | ||||||
| 	u32 probe_res_ie_len; | 	u32 probe_res_ie_len; | ||||||
| 	u32 beacon_ie_len; | 	u32 beacon_ie_len; | ||||||
|  | 	u32 assoc_req_ie_len; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -145,6 +193,7 @@ struct vif_saved_ie { | ||||||
|  * @sme_state: SME state using enum brcmf_vif_status bits. |  * @sme_state: SME state using enum brcmf_vif_status bits. | ||||||
|  * @pm_block: power-management blocked. |  * @pm_block: power-management blocked. | ||||||
|  * @list: linked list. |  * @list: linked list. | ||||||
|  |  * @mgmt_rx_reg: registered rx mgmt frame types. | ||||||
|  */ |  */ | ||||||
| struct brcmf_cfg80211_vif { | struct brcmf_cfg80211_vif { | ||||||
| 	struct brcmf_if *ifp; | 	struct brcmf_if *ifp; | ||||||
|  | @ -156,6 +205,7 @@ struct brcmf_cfg80211_vif { | ||||||
| 	bool pm_block; | 	bool pm_block; | ||||||
| 	struct vif_saved_ie saved_ie; | 	struct vif_saved_ie saved_ie; | ||||||
| 	struct list_head list; | 	struct list_head list; | ||||||
|  | 	u16 mgmt_rx_reg; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /* association inform */ | /* association inform */ | ||||||
|  | @ -189,6 +239,9 @@ struct escan_info { | ||||||
| 	u8 escan_buf[WL_ESCAN_BUF_SIZE]; | 	u8 escan_buf[WL_ESCAN_BUF_SIZE]; | ||||||
| 	struct wiphy *wiphy; | 	struct wiphy *wiphy; | ||||||
| 	struct net_device *ndev; | 	struct net_device *ndev; | ||||||
|  | 	s32 (*run)(struct brcmf_cfg80211_info *cfg, | ||||||
|  | 		   struct net_device *ndev, | ||||||
|  | 		   struct cfg80211_scan_request *request, u16 action); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -272,11 +325,28 @@ struct brcmf_pno_scanresults_le { | ||||||
| 	__le32 count; | 	__le32 count; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct brcmf_cfg80211_vif_event - virtual interface event information. | ||||||
|  |  * | ||||||
|  |  * @vif_wq: waitqueue awaiting interface event from firmware. | ||||||
|  |  * @vif_event_lock: protects other members in this structure. | ||||||
|  |  * @vif_complete: completion for net attach. | ||||||
|  |  * @action: either add, change, or delete. | ||||||
|  |  * @vif: virtual interface object related to the event. | ||||||
|  |  */ | ||||||
|  | struct brcmf_cfg80211_vif_event { | ||||||
|  | 	wait_queue_head_t vif_wq; | ||||||
|  | 	struct mutex vif_event_lock; | ||||||
|  | 	u8 action; | ||||||
|  | 	struct brcmf_cfg80211_vif *vif; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface |  * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface | ||||||
|  * |  * | ||||||
|  * @wiphy: wiphy object for cfg80211 interface. |  * @wiphy: wiphy object for cfg80211 interface. | ||||||
|  * @conf: dongle configuration. |  * @conf: dongle configuration. | ||||||
|  |  * @p2p: peer-to-peer specific information. | ||||||
|  * @scan_request: cfg80211 scan request object. |  * @scan_request: cfg80211 scan request object. | ||||||
|  * @usr_sync: mainly for dongle up/down synchronization. |  * @usr_sync: mainly for dongle up/down synchronization. | ||||||
|  * @bss_list: bss_list holding scanned ap information. |  * @bss_list: bss_list holding scanned ap information. | ||||||
|  | @ -304,10 +374,12 @@ struct brcmf_pno_scanresults_le { | ||||||
|  * @escan_ioctl_buf: dongle command buffer for escan commands. |  * @escan_ioctl_buf: dongle command buffer for escan commands. | ||||||
|  * @vif_list: linked list of vif instances. |  * @vif_list: linked list of vif instances. | ||||||
|  * @vif_cnt: number of vif instances. |  * @vif_cnt: number of vif instances. | ||||||
|  |  * @vif_event: vif event signalling. | ||||||
|  */ |  */ | ||||||
| struct brcmf_cfg80211_info { | struct brcmf_cfg80211_info { | ||||||
| 	struct wiphy *wiphy; | 	struct wiphy *wiphy; | ||||||
| 	struct brcmf_cfg80211_conf *conf; | 	struct brcmf_cfg80211_conf *conf; | ||||||
|  | 	struct brcmf_p2p_info p2p; | ||||||
| 	struct cfg80211_scan_request *scan_request; | 	struct cfg80211_scan_request *scan_request; | ||||||
| 	struct mutex usr_sync; | 	struct mutex usr_sync; | ||||||
| 	struct brcmf_scan_results *bss_list; | 	struct brcmf_scan_results *bss_list; | ||||||
|  | @ -335,6 +407,21 @@ struct brcmf_cfg80211_info { | ||||||
| 	u8 *escan_ioctl_buf; | 	u8 *escan_ioctl_buf; | ||||||
| 	struct list_head vif_list; | 	struct list_head vif_list; | ||||||
| 	u8 vif_cnt; | 	u8 vif_cnt; | ||||||
|  | 	struct brcmf_cfg80211_vif_event vif_event; | ||||||
|  | 	struct completion vif_disabled; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct brcmf_tlv - tag_ID/length/value_buffer tuple. | ||||||
|  |  * | ||||||
|  |  * @id: tag identifier. | ||||||
|  |  * @len: number of bytes in value buffer. | ||||||
|  |  * @data: value buffer. | ||||||
|  |  */ | ||||||
|  | struct brcmf_tlv { | ||||||
|  | 	u8 id; | ||||||
|  | 	u8 len; | ||||||
|  | 	u8 data[1]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *cfg) | static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *cfg) | ||||||
|  | @ -389,4 +476,26 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg); | ||||||
| s32 brcmf_cfg80211_up(struct net_device *ndev); | s32 brcmf_cfg80211_up(struct net_device *ndev); | ||||||
| s32 brcmf_cfg80211_down(struct net_device *ndev); | s32 brcmf_cfg80211_down(struct net_device *ndev); | ||||||
| 
 | 
 | ||||||
|  | struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, | ||||||
|  | 					   enum nl80211_iftype type, | ||||||
|  | 					   bool pm_block); | ||||||
|  | void brcmf_free_vif(struct brcmf_cfg80211_vif *vif); | ||||||
|  | 
 | ||||||
|  | s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, | ||||||
|  | 			  const u8 *vndr_ie_buf, u32 vndr_ie_len); | ||||||
|  | s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif); | ||||||
|  | struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key); | ||||||
|  | u16 channel_to_chanspec(struct ieee80211_channel *ch); | ||||||
|  | u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state); | ||||||
|  | void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg, | ||||||
|  | 				  struct brcmf_cfg80211_vif *vif); | ||||||
|  | bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg); | ||||||
|  | int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg, | ||||||
|  | 					  u8 action, ulong timeout); | ||||||
|  | s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, | ||||||
|  | 				struct net_device *ndev, | ||||||
|  | 				bool aborted, bool fw_abort); | ||||||
|  | void brcmf_set_mpc(struct net_device *ndev, int mpc); | ||||||
|  | void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg); | ||||||
|  | 
 | ||||||
| #endif				/* _wl_cfg80211_h_ */ | #endif				/* _wl_cfg80211_h_ */ | ||||||
|  |  | ||||||
|  | @ -183,8 +183,7 @@ static bool brcms_c_country_valid(const char *ccode) | ||||||
| 	 * chars. | 	 * chars. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (!((0x80 & ccode[0]) == 0 && ccode[0] >= 0x41 && ccode[0] <= 0x5A && | 	if (!((0x80 & ccode[0]) == 0 && ccode[0] >= 0x41 && ccode[0] <= 0x5A && | ||||||
| 	      (0x80 & ccode[1]) == 0 && ccode[1] >= 0x41 && ccode[1] <= 0x5A && | 	      (0x80 & ccode[1]) == 0 && ccode[1] >= 0x41 && ccode[1] <= 0x5A)) | ||||||
| 	      ccode[2] == '\0')) |  | ||||||
| 		return false; | 		return false; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
|  |  | ||||||
|  | @ -101,8 +101,6 @@ | ||||||
| #define DOT11_RTS_LEN			16 | #define DOT11_RTS_LEN			16 | ||||||
| #define DOT11_CTS_LEN			10 | #define DOT11_CTS_LEN			10 | ||||||
| #define DOT11_BA_BITMAP_LEN		128 | #define DOT11_BA_BITMAP_LEN		128 | ||||||
| #define DOT11_MIN_BEACON_PERIOD		1 |  | ||||||
| #define DOT11_MAX_BEACON_PERIOD		0xFFFF |  | ||||||
| #define DOT11_MAXNUMFRAGS		16 | #define DOT11_MAXNUMFRAGS		16 | ||||||
| #define DOT11_MAX_FRAG_LEN		2346 | #define DOT11_MAX_FRAG_LEN		2346 | ||||||
| 
 | 
 | ||||||
|  | @ -3140,8 +3138,7 @@ void brcms_c_reset(struct brcms_c_info *wlc) | ||||||
| 	brcms_c_statsupd(wlc); | 	brcms_c_statsupd(wlc); | ||||||
| 
 | 
 | ||||||
| 	/* reset our snapshot of macstat counters */ | 	/* reset our snapshot of macstat counters */ | ||||||
| 	memset((char *)wlc->core->macstat_snapshot, 0, | 	memset(wlc->core->macstat_snapshot, 0, sizeof(struct macstat)); | ||||||
| 		sizeof(struct macstat)); |  | ||||||
| 
 | 
 | ||||||
| 	brcms_b_reset(wlc->hw); | 	brcms_b_reset(wlc->hw); | ||||||
| } | } | ||||||
|  | @ -4054,7 +4051,7 @@ void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci, | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	memset((char *)&acp_shm, 0, sizeof(struct shm_acparams)); | 	memset(&acp_shm, 0, sizeof(struct shm_acparams)); | ||||||
| 	/* fill in shm ac params struct */ | 	/* fill in shm ac params struct */ | ||||||
| 	acp_shm.txop = params->txop; | 	acp_shm.txop = params->txop; | ||||||
| 	/* convert from units of 32us to us for ucode */ | 	/* convert from units of 32us to us for ucode */ | ||||||
|  | @ -4770,7 +4767,7 @@ static void brcms_c_bss_default_init(struct brcms_c_info *wlc) | ||||||
| 	struct brcms_bss_info *bi = wlc->default_bss; | 	struct brcms_bss_info *bi = wlc->default_bss; | ||||||
| 
 | 
 | ||||||
| 	/* init default and target BSS with some sane initial values */ | 	/* init default and target BSS with some sane initial values */ | ||||||
| 	memset((char *)(bi), 0, sizeof(struct brcms_bss_info)); | 	memset(bi, 0, sizeof(*bi)); | ||||||
| 	bi->beacon_period = BEACON_INTERVAL_DEFAULT; | 	bi->beacon_period = BEACON_INTERVAL_DEFAULT; | ||||||
| 
 | 
 | ||||||
| 	/* fill the default channel as the first valid channel
 | 	/* fill the default channel as the first valid channel
 | ||||||
|  | @ -5299,7 +5296,7 @@ int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config) | ||||||
| 		brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, gmode); | 		brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, gmode); | ||||||
| 
 | 
 | ||||||
| 	/* Clear rateset override */ | 	/* Clear rateset override */ | ||||||
| 	memset(&rs, 0, sizeof(struct brcms_c_rateset)); | 	memset(&rs, 0, sizeof(rs)); | ||||||
| 
 | 
 | ||||||
| 	switch (gmode) { | 	switch (gmode) { | ||||||
| 	case GMODE_LEGACY_B: | 	case GMODE_LEGACY_B: | ||||||
|  | @ -5522,7 +5519,7 @@ int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs) | ||||||
| 	if (rs->count > BRCMS_NUMRATES) | 	if (rs->count > BRCMS_NUMRATES) | ||||||
| 		return -ENOBUFS; | 		return -ENOBUFS; | ||||||
| 
 | 
 | ||||||
| 	memset(&internal_rs, 0, sizeof(struct brcms_c_rateset)); | 	memset(&internal_rs, 0, sizeof(internal_rs)); | ||||||
| 
 | 
 | ||||||
| 	/* Copy only legacy rateset section */ | 	/* Copy only legacy rateset section */ | ||||||
| 	internal_rs.count = rs->count; | 	internal_rs.count = rs->count; | ||||||
|  | @ -5548,8 +5545,7 @@ int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs) | ||||||
| 
 | 
 | ||||||
| int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period) | int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period) | ||||||
| { | { | ||||||
| 	if (period < DOT11_MIN_BEACON_PERIOD || | 	if (period == 0) | ||||||
| 	    period > DOT11_MAX_BEACON_PERIOD) |  | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
| 	wlc->default_bss->beacon_period = period; | 	wlc->default_bss->beacon_period = period; | ||||||
|  | @ -5626,7 +5622,7 @@ int brcms_c_module_unregister(struct brcms_pub *pub, const char *name, | ||||||
| 	for (i = 0; i < BRCMS_MAXMODULES; i++) { | 	for (i = 0; i < BRCMS_MAXMODULES; i++) { | ||||||
| 		if (!strcmp(wlc->modulecb[i].name, name) && | 		if (!strcmp(wlc->modulecb[i].name, name) && | ||||||
| 		    (wlc->modulecb[i].hdl == hdl)) { | 		    (wlc->modulecb[i].hdl == hdl)) { | ||||||
| 			memset(&wlc->modulecb[i], 0, sizeof(struct modulecb)); | 			memset(&wlc->modulecb[i], 0, sizeof(wlc->modulecb[i])); | ||||||
| 			return 0; | 			return 0; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | @ -6446,9 +6442,8 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw, | ||||||
| 
 | 
 | ||||||
| 			if ((txrate[k]->flags & IEEE80211_TX_RC_MCS) | 			if ((txrate[k]->flags & IEEE80211_TX_RC_MCS) | ||||||
| 			    && (!is_mcs_rate(rspec[k]))) { | 			    && (!is_mcs_rate(rspec[k]))) { | ||||||
| 				brcms_err(wlc->hw->d11core, | 				brcms_warn(wlc->hw->d11core, | ||||||
| 					  "wl%d: %s: IEEE80211_TX_" | 					   "wl%d: %s: IEEE80211_TX_RC_MCS != is_mcs_rate(rspec)\n", | ||||||
| 					  "RC_MCS != is_mcs_rate(rspec)\n", |  | ||||||
| 					   wlc->pub->unit, __func__); | 					   wlc->pub->unit, __func__); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  | @ -6682,11 +6677,9 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw, | ||||||
| 					(struct ofdm_phy_hdr *) rts_plcp) : | 					(struct ofdm_phy_hdr *) rts_plcp) : | ||||||
| 				rts_plcp[0]) << 8; | 				rts_plcp[0]) << 8; | ||||||
| 	} else { | 	} else { | ||||||
| 		memset((char *)txh->RTSPhyHeader, 0, D11_PHY_HDR_LEN); | 		memset(txh->RTSPhyHeader, 0, D11_PHY_HDR_LEN); | ||||||
| 		memset((char *)&txh->rts_frame, 0, | 		memset(&txh->rts_frame, 0, sizeof(struct ieee80211_rts)); | ||||||
| 			sizeof(struct ieee80211_rts)); | 		memset(txh->RTSPLCPFallback, 0, sizeof(txh->RTSPLCPFallback)); | ||||||
| 		memset((char *)txh->RTSPLCPFallback, 0, |  | ||||||
| 		      sizeof(txh->RTSPLCPFallback)); |  | ||||||
| 		txh->RTSDurFallback = 0; | 		txh->RTSDurFallback = 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -6841,17 +6834,15 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw, | ||||||
| 					wlc->fragthresh[queue] = | 					wlc->fragthresh[queue] = | ||||||
| 					    (u16) newfragthresh; | 					    (u16) newfragthresh; | ||||||
| 			} else { | 			} else { | ||||||
| 				brcms_err(wlc->hw->d11core, | 				brcms_warn(wlc->hw->d11core, | ||||||
| 					  "wl%d: %s txop invalid " | 					   "wl%d: %s txop invalid for rate %d\n", | ||||||
| 					  "for rate %d\n", |  | ||||||
| 					   wlc->pub->unit, fifo_names[queue], | 					   wlc->pub->unit, fifo_names[queue], | ||||||
| 					   rspec2rate(rspec[0])); | 					   rspec2rate(rspec[0])); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			if (dur > wlc->edcf_txop[ac]) | 			if (dur > wlc->edcf_txop[ac]) | ||||||
| 				brcms_err(wlc->hw->d11core, | 				brcms_warn(wlc->hw->d11core, | ||||||
| 					  "wl%d: %s: %s txop " | 					   "wl%d: %s: %s txop exceeded phylen %d/%d dur %d/%d\n", | ||||||
| 					  "exceeded phylen %d/%d dur %d/%d\n", |  | ||||||
| 					   wlc->pub->unit, __func__, | 					   wlc->pub->unit, __func__, | ||||||
| 					   fifo_names[queue], | 					   fifo_names[queue], | ||||||
| 					   phylen, wlc->fragthresh[queue], | 					   phylen, wlc->fragthresh[queue], | ||||||
|  | @ -7330,7 +7321,7 @@ brcms_c_bcn_prb_template(struct brcms_c_info *wlc, u16 type, | ||||||
| 	*len = hdr_len + body_len; | 	*len = hdr_len + body_len; | ||||||
| 
 | 
 | ||||||
| 	/* format PHY and MAC headers */ | 	/* format PHY and MAC headers */ | ||||||
| 	memset((char *)buf, 0, hdr_len); | 	memset(buf, 0, hdr_len); | ||||||
| 
 | 
 | ||||||
| 	plcp = (struct cck_phy_hdr *) buf; | 	plcp = (struct cck_phy_hdr *) buf; | ||||||
| 
 | 
 | ||||||
|  | @ -7401,9 +7392,13 @@ brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc, | ||||||
| 			      struct brcms_bss_cfg *cfg, | 			      struct brcms_bss_cfg *cfg, | ||||||
| 			      bool suspend) | 			      bool suspend) | ||||||
| { | { | ||||||
| 	u16 prb_resp[BCN_TMPL_LEN / 2]; | 	u16 *prb_resp; | ||||||
| 	int len = BCN_TMPL_LEN; | 	int len = BCN_TMPL_LEN; | ||||||
| 
 | 
 | ||||||
|  | 	prb_resp = kmalloc(BCN_TMPL_LEN, GFP_ATOMIC); | ||||||
|  | 	if (!prb_resp) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * write the probe response to hardware, or save in | 	 * write the probe response to hardware, or save in | ||||||
| 	 * the config structure | 	 * the config structure | ||||||
|  | @ -7437,6 +7432,8 @@ brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc, | ||||||
| 
 | 
 | ||||||
| 	if (suspend) | 	if (suspend) | ||||||
| 		brcms_c_enable_mac(wlc); | 		brcms_c_enable_mac(wlc); | ||||||
|  | 
 | ||||||
|  | 	kfree(prb_resp); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend) | void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend) | ||||||
|  |  | ||||||
|  | @ -572,26 +572,11 @@ il3945_tx_skb(struct il_priv *il, | ||||||
| 	il3945_hw_build_tx_cmd_rate(il, out_cmd, info, hdr, sta_id); | 	il3945_hw_build_tx_cmd_rate(il, out_cmd, info, hdr, sta_id); | ||||||
| 
 | 
 | ||||||
| 	/* Total # bytes to be transmitted */ | 	/* Total # bytes to be transmitted */ | ||||||
| 	len = (u16) skb->len; | 	tx_cmd->len = cpu_to_le16((u16) skb->len); | ||||||
| 	tx_cmd->len = cpu_to_le16(len); |  | ||||||
| 
 | 
 | ||||||
| 	il_update_stats(il, true, fc, len); |  | ||||||
| 	tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; | 	tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; | ||||||
| 	tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; | 	tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; | ||||||
| 
 | 
 | ||||||
| 	if (!ieee80211_has_morefrags(hdr->frame_control)) { |  | ||||||
| 		txq->need_update = 1; |  | ||||||
| 	} else { |  | ||||||
| 		wait_write_ptr = 1; |  | ||||||
| 		txq->need_update = 0; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	D_TX("sequence nr = 0X%x\n", le16_to_cpu(out_cmd->hdr.sequence)); |  | ||||||
| 	D_TX("tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags)); |  | ||||||
| 	il_print_hex_dump(il, IL_DL_TX, tx_cmd, sizeof(*tx_cmd)); |  | ||||||
| 	il_print_hex_dump(il, IL_DL_TX, (u8 *) tx_cmd->hdr, |  | ||||||
| 			  ieee80211_hdrlen(fc)); |  | ||||||
| 
 |  | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Use the first empty entry in this queue's command buffer array | 	 * Use the first empty entry in this queue's command buffer array | ||||||
| 	 * to contain the Tx command and MAC header concatenated together | 	 * to contain the Tx command and MAC header concatenated together | ||||||
|  | @ -610,14 +595,8 @@ il3945_tx_skb(struct il_priv *il, | ||||||
| 	 * within command buffer array. */ | 	 * within command buffer array. */ | ||||||
| 	txcmd_phys = | 	txcmd_phys = | ||||||
| 	    pci_map_single(il->pci_dev, &out_cmd->hdr, len, PCI_DMA_TODEVICE); | 	    pci_map_single(il->pci_dev, &out_cmd->hdr, len, PCI_DMA_TODEVICE); | ||||||
| 	/* we do not map meta data ... so we can safely access address to
 | 	if (unlikely(pci_dma_mapping_error(il->pci_dev, txcmd_phys))) | ||||||
| 	 * provide to unmap command*/ | 		goto drop_unlock; | ||||||
| 	dma_unmap_addr_set(out_meta, mapping, txcmd_phys); |  | ||||||
| 	dma_unmap_len_set(out_meta, len, len); |  | ||||||
| 
 |  | ||||||
| 	/* Add buffer containing Tx command and MAC(!) header to TFD's
 |  | ||||||
| 	 * first entry */ |  | ||||||
| 	il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, len, 1, 0); |  | ||||||
| 
 | 
 | ||||||
| 	/* Set up TFD's 2nd entry to point directly to remainder of skb,
 | 	/* Set up TFD's 2nd entry to point directly to remainder of skb,
 | ||||||
| 	 * if any (802.11 null frames have no payload). */ | 	 * if any (802.11 null frames have no payload). */ | ||||||
|  | @ -626,10 +605,34 @@ il3945_tx_skb(struct il_priv *il, | ||||||
| 		phys_addr = | 		phys_addr = | ||||||
| 		    pci_map_single(il->pci_dev, skb->data + hdr_len, len, | 		    pci_map_single(il->pci_dev, skb->data + hdr_len, len, | ||||||
| 				   PCI_DMA_TODEVICE); | 				   PCI_DMA_TODEVICE); | ||||||
|  | 		if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr))) | ||||||
|  | 			goto drop_unlock; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Add buffer containing Tx command and MAC(!) header to TFD's
 | ||||||
|  | 	 * first entry */ | ||||||
|  | 	il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, len, 1, 0); | ||||||
|  | 	dma_unmap_addr_set(out_meta, mapping, txcmd_phys); | ||||||
|  | 	dma_unmap_len_set(out_meta, len, len); | ||||||
|  | 	if (len) | ||||||
| 		il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, len, 0, | 		il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, len, 0, | ||||||
| 					       U32_PAD(len)); | 					       U32_PAD(len)); | ||||||
|  | 
 | ||||||
|  | 	if (!ieee80211_has_morefrags(hdr->frame_control)) { | ||||||
|  | 		txq->need_update = 1; | ||||||
|  | 	} else { | ||||||
|  | 		wait_write_ptr = 1; | ||||||
|  | 		txq->need_update = 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	il_update_stats(il, true, fc, skb->len); | ||||||
|  | 
 | ||||||
|  | 	D_TX("sequence nr = 0X%x\n", le16_to_cpu(out_cmd->hdr.sequence)); | ||||||
|  | 	D_TX("tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags)); | ||||||
|  | 	il_print_hex_dump(il, IL_DL_TX, tx_cmd, sizeof(*tx_cmd)); | ||||||
|  | 	il_print_hex_dump(il, IL_DL_TX, (u8 *) tx_cmd->hdr, | ||||||
|  | 			  ieee80211_hdrlen(fc)); | ||||||
|  | 
 | ||||||
| 	/* Tell device the write idx *just past* this latest filled TFD */ | 	/* Tell device the write idx *just past* this latest filled TFD */ | ||||||
| 	q->write_ptr = il_queue_inc_wrap(q->write_ptr, q->n_bd); | 	q->write_ptr = il_queue_inc_wrap(q->write_ptr, q->n_bd); | ||||||
| 	il_txq_update_write_ptr(il, txq); | 	il_txq_update_write_ptr(il, txq); | ||||||
|  |  | ||||||
|  | @ -1793,8 +1793,7 @@ il4965_tx_skb(struct il_priv *il, | ||||||
| 	memcpy(tx_cmd->hdr, hdr, hdr_len); | 	memcpy(tx_cmd->hdr, hdr, hdr_len); | ||||||
| 
 | 
 | ||||||
| 	/* Total # bytes to be transmitted */ | 	/* Total # bytes to be transmitted */ | ||||||
| 	len = (u16) skb->len; | 	tx_cmd->len = cpu_to_le16((u16) skb->len); | ||||||
| 	tx_cmd->len = cpu_to_le16(len); |  | ||||||
| 
 | 
 | ||||||
| 	if (info->control.hw_key) | 	if (info->control.hw_key) | ||||||
| 		il4965_tx_cmd_build_hwcrypto(il, info, tx_cmd, skb, sta_id); | 		il4965_tx_cmd_build_hwcrypto(il, info, tx_cmd, skb, sta_id); | ||||||
|  | @ -1804,7 +1803,6 @@ il4965_tx_skb(struct il_priv *il, | ||||||
| 
 | 
 | ||||||
| 	il4965_tx_cmd_build_rate(il, tx_cmd, info, sta, fc); | 	il4965_tx_cmd_build_rate(il, tx_cmd, info, sta, fc); | ||||||
| 
 | 
 | ||||||
| 	il_update_stats(il, true, fc, len); |  | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Use the first empty entry in this queue's command buffer array | 	 * Use the first empty entry in this queue's command buffer array | ||||||
| 	 * to contain the Tx command and MAC header concatenated together | 	 * to contain the Tx command and MAC header concatenated together | ||||||
|  | @ -1826,18 +1824,8 @@ il4965_tx_skb(struct il_priv *il, | ||||||
| 	txcmd_phys = | 	txcmd_phys = | ||||||
| 	    pci_map_single(il->pci_dev, &out_cmd->hdr, firstlen, | 	    pci_map_single(il->pci_dev, &out_cmd->hdr, firstlen, | ||||||
| 			   PCI_DMA_BIDIRECTIONAL); | 			   PCI_DMA_BIDIRECTIONAL); | ||||||
| 	dma_unmap_addr_set(out_meta, mapping, txcmd_phys); | 	if (unlikely(pci_dma_mapping_error(il->pci_dev, txcmd_phys))) | ||||||
| 	dma_unmap_len_set(out_meta, len, firstlen); | 		goto drop_unlock; | ||||||
| 	/* Add buffer containing Tx command and MAC(!) header to TFD's
 |  | ||||||
| 	 * first entry */ |  | ||||||
| 	il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, firstlen, 1, 0); |  | ||||||
| 
 |  | ||||||
| 	if (!ieee80211_has_morefrags(hdr->frame_control)) { |  | ||||||
| 		txq->need_update = 1; |  | ||||||
| 	} else { |  | ||||||
| 		wait_write_ptr = 1; |  | ||||||
| 		txq->need_update = 0; |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	/* Set up TFD's 2nd entry to point directly to remainder of skb,
 | 	/* Set up TFD's 2nd entry to point directly to remainder of skb,
 | ||||||
| 	 * if any (802.11 null frames have no payload). */ | 	 * if any (802.11 null frames have no payload). */ | ||||||
|  | @ -1846,8 +1834,24 @@ il4965_tx_skb(struct il_priv *il, | ||||||
| 		phys_addr = | 		phys_addr = | ||||||
| 		    pci_map_single(il->pci_dev, skb->data + hdr_len, secondlen, | 		    pci_map_single(il->pci_dev, skb->data + hdr_len, secondlen, | ||||||
| 				   PCI_DMA_TODEVICE); | 				   PCI_DMA_TODEVICE); | ||||||
|  | 		if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr))) | ||||||
|  | 			goto drop_unlock; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Add buffer containing Tx command and MAC(!) header to TFD's
 | ||||||
|  | 	 * first entry */ | ||||||
|  | 	il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, firstlen, 1, 0); | ||||||
|  | 	dma_unmap_addr_set(out_meta, mapping, txcmd_phys); | ||||||
|  | 	dma_unmap_len_set(out_meta, len, firstlen); | ||||||
|  | 	if (secondlen) | ||||||
| 		il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, secondlen, | 		il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, secondlen, | ||||||
| 					       0, 0); | 					       0, 0); | ||||||
|  | 
 | ||||||
|  | 	if (!ieee80211_has_morefrags(hdr->frame_control)) { | ||||||
|  | 		txq->need_update = 1; | ||||||
|  | 	} else { | ||||||
|  | 		wait_write_ptr = 1; | ||||||
|  | 		txq->need_update = 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	scratch_phys = | 	scratch_phys = | ||||||
|  | @ -1860,6 +1864,8 @@ il4965_tx_skb(struct il_priv *il, | ||||||
| 	tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); | 	tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); | ||||||
| 	tx_cmd->dram_msb_ptr = il_get_dma_hi_addr(scratch_phys); | 	tx_cmd->dram_msb_ptr = il_get_dma_hi_addr(scratch_phys); | ||||||
| 
 | 
 | ||||||
|  | 	il_update_stats(il, true, fc, skb->len); | ||||||
|  | 
 | ||||||
| 	D_TX("sequence nr = 0X%x\n", le16_to_cpu(out_cmd->hdr.sequence)); | 	D_TX("sequence nr = 0X%x\n", le16_to_cpu(out_cmd->hdr.sequence)); | ||||||
| 	D_TX("tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags)); | 	D_TX("tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags)); | ||||||
| 	il_print_hex_dump(il, IL_DL_TX, (u8 *) tx_cmd, sizeof(*tx_cmd)); | 	il_print_hex_dump(il, IL_DL_TX, (u8 *) tx_cmd, sizeof(*tx_cmd)); | ||||||
|  | @ -5733,7 +5739,7 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length) | ||||||
| 	/* Tell mac80211 our characteristics */ | 	/* Tell mac80211 our characteristics */ | ||||||
| 	hw->flags = | 	hw->flags = | ||||||
| 	    IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_AMPDU_AGGREGATION | | 	    IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_AMPDU_AGGREGATION | | ||||||
| 	    IEEE80211_HW_NEED_DTIM_PERIOD | IEEE80211_HW_SPECTRUM_MGMT | | 	    IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC | IEEE80211_HW_SPECTRUM_MGMT | | ||||||
| 	    IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS | | 	    IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS | | ||||||
| 	    IEEE80211_HW_SUPPORTS_DYNAMIC_PS; | 	    IEEE80211_HW_SUPPORTS_DYNAMIC_PS; | ||||||
| 	if (il->cfg->sku & IL_SKU_N) | 	if (il->cfg->sku & IL_SKU_N) | ||||||
|  |  | ||||||
|  | @ -1183,8 +1183,7 @@ il4965_rs_switch_to_mimo2(struct il_priv *il, struct il_lq_sta *lq_sta, | ||||||
| 	if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) | 	if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) | ||||||
| 		return -1; | 		return -1; | ||||||
| 
 | 
 | ||||||
| 	if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) == | 	if (sta->smps_mode == IEEE80211_SMPS_STATIC) | ||||||
| 	    WLAN_HT_CAP_SM_PS_STATIC) |  | ||||||
| 		return -1; | 		return -1; | ||||||
| 
 | 
 | ||||||
| 	/* Need both Tx chains/antennas to support MIMO */ | 	/* Need both Tx chains/antennas to support MIMO */ | ||||||
|  |  | ||||||
|  | @ -1830,32 +1830,30 @@ il_set_ht_add_station(struct il_priv *il, u8 idx, struct ieee80211_sta *sta) | ||||||
| { | { | ||||||
| 	struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap; | 	struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap; | ||||||
| 	__le32 sta_flags; | 	__le32 sta_flags; | ||||||
| 	u8 mimo_ps_mode; |  | ||||||
| 
 | 
 | ||||||
| 	if (!sta || !sta_ht_inf->ht_supported) | 	if (!sta || !sta_ht_inf->ht_supported) | ||||||
| 		goto done; | 		goto done; | ||||||
| 
 | 
 | ||||||
| 	mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2; |  | ||||||
| 	D_ASSOC("spatial multiplexing power save mode: %s\n", | 	D_ASSOC("spatial multiplexing power save mode: %s\n", | ||||||
| 		(mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ? "static" : | 		(sta->smps_mode == IEEE80211_SMPS_STATIC) ? "static" : | ||||||
| 		(mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ? "dynamic" : | 		(sta->smps_mode == IEEE80211_SMPS_DYNAMIC) ? "dynamic" : | ||||||
| 		"disabled"); | 		"disabled"); | ||||||
| 
 | 
 | ||||||
| 	sta_flags = il->stations[idx].sta.station_flags; | 	sta_flags = il->stations[idx].sta.station_flags; | ||||||
| 
 | 
 | ||||||
| 	sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK); | 	sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK); | ||||||
| 
 | 
 | ||||||
| 	switch (mimo_ps_mode) { | 	switch (sta->smps_mode) { | ||||||
| 	case WLAN_HT_CAP_SM_PS_STATIC: | 	case IEEE80211_SMPS_STATIC: | ||||||
| 		sta_flags |= STA_FLG_MIMO_DIS_MSK; | 		sta_flags |= STA_FLG_MIMO_DIS_MSK; | ||||||
| 		break; | 		break; | ||||||
| 	case WLAN_HT_CAP_SM_PS_DYNAMIC: | 	case IEEE80211_SMPS_DYNAMIC: | ||||||
| 		sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; | 		sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; | ||||||
| 		break; | 		break; | ||||||
| 	case WLAN_HT_CAP_SM_PS_DISABLED: | 	case IEEE80211_SMPS_OFF: | ||||||
| 		break; | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		IL_WARN("Invalid MIMO PS mode %d\n", mimo_ps_mode); | 		IL_WARN("Invalid MIMO PS mode %d\n", sta->smps_mode); | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -3162,18 +3160,23 @@ il_enqueue_hcmd(struct il_priv *il, struct il_host_cmd *cmd) | ||||||
| 		     idx, il->cmd_queue); | 		     idx, il->cmd_queue); | ||||||
| 	} | 	} | ||||||
| #endif | #endif | ||||||
|  | 
 | ||||||
|  | 	phys_addr = | ||||||
|  | 	    pci_map_single(il->pci_dev, &out_cmd->hdr, fix_size, | ||||||
|  | 			   PCI_DMA_BIDIRECTIONAL); | ||||||
|  | 	if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr))) { | ||||||
|  | 		idx = -ENOMEM; | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 	dma_unmap_addr_set(out_meta, mapping, phys_addr); | ||||||
|  | 	dma_unmap_len_set(out_meta, len, fix_size); | ||||||
|  | 
 | ||||||
| 	txq->need_update = 1; | 	txq->need_update = 1; | ||||||
| 
 | 
 | ||||||
| 	if (il->ops->txq_update_byte_cnt_tbl) | 	if (il->ops->txq_update_byte_cnt_tbl) | ||||||
| 		/* Set up entry in queue's byte count circular buffer */ | 		/* Set up entry in queue's byte count circular buffer */ | ||||||
| 		il->ops->txq_update_byte_cnt_tbl(il, txq, 0); | 		il->ops->txq_update_byte_cnt_tbl(il, txq, 0); | ||||||
| 
 | 
 | ||||||
| 	phys_addr = |  | ||||||
| 	    pci_map_single(il->pci_dev, &out_cmd->hdr, fix_size, |  | ||||||
| 			   PCI_DMA_BIDIRECTIONAL); |  | ||||||
| 	dma_unmap_addr_set(out_meta, mapping, phys_addr); |  | ||||||
| 	dma_unmap_len_set(out_meta, len, fix_size); |  | ||||||
| 
 |  | ||||||
| 	il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, fix_size, 1, | 	il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, fix_size, 1, | ||||||
| 					    U32_PAD(cmd->len)); | 					    U32_PAD(cmd->len)); | ||||||
| 
 | 
 | ||||||
|  | @ -3181,6 +3184,7 @@ il_enqueue_hcmd(struct il_priv *il, struct il_host_cmd *cmd) | ||||||
| 	q->write_ptr = il_queue_inc_wrap(q->write_ptr, q->n_bd); | 	q->write_ptr = il_queue_inc_wrap(q->write_ptr, q->n_bd); | ||||||
| 	il_txq_update_write_ptr(il, txq); | 	il_txq_update_write_ptr(il, txq); | ||||||
| 
 | 
 | ||||||
|  | out: | ||||||
| 	spin_unlock_irqrestore(&il->hcmd_lock, flags); | 	spin_unlock_irqrestore(&il->hcmd_lock, flags); | ||||||
| 	return idx; | 	return idx; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -338,7 +338,7 @@ int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx, | ||||||
| 
 | 
 | ||||||
| bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, | bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, | ||||||
| 			    struct iwl_rxon_context *ctx, | 			    struct iwl_rxon_context *ctx, | ||||||
| 			    struct ieee80211_sta_ht_cap *ht_cap); | 			    struct ieee80211_sta *sta); | ||||||
| 
 | 
 | ||||||
| static inline int iwl_sta_id(struct ieee80211_sta *sta) | static inline int iwl_sta_id(struct ieee80211_sta *sta) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -3897,6 +3897,24 @@ struct iwlagn_wowlan_kek_kck_material_cmd { | ||||||
| 	__le64	replay_ctr; | 	__le64	replay_ctr; | ||||||
| } __packed; | } __packed; | ||||||
| 
 | 
 | ||||||
|  | #define RF_KILL_INDICATOR_FOR_WOWLAN	0x87 | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * REPLY_WOWLAN_GET_STATUS = 0xe5 | ||||||
|  |  */ | ||||||
|  | struct iwlagn_wowlan_status { | ||||||
|  | 	__le64 replay_ctr; | ||||||
|  | 	__le32 rekey_status; | ||||||
|  | 	__le32 wakeup_reason; | ||||||
|  | 	u8 pattern_number; | ||||||
|  | 	u8 reserved1; | ||||||
|  | 	__le16 qos_seq_ctr[8]; | ||||||
|  | 	__le16 non_qos_seq_ctr; | ||||||
|  | 	__le16 reserved2; | ||||||
|  | 	union iwlagn_all_tsc_rsc tsc_rsc; | ||||||
|  | 	__le16 reserved3; | ||||||
|  | } __packed; | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * REPLY_WIPAN_PARAMS = 0xb2 (Commands and Notification) |  * REPLY_WIPAN_PARAMS = 0xb2 (Commands and Notification) | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  | @ -145,14 +145,13 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, | ||||||
| 	/* Tell mac80211 our characteristics */ | 	/* Tell mac80211 our characteristics */ | ||||||
| 	hw->flags = IEEE80211_HW_SIGNAL_DBM | | 	hw->flags = IEEE80211_HW_SIGNAL_DBM | | ||||||
| 		    IEEE80211_HW_AMPDU_AGGREGATION | | 		    IEEE80211_HW_AMPDU_AGGREGATION | | ||||||
| 		    IEEE80211_HW_NEED_DTIM_PERIOD | | 		    IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC | | ||||||
| 		    IEEE80211_HW_SPECTRUM_MGMT | | 		    IEEE80211_HW_SPECTRUM_MGMT | | ||||||
| 		    IEEE80211_HW_REPORTS_TX_ACK_STATUS | | 		    IEEE80211_HW_REPORTS_TX_ACK_STATUS | | ||||||
| 		    IEEE80211_HW_QUEUE_CONTROL | | 		    IEEE80211_HW_QUEUE_CONTROL | | ||||||
| 		    IEEE80211_HW_SUPPORTS_PS | | 		    IEEE80211_HW_SUPPORTS_PS | | ||||||
| 		    IEEE80211_HW_SUPPORTS_DYNAMIC_PS | | 		    IEEE80211_HW_SUPPORTS_DYNAMIC_PS | | ||||||
| 		    IEEE80211_HW_WANT_MONITOR_VIF | | 		    IEEE80211_HW_WANT_MONITOR_VIF; | ||||||
| 		    IEEE80211_HW_SCAN_WHILE_IDLE; |  | ||||||
| 
 | 
 | ||||||
| 	hw->offchannel_tx_hw_queue = IWL_AUX_QUEUE; | 	hw->offchannel_tx_hw_queue = IWL_AUX_QUEUE; | ||||||
| 	hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FMT; | 	hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FMT; | ||||||
|  | @ -442,52 +441,154 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw, | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | struct iwl_resume_data { | ||||||
|  | 	struct iwl_priv *priv; | ||||||
|  | 	struct iwlagn_wowlan_status *cmd; | ||||||
|  | 	bool valid; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static bool iwl_resume_status_fn(struct iwl_notif_wait_data *notif_wait, | ||||||
|  | 				 struct iwl_rx_packet *pkt, void *data) | ||||||
|  | { | ||||||
|  | 	struct iwl_resume_data *resume_data = data; | ||||||
|  | 	struct iwl_priv *priv = resume_data->priv; | ||||||
|  | 	u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; | ||||||
|  | 
 | ||||||
|  | 	if (len - 4 != sizeof(*resume_data->cmd)) { | ||||||
|  | 		IWL_ERR(priv, "rx wrong size data\n"); | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  | 	memcpy(resume_data->cmd, pkt->data, sizeof(*resume_data->cmd)); | ||||||
|  | 	resume_data->valid = true; | ||||||
|  | 
 | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int iwlagn_mac_resume(struct ieee80211_hw *hw) | static int iwlagn_mac_resume(struct ieee80211_hw *hw) | ||||||
| { | { | ||||||
| 	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); | 	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); | ||||||
| 	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; | 	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; | ||||||
| 	struct ieee80211_vif *vif; | 	struct ieee80211_vif *vif; | ||||||
| 	unsigned long flags; | 	u32 base; | ||||||
| 	u32 base, status = 0xffffffff; | 	int ret; | ||||||
| 	int ret = -EIO; | 	enum iwl_d3_status d3_status; | ||||||
|  | 	struct error_table_start { | ||||||
|  | 		/* cf. struct iwl_error_event_table */ | ||||||
|  | 		u32 valid; | ||||||
|  | 		u32 error_id; | ||||||
|  | 	} err_info; | ||||||
|  | 	struct iwl_notification_wait status_wait; | ||||||
|  | 	static const u8 status_cmd[] = { | ||||||
|  | 		REPLY_WOWLAN_GET_STATUS, | ||||||
|  | 	}; | ||||||
|  | 	struct iwlagn_wowlan_status status_data = {}; | ||||||
|  | 	struct iwl_resume_data resume_data = { | ||||||
|  | 		.priv = priv, | ||||||
|  | 		.cmd = &status_data, | ||||||
|  | 		.valid = false, | ||||||
|  | 	}; | ||||||
|  | 	struct cfg80211_wowlan_wakeup wakeup = { | ||||||
|  | 		.pattern_idx = -1, | ||||||
|  | 	}; | ||||||
|  | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||||||
|  | 	const struct fw_img *img; | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| 	IWL_DEBUG_MAC80211(priv, "enter\n"); | 	IWL_DEBUG_MAC80211(priv, "enter\n"); | ||||||
| 	mutex_lock(&priv->mutex); | 	mutex_lock(&priv->mutex); | ||||||
| 
 | 
 | ||||||
| 	iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR, | 	/* we'll clear ctx->vif during iwlagn_prepare_restart() */ | ||||||
| 			  CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); | 	vif = ctx->vif; | ||||||
|  | 
 | ||||||
|  | 	ret = iwl_trans_d3_resume(priv->trans, &d3_status); | ||||||
|  | 	if (ret) | ||||||
|  | 		goto out_unlock; | ||||||
|  | 
 | ||||||
|  | 	if (d3_status != IWL_D3_STATUS_ALIVE) { | ||||||
|  | 		IWL_INFO(priv, "Device was reset during suspend\n"); | ||||||
|  | 		goto out_unlock; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	base = priv->device_pointers.error_event_table; | 	base = priv->device_pointers.error_event_table; | ||||||
| 	if (iwlagn_hw_valid_rtc_data_addr(base)) { | 	if (!iwlagn_hw_valid_rtc_data_addr(base)) { | ||||||
| 		if (iwl_trans_grab_nic_access(priv->trans, true, &flags)) { | 		IWL_WARN(priv, "Invalid error table during resume!\n"); | ||||||
| 			iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base); | 		goto out_unlock; | ||||||
| 			status = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); | 	} | ||||||
| 			iwl_trans_release_nic_access(priv->trans, &flags); | 
 | ||||||
| 			ret = 0; | 	iwl_trans_read_mem_bytes(priv->trans, base, | ||||||
|  | 				 &err_info, sizeof(err_info)); | ||||||
|  | 
 | ||||||
|  | 	if (err_info.valid) { | ||||||
|  | 		IWL_INFO(priv, "error table is valid (%d, 0x%x)\n", | ||||||
|  | 			 err_info.valid, err_info.error_id); | ||||||
|  | 		if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) { | ||||||
|  | 			wakeup.rfkill_release = true; | ||||||
|  | 			ieee80211_report_wowlan_wakeup(vif, &wakeup, | ||||||
|  | 						       GFP_KERNEL); | ||||||
|  | 		} | ||||||
|  | 		goto out_unlock; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_IWLWIFI_DEBUGFS | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||||||
| 		if (ret == 0) { | 	img = &priv->fw->img[IWL_UCODE_WOWLAN]; | ||||||
| 			const struct fw_img *img; | 	if (!priv->wowlan_sram) | ||||||
| 
 |  | ||||||
| 			img = &(priv->fw->img[IWL_UCODE_WOWLAN]); |  | ||||||
| 			if (!priv->wowlan_sram) { |  | ||||||
| 		priv->wowlan_sram = | 		priv->wowlan_sram = | ||||||
| 			kzalloc(img->sec[IWL_UCODE_SECTION_DATA].len, | 			kzalloc(img->sec[IWL_UCODE_SECTION_DATA].len, | ||||||
| 				GFP_KERNEL); | 				GFP_KERNEL); | ||||||
| 			} |  | ||||||
| 
 | 
 | ||||||
| 	if (priv->wowlan_sram) | 	if (priv->wowlan_sram) | ||||||
| 				iwl_trans_read_mem( | 		iwl_trans_read_mem(priv->trans, 0x800000, | ||||||
| 				      priv->trans, 0x800000, |  | ||||||
| 				   priv->wowlan_sram, | 				   priv->wowlan_sram, | ||||||
| 				   img->sec[IWL_UCODE_SECTION_DATA].len / 4); | 				   img->sec[IWL_UCODE_SECTION_DATA].len / 4); | ||||||
| 		} |  | ||||||
| #endif | #endif | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * This is very strange. The GET_STATUS command is sent but the device | ||||||
|  | 	 * doesn't reply properly, it seems it doesn't close the RBD so one is | ||||||
|  | 	 * always left open ... As a result, we need to send another command | ||||||
|  | 	 * and have to reset the driver afterwards. As we need to switch to | ||||||
|  | 	 * runtime firmware again that'll happen. | ||||||
|  | 	 */ | ||||||
|  | 
 | ||||||
|  | 	iwl_init_notification_wait(&priv->notif_wait, &status_wait, status_cmd, | ||||||
|  | 				   ARRAY_SIZE(status_cmd), iwl_resume_status_fn, | ||||||
|  | 				   &resume_data); | ||||||
|  | 
 | ||||||
|  | 	iwl_dvm_send_cmd_pdu(priv, REPLY_WOWLAN_GET_STATUS, CMD_ASYNC, 0, NULL); | ||||||
|  | 	iwl_dvm_send_cmd_pdu(priv, REPLY_ECHO, CMD_ASYNC, 0, NULL); | ||||||
|  | 	/* an RBD is left open in the firmware now! */ | ||||||
|  | 
 | ||||||
|  | 	ret = iwl_wait_notification(&priv->notif_wait, &status_wait, HZ/5); | ||||||
|  | 	if (ret) | ||||||
|  | 		goto out_unlock; | ||||||
|  | 
 | ||||||
|  | 	if (resume_data.valid && priv->contexts[IWL_RXON_CTX_BSS].vif) { | ||||||
|  | 		u32 reasons = le32_to_cpu(status_data.wakeup_reason); | ||||||
|  | 		struct cfg80211_wowlan_wakeup *wakeup_report; | ||||||
|  | 
 | ||||||
|  | 		IWL_INFO(priv, "WoWLAN wakeup reason(s): 0x%.8x\n", reasons); | ||||||
|  | 
 | ||||||
|  | 		if (reasons) { | ||||||
|  | 			if (reasons & IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET) | ||||||
|  | 				wakeup.magic_pkt = true; | ||||||
|  | 			if (reasons & IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH) | ||||||
|  | 				wakeup.pattern_idx = status_data.pattern_number; | ||||||
|  | 			if (reasons & (IWLAGN_WOWLAN_WAKEUP_BEACON_MISS | | ||||||
|  | 				       IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE)) | ||||||
|  | 				wakeup.disconnect = true; | ||||||
|  | 			if (reasons & IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL) | ||||||
|  | 				wakeup.gtk_rekey_failure = true; | ||||||
|  | 			if (reasons & IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ) | ||||||
|  | 				wakeup.eap_identity_req = true; | ||||||
|  | 			if (reasons & IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE) | ||||||
|  | 				wakeup.four_way_handshake = true; | ||||||
|  | 			wakeup_report = &wakeup; | ||||||
|  | 		} else { | ||||||
|  | 			wakeup_report = NULL; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 	/* we'll clear ctx->vif during iwlagn_prepare_restart() */ | 		ieee80211_report_wowlan_wakeup(vif, wakeup_report, GFP_KERNEL); | ||||||
| 	vif = ctx->vif; | 	} | ||||||
| 
 | 
 | ||||||
| 	priv->wowlan = false; | 	priv->wowlan = false; | ||||||
| 
 | 
 | ||||||
|  | @ -497,6 +598,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) | ||||||
| 	iwl_connection_init_rx_config(priv, ctx); | 	iwl_connection_init_rx_config(priv, ctx); | ||||||
| 	iwlagn_set_rxon_chain(priv, ctx); | 	iwlagn_set_rxon_chain(priv, ctx); | ||||||
| 
 | 
 | ||||||
|  |  out_unlock: | ||||||
| 	mutex_unlock(&priv->mutex); | 	mutex_unlock(&priv->mutex); | ||||||
| 	IWL_DEBUG_MAC80211(priv, "leave\n"); | 	IWL_DEBUG_MAC80211(priv, "leave\n"); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1289,8 +1289,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, | ||||||
| 	if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) | 	if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) | ||||||
| 		return -1; | 		return -1; | ||||||
| 
 | 
 | ||||||
| 	if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) | 	if (sta->smps_mode == IEEE80211_SMPS_STATIC) | ||||||
| 						== WLAN_HT_CAP_SM_PS_STATIC) |  | ||||||
| 		return -1; | 		return -1; | ||||||
| 
 | 
 | ||||||
| 	/* Need both Tx chains/antennas to support MIMO */ | 	/* Need both Tx chains/antennas to support MIMO */ | ||||||
|  | @ -1305,7 +1304,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, | ||||||
| 	tbl->max_search = IWL_MAX_SEARCH; | 	tbl->max_search = IWL_MAX_SEARCH; | ||||||
| 	rate_mask = lq_sta->active_mimo2_rate; | 	rate_mask = lq_sta->active_mimo2_rate; | ||||||
| 
 | 
 | ||||||
| 	if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap)) | 	if (iwl_is_ht40_tx_allowed(priv, ctx, sta)) | ||||||
| 		tbl->is_ht40 = 1; | 		tbl->is_ht40 = 1; | ||||||
| 	else | 	else | ||||||
| 		tbl->is_ht40 = 0; | 		tbl->is_ht40 = 0; | ||||||
|  | @ -1345,8 +1344,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv, | ||||||
| 	if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) | 	if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) | ||||||
| 		return -1; | 		return -1; | ||||||
| 
 | 
 | ||||||
| 	if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) | 	if (sta->smps_mode == IEEE80211_SMPS_STATIC) | ||||||
| 						== WLAN_HT_CAP_SM_PS_STATIC) |  | ||||||
| 		return -1; | 		return -1; | ||||||
| 
 | 
 | ||||||
| 	/* Need both Tx chains/antennas to support MIMO */ | 	/* Need both Tx chains/antennas to support MIMO */ | ||||||
|  | @ -1361,7 +1359,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv, | ||||||
| 	tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; | 	tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; | ||||||
| 	rate_mask = lq_sta->active_mimo3_rate; | 	rate_mask = lq_sta->active_mimo3_rate; | ||||||
| 
 | 
 | ||||||
| 	if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap)) | 	if (iwl_is_ht40_tx_allowed(priv, ctx, sta)) | ||||||
| 		tbl->is_ht40 = 1; | 		tbl->is_ht40 = 1; | ||||||
| 	else | 	else | ||||||
| 		tbl->is_ht40 = 0; | 		tbl->is_ht40 = 0; | ||||||
|  | @ -1410,7 +1408,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv, | ||||||
| 	tbl->max_search = IWL_MAX_SEARCH; | 	tbl->max_search = IWL_MAX_SEARCH; | ||||||
| 	rate_mask = lq_sta->active_siso_rate; | 	rate_mask = lq_sta->active_siso_rate; | ||||||
| 
 | 
 | ||||||
| 	if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap)) | 	if (iwl_is_ht40_tx_allowed(priv, ctx, sta)) | ||||||
| 		tbl->is_ht40 = 1; | 		tbl->is_ht40 = 1; | ||||||
| 	else | 	else | ||||||
| 		tbl->is_ht40 = 0; | 		tbl->is_ht40 = 0; | ||||||
|  |  | ||||||
|  | @ -790,7 +790,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, | ||||||
| 
 | 
 | ||||||
| 	memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); | 	memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); | ||||||
| 
 | 
 | ||||||
| 	ieee80211_rx(priv->hw, skb); | 	ieee80211_rx_ni(priv->hw, skb); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) | static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) | ||||||
|  |  | ||||||
|  | @ -1545,10 +1545,9 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, | ||||||
| 				bss_conf->bssid); | 				bss_conf->bssid); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_ADHOC && | 	if (changes & BSS_CHANGED_BEACON && priv->beacon_ctx == ctx) { | ||||||
| 	    priv->beacon_ctx) { |  | ||||||
| 		if (iwlagn_update_beacon(priv, vif)) | 		if (iwlagn_update_beacon(priv, vif)) | ||||||
| 			IWL_ERR(priv, "Error sending IBSS beacon\n"); | 			IWL_ERR(priv, "Error updating beacon\n"); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	mutex_unlock(&priv->mutex); | 	mutex_unlock(&priv->mutex); | ||||||
|  |  | ||||||
|  | @ -77,7 +77,7 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, | ||||||
| 	IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n", | 	IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n", | ||||||
| 		       sta_id); | 		       sta_id); | ||||||
| 
 | 
 | ||||||
| 	spin_lock(&priv->sta_lock); | 	spin_lock_bh(&priv->sta_lock); | ||||||
| 
 | 
 | ||||||
| 	switch (add_sta_resp->status) { | 	switch (add_sta_resp->status) { | ||||||
| 	case ADD_STA_SUCCESS_MSK: | 	case ADD_STA_SUCCESS_MSK: | ||||||
|  | @ -119,7 +119,7 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, | ||||||
| 		       priv->stations[sta_id].sta.mode == | 		       priv->stations[sta_id].sta.mode == | ||||||
| 		       STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", | 		       STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", | ||||||
| 		       addsta->sta.addr); | 		       addsta->sta.addr); | ||||||
| 	spin_unlock(&priv->sta_lock); | 	spin_unlock_bh(&priv->sta_lock); | ||||||
| 
 | 
 | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  | @ -173,7 +173,7 @@ int iwl_send_add_sta(struct iwl_priv *priv, | ||||||
| 
 | 
 | ||||||
| bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, | bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, | ||||||
| 			    struct iwl_rxon_context *ctx, | 			    struct iwl_rxon_context *ctx, | ||||||
| 			    struct ieee80211_sta_ht_cap *ht_cap) | 			    struct ieee80211_sta *sta) | ||||||
| { | { | ||||||
| 	if (!ctx->ht.enabled || !ctx->ht.is_40mhz) | 	if (!ctx->ht.enabled || !ctx->ht.is_40mhz) | ||||||
| 		return false; | 		return false; | ||||||
|  | @ -183,20 +183,11 @@ bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, | ||||||
| 		return false; | 		return false; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/* special case for RXON */ | ||||||
| 	 * Remainder of this function checks ht_cap, but if it's | 	if (!sta) | ||||||
| 	 * NULL then we can do HT40 (special case for RXON) |  | ||||||
| 	 */ |  | ||||||
| 	if (!ht_cap) |  | ||||||
| 		return true; | 		return true; | ||||||
| 
 | 
 | ||||||
| 	if (!ht_cap->ht_supported) | 	return sta->bandwidth >= IEEE80211_STA_RX_BW_40; | ||||||
| 		return false; |  | ||||||
| 
 |  | ||||||
| 	if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) |  | ||||||
| 		return false; |  | ||||||
| 
 |  | ||||||
| 	return true; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void iwl_sta_calc_ht_flags(struct iwl_priv *priv, | static void iwl_sta_calc_ht_flags(struct iwl_priv *priv, | ||||||
|  | @ -205,7 +196,6 @@ static void iwl_sta_calc_ht_flags(struct iwl_priv *priv, | ||||||
| 				  __le32 *flags, __le32 *mask) | 				  __le32 *flags, __le32 *mask) | ||||||
| { | { | ||||||
| 	struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap; | 	struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap; | ||||||
| 	u8 mimo_ps_mode; |  | ||||||
| 
 | 
 | ||||||
| 	*mask = STA_FLG_RTS_MIMO_PROT_MSK | | 	*mask = STA_FLG_RTS_MIMO_PROT_MSK | | ||||||
| 		STA_FLG_MIMO_DIS_MSK | | 		STA_FLG_MIMO_DIS_MSK | | ||||||
|  | @ -217,26 +207,24 @@ static void iwl_sta_calc_ht_flags(struct iwl_priv *priv, | ||||||
| 	if (!sta || !sta_ht_inf->ht_supported) | 	if (!sta || !sta_ht_inf->ht_supported) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2; |  | ||||||
| 
 |  | ||||||
| 	IWL_DEBUG_INFO(priv, "STA %pM SM PS mode: %s\n", | 	IWL_DEBUG_INFO(priv, "STA %pM SM PS mode: %s\n", | ||||||
| 			sta->addr, | 			sta->addr, | ||||||
| 			(mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ? | 			(sta->smps_mode == IEEE80211_SMPS_STATIC) ? | ||||||
| 			"static" : | 			"static" : | ||||||
| 			(mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ? | 			(sta->smps_mode == IEEE80211_SMPS_DYNAMIC) ? | ||||||
| 			"dynamic" : "disabled"); | 			"dynamic" : "disabled"); | ||||||
| 
 | 
 | ||||||
| 	switch (mimo_ps_mode) { | 	switch (sta->smps_mode) { | ||||||
| 	case WLAN_HT_CAP_SM_PS_STATIC: | 	case IEEE80211_SMPS_STATIC: | ||||||
| 		*flags |= STA_FLG_MIMO_DIS_MSK; | 		*flags |= STA_FLG_MIMO_DIS_MSK; | ||||||
| 		break; | 		break; | ||||||
| 	case WLAN_HT_CAP_SM_PS_DYNAMIC: | 	case IEEE80211_SMPS_DYNAMIC: | ||||||
| 		*flags |= STA_FLG_RTS_MIMO_PROT_MSK; | 		*flags |= STA_FLG_RTS_MIMO_PROT_MSK; | ||||||
| 		break; | 		break; | ||||||
| 	case WLAN_HT_CAP_SM_PS_DISABLED: | 	case IEEE80211_SMPS_OFF: | ||||||
| 		break; | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		IWL_WARN(priv, "Invalid MIMO PS mode %d\n", mimo_ps_mode); | 		IWL_WARN(priv, "Invalid MIMO PS mode %d\n", sta->smps_mode); | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -246,7 +234,7 @@ static void iwl_sta_calc_ht_flags(struct iwl_priv *priv, | ||||||
| 	*flags |= cpu_to_le32( | 	*flags |= cpu_to_le32( | ||||||
| 		(u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); | 		(u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); | ||||||
| 
 | 
 | ||||||
| 	if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap)) | 	if (iwl_is_ht40_tx_allowed(priv, ctx, sta)) | ||||||
| 		*flags |= STA_FLG_HT40_EN_MSK; | 		*flags |= STA_FLG_HT40_EN_MSK; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1117,7 +1117,7 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, | ||||||
| 	sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >> | 	sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >> | ||||||
| 		IWLAGN_TX_RES_RA_POS; | 		IWLAGN_TX_RES_RA_POS; | ||||||
| 
 | 
 | ||||||
| 	spin_lock(&priv->sta_lock); | 	spin_lock_bh(&priv->sta_lock); | ||||||
| 
 | 
 | ||||||
| 	if (is_agg) | 	if (is_agg) | ||||||
| 		iwl_rx_reply_tx_agg(priv, tx_resp); | 		iwl_rx_reply_tx_agg(priv, tx_resp); | ||||||
|  | @ -1207,7 +1207,15 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, | ||||||
| 			freed++; | 			freed++; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		WARN_ON(!is_agg && freed != 1); | 		if (tid != IWL_TID_NON_QOS) { | ||||||
|  | 			priv->tid_data[sta_id][tid].next_reclaimed = | ||||||
|  | 				next_reclaimed; | ||||||
|  | 			IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n", | ||||||
|  | 					   next_reclaimed); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (!is_agg && freed != 1) | ||||||
|  | 			IWL_ERR(priv, "Q: %d, freed %d\n", txq_id, freed); | ||||||
| 
 | 
 | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * An offchannel frame can be send only on the AUX queue, where | 		 * An offchannel frame can be send only on the AUX queue, where | ||||||
|  | @ -1228,11 +1236,11 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, | ||||||
| 			   le16_to_cpu(tx_resp->seq_ctl)); | 			   le16_to_cpu(tx_resp->seq_ctl)); | ||||||
| 
 | 
 | ||||||
| 	iwl_check_abort_status(priv, tx_resp->frame_count, status); | 	iwl_check_abort_status(priv, tx_resp->frame_count, status); | ||||||
| 	spin_unlock(&priv->sta_lock); | 	spin_unlock_bh(&priv->sta_lock); | ||||||
| 
 | 
 | ||||||
| 	while (!skb_queue_empty(&skbs)) { | 	while (!skb_queue_empty(&skbs)) { | ||||||
| 		skb = __skb_dequeue(&skbs); | 		skb = __skb_dequeue(&skbs); | ||||||
| 		ieee80211_tx_status(priv->hw, skb); | 		ieee80211_tx_status_ni(priv->hw, skb); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (is_offchannel_skb) | 	if (is_offchannel_skb) | ||||||
|  | @ -1279,12 +1287,12 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | ||||||
| 	tid = ba_resp->tid; | 	tid = ba_resp->tid; | ||||||
| 	agg = &priv->tid_data[sta_id][tid].agg; | 	agg = &priv->tid_data[sta_id][tid].agg; | ||||||
| 
 | 
 | ||||||
| 	spin_lock(&priv->sta_lock); | 	spin_lock_bh(&priv->sta_lock); | ||||||
| 
 | 
 | ||||||
| 	if (unlikely(!agg->wait_for_ba)) { | 	if (unlikely(!agg->wait_for_ba)) { | ||||||
| 		if (unlikely(ba_resp->bitmap)) | 		if (unlikely(ba_resp->bitmap)) | ||||||
| 			IWL_ERR(priv, "Received BA when not expected\n"); | 			IWL_ERR(priv, "Received BA when not expected\n"); | ||||||
| 		spin_unlock(&priv->sta_lock); | 		spin_unlock_bh(&priv->sta_lock); | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -1298,7 +1306,7 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | ||||||
| 		IWL_DEBUG_TX_QUEUES(priv, | 		IWL_DEBUG_TX_QUEUES(priv, | ||||||
| 				    "Bad queue mapping txq_id=%d, agg_txq[sta:%d,tid:%d]=%d\n", | 				    "Bad queue mapping txq_id=%d, agg_txq[sta:%d,tid:%d]=%d\n", | ||||||
| 				    scd_flow, sta_id, tid, agg->txq_id); | 				    scd_flow, sta_id, tid, agg->txq_id); | ||||||
| 		spin_unlock(&priv->sta_lock); | 		spin_unlock_bh(&priv->sta_lock); | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -1367,11 +1375,11 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	spin_unlock(&priv->sta_lock); | 	spin_unlock_bh(&priv->sta_lock); | ||||||
| 
 | 
 | ||||||
| 	while (!skb_queue_empty(&reclaimed_skbs)) { | 	while (!skb_queue_empty(&reclaimed_skbs)) { | ||||||
| 		skb = __skb_dequeue(&reclaimed_skbs); | 		skb = __skb_dequeue(&reclaimed_skbs); | ||||||
| 		ieee80211_tx_status(priv->hw, skb); | 		ieee80211_tx_status_ni(priv->hw, skb); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -113,13 +113,13 @@ struct iwl_cfg; | ||||||
|  *	May sleep |  *	May sleep | ||||||
|  * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the |  * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the | ||||||
|  *	HCMD the this Rx responds to. |  *	HCMD the this Rx responds to. | ||||||
|  *	Must be atomic and called with BH disabled. |  *	This callback may sleep, it is called from a threaded IRQ handler. | ||||||
|  * @queue_full: notifies that a HW queue is full. |  * @queue_full: notifies that a HW queue is full. | ||||||
|  *	Must be atomic and called with BH disabled. |  *	Must be atomic and called with BH disabled. | ||||||
|  * @queue_not_full: notifies that a HW queue is not full any more. |  * @queue_not_full: notifies that a HW queue is not full any more. | ||||||
|  *	Must be atomic and called with BH disabled. |  *	Must be atomic and called with BH disabled. | ||||||
|  * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that |  * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that | ||||||
|  *	the radio is killed. Must be atomic. |  *	the radio is killed. May sleep. | ||||||
|  * @free_skb: allows the transport layer to free skbs that haven't been |  * @free_skb: allows the transport layer to free skbs that haven't been | ||||||
|  *	reclaimed by the op_mode. This can happen when the driver is freed and |  *	reclaimed by the op_mode. This can happen when the driver is freed and | ||||||
|  *	there are Tx packets pending in the transport layer. |  *	there are Tx packets pending in the transport layer. | ||||||
|  | @ -130,8 +130,7 @@ struct iwl_cfg; | ||||||
|  *	called with BH disabled. |  *	called with BH disabled. | ||||||
|  * @nic_config: configure NIC, called before firmware is started. |  * @nic_config: configure NIC, called before firmware is started. | ||||||
|  *	May sleep |  *	May sleep | ||||||
|  * @wimax_active: invoked when WiMax becomes active.  Must be atomic and called |  * @wimax_active: invoked when WiMax becomes active. May sleep | ||||||
|  *	with BH disabled. |  | ||||||
|  */ |  */ | ||||||
| struct iwl_op_mode_ops { | struct iwl_op_mode_ops { | ||||||
| 	struct iwl_op_mode *(*start)(struct iwl_trans *trans, | 	struct iwl_op_mode *(*start)(struct iwl_trans *trans, | ||||||
|  | @ -178,6 +177,7 @@ static inline int iwl_op_mode_rx(struct iwl_op_mode *op_mode, | ||||||
| 				  struct iwl_rx_cmd_buffer *rxb, | 				  struct iwl_rx_cmd_buffer *rxb, | ||||||
| 				  struct iwl_device_cmd *cmd) | 				  struct iwl_device_cmd *cmd) | ||||||
| { | { | ||||||
|  | 	might_sleep(); | ||||||
| 	return op_mode->ops->rx(op_mode, rxb, cmd); | 	return op_mode->ops->rx(op_mode, rxb, cmd); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -196,6 +196,7 @@ static inline void iwl_op_mode_queue_not_full(struct iwl_op_mode *op_mode, | ||||||
| static inline void iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode, | static inline void iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode, | ||||||
| 					  bool state) | 					  bool state) | ||||||
| { | { | ||||||
|  | 	might_sleep(); | ||||||
| 	op_mode->ops->hw_rf_kill(op_mode, state); | 	op_mode->ops->hw_rf_kill(op_mode, state); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -223,6 +224,7 @@ static inline void iwl_op_mode_nic_config(struct iwl_op_mode *op_mode) | ||||||
| 
 | 
 | ||||||
| static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode) | static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode) | ||||||
| { | { | ||||||
|  | 	might_sleep(); | ||||||
| 	op_mode->ops->wimax_active(op_mode); | 	op_mode->ops->wimax_active(op_mode); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -65,6 +65,7 @@ | ||||||
| 
 | 
 | ||||||
| #include <linux/ieee80211.h> | #include <linux/ieee80211.h> | ||||||
| #include <linux/mm.h> /* for page_address */ | #include <linux/mm.h> /* for page_address */ | ||||||
|  | #include <linux/lockdep.h> | ||||||
| 
 | 
 | ||||||
| #include "iwl-debug.h" | #include "iwl-debug.h" | ||||||
| #include "iwl-config.h" | #include "iwl-config.h" | ||||||
|  | @ -526,6 +527,10 @@ struct iwl_trans { | ||||||
| 
 | 
 | ||||||
| 	struct dentry *dbgfs_dir; | 	struct dentry *dbgfs_dir; | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_LOCKDEP | ||||||
|  | 	struct lockdep_map sync_cmd_lockdep_map; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| 	/* pointer to trans specific struct */ | 	/* pointer to trans specific struct */ | ||||||
| 	/*Ensure that this pointer will always be aligned to sizeof pointer */ | 	/*Ensure that this pointer will always be aligned to sizeof pointer */ | ||||||
| 	char trans_specific[0] __aligned(sizeof(void *)); | 	char trans_specific[0] __aligned(sizeof(void *)); | ||||||
|  | @ -604,10 +609,20 @@ static inline int iwl_trans_d3_resume(struct iwl_trans *trans, | ||||||
| static inline int iwl_trans_send_cmd(struct iwl_trans *trans, | static inline int iwl_trans_send_cmd(struct iwl_trans *trans, | ||||||
| 				     struct iwl_host_cmd *cmd) | 				     struct iwl_host_cmd *cmd) | ||||||
| { | { | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
| 	WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, | 	WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, | ||||||
| 		  "%s bad state = %d", __func__, trans->state); | 		  "%s bad state = %d", __func__, trans->state); | ||||||
| 
 | 
 | ||||||
| 	return trans->ops->send_cmd(trans, cmd); | 	if (!(cmd->flags & CMD_ASYNC)) | ||||||
|  | 		lock_map_acquire_read(&trans->sync_cmd_lockdep_map); | ||||||
|  | 
 | ||||||
|  | 	ret = trans->ops->send_cmd(trans, cmd); | ||||||
|  | 
 | ||||||
|  | 	if (!(cmd->flags & CMD_ASYNC)) | ||||||
|  | 		lock_map_release(&trans->sync_cmd_lockdep_map); | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline struct iwl_device_cmd * | static inline struct iwl_device_cmd * | ||||||
|  | @ -791,4 +806,14 @@ iwl_trans_release_nic_access(struct iwl_trans *trans, unsigned long *flags) | ||||||
| int __must_check iwl_pci_register_driver(void); | int __must_check iwl_pci_register_driver(void); | ||||||
| void iwl_pci_unregister_driver(void); | void iwl_pci_unregister_driver(void); | ||||||
| 
 | 
 | ||||||
|  | static inline void trans_lockdep_init(struct iwl_trans *trans) | ||||||
|  | { | ||||||
|  | #ifdef CONFIG_LOCKDEP | ||||||
|  | 	static struct lock_class_key __key; | ||||||
|  | 
 | ||||||
|  | 	lockdep_init_map(&trans->sync_cmd_lockdep_map, "sync_cmd_lockdep_map", | ||||||
|  | 			 &__key, 0); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #endif /* __iwl_trans_h__ */ | #endif /* __iwl_trans_h__ */ | ||||||
|  |  | ||||||
|  | @ -97,14 +97,14 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw, | ||||||
| 	struct inet6_ifaddr *ifa; | 	struct inet6_ifaddr *ifa; | ||||||
| 	int idx = 0; | 	int idx = 0; | ||||||
| 
 | 
 | ||||||
| 	read_lock(&idev->lock); | 	read_lock_bh(&idev->lock); | ||||||
| 	list_for_each_entry(ifa, &idev->addr_list, if_list) { | 	list_for_each_entry(ifa, &idev->addr_list, if_list) { | ||||||
| 		mvmvif->target_ipv6_addrs[idx] = ifa->addr; | 		mvmvif->target_ipv6_addrs[idx] = ifa->addr; | ||||||
| 		idx++; | 		idx++; | ||||||
| 		if (idx >= IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS) | 		if (idx >= IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS) | ||||||
| 			break; | 			break; | ||||||
| 	} | 	} | ||||||
| 	read_unlock(&idev->lock); | 	read_unlock_bh(&idev->lock); | ||||||
| 
 | 
 | ||||||
| 	mvmvif->num_target_ipv6_addrs = idx; | 	mvmvif->num_target_ipv6_addrs = idx; | ||||||
| } | } | ||||||
|  | @ -490,7 +490,7 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||||||
| 		return -EIO; | 		return -EIO; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ret = iwl_mvm_sta_add_to_fw(mvm, ap_sta); | 	ret = iwl_mvm_sta_send_to_fw(mvm, ap_sta, false); | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		return ret; | 		return ret; | ||||||
| 	rcu_assign_pointer(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], ap_sta); | 	rcu_assign_pointer(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], ap_sta); | ||||||
|  | @ -763,6 +763,146 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | ||||||
|  | 					 struct ieee80211_vif *vif) | ||||||
|  | { | ||||||
|  | 	u32 base = mvm->error_event_table; | ||||||
|  | 	struct error_table_start { | ||||||
|  | 		/* cf. struct iwl_error_event_table */ | ||||||
|  | 		u32 valid; | ||||||
|  | 		u32 error_id; | ||||||
|  | 	} err_info; | ||||||
|  | 	struct cfg80211_wowlan_wakeup wakeup = { | ||||||
|  | 		.pattern_idx = -1, | ||||||
|  | 	}; | ||||||
|  | 	struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup; | ||||||
|  | 	struct iwl_host_cmd cmd = { | ||||||
|  | 		.id = WOWLAN_GET_STATUSES, | ||||||
|  | 		.flags = CMD_SYNC | CMD_WANT_SKB, | ||||||
|  | 	}; | ||||||
|  | 	struct iwl_wowlan_status *status; | ||||||
|  | 	u32 reasons; | ||||||
|  | 	int ret, len; | ||||||
|  | 	bool pkt8023 = false; | ||||||
|  | 	struct sk_buff *pkt = NULL; | ||||||
|  | 
 | ||||||
|  | 	iwl_trans_read_mem_bytes(mvm->trans, base, | ||||||
|  | 				 &err_info, sizeof(err_info)); | ||||||
|  | 
 | ||||||
|  | 	if (err_info.valid) { | ||||||
|  | 		IWL_INFO(mvm, "error table is valid (%d)\n", | ||||||
|  | 			 err_info.valid); | ||||||
|  | 		if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) { | ||||||
|  | 			wakeup.rfkill_release = true; | ||||||
|  | 			ieee80211_report_wowlan_wakeup(vif, &wakeup, | ||||||
|  | 						       GFP_KERNEL); | ||||||
|  | 		} | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* only for tracing for now */ | ||||||
|  | 	ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, CMD_SYNC, 0, NULL); | ||||||
|  | 	if (ret) | ||||||
|  | 		IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret); | ||||||
|  | 
 | ||||||
|  | 	ret = iwl_mvm_send_cmd(mvm, &cmd); | ||||||
|  | 	if (ret) { | ||||||
|  | 		IWL_ERR(mvm, "failed to query status (%d)\n", ret); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* RF-kill already asserted again... */ | ||||||
|  | 	if (!cmd.resp_pkt) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	len = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; | ||||||
|  | 	if (len - sizeof(struct iwl_cmd_header) < sizeof(*status)) { | ||||||
|  | 		IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	status = (void *)cmd.resp_pkt->data; | ||||||
|  | 
 | ||||||
|  | 	if (len - sizeof(struct iwl_cmd_header) != | ||||||
|  | 	    sizeof(*status) + le32_to_cpu(status->wake_packet_bufsize)) { | ||||||
|  | 		IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	reasons = le32_to_cpu(status->wakeup_reasons); | ||||||
|  | 
 | ||||||
|  | 	if (reasons == IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) { | ||||||
|  | 		wakeup_report = NULL; | ||||||
|  | 		goto report; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET) { | ||||||
|  | 		wakeup.magic_pkt = true; | ||||||
|  | 		pkt8023 = true; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN) { | ||||||
|  | 		wakeup.pattern_idx = | ||||||
|  | 			le16_to_cpu(status->pattern_number); | ||||||
|  | 		pkt8023 = true; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | | ||||||
|  | 		       IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH)) | ||||||
|  | 		wakeup.disconnect = true; | ||||||
|  | 
 | ||||||
|  | 	if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE) { | ||||||
|  | 		wakeup.gtk_rekey_failure = true; | ||||||
|  | 		pkt8023 = true; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED) { | ||||||
|  | 		wakeup.rfkill_release = true; | ||||||
|  | 		pkt8023 = true; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST) { | ||||||
|  | 		wakeup.eap_identity_req = true; | ||||||
|  | 		pkt8023 = true; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE) { | ||||||
|  | 		wakeup.four_way_handshake = true; | ||||||
|  | 		pkt8023 = true; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (status->wake_packet_bufsize) { | ||||||
|  | 		u32 pktsize = le32_to_cpu(status->wake_packet_bufsize); | ||||||
|  | 		u32 pktlen = le32_to_cpu(status->wake_packet_length); | ||||||
|  | 
 | ||||||
|  | 		if (pkt8023) { | ||||||
|  | 			pkt = alloc_skb(pktsize, GFP_KERNEL); | ||||||
|  | 			if (!pkt) | ||||||
|  | 				goto report; | ||||||
|  | 			memcpy(skb_put(pkt, pktsize), status->wake_packet, | ||||||
|  | 			       pktsize); | ||||||
|  | 			if (ieee80211_data_to_8023(pkt, vif->addr, vif->type)) | ||||||
|  | 				goto report; | ||||||
|  | 			wakeup.packet = pkt->data; | ||||||
|  | 			wakeup.packet_present_len = pkt->len; | ||||||
|  | 			wakeup.packet_len = pkt->len - (pktlen - pktsize); | ||||||
|  | 			wakeup.packet_80211 = false; | ||||||
|  | 		} else { | ||||||
|  | 			wakeup.packet = status->wake_packet; | ||||||
|  | 			wakeup.packet_present_len = pktsize; | ||||||
|  | 			wakeup.packet_len = pktlen; | ||||||
|  | 			wakeup.packet_80211 = true; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  |  report: | ||||||
|  | 	ieee80211_report_wowlan_wakeup(vif, wakeup_report, GFP_KERNEL); | ||||||
|  | 	kfree_skb(pkt); | ||||||
|  | 
 | ||||||
|  |  out: | ||||||
|  | 	iwl_free_resp(&cmd); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int iwl_mvm_resume(struct ieee80211_hw *hw) | int iwl_mvm_resume(struct ieee80211_hw *hw) | ||||||
| { | { | ||||||
| 	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||||||
|  | @ -770,14 +910,8 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) | ||||||
| 		.mvm = mvm, | 		.mvm = mvm, | ||||||
| 	}; | 	}; | ||||||
| 	struct ieee80211_vif *vif = NULL; | 	struct ieee80211_vif *vif = NULL; | ||||||
| 	u32 base; |  | ||||||
| 	int ret; | 	int ret; | ||||||
| 	enum iwl_d3_status d3_status; | 	enum iwl_d3_status d3_status; | ||||||
| 	struct error_table_start { |  | ||||||
| 		/* cf. struct iwl_error_event_table */ |  | ||||||
| 		u32 valid; |  | ||||||
| 		u32 error_id; |  | ||||||
| 	} err_info; |  | ||||||
| 
 | 
 | ||||||
| 	mutex_lock(&mvm->mutex); | 	mutex_lock(&mvm->mutex); | ||||||
| 
 | 
 | ||||||
|  | @ -800,27 +934,7 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) | ||||||
| 		goto out_unlock; | 		goto out_unlock; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	base = mvm->error_event_table; | 	iwl_mvm_query_wakeup_reasons(mvm, vif); | ||||||
| 
 |  | ||||||
| 	iwl_trans_read_mem_bytes(mvm->trans, base, |  | ||||||
| 				 &err_info, sizeof(err_info)); |  | ||||||
| 
 |  | ||||||
| 	if (err_info.valid) { |  | ||||||
| 		IWL_INFO(mvm, "error table is valid (%d)\n", |  | ||||||
| 			 err_info.valid); |  | ||||||
| 		if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) |  | ||||||
| 			IWL_ERR(mvm, "this was due to RF-kill\n"); |  | ||||||
| 		goto out_unlock; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* TODO: get status and whatever else ... */ |  | ||||||
| 	ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_GET_STATUSES, CMD_SYNC, 0, NULL); |  | ||||||
| 	if (ret) |  | ||||||
| 		IWL_ERR(mvm, "failed to query status (%d)\n", ret); |  | ||||||
| 
 |  | ||||||
| 	ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, CMD_SYNC, 0, NULL); |  | ||||||
| 	if (ret) |  | ||||||
| 		IWL_ERR(mvm, "failed to query offloads (%d)\n", ret); |  | ||||||
| 
 | 
 | ||||||
|  out_unlock: |  out_unlock: | ||||||
| 	mutex_unlock(&mvm->mutex); | 	mutex_unlock(&mvm->mutex); | ||||||
|  |  | ||||||
|  | @ -633,6 +633,9 @@ struct iwl_binding_cmd { | ||||||
| 	__le32 phy; | 	__le32 phy; | ||||||
| } __packed; /* BINDING_CMD_API_S_VER_1 */ | } __packed; /* BINDING_CMD_API_S_VER_1 */ | ||||||
| 
 | 
 | ||||||
|  | /* The maximal number of fragments in the FW's schedule session */ | ||||||
|  | #define IWL_MVM_MAX_QUOTA 128 | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * struct iwl_time_quota_data - configuration of time quota per binding |  * struct iwl_time_quota_data - configuration of time quota per binding | ||||||
|  * @id_and_color: ID and color of the relevant Binding |  * @id_and_color: ID and color of the relevant Binding | ||||||
|  |  | ||||||
|  | @ -621,10 +621,6 @@ int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, | ||||||
| 			  (flags & CT_KILL_CARD_DISABLED) ? | 			  (flags & CT_KILL_CARD_DISABLED) ? | ||||||
| 			  "Reached" : "Not reached"); | 			  "Reached" : "Not reached"); | ||||||
| 
 | 
 | ||||||
| 	if (flags & CARD_DISABLED_MSK) |  | ||||||
| 		iwl_write32(mvm->trans, CSR_UCODE_DRV_GP1_SET, |  | ||||||
| 			    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); |  | ||||||
| 
 |  | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -584,7 +584,11 @@ static void iwl_mvm_mac_ctxt_cmd_fill_sta(struct iwl_mvm *mvm, | ||||||
| 					  struct ieee80211_vif *vif, | 					  struct ieee80211_vif *vif, | ||||||
| 					  struct iwl_mac_data_sta *ctxt_sta) | 					  struct iwl_mac_data_sta *ctxt_sta) | ||||||
| { | { | ||||||
| 	ctxt_sta->is_assoc = cpu_to_le32(vif->bss_conf.assoc ? 1 : 0); | 	/* We need the dtim_period to set the MAC as associated */ | ||||||
|  | 	if (vif->bss_conf.assoc && vif->bss_conf.dtim_period) | ||||||
|  | 		ctxt_sta->is_assoc = cpu_to_le32(1); | ||||||
|  | 	else | ||||||
|  | 		ctxt_sta->is_assoc = cpu_to_le32(0); | ||||||
| 
 | 
 | ||||||
| 	ctxt_sta->bi = cpu_to_le32(vif->bss_conf.beacon_int); | 	ctxt_sta->bi = cpu_to_le32(vif->bss_conf.beacon_int); | ||||||
| 	ctxt_sta->bi_reciprocal = | 	ctxt_sta->bi_reciprocal = | ||||||
|  |  | ||||||
|  | @ -113,8 +113,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | ||||||
| 		    IEEE80211_HW_REPORTS_TX_ACK_STATUS | | 		    IEEE80211_HW_REPORTS_TX_ACK_STATUS | | ||||||
| 		    IEEE80211_HW_QUEUE_CONTROL | | 		    IEEE80211_HW_QUEUE_CONTROL | | ||||||
| 		    IEEE80211_HW_WANT_MONITOR_VIF | | 		    IEEE80211_HW_WANT_MONITOR_VIF | | ||||||
| 		    IEEE80211_HW_SCAN_WHILE_IDLE | | 		    IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC | | ||||||
| 		    IEEE80211_HW_NEED_DTIM_PERIOD | |  | ||||||
| 		    IEEE80211_HW_SUPPORTS_PS | | 		    IEEE80211_HW_SUPPORTS_PS | | ||||||
| 		    IEEE80211_HW_SUPPORTS_DYNAMIC_PS | | 		    IEEE80211_HW_SUPPORTS_DYNAMIC_PS | | ||||||
| 		    IEEE80211_HW_AMPDU_AGGREGATION; | 		    IEEE80211_HW_AMPDU_AGGREGATION; | ||||||
|  | @ -475,7 +474,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | ||||||
| 	if (mvm->vif_count > 1) { | 	if (mvm->vif_count > 1) { | ||||||
| 		IWL_DEBUG_MAC80211(mvm, | 		IWL_DEBUG_MAC80211(mvm, | ||||||
| 				   "Disable power on existing interfaces\n"); | 				   "Disable power on existing interfaces\n"); | ||||||
| 		ieee80211_iterate_active_interfaces( | 		ieee80211_iterate_active_interfaces_atomic( | ||||||
| 					    mvm->hw, | 					    mvm->hw, | ||||||
| 					    IEEE80211_IFACE_ITER_NORMAL, | 					    IEEE80211_IFACE_ITER_NORMAL, | ||||||
| 					    iwl_mvm_pm_disable_iterator, mvm); | 					    iwl_mvm_pm_disable_iterator, mvm); | ||||||
|  | @ -671,8 +670,6 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | ||||||
| 				IWL_ERR(mvm, "failed to update quotas\n"); | 				IWL_ERR(mvm, "failed to update quotas\n"); | ||||||
| 				return; | 				return; | ||||||
| 			} | 			} | ||||||
| 			iwl_mvm_remove_time_event(mvm, mvmvif, |  | ||||||
| 						  &mvmvif->time_event_data); |  | ||||||
| 		} else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { | 		} else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { | ||||||
| 			/* remove AP station now that the MAC is unassoc */ | 			/* remove AP station now that the MAC is unassoc */ | ||||||
| 			ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); | 			ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); | ||||||
|  | @ -684,6 +681,13 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | ||||||
| 			if (ret) | 			if (ret) | ||||||
| 				IWL_ERR(mvm, "failed to update quotas\n"); | 				IWL_ERR(mvm, "failed to update quotas\n"); | ||||||
| 		} | 		} | ||||||
|  | 	} else if (changes & BSS_CHANGED_DTIM_PERIOD) { | ||||||
|  | 		/*
 | ||||||
|  | 		 * We received a beacon _after_ association so | ||||||
|  | 		 * remove the session protection. | ||||||
|  | 		 */ | ||||||
|  | 		iwl_mvm_remove_time_event(mvm, mvmvif, | ||||||
|  | 					  &mvmvif->time_event_data); | ||||||
| 	} else if (changes & BSS_CHANGED_PS) { | 	} else if (changes & BSS_CHANGED_PS) { | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * TODO: remove this temporary code. | 		 * TODO: remove this temporary code. | ||||||
|  | @ -922,8 +926,10 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, | ||||||
| 		ret = 0; | 		ret = 0; | ||||||
| 	} else if (old_state == IEEE80211_STA_AUTH && | 	} else if (old_state == IEEE80211_STA_AUTH && | ||||||
| 		   new_state == IEEE80211_STA_ASSOC) { | 		   new_state == IEEE80211_STA_ASSOC) { | ||||||
| 		iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band); | 		ret = iwl_mvm_update_sta(mvm, vif, sta); | ||||||
| 		ret = 0; | 		if (ret == 0) | ||||||
|  | 			iwl_mvm_rs_rate_init(mvm, sta, | ||||||
|  | 					     mvmvif->phy_ctxt->channel->band); | ||||||
| 	} else if (old_state == IEEE80211_STA_ASSOC && | 	} else if (old_state == IEEE80211_STA_ASSOC && | ||||||
| 		   new_state == IEEE80211_STA_AUTHORIZED) { | 		   new_state == IEEE80211_STA_AUTHORIZED) { | ||||||
| 		ret = 0; | 		ret = 0; | ||||||
|  |  | ||||||
|  | @ -536,8 +536,11 @@ static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < ARRAY_SIZE(iwl_mvm_rx_handlers); i++) { | 	for (i = 0; i < ARRAY_SIZE(iwl_mvm_rx_handlers); i++) { | ||||||
| 		const struct iwl_rx_handlers *rx_h = &iwl_mvm_rx_handlers[i]; | 		const struct iwl_rx_handlers *rx_h = &iwl_mvm_rx_handlers[i]; | ||||||
| 		if (rx_h->cmd_id == pkt->hdr.cmd) { |  | ||||||
| 		struct iwl_async_handler_entry *entry; | 		struct iwl_async_handler_entry *entry; | ||||||
|  | 
 | ||||||
|  | 		if (rx_h->cmd_id != pkt->hdr.cmd) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
| 		if (!rx_h->async) | 		if (!rx_h->async) | ||||||
| 			return rx_h->fn(mvm, rxb, cmd); | 			return rx_h->fn(mvm, rxb, cmd); | ||||||
| 
 | 
 | ||||||
|  | @ -554,7 +557,7 @@ static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, | ||||||
| 		list_add_tail(&entry->list, &mvm->async_handlers_list); | 		list_add_tail(&entry->list, &mvm->async_handlers_list); | ||||||
| 		spin_unlock(&mvm->async_handlers_lock); | 		spin_unlock(&mvm->async_handlers_lock); | ||||||
| 		schedule_work(&mvm->async_handlers_wk); | 		schedule_work(&mvm->async_handlers_wk); | ||||||
| 		} | 		break; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -194,7 +194,7 @@ int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||||||
| 			cmd.id_and_color, iwlmvm_mod_params.power_scheme, | 			cmd.id_and_color, iwlmvm_mod_params.power_scheme, | ||||||
| 			le16_to_cpu(cmd.flags)); | 			le16_to_cpu(cmd.flags)); | ||||||
| 
 | 
 | ||||||
| 	return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, | 	return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC, | ||||||
| 				    sizeof(cmd), &cmd); | 				    sizeof(cmd), &cmd); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -131,7 +131,7 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac, | ||||||
| int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) | int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) | ||||||
| { | { | ||||||
| 	struct iwl_time_quota_cmd cmd; | 	struct iwl_time_quota_cmd cmd; | ||||||
| 	int i, idx, ret; | 	int i, idx, ret, num_active_bindings, quota, quota_rem; | ||||||
| 	struct iwl_mvm_quota_iterator_data data = { | 	struct iwl_mvm_quota_iterator_data data = { | ||||||
| 		.n_interfaces = {}, | 		.n_interfaces = {}, | ||||||
| 		.colors = { -1, -1, -1, -1 }, | 		.colors = { -1, -1, -1, -1 }, | ||||||
|  | @ -156,20 +156,39 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) | ||||||
| 		iwl_mvm_quota_iterator(&data, newvif->addr, newvif); | 		iwl_mvm_quota_iterator(&data, newvif->addr, newvif); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * The FW's scheduling session consists of | ||||||
|  | 	 * IWL_MVM_MAX_QUOTA fragments. Divide these fragments | ||||||
|  | 	 * equally between all the bindings that require quota | ||||||
|  | 	 */ | ||||||
|  | 	num_active_bindings = 0; | ||||||
|  | 	for (i = 0; i < MAX_BINDINGS; i++) { | ||||||
|  | 		cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID); | ||||||
|  | 		if (data.n_interfaces[i] > 0) | ||||||
|  | 			num_active_bindings++; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!num_active_bindings) | ||||||
|  | 		goto send_cmd; | ||||||
|  | 
 | ||||||
|  | 	quota = IWL_MVM_MAX_QUOTA / num_active_bindings; | ||||||
|  | 	quota_rem = IWL_MVM_MAX_QUOTA % num_active_bindings; | ||||||
|  | 
 | ||||||
| 	for (idx = 0, i = 0; i < MAX_BINDINGS; i++) { | 	for (idx = 0, i = 0; i < MAX_BINDINGS; i++) { | ||||||
| 		if (data.n_interfaces[i] <= 0) | 		if (data.n_interfaces[i] <= 0) | ||||||
| 			continue; | 			continue; | ||||||
| 
 | 
 | ||||||
| 		cmd.quotas[idx].id_and_color = | 		cmd.quotas[idx].id_and_color = | ||||||
| 			cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i])); | 			cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i])); | ||||||
| 		cmd.quotas[idx].quota = cpu_to_le32(100); | 		cmd.quotas[idx].quota = cpu_to_le32(quota); | ||||||
| 		cmd.quotas[idx].max_duration = cpu_to_le32(1000); | 		cmd.quotas[idx].max_duration = cpu_to_le32(IWL_MVM_MAX_QUOTA); | ||||||
| 		idx++; | 		idx++; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for (i = idx; i < MAX_BINDINGS; i++) | 	/* Give the remainder of the session to the first binding */ | ||||||
| 		cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID); | 	le32_add_cpu(&cmd.quotas[0].quota, quota_rem); | ||||||
| 
 | 
 | ||||||
|  | send_cmd: | ||||||
| 	ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC, | 	ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC, | ||||||
| 				   sizeof(cmd), &cmd); | 				   sizeof(cmd), &cmd); | ||||||
| 	if (ret) | 	if (ret) | ||||||
|  |  | ||||||
|  | @ -1209,23 +1209,9 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm, | ||||||
| 	return new_rate; | 	return new_rate; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool iwl_is_ht40_tx_allowed(struct iwl_mvm *mvm, | static bool iwl_is_ht40_tx_allowed(struct ieee80211_sta *sta) | ||||||
| 			    struct ieee80211_sta_ht_cap *ht_cap) |  | ||||||
| { | { | ||||||
| 	/*
 | 	return sta->bandwidth >= IEEE80211_STA_RX_BW_40; | ||||||
| 	 * Remainder of this function checks ht_cap, but if it's |  | ||||||
| 	 * NULL then we can do HT40 (special case for RXON) |  | ||||||
| 	 */ |  | ||||||
| 	if (!ht_cap) |  | ||||||
| 		return true; |  | ||||||
| 
 |  | ||||||
| 	if (!ht_cap->ht_supported) |  | ||||||
| 		return false; |  | ||||||
| 
 |  | ||||||
| 	if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) |  | ||||||
| 		return false; |  | ||||||
| 
 |  | ||||||
| 	return true; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -1243,8 +1229,7 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm, | ||||||
| 	if (!sta->ht_cap.ht_supported) | 	if (!sta->ht_cap.ht_supported) | ||||||
| 		return -1; | 		return -1; | ||||||
| 
 | 
 | ||||||
| 	if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) | 	if (sta->smps_mode == IEEE80211_SMPS_STATIC) | ||||||
| 						== WLAN_HT_CAP_SM_PS_STATIC) |  | ||||||
| 		return -1; | 		return -1; | ||||||
| 
 | 
 | ||||||
| 	/* Need both Tx chains/antennas to support MIMO */ | 	/* Need both Tx chains/antennas to support MIMO */ | ||||||
|  | @ -1258,7 +1243,7 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm, | ||||||
| 	tbl->max_search = IWL_MAX_SEARCH; | 	tbl->max_search = IWL_MAX_SEARCH; | ||||||
| 	rate_mask = lq_sta->active_mimo2_rate; | 	rate_mask = lq_sta->active_mimo2_rate; | ||||||
| 
 | 
 | ||||||
| 	if (iwl_is_ht40_tx_allowed(mvm, &sta->ht_cap)) | 	if (iwl_is_ht40_tx_allowed(sta)) | ||||||
| 		tbl->is_ht40 = 1; | 		tbl->is_ht40 = 1; | ||||||
| 	else | 	else | ||||||
| 		tbl->is_ht40 = 0; | 		tbl->is_ht40 = 0; | ||||||
|  | @ -1296,8 +1281,7 @@ static int rs_switch_to_mimo3(struct iwl_mvm *mvm, | ||||||
| 	if (!sta->ht_cap.ht_supported) | 	if (!sta->ht_cap.ht_supported) | ||||||
| 		return -1; | 		return -1; | ||||||
| 
 | 
 | ||||||
| 	if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) | 	if (sta->smps_mode == IEEE80211_SMPS_STATIC) | ||||||
| 						== WLAN_HT_CAP_SM_PS_STATIC) |  | ||||||
| 		return -1; | 		return -1; | ||||||
| 
 | 
 | ||||||
| 	/* Need both Tx chains/antennas to support MIMO */ | 	/* Need both Tx chains/antennas to support MIMO */ | ||||||
|  | @ -1311,7 +1295,7 @@ static int rs_switch_to_mimo3(struct iwl_mvm *mvm, | ||||||
| 	tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; | 	tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; | ||||||
| 	rate_mask = lq_sta->active_mimo3_rate; | 	rate_mask = lq_sta->active_mimo3_rate; | ||||||
| 
 | 
 | ||||||
| 	if (iwl_is_ht40_tx_allowed(mvm, &sta->ht_cap)) | 	if (iwl_is_ht40_tx_allowed(sta)) | ||||||
| 		tbl->is_ht40 = 1; | 		tbl->is_ht40 = 1; | ||||||
| 	else | 	else | ||||||
| 		tbl->is_ht40 = 0; | 		tbl->is_ht40 = 0; | ||||||
|  | @ -1356,7 +1340,7 @@ static int rs_switch_to_siso(struct iwl_mvm *mvm, | ||||||
| 	tbl->max_search = IWL_MAX_SEARCH; | 	tbl->max_search = IWL_MAX_SEARCH; | ||||||
| 	rate_mask = lq_sta->active_siso_rate; | 	rate_mask = lq_sta->active_siso_rate; | ||||||
| 
 | 
 | ||||||
| 	if (iwl_is_ht40_tx_allowed(mvm, &sta->ht_cap)) | 	if (iwl_is_ht40_tx_allowed(sta)) | ||||||
| 		tbl->is_ht40 = 1; | 		tbl->is_ht40 = 1; | ||||||
| 	else | 	else | ||||||
| 		tbl->is_ht40 = 0; | 		tbl->is_ht40 = 0; | ||||||
|  |  | ||||||
|  | @ -121,7 +121,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, | ||||||
| 
 | 
 | ||||||
| 	memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); | 	memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); | ||||||
| 
 | 
 | ||||||
| 	ieee80211_rx(mvm->hw, skb); | 	ieee80211_rx_ni(mvm->hw, skb); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  |  | ||||||
|  | @ -81,8 +81,9 @@ static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm) | ||||||
| 	return IWL_MVM_STATION_COUNT; | 	return IWL_MVM_STATION_COUNT; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* add a NEW station to fw */ | /* send station add/update command to firmware */ | ||||||
| int iwl_mvm_sta_add_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta) | int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | ||||||
|  | 			   bool update) | ||||||
| { | { | ||||||
| 	struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | 	struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | ||||||
| 	struct iwl_mvm_add_sta_cmd add_sta_cmd; | 	struct iwl_mvm_add_sta_cmd add_sta_cmd; | ||||||
|  | @ -94,8 +95,11 @@ int iwl_mvm_sta_add_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta) | ||||||
| 
 | 
 | ||||||
| 	add_sta_cmd.sta_id = mvm_sta->sta_id; | 	add_sta_cmd.sta_id = mvm_sta->sta_id; | ||||||
| 	add_sta_cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); | 	add_sta_cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); | ||||||
|  | 	if (!update) { | ||||||
| 		add_sta_cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk); | 		add_sta_cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk); | ||||||
| 		memcpy(&add_sta_cmd.addr, sta->addr, ETH_ALEN); | 		memcpy(&add_sta_cmd.addr, sta->addr, ETH_ALEN); | ||||||
|  | 	} | ||||||
|  | 	add_sta_cmd.add_modify = update ? 1 : 0; | ||||||
| 
 | 
 | ||||||
| 	/* STA_FLG_FAT_EN_MSK ? */ | 	/* STA_FLG_FAT_EN_MSK ? */ | ||||||
| 	/* STA_FLG_MIMO_EN_MSK ? */ | 	/* STA_FLG_MIMO_EN_MSK ? */ | ||||||
|  | @ -181,7 +185,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, | ||||||
| 	/* for HW restart - need to reset the seq_number etc... */ | 	/* for HW restart - need to reset the seq_number etc... */ | ||||||
| 	memset(mvm_sta->tid_data, 0, sizeof(mvm_sta->tid_data)); | 	memset(mvm_sta->tid_data, 0, sizeof(mvm_sta->tid_data)); | ||||||
| 
 | 
 | ||||||
| 	ret = iwl_mvm_sta_add_to_fw(mvm, sta); | 	ret = iwl_mvm_sta_send_to_fw(mvm, sta, false); | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		return ret; | 		return ret; | ||||||
| 
 | 
 | ||||||
|  | @ -195,6 +199,13 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | int iwl_mvm_update_sta(struct iwl_mvm *mvm, | ||||||
|  | 		       struct ieee80211_vif *vif, | ||||||
|  | 		       struct ieee80211_sta *sta) | ||||||
|  | { | ||||||
|  | 	return iwl_mvm_sta_send_to_fw(mvm, sta, true); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, | int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, | ||||||
| 		      bool drain) | 		      bool drain) | ||||||
| { | { | ||||||
|  | @ -1116,7 +1127,8 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, | ||||||
| 	if (WARN_ON_ONCE(mvm_sta->vif != vif)) | 	if (WARN_ON_ONCE(mvm_sta->vif != vif)) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
| 	key_flags = cpu_to_le16(keyconf->keyidx & STA_KEY_FLG_KEYID_MSK); | 	key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & | ||||||
|  | 				 STA_KEY_FLG_KEYID_MSK); | ||||||
| 	key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP); | 	key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP); | ||||||
| 	key_flags |= cpu_to_le16(STA_KEY_NOT_VALID); | 	key_flags |= cpu_to_le16(STA_KEY_NOT_VALID); | ||||||
| 
 | 
 | ||||||
|  | @ -1154,14 +1166,26 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, | ||||||
| 			     struct ieee80211_sta *sta, u32 iv32, | 			     struct ieee80211_sta *sta, u32 iv32, | ||||||
| 			     u16 *phase1key) | 			     u16 *phase1key) | ||||||
| { | { | ||||||
| 	struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | 	struct iwl_mvm_sta *mvm_sta; | ||||||
| 	u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta); | 	u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta); | ||||||
| 
 | 
 | ||||||
| 	if (sta_id == IWL_INVALID_STATION) | 	if (WARN_ON_ONCE(sta_id == IWL_INVALID_STATION)) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
|  | 	rcu_read_lock(); | ||||||
|  | 
 | ||||||
|  | 	if (!sta) { | ||||||
|  | 		sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); | ||||||
|  | 		if (WARN_ON(IS_ERR_OR_NULL(sta))) { | ||||||
|  | 			rcu_read_unlock(); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mvm_sta = (void *)sta->drv_priv; | ||||||
| 	iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id, | 	iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id, | ||||||
| 			     iv32, phase1key, CMD_ASYNC); | 			     iv32, phase1key, CMD_ASYNC); | ||||||
|  | 	rcu_read_unlock(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, int sta_id) | void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, int sta_id) | ||||||
|  |  | ||||||
|  | @ -309,10 +309,14 @@ struct iwl_mvm_int_sta { | ||||||
| 	u32 tfd_queue_msk; | 	u32 tfd_queue_msk; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| int iwl_mvm_sta_add_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta); | int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | ||||||
|  | 			   bool update); | ||||||
| int iwl_mvm_add_sta(struct iwl_mvm *mvm, | int iwl_mvm_add_sta(struct iwl_mvm *mvm, | ||||||
| 		    struct ieee80211_vif *vif, | 		    struct ieee80211_vif *vif, | ||||||
| 		    struct ieee80211_sta *sta); | 		    struct ieee80211_sta *sta); | ||||||
|  | int iwl_mvm_update_sta(struct iwl_mvm *mvm, | ||||||
|  | 		       struct ieee80211_vif *vif, | ||||||
|  | 		       struct ieee80211_sta *sta); | ||||||
| int iwl_mvm_rm_sta(struct iwl_mvm *mvm, | int iwl_mvm_rm_sta(struct iwl_mvm *mvm, | ||||||
| 		   struct ieee80211_vif *vif, | 		   struct ieee80211_vif *vif, | ||||||
| 		   struct ieee80211_sta *sta); | 		   struct ieee80211_sta *sta); | ||||||
|  |  | ||||||
|  | @ -76,6 +76,15 @@ | ||||||
| #define TU_TO_JIFFIES(_tu)	(usecs_to_jiffies((_tu) * 1024)) | #define TU_TO_JIFFIES(_tu)	(usecs_to_jiffies((_tu) * 1024)) | ||||||
| #define MSEC_TO_TU(_msec)	(_msec*1000/1024) | #define MSEC_TO_TU(_msec)	(_msec*1000/1024) | ||||||
| 
 | 
 | ||||||
|  | /* For ROC use a TE type which has priority high enough to be scheduled when
 | ||||||
|  |  * there is a concurrent BSS or GO/AP. Currently, use a TE type that has | ||||||
|  |  * priority similar to the TE priority used for action scans by the FW. | ||||||
|  |  * TODO: This needs to be changed, based on the reason for the ROC, i.e., use | ||||||
|  |  * TE_P2P_DEVICE_DISCOVERABLE for remain on channel without mgmt skb, and use | ||||||
|  |  * TE_P2P_DEVICE_ACTION_SCAN | ||||||
|  |  */ | ||||||
|  | #define IWL_MVM_ROC_TE_TYPE TE_P2P_DEVICE_ACTION_SCAN | ||||||
|  | 
 | ||||||
| void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, | void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, | ||||||
| 			   struct iwl_mvm_time_event_data *te_data) | 			   struct iwl_mvm_time_event_data *te_data) | ||||||
| { | { | ||||||
|  | @ -175,9 +184,11 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, | ||||||
| 		 */ | 		 */ | ||||||
| 		if (te_data->vif->type == NL80211_IFTYPE_STATION && | 		if (te_data->vif->type == NL80211_IFTYPE_STATION && | ||||||
| 		    (!te_data->vif->bss_conf.assoc || | 		    (!te_data->vif->bss_conf.assoc || | ||||||
| 		     !te_data->vif->bss_conf.dtim_period)) | 		     !te_data->vif->bss_conf.dtim_period)) { | ||||||
| 			IWL_ERR(mvm, | 			IWL_ERR(mvm, | ||||||
| 				"No assocation and the time event is over already...\n"); | 				"No assocation and the time event is over already...\n"); | ||||||
|  | 			ieee80211_connection_loss(te_data->vif); | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		iwl_mvm_te_clear_data(mvm, te_data); | 		iwl_mvm_te_clear_data(mvm, te_data); | ||||||
| 	} else if (le32_to_cpu(notif->action) == TE_NOTIF_HOST_START) { | 	} else if (le32_to_cpu(notif->action) == TE_NOTIF_HOST_START) { | ||||||
|  | @ -219,57 +230,86 @@ int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool iwl_mvm_time_event_notif(struct iwl_notif_wait_data *notif_wait, | static bool iwl_mvm_time_event_response(struct iwl_notif_wait_data *notif_wait, | ||||||
| 					struct iwl_rx_packet *pkt, void *data) | 					struct iwl_rx_packet *pkt, void *data) | ||||||
| { | { | ||||||
| 	struct iwl_mvm *mvm = | 	struct iwl_mvm *mvm = | ||||||
| 		container_of(notif_wait, struct iwl_mvm, notif_wait); | 		container_of(notif_wait, struct iwl_mvm, notif_wait); | ||||||
| 	struct iwl_mvm_time_event_data *te_data = data; | 	struct iwl_mvm_time_event_data *te_data = data; | ||||||
| 	struct ieee80211_vif *vif = te_data->vif; |  | ||||||
| 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |  | ||||||
| 	struct iwl_time_event_notif *notif; |  | ||||||
| 	struct iwl_time_event_resp *resp; | 	struct iwl_time_event_resp *resp; | ||||||
|  | 	int resp_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; | ||||||
| 
 | 
 | ||||||
| 	u32 mac_id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color); | 	if (WARN_ON(pkt->hdr.cmd != TIME_EVENT_CMD)) | ||||||
| 
 |  | ||||||
| 	/* until we do something else */ |  | ||||||
| 	WARN_ON(te_data->id != TE_BSS_STA_AGGRESSIVE_ASSOC); |  | ||||||
| 
 |  | ||||||
| 	switch (pkt->hdr.cmd) { |  | ||||||
| 	case TIME_EVENT_CMD: |  | ||||||
| 		resp = (void *)pkt->data; |  | ||||||
| 		/* TODO: I can't check that since the fw is buggy - it doesn't
 |  | ||||||
| 		 * put the right values when we remove a TE. We can be here |  | ||||||
| 		 * when we remove a TE because the remove TE command is sent in |  | ||||||
| 		 * ASYNC... |  | ||||||
| 		 * WARN_ON(mac_id_n_color != le32_to_cpu(resp->id_and_color)); |  | ||||||
| 		 */ |  | ||||||
| 		te_data->uid = le32_to_cpu(resp->unique_id); |  | ||||||
| 		IWL_DEBUG_TE(mvm, "Got response - UID = 0x%x\n", te_data->uid); |  | ||||||
| 		return false; |  | ||||||
| 
 |  | ||||||
| 	case TIME_EVENT_NOTIFICATION: |  | ||||||
| 		notif = (void *)pkt->data; |  | ||||||
| 		WARN_ON(le32_to_cpu(notif->status) != 1); |  | ||||||
| 		WARN_ON(mac_id_n_color != le32_to_cpu(notif->id_and_color)); |  | ||||||
| 		/* check if this is our Time Event that is starting */ |  | ||||||
| 		if (le32_to_cpu(notif->unique_id) != te_data->uid) |  | ||||||
| 			return false; |  | ||||||
| 		IWL_DEBUG_TE(mvm, "Event %d is starting - time is %d\n", |  | ||||||
| 			     te_data->uid, le32_to_cpu(notif->timestamp)); |  | ||||||
| 
 |  | ||||||
| 		WARN_ONCE(!le32_to_cpu(notif->status), |  | ||||||
| 			  "Failed to schedule protected session TE\n"); |  | ||||||
| 
 |  | ||||||
| 		te_data->running = true; |  | ||||||
| 		te_data->end_jiffies = jiffies + |  | ||||||
| 				       TU_TO_JIFFIES(te_data->duration); |  | ||||||
| 		return true; | 		return true; | ||||||
| 
 | 
 | ||||||
| 	default: | 	if (WARN_ON_ONCE(resp_len != sizeof(pkt->hdr) + sizeof(*resp))) { | ||||||
| 		WARN_ON(1); | 		IWL_ERR(mvm, "Invalid TIME_EVENT_CMD response\n"); | ||||||
| 		return false; | 		return true; | ||||||
| 	}; | 	} | ||||||
|  | 
 | ||||||
|  | 	resp = (void *)pkt->data; | ||||||
|  | 	te_data->uid = le32_to_cpu(resp->unique_id); | ||||||
|  | 	IWL_DEBUG_TE(mvm, "TIME_EVENT_CMD response - UID = 0x%x\n", | ||||||
|  | 		     te_data->uid); | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm, | ||||||
|  | 				       struct ieee80211_vif *vif, | ||||||
|  | 				       struct iwl_mvm_time_event_data *te_data, | ||||||
|  | 				       struct iwl_time_event_cmd *te_cmd) | ||||||
|  | { | ||||||
|  | 	static const u8 time_event_response[] = { TIME_EVENT_CMD }; | ||||||
|  | 	struct iwl_notification_wait wait_time_event; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	lockdep_assert_held(&mvm->mutex); | ||||||
|  | 
 | ||||||
|  | 	spin_lock_bh(&mvm->time_event_lock); | ||||||
|  | 	if (WARN_ON(te_data->id != TE_MAX)) { | ||||||
|  | 		spin_unlock_bh(&mvm->time_event_lock); | ||||||
|  | 		return -EIO; | ||||||
|  | 	} | ||||||
|  | 	te_data->vif = vif; | ||||||
|  | 	te_data->duration = le32_to_cpu(te_cmd->duration); | ||||||
|  | 	te_data->id = le32_to_cpu(te_cmd->id); | ||||||
|  | 	list_add_tail(&te_data->list, &mvm->time_event_list); | ||||||
|  | 	spin_unlock_bh(&mvm->time_event_lock); | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Use a notification wait, which really just processes the | ||||||
|  | 	 * command response and doesn't wait for anything, in order | ||||||
|  | 	 * to be able to process the response and get the UID inside | ||||||
|  | 	 * the RX path. Using CMD_WANT_SKB doesn't work because it | ||||||
|  | 	 * stores the buffer and then wakes up this thread, by which | ||||||
|  | 	 * time another notification (that the time event started) | ||||||
|  | 	 * might already be processed unsuccessfully. | ||||||
|  | 	 */ | ||||||
|  | 	iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event, | ||||||
|  | 				   time_event_response, | ||||||
|  | 				   ARRAY_SIZE(time_event_response), | ||||||
|  | 				   iwl_mvm_time_event_response, te_data); | ||||||
|  | 
 | ||||||
|  | 	ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, | ||||||
|  | 				   sizeof(*te_cmd), te_cmd); | ||||||
|  | 	if (ret) { | ||||||
|  | 		IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret); | ||||||
|  | 		iwl_remove_notification(&mvm->notif_wait, &wait_time_event); | ||||||
|  | 		goto out_clear_te; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* No need to wait for anything, so just pass 1 (0 isn't valid) */ | ||||||
|  | 	ret = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1); | ||||||
|  | 	/* should never fail */ | ||||||
|  | 	WARN_ON_ONCE(ret); | ||||||
|  | 
 | ||||||
|  | 	if (ret) { | ||||||
|  |  out_clear_te: | ||||||
|  | 		spin_lock_bh(&mvm->time_event_lock); | ||||||
|  | 		iwl_mvm_te_clear_data(mvm, te_data); | ||||||
|  | 		spin_unlock_bh(&mvm->time_event_lock); | ||||||
|  | 	} | ||||||
|  | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void iwl_mvm_protect_session(struct iwl_mvm *mvm, | void iwl_mvm_protect_session(struct iwl_mvm *mvm, | ||||||
|  | @ -278,11 +318,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, | ||||||
| { | { | ||||||
| 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||||||
| 	struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; | 	struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; | ||||||
| 	static const u8 time_event_notif[] = { TIME_EVENT_CMD, |  | ||||||
| 					       TIME_EVENT_NOTIFICATION }; |  | ||||||
| 	struct iwl_notification_wait wait_time_event; |  | ||||||
| 	struct iwl_time_event_cmd time_cmd = {}; | 	struct iwl_time_event_cmd time_cmd = {}; | ||||||
| 	int ret; |  | ||||||
| 
 | 
 | ||||||
| 	lockdep_assert_held(&mvm->mutex); | 	lockdep_assert_held(&mvm->mutex); | ||||||
| 
 | 
 | ||||||
|  | @ -309,12 +345,6 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, | ||||||
| 		iwl_mvm_stop_session_protection(mvm, vif); | 		iwl_mvm_stop_session_protection(mvm, vif); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event, |  | ||||||
| 				   time_event_notif, |  | ||||||
| 				   ARRAY_SIZE(time_event_notif), |  | ||||||
| 				   iwl_mvm_time_event_notif, |  | ||||||
| 				   &mvmvif->time_event_data); |  | ||||||
| 
 |  | ||||||
| 	time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); | 	time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); | ||||||
| 	time_cmd.id_and_color = | 	time_cmd.id_and_color = | ||||||
| 		cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); | 		cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); | ||||||
|  | @ -322,6 +352,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, | ||||||
| 
 | 
 | ||||||
| 	time_cmd.apply_time = | 	time_cmd.apply_time = | ||||||
| 		cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG)); | 		cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG)); | ||||||
|  | 
 | ||||||
| 	time_cmd.dep_policy = TE_INDEPENDENT; | 	time_cmd.dep_policy = TE_INDEPENDENT; | ||||||
| 	time_cmd.is_present = cpu_to_le32(1); | 	time_cmd.is_present = cpu_to_le32(1); | ||||||
| 	time_cmd.max_frags = cpu_to_le32(TE_FRAG_NONE); | 	time_cmd.max_frags = cpu_to_le32(TE_FRAG_NONE); | ||||||
|  | @ -333,33 +364,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, | ||||||
| 	time_cmd.repeat = cpu_to_le32(1); | 	time_cmd.repeat = cpu_to_le32(1); | ||||||
| 	time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END); | 	time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END); | ||||||
| 
 | 
 | ||||||
| 	te_data->vif = vif; | 	iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); | ||||||
| 	te_data->duration = duration; |  | ||||||
| 
 |  | ||||||
| 	spin_lock_bh(&mvm->time_event_lock); |  | ||||||
| 	te_data->id = le32_to_cpu(time_cmd.id); |  | ||||||
| 	list_add_tail(&te_data->list, &mvm->time_event_list); |  | ||||||
| 	spin_unlock_bh(&mvm->time_event_lock); |  | ||||||
| 
 |  | ||||||
| 	ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, |  | ||||||
| 				   sizeof(time_cmd), &time_cmd); |  | ||||||
| 	if (ret) { |  | ||||||
| 		IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret); |  | ||||||
| 		goto out_remove_notif; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	ret = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1 * HZ); |  | ||||||
| 	if (ret) { |  | ||||||
| 		IWL_ERR(mvm, "%s - failed on timeout\n", __func__); |  | ||||||
| 		spin_lock_bh(&mvm->time_event_lock); |  | ||||||
| 		iwl_mvm_te_clear_data(mvm, te_data); |  | ||||||
| 		spin_unlock_bh(&mvm->time_event_lock); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return; |  | ||||||
| 
 |  | ||||||
| out_remove_notif: |  | ||||||
| 	iwl_remove_notification(&mvm->notif_wait, &wait_time_event); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -424,43 +429,12 @@ void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm, | ||||||
| 	iwl_mvm_remove_time_event(mvm, mvmvif, te_data); | 	iwl_mvm_remove_time_event(mvm, mvmvif, te_data); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool iwl_mvm_roc_te_notif(struct iwl_notif_wait_data *notif_wait, |  | ||||||
| 				 struct iwl_rx_packet *pkt, void *data) |  | ||||||
| { |  | ||||||
| 	struct iwl_mvm *mvm = |  | ||||||
| 		container_of(notif_wait, struct iwl_mvm, notif_wait); |  | ||||||
| 	struct iwl_mvm_time_event_data *te_data = data; |  | ||||||
| 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); |  | ||||||
| 	struct iwl_time_event_resp *resp; |  | ||||||
| 
 |  | ||||||
| 	u32 mac_id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color); |  | ||||||
| 
 |  | ||||||
| 	/* until we do something else */ |  | ||||||
| 	WARN_ON(te_data->id != TE_P2P_DEVICE_DISCOVERABLE); |  | ||||||
| 
 |  | ||||||
| 	switch (pkt->hdr.cmd) { |  | ||||||
| 	case TIME_EVENT_CMD: |  | ||||||
| 		resp = (void *)pkt->data; |  | ||||||
| 		WARN_ON(mac_id_n_color != le32_to_cpu(resp->id_and_color)); |  | ||||||
| 		te_data->uid = le32_to_cpu(resp->unique_id); |  | ||||||
| 		IWL_DEBUG_TE(mvm, "Got response - UID = 0x%x\n", te_data->uid); |  | ||||||
| 		return true; |  | ||||||
| 
 |  | ||||||
| 	default: |  | ||||||
| 		WARN_ON(1); |  | ||||||
| 		return false; |  | ||||||
| 	}; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||||||
| 			  int duration) | 			  int duration) | ||||||
| { | { | ||||||
| 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||||||
| 	struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; | 	struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; | ||||||
| 	static const u8 roc_te_notif[] = { TIME_EVENT_CMD }; |  | ||||||
| 	struct iwl_notification_wait wait_time_event; |  | ||||||
| 	struct iwl_time_event_cmd time_cmd = {}; | 	struct iwl_time_event_cmd time_cmd = {}; | ||||||
| 	int ret; |  | ||||||
| 
 | 
 | ||||||
| 	lockdep_assert_held(&mvm->mutex); | 	lockdep_assert_held(&mvm->mutex); | ||||||
| 	if (te_data->running) { | 	if (te_data->running) { | ||||||
|  | @ -474,16 +448,10 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||||||
| 	 */ | 	 */ | ||||||
| 	flush_work(&mvm->roc_done_wk); | 	flush_work(&mvm->roc_done_wk); | ||||||
| 
 | 
 | ||||||
| 	iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event, |  | ||||||
| 				   roc_te_notif, |  | ||||||
| 				   ARRAY_SIZE(roc_te_notif), |  | ||||||
| 				   iwl_mvm_roc_te_notif, |  | ||||||
| 				   &mvmvif->time_event_data); |  | ||||||
| 
 |  | ||||||
| 	time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); | 	time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); | ||||||
| 	time_cmd.id_and_color = | 	time_cmd.id_and_color = | ||||||
| 		cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); | 		cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); | ||||||
| 	time_cmd.id = cpu_to_le32(TE_P2P_DEVICE_DISCOVERABLE); | 	time_cmd.id = cpu_to_le32(IWL_MVM_ROC_TE_TYPE); | ||||||
| 
 | 
 | ||||||
| 	time_cmd.apply_time = cpu_to_le32(0); | 	time_cmd.apply_time = cpu_to_le32(0); | ||||||
| 	time_cmd.dep_policy = cpu_to_le32(TE_INDEPENDENT); | 	time_cmd.dep_policy = cpu_to_le32(TE_INDEPENDENT); | ||||||
|  | @ -492,7 +460,7 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||||||
| 	time_cmd.interval = cpu_to_le32(1); | 	time_cmd.interval = cpu_to_le32(1); | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * TE_P2P_DEVICE_DISCOVERABLE can have lower priority than other events | 	 * IWL_MVM_ROC_TE_TYPE can have lower priority than other events | ||||||
| 	 * that are being scheduled by the driver/fw, and thus it might not be | 	 * that are being scheduled by the driver/fw, and thus it might not be | ||||||
| 	 * scheduled. To improve the chances of it being scheduled, allow it to | 	 * scheduled. To improve the chances of it being scheduled, allow it to | ||||||
| 	 * be fragmented. | 	 * be fragmented. | ||||||
|  | @ -505,33 +473,7 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||||||
| 	time_cmd.repeat = cpu_to_le32(1); | 	time_cmd.repeat = cpu_to_le32(1); | ||||||
| 	time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END); | 	time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END); | ||||||
| 
 | 
 | ||||||
| 	/* Push the te data to the tracked te list */ | 	return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); | ||||||
| 	te_data->vif = vif; |  | ||||||
| 	te_data->duration = MSEC_TO_TU(duration); |  | ||||||
| 
 |  | ||||||
| 	spin_lock_bh(&mvm->time_event_lock); |  | ||||||
| 	te_data->id = le32_to_cpu(time_cmd.id); |  | ||||||
| 	list_add_tail(&te_data->list, &mvm->time_event_list); |  | ||||||
| 	spin_unlock_bh(&mvm->time_event_lock); |  | ||||||
| 
 |  | ||||||
| 	ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, |  | ||||||
| 				   sizeof(time_cmd), &time_cmd); |  | ||||||
| 	if (ret) { |  | ||||||
| 		IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret); |  | ||||||
| 		goto out_remove_notif; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	ret = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1 * HZ); |  | ||||||
| 	if (ret) { |  | ||||||
| 		IWL_ERR(mvm, "%s - failed on timeout\n", __func__); |  | ||||||
| 		iwl_mvm_te_clear_data(mvm, te_data); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return ret; |  | ||||||
| 
 |  | ||||||
| out_remove_notif: |  | ||||||
| 	iwl_remove_notification(&mvm->notif_wait, &wait_time_event); |  | ||||||
| 	return ret; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm) | void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm) | ||||||
|  |  | ||||||
|  | @ -620,7 +620,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | ||||||
| 			seq_ctl = le16_to_cpu(hdr->seq_ctrl); | 			seq_ctl = le16_to_cpu(hdr->seq_ctrl); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		ieee80211_tx_status(mvm->hw, skb); | 		ieee80211_tx_status_ni(mvm->hw, skb); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (txq_id >= IWL_FIRST_AMPDU_QUEUE) { | 	if (txq_id >= IWL_FIRST_AMPDU_QUEUE) { | ||||||
|  | @ -663,12 +663,12 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | ||||||
| 			struct iwl_mvm_tid_data *tid_data = | 			struct iwl_mvm_tid_data *tid_data = | ||||||
| 				&mvmsta->tid_data[tid]; | 				&mvmsta->tid_data[tid]; | ||||||
| 
 | 
 | ||||||
| 			spin_lock(&mvmsta->lock); | 			spin_lock_bh(&mvmsta->lock); | ||||||
| 			tid_data->next_reclaimed = next_reclaimed; | 			tid_data->next_reclaimed = next_reclaimed; | ||||||
| 			IWL_DEBUG_TX_REPLY(mvm, "Next reclaimed packet:%d\n", | 			IWL_DEBUG_TX_REPLY(mvm, "Next reclaimed packet:%d\n", | ||||||
| 					   next_reclaimed); | 					   next_reclaimed); | ||||||
| 			iwl_mvm_check_ratid_empty(mvm, sta, tid); | 			iwl_mvm_check_ratid_empty(mvm, sta, tid); | ||||||
| 			spin_unlock(&mvmsta->lock); | 			spin_unlock_bh(&mvmsta->lock); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_PM_SLEEP | #ifdef CONFIG_PM_SLEEP | ||||||
|  | @ -832,7 +832,7 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	spin_lock(&mvmsta->lock); | 	spin_lock_bh(&mvmsta->lock); | ||||||
| 
 | 
 | ||||||
| 	__skb_queue_head_init(&reclaimed_skbs); | 	__skb_queue_head_init(&reclaimed_skbs); | ||||||
| 
 | 
 | ||||||
|  | @ -886,13 +886,13 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	spin_unlock(&mvmsta->lock); | 	spin_unlock_bh(&mvmsta->lock); | ||||||
| 
 | 
 | ||||||
| 	rcu_read_unlock(); | 	rcu_read_unlock(); | ||||||
| 
 | 
 | ||||||
| 	while (!skb_queue_empty(&reclaimed_skbs)) { | 	while (!skb_queue_empty(&reclaimed_skbs)) { | ||||||
| 		skb = __skb_dequeue(&reclaimed_skbs); | 		skb = __skb_dequeue(&reclaimed_skbs); | ||||||
| 		ieee80211_tx_status(mvm->hw, skb); | 		ieee80211_tx_status_ni(mvm->hw, skb); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -249,7 +249,6 @@ struct iwl_trans_pcie { | ||||||
| 	int ict_index; | 	int ict_index; | ||||||
| 	u32 inta; | 	u32 inta; | ||||||
| 	bool use_ict; | 	bool use_ict; | ||||||
| 	struct tasklet_struct irq_tasklet; |  | ||||||
| 	struct isr_statistics isr_stats; | 	struct isr_statistics isr_stats; | ||||||
| 
 | 
 | ||||||
| 	spinlock_t irq_lock; | 	spinlock_t irq_lock; | ||||||
|  | @ -330,7 +329,7 @@ void iwl_trans_pcie_free(struct iwl_trans *trans); | ||||||
| * RX | * RX | ||||||
| ******************************************************/ | ******************************************************/ | ||||||
| int iwl_pcie_rx_init(struct iwl_trans *trans); | int iwl_pcie_rx_init(struct iwl_trans *trans); | ||||||
| void iwl_pcie_tasklet(struct iwl_trans *trans); | irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id); | ||||||
| int iwl_pcie_rx_stop(struct iwl_trans *trans); | int iwl_pcie_rx_stop(struct iwl_trans *trans); | ||||||
| void iwl_pcie_rx_free(struct iwl_trans *trans); | void iwl_pcie_rx_free(struct iwl_trans *trans); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -81,10 +81,10 @@ | ||||||
|  *   'processed' and 'read' driver indexes as well) |  *   'processed' and 'read' driver indexes as well) | ||||||
|  * + A received packet is processed and handed to the kernel network stack, |  * + A received packet is processed and handed to the kernel network stack, | ||||||
|  *   detached from the iwl->rxq.  The driver 'processed' index is updated. |  *   detached from the iwl->rxq.  The driver 'processed' index is updated. | ||||||
|  * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free |  * + The Host/Firmware iwl->rxq is replenished at irq thread time from the | ||||||
|  *   list. If there are no allocated buffers in iwl->rxq->rx_free, the READ |  *   rx_free list. If there are no allocated buffers in iwl->rxq->rx_free, | ||||||
|  *   INDEX is not incremented and iwl->status(RX_STALLED) is set.  If there |  *   the READ INDEX is not incremented and iwl->status(RX_STALLED) is set. | ||||||
|  *   were enough free buffers and RX_STALLED is set it is cleared. |  *   If there were enough free buffers and RX_STALLED is set it is cleared. | ||||||
|  * |  * | ||||||
|  * |  * | ||||||
|  * Driver sequence: |  * Driver sequence: | ||||||
|  | @ -214,9 +214,9 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans) | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * If the device isn't enabled - not need to try to add buffers... | 	 * If the device isn't enabled - not need to try to add buffers... | ||||||
| 	 * This can happen when we stop the device and still have an interrupt | 	 * This can happen when we stop the device and still have an interrupt | ||||||
| 	 * pending. We stop the APM before we sync the interrupts / tasklets | 	 * pending. We stop the APM before we sync the interrupts because we | ||||||
| 	 * because we have to (see comment there). On the other hand, since | 	 * have to (see comment there). On the other hand, since the APM is | ||||||
| 	 * the APM is stopped, we cannot access the HW (in particular not prph). | 	 * stopped, we cannot access the HW (in particular not prph). | ||||||
| 	 * So don't try to restock if the APM has been already stopped. | 	 * So don't try to restock if the APM has been already stopped. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (!test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) | 	if (!test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) | ||||||
|  | @ -796,11 +796,14 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) | ||||||
| 	clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); | 	clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); | ||||||
| 	wake_up(&trans_pcie->wait_command_queue); | 	wake_up(&trans_pcie->wait_command_queue); | ||||||
| 
 | 
 | ||||||
|  | 	local_bh_disable(); | ||||||
| 	iwl_op_mode_nic_error(trans->op_mode); | 	iwl_op_mode_nic_error(trans->op_mode); | ||||||
|  | 	local_bh_enable(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void iwl_pcie_tasklet(struct iwl_trans *trans) | irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) | ||||||
| { | { | ||||||
|  | 	struct iwl_trans *trans = dev_id; | ||||||
| 	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | ||||||
| 	struct isr_statistics *isr_stats = &trans_pcie->isr_stats; | 	struct isr_statistics *isr_stats = &trans_pcie->isr_stats; | ||||||
| 	u32 inta = 0; | 	u32 inta = 0; | ||||||
|  | @ -811,6 +814,8 @@ void iwl_pcie_tasklet(struct iwl_trans *trans) | ||||||
| 	u32 inta_mask; | 	u32 inta_mask; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | 	lock_map_acquire(&trans->sync_cmd_lockdep_map); | ||||||
|  | 
 | ||||||
| 	spin_lock_irqsave(&trans_pcie->irq_lock, flags); | 	spin_lock_irqsave(&trans_pcie->irq_lock, flags); | ||||||
| 
 | 
 | ||||||
| 	/* Ack/clear/reset pending uCode interrupts.
 | 	/* Ack/clear/reset pending uCode interrupts.
 | ||||||
|  | @ -855,7 +860,7 @@ void iwl_pcie_tasklet(struct iwl_trans *trans) | ||||||
| 
 | 
 | ||||||
| 		handled |= CSR_INT_BIT_HW_ERR; | 		handled |= CSR_INT_BIT_HW_ERR; | ||||||
| 
 | 
 | ||||||
| 		return; | 		goto out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_IWLWIFI_DEBUG | #ifdef CONFIG_IWLWIFI_DEBUG | ||||||
|  | @ -1005,6 +1010,10 @@ void iwl_pcie_tasklet(struct iwl_trans *trans) | ||||||
| 	/* Re-enable RF_KILL if it occurred */ | 	/* Re-enable RF_KILL if it occurred */ | ||||||
| 	else if (handled & CSR_INT_BIT_RF_KILL) | 	else if (handled & CSR_INT_BIT_RF_KILL) | ||||||
| 		iwl_enable_rfkill_int(trans); | 		iwl_enable_rfkill_int(trans); | ||||||
|  | 
 | ||||||
|  | out: | ||||||
|  | 	lock_map_release(&trans->sync_cmd_lockdep_map); | ||||||
|  | 	return IRQ_HANDLED; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /******************************************************************************
 | /******************************************************************************
 | ||||||
|  | @ -1127,7 +1136,7 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data) | ||||||
| 
 | 
 | ||||||
| 	/* Disable (but don't clear!) interrupts here to avoid
 | 	/* Disable (but don't clear!) interrupts here to avoid
 | ||||||
| 	 *    back-to-back ISRs and sporadic interrupts from our NIC. | 	 *    back-to-back ISRs and sporadic interrupts from our NIC. | ||||||
| 	 * If we have something to service, the tasklet will re-enable ints. | 	 * If we have something to service, the irq thread will re-enable ints. | ||||||
| 	 * If we *don't* have something, we'll re-enable before leaving here. */ | 	 * If we *don't* have something, we'll re-enable before leaving here. */ | ||||||
| 	inta_mask = iwl_read32(trans, CSR_INT_MASK); | 	inta_mask = iwl_read32(trans, CSR_INT_MASK); | ||||||
| 	iwl_write32(trans, CSR_INT_MASK, 0x00000000); | 	iwl_write32(trans, CSR_INT_MASK, 0x00000000); | ||||||
|  | @ -1167,9 +1176,9 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data) | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 	trans_pcie->inta |= inta; | 	trans_pcie->inta |= inta; | ||||||
| 	/* iwl_pcie_tasklet() will service interrupts and re-enable them */ | 	/* the thread will service interrupts and re-enable them */ | ||||||
| 	if (likely(inta)) | 	if (likely(inta)) | ||||||
| 		tasklet_schedule(&trans_pcie->irq_tasklet); | 		return IRQ_WAKE_THREAD; | ||||||
| 	else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && | 	else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && | ||||||
| 		 !trans_pcie->inta) | 		 !trans_pcie->inta) | ||||||
| 		iwl_enable_interrupts(trans); | 		iwl_enable_interrupts(trans); | ||||||
|  | @ -1277,9 +1286,10 @@ irqreturn_t iwl_pcie_isr_ict(int irq, void *data) | ||||||
| 	trans_pcie->inta |= inta; | 	trans_pcie->inta |= inta; | ||||||
| 
 | 
 | ||||||
| 	/* iwl_pcie_tasklet() will service interrupts and re-enable them */ | 	/* iwl_pcie_tasklet() will service interrupts and re-enable them */ | ||||||
| 	if (likely(inta)) | 	if (likely(inta)) { | ||||||
| 		tasklet_schedule(&trans_pcie->irq_tasklet); | 		spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); | ||||||
| 	else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && | 		return IRQ_WAKE_THREAD; | ||||||
|  | 	} else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && | ||||||
| 		 !trans_pcie->inta) { | 		 !trans_pcie->inta) { | ||||||
| 		/* Allow interrupt if was disabled by this handler and
 | 		/* Allow interrupt if was disabled by this handler and
 | ||||||
| 		 * no tasklet was schedules, We should not enable interrupt, | 		 * no tasklet was schedules, We should not enable interrupt, | ||||||
|  |  | ||||||
|  | @ -760,7 +760,6 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) | ||||||
| 	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | ||||||
| 
 | 
 | ||||||
| 	synchronize_irq(trans_pcie->pci_dev->irq); | 	synchronize_irq(trans_pcie->pci_dev->irq); | ||||||
| 	tasklet_kill(&trans_pcie->irq_tasklet); |  | ||||||
| 
 | 
 | ||||||
| 	iwl_pcie_tx_free(trans); | 	iwl_pcie_tx_free(trans); | ||||||
| 	iwl_pcie_rx_free(trans); | 	iwl_pcie_rx_free(trans); | ||||||
|  | @ -1480,6 +1479,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, | ||||||
| 
 | 
 | ||||||
| 	trans->ops = &trans_ops_pcie; | 	trans->ops = &trans_ops_pcie; | ||||||
| 	trans->cfg = cfg; | 	trans->cfg = cfg; | ||||||
|  | 	trans_lockdep_init(trans); | ||||||
| 	trans_pcie->trans = trans; | 	trans_pcie->trans = trans; | ||||||
| 	spin_lock_init(&trans_pcie->irq_lock); | 	spin_lock_init(&trans_pcie->irq_lock); | ||||||
| 	spin_lock_init(&trans_pcie->reg_lock); | 	spin_lock_init(&trans_pcie->reg_lock); | ||||||
|  | @ -1567,15 +1567,12 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, | ||||||
| 
 | 
 | ||||||
| 	trans_pcie->inta_mask = CSR_INI_SET_MASK; | 	trans_pcie->inta_mask = CSR_INI_SET_MASK; | ||||||
| 
 | 
 | ||||||
| 	tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long)) |  | ||||||
| 		     iwl_pcie_tasklet, (unsigned long)trans); |  | ||||||
| 
 |  | ||||||
| 	if (iwl_pcie_alloc_ict(trans)) | 	if (iwl_pcie_alloc_ict(trans)) | ||||||
| 		goto out_free_cmd_pool; | 		goto out_free_cmd_pool; | ||||||
| 
 | 
 | ||||||
| 	err = request_irq(pdev->irq, iwl_pcie_isr_ict, | 	if (request_threaded_irq(pdev->irq, iwl_pcie_isr_ict, | ||||||
| 			  IRQF_SHARED, DRV_NAME, trans); | 				 iwl_pcie_irq_handler, | ||||||
| 	if (err) { | 				 IRQF_SHARED, DRV_NAME, trans)) { | ||||||
| 		IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq); | 		IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq); | ||||||
| 		goto out_free_ict; | 		goto out_free_ict; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -926,7 +926,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, | ||||||
| 	if (WARN_ON(txq_id == trans_pcie->cmd_queue)) | 	if (WARN_ON(txq_id == trans_pcie->cmd_queue)) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	spin_lock(&txq->lock); | 	spin_lock_bh(&txq->lock); | ||||||
| 
 | 
 | ||||||
| 	if (txq->q.read_ptr == tfd_num) | 	if (txq->q.read_ptr == tfd_num) | ||||||
| 		goto out; | 		goto out; | ||||||
|  | @ -970,7 +970,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, | ||||||
| 	if (iwl_queue_space(&txq->q) > txq->q.low_mark) | 	if (iwl_queue_space(&txq->q) > txq->q.low_mark) | ||||||
| 		iwl_wake_queue(trans, txq); | 		iwl_wake_queue(trans, txq); | ||||||
| out: | out: | ||||||
| 	spin_unlock(&txq->lock); | 	spin_unlock_bh(&txq->lock); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -1371,7 +1371,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	spin_lock(&txq->lock); | 	spin_lock_bh(&txq->lock); | ||||||
| 
 | 
 | ||||||
| 	cmd_index = get_cmd_index(&txq->q, index); | 	cmd_index = get_cmd_index(&txq->q, index); | ||||||
| 	cmd = txq->entries[cmd_index].cmd; | 	cmd = txq->entries[cmd_index].cmd; | ||||||
|  | @ -1405,7 +1405,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, | ||||||
| 
 | 
 | ||||||
| 	meta->flags = 0; | 	meta->flags = 0; | ||||||
| 
 | 
 | ||||||
| 	spin_unlock(&txq->lock); | 	spin_unlock_bh(&txq->lock); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #define HOST_COMPLETE_TIMEOUT (2 * HZ) | #define HOST_COMPLETE_TIMEOUT (2 * HZ) | ||||||
|  |  | ||||||
|  | @ -657,7 +657,7 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy, | ||||||
| 					capa, intvl, ie, ielen, | 					capa, intvl, ie, ielen, | ||||||
| 					LBS_SCAN_RSSI_TO_MBM(rssi), | 					LBS_SCAN_RSSI_TO_MBM(rssi), | ||||||
| 					GFP_KERNEL); | 					GFP_KERNEL); | ||||||
| 				cfg80211_put_bss(bss); | 				cfg80211_put_bss(wiphy, bss); | ||||||
| 			} | 			} | ||||||
| 		} else | 		} else | ||||||
| 			lbs_deb_scan("scan response: missing BSS channel IE\n"); | 			lbs_deb_scan("scan response: missing BSS channel IE\n"); | ||||||
|  | @ -1444,7 +1444,7 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev, | ||||||
| 
 | 
 | ||||||
|  done: |  done: | ||||||
| 	if (bss) | 	if (bss) | ||||||
| 		cfg80211_put_bss(bss); | 		cfg80211_put_bss(wiphy, bss); | ||||||
| 	lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); | 	lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  | @ -1766,7 +1766,7 @@ static void lbs_join_post(struct lbs_private *priv, | ||||||
| 				  params->beacon_interval, | 				  params->beacon_interval, | ||||||
| 				  fake_ie, fake - fake_ie, | 				  fake_ie, fake - fake_ie, | ||||||
| 				  0, GFP_KERNEL); | 				  0, GFP_KERNEL); | ||||||
| 	cfg80211_put_bss(bss); | 	cfg80211_put_bss(priv->wdev->wiphy, bss); | ||||||
| 
 | 
 | ||||||
| 	memcpy(priv->wdev->ssid, params->ssid, params->ssid_len); | 	memcpy(priv->wdev->ssid, params->ssid, params->ssid_len); | ||||||
| 	priv->wdev->ssid_len = params->ssid_len; | 	priv->wdev->ssid_len = params->ssid_len; | ||||||
|  | @ -2011,7 +2011,7 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev, | ||||||
| 
 | 
 | ||||||
| 	if (bss) { | 	if (bss) { | ||||||
| 		ret = lbs_ibss_join_existing(priv, params, bss); | 		ret = lbs_ibss_join_existing(priv, params, bss); | ||||||
| 		cfg80211_put_bss(bss); | 		cfg80211_put_bss(wiphy, bss); | ||||||
| 	} else | 	} else | ||||||
| 		ret = lbs_ibss_start_new(priv, params); | 		ret = lbs_ibss_start_new(priv, params); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2247,6 +2247,7 @@ static int __init init_mac80211_hwsim(void) | ||||||
| 		/* ask mac80211 to reserve space for magic */ | 		/* ask mac80211 to reserve space for magic */ | ||||||
| 		hw->vif_data_size = sizeof(struct hwsim_vif_priv); | 		hw->vif_data_size = sizeof(struct hwsim_vif_priv); | ||||||
| 		hw->sta_data_size = sizeof(struct hwsim_sta_priv); | 		hw->sta_data_size = sizeof(struct hwsim_sta_priv); | ||||||
|  | 		hw->chanctx_data_size = sizeof(struct hwsim_chanctx_priv); | ||||||
| 
 | 
 | ||||||
| 		memcpy(data->channels_2ghz, hwsim_channels_2ghz, | 		memcpy(data->channels_2ghz, hwsim_channels_2ghz, | ||||||
| 			sizeof(hwsim_channels_2ghz)); | 			sizeof(hwsim_channels_2ghz)); | ||||||
|  |  | ||||||
|  | @ -20,12 +20,12 @@ config MWIFIEX_SDIO | ||||||
| 	  mwifiex_sdio. | 	  mwifiex_sdio. | ||||||
| 
 | 
 | ||||||
| config MWIFIEX_PCIE | config MWIFIEX_PCIE | ||||||
| 	tristate "Marvell WiFi-Ex Driver for PCIE 8766" | 	tristate "Marvell WiFi-Ex Driver for PCIE 8766/8897" | ||||||
| 	depends on MWIFIEX && PCI | 	depends on MWIFIEX && PCI | ||||||
| 	select FW_LOADER | 	select FW_LOADER | ||||||
| 	---help--- | 	---help--- | ||||||
| 	  This adds support for wireless adapters based on Marvell | 	  This adds support for wireless adapters based on Marvell | ||||||
| 	  8766 chipset with PCIe interface. | 	  8766/8897 chipsets with PCIe interface. | ||||||
| 
 | 
 | ||||||
| 	  If you choose to build it as a module, it will be called | 	  If you choose to build it as a module, it will be called | ||||||
| 	  mwifiex_pcie. | 	  mwifiex_pcie. | ||||||
|  |  | ||||||
|  | @ -1430,7 +1430,7 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) | ||||||
| 	bss = cfg80211_inform_bss(priv->wdev->wiphy, chan, | 	bss = cfg80211_inform_bss(priv->wdev->wiphy, chan, | ||||||
| 				  bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, | 				  bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, | ||||||
| 				  0, ie_buf, ie_len, 0, GFP_KERNEL); | 				  0, ie_buf, ie_len, 0, GFP_KERNEL); | ||||||
| 	cfg80211_put_bss(bss); | 	cfg80211_put_bss(priv->wdev->wiphy, bss); | ||||||
| 	memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN); | 	memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -29,6 +29,11 @@ | ||||||
| #include    "main.h" | #include    "main.h" | ||||||
| 
 | 
 | ||||||
| #define PCIE8766_DEFAULT_FW_NAME "mrvl/pcie8766_uapsta.bin" | #define PCIE8766_DEFAULT_FW_NAME "mrvl/pcie8766_uapsta.bin" | ||||||
|  | #define PCIE8897_DEFAULT_FW_NAME "mrvl/pcie8897_uapsta.bin" | ||||||
|  | 
 | ||||||
|  | #define PCIE_VENDOR_ID_MARVELL              (0x11ab) | ||||||
|  | #define PCIE_DEVICE_ID_MARVELL_88W8766P		(0x2b30) | ||||||
|  | #define PCIE_DEVICE_ID_MARVELL_88W8897		(0x2b38) | ||||||
| 
 | 
 | ||||||
| /* Constants for Buffer Descriptor (BD) rings */ | /* Constants for Buffer Descriptor (BD) rings */ | ||||||
| #define MWIFIEX_MAX_TXRX_BD			0x20 | #define MWIFIEX_MAX_TXRX_BD			0x20 | ||||||
|  | @ -57,6 +62,8 @@ | ||||||
| #define PCIE_SCRATCH_10_REG				0xCE8 | #define PCIE_SCRATCH_10_REG				0xCE8 | ||||||
| #define PCIE_SCRATCH_11_REG				0xCEC | #define PCIE_SCRATCH_11_REG				0xCEC | ||||||
| #define PCIE_SCRATCH_12_REG				0xCF0 | #define PCIE_SCRATCH_12_REG				0xCF0 | ||||||
|  | #define PCIE_RD_DATA_PTR_Q0_Q1                          0xC08C | ||||||
|  | #define PCIE_WR_DATA_PTR_Q0_Q1                          0xC05C | ||||||
| 
 | 
 | ||||||
| #define CPU_INTR_DNLD_RDY				BIT(0) | #define CPU_INTR_DNLD_RDY				BIT(0) | ||||||
| #define CPU_INTR_DOOR_BELL				BIT(1) | #define CPU_INTR_DOOR_BELL				BIT(1) | ||||||
|  | @ -75,27 +82,14 @@ | ||||||
| #define MWIFIEX_BD_FLAG_ROLLOVER_IND			BIT(7) | #define MWIFIEX_BD_FLAG_ROLLOVER_IND			BIT(7) | ||||||
| #define MWIFIEX_BD_FLAG_FIRST_DESC			BIT(0) | #define MWIFIEX_BD_FLAG_FIRST_DESC			BIT(0) | ||||||
| #define MWIFIEX_BD_FLAG_LAST_DESC			BIT(1) | #define MWIFIEX_BD_FLAG_LAST_DESC			BIT(1) | ||||||
| #define REG_CMD_ADDR_LO					PCIE_SCRATCH_0_REG | #define MWIFIEX_BD_FLAG_SOP				BIT(0) | ||||||
| #define REG_CMD_ADDR_HI					PCIE_SCRATCH_1_REG | #define MWIFIEX_BD_FLAG_EOP				BIT(1) | ||||||
| #define REG_CMD_SIZE					PCIE_SCRATCH_2_REG | #define MWIFIEX_BD_FLAG_XS_SOP				BIT(2) | ||||||
| 
 | #define MWIFIEX_BD_FLAG_XS_EOP				BIT(3) | ||||||
| #define REG_CMDRSP_ADDR_LO				PCIE_SCRATCH_4_REG | #define MWIFIEX_BD_FLAG_EVT_ROLLOVER_IND		BIT(7) | ||||||
| #define REG_CMDRSP_ADDR_HI				PCIE_SCRATCH_5_REG | #define MWIFIEX_BD_FLAG_RX_ROLLOVER_IND			BIT(10) | ||||||
| 
 | #define MWIFIEX_BD_FLAG_TX_START_PTR			BIT(16) | ||||||
| /* TX buffer description read pointer */ | #define MWIFIEX_BD_FLAG_TX_ROLLOVER_IND			BIT(26) | ||||||
| #define REG_TXBD_RDPTR					PCIE_SCRATCH_6_REG |  | ||||||
| /* TX buffer description write pointer */ |  | ||||||
| #define REG_TXBD_WRPTR					PCIE_SCRATCH_7_REG |  | ||||||
| /* RX buffer description read pointer */ |  | ||||||
| #define REG_RXBD_RDPTR					PCIE_SCRATCH_8_REG |  | ||||||
| /* RX buffer description write pointer */ |  | ||||||
| #define REG_RXBD_WRPTR					PCIE_SCRATCH_9_REG |  | ||||||
| /* Event buffer description read pointer */ |  | ||||||
| #define REG_EVTBD_RDPTR					PCIE_SCRATCH_10_REG |  | ||||||
| /* Event buffer description write pointer */ |  | ||||||
| #define REG_EVTBD_WRPTR					PCIE_SCRATCH_11_REG |  | ||||||
| /* Driver ready signature write pointer */ |  | ||||||
| #define REG_DRV_READY					PCIE_SCRATCH_12_REG |  | ||||||
| 
 | 
 | ||||||
| /* Max retry number of command write */ | /* Max retry number of command write */ | ||||||
| #define MAX_WRITE_IOMEM_RETRY				2 | #define MAX_WRITE_IOMEM_RETRY				2 | ||||||
|  | @ -104,15 +98,142 @@ | ||||||
| /* FW awake cookie after FW ready */ | /* FW awake cookie after FW ready */ | ||||||
| #define FW_AWAKE_COOKIE						(0xAA55AA55) | #define FW_AWAKE_COOKIE						(0xAA55AA55) | ||||||
| 
 | 
 | ||||||
|  | struct mwifiex_pcie_card_reg { | ||||||
|  | 	u16 cmd_addr_lo; | ||||||
|  | 	u16 cmd_addr_hi; | ||||||
|  | 	u16 fw_status; | ||||||
|  | 	u16 cmd_size; | ||||||
|  | 	u16 cmdrsp_addr_lo; | ||||||
|  | 	u16 cmdrsp_addr_hi; | ||||||
|  | 	u16 tx_rdptr; | ||||||
|  | 	u16 tx_wrptr; | ||||||
|  | 	u16 rx_rdptr; | ||||||
|  | 	u16 rx_wrptr; | ||||||
|  | 	u16 evt_rdptr; | ||||||
|  | 	u16 evt_wrptr; | ||||||
|  | 	u16 drv_rdy; | ||||||
|  | 	u16 tx_start_ptr; | ||||||
|  | 	u32 tx_mask; | ||||||
|  | 	u32 tx_wrap_mask; | ||||||
|  | 	u32 rx_mask; | ||||||
|  | 	u32 rx_wrap_mask; | ||||||
|  | 	u32 tx_rollover_ind; | ||||||
|  | 	u32 rx_rollover_ind; | ||||||
|  | 	u32 evt_rollover_ind; | ||||||
|  | 	u8 ring_flag_sop; | ||||||
|  | 	u8 ring_flag_eop; | ||||||
|  | 	u8 ring_flag_xs_sop; | ||||||
|  | 	u8 ring_flag_xs_eop; | ||||||
|  | 	u32 ring_tx_start_ptr; | ||||||
|  | 	u8 pfu_enabled; | ||||||
|  | 	u8 sleep_cookie; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct mwifiex_pcie_card_reg mwifiex_reg_8766 = { | ||||||
|  | 	.cmd_addr_lo = PCIE_SCRATCH_0_REG, | ||||||
|  | 	.cmd_addr_hi = PCIE_SCRATCH_1_REG, | ||||||
|  | 	.cmd_size = PCIE_SCRATCH_2_REG, | ||||||
|  | 	.fw_status = PCIE_SCRATCH_3_REG, | ||||||
|  | 	.cmdrsp_addr_lo = PCIE_SCRATCH_4_REG, | ||||||
|  | 	.cmdrsp_addr_hi = PCIE_SCRATCH_5_REG, | ||||||
|  | 	.tx_rdptr = PCIE_SCRATCH_6_REG, | ||||||
|  | 	.tx_wrptr = PCIE_SCRATCH_7_REG, | ||||||
|  | 	.rx_rdptr = PCIE_SCRATCH_8_REG, | ||||||
|  | 	.rx_wrptr = PCIE_SCRATCH_9_REG, | ||||||
|  | 	.evt_rdptr = PCIE_SCRATCH_10_REG, | ||||||
|  | 	.evt_wrptr = PCIE_SCRATCH_11_REG, | ||||||
|  | 	.drv_rdy = PCIE_SCRATCH_12_REG, | ||||||
|  | 	.tx_start_ptr = 0, | ||||||
|  | 	.tx_mask = MWIFIEX_TXBD_MASK, | ||||||
|  | 	.tx_wrap_mask = 0, | ||||||
|  | 	.rx_mask = MWIFIEX_RXBD_MASK, | ||||||
|  | 	.rx_wrap_mask = 0, | ||||||
|  | 	.tx_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND, | ||||||
|  | 	.rx_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND, | ||||||
|  | 	.evt_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND, | ||||||
|  | 	.ring_flag_sop = 0, | ||||||
|  | 	.ring_flag_eop = 0, | ||||||
|  | 	.ring_flag_xs_sop = 0, | ||||||
|  | 	.ring_flag_xs_eop = 0, | ||||||
|  | 	.ring_tx_start_ptr = 0, | ||||||
|  | 	.pfu_enabled = 0, | ||||||
|  | 	.sleep_cookie = 1, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = { | ||||||
|  | 	.cmd_addr_lo = PCIE_SCRATCH_0_REG, | ||||||
|  | 	.cmd_addr_hi = PCIE_SCRATCH_1_REG, | ||||||
|  | 	.cmd_size = PCIE_SCRATCH_2_REG, | ||||||
|  | 	.fw_status = PCIE_SCRATCH_3_REG, | ||||||
|  | 	.cmdrsp_addr_lo = PCIE_SCRATCH_4_REG, | ||||||
|  | 	.cmdrsp_addr_hi = PCIE_SCRATCH_5_REG, | ||||||
|  | 	.tx_rdptr = PCIE_RD_DATA_PTR_Q0_Q1, | ||||||
|  | 	.tx_wrptr = PCIE_WR_DATA_PTR_Q0_Q1, | ||||||
|  | 	.rx_rdptr = PCIE_WR_DATA_PTR_Q0_Q1, | ||||||
|  | 	.rx_wrptr = PCIE_RD_DATA_PTR_Q0_Q1, | ||||||
|  | 	.evt_rdptr = PCIE_SCRATCH_10_REG, | ||||||
|  | 	.evt_wrptr = PCIE_SCRATCH_11_REG, | ||||||
|  | 	.drv_rdy = PCIE_SCRATCH_12_REG, | ||||||
|  | 	.tx_start_ptr = 16, | ||||||
|  | 	.tx_mask = 0x03FF0000, | ||||||
|  | 	.tx_wrap_mask = 0x07FF0000, | ||||||
|  | 	.rx_mask = 0x000003FF, | ||||||
|  | 	.rx_wrap_mask = 0x000007FF, | ||||||
|  | 	.tx_rollover_ind = MWIFIEX_BD_FLAG_TX_ROLLOVER_IND, | ||||||
|  | 	.rx_rollover_ind = MWIFIEX_BD_FLAG_RX_ROLLOVER_IND, | ||||||
|  | 	.evt_rollover_ind = MWIFIEX_BD_FLAG_EVT_ROLLOVER_IND, | ||||||
|  | 	.ring_flag_sop = MWIFIEX_BD_FLAG_SOP, | ||||||
|  | 	.ring_flag_eop = MWIFIEX_BD_FLAG_EOP, | ||||||
|  | 	.ring_flag_xs_sop = MWIFIEX_BD_FLAG_XS_SOP, | ||||||
|  | 	.ring_flag_xs_eop = MWIFIEX_BD_FLAG_XS_EOP, | ||||||
|  | 	.ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR, | ||||||
|  | 	.pfu_enabled = 1, | ||||||
|  | 	.sleep_cookie = 0, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct mwifiex_pcie_device { | ||||||
|  | 	const char *firmware; | ||||||
|  | 	const struct mwifiex_pcie_card_reg *reg; | ||||||
|  | 	u16 blksz_fw_dl; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct mwifiex_pcie_device mwifiex_pcie8766 = { | ||||||
|  | 	.firmware       = PCIE8766_DEFAULT_FW_NAME, | ||||||
|  | 	.reg            = &mwifiex_reg_8766, | ||||||
|  | 	.blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct mwifiex_pcie_device mwifiex_pcie8897 = { | ||||||
|  | 	.firmware       = PCIE8897_DEFAULT_FW_NAME, | ||||||
|  | 	.reg            = &mwifiex_reg_8897, | ||||||
|  | 	.blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct mwifiex_evt_buf_desc { | ||||||
|  | 	u64 paddr; | ||||||
|  | 	u16 len; | ||||||
|  | 	u16 flags; | ||||||
|  | } __packed; | ||||||
|  | 
 | ||||||
| struct mwifiex_pcie_buf_desc { | struct mwifiex_pcie_buf_desc { | ||||||
| 	u64 paddr; | 	u64 paddr; | ||||||
| 	u16 len; | 	u16 len; | ||||||
| 	u16 flags; | 	u16 flags; | ||||||
| } __packed; | } __packed; | ||||||
| 
 | 
 | ||||||
|  | struct mwifiex_pfu_buf_desc { | ||||||
|  | 	u16 flags; | ||||||
|  | 	u16 offset; | ||||||
|  | 	u16 frag_len; | ||||||
|  | 	u16 len; | ||||||
|  | 	u64 paddr; | ||||||
|  | 	u32 reserved; | ||||||
|  | } __packed; | ||||||
|  | 
 | ||||||
| struct pcie_service_card { | struct pcie_service_card { | ||||||
| 	struct pci_dev *dev; | 	struct pci_dev *dev; | ||||||
| 	struct mwifiex_adapter *adapter; | 	struct mwifiex_adapter *adapter; | ||||||
|  | 	struct mwifiex_pcie_device pcie; | ||||||
| 
 | 
 | ||||||
| 	u8 txbd_flush; | 	u8 txbd_flush; | ||||||
| 	u32 txbd_wrptr; | 	u32 txbd_wrptr; | ||||||
|  | @ -120,7 +241,7 @@ struct pcie_service_card { | ||||||
| 	u32 txbd_ring_size; | 	u32 txbd_ring_size; | ||||||
| 	u8 *txbd_ring_vbase; | 	u8 *txbd_ring_vbase; | ||||||
| 	dma_addr_t txbd_ring_pbase; | 	dma_addr_t txbd_ring_pbase; | ||||||
| 	struct mwifiex_pcie_buf_desc *txbd_ring[MWIFIEX_MAX_TXRX_BD]; | 	void *txbd_ring[MWIFIEX_MAX_TXRX_BD]; | ||||||
| 	struct sk_buff *tx_buf_list[MWIFIEX_MAX_TXRX_BD]; | 	struct sk_buff *tx_buf_list[MWIFIEX_MAX_TXRX_BD]; | ||||||
| 
 | 
 | ||||||
| 	u32 rxbd_wrptr; | 	u32 rxbd_wrptr; | ||||||
|  | @ -128,7 +249,7 @@ struct pcie_service_card { | ||||||
| 	u32 rxbd_ring_size; | 	u32 rxbd_ring_size; | ||||||
| 	u8 *rxbd_ring_vbase; | 	u8 *rxbd_ring_vbase; | ||||||
| 	dma_addr_t rxbd_ring_pbase; | 	dma_addr_t rxbd_ring_pbase; | ||||||
| 	struct mwifiex_pcie_buf_desc *rxbd_ring[MWIFIEX_MAX_TXRX_BD]; | 	void *rxbd_ring[MWIFIEX_MAX_TXRX_BD]; | ||||||
| 	struct sk_buff *rx_buf_list[MWIFIEX_MAX_TXRX_BD]; | 	struct sk_buff *rx_buf_list[MWIFIEX_MAX_TXRX_BD]; | ||||||
| 
 | 
 | ||||||
| 	u32 evtbd_wrptr; | 	u32 evtbd_wrptr; | ||||||
|  | @ -136,7 +257,7 @@ struct pcie_service_card { | ||||||
| 	u32 evtbd_ring_size; | 	u32 evtbd_ring_size; | ||||||
| 	u8 *evtbd_ring_vbase; | 	u8 *evtbd_ring_vbase; | ||||||
| 	dma_addr_t evtbd_ring_pbase; | 	dma_addr_t evtbd_ring_pbase; | ||||||
| 	struct mwifiex_pcie_buf_desc *evtbd_ring[MWIFIEX_MAX_EVT_BD]; | 	void *evtbd_ring[MWIFIEX_MAX_EVT_BD]; | ||||||
| 	struct sk_buff *evt_buf_list[MWIFIEX_MAX_EVT_BD]; | 	struct sk_buff *evt_buf_list[MWIFIEX_MAX_EVT_BD]; | ||||||
| 
 | 
 | ||||||
| 	struct sk_buff *cmd_buf; | 	struct sk_buff *cmd_buf; | ||||||
|  | @ -150,11 +271,24 @@ struct pcie_service_card { | ||||||
| static inline int | static inline int | ||||||
| mwifiex_pcie_txbd_empty(struct pcie_service_card *card, u32 rdptr) | mwifiex_pcie_txbd_empty(struct pcie_service_card *card, u32 rdptr) | ||||||
| { | { | ||||||
| 	if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) == | 	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; | ||||||
| 			(rdptr & MWIFIEX_TXBD_MASK)) && | 
 | ||||||
| 	    ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) != | 	switch (card->dev->device) { | ||||||
| 			(rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) | 	case PCIE_DEVICE_ID_MARVELL_88W8766P: | ||||||
|  | 		if (((card->txbd_wrptr & reg->tx_mask) == | ||||||
|  | 		     (rdptr & reg->tx_mask)) && | ||||||
|  | 		    ((card->txbd_wrptr & reg->tx_rollover_ind) != | ||||||
|  | 		     (rdptr & reg->tx_rollover_ind))) | ||||||
| 			return 1; | 			return 1; | ||||||
|  | 		break; | ||||||
|  | 	case PCIE_DEVICE_ID_MARVELL_88W8897: | ||||||
|  | 		if (((card->txbd_wrptr & reg->tx_mask) == | ||||||
|  | 		     (rdptr & reg->tx_mask)) && | ||||||
|  | 		    ((card->txbd_wrptr & reg->tx_rollover_ind) == | ||||||
|  | 			(rdptr & reg->tx_rollover_ind))) | ||||||
|  | 			return 1; | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | @ -162,11 +296,24 @@ mwifiex_pcie_txbd_empty(struct pcie_service_card *card, u32 rdptr) | ||||||
| static inline int | static inline int | ||||||
| mwifiex_pcie_txbd_not_full(struct pcie_service_card *card) | mwifiex_pcie_txbd_not_full(struct pcie_service_card *card) | ||||||
| { | { | ||||||
| 	if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) != | 	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; | ||||||
| 	     (card->txbd_rdptr & MWIFIEX_TXBD_MASK)) || | 
 | ||||||
| 	    ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) != | 	switch (card->dev->device) { | ||||||
| 	     (card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) | 	case PCIE_DEVICE_ID_MARVELL_88W8766P: | ||||||
|  | 		if (((card->txbd_wrptr & reg->tx_mask) != | ||||||
|  | 		     (card->txbd_rdptr & reg->tx_mask)) || | ||||||
|  | 		    ((card->txbd_wrptr & reg->tx_rollover_ind) != | ||||||
|  | 		     (card->txbd_rdptr & reg->tx_rollover_ind))) | ||||||
| 			return 1; | 			return 1; | ||||||
|  | 		break; | ||||||
|  | 	case PCIE_DEVICE_ID_MARVELL_88W8897: | ||||||
|  | 		if (((card->txbd_wrptr & reg->tx_mask) != | ||||||
|  | 		     (card->txbd_rdptr & reg->tx_mask)) || | ||||||
|  | 		    ((card->txbd_wrptr & reg->tx_rollover_ind) == | ||||||
|  | 		     (card->txbd_rdptr & reg->tx_rollover_ind))) | ||||||
|  | 			return 1; | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1741,7 +1741,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, | ||||||
| 					    .mac_address, ETH_ALEN)) | 					    .mac_address, ETH_ALEN)) | ||||||
| 					mwifiex_update_curr_bss_params(priv, | 					mwifiex_update_curr_bss_params(priv, | ||||||
| 								       bss); | 								       bss); | ||||||
| 				cfg80211_put_bss(bss); | 				cfg80211_put_bss(priv->wdev->wiphy, bss); | ||||||
| 			} | 			} | ||||||
| 		} else { | 		} else { | ||||||
| 			dev_dbg(adapter->dev, "missing BSS channel IE\n"); | 			dev_dbg(adapter->dev, "missing BSS channel IE\n"); | ||||||
|  |  | ||||||
|  | @ -162,13 +162,9 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, | ||||||
| 
 | 
 | ||||||
| 	rcu_read_lock(); | 	rcu_read_lock(); | ||||||
| 	ies = rcu_dereference(bss->ies); | 	ies = rcu_dereference(bss->ies); | ||||||
| 	if (WARN_ON(!ies)) { |  | ||||||
| 		/* should never happen */ |  | ||||||
| 		rcu_read_unlock(); |  | ||||||
| 		return -EINVAL; |  | ||||||
| 	} |  | ||||||
| 	beacon_ie = kmemdup(ies->data, ies->len, GFP_ATOMIC); | 	beacon_ie = kmemdup(ies->data, ies->len, GFP_ATOMIC); | ||||||
| 	beacon_ie_len = ies->len; | 	beacon_ie_len = ies->len; | ||||||
|  | 	bss_desc->timestamp = ies->tsf; | ||||||
| 	rcu_read_unlock(); | 	rcu_read_unlock(); | ||||||
| 
 | 
 | ||||||
| 	if (!beacon_ie) { | 	if (!beacon_ie) { | ||||||
|  | @ -184,7 +180,6 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, | ||||||
| 	bss_desc->cap_info_bitmap = bss->capability; | 	bss_desc->cap_info_bitmap = bss->capability; | ||||||
| 	bss_desc->bss_band = bss_priv->band; | 	bss_desc->bss_band = bss_priv->band; | ||||||
| 	bss_desc->fw_tsf = bss_priv->fw_tsf; | 	bss_desc->fw_tsf = bss_priv->fw_tsf; | ||||||
| 	bss_desc->timestamp = bss->tsf; |  | ||||||
| 	if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) { | 	if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) { | ||||||
| 		dev_dbg(priv->adapter->dev, "info: InterpretIE: AP WEP enabled\n"); | 		dev_dbg(priv->adapter->dev, "info: InterpretIE: AP WEP enabled\n"); | ||||||
| 		bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; | 		bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; | ||||||
|  | @ -322,7 +317,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (bss) | 		if (bss) | ||||||
| 			cfg80211_put_bss(bss); | 			cfg80211_put_bss(priv->adapter->wiphy, bss); | ||||||
| 	} else { | 	} else { | ||||||
| 		/* Adhoc mode */ | 		/* Adhoc mode */ | ||||||
| 		/* If the requested SSID matches current SSID, return */ | 		/* If the requested SSID matches current SSID, return */ | ||||||
|  | @ -352,7 +347,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, | ||||||
| 							" list. Joining...\n"); | 							" list. Joining...\n"); | ||||||
| 			ret = mwifiex_adhoc_join(priv, bss_desc); | 			ret = mwifiex_adhoc_join(priv, bss_desc); | ||||||
| 			if (bss) | 			if (bss) | ||||||
| 				cfg80211_put_bss(bss); | 				cfg80211_put_bss(priv->adapter->wiphy, bss); | ||||||
| 		} else { | 		} else { | ||||||
| 			dev_dbg(adapter->dev, "info: Network not found in " | 			dev_dbg(adapter->dev, "info: Network not found in " | ||||||
| 				"the list, creating adhoc with ssid = %s\n", | 				"the list, creating adhoc with ssid = %s\n", | ||||||
|  |  | ||||||
|  | @ -5471,6 +5471,8 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { | ||||||
| 	{ PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = MWL8687, }, | 	{ PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = MWL8687, }, | ||||||
| 	{ PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = MWL8687, }, | 	{ PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = MWL8687, }, | ||||||
| 	{ PCI_VDEVICE(MARVELL, 0x2a40), .driver_data = MWL8366, }, | 	{ PCI_VDEVICE(MARVELL, 0x2a40), .driver_data = MWL8366, }, | ||||||
|  | 	{ PCI_VDEVICE(MARVELL, 0x2a41), .driver_data = MWL8366, }, | ||||||
|  | 	{ PCI_VDEVICE(MARVELL, 0x2a42), .driver_data = MWL8366, }, | ||||||
| 	{ PCI_VDEVICE(MARVELL, 0x2a43), .driver_data = MWL8366, }, | 	{ PCI_VDEVICE(MARVELL, 0x2a43), .driver_data = MWL8366, }, | ||||||
| 	{ }, | 	{ }, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -125,7 +125,7 @@ static void orinoco_add_hostscan_result(struct orinoco_private *priv, | ||||||
| 	cbss = cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp, | 	cbss = cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp, | ||||||
| 				   capability, beacon_interval, ie_buf, ie_len, | 				   capability, beacon_interval, ie_buf, ie_len, | ||||||
| 				   signal, GFP_KERNEL); | 				   signal, GFP_KERNEL); | ||||||
| 	cfg80211_put_bss(cbss); | 	cfg80211_put_bss(wiphy, cbss); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void orinoco_add_extscan_result(struct orinoco_private *priv, | void orinoco_add_extscan_result(struct orinoco_private *priv, | ||||||
|  | @ -158,7 +158,7 @@ void orinoco_add_extscan_result(struct orinoco_private *priv, | ||||||
| 	cbss = cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp, | 	cbss = cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp, | ||||||
| 				   capability, beacon_interval, ie, ie_len, | 				   capability, beacon_interval, ie, ie_len, | ||||||
| 				   signal, GFP_KERNEL); | 				   signal, GFP_KERNEL); | ||||||
| 	cfg80211_put_bss(cbss); | 	cfg80211_put_bss(wiphy, cbss); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void orinoco_add_hostscan_results(struct orinoco_private *priv, | void orinoco_add_hostscan_results(struct orinoco_private *priv, | ||||||
|  |  | ||||||
|  | @ -84,8 +84,8 @@ static struct usb_device_id p54u_table[] = { | ||||||
| 	{USB_DEVICE(0x06b9, 0x0121)},	/* Thomson SpeedTouch 121g */ | 	{USB_DEVICE(0x06b9, 0x0121)},	/* Thomson SpeedTouch 121g */ | ||||||
| 	{USB_DEVICE(0x0707, 0xee13)},   /* SMC 2862W-G version 2 */ | 	{USB_DEVICE(0x0707, 0xee13)},   /* SMC 2862W-G version 2 */ | ||||||
| 	{USB_DEVICE(0x0803, 0x4310)},	/* Zoom 4410a */ | 	{USB_DEVICE(0x0803, 0x4310)},	/* Zoom 4410a */ | ||||||
| 	{USB_DEVICE(0x083a, 0x4503)},	/* T-Com Sinus 154 data II */ |  | ||||||
| 	{USB_DEVICE(0x083a, 0x4521)},   /* Siemens Gigaset USB Adapter 54 version 2 */ | 	{USB_DEVICE(0x083a, 0x4521)},   /* Siemens Gigaset USB Adapter 54 version 2 */ | ||||||
|  | 	{USB_DEVICE(0x083a, 0x4531)},	/* T-Com Sinus 154 data II */ | ||||||
| 	{USB_DEVICE(0x083a, 0xc501)},	/* Zoom Wireless-G 4410 */ | 	{USB_DEVICE(0x083a, 0xc501)},	/* Zoom Wireless-G 4410 */ | ||||||
| 	{USB_DEVICE(0x083a, 0xf503)},	/* Accton FD7050E ver 1010ec  */ | 	{USB_DEVICE(0x083a, 0xf503)},	/* Accton FD7050E ver 1010ec  */ | ||||||
| 	{USB_DEVICE(0x0846, 0x4240)},	/* Netgear WG111 (v2) */ | 	{USB_DEVICE(0x0846, 0x4240)},	/* Netgear WG111 (v2) */ | ||||||
|  |  | ||||||
|  | @ -2026,7 +2026,7 @@ static bool rndis_bss_info_update(struct usbnet *usbdev, | ||||||
| 	bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid->mac, | 	bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid->mac, | ||||||
| 		timestamp, capability, beacon_interval, ie, ie_len, signal, | 		timestamp, capability, beacon_interval, ie, ie_len, signal, | ||||||
| 		GFP_KERNEL); | 		GFP_KERNEL); | ||||||
| 	cfg80211_put_bss(bss); | 	cfg80211_put_bss(priv->wdev.wiphy, bss); | ||||||
| 
 | 
 | ||||||
| 	return (bss != NULL); | 	return (bss != NULL); | ||||||
| } | } | ||||||
|  | @ -2715,7 +2715,7 @@ static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid, | ||||||
| 	bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid, | 	bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid, | ||||||
| 		timestamp, capability, beacon_period, ie_buf, ie_len, | 		timestamp, capability, beacon_period, ie_buf, ie_len, | ||||||
| 		signal, GFP_KERNEL); | 		signal, GFP_KERNEL); | ||||||
| 	cfg80211_put_bss(bss); | 	cfg80211_put_bss(priv->wdev.wiphy, bss); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  |  | ||||||
|  | @ -1185,8 +1185,14 @@ static void rt2400pci_write_beacon(struct queue_entry *entry, | ||||||
| 	rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); | 	rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); | ||||||
| 	rt2x00pci_register_write(rt2x00dev, CSR14, reg); | 	rt2x00pci_register_write(rt2x00dev, CSR14, reg); | ||||||
| 
 | 
 | ||||||
| 	rt2x00queue_map_txskb(entry); | 	if (rt2x00queue_map_txskb(entry)) { | ||||||
| 
 | 		ERROR(rt2x00dev, "Fail to map beacon, aborting\n"); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 	/*
 | ||||||
|  | 	 * Enable beaconing again. | ||||||
|  | 	 */ | ||||||
|  | 	rt2x00_set_field32(®, CSR14_BEACON_GEN, 1); | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Write the TX descriptor for the beacon. | 	 * Write the TX descriptor for the beacon. | ||||||
| 	 */ | 	 */ | ||||||
|  | @ -1196,7 +1202,7 @@ static void rt2400pci_write_beacon(struct queue_entry *entry, | ||||||
| 	 * Dump beacon to userspace through debugfs. | 	 * Dump beacon to userspace through debugfs. | ||||||
| 	 */ | 	 */ | ||||||
| 	rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb); | 	rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb); | ||||||
| 
 | out: | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Enable beaconing again. | 	 * Enable beaconing again. | ||||||
| 	 */ | 	 */ | ||||||
|  |  | ||||||
|  | @ -1338,7 +1338,10 @@ static void rt2500pci_write_beacon(struct queue_entry *entry, | ||||||
| 	rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); | 	rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); | ||||||
| 	rt2x00pci_register_write(rt2x00dev, CSR14, reg); | 	rt2x00pci_register_write(rt2x00dev, CSR14, reg); | ||||||
| 
 | 
 | ||||||
| 	rt2x00queue_map_txskb(entry); | 	if (rt2x00queue_map_txskb(entry)) { | ||||||
|  | 		ERROR(rt2x00dev, "Fail to map beacon, aborting\n"); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Write the TX descriptor for the beacon. | 	 * Write the TX descriptor for the beacon. | ||||||
|  | @ -1349,7 +1352,7 @@ static void rt2500pci_write_beacon(struct queue_entry *entry, | ||||||
| 	 * Dump beacon to userspace through debugfs. | 	 * Dump beacon to userspace through debugfs. | ||||||
| 	 */ | 	 */ | ||||||
| 	rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb); | 	rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb); | ||||||
| 
 | out: | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Enable beaconing again. | 	 * Enable beaconing again. | ||||||
| 	 */ | 	 */ | ||||||
|  |  | ||||||
|  | @ -1099,9 +1099,11 @@ static struct usb_device_id rt2800usb_device_table[] = { | ||||||
| 	{ USB_DEVICE(0x15a9, 0x0006) }, | 	{ USB_DEVICE(0x15a9, 0x0006) }, | ||||||
| 	/* Sweex */ | 	/* Sweex */ | ||||||
| 	{ USB_DEVICE(0x177f, 0x0153) }, | 	{ USB_DEVICE(0x177f, 0x0153) }, | ||||||
|  | 	{ USB_DEVICE(0x177f, 0x0164) }, | ||||||
| 	{ USB_DEVICE(0x177f, 0x0302) }, | 	{ USB_DEVICE(0x177f, 0x0302) }, | ||||||
| 	{ USB_DEVICE(0x177f, 0x0313) }, | 	{ USB_DEVICE(0x177f, 0x0313) }, | ||||||
| 	{ USB_DEVICE(0x177f, 0x0323) }, | 	{ USB_DEVICE(0x177f, 0x0323) }, | ||||||
|  | 	{ USB_DEVICE(0x177f, 0x0324) }, | ||||||
| 	/* U-Media */ | 	/* U-Media */ | ||||||
| 	{ USB_DEVICE(0x157e, 0x300e) }, | 	{ USB_DEVICE(0x157e, 0x300e) }, | ||||||
| 	{ USB_DEVICE(0x157e, 0x3013) }, | 	{ USB_DEVICE(0x157e, 0x3013) }, | ||||||
|  | @ -1133,6 +1135,9 @@ static struct usb_device_id rt2800usb_device_table[] = { | ||||||
| 	{ USB_DEVICE(0x148f, 0x8070) }, | 	{ USB_DEVICE(0x148f, 0x8070) }, | ||||||
| 	/* Sitecom */ | 	/* Sitecom */ | ||||||
| 	{ USB_DEVICE(0x0df6, 0x0050) }, | 	{ USB_DEVICE(0x0df6, 0x0050) }, | ||||||
|  | 	/* Sweex */ | ||||||
|  | 	{ USB_DEVICE(0x177f, 0x0163) }, | ||||||
|  | 	{ USB_DEVICE(0x177f, 0x0165) }, | ||||||
| #endif | #endif | ||||||
| #ifdef CONFIG_RT2800USB_RT35XX | #ifdef CONFIG_RT2800USB_RT35XX | ||||||
| 	/* Allwin */ | 	/* Allwin */ | ||||||
|  | @ -1214,10 +1219,15 @@ static struct usb_device_id rt2800usb_device_table[] = { | ||||||
| 	{ USB_DEVICE(0x0b05, 0x1760) }, | 	{ USB_DEVICE(0x0b05, 0x1760) }, | ||||||
| 	{ USB_DEVICE(0x0b05, 0x1761) }, | 	{ USB_DEVICE(0x0b05, 0x1761) }, | ||||||
| 	{ USB_DEVICE(0x0b05, 0x1790) }, | 	{ USB_DEVICE(0x0b05, 0x1790) }, | ||||||
|  | 	{ USB_DEVICE(0x0b05, 0x17a7) }, | ||||||
| 	/* AzureWave */ | 	/* AzureWave */ | ||||||
| 	{ USB_DEVICE(0x13d3, 0x3262) }, | 	{ USB_DEVICE(0x13d3, 0x3262) }, | ||||||
| 	{ USB_DEVICE(0x13d3, 0x3284) }, | 	{ USB_DEVICE(0x13d3, 0x3284) }, | ||||||
| 	{ USB_DEVICE(0x13d3, 0x3322) }, | 	{ USB_DEVICE(0x13d3, 0x3322) }, | ||||||
|  | 	{ USB_DEVICE(0x13d3, 0x3340) }, | ||||||
|  | 	{ USB_DEVICE(0x13d3, 0x3399) }, | ||||||
|  | 	{ USB_DEVICE(0x13d3, 0x3400) }, | ||||||
|  | 	{ USB_DEVICE(0x13d3, 0x3401) }, | ||||||
| 	/* Belkin */ | 	/* Belkin */ | ||||||
| 	{ USB_DEVICE(0x050d, 0x1003) }, | 	{ USB_DEVICE(0x050d, 0x1003) }, | ||||||
| 	/* Buffalo */ | 	/* Buffalo */ | ||||||
|  | @ -1232,10 +1242,15 @@ static struct usb_device_id rt2800usb_device_table[] = { | ||||||
| 	{ USB_DEVICE(0x07d1, 0x3c0b) }, | 	{ USB_DEVICE(0x07d1, 0x3c0b) }, | ||||||
| 	/* Encore */ | 	/* Encore */ | ||||||
| 	{ USB_DEVICE(0x203d, 0x14a1) }, | 	{ USB_DEVICE(0x203d, 0x14a1) }, | ||||||
|  | 	/* EnGenius */ | ||||||
|  | 	{ USB_DEVICE(0x1740, 0x0600) }, | ||||||
|  | 	{ USB_DEVICE(0x1740, 0x0602) }, | ||||||
| 	/* Gemtek */ | 	/* Gemtek */ | ||||||
| 	{ USB_DEVICE(0x15a9, 0x0010) }, | 	{ USB_DEVICE(0x15a9, 0x0010) }, | ||||||
| 	/* Gigabyte */ | 	/* Gigabyte */ | ||||||
| 	{ USB_DEVICE(0x1044, 0x800c) }, | 	{ USB_DEVICE(0x1044, 0x800c) }, | ||||||
|  | 	/* Hercules */ | ||||||
|  | 	{ USB_DEVICE(0x06f8, 0xe036) }, | ||||||
| 	/* Huawei */ | 	/* Huawei */ | ||||||
| 	{ USB_DEVICE(0x148f, 0xf101) }, | 	{ USB_DEVICE(0x148f, 0xf101) }, | ||||||
| 	/* I-O DATA */ | 	/* I-O DATA */ | ||||||
|  | @ -1262,11 +1277,17 @@ static struct usb_device_id rt2800usb_device_table[] = { | ||||||
| 	{ USB_DEVICE(0x0df6, 0x004a) }, | 	{ USB_DEVICE(0x0df6, 0x004a) }, | ||||||
| 	{ USB_DEVICE(0x0df6, 0x004d) }, | 	{ USB_DEVICE(0x0df6, 0x004d) }, | ||||||
| 	{ USB_DEVICE(0x0df6, 0x0053) }, | 	{ USB_DEVICE(0x0df6, 0x0053) }, | ||||||
|  | 	{ USB_DEVICE(0x0df6, 0x0069) }, | ||||||
|  | 	{ USB_DEVICE(0x0df6, 0x006f) }, | ||||||
| 	/* SMC */ | 	/* SMC */ | ||||||
| 	{ USB_DEVICE(0x083a, 0xa512) }, | 	{ USB_DEVICE(0x083a, 0xa512) }, | ||||||
| 	{ USB_DEVICE(0x083a, 0xc522) }, | 	{ USB_DEVICE(0x083a, 0xc522) }, | ||||||
| 	{ USB_DEVICE(0x083a, 0xd522) }, | 	{ USB_DEVICE(0x083a, 0xd522) }, | ||||||
| 	{ USB_DEVICE(0x083a, 0xf511) }, | 	{ USB_DEVICE(0x083a, 0xf511) }, | ||||||
|  | 	/* Sweex */ | ||||||
|  | 	{ USB_DEVICE(0x177f, 0x0254) }, | ||||||
|  | 	/* TP-LINK */ | ||||||
|  | 	{ USB_DEVICE(0xf201, 0x5370) }, | ||||||
| #endif | #endif | ||||||
| 	{ 0, } | 	{ 0, } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -1169,8 +1169,10 @@ static inline bool rt2x00_is_soc(struct rt2x00_dev *rt2x00dev) | ||||||
| /**
 | /**
 | ||||||
|  * rt2x00queue_map_txskb - Map a skb into DMA for TX purposes. |  * rt2x00queue_map_txskb - Map a skb into DMA for TX purposes. | ||||||
|  * @entry: Pointer to &struct queue_entry |  * @entry: Pointer to &struct queue_entry | ||||||
|  |  * | ||||||
|  |  * Returns -ENOMEM if mapping fail, 0 otherwise. | ||||||
|  */ |  */ | ||||||
| void rt2x00queue_map_txskb(struct queue_entry *entry); | int rt2x00queue_map_txskb(struct queue_entry *entry); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * rt2x00queue_unmap_skb - Unmap a skb from DMA. |  * rt2x00queue_unmap_skb - Unmap a skb from DMA. | ||||||
|  |  | ||||||
|  | @ -87,24 +87,35 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry, gfp_t gfp) | ||||||
| 	skbdesc->entry = entry; | 	skbdesc->entry = entry; | ||||||
| 
 | 
 | ||||||
| 	if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) { | 	if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) { | ||||||
| 		skbdesc->skb_dma = dma_map_single(rt2x00dev->dev, | 		dma_addr_t skb_dma; | ||||||
| 						  skb->data, | 
 | ||||||
| 						  skb->len, | 		skb_dma = dma_map_single(rt2x00dev->dev, skb->data, skb->len, | ||||||
| 					 DMA_FROM_DEVICE); | 					 DMA_FROM_DEVICE); | ||||||
|  | 		if (unlikely(dma_mapping_error(rt2x00dev->dev, skb_dma))) { | ||||||
|  | 			dev_kfree_skb_any(skb); | ||||||
|  | 			return NULL; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		skbdesc->skb_dma = skb_dma; | ||||||
| 		skbdesc->flags |= SKBDESC_DMA_MAPPED_RX; | 		skbdesc->flags |= SKBDESC_DMA_MAPPED_RX; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return skb; | 	return skb; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void rt2x00queue_map_txskb(struct queue_entry *entry) | int rt2x00queue_map_txskb(struct queue_entry *entry) | ||||||
| { | { | ||||||
| 	struct device *dev = entry->queue->rt2x00dev->dev; | 	struct device *dev = entry->queue->rt2x00dev->dev; | ||||||
| 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); | 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); | ||||||
| 
 | 
 | ||||||
| 	skbdesc->skb_dma = | 	skbdesc->skb_dma = | ||||||
| 	    dma_map_single(dev, entry->skb->data, entry->skb->len, DMA_TO_DEVICE); | 	    dma_map_single(dev, entry->skb->data, entry->skb->len, DMA_TO_DEVICE); | ||||||
|  | 
 | ||||||
|  | 	if (unlikely(dma_mapping_error(dev, skbdesc->skb_dma))) | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 
 | ||||||
| 	skbdesc->flags |= SKBDESC_DMA_MAPPED_TX; | 	skbdesc->flags |= SKBDESC_DMA_MAPPED_TX; | ||||||
|  | 	return 0; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb); | EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb); | ||||||
| 
 | 
 | ||||||
|  | @ -343,10 +354,7 @@ static void rt2x00queue_create_tx_descriptor_ht(struct rt2x00_dev *rt2x00dev, | ||||||
| 		 * when using more then one tx stream (>MCS7). | 		 * when using more then one tx stream (>MCS7). | ||||||
| 		 */ | 		 */ | ||||||
| 		if (sta && txdesc->u.ht.mcs > 7 && | 		if (sta && txdesc->u.ht.mcs > 7 && | ||||||
| 		    ((sta->ht_cap.cap & | 		    sta->smps_mode == IEEE80211_SMPS_DYNAMIC) | ||||||
| 		      IEEE80211_HT_CAP_SM_PS) >> |  | ||||||
| 		     IEEE80211_HT_CAP_SM_PS_SHIFT) == |  | ||||||
| 		    WLAN_HT_CAP_SM_PS_DYNAMIC) |  | ||||||
| 			__set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags); | 			__set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags); | ||||||
| 	} else { | 	} else { | ||||||
| 		txdesc->u.ht.mcs = rt2x00_get_rate_mcs(hwrate->mcs); | 		txdesc->u.ht.mcs = rt2x00_get_rate_mcs(hwrate->mcs); | ||||||
|  | @ -545,8 +553,9 @@ static int rt2x00queue_write_tx_data(struct queue_entry *entry, | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Map the skb to DMA. | 	 * Map the skb to DMA. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) | 	if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags) && | ||||||
| 		rt2x00queue_map_txskb(entry); | 	    rt2x00queue_map_txskb(entry)) | ||||||
|  | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,8 +1,26 @@ | ||||||
|  | config RTLWIFI | ||||||
|  | 	tristate "Realtek wireless card support" | ||||||
|  | 	depends on MAC80211 | ||||||
|  | 	select FW_LOADER | ||||||
|  | 	---help--- | ||||||
|  | 	  This is common code for RTL8192CE/RTL8192CU/RTL8192SE/RTL8723AE | ||||||
|  | 	  drivers.  This module does nothing by itself - the various front-end | ||||||
|  | 	  drivers need to be enabled to support any desired devices. | ||||||
|  | 
 | ||||||
|  | 	  If you choose to build as a module, it'll be called rtlwifi. | ||||||
|  | 
 | ||||||
|  | config RTLWIFI_DEBUG | ||||||
|  | 	bool "Debugging output for rtlwifi driver family" | ||||||
|  | 	depends on RTLWIFI | ||||||
|  | 	default y | ||||||
|  | 	---help--- | ||||||
|  | 	To use the module option that sets the dynamic-debugging level for, | ||||||
|  | 	the front-end driver, this parameter must be "Y". For memory-limited | ||||||
|  | 	systems, choose "N". If in doubt, choose "Y". | ||||||
|  | 
 | ||||||
| config RTL8192CE | config RTL8192CE | ||||||
| 	tristate "Realtek RTL8192CE/RTL8188CE Wireless Network Adapter" | 	tristate "Realtek RTL8192CE/RTL8188CE Wireless Network Adapter" | ||||||
| 	depends on MAC80211 && PCI | 	depends on RTLWIFI && PCI | ||||||
| 	select FW_LOADER |  | ||||||
| 	select RTLWIFI |  | ||||||
| 	select RTL8192C_COMMON | 	select RTL8192C_COMMON | ||||||
| 	---help--- | 	---help--- | ||||||
| 	This is the driver for Realtek RTL8192CE/RTL8188CE 802.11n PCIe | 	This is the driver for Realtek RTL8192CE/RTL8188CE 802.11n PCIe | ||||||
|  | @ -12,9 +30,7 @@ config RTL8192CE | ||||||
| 
 | 
 | ||||||
| config RTL8192SE | config RTL8192SE | ||||||
| 	tristate "Realtek RTL8192SE/RTL8191SE PCIe Wireless Network Adapter" | 	tristate "Realtek RTL8192SE/RTL8191SE PCIe Wireless Network Adapter" | ||||||
| 	depends on MAC80211 && PCI | 	depends on RTLWIFI && PCI | ||||||
| 	select FW_LOADER |  | ||||||
| 	select RTLWIFI |  | ||||||
| 	---help--- | 	---help--- | ||||||
| 	This is the driver for Realtek RTL8192SE/RTL8191SE 802.11n PCIe | 	This is the driver for Realtek RTL8192SE/RTL8191SE 802.11n PCIe | ||||||
| 	wireless network adapters. | 	wireless network adapters. | ||||||
|  | @ -23,9 +39,7 @@ config RTL8192SE | ||||||
| 
 | 
 | ||||||
| config RTL8192DE | config RTL8192DE | ||||||
| 	tristate "Realtek RTL8192DE/RTL8188DE PCIe Wireless Network Adapter" | 	tristate "Realtek RTL8192DE/RTL8188DE PCIe Wireless Network Adapter" | ||||||
| 	depends on MAC80211 && PCI | 	depends on RTLWIFI && PCI | ||||||
| 	select FW_LOADER |  | ||||||
| 	select RTLWIFI |  | ||||||
| 	---help--- | 	---help--- | ||||||
| 	This is the driver for Realtek RTL8192DE/RTL8188DE 802.11n PCIe | 	This is the driver for Realtek RTL8192DE/RTL8188DE 802.11n PCIe | ||||||
| 	wireless network adapters. | 	wireless network adapters. | ||||||
|  | @ -34,9 +48,7 @@ config RTL8192DE | ||||||
| 
 | 
 | ||||||
| config RTL8723AE | config RTL8723AE | ||||||
| 	tristate "Realtek RTL8723AE PCIe Wireless Network Adapter" | 	tristate "Realtek RTL8723AE PCIe Wireless Network Adapter" | ||||||
| 	depends on MAC80211 && PCI && EXPERIMENTAL | 	depends on RTLWIFI && PCI | ||||||
| 	select FW_LOADER |  | ||||||
| 	select RTLWIFI |  | ||||||
| 	---help--- | 	---help--- | ||||||
| 	This is the driver for Realtek RTL8723AE 802.11n PCIe | 	This is the driver for Realtek RTL8723AE 802.11n PCIe | ||||||
| 	wireless network adapters. | 	wireless network adapters. | ||||||
|  | @ -45,9 +57,7 @@ config RTL8723AE | ||||||
| 
 | 
 | ||||||
| config RTL8192CU | config RTL8192CU | ||||||
| 	tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter" | 	tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter" | ||||||
| 	depends on MAC80211 && USB | 	depends on RTLWIFI && USB | ||||||
| 	select FW_LOADER |  | ||||||
| 	select RTLWIFI |  | ||||||
| 	select RTL8192C_COMMON | 	select RTL8192C_COMMON | ||||||
| 	---help--- | 	---help--- | ||||||
| 	This is the driver for Realtek RTL8192CU/RTL8188CU 802.11n USB | 	This is the driver for Realtek RTL8192CU/RTL8188CU 802.11n USB | ||||||
|  | @ -55,16 +65,6 @@ config RTL8192CU | ||||||
| 
 | 
 | ||||||
| 	If you choose to build it as a module, it will be called rtl8192cu | 	If you choose to build it as a module, it will be called rtl8192cu | ||||||
| 
 | 
 | ||||||
| config RTLWIFI |  | ||||||
| 	tristate |  | ||||||
| 	depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE || RTL8723AE |  | ||||||
| 	default m |  | ||||||
| 
 |  | ||||||
| config RTLWIFI_DEBUG |  | ||||||
| 	bool "Additional debugging output" |  | ||||||
| 	depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE || RTL8723AE |  | ||||||
| 	default y |  | ||||||
| 
 |  | ||||||
| config RTL8192C_COMMON | config RTL8192C_COMMON | ||||||
| 	tristate | 	tristate | ||||||
| 	depends on RTL8192CE || RTL8192CU | 	depends on RTL8192CE || RTL8192CU | ||||||
|  |  | ||||||
|  | @ -524,7 +524,7 @@ static void _rtl_query_shortgi(struct ieee80211_hw *hw, | ||||||
| 		bw_40 = mac->bw_40; | 		bw_40 = mac->bw_40; | ||||||
| 	else if (mac->opmode == NL80211_IFTYPE_AP || | 	else if (mac->opmode == NL80211_IFTYPE_AP || | ||||||
| 		 mac->opmode == NL80211_IFTYPE_ADHOC) | 		 mac->opmode == NL80211_IFTYPE_ADHOC) | ||||||
| 		bw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 		bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40; | ||||||
| 
 | 
 | ||||||
| 	if (bw_40 && sgi_40) | 	if (bw_40 && sgi_40) | ||||||
| 		tcb_desc->use_shortgi = true; | 		tcb_desc->use_shortgi = true; | ||||||
|  | @ -634,8 +634,7 @@ static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw, | ||||||
| 		return; | 		return; | ||||||
| 	if (mac->opmode == NL80211_IFTYPE_AP || | 	if (mac->opmode == NL80211_IFTYPE_AP || | ||||||
| 	    mac->opmode == NL80211_IFTYPE_ADHOC) { | 	    mac->opmode == NL80211_IFTYPE_ADHOC) { | ||||||
| 		if (!(sta->ht_cap.ht_supported) || | 		if (sta->bandwidth == IEEE80211_STA_RX_BW_20) | ||||||
| 		    !(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) |  | ||||||
| 			return; | 			return; | ||||||
| 	} else if (mac->opmode == NL80211_IFTYPE_STATION) { | 	} else if (mac->opmode == NL80211_IFTYPE_STATION) { | ||||||
| 		if (!mac->bw_40 || !(sta->ht_cap.ht_supported)) | 		if (!mac->bw_40 || !(sta->ht_cap.ht_supported)) | ||||||
|  |  | ||||||
|  | @ -117,8 +117,7 @@ static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv, | ||||||
| 			rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; | 			rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; | ||||||
| 		if (mac->opmode == NL80211_IFTYPE_AP || | 		if (mac->opmode == NL80211_IFTYPE_AP || | ||||||
| 		    mac->opmode == NL80211_IFTYPE_ADHOC) { | 		    mac->opmode == NL80211_IFTYPE_ADHOC) { | ||||||
| 			if (sta && (sta->ht_cap.cap & | 			if (sta && (sta->bandwidth >= IEEE80211_STA_RX_BW_40)) | ||||||
| 			    IEEE80211_HT_CAP_SUP_WIDTH_20_40)) |  | ||||||
| 				rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | 				rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | ||||||
| 		} else { | 		} else { | ||||||
| 			if (mac->bw_40) | 			if (mac->bw_40) | ||||||
|  | @ -217,6 +216,12 @@ static void rtl_tx_status(void *ppriv, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void rtl_rate_init(void *ppriv, | ||||||
|  | 			  struct ieee80211_supported_band *sband, | ||||||
|  | 			  struct ieee80211_sta *sta, void *priv_sta) | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void *rtl_rate_alloc(struct ieee80211_hw *hw, | static void *rtl_rate_alloc(struct ieee80211_hw *hw, | ||||||
| 		struct dentry *debugfsdir) | 		struct dentry *debugfsdir) | ||||||
| { | { | ||||||
|  | @ -261,6 +266,7 @@ static struct rate_control_ops rtl_rate_ops = { | ||||||
| 	.free = rtl_rate_free, | 	.free = rtl_rate_free, | ||||||
| 	.alloc_sta = rtl_rate_alloc_sta, | 	.alloc_sta = rtl_rate_alloc_sta, | ||||||
| 	.free_sta = rtl_rate_free_sta, | 	.free_sta = rtl_rate_free_sta, | ||||||
|  | 	.rate_init = rtl_rate_init, | ||||||
| 	.tx_status = rtl_tx_status, | 	.tx_status = rtl_tx_status, | ||||||
| 	.get_rate = rtl_get_rate, | 	.get_rate = rtl_get_rate, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -1846,9 +1846,9 @@ static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, | ||||||
| 	struct rtl_sta_info *sta_entry = NULL; | 	struct rtl_sta_info *sta_entry = NULL; | ||||||
| 	u32 ratr_bitmap; | 	u32 ratr_bitmap; | ||||||
| 	u8 ratr_index; | 	u8 ratr_index; | ||||||
| 	u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) | 	u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0; | ||||||
| 				? 1 : 0; | 	u8 curshortgi_40mhz = curtxbw_40mhz && | ||||||
| 	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? | 			      (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? | ||||||
| 				1 : 0; | 				1 : 0; | ||||||
| 	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? | 	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? | ||||||
| 				1 : 0; | 				1 : 0; | ||||||
|  |  | ||||||
|  | @ -488,7 +488,7 @@ static void _rtl92ce_translate_rx_signal_stuff(struct ieee80211_hw *hw, | ||||||
| 	u8 *praddr; | 	u8 *praddr; | ||||||
| 	__le16 fc; | 	__le16 fc; | ||||||
| 	u16 type, c_fc; | 	u16 type, c_fc; | ||||||
| 	bool packet_matchbssid, packet_toself, packet_beacon; | 	bool packet_matchbssid, packet_toself, packet_beacon = false; | ||||||
| 
 | 
 | ||||||
| 	tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift; | 	tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift; | ||||||
| 
 | 
 | ||||||
|  | @ -626,8 +626,7 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, | ||||||
| 	} else if (mac->opmode == NL80211_IFTYPE_AP || | 	} else if (mac->opmode == NL80211_IFTYPE_AP || | ||||||
| 		mac->opmode == NL80211_IFTYPE_ADHOC) { | 		mac->opmode == NL80211_IFTYPE_ADHOC) { | ||||||
| 		if (sta) | 		if (sta) | ||||||
| 			bw_40 = sta->ht_cap.cap & | 			bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40; | ||||||
| 				IEEE80211_HT_CAP_SUP_WIDTH_20_40; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; | 	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; | ||||||
|  |  | ||||||
|  | @ -1084,7 +1084,7 @@ void rtl92c_translate_rx_signal_stuff(struct ieee80211_hw *hw, | ||||||
| 	u8 *praddr; | 	u8 *praddr; | ||||||
| 	__le16 fc; | 	__le16 fc; | ||||||
| 	u16 type, cpu_fc; | 	u16 type, cpu_fc; | ||||||
| 	bool packet_matchbssid, packet_toself, packet_beacon; | 	bool packet_matchbssid, packet_toself, packet_beacon = false; | ||||||
| 
 | 
 | ||||||
| 	tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift; | 	tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift; | ||||||
| 	hdr = (struct ieee80211_hdr *)tmp_buf; | 	hdr = (struct ieee80211_hdr *)tmp_buf; | ||||||
|  |  | ||||||
|  | @ -285,6 +285,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = { | ||||||
| 	{RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817f, rtl92cu_hal_cfg)}, | 	{RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817f, rtl92cu_hal_cfg)}, | ||||||
| 	/* RTL8188CUS-VL */ | 	/* RTL8188CUS-VL */ | ||||||
| 	{RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x818a, rtl92cu_hal_cfg)}, | 	{RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x818a, rtl92cu_hal_cfg)}, | ||||||
|  | 	{RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x819a, rtl92cu_hal_cfg)}, | ||||||
| 	/* 8188 Combo for BC4 */ | 	/* 8188 Combo for BC4 */ | ||||||
| 	{RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8754, rtl92cu_hal_cfg)}, | 	{RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8754, rtl92cu_hal_cfg)}, | ||||||
| 
 | 
 | ||||||
|  | @ -363,9 +364,15 @@ static struct usb_device_id rtl8192c_usb_ids[] = { | ||||||
| 
 | 
 | ||||||
| MODULE_DEVICE_TABLE(usb, rtl8192c_usb_ids); | MODULE_DEVICE_TABLE(usb, rtl8192c_usb_ids); | ||||||
| 
 | 
 | ||||||
|  | static int rtl8192cu_probe(struct usb_interface *intf, | ||||||
|  | 			   const struct usb_device_id *id) | ||||||
|  | { | ||||||
|  | 	return rtl_usb_probe(intf, id, &rtl92cu_hal_cfg); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static struct usb_driver rtl8192cu_driver = { | static struct usb_driver rtl8192cu_driver = { | ||||||
| 	.name = "rtl8192cu", | 	.name = "rtl8192cu", | ||||||
| 	.probe = rtl_usb_probe, | 	.probe = rtl8192cu_probe, | ||||||
| 	.disconnect = rtl_usb_disconnect, | 	.disconnect = rtl_usb_disconnect, | ||||||
| 	.id_table = rtl8192c_usb_ids, | 	.id_table = rtl8192c_usb_ids, | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1970,8 +1970,7 @@ static void rtl92de_update_hal_rate_mask(struct ieee80211_hw *hw, | ||||||
| 	struct rtl_sta_info *sta_entry = NULL; | 	struct rtl_sta_info *sta_entry = NULL; | ||||||
| 	u32 ratr_bitmap; | 	u32 ratr_bitmap; | ||||||
| 	u8 ratr_index; | 	u8 ratr_index; | ||||||
| 	u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) | 	u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0; | ||||||
| 							? 1 : 0; |  | ||||||
| 	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? | 	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? | ||||||
| 							1 : 0; | 							1 : 0; | ||||||
| 	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? | 	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? | ||||||
|  |  | ||||||
|  | @ -574,8 +574,7 @@ void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, | ||||||
| 	} else if (mac->opmode == NL80211_IFTYPE_AP || | 	} else if (mac->opmode == NL80211_IFTYPE_AP || | ||||||
| 		mac->opmode == NL80211_IFTYPE_ADHOC) { | 		mac->opmode == NL80211_IFTYPE_ADHOC) { | ||||||
| 		if (sta) | 		if (sta) | ||||||
| 			bw_40 = sta->ht_cap.cap & | 			bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40; | ||||||
| 				IEEE80211_HT_CAP_SUP_WIDTH_20_40; |  | ||||||
| 	} | 	} | ||||||
| 	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; | 	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; | ||||||
| 	rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc); | 	rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc); | ||||||
|  |  | ||||||
|  | @ -2085,8 +2085,7 @@ static void rtl92se_update_hal_rate_mask(struct ieee80211_hw *hw, | ||||||
| 	struct rtl_sta_info *sta_entry = NULL; | 	struct rtl_sta_info *sta_entry = NULL; | ||||||
| 	u32 ratr_bitmap; | 	u32 ratr_bitmap; | ||||||
| 	u8 ratr_index = 0; | 	u8 ratr_index = 0; | ||||||
| 	u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) | 	u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0; | ||||||
| 				? 1 : 0; |  | ||||||
| 	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? | 	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? | ||||||
| 				1 : 0; | 				1 : 0; | ||||||
| 	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? | 	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? | ||||||
|  |  | ||||||
|  | @ -621,8 +621,7 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, | ||||||
| 	} else if (mac->opmode == NL80211_IFTYPE_AP || | 	} else if (mac->opmode == NL80211_IFTYPE_AP || | ||||||
| 		mac->opmode == NL80211_IFTYPE_ADHOC) { | 		mac->opmode == NL80211_IFTYPE_ADHOC) { | ||||||
| 		if (sta) | 		if (sta) | ||||||
| 			bw_40 = sta->ht_cap.cap & | 			bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40; | ||||||
| 				    IEEE80211_HT_CAP_SUP_WIDTH_20_40; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; | 	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; | ||||||
|  |  | ||||||
|  | @ -1866,8 +1866,7 @@ static void rtl8723ae_update_hal_rate_mask(struct ieee80211_hw *hw, | ||||||
| 	struct rtl_sta_info *sta_entry = NULL; | 	struct rtl_sta_info *sta_entry = NULL; | ||||||
| 	u32 ratr_bitmap; | 	u32 ratr_bitmap; | ||||||
| 	u8 ratr_index; | 	u8 ratr_index; | ||||||
| 	u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) | 	u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0; | ||||||
| 				? 1 : 0; |  | ||||||
| 	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? | 	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? | ||||||
| 				1 : 0; | 				1 : 0; | ||||||
| 	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? | 	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? | ||||||
|  |  | ||||||
|  | @ -395,8 +395,7 @@ void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw, | ||||||
| 	} else if (mac->opmode == NL80211_IFTYPE_AP || | 	} else if (mac->opmode == NL80211_IFTYPE_AP || | ||||||
| 		mac->opmode == NL80211_IFTYPE_ADHOC) { | 		mac->opmode == NL80211_IFTYPE_ADHOC) { | ||||||
| 		if (sta) | 		if (sta) | ||||||
| 			bw_40 = sta->ht_cap.cap & | 			bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40; | ||||||
| 				IEEE80211_HT_CAP_SUP_WIDTH_20_40; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; | 	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; | ||||||
|  |  | ||||||
|  | @ -937,7 +937,8 @@ static struct rtl_intf_ops rtl_usb_ops = { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| int rtl_usb_probe(struct usb_interface *intf, | int rtl_usb_probe(struct usb_interface *intf, | ||||||
| 			const struct usb_device_id *id) | 		  const struct usb_device_id *id, | ||||||
|  | 		  struct rtl_hal_cfg *rtl_hal_cfg) | ||||||
| { | { | ||||||
| 	int err; | 	int err; | ||||||
| 	struct ieee80211_hw *hw = NULL; | 	struct ieee80211_hw *hw = NULL; | ||||||
|  | @ -972,7 +973,7 @@ int rtl_usb_probe(struct usb_interface *intf, | ||||||
| 	usb_set_intfdata(intf, hw); | 	usb_set_intfdata(intf, hw); | ||||||
| 	/* init cfg & intf_ops */ | 	/* init cfg & intf_ops */ | ||||||
| 	rtlpriv->rtlhal.interface = INTF_USB; | 	rtlpriv->rtlhal.interface = INTF_USB; | ||||||
| 	rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_info); | 	rtlpriv->cfg = rtl_hal_cfg; | ||||||
| 	rtlpriv->intf_ops = &rtl_usb_ops; | 	rtlpriv->intf_ops = &rtl_usb_ops; | ||||||
| 	rtl_dbgp_flag_init(hw); | 	rtl_dbgp_flag_init(hw); | ||||||
| 	/* Init IO handler */ | 	/* Init IO handler */ | ||||||
|  |  | ||||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 John W. Linville
				John W. Linville