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

Commit 65e25482 authored by Johannes Berg's avatar Johannes Berg Committed by Luca Coelho
Browse files

iwlwifi: mvm: use firmware station PM notification for AP_LINK_PS



When using RSS on 9000 series devices, we can't rely on processing the
received frames for station powersave handling, since they could be
processed on different CPUs and out of order.

In order to still manage the powersave of stations, the firmware sends
a notification on sleep->wake, wake->sleep and - for U-APSD - frames
received with PM while already sleeping (with the TID.)

With this, the driver can set AP_LINK_PS, which is required for real
parallel RX. In addition, this requires checking for PS-Poll frames
and calling ieee80211_sta_pspoll() appropriately.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent ad5de737
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -293,6 +293,7 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;
 *	is supported.
 * @IWL_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC
 * @IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT: supports gscan
 * @IWL_UCODE_TLV_CAPA_STA_PM_NOTIF: firmware will send STA PM notification
 * @IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement
 * @IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS: supports short PM timeouts
 * @IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT
@@ -342,6 +343,7 @@ enum iwl_ucode_tlv_capa {
	IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC		= (__force iwl_ucode_tlv_capa_t)29,
	IWL_UCODE_TLV_CAPA_BT_COEX_RRC			= (__force iwl_ucode_tlv_capa_t)30,
	IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT		= (__force iwl_ucode_tlv_capa_t)31,
	IWL_UCODE_TLV_CAPA_STA_PM_NOTIF			= (__force iwl_ucode_tlv_capa_t)38,
	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,
	IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT		= (__force iwl_ucode_tlv_capa_t)67,
+26 −0
Original line number Diff line number Diff line
@@ -474,4 +474,30 @@ struct iwl_mvm_internal_rxq_notif {
	u8 data[];
} __packed;

/**
 * enum iwl_mvm_pm_event - type of station PM event
 * @IWL_MVM_PM_EVENT_AWAKE: station woke up
 * @IWL_MVM_PM_EVENT_ASLEEP: station went to sleep
 * @IWL_MVM_PM_EVENT_UAPSD: station sent uAPSD trigger
 * @IWL_MVM_PM_EVENT_PS_POLL: station sent PS-Poll
 */
enum iwl_mvm_pm_event {
	IWL_MVM_PM_EVENT_AWAKE,
	IWL_MVM_PM_EVENT_ASLEEP,
	IWL_MVM_PM_EVENT_UAPSD,
	IWL_MVM_PM_EVENT_PS_POLL,
}; /* PEER_PM_NTFY_API_E_VER_1 */

/**
 * struct iwl_mvm_pm_state_notification - station PM state notification
 * @sta_id: station ID of the station changing state
 * @type: the new powersave state, see IWL_MVM_PM_EVENT_ above
 */
struct iwl_mvm_pm_state_notification {
	u8 sta_id;
	u8 type;
	/* private: */
	u16 reserved;
} __packed; /* PEER_PM_NTFY_API_S_VER_1 */

#endif /* __fw_api_rx_h__ */
+6 −3
Original line number Diff line number Diff line
@@ -179,7 +179,7 @@ enum iwl_sta_key_flag {
 * enum iwl_sta_modify_flag - indicate to the fw what flag are being changed
 * @STA_MODIFY_QUEUE_REMOVAL: this command removes a queue
 * @STA_MODIFY_TID_DISABLE_TX: this command modifies %tid_disable_tx
 * @STA_MODIFY_TX_RATE: unused
 * @STA_MODIFY_UAPSD_ACS: this command modifies %uapsd_trigger_acs
 * @STA_MODIFY_ADD_BA_TID: this command modifies %add_immediate_ba_tid
 * @STA_MODIFY_REMOVE_BA_TID: this command modifies %remove_immediate_ba_tid
 * @STA_MODIFY_SLEEPING_STA_TX_COUNT: this command modifies %sleep_tx_count
@@ -189,7 +189,7 @@ enum iwl_sta_key_flag {
enum iwl_sta_modify_flag {
	STA_MODIFY_QUEUE_REMOVAL		= BIT(0),
	STA_MODIFY_TID_DISABLE_TX		= BIT(1),
	STA_MODIFY_TX_RATE			= BIT(2),
	STA_MODIFY_UAPSD_ACS			= BIT(2),
	STA_MODIFY_ADD_BA_TID			= BIT(3),
	STA_MODIFY_REMOVE_BA_TID		= BIT(4),
	STA_MODIFY_SLEEPING_STA_TX_COUNT	= BIT(5),
@@ -353,6 +353,8 @@ struct iwl_mvm_add_sta_cmd_v7 {
 * @beamform_flags: beam forming controls
 * @tfd_queue_msk: tfd queues used by this station
 * @rx_ba_window: aggregation window size
 * @scd_queue_bank: queue bank in used. Each bank contains 32 queues. 0 means
 *	that the queues used by this station are in the first 32.
 *
 * The device contains an internal table of per-station information, with info
 * on security keys, aggregation parameters, and Tx rates for initial Tx
@@ -382,7 +384,8 @@ struct iwl_mvm_add_sta_cmd {
	__le16 beamform_flags;
	__le32 tfd_queue_msk;
	__le16 rx_ba_window;
	__le16 reserved;
	u8 scd_queue_bank;
	u8 uapsd_trigger_acs;
} __packed; /* ADD_STA_CMD_API_S_VER_8 */

/**
+1 −0
Original line number Diff line number Diff line
@@ -332,6 +332,7 @@ enum iwl_data_path_subcmd_ids {
	DQA_ENABLE_CMD = 0x0,
	UPDATE_MU_GROUPS_CMD = 0x1,
	TRIGGER_RX_QUEUES_NOTIF_CMD = 0x2,
	STA_PM_NOTIF = 0xFD,
	MU_GROUP_MGMT_NOTIF = 0xFE,
	RX_QUEUES_NOTIFICATION = 0xFF,
};
+66 −4
Original line number Diff line number Diff line
@@ -445,6 +445,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
	ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
	if (iwl_mvm_has_new_rx_api(mvm))
		ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
	if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_STA_PM_NOTIF))
		ieee80211_hw_set(hw, AP_LINK_PS);

	if (mvm->trans->num_rx_queues > 1)
		ieee80211_hw_set(hw, USES_RSS);
@@ -2318,8 +2320,7 @@ iwl_mvm_mac_release_buffered_frames(struct ieee80211_hw *hw,
					  tids, more_data, true);
}

static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
				   struct ieee80211_vif *vif,
static void __iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
				     enum sta_notify_cmd cmd,
				     struct ieee80211_sta *sta)
{
@@ -2374,6 +2375,67 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
	spin_unlock_bh(&mvmsta->lock);
}

static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
				   struct ieee80211_vif *vif,
				   enum sta_notify_cmd cmd,
				   struct ieee80211_sta *sta)
{
	__iwl_mvm_mac_sta_notify(hw, cmd, sta);
}

void iwl_mvm_sta_pm_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
{
	struct iwl_rx_packet *pkt = rxb_addr(rxb);
	struct iwl_mvm_pm_state_notification *notif = (void *)pkt->data;
	struct ieee80211_sta *sta;
	struct iwl_mvm_sta *mvmsta;
	bool sleeping = (notif->type != IWL_MVM_PM_EVENT_AWAKE);

	if (WARN_ON(notif->sta_id >= ARRAY_SIZE(mvm->fw_id_to_mac_id)))
		return;

	rcu_read_lock();
	sta = mvm->fw_id_to_mac_id[notif->sta_id];
	if (WARN_ON(IS_ERR_OR_NULL(sta))) {
		rcu_read_unlock();
		return;
	}

	mvmsta = iwl_mvm_sta_from_mac80211(sta);

	if (!mvmsta->vif ||
	    mvmsta->vif->type != NL80211_IFTYPE_AP) {
		rcu_read_unlock();
		return;
	}

	if (mvmsta->sleeping != sleeping) {
		mvmsta->sleeping = sleeping;
		__iwl_mvm_mac_sta_notify(mvm->hw,
			sleeping ? STA_NOTIFY_SLEEP : STA_NOTIFY_AWAKE,
			sta);
		ieee80211_sta_ps_transition(sta, sleeping);
	}

	if (sleeping) {
		switch (notif->type) {
		case IWL_MVM_PM_EVENT_AWAKE:
		case IWL_MVM_PM_EVENT_ASLEEP:
			break;
		case IWL_MVM_PM_EVENT_UAPSD:
			ieee80211_sta_uapsd_trigger(sta, IEEE80211_NUM_TIDS);
			break;
		case IWL_MVM_PM_EVENT_PS_POLL:
			ieee80211_sta_pspoll(sta);
			break;
		default:
			break;
		}
	}

	rcu_read_unlock();
}

static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,
				       struct ieee80211_vif *vif,
				       struct ieee80211_sta *sta)
Loading