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

Commit 3e56eadf authored by Johannes Berg's avatar Johannes Berg Committed by Emmanuel Grumbach
Browse files

iwlwifi: mvm: implement AP/GO uAPSD support



Newer firmware will support uAPSD clients in AP/GO mode, so complete
the driver support for it. The way it works is described in comments
in the code, but basically the driver just has to pass down all the
mac80211 requests and do accounting on agg/non-agg queues properly.

For older firmware, this doesn't change anything as it ignores the
fields used by the new firmware, and we only advertise uAPSD support
when the firmware does.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
parent 9b0cd304
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -95,6 +95,7 @@
 * @IWL_UCODE_TLV_FLAGS_P2P_PS: P2P client power save is supported (only on a
 *	single bound interface).
 * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save
 * @IWL_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients
 */
enum iwl_ucode_tlv_flag {
	IWL_UCODE_TLV_FLAGS_PAN			= BIT(0),
@@ -119,6 +120,7 @@ enum iwl_ucode_tlv_flag {
	IWL_UCODE_TLV_FLAGS_P2P_PS		= BIT(21),
	IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT	= BIT(24),
	IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD	= BIT(26),
	IWL_UCODE_TLV_FLAGS_GO_UAPSD		= BIT(30),
};

/* The default calibrate table size if not specified by firmware file */
+23 −8
Original line number Diff line number Diff line
@@ -199,11 +199,14 @@ enum iwl_sta_modify_flag {
 * @STA_SLEEP_STATE_AWAKE:
 * @STA_SLEEP_STATE_PS_POLL:
 * @STA_SLEEP_STATE_UAPSD:
 * @STA_SLEEP_STATE_MOREDATA: set more-data bit on
 *	(last) released frame
 */
enum iwl_sta_sleep_flag {
	STA_SLEEP_STATE_AWAKE		= 0,
	STA_SLEEP_STATE_PS_POLL		= BIT(0),
	STA_SLEEP_STATE_UAPSD		= BIT(1),
	STA_SLEEP_STATE_MOREDATA	= BIT(2),
};

/* STA ID and color bits definitions */
@@ -318,13 +321,15 @@ struct iwl_mvm_add_sta_cmd_v5 {
} __packed; /* ADD_STA_CMD_API_S_VER_5 */

/**
 * struct iwl_mvm_add_sta_cmd_v6 - Add / modify a station
 * VER_6 of this command is quite similar to VER_5 except
 * struct iwl_mvm_add_sta_cmd_v7 - Add / modify a station
 * VER_7 of this command is quite similar to VER_5 except
 * exclusion of all fields related to the security key installation.
 * It only differs from VER_6 by the "awake_acs" field that is
 * reserved and ignored in VER_6.
 */
struct iwl_mvm_add_sta_cmd_v6 {
struct iwl_mvm_add_sta_cmd_v7 {
	u8 add_modify;
	u8 reserved1;
	u8 awake_acs;
	__le16 tid_disable_tx;
	__le32 mac_id_n_color;
	u8 addr[ETH_ALEN];	/* _STA_ID_MODIFY_INFO_API_S_VER_1 */
@@ -342,7 +347,7 @@ struct iwl_mvm_add_sta_cmd_v6 {
	__le16 assoc_id;
	__le16 beamform_flags;
	__le32 tfd_queue_msk;
} __packed; /* ADD_STA_CMD_API_S_VER_6 */
} __packed; /* ADD_STA_CMD_API_S_VER_7 */

/**
 * struct iwl_mvm_add_sta_key_cmd - add/modify sta key
@@ -432,5 +437,15 @@ struct iwl_mvm_wep_key_cmd {
	struct iwl_mvm_wep_key wep_key[0];
} __packed; /* SEC_CURR_WEP_KEY_CMD_API_S_VER_2 */

/**
 * struct iwl_mvm_eosp_notification - EOSP notification from firmware
 * @remain_frame_count: # of frames remaining, non-zero if SP was cut
 *	short by GO absence
 * @sta_id: station ID
 */
struct iwl_mvm_eosp_notification {
	__le32 remain_frame_count;
	__le32 sta_id;
} __packed; /* UAPSD_EOSP_NTFY_API_S_VER_1 */

#endif /* __fw_api_sta_h__ */
+1 −0
Original line number Diff line number Diff line
@@ -163,6 +163,7 @@ enum {
	TX_ANT_CONFIGURATION_CMD = 0x98,
	BT_CONFIG = 0x9b,
	STATISTICS_NOTIFICATION = 0x9d,
	EOSP_NOTIFICATION = 0x9e,
	REDUCE_TX_POWER_CMD = 0x9f,

	/* RF-KILL commands and notifications */
+50 −9
Original line number Diff line number Diff line
@@ -203,6 +203,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
	hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
				       REGULATORY_DISABLE_BEACON_HINTS;

	if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD)
		hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;

	hw->wiphy->iface_combinations = iwl_mvm_iface_combinations;
	hw->wiphy->n_iface_combinations =
		ARRAY_SIZE(iwl_mvm_iface_combinations);
@@ -305,6 +308,9 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
			   struct sk_buff *skb)
{
	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
	struct ieee80211_sta *sta = control->sta;
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
	struct ieee80211_hdr *hdr = (void *)skb->data;

	if (iwl_mvm_is_radio_killed(mvm)) {
		IWL_DEBUG_DROP(mvm, "Dropping - RF/CT KILL\n");
@@ -315,8 +321,16 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
	    !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status))
		goto drop;

	if (control->sta) {
		if (iwl_mvm_tx_skb(mvm, skb, control->sta))
	/* treat non-bufferable MMPDUs as broadcast if sta is sleeping */
	if (unlikely(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER &&
		     ieee80211_is_mgmt(hdr->frame_control) &&
		     !ieee80211_is_deauth(hdr->frame_control) &&
		     !ieee80211_is_disassoc(hdr->frame_control) &&
		     !ieee80211_is_action(hdr->frame_control)))
		sta = NULL;

	if (sta) {
		if (iwl_mvm_tx_skb(mvm, skb, sta))
			goto drop;
		return;
	}
@@ -1168,20 +1182,32 @@ static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw,

static void
iwl_mvm_mac_allow_buffered_frames(struct ieee80211_hw *hw,
				  struct ieee80211_sta *sta, u16 tid,
				  struct ieee80211_sta *sta, u16 tids,
				  int num_frames,
				  enum ieee80211_frame_release_type reason,
				  bool more_data)
{
	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);

	/* TODO: how do we tell the fw to send frames for a specific TID */
	/* Called when we need to transmit (a) frame(s) from mac80211 */

	/*
	 * The fw will send EOSP notification when the last frame will be
	 * transmitted.
	 */
	iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames);
	iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames,
					  tids, more_data, false);
}

static void
iwl_mvm_mac_release_buffered_frames(struct ieee80211_hw *hw,
				    struct ieee80211_sta *sta, u16 tids,
				    int num_frames,
				    enum ieee80211_frame_release_type reason,
				    bool more_data)
{
	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);

	/* Called when we need to transmit (a) frame(s) from agg queue */

	iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames,
					  tids, more_data, true);
}

static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
@@ -1191,11 +1217,25 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
{
	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
	int tid;

	switch (cmd) {
	case STA_NOTIFY_SLEEP:
		if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0)
			ieee80211_sta_block_awake(hw, sta, true);
		spin_lock_bh(&mvmsta->lock);
		for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
			struct iwl_mvm_tid_data *tid_data;

			tid_data = &mvmsta->tid_data[tid];
			if (tid_data->state != IWL_AGG_ON &&
			    tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA)
				continue;
			if (iwl_mvm_tid_queued(tid_data) == 0)
				continue;
			ieee80211_sta_set_buffered(sta, tid, true);
		}
		spin_unlock_bh(&mvmsta->lock);
		/*
		 * The fw updates the STA to be asleep. Tx packets on the Tx
		 * queues to this station will not be transmitted. The fw will
@@ -1914,6 +1954,7 @@ struct ieee80211_ops iwl_mvm_hw_ops = {
	.sta_state = iwl_mvm_mac_sta_state,
	.sta_notify = iwl_mvm_mac_sta_notify,
	.allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames,
	.release_buffered_frames = iwl_mvm_mac_release_buffered_frames,
	.set_rts_threshold = iwl_mvm_mac_set_rts_threshold,
	.sta_rc_update = iwl_mvm_sta_rc_update,
	.conf_tx = iwl_mvm_mac_conf_tx,
+3 −0
Original line number Diff line number Diff line
@@ -222,6 +222,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {

	RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false),

	RX_HANDLER(EOSP_NOTIFICATION, iwl_mvm_rx_eosp_notif, false),

	RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false),
	RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false),
	RX_HANDLER(SCAN_OFFLOAD_COMPLETE,
@@ -284,6 +286,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
	CMD(BEACON_NOTIFICATION),
	CMD(BEACON_TEMPLATE_CMD),
	CMD(STATISTICS_NOTIFICATION),
	CMD(EOSP_NOTIFICATION),
	CMD(REDUCE_TX_POWER_CMD),
	CMD(TX_ANT_CONFIGURATION_CMD),
	CMD(D3_CONFIG_CMD),
Loading