Commit fe8b2ad3 authored by Miri Korenblit's avatar Miri Korenblit Committed by Johannes Berg
Browse files

wifi: iwlwifi: mvm: add cancel/remain_on_channel for MLD mode

parent feebebae
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -491,11 +491,14 @@ struct iwl_link_config_cmd {
 * @STATION_TYPE_MCAST: the station used for BCAST / MCAST in GO. Will be
 *	suspended / resumed at the right timing depending on the clients'
 *	power save state and the DTIM timing
 * @STATION_TYPE_AUX: aux sta. In the FW there is no need for a special type
 *	for the aux sta, so this type is only for driver - internal use.
 */
enum iwl_fw_sta_type {
	STATION_TYPE_PEER,
	STATION_TYPE_BCAST_MGMT,
	STATION_TYPE_MCAST,
	STATION_TYPE_AUX,
}; /* STATION_TYPE_E_VER_1 */

/**
+19 −5
Original line number Diff line number Diff line
@@ -4309,6 +4309,20 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
		       struct ieee80211_channel *channel,
		       int duration,
		       enum ieee80211_roc_type type)
{
	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,
	};

	return iwl_mvm_roc_common(hw, vif, channel, duration, type, &ops);
}

/* Execute the common part for MLD and non-MLD modes */
int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
		       struct ieee80211_channel *channel, int duration,
		       enum ieee80211_roc_type type,
		       struct iwl_mvm_roc_ops *ops)
{
	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -4334,7 +4348,7 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
		lmac_id = iwl_mvm_get_lmac_id(mvm->fw, channel->band);

		/* Use aux roc framework (HS20) */
		ret = iwl_mvm_add_aux_sta_for_hs20(mvm, lmac_id);
		ret = ops->add_aux_sta_for_hs20(mvm, lmac_id);
		if (!ret)
			ret = iwl_mvm_send_aux_roc_cmd(mvm, channel,
						       vif, duration);
@@ -4354,7 +4368,7 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
			continue;

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

@@ -4408,7 +4422,7 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
			goto out_unlock;
		}

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

@@ -4425,7 +4439,7 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
	return ret;
}

static int iwl_mvm_cancel_roc(struct ieee80211_hw *hw,
int iwl_mvm_cancel_roc(struct ieee80211_hw *hw,
		       struct ieee80211_vif *vif)
{
	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+43 −0
Original line number Diff line number Diff line
@@ -592,10 +592,53 @@ 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)
{
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
	int ret = 0;

	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, 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;

	ret = iwl_mvm_link_changed(mvm, vif, 0, false);
	if (WARN(ret, "Failed to deactivate link\n"))
		return ret;

	ret = iwl_mvm_link_changed(mvm, vif, LINK_CONTEXT_MODIFY_ACTIVE, true);
	WARN(ret, "Failed binding P2P_DEVICE\n");
	return ret;
}

static int iwl_mvm_mld_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
			   struct ieee80211_channel *channel, int duration,
			   enum ieee80211_roc_type type)
{
	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,
	};

	return iwl_mvm_roc_common(hw, vif, channel, duration, type, &ops);
}
const struct ieee80211_ops iwl_mvm_mld_hw_ops = {
	.add_interface = iwl_mvm_mld_mac_add_interface,
	.remove_interface = iwl_mvm_mld_mac_remove_interface,
	.config_iface_filter = iwl_mvm_mld_config_iface_filter,
	.remain_on_channel = iwl_mvm_mld_roc,
	.cancel_remain_on_channel = iwl_mvm_cancel_roc,
	.assign_vif_chanctx = iwl_mvm_mld_assign_vif_chanctx,
	.unassign_vif_chanctx = iwl_mvm_mld_unassign_vif_chanctx,
	.switch_vif_chanctx = iwl_mvm_mld_switch_vif_chanctx,
+43 −1
Original line number Diff line number Diff line
@@ -75,6 +75,24 @@ static int iwl_mvm_mld_rm_sta_from_fw(struct iwl_mvm *mvm, u32 sta_id)
	return 0;
}

static int iwl_mvm_add_aux_sta_to_fw(struct iwl_mvm *mvm,
				     struct iwl_mvm_int_sta *sta,
				     u32 lmac_id)
{
	int ret;

	struct iwl_mvm_aux_sta_cmd cmd = {
		.sta_id = cpu_to_le32(sta->sta_id),
		.lmac_id = cpu_to_le32(lmac_id),
	};

	ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(MAC_CONF_GROUP, AUX_STA_CMD),
				   0, sizeof(cmd), &cmd);
	if (ret)
		IWL_ERR(mvm, "Failed to send AUX_STA_CMD\n");
	return ret;
}

/*
 * Adds an internal sta to the FW table with its queues
 */
@@ -91,6 +109,9 @@ static int iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm *mvm,
	if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_INVALID_STA))
		return -ENOSPC;

	if (sta->type == STATION_TYPE_AUX)
		ret = iwl_mvm_add_aux_sta_to_fw(mvm, sta, phy_id);
	else
		ret = iwl_mvm_mld_add_int_sta_to_fw(mvm, sta, addr, phy_id);
	if (ret)
		return ret;
@@ -224,6 +245,19 @@ int iwl_mvm_mld_add_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
				       IWL_MAX_TID_COUNT, NULL);
}

int iwl_mvm_mld_add_aux_sta(struct iwl_mvm *mvm, u32 lmac_id)
{
	lockdep_assert_held(&mvm->mutex);

	/* In CDB NICs we need to specify which lmac to use for aux activity
	 * using the phy_id argument place to send lmac_id to the function
	 */
	return iwl_mvm_mld_add_int_sta(mvm, &mvm->aux_sta, &mvm->aux_queue,
				       NL80211_IFTYPE_UNSPECIFIED,
				       STATION_TYPE_AUX, lmac_id, NULL,
				       IWL_MAX_TID_COUNT, NULL);
}

static int iwl_mvm_mld_disable_txq(struct iwl_mvm *mvm,
				   struct ieee80211_sta *sta,
				   u16 *queueptr, u8 tid)
@@ -332,6 +366,14 @@ int iwl_mvm_mld_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
				      IWL_MAX_TID_COUNT, &mvm->snif_queue);
}

int iwl_mvm_mld_rm_aux_sta(struct iwl_mvm *mvm)
{
	lockdep_assert_held(&mvm->mutex);

	return iwl_mvm_mld_rm_int_sta(mvm, &mvm->aux_sta, false,
				      IWL_MAX_TID_COUNT, &mvm->aux_queue);
}

/* send a cfg sta command to add/update a sta in firmware */
static int iwl_mvm_mld_cfg_sta(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
			       struct ieee80211_vif *vif, u16 phy_id)
+26 −0
Original line number Diff line number Diff line
@@ -1827,6 +1827,32 @@ void iwl_mvm_bss_info_changed_station_assoc(struct iwl_mvm *mvm,
					    struct ieee80211_vif *vif,
					    u64 changes);

/* ROC */
/**
 * struct iwl_mvm_roc_ops - callbacks for the remain_on_channel()
 *
 * Since the only difference between both MLD and
 * non-MLD versions of remain_on_channel() is these function calls,
 * each version will send its specific function calls to
 * %iwl_mvm_roc_common().
 *
 * @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
 */
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 iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
		       struct ieee80211_channel *channel, int duration,
		       enum ieee80211_roc_type type,
		       struct iwl_mvm_roc_ops *ops);
int iwl_mvm_cancel_roc(struct ieee80211_hw *hw,
		       struct ieee80211_vif *vif);
/*Session Protection */
void iwl_mvm_protect_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
			   u32 duration_override);
Loading