diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c')
| -rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 97 | 
1 files changed, 86 insertions, 11 deletions
| diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index b2cc3d98e0f7..94aae9c8562c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -193,14 +193,11 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,  u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,  				struct ieee80211_vif *vif)  { -	u32 qmask, ac; +	u32 qmask = 0, ac;  	if (vif->type == NL80211_IFTYPE_P2P_DEVICE)  		return BIT(IWL_MVM_OFFCHANNEL_QUEUE); -	qmask = (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) ? -		BIT(vif->cab_queue) : 0; -  	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)  		if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)  			qmask |= BIT(vif->hw_queue[ac]); @@ -227,7 +224,7 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,  		.found_vif = false,  	};  	u32 ac; -	int ret; +	int ret, i;  	/*  	 * Allocate a MAC ID and a TSF for this MAC, along with the queues @@ -335,6 +332,9 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,  	mvmvif->bcast_sta.sta_id = IWL_MVM_STATION_COUNT;  	mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; +	for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) +		mvmvif->smps_requests[i] = IEEE80211_SMPS_AUTOMATIC; +  	return 0;  exit_fail: @@ -362,7 +362,7 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  		break;  	case NL80211_IFTYPE_AP:  		iwl_trans_ac_txq_enable(mvm->trans, vif->cab_queue, -					IWL_MVM_TX_FIFO_VO); +					IWL_MVM_TX_FIFO_MCAST);  		/* fall through */  	default:  		for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) @@ -550,6 +550,10 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,  		cmd->ac[i].fifos_mask = BIT(iwl_mvm_ac_to_tx_fifo[i]);  	} +	/* in AP mode, the MCAST FIFO takes the EDCA params from VO */ +	if (vif->type == NL80211_IFTYPE_AP) +		cmd->ac[AC_VO].fifos_mask |= BIT(IWL_MVM_TX_FIFO_MCAST); +  	if (vif->bss_conf.qos)  		cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA); @@ -861,6 +865,30 @@ int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,  	return ret;  } +struct iwl_mvm_mac_ap_iterator_data { +	struct iwl_mvm *mvm; +	struct ieee80211_vif *vif; +	u32 beacon_device_ts; +	u16 beacon_int; +}; + +/* Find the beacon_device_ts and beacon_int for a managed interface */ +static void iwl_mvm_mac_ap_iterator(void *_data, u8 *mac, +				    struct ieee80211_vif *vif) +{ +	struct iwl_mvm_mac_ap_iterator_data *data = _data; + +	if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc) +		return; + +	/* Station client has higher priority over P2P client*/ +	if (vif->p2p && data->beacon_device_ts) +		return; + +	data->beacon_device_ts = vif->bss_conf.sync_device_ts; +	data->beacon_int = vif->bss_conf.beacon_int; +} +  /*   * Fill the specific data for mac context of type AP of P2P GO   */ @@ -870,6 +898,11 @@ static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,  					 bool add)  {  	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); +	struct iwl_mvm_mac_ap_iterator_data data = { +		.mvm = mvm, +		.vif = vif, +		.beacon_device_ts = 0 +	};  	ctxt_ap->bi = cpu_to_le32(vif->bss_conf.beacon_int);  	ctxt_ap->bi_reciprocal = @@ -883,16 +916,33 @@ static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,  	ctxt_ap->mcast_qid = cpu_to_le32(vif->cab_queue);  	/* -	 * Only read the system time when the MAC is being added, when we +	 * Only set the beacon time when the MAC is being added, when we  	 * just modify the MAC then we should keep the time -- the firmware  	 * can otherwise have a "jumping" TBTT.  	 */ -	if (add) -		mvmvif->ap_beacon_time = -			iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG); +	if (add) { +		/* +		 * If there is a station/P2P client interface which is +		 * associated, set the AP's TBTT far enough from the station's +		 * TBTT. Otherwise, set it to the current system time +		 */ +		ieee80211_iterate_active_interfaces_atomic( +			mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, +			iwl_mvm_mac_ap_iterator, &data); + +		if (data.beacon_device_ts) { +			u32 rand = (prandom_u32() % (80 - 20)) + 20; +			mvmvif->ap_beacon_time = data.beacon_device_ts + +				ieee80211_tu_to_usec(data.beacon_int * rand / +						     100); +		} else { +			mvmvif->ap_beacon_time = +				iwl_read_prph(mvm->trans, +					      DEVICE_SYSTEM_TIME_REG); +		} +	}  	ctxt_ap->beacon_time = cpu_to_le32(mvmvif->ap_beacon_time); -  	ctxt_ap->beacon_tsf = 0; /* unused */  	/* TODO: Assume that the beacon id == mac context id */ @@ -1047,3 +1097,28 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,  		     rate);  	return 0;  } + +static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac, +					 struct ieee80211_vif *vif) +{ +	u16 *id = _data; +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + +	if (mvmvif->id == *id) +		ieee80211_beacon_loss(vif); +} + +int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, +				    struct iwl_rx_cmd_buffer *rxb, +				    struct iwl_device_cmd *cmd) +{ +	struct iwl_rx_packet *pkt = rxb_addr(rxb); +	struct iwl_missed_beacons_notif *missed_beacons = (void *)pkt->data; +	u16 id = (u16)le32_to_cpu(missed_beacons->mac_id); + +	ieee80211_iterate_active_interfaces_atomic(mvm->hw, +						   IEEE80211_IFACE_ITER_NORMAL, +						   iwl_mvm_beacon_loss_iterator, +						   &id); +	return 0; +} |