Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 74a10252 authored by Sara Sharon's avatar Sara Sharon Committed by Luca Coelho
Browse files

iwlwifi: mvm: support CHANNEL_SWITCH_TIME_EVENT_CMD command



When we do channel switch, we used to schedule time events
ourselves. This was offloaded to FW. Support the new command
and flow.

Signed-off-by: default avatarSara Sharon <sara.sharon@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent b2c1bf59
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -73,6 +73,10 @@ enum iwl_mac_conf_subcmd_ids {
	 * @LOW_LATENCY_CMD: &struct iwl_mac_low_latency_cmd
	 */
	LOW_LATENCY_CMD = 0x3,
	/**
	 * @CHANNEL_SWITCH_TIME_EVENT_CMD: &struct iwl_chan_switch_te_cmd
	 */
	CHANNEL_SWITCH_TIME_EVENT_CMD = 0x4,
	/**
	 * @PROBE_RESPONSE_DATA_NOTIF: &struct iwl_probe_resp_data_notif
	 */
@@ -135,6 +139,29 @@ struct iwl_channel_switch_noa_notif {
	__le32 id_and_color;
} __packed; /* CHANNEL_SWITCH_START_NTFY_API_S_VER_1 */

/**
 * struct iwl_chan_switch_te_cmd - Channel Switch Time Event command
 *
 * @mac_id: MAC ID for channel switch
 * @action: action to perform, one of FW_CTXT_ACTION_*
 * @tsf: beacon tsf
 * @cs_count: channel switch count from CSA/eCSA IE
 * @cs_delayed_bcn_count: if set to N (!= 0) GO/AP can delay N beacon intervals
 *	at the new channel after the channel switch, otherwise (N == 0) expect
 *	beacon right after the channel switch.
 * @cs_mode: 1 - quiet, 0 - otherwise
 * @reserved: reserved for alignment purposes
 */
struct iwl_chan_switch_te_cmd {
	__le32 mac_id;
	__le32 action;
	__le32 tsf;
	u8 cs_count;
	u8 cs_delayed_bcn_count;
	u8 cs_mode;
	u8 reserved;
} __packed; /* MAC_CHANNEL_SWITCH_TIME_EVENT_S_VER_2 */

/**
 * struct iwl_mac_low_latency_cmd - set/clear mac to 'low-latency mode'
 *
+2 −0
Original line number Diff line number Diff line
@@ -333,6 +333,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t;
 * @IWL_UCODE_TLV_CAPA_TLC_OFFLOAD: firmware implements rate scaling algorithm
 * @IWL_UCODE_TLV_CAPA_DYNAMIC_QUOTA: firmware implements quota related
 * @IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2: firmware implements Coex Schema 2
 * IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD: firmware supports CSA command
 * @IWL_UCODE_TLV_CAPA_ULTRA_HB_CHANNELS: firmware supports ultra high band
 *	(6 GHz).
 * @IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement
@@ -397,6 +398,7 @@ enum iwl_ucode_tlv_capa {
	IWL_UCODE_TLV_CAPA_TLC_OFFLOAD                  = (__force iwl_ucode_tlv_capa_t)43,
	IWL_UCODE_TLV_CAPA_DYNAMIC_QUOTA                = (__force iwl_ucode_tlv_capa_t)44,
	IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2		= (__force iwl_ucode_tlv_capa_t)45,
	IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD		= (__force iwl_ucode_tlv_capa_t)46,
	IWL_UCODE_TLV_CAPA_ULTRA_HB_CHANNELS		= (__force iwl_ucode_tlv_capa_t)48,
	IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE		= (__force iwl_ucode_tlv_capa_t)64,
	IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS		= (__force iwl_ucode_tlv_capa_t)65,
+37 −21
Original line number Diff line number Diff line
@@ -1539,26 +1539,35 @@ void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm,
{
	struct iwl_rx_packet *pkt = rxb_addr(rxb);
	struct iwl_channel_switch_noa_notif *notif = (void *)pkt->data;
	struct ieee80211_vif *csa_vif;
	struct ieee80211_vif *csa_vif, *vif;
	struct iwl_mvm_vif *mvmvif;
	int len = iwl_rx_packet_payload_len(pkt);
	u32 id_n_color;
	u32 id_n_color, csa_id, mac_id;

	if (WARN_ON_ONCE(len < sizeof(*notif)))
		return;

	id_n_color = le32_to_cpu(notif->id_and_color);
	mac_id = id_n_color & FW_CTXT_ID_MSK;

	if (WARN_ON_ONCE(mac_id >= NUM_MAC_INDEX_DRIVER))
		return;

	rcu_read_lock();
	vif = rcu_dereference(mvm->vif_id_to_mac[mac_id]);

	switch (vif->type) {
	case NL80211_IFTYPE_AP:
		csa_vif = rcu_dereference(mvm->csa_vif);
	if (WARN_ON(!csa_vif || !csa_vif->csa_active))
		if (WARN_ON(!csa_vif || !csa_vif->csa_active ||
			    csa_vif != vif))
			goto out_unlock;

	id_n_color = le32_to_cpu(notif->id_and_color);

		mvmvif = iwl_mvm_vif_from_mac80211(csa_vif);
	if (WARN(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color) != id_n_color,
		csa_id = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color);
		if (WARN(csa_id != id_n_color,
			 "channel switch noa notification on unexpected vif (csa_vif=%d, notif=%d)",
		 FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color), id_n_color))
			 csa_id, id_n_color))
			goto out_unlock;

		IWL_DEBUG_INFO(mvm, "Channel Switch Started Notification\n");
@@ -1572,9 +1581,16 @@ void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm,
		rcu_read_unlock();

		RCU_INIT_POINTER(mvm->csa_vif, NULL);

		return;

	case NL80211_IFTYPE_STATION:
		iwl_mvm_csa_client_absent(mvm, vif);
		ieee80211_chswitch_done(vif, true);
		break;
	default:
		/* should never happen */
		WARN_ON_ONCE(1);
		break;
	}
out_unlock:
	rcu_read_unlock();
}
+52 −19
Original line number Diff line number Diff line
@@ -3953,8 +3953,13 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
	}

	if (switching_chanctx && vif->type == NL80211_IFTYPE_STATION) {
		mvmvif->csa_bcn_pending = true;

		if (!fw_has_capa(&mvm->fw->ucode_capa,
				 IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD)) {
			u32 duration = 3 * vif->bss_conf.beacon_int;


			/* iwl_mvm_protect_session() reads directly from the
			 * device (the system time), so make sure it is
			 * available.
@@ -3966,12 +3971,12 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
			/* Protect the session to make sure we hear the first
			 * beacon on the new channel.
			 */
		mvmvif->csa_bcn_pending = true;
			iwl_mvm_protect_session(mvm, vif, duration, duration,
						vif->bss_conf.beacon_int / 2,
						true);

			iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_CSA);
		}

		iwl_mvm_update_quotas(mvm, false, NULL);
	}
@@ -4041,6 +4046,8 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm,

		disabled_vif = vif;

		if (!fw_has_capa(&mvm->fw->ucode_capa,
				 IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD))
			iwl_mvm_mac_ctxt_changed(mvm, vif, true, NULL);
		break;
	default:
@@ -4292,6 +4299,27 @@ static void iwl_mvm_channel_switch(struct ieee80211_hw *hw,
			   "dummy channel switch op\n");
}

static int iwl_mvm_schedule_client_csa(struct iwl_mvm *mvm,
				       struct ieee80211_vif *vif,
				       struct ieee80211_channel_switch *chsw)
{
	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
	struct iwl_chan_switch_te_cmd cmd = {
		.mac_id = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
							  mvmvif->color)),
		.action = cpu_to_le32(FW_CTXT_ACTION_ADD),
		.tsf = cpu_to_le32(chsw->timestamp),
		.cs_count = chsw->count,
	};

	lockdep_assert_held(&mvm->mutex);

	return iwl_mvm_send_cmd_pdu(mvm,
				    WIDE_ID(MAC_CONF_GROUP,
					    CHANNEL_SWITCH_TIME_EVENT_CMD),
				    0, sizeof(cmd), &cmd);
}

static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
				      struct ieee80211_vif *vif,
				      struct ieee80211_channel_switch *chsw)
@@ -4359,14 +4387,19 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
		if (chsw->block_tx)
			iwl_mvm_csa_client_absent(mvm, vif);

		iwl_mvm_schedule_csa_period(mvm, vif, vif->bss_conf.beacon_int,
					    apply_time);
		if (mvmvif->bf_data.bf_enabled) {
			ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0);
			if (ret)
				goto out_unlock;
		}

		if (fw_has_capa(&mvm->fw->ucode_capa,
				IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD))
			iwl_mvm_schedule_client_csa(mvm, vif, chsw);
		else
			iwl_mvm_schedule_csa_period(mvm, vif,
						    vif->bss_conf.beacon_int,
						    apply_time);
		break;
	default:
		break;
+1 −0
Original line number Diff line number Diff line
@@ -421,6 +421,7 @@ static const struct iwl_hcmd_names iwl_mvm_system_names[] = {
 * Access is done through binary search
 */
static const struct iwl_hcmd_names iwl_mvm_mac_conf_names[] = {
	HCMD_NAME(CHANNEL_SWITCH_TIME_EVENT_CMD),
	HCMD_NAME(CHANNEL_SWITCH_NOA_NOTIF),
};