Commit 84ef7cbe authored by Ilan Peer's avatar Ilan Peer Committed by Johannes Berg
Browse files

wifi: iwlwifi: mvm: Don't always bind/link the P2P Device interface



It is not necessary to keep the P2P Device bound/linked to a PHY
context when there is no active ROC.

Modify the P2P Device flows so the binding/linking would be done
only while ROC is active. With this change the switch_phy_ctxt()
is no longer needed so remove it.

Signed-off-by: default avatarIlan Peer <ilan.peer@intel.com>
Signed-off-by: default avatarGregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20231004123422.c5b83b4bf9de.Ia80daf3ba0b5fec7d0919247fcbdbdb58bddf02b@changeid


Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 706f1b5d
Loading
Loading
Loading
Loading
+2 −7
Original line number Diff line number Diff line
@@ -53,7 +53,6 @@ int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
	unsigned int link_id = link_conf->link_id;
	struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id];
	struct iwl_link_config_cmd cmd = {};
	struct iwl_mvm_phy_ctxt *phyctxt;

	if (WARN_ON_ONCE(!link_info))
		return -EINVAL;
@@ -77,11 +76,7 @@ int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
	cmd.link_id = cpu_to_le32(link_info->fw_link_id);
	cmd.mac_id = cpu_to_le32(mvmvif->id);
	cmd.spec_link_id = link_conf->link_id;
	/* P2P-Device already has a valid PHY context during add */
	phyctxt = link_info->phy_ctxt;
	if (phyctxt)
		cmd.phy_id = cpu_to_le32(phyctxt->id);
	else
	WARN_ON_ONCE(link_info->phy_ctxt);
	cmd.phy_id = cpu_to_le32(FW_CTXT_INVALID);

	memcpy(cmd.local_link_addr, link_conf->addr, ETH_ALEN);
+4 −4
Original line number Diff line number Diff line
@@ -286,6 +286,10 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
	INIT_LIST_HEAD(&mvmvif->time_event_data.list);
	mvmvif->time_event_data.id = TE_MAX;

	mvmvif->deflink.bcast_sta.sta_id = IWL_MVM_INVALID_STA;
	mvmvif->deflink.mcast_sta.sta_id = IWL_MVM_INVALID_STA;
	mvmvif->deflink.ap_sta_id = IWL_MVM_INVALID_STA;

	/* No need to allocate data queues to P2P Device MAC and NAN.*/
	if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
		return 0;
@@ -300,10 +304,6 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
		mvmvif->deflink.cab_queue = IWL_MVM_DQA_GCAST_QUEUE;
	}

	mvmvif->deflink.bcast_sta.sta_id = IWL_MVM_INVALID_STA;
	mvmvif->deflink.mcast_sta.sta_id = IWL_MVM_INVALID_STA;
	mvmvif->deflink.ap_sta_id = IWL_MVM_INVALID_STA;

	for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++)
		mvmvif->deflink.smps_requests[i] = IEEE80211_SMPS_AUTOMATIC;

+48 −104
Original line number Diff line number Diff line
@@ -1607,32 +1607,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
				     IEEE80211_VIF_SUPPORTS_CQM_RSSI;
	}

	/*
	 * P2P_DEVICE interface does not have a channel context assigned to it,
	 * so a dedicated PHY context is allocated to it and the corresponding
	 * MAC context is bound to it at this stage.
	 */
	if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {

		mvmvif->deflink.phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm);
		if (!mvmvif->deflink.phy_ctxt) {
			ret = -ENOSPC;
			goto out_free_bf;
		}

		iwl_mvm_phy_ctxt_ref(mvm, mvmvif->deflink.phy_ctxt);
		ret = iwl_mvm_binding_add_vif(mvm, vif);
		if (ret)
			goto out_unref_phy;

		ret = iwl_mvm_add_p2p_bcast_sta(mvm, vif);
		if (ret)
			goto out_unbind;

		/* Save a pointer to p2p device vif, so it can later be used to
		 * update the p2p device MAC when a GO is started/stopped */
	if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
		mvm->p2p_device_vif = vif;
	}

	iwl_mvm_tcm_add_vif(mvm, vif);
	INIT_DELAYED_WORK(&mvmvif->csa_work,
@@ -1661,11 +1637,6 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,

	goto out_unlock;

 out_unbind:
	iwl_mvm_binding_remove_vif(mvm, vif);
 out_unref_phy:
	iwl_mvm_phy_ctxt_unref(mvm, mvmvif->deflink.phy_ctxt);
 out_free_bf:
	if (mvm->bf_allowed_vif == mvmvif) {
		mvm->bf_allowed_vif = NULL;
		vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER |
@@ -1762,13 +1733,18 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
	if (iwl_mvm_mac_remove_interface_common(hw, vif))
		goto out;

	/* Before the interface removal, mac80211 would cancel the ROC, and the
	 * ROC worker would be scheduled if needed. The worker would be flushed
	 * in iwl_mvm_prepare_mac_removal() and thus at this point there is no
	 * binding etc. so nothing needs to be done here.
	 */
	if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
		mvm->p2p_device_vif = NULL;
		iwl_mvm_rm_p2p_bcast_sta(mvm, vif);
		iwl_mvm_binding_remove_vif(mvm, vif);
		if (mvmvif->deflink.phy_ctxt) {
			iwl_mvm_phy_ctxt_unref(mvm, mvmvif->deflink.phy_ctxt);
			mvmvif->deflink.phy_ctxt = NULL;
		}
		mvm->p2p_device_vif = NULL;
	}

	iwl_mvm_mac_ctxt_remove(mvm, vif);

@@ -4576,30 +4552,20 @@ static int iwl_mvm_add_aux_sta_for_hs20(struct iwl_mvm *mvm, u32 lmac_id)
	return ret;
}

static int iwl_mvm_roc_switch_binding(struct iwl_mvm *mvm,
				      struct ieee80211_vif *vif,
				      struct iwl_mvm_phy_ctxt *new_phy_ctxt)
static int iwl_mvm_roc_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
	int ret = 0;
	int ret;

	lockdep_assert_held(&mvm->mutex);

	/* Unbind the P2P_DEVICE from the current PHY context,
	 * and if the PHY context is not used remove it.
	 */
	ret = iwl_mvm_binding_remove_vif(mvm, vif);
	if (WARN(ret, "Failed unbinding P2P_DEVICE\n"))
		return ret;

	iwl_mvm_phy_ctxt_unref(mvm, mvmvif->deflink.phy_ctxt);

	/* Bind the P2P_DEVICE to the current PHY Context */
	mvmvif->deflink.phy_ctxt = new_phy_ctxt;

	ret = iwl_mvm_binding_add_vif(mvm, vif);
	WARN(ret, "Failed binding P2P_DEVICE\n");
	if (WARN(ret, "Failed binding P2P_DEVICE\n"))
		return ret;

	/* The station and queue allocation must be done only after the binding
	 * is done, as otherwise the FW might incorrectly configure its state.
	 */
	return iwl_mvm_add_p2p_bcast_sta(mvm, vif);
}

static int iwl_mvm_roc(struct ieee80211_hw *hw,
@@ -4610,7 +4576,7 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
{
	static const struct iwl_mvm_roc_ops ops = {
		.add_aux_sta_for_hs20 = iwl_mvm_add_aux_sta_for_hs20,
		.switch_phy_ctxt = iwl_mvm_roc_switch_binding,
		.link = iwl_mvm_roc_link,
	};

	return iwl_mvm_roc_common(hw, vif, channel, duration, type, &ops);
@@ -4626,7 +4592,6 @@ int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
	struct cfg80211_chan_def chandef;
	struct iwl_mvm_phy_ctxt *phy_ctxt;
	bool band_change_removal;
	int ret, i;
	u32 lmac_id;

@@ -4655,64 +4620,48 @@ int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
		/* handle below */
		break;
	default:
		IWL_ERR(mvm, "vif isn't P2P_DEVICE: %d\n", vif->type);
		IWL_ERR(mvm, "ROC: Invalid vif type=%u\n", vif->type);
		ret = -EINVAL;
		goto out_unlock;
	}

	/* Try using a PHY context that is already in use */
	for (i = 0; i < NUM_PHY_CTX; i++) {
		phy_ctxt = &mvm->phy_ctxts[i];
		if (phy_ctxt->ref == 0 || mvmvif->deflink.phy_ctxt == phy_ctxt)
		if (!phy_ctxt->ref || mvmvif->deflink.phy_ctxt == phy_ctxt)
			continue;

		if (phy_ctxt->ref && channel == phy_ctxt->channel) {
			ret = ops->switch_phy_ctxt(mvm, vif, phy_ctxt);
			if (ret)
				goto out_unlock;
		if (channel == phy_ctxt->channel) {
			if (mvmvif->deflink.phy_ctxt)
				iwl_mvm_phy_ctxt_unref(mvm,
						       mvmvif->deflink.phy_ctxt);

			mvmvif->deflink.phy_ctxt = phy_ctxt;
			iwl_mvm_phy_ctxt_ref(mvm, mvmvif->deflink.phy_ctxt);
			goto schedule_time_event;
			goto link_and_start_p2p_roc;
		}
	}

	/* Need to update the PHY context only if the ROC channel changed */
	if (channel == mvmvif->deflink.phy_ctxt->channel)
		goto schedule_time_event;

	cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT);

	/*
	 * Check if the remain-on-channel is on a different band and that
	 * requires context removal, see iwl_mvm_phy_ctxt_changed(). If
	 * so, we'll need to release and then re-configure here, since we
	 * must not remove a PHY context that's part of a binding.
	 */
	band_change_removal =
		fw_has_capa(&mvm->fw->ucode_capa,
			    IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT) &&
		mvmvif->deflink.phy_ctxt->channel->band != chandef.chan->band;

	if (mvmvif->deflink.phy_ctxt->ref == 1 && !band_change_removal) {
		/*
		 * Change the PHY context configuration as it is currently
		 * referenced only by the P2P Device MAC (and we can modify it)
	/* If the currently used PHY context is configured with a matching
	 * channel use it
	 */
		ret = iwl_mvm_phy_ctxt_changed(mvm, mvmvif->deflink.phy_ctxt,
					       &chandef, 1, 1);
		if (ret)
			goto out_unlock;
	if (mvmvif->deflink.phy_ctxt) {
		if (channel == mvmvif->deflink.phy_ctxt->channel)
			goto link_and_start_p2p_roc;
	} else {
		/*
		 * The PHY context is shared with other MACs (or we're trying to
		 * switch bands), so remove the P2P Device from the binding,
		 * allocate an new PHY context and create a new binding.
		 */
		phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm);
		if (!phy_ctxt) {
			ret = -ENOSPC;
			goto out_unlock;
		}

		mvmvif->deflink.phy_ctxt = phy_ctxt;
		iwl_mvm_phy_ctxt_ref(mvm, mvmvif->deflink.phy_ctxt);
	}

	/* Configure the PHY context */
	cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT);

	ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chandef,
				       1, 1);
	if (ret) {
@@ -4720,17 +4669,12 @@ int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
		goto out_unlock;
	}

		ret = ops->switch_phy_ctxt(mvm, vif, phy_ctxt);
link_and_start_p2p_roc:
	ret = ops->link(mvm, vif);
	if (ret)
		goto out_unlock;

		iwl_mvm_phy_ctxt_ref(mvm, mvmvif->deflink.phy_ctxt);
	}

schedule_time_event:
	/* Schedule the time events */
	ret = iwl_mvm_start_p2p_roc(mvm, vif, duration, type);

out_unlock:
	mutex_unlock(&mvm->mutex);
	IWL_DEBUG_MAC80211(mvm, "leave\n");
+32 −68
Original line number Diff line number Diff line
@@ -56,43 +56,15 @@ static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw,
				     IEEE80211_VIF_SUPPORTS_CQM_RSSI;
	}

	/*
	 * P2P_DEVICE interface does not have a channel context assigned to it,
	 * so a dedicated PHY context is allocated to it and the corresponding
	 * MAC context is bound to it at this stage.
	 */
	if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
		mvmvif->deflink.phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm);
		if (!mvmvif->deflink.phy_ctxt) {
			ret = -ENOSPC;
			goto out_free_bf;
		}

		iwl_mvm_phy_ctxt_ref(mvm, mvmvif->deflink.phy_ctxt);
	ret = iwl_mvm_add_link(mvm, vif, &vif->bss_conf);
	if (ret)
			goto out_unref_phy;

		ret = iwl_mvm_link_changed(mvm, vif, &vif->bss_conf,
					   LINK_CONTEXT_MODIFY_ACTIVE |
					   LINK_CONTEXT_MODIFY_RATES_INFO,
					   true);
		if (ret)
			goto out_remove_link;

		ret = iwl_mvm_mld_add_bcast_sta(mvm, vif, &vif->bss_conf);
		if (ret)
			goto out_remove_link;
		goto out_free_bf;

	/* Save a pointer to p2p device vif, so it can later be used to
	 * update the p2p device MAC when a GO is started/stopped
	 */
	if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
		mvm->p2p_device_vif = vif;
	} else {
		ret = iwl_mvm_add_link(mvm, vif, &vif->bss_conf);
		if (ret)
			goto out_free_bf;
	}

	ret = iwl_mvm_power_update_mac(mvm);
	if (ret)
@@ -119,10 +91,6 @@ static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw,

	goto out_unlock;

 out_remove_link:
	iwl_mvm_disable_link(mvm, vif, &vif->bss_conf);
 out_unref_phy:
	iwl_mvm_phy_ctxt_unref(mvm, mvmvif->deflink.phy_ctxt);
 out_free_bf:
	if (mvm->bf_allowed_vif == mvmvif) {
		mvm->bf_allowed_vif = NULL;
@@ -130,7 +98,6 @@ static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw,
				       IEEE80211_VIF_SUPPORTS_CQM_RSSI);
	}
 out_remove_mac:
	mvmvif->deflink.phy_ctxt = NULL;
	mvmvif->link[0] = NULL;
	iwl_mvm_mld_mac_ctxt_remove(mvm, vif);
 out_unlock:
@@ -185,14 +152,18 @@ static void iwl_mvm_mld_mac_remove_interface(struct ieee80211_hw *hw,

	iwl_mvm_power_update_mac(mvm);

	/* Before the interface removal, mac80211 would cancel the ROC, and the
	 * ROC worker would be scheduled if needed. The worker would be flushed
	 * in iwl_mvm_prepare_mac_removal() and thus at this point the link is
	 * not active. So need only to remove the link.
	 */
	if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
		mvm->p2p_device_vif = NULL;

		/* P2P device uses only one link */
		iwl_mvm_mld_rm_bcast_sta(mvm, vif, &vif->bss_conf);
		iwl_mvm_disable_link(mvm, vif, &vif->bss_conf);
		if (mvmvif->deflink.phy_ctxt) {
			iwl_mvm_phy_ctxt_unref(mvm, mvmvif->deflink.phy_ctxt);
			mvmvif->deflink.phy_ctxt = NULL;
		}
		mvm->p2p_device_vif = NULL;
		iwl_mvm_remove_link(mvm, vif, &vif->bss_conf);
	} else {
		iwl_mvm_disable_link(mvm, vif, &vif->bss_conf);
	}
@@ -1091,36 +1062,29 @@ iwl_mvm_mld_mac_conf_tx(struct ieee80211_hw *hw,
	return 0;
}

static int iwl_mvm_link_switch_phy_ctx(struct iwl_mvm *mvm,
				       struct ieee80211_vif *vif,
				       struct iwl_mvm_phy_ctxt *new_phy_ctxt)
static int iwl_mvm_mld_roc_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
	int ret = 0;
	int ret;

	lockdep_assert_held(&mvm->mutex);

	/* Inorder to change the phy_ctx of a link, the link needs to be
	 * inactive. Therefore, first deactivate the link, then change its
	 * phy_ctx, and then activate it again.
	 */
	ret = iwl_mvm_link_changed(mvm, vif, &vif->bss_conf,
				   LINK_CONTEXT_MODIFY_ACTIVE, false);
	if (WARN(ret, "Failed to deactivate link\n"))
		return ret;

	iwl_mvm_phy_ctxt_unref(mvm, mvmvif->deflink.phy_ctxt);

	mvmvif->deflink.phy_ctxt = new_phy_ctxt;

	/* The PHY context ID might have changed so need to set it */
	ret = iwl_mvm_link_changed(mvm, vif, &vif->bss_conf, 0, false);
	if (WARN(ret, "Failed to deactivate link\n"))
	if (WARN(ret, "Failed to set PHY context ID\n"))
		return ret;

	ret = iwl_mvm_link_changed(mvm, vif, &vif->bss_conf,
				   LINK_CONTEXT_MODIFY_ACTIVE, true);
	WARN(ret, "Failed binding P2P_DEVICE\n");
				   LINK_CONTEXT_MODIFY_ACTIVE |
				   LINK_CONTEXT_MODIFY_RATES_INFO,
				   true);

	if (WARN(ret, "Failed linking P2P_DEVICE\n"))
		return ret;

	/* The station and queue allocation must be done only after the linking
	 * is done, as otherwise the FW might incorrectly configure its state.
	 */
	return iwl_mvm_mld_add_bcast_sta(mvm, vif, &vif->bss_conf);
}

static int iwl_mvm_mld_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
@@ -1129,7 +1093,7 @@ static int iwl_mvm_mld_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
{
	static const struct iwl_mvm_roc_ops ops = {
		.add_aux_sta_for_hs20 = iwl_mvm_mld_add_aux_sta,
		.switch_phy_ctxt = iwl_mvm_link_switch_phy_ctx,
		.link = iwl_mvm_mld_roc_link,
	};

	return iwl_mvm_roc_common(hw, vif, channel, duration, type, &ops);
+3 −4
Original line number Diff line number Diff line
@@ -1971,13 +1971,12 @@ void iwl_mvm_bss_info_changed_station_assoc(struct iwl_mvm *mvm,
 *
 * @add_aux_sta_for_hs20: pointer to the function that adds an aux sta
 *	for Hot Spot 2.0
 * @switch_phy_ctxt: pointer to the function that switches a vif from one
 *	phy_ctx to another
 * @link: For a P2P Device interface, pointer to a function that links the
 *      MAC/Link to the PHY context
 */
struct iwl_mvm_roc_ops {
	int (*add_aux_sta_for_hs20)(struct iwl_mvm *mvm, u32 lmac_id);
	int (*switch_phy_ctxt)(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
			       struct iwl_mvm_phy_ctxt *new_phy_ctxt);
	int (*link)(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
};

int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
Loading