diff options
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/time-event.c')
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | 103 | 
1 files changed, 69 insertions, 34 deletions
| diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 7fce79c1c114..1db6d8d38822 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -641,11 +641,32 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,  	}  } +static void iwl_mvm_cancel_session_protection(struct iwl_mvm *mvm, +					      struct iwl_mvm_vif *mvmvif) +{ +	struct iwl_mvm_session_prot_cmd cmd = { +		.id_and_color = +			cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, +							mvmvif->color)), +		.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), +		.conf_id = cpu_to_le32(mvmvif->time_event_data.id), +	}; +	int ret; + +	ret = iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(SESSION_PROTECTION_CMD, +						   MAC_CONF_GROUP, 0), +				   0, sizeof(cmd), &cmd); +	if (ret) +		IWL_ERR(mvm, +			"Couldn't send the SESSION_PROTECTION_CMD: %d\n", ret); +} +  static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm,  					struct iwl_mvm_time_event_data *te_data,  					u32 *uid)  {  	u32 id; +	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);  	/*  	 * It is possible that by the time we got to this point the time @@ -663,14 +684,29 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm,  	iwl_mvm_te_clear_data(mvm, te_data);  	spin_unlock_bh(&mvm->time_event_lock); -	/* -	 * It is possible that by the time we try to remove it, the time event -	 * has already ended and removed. In such a case there is no need to -	 * send a removal command. +	/* When session protection is supported, the te_data->id field +	 * is reused to save session protection's configuration.  	 */ -	if (id == TE_MAX) { -		IWL_DEBUG_TE(mvm, "TE 0x%x has already ended\n", *uid); +	if (fw_has_capa(&mvm->fw->ucode_capa, +			IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) { +		if (mvmvif && id < SESSION_PROTECT_CONF_MAX_ID) { +			/* Session protection is still ongoing. Cancel it */ +			iwl_mvm_cancel_session_protection(mvm, mvmvif); +			if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { +				set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); +				iwl_mvm_roc_finished(mvm); +			} +		}  		return false; +	} else { +		/* It is possible that by the time we try to remove it, the +		 * time event has already ended and removed. In such a case +		 * there is no need to send a removal command. +		 */ +		if (id == TE_MAX) { +			IWL_DEBUG_TE(mvm, "TE 0x%x has already ended\n", *uid); +			return false; +		}  	}  	return true; @@ -771,6 +807,7 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm,  	struct iwl_rx_packet *pkt = rxb_addr(rxb);  	struct iwl_mvm_session_prot_notif *notif = (void *)pkt->data;  	struct ieee80211_vif *vif; +	struct iwl_mvm_vif *mvmvif;  	rcu_read_lock();  	vif = iwl_mvm_rcu_dereference_vif_id(mvm, le32_to_cpu(notif->mac_id), @@ -779,9 +816,10 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm,  	if (!vif)  		goto out_unlock; +	mvmvif = iwl_mvm_vif_from_mac80211(vif); +  	/* The vif is not a P2P_DEVICE, maintain its time_event_data */  	if (vif->type != NL80211_IFTYPE_P2P_DEVICE) { -		struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);  		struct iwl_mvm_time_event_data *te_data =  			&mvmvif->time_event_data; @@ -816,10 +854,14 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm,  	if (!le32_to_cpu(notif->status) || !le32_to_cpu(notif->start)) {  		/* End TE, notify mac80211 */ +		mvmvif->time_event_data.id = SESSION_PROTECT_CONF_MAX_ID;  		ieee80211_remain_on_channel_expired(mvm->hw);  		set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status);  		iwl_mvm_roc_finished(mvm);  	} else if (le32_to_cpu(notif->start)) { +		if (WARN_ON(mvmvif->time_event_data.id != +				le32_to_cpu(notif->conf_id))) +			goto out_unlock;  		set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);  		ieee80211_ready_on_channel(mvm->hw); /* Start TE */  	} @@ -845,20 +887,24 @@ iwl_mvm_start_p2p_roc_session_protection(struct iwl_mvm *mvm,  	lockdep_assert_held(&mvm->mutex); +	/* The time_event_data.id field is reused to save session +	 * protection's configuration. +	 */  	switch (type) {  	case IEEE80211_ROC_TYPE_NORMAL: -		cmd.conf_id = -			cpu_to_le32(SESSION_PROTECT_CONF_P2P_DEVICE_DISCOV); +		mvmvif->time_event_data.id = +			SESSION_PROTECT_CONF_P2P_DEVICE_DISCOV;  		break;  	case IEEE80211_ROC_TYPE_MGMT_TX: -		cmd.conf_id = -			cpu_to_le32(SESSION_PROTECT_CONF_P2P_GO_NEGOTIATION); +		mvmvif->time_event_data.id = +			SESSION_PROTECT_CONF_P2P_GO_NEGOTIATION;  		break;  	default:  		WARN_ONCE(1, "Got an invalid ROC type\n");  		return -EINVAL;  	} +	cmd.conf_id = cpu_to_le32(mvmvif->time_event_data.id);  	return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(SESSION_PROTECTION_CMD,  						    MAC_CONF_GROUP, 0),  				    0, sizeof(cmd), &cmd); @@ -960,25 +1006,6 @@ void iwl_mvm_cleanup_roc_te(struct iwl_mvm *mvm)  		__iwl_mvm_remove_time_event(mvm, te_data, &uid);  } -static void iwl_mvm_cancel_session_protection(struct iwl_mvm *mvm, -					      struct iwl_mvm_vif *mvmvif) -{ -	struct iwl_mvm_session_prot_cmd cmd = { -		.id_and_color = -			cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, -							mvmvif->color)), -		.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), -	}; -	int ret; - -	ret = iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(SESSION_PROTECTION_CMD, -						   MAC_CONF_GROUP, 0), -				   0, sizeof(cmd), &cmd); -	if (ret) -		IWL_ERR(mvm, -			"Couldn't send the SESSION_PROTECTION_CMD: %d\n", ret); -} -  void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  {  	struct iwl_mvm_vif *mvmvif; @@ -988,10 +1015,13 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  			IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) {  		mvmvif = iwl_mvm_vif_from_mac80211(vif); -		iwl_mvm_cancel_session_protection(mvm, mvmvif); - -		if (vif->type == NL80211_IFTYPE_P2P_DEVICE) +		if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { +			iwl_mvm_cancel_session_protection(mvm, mvmvif);  			set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); +		} else { +			iwl_mvm_remove_aux_roc_te(mvm, mvmvif, +						  &mvmvif->time_event_data); +		}  		iwl_mvm_roc_finished(mvm); @@ -1126,10 +1156,15 @@ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm,  			cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,  							mvmvif->color)),  		.action = cpu_to_le32(FW_CTXT_ACTION_ADD), -		.conf_id = cpu_to_le32(SESSION_PROTECT_CONF_ASSOC),  		.duration_tu = cpu_to_le32(MSEC_TO_TU(duration)),  	}; +	/* The time_event_data.id field is reused to save session +	 * protection's configuration. +	 */ +	mvmvif->time_event_data.id = SESSION_PROTECT_CONF_ASSOC; +	cmd.conf_id = cpu_to_le32(mvmvif->time_event_data.id); +  	lockdep_assert_held(&mvm->mutex);  	spin_lock_bh(&mvm->time_event_lock); | 
