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

Commit 1d3c3f63 authored by Arik Nemtsov's avatar Arik Nemtsov Committed by Emmanuel Grumbach
Browse files

iwlwifi: mvm: implement mac80211 TDLS channel-switch APIs



Maintain a TDLS channel-switch state and update it according to
notifications from FW and timeouts. Explicitly check all state
transitions are valid.
When switching is initiated by mac80211, use a delayed work to
periodically reschedule it from iwlwifi.
Give the FW mac80211 generated TDLS channel-switch request/response
templates. It will change appropriate values (switch timings) and Tx
them at appropriate times.

Enable the channel switch wiphy capability bit when the FW supports it.

Signed-off-by: default avatarArik Nemtsov <arikx.nemtsov@intel.com>
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
parent 9c126cd6
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -466,6 +466,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
	for (i = 0; i < IWL_MVM_STATION_COUNT; i++)
		RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL);

	mvm->tdls_cs.peer.sta_id = IWL_MVM_STATION_COUNT;

	/* reset quota debouncing buffer - 0xff will yield invalid data */
	memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd));

+10 −0
Original line number Diff line number Diff line
@@ -495,6 +495,12 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
		hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
	}

	if (mvm->fw->ucode_capa.capa[0] &
	    IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH) {
		IWL_DEBUG_TDLS(mvm, "TDLS channel switch supported\n");
		hw->wiphy->features |= NL80211_FEATURE_TDLS_CHANNEL_SWITCH;
	}

	ret = ieee80211_register_hw(mvm->hw);
	if (ret)
		iwl_mvm_leds_exit(mvm);
@@ -3211,6 +3217,10 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {

	.channel_switch_beacon = iwl_mvm_channel_switch_beacon,

	.tdls_channel_switch = iwl_mvm_tdls_channel_switch,
	.tdls_cancel_channel_switch = iwl_mvm_tdls_cancel_channel_switch,
	.tdls_recv_channel_switch = iwl_mvm_tdls_recv_channel_switch,

	CFG80211_TESTMODE_CMD(iwl_mvm_mac_testmode_cmd)

#ifdef CONFIG_PM_SLEEP
+43 −0
Original line number Diff line number Diff line
@@ -519,6 +519,13 @@ enum {
#define IWL_MVM_DEBUG_SET_TEMPERATURE_MIN -100
#define IWL_MVM_DEBUG_SET_TEMPERATURE_MAX 200

enum iwl_mvm_tdls_cs_state {
	IWL_MVM_TDLS_SW_IDLE = 0,
	IWL_MVM_TDLS_SW_REQ_SENT,
	IWL_MVM_TDLS_SW_REQ_RCVD,
	IWL_MVM_TDLS_SW_ACTIVE,
};

struct iwl_mvm {
	/* for logger access */
	struct device *dev;
@@ -740,6 +747,28 @@ struct iwl_mvm {
	u32 ap_last_beacon_gp2;

	u8 low_latency_agg_frame_limit;

	/* TDLS channel switch data */
	struct {
		struct delayed_work dwork;
		enum iwl_mvm_tdls_cs_state state;

		/*
		 * Current cs sta - might be different from periodic cs peer
		 * station. Value is meaningless when the cs-state is idle.
		 */
		u8 cur_sta_id;

		/* TDLS periodic channel-switch peer */
		struct {
			u8 sta_id;
			u8 op_class;
			bool initiator; /* are we the link initiator */
			struct cfg80211_chan_def chandef;
			struct sk_buff *skb; /* ch sw template */
			u32 ch_sw_tm_ie;
		} peer;
	} tdls_cs;
};

/* Extract MVM priv from op_mode and _hw */
@@ -1258,6 +1287,20 @@ void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
			       bool sta_added);
void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
					   struct ieee80211_vif *vif);
int iwl_mvm_tdls_channel_switch(struct ieee80211_hw *hw,
				struct ieee80211_vif *vif,
				struct ieee80211_sta *sta, u8 oper_class,
				struct cfg80211_chan_def *chandef,
				struct sk_buff *tmpl_skb, u32 ch_sw_tm_ie);
void iwl_mvm_tdls_recv_channel_switch(struct ieee80211_hw *hw,
				      struct ieee80211_vif *vif,
				      struct ieee80211_tdls_ch_sw_params *params);
void iwl_mvm_tdls_cancel_channel_switch(struct ieee80211_hw *hw,
					struct ieee80211_vif *vif,
					struct ieee80211_sta *sta);
int iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
			  struct iwl_device_cmd *cmd);
void iwl_mvm_tdls_ch_switch_work(struct work_struct *work);

struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm);

+4 −0
Original line number Diff line number Diff line
@@ -258,6 +258,9 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
		   iwl_mvm_power_uapsd_misbehaving_ap_notif, false),
	RX_HANDLER(DTS_MEASUREMENT_NOTIFICATION, iwl_mvm_temp_notif, true),

	RX_HANDLER(TDLS_CHANNEL_SWITCH_NOTIFICATION, iwl_mvm_rx_tdls_notif,
		   true),

};
#undef RX_HANDLER
#define CMD(x) [x] = #x
@@ -453,6 +456,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
	INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk);
	INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work);
	INIT_WORK(&mvm->fw_error_dump_wk, iwl_mvm_fw_error_dump_wk);
	INIT_DELAYED_WORK(&mvm->tdls_cs.dwork, iwl_mvm_tdls_ch_switch_work);

	spin_lock_init(&mvm->d0i3_tx_lock);
	spin_lock_init(&mvm->refs_lock);
+9 −0
Original line number Diff line number Diff line
@@ -503,6 +503,15 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
			mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT;
	}

	/*
	 * This shouldn't happen - the TDLS channel switch should be canceled
	 * before the STA is removed.
	 */
	if (WARN_ON_ONCE(mvm->tdls_cs.peer.sta_id == mvm_sta->sta_id)) {
		mvm->tdls_cs.peer.sta_id = IWL_MVM_STATION_COUNT;
		cancel_delayed_work(&mvm->tdls_cs.dwork);
	}

	/*
	 * Make sure that the tx response code sees the station as -EBUSY and
	 * calls the drain worker.
Loading