aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-02-15 16:23:18 -0500
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-02-03 15:23:31 -0500
commit3e56eadfb6a1f28d753afa9fe27296258ae240e5 (patch)
tree885e0de4c11cbb7721a86866bb70649b3c0c612b /drivers/net/wireless
parent9b0cd304f26b9fca140de15deeac2bf357d1f388 (diff)
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: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h31
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h1
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c59
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c3
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.c171
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.h57
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tx.c23
8 files changed, 270 insertions, 77 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index 5f1493c44097..726327782401 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -95,6 +95,7 @@
95 * @IWL_UCODE_TLV_FLAGS_P2P_PS: P2P client power save is supported (only on a 95 * @IWL_UCODE_TLV_FLAGS_P2P_PS: P2P client power save is supported (only on a
96 * single bound interface). 96 * single bound interface).
97 * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save 97 * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save
98 * @IWL_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients
98 */ 99 */
99enum iwl_ucode_tlv_flag { 100enum iwl_ucode_tlv_flag {
100 IWL_UCODE_TLV_FLAGS_PAN = BIT(0), 101 IWL_UCODE_TLV_FLAGS_PAN = BIT(0),
@@ -119,6 +120,7 @@ enum iwl_ucode_tlv_flag {
119 IWL_UCODE_TLV_FLAGS_P2P_PS = BIT(21), 120 IWL_UCODE_TLV_FLAGS_P2P_PS = BIT(21),
120 IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24), 121 IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24),
121 IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD = BIT(26), 122 IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD = BIT(26),
123 IWL_UCODE_TLV_FLAGS_GO_UAPSD = BIT(30),
122}; 124};
123 125
124/* The default calibrate table size if not specified by firmware file */ 126/* The default calibrate table size if not specified by firmware file */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
index 1b60fdff6a56..d63647867262 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
@@ -199,11 +199,14 @@ enum iwl_sta_modify_flag {
199 * @STA_SLEEP_STATE_AWAKE: 199 * @STA_SLEEP_STATE_AWAKE:
200 * @STA_SLEEP_STATE_PS_POLL: 200 * @STA_SLEEP_STATE_PS_POLL:
201 * @STA_SLEEP_STATE_UAPSD: 201 * @STA_SLEEP_STATE_UAPSD:
202 * @STA_SLEEP_STATE_MOREDATA: set more-data bit on
203 * (last) released frame
202 */ 204 */
203enum iwl_sta_sleep_flag { 205enum iwl_sta_sleep_flag {
204 STA_SLEEP_STATE_AWAKE = 0, 206 STA_SLEEP_STATE_AWAKE = 0,
205 STA_SLEEP_STATE_PS_POLL = BIT(0), 207 STA_SLEEP_STATE_PS_POLL = BIT(0),
206 STA_SLEEP_STATE_UAPSD = BIT(1), 208 STA_SLEEP_STATE_UAPSD = BIT(1),
209 STA_SLEEP_STATE_MOREDATA = BIT(2),
207}; 210};
208 211
209/* STA ID and color bits definitions */ 212/* STA ID and color bits definitions */
@@ -318,13 +321,15 @@ struct iwl_mvm_add_sta_cmd_v5 {
318} __packed; /* ADD_STA_CMD_API_S_VER_5 */ 321} __packed; /* ADD_STA_CMD_API_S_VER_5 */
319 322
320/** 323/**
321 * struct iwl_mvm_add_sta_cmd_v6 - Add / modify a station 324 * struct iwl_mvm_add_sta_cmd_v7 - Add / modify a station
322 * VER_6 of this command is quite similar to VER_5 except 325 * VER_7 of this command is quite similar to VER_5 except
323 * exclusion of all fields related to the security key installation. 326 * exclusion of all fields related to the security key installation.
327 * It only differs from VER_6 by the "awake_acs" field that is
328 * reserved and ignored in VER_6.
324 */ 329 */
325struct iwl_mvm_add_sta_cmd_v6 { 330struct iwl_mvm_add_sta_cmd_v7 {
326 u8 add_modify; 331 u8 add_modify;
327 u8 reserved1; 332 u8 awake_acs;
328 __le16 tid_disable_tx; 333 __le16 tid_disable_tx;
329 __le32 mac_id_n_color; 334 __le32 mac_id_n_color;
330 u8 addr[ETH_ALEN]; /* _STA_ID_MODIFY_INFO_API_S_VER_1 */ 335 u8 addr[ETH_ALEN]; /* _STA_ID_MODIFY_INFO_API_S_VER_1 */
@@ -342,7 +347,7 @@ struct iwl_mvm_add_sta_cmd_v6 {
342 __le16 assoc_id; 347 __le16 assoc_id;
343 __le16 beamform_flags; 348 __le16 beamform_flags;
344 __le32 tfd_queue_msk; 349 __le32 tfd_queue_msk;
345} __packed; /* ADD_STA_CMD_API_S_VER_6 */ 350} __packed; /* ADD_STA_CMD_API_S_VER_7 */
346 351
347/** 352/**
348 * struct iwl_mvm_add_sta_key_cmd - add/modify sta key 353 * struct iwl_mvm_add_sta_key_cmd - add/modify sta key
@@ -432,5 +437,15 @@ struct iwl_mvm_wep_key_cmd {
432 struct iwl_mvm_wep_key wep_key[0]; 437 struct iwl_mvm_wep_key wep_key[0];
433} __packed; /* SEC_CURR_WEP_KEY_CMD_API_S_VER_2 */ 438} __packed; /* SEC_CURR_WEP_KEY_CMD_API_S_VER_2 */
434 439
440/**
441 * struct iwl_mvm_eosp_notification - EOSP notification from firmware
442 * @remain_frame_count: # of frames remaining, non-zero if SP was cut
443 * short by GO absence
444 * @sta_id: station ID
445 */
446struct iwl_mvm_eosp_notification {
447 __le32 remain_frame_count;
448 __le32 sta_id;
449} __packed; /* UAPSD_EOSP_NTFY_API_S_VER_1 */
435 450
436#endif /* __fw_api_sta_h__ */ 451#endif /* __fw_api_sta_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index 989d7dbdca6c..a043a1f2f06f 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -163,6 +163,7 @@ enum {
163 TX_ANT_CONFIGURATION_CMD = 0x98, 163 TX_ANT_CONFIGURATION_CMD = 0x98,
164 BT_CONFIG = 0x9b, 164 BT_CONFIG = 0x9b,
165 STATISTICS_NOTIFICATION = 0x9d, 165 STATISTICS_NOTIFICATION = 0x9d,
166 EOSP_NOTIFICATION = 0x9e,
166 REDUCE_TX_POWER_CMD = 0x9f, 167 REDUCE_TX_POWER_CMD = 0x9f,
167 168
168 /* RF-KILL commands and notifications */ 169 /* RF-KILL commands and notifications */
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index c49b5073c251..5b9cfe1f35bd 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -203,6 +203,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
203 hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | 203 hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
204 REGULATORY_DISABLE_BEACON_HINTS; 204 REGULATORY_DISABLE_BEACON_HINTS;
205 205
206 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD)
207 hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
208
206 hw->wiphy->iface_combinations = iwl_mvm_iface_combinations; 209 hw->wiphy->iface_combinations = iwl_mvm_iface_combinations;
207 hw->wiphy->n_iface_combinations = 210 hw->wiphy->n_iface_combinations =
208 ARRAY_SIZE(iwl_mvm_iface_combinations); 211 ARRAY_SIZE(iwl_mvm_iface_combinations);
@@ -305,6 +308,9 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
305 struct sk_buff *skb) 308 struct sk_buff *skb)
306{ 309{
307 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 310 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
311 struct ieee80211_sta *sta = control->sta;
312 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
313 struct ieee80211_hdr *hdr = (void *)skb->data;
308 314
309 if (iwl_mvm_is_radio_killed(mvm)) { 315 if (iwl_mvm_is_radio_killed(mvm)) {
310 IWL_DEBUG_DROP(mvm, "Dropping - RF/CT KILL\n"); 316 IWL_DEBUG_DROP(mvm, "Dropping - RF/CT KILL\n");
@@ -315,8 +321,16 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
315 !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status)) 321 !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status))
316 goto drop; 322 goto drop;
317 323
318 if (control->sta) { 324 /* treat non-bufferable MMPDUs as broadcast if sta is sleeping */
319 if (iwl_mvm_tx_skb(mvm, skb, control->sta)) 325 if (unlikely(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER &&
326 ieee80211_is_mgmt(hdr->frame_control) &&
327 !ieee80211_is_deauth(hdr->frame_control) &&
328 !ieee80211_is_disassoc(hdr->frame_control) &&
329 !ieee80211_is_action(hdr->frame_control)))
330 sta = NULL;
331
332 if (sta) {
333 if (iwl_mvm_tx_skb(mvm, skb, sta))
320 goto drop; 334 goto drop;
321 return; 335 return;
322 } 336 }
@@ -1168,20 +1182,32 @@ static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw,
1168 1182
1169static void 1183static void
1170iwl_mvm_mac_allow_buffered_frames(struct ieee80211_hw *hw, 1184iwl_mvm_mac_allow_buffered_frames(struct ieee80211_hw *hw,
1171 struct ieee80211_sta *sta, u16 tid, 1185 struct ieee80211_sta *sta, u16 tids,
1172 int num_frames, 1186 int num_frames,
1173 enum ieee80211_frame_release_type reason, 1187 enum ieee80211_frame_release_type reason,
1174 bool more_data) 1188 bool more_data)
1175{ 1189{
1176 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 1190 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1177 1191
1178 /* TODO: how do we tell the fw to send frames for a specific TID */ 1192 /* Called when we need to transmit (a) frame(s) from mac80211 */
1179 1193
1180 /* 1194 iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames,
1181 * The fw will send EOSP notification when the last frame will be 1195 tids, more_data, false);
1182 * transmitted. 1196}
1183 */ 1197
1184 iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames); 1198static void
1199iwl_mvm_mac_release_buffered_frames(struct ieee80211_hw *hw,
1200 struct ieee80211_sta *sta, u16 tids,
1201 int num_frames,
1202 enum ieee80211_frame_release_type reason,
1203 bool more_data)
1204{
1205 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1206
1207 /* Called when we need to transmit (a) frame(s) from agg queue */
1208
1209 iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames,
1210 tids, more_data, true);
1185} 1211}
1186 1212
1187static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, 1213static 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,
1191{ 1217{
1192 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 1218 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1193 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); 1219 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
1220 int tid;
1194 1221
1195 switch (cmd) { 1222 switch (cmd) {
1196 case STA_NOTIFY_SLEEP: 1223 case STA_NOTIFY_SLEEP:
1197 if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0) 1224 if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0)
1198 ieee80211_sta_block_awake(hw, sta, true); 1225 ieee80211_sta_block_awake(hw, sta, true);
1226 spin_lock_bh(&mvmsta->lock);
1227 for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
1228 struct iwl_mvm_tid_data *tid_data;
1229
1230 tid_data = &mvmsta->tid_data[tid];
1231 if (tid_data->state != IWL_AGG_ON &&
1232 tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA)
1233 continue;
1234 if (iwl_mvm_tid_queued(tid_data) == 0)
1235 continue;
1236 ieee80211_sta_set_buffered(sta, tid, true);
1237 }
1238 spin_unlock_bh(&mvmsta->lock);
1199 /* 1239 /*
1200 * The fw updates the STA to be asleep. Tx packets on the Tx 1240 * The fw updates the STA to be asleep. Tx packets on the Tx
1201 * queues to this station will not be transmitted. The fw will 1241 * queues to this station will not be transmitted. The fw will
@@ -1914,6 +1954,7 @@ struct ieee80211_ops iwl_mvm_hw_ops = {
1914 .sta_state = iwl_mvm_mac_sta_state, 1954 .sta_state = iwl_mvm_mac_sta_state,
1915 .sta_notify = iwl_mvm_mac_sta_notify, 1955 .sta_notify = iwl_mvm_mac_sta_notify,
1916 .allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames, 1956 .allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames,
1957 .release_buffered_frames = iwl_mvm_mac_release_buffered_frames,
1917 .set_rts_threshold = iwl_mvm_mac_set_rts_threshold, 1958 .set_rts_threshold = iwl_mvm_mac_set_rts_threshold,
1918 .sta_rc_update = iwl_mvm_sta_rc_update, 1959 .sta_rc_update = iwl_mvm_sta_rc_update,
1919 .conf_tx = iwl_mvm_mac_conf_tx, 1960 .conf_tx = iwl_mvm_mac_conf_tx,
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index a3d43de342d7..a65eeb335cfb 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -222,6 +222,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
222 222
223 RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false), 223 RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false),
224 224
225 RX_HANDLER(EOSP_NOTIFICATION, iwl_mvm_rx_eosp_notif, false),
226
225 RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false), 227 RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false),
226 RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false), 228 RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false),
227 RX_HANDLER(SCAN_OFFLOAD_COMPLETE, 229 RX_HANDLER(SCAN_OFFLOAD_COMPLETE,
@@ -284,6 +286,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
284 CMD(BEACON_NOTIFICATION), 286 CMD(BEACON_NOTIFICATION),
285 CMD(BEACON_TEMPLATE_CMD), 287 CMD(BEACON_TEMPLATE_CMD),
286 CMD(STATISTICS_NOTIFICATION), 288 CMD(STATISTICS_NOTIFICATION),
289 CMD(EOSP_NOTIFICATION),
287 CMD(REDUCE_TX_POWER_CMD), 290 CMD(REDUCE_TX_POWER_CMD),
288 CMD(TX_ANT_CONFIGURATION_CMD), 291 CMD(TX_ANT_CONFIGURATION_CMD),
289 CMD(D3_CONFIG_CMD), 292 CMD(D3_CONFIG_CMD),
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
index ec1812133235..af94f75c3999 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -66,27 +66,27 @@
66#include "sta.h" 66#include "sta.h"
67#include "rs.h" 67#include "rs.h"
68 68
69static void iwl_mvm_add_sta_cmd_v6_to_v5(struct iwl_mvm_add_sta_cmd_v6 *cmd_v6, 69static void iwl_mvm_add_sta_cmd_v7_to_v5(struct iwl_mvm_add_sta_cmd_v7 *cmd_v7,
70 struct iwl_mvm_add_sta_cmd_v5 *cmd_v5) 70 struct iwl_mvm_add_sta_cmd_v5 *cmd_v5)
71{ 71{
72 memset(cmd_v5, 0, sizeof(*cmd_v5)); 72 memset(cmd_v5, 0, sizeof(*cmd_v5));
73 73
74 cmd_v5->add_modify = cmd_v6->add_modify; 74 cmd_v5->add_modify = cmd_v7->add_modify;
75 cmd_v5->tid_disable_tx = cmd_v6->tid_disable_tx; 75 cmd_v5->tid_disable_tx = cmd_v7->tid_disable_tx;
76 cmd_v5->mac_id_n_color = cmd_v6->mac_id_n_color; 76 cmd_v5->mac_id_n_color = cmd_v7->mac_id_n_color;
77 memcpy(cmd_v5->addr, cmd_v6->addr, ETH_ALEN); 77 memcpy(cmd_v5->addr, cmd_v7->addr, ETH_ALEN);
78 cmd_v5->sta_id = cmd_v6->sta_id; 78 cmd_v5->sta_id = cmd_v7->sta_id;
79 cmd_v5->modify_mask = cmd_v6->modify_mask; 79 cmd_v5->modify_mask = cmd_v7->modify_mask;
80 cmd_v5->station_flags = cmd_v6->station_flags; 80 cmd_v5->station_flags = cmd_v7->station_flags;
81 cmd_v5->station_flags_msk = cmd_v6->station_flags_msk; 81 cmd_v5->station_flags_msk = cmd_v7->station_flags_msk;
82 cmd_v5->add_immediate_ba_tid = cmd_v6->add_immediate_ba_tid; 82 cmd_v5->add_immediate_ba_tid = cmd_v7->add_immediate_ba_tid;
83 cmd_v5->remove_immediate_ba_tid = cmd_v6->remove_immediate_ba_tid; 83 cmd_v5->remove_immediate_ba_tid = cmd_v7->remove_immediate_ba_tid;
84 cmd_v5->add_immediate_ba_ssn = cmd_v6->add_immediate_ba_ssn; 84 cmd_v5->add_immediate_ba_ssn = cmd_v7->add_immediate_ba_ssn;
85 cmd_v5->sleep_tx_count = cmd_v6->sleep_tx_count; 85 cmd_v5->sleep_tx_count = cmd_v7->sleep_tx_count;
86 cmd_v5->sleep_state_flags = cmd_v6->sleep_state_flags; 86 cmd_v5->sleep_state_flags = cmd_v7->sleep_state_flags;
87 cmd_v5->assoc_id = cmd_v6->assoc_id; 87 cmd_v5->assoc_id = cmd_v7->assoc_id;
88 cmd_v5->beamform_flags = cmd_v6->beamform_flags; 88 cmd_v5->beamform_flags = cmd_v7->beamform_flags;
89 cmd_v5->tfd_queue_msk = cmd_v6->tfd_queue_msk; 89 cmd_v5->tfd_queue_msk = cmd_v7->tfd_queue_msk;
90} 90}
91 91
92static void 92static void
@@ -110,7 +110,7 @@ iwl_mvm_add_sta_key_to_add_sta_cmd_v5(struct iwl_mvm_add_sta_key_cmd *key_cmd,
110} 110}
111 111
112static int iwl_mvm_send_add_sta_cmd_status(struct iwl_mvm *mvm, 112static int iwl_mvm_send_add_sta_cmd_status(struct iwl_mvm *mvm,
113 struct iwl_mvm_add_sta_cmd_v6 *cmd, 113 struct iwl_mvm_add_sta_cmd_v7 *cmd,
114 int *status) 114 int *status)
115{ 115{
116 struct iwl_mvm_add_sta_cmd_v5 cmd_v5; 116 struct iwl_mvm_add_sta_cmd_v5 cmd_v5;
@@ -119,14 +119,14 @@ static int iwl_mvm_send_add_sta_cmd_status(struct iwl_mvm *mvm,
119 return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(*cmd), 119 return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(*cmd),
120 cmd, status); 120 cmd, status);
121 121
122 iwl_mvm_add_sta_cmd_v6_to_v5(cmd, &cmd_v5); 122 iwl_mvm_add_sta_cmd_v7_to_v5(cmd, &cmd_v5);
123 123
124 return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd_v5), 124 return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd_v5),
125 &cmd_v5, status); 125 &cmd_v5, status);
126} 126}
127 127
128static int iwl_mvm_send_add_sta_cmd(struct iwl_mvm *mvm, u32 flags, 128static int iwl_mvm_send_add_sta_cmd(struct iwl_mvm *mvm, u32 flags,
129 struct iwl_mvm_add_sta_cmd_v6 *cmd) 129 struct iwl_mvm_add_sta_cmd_v7 *cmd)
130{ 130{
131 struct iwl_mvm_add_sta_cmd_v5 cmd_v5; 131 struct iwl_mvm_add_sta_cmd_v5 cmd_v5;
132 132
@@ -134,7 +134,7 @@ static int iwl_mvm_send_add_sta_cmd(struct iwl_mvm *mvm, u32 flags,
134 return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, 134 return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags,
135 sizeof(*cmd), cmd); 135 sizeof(*cmd), cmd);
136 136
137 iwl_mvm_add_sta_cmd_v6_to_v5(cmd, &cmd_v5); 137 iwl_mvm_add_sta_cmd_v7_to_v5(cmd, &cmd_v5);
138 138
139 return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, sizeof(cmd_v5), 139 return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, sizeof(cmd_v5),
140 &cmd_v5); 140 &cmd_v5);
@@ -196,7 +196,7 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
196 bool update) 196 bool update)
197{ 197{
198 struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; 198 struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
199 struct iwl_mvm_add_sta_cmd_v6 add_sta_cmd; 199 struct iwl_mvm_add_sta_cmd_v7 add_sta_cmd;
200 int ret; 200 int ret;
201 u32 status; 201 u32 status;
202 u32 agg_size = 0, mpdu_dens = 0; 202 u32 agg_size = 0, mpdu_dens = 0;
@@ -368,7 +368,7 @@ int iwl_mvm_update_sta(struct iwl_mvm *mvm,
368int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, 368int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
369 bool drain) 369 bool drain)
370{ 370{
371 struct iwl_mvm_add_sta_cmd_v6 cmd = {}; 371 struct iwl_mvm_add_sta_cmd_v7 cmd = {};
372 int ret; 372 int ret;
373 u32 status; 373 u32 status;
374 374
@@ -587,13 +587,13 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm,
587 const u8 *addr, 587 const u8 *addr,
588 u16 mac_id, u16 color) 588 u16 mac_id, u16 color)
589{ 589{
590 struct iwl_mvm_add_sta_cmd_v6 cmd; 590 struct iwl_mvm_add_sta_cmd_v7 cmd;
591 int ret; 591 int ret;
592 u32 status; 592 u32 status;
593 593
594 lockdep_assert_held(&mvm->mutex); 594 lockdep_assert_held(&mvm->mutex);
595 595
596 memset(&cmd, 0, sizeof(struct iwl_mvm_add_sta_cmd_v6)); 596 memset(&cmd, 0, sizeof(struct iwl_mvm_add_sta_cmd_v7));
597 cmd.sta_id = sta->sta_id; 597 cmd.sta_id = sta->sta_id;
598 cmd.mac_id_n_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mac_id, 598 cmd.mac_id_n_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mac_id,
599 color)); 599 color));
@@ -735,7 +735,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
735 int tid, u16 ssn, bool start) 735 int tid, u16 ssn, bool start)
736{ 736{
737 struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; 737 struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
738 struct iwl_mvm_add_sta_cmd_v6 cmd = {}; 738 struct iwl_mvm_add_sta_cmd_v7 cmd = {};
739 int ret; 739 int ret;
740 u32 status; 740 u32 status;
741 741
@@ -794,7 +794,7 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
794 int tid, u8 queue, bool start) 794 int tid, u8 queue, bool start)
795{ 795{
796 struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; 796 struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
797 struct iwl_mvm_add_sta_cmd_v6 cmd = {}; 797 struct iwl_mvm_add_sta_cmd_v7 cmd = {};
798 int ret; 798 int ret;
799 u32 status; 799 u32 status;
800 800
@@ -833,7 +833,7 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
833 return ret; 833 return ret;
834} 834}
835 835
836static const u8 tid_to_ac[] = { 836static const u8 tid_to_mac80211_ac[] = {
837 IEEE80211_AC_BE, 837 IEEE80211_AC_BE,
838 IEEE80211_AC_BK, 838 IEEE80211_AC_BK,
839 IEEE80211_AC_BK, 839 IEEE80211_AC_BK,
@@ -844,6 +844,17 @@ static const u8 tid_to_ac[] = {
844 IEEE80211_AC_VO, 844 IEEE80211_AC_VO,
845}; 845};
846 846
847static const u8 tid_to_ucode_ac[] = {
848 AC_BE,
849 AC_BK,
850 AC_BK,
851 AC_BE,
852 AC_VI,
853 AC_VI,
854 AC_VO,
855 AC_VO,
856};
857
847int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 858int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
848 struct ieee80211_sta *sta, u16 tid, u16 *ssn) 859 struct ieee80211_sta *sta, u16 tid, u16 *ssn)
849{ 860{
@@ -874,7 +885,7 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
874 } 885 }
875 886
876 /* the new tx queue is still connected to the same mac80211 queue */ 887 /* the new tx queue is still connected to the same mac80211 queue */
877 mvm->queue_to_mac80211[txq_id] = vif->hw_queue[tid_to_ac[tid]]; 888 mvm->queue_to_mac80211[txq_id] = vif->hw_queue[tid_to_mac80211_ac[tid]];
878 889
879 spin_lock_bh(&mvmsta->lock); 890 spin_lock_bh(&mvmsta->lock);
880 tid_data = &mvmsta->tid_data[tid]; 891 tid_data = &mvmsta->tid_data[tid];
@@ -916,7 +927,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
916 tid_data->ssn = 0xffff; 927 tid_data->ssn = 0xffff;
917 spin_unlock_bh(&mvmsta->lock); 928 spin_unlock_bh(&mvmsta->lock);
918 929
919 fifo = iwl_mvm_ac_to_tx_fifo[tid_to_ac[tid]]; 930 fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]];
920 931
921 ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true); 932 ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true);
922 if (ret) 933 if (ret)
@@ -1411,7 +1422,7 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
1411 struct ieee80211_sta *sta) 1422 struct ieee80211_sta *sta)
1412{ 1423{
1413 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); 1424 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
1414 struct iwl_mvm_add_sta_cmd_v6 cmd = { 1425 struct iwl_mvm_add_sta_cmd_v7 cmd = {
1415 .add_modify = STA_MODE_MODIFY, 1426 .add_modify = STA_MODE_MODIFY,
1416 .sta_id = mvmsta->sta_id, 1427 .sta_id = mvmsta->sta_id,
1417 .station_flags_msk = cpu_to_le32(STA_FLG_PS), 1428 .station_flags_msk = cpu_to_le32(STA_FLG_PS),
@@ -1427,28 +1438,102 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
1427void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, 1438void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
1428 struct ieee80211_sta *sta, 1439 struct ieee80211_sta *sta,
1429 enum ieee80211_frame_release_type reason, 1440 enum ieee80211_frame_release_type reason,
1430 u16 cnt) 1441 u16 cnt, u16 tids, bool more_data,
1442 bool agg)
1431{ 1443{
1432 u16 sleep_state_flags =
1433 (reason == IEEE80211_FRAME_RELEASE_UAPSD) ?
1434 STA_SLEEP_STATE_UAPSD : STA_SLEEP_STATE_PS_POLL;
1435 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); 1444 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
1436 struct iwl_mvm_add_sta_cmd_v6 cmd = { 1445 struct iwl_mvm_add_sta_cmd_v7 cmd = {
1437 .add_modify = STA_MODE_MODIFY, 1446 .add_modify = STA_MODE_MODIFY,
1438 .sta_id = mvmsta->sta_id, 1447 .sta_id = mvmsta->sta_id,
1439 .modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT, 1448 .modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT,
1440 .sleep_tx_count = cpu_to_le16(cnt), 1449 .sleep_tx_count = cpu_to_le16(cnt),
1441 .mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color), 1450 .mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color),
1442 /*
1443 * Same modify mask for sleep_tx_count and sleep_state_flags so
1444 * we must set the sleep_state_flags too.
1445 */
1446 .sleep_state_flags = cpu_to_le16(sleep_state_flags),
1447 }; 1451 };
1448 int ret; 1452 int tid, ret;
1453 unsigned long _tids = tids;
1454
1455 /* convert TIDs to ACs - we don't support TSPEC so that's OK
1456 * Note that this field is reserved and unused by firmware not
1457 * supporting GO uAPSD, so it's safe to always do this.
1458 */
1459 for_each_set_bit(tid, &_tids, IWL_MAX_TID_COUNT)
1460 cmd.awake_acs |= BIT(tid_to_ucode_ac[tid]);
1461
1462 /* If we're releasing frames from aggregation queues then check if the
1463 * all queues combined that we're releasing frames from have
1464 * - more frames than the service period, in which case more_data
1465 * needs to be set
1466 * - fewer than 'cnt' frames, in which case we need to adjust the
1467 * firmware command (but do that unconditionally)
1468 */
1469 if (agg) {
1470 int remaining = cnt;
1471
1472 spin_lock_bh(&mvmsta->lock);
1473 for_each_set_bit(tid, &_tids, IWL_MAX_TID_COUNT) {
1474 struct iwl_mvm_tid_data *tid_data;
1475 u16 n_queued;
1476
1477 tid_data = &mvmsta->tid_data[tid];
1478 if (WARN(tid_data->state != IWL_AGG_ON &&
1479 tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA,
1480 "TID %d state is %d\n",
1481 tid, tid_data->state)) {
1482 spin_unlock_bh(&mvmsta->lock);
1483 ieee80211_sta_eosp(sta);
1484 return;
1485 }
1486
1487 n_queued = iwl_mvm_tid_queued(tid_data);
1488 if (n_queued > remaining) {
1489 more_data = true;
1490 remaining = 0;
1491 break;
1492 }
1493 remaining -= n_queued;
1494 }
1495 spin_unlock_bh(&mvmsta->lock);
1496
1497 cmd.sleep_tx_count = cpu_to_le16(cnt - remaining);
1498 if (WARN_ON(cnt - remaining == 0)) {
1499 ieee80211_sta_eosp(sta);
1500 return;
1501 }
1502 }
1503
1504 /* Note: this is ignored by firmware not supporting GO uAPSD */
1505 if (more_data)
1506 cmd.sleep_state_flags |= cpu_to_le16(STA_SLEEP_STATE_MOREDATA);
1507
1508 if (reason == IEEE80211_FRAME_RELEASE_PSPOLL) {
1509 mvmsta->next_status_eosp = true;
1510 cmd.sleep_state_flags |= cpu_to_le16(STA_SLEEP_STATE_PS_POLL);
1511 } else {
1512 cmd.sleep_state_flags |= cpu_to_le16(STA_SLEEP_STATE_UAPSD);
1513 }
1449 1514
1450 /* TODO: somehow the fw doesn't seem to take PS_POLL into account */
1451 ret = iwl_mvm_send_add_sta_cmd(mvm, CMD_ASYNC, &cmd); 1515 ret = iwl_mvm_send_add_sta_cmd(mvm, CMD_ASYNC, &cmd);
1452 if (ret) 1516 if (ret)
1453 IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); 1517 IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
1454} 1518}
1519
1520int iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm,
1521 struct iwl_rx_cmd_buffer *rxb,
1522 struct iwl_device_cmd *cmd)
1523{
1524 struct iwl_rx_packet *pkt = rxb_addr(rxb);
1525 struct iwl_mvm_eosp_notification *notif = (void *)pkt->data;
1526 struct ieee80211_sta *sta;
1527 u32 sta_id = le32_to_cpu(notif->sta_id);
1528
1529 if (WARN_ON_ONCE(sta_id >= IWL_MVM_STATION_COUNT))
1530 return 0;
1531
1532 rcu_read_lock();
1533 sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
1534 if (!IS_ERR_OR_NULL(sta))
1535 ieee80211_sta_eosp(sta);
1536 rcu_read_unlock();
1537
1538 return 0;
1539}
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h
index 4968d0237dc5..64f9a1bf7c43 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.h
@@ -195,24 +195,33 @@ struct iwl_mvm;
195/** 195/**
196 * DOC: AP mode - PS 196 * DOC: AP mode - PS
197 * 197 *
198 * When a station is asleep, the fw will set it as "asleep". All the 198 * When a station is asleep, the fw will set it as "asleep". All frames on
199 * non-aggregation frames to that station will be dropped by the fw 199 * shared queues (i.e. non-aggregation queues) to that station will be dropped
200 * (%TX_STATUS_FAIL_DEST_PS failure code). 200 * by the fw (%TX_STATUS_FAIL_DEST_PS failure code).
201 *
201 * AMPDUs are in a separate queue that is stopped by the fw. We just need to 202 * AMPDUs are in a separate queue that is stopped by the fw. We just need to
202 * let mac80211 know how many frames we have in these queues so that it can 203 * let mac80211 know when there are frames in these queues so that it can
203 * properly handle trigger frames. 204 * properly handle trigger frames.
204 * When the a trigger frame is received, mac80211 tells the driver to send 205 *
205 * frames from the AMPDU queues or AC queue depending on which queue are 206 * When a trigger frame is received, mac80211 tells the driver to send frames
206 * delivery-enabled and what TID has frames to transmit (Note that mac80211 has 207 * from the AMPDU queues or sends frames to non-aggregation queues itself,
207 * all the knowledege since all the non-agg frames are buffered / filtered, and 208 * depending on which ACs are delivery-enabled and what TID has frames to
208 * the driver tells mac80211 about agg frames). The driver needs to tell the fw 209 * transmit. Note that mac80211 has all the knowledege since all the non-agg
209 * to let frames out even if the station is asleep. This is done by 210 * frames are buffered / filtered, and the driver tells mac80211 about agg
210 * %iwl_mvm_sta_modify_sleep_tx_count. 211 * frames). The driver needs to tell the fw to let frames out even if the
211 * When we receive a frame from that station with PM bit unset, the 212 * station is asleep. This is done by %iwl_mvm_sta_modify_sleep_tx_count.
212 * driver needs to let the fw know that this station isn't alseep any more. 213 *
213 * This is done by %iwl_mvm_sta_modify_ps_wake. 214 * When we receive a frame from that station with PM bit unset, the driver
214 * 215 * needs to let the fw know that this station isn't asleep any more. This is
215 * TODO - EOSP handling 216 * done by %iwl_mvm_sta_modify_ps_wake in response to mac80211 signalling the
217 * station's wakeup.
218 *
219 * For a GO, the Service Period might be cut short due to an absence period
220 * of the GO. In this (and all other cases) the firmware notifies us with the
221 * EOSP_NOTIFICATION, and we notify mac80211 of that. Further frames that we
222 * already sent to the device will be rejected again.
223 *
224 * See also "AP support for powersaving clients" in mac80211.h.
216 */ 225 */
217 226
218/** 227/**
@@ -261,6 +270,12 @@ struct iwl_mvm_tid_data {
261 u16 ssn; 270 u16 ssn;
262}; 271};
263 272
273static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data)
274{
275 return ieee80211_sn_sub(IEEE80211_SEQ_TO_SN(tid_data->seq_number),
276 tid_data->next_reclaimed);
277}
278
264/** 279/**
265 * struct iwl_mvm_sta - representation of a station in the driver 280 * struct iwl_mvm_sta - representation of a station in the driver
266 * @sta_id: the index of the station in the fw (will be replaced by id_n_color) 281 * @sta_id: the index of the station in the fw (will be replaced by id_n_color)
@@ -270,6 +285,8 @@ struct iwl_mvm_tid_data {
270 * tid. 285 * tid.
271 * @max_agg_bufsize: the maximal size of the AGG buffer for this station 286 * @max_agg_bufsize: the maximal size of the AGG buffer for this station
272 * @bt_reduced_txpower: is reduced tx power enabled for this station 287 * @bt_reduced_txpower: is reduced tx power enabled for this station
288 * @next_status_eosp: the next reclaimed packet is a PS-Poll response and
289 * we need to signal the EOSP
273 * @lock: lock to protect the whole struct. Since %tid_data is access from Tx 290 * @lock: lock to protect the whole struct. Since %tid_data is access from Tx
274 * and from Tx response flow, it needs a spinlock. 291 * and from Tx response flow, it needs a spinlock.
275 * @tid_data: per tid data. Look at %iwl_mvm_tid_data. 292 * @tid_data: per tid data. Look at %iwl_mvm_tid_data.
@@ -288,6 +305,7 @@ struct iwl_mvm_sta {
288 u16 tid_disable_agg; 305 u16 tid_disable_agg;
289 u8 max_agg_bufsize; 306 u8 max_agg_bufsize;
290 bool bt_reduced_txpower; 307 bool bt_reduced_txpower;
308 bool next_status_eosp;
291 spinlock_t lock; 309 spinlock_t lock;
292 struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT]; 310 struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT];
293 struct iwl_lq_sta lq_sta; 311 struct iwl_lq_sta lq_sta;
@@ -345,6 +363,10 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
345 struct ieee80211_sta *sta, u32 iv32, 363 struct ieee80211_sta *sta, u32 iv32,
346 u16 *phase1key); 364 u16 *phase1key);
347 365
366int iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm,
367 struct iwl_rx_cmd_buffer *rxb,
368 struct iwl_device_cmd *cmd);
369
348/* AMPDU */ 370/* AMPDU */
349int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, 371int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
350 int tid, u16 ssn, bool start); 372 int tid, u16 ssn, bool start);
@@ -375,7 +397,8 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
375void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, 397void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
376 struct ieee80211_sta *sta, 398 struct ieee80211_sta *sta,
377 enum ieee80211_frame_release_type reason, 399 enum ieee80211_frame_release_type reason,
378 u16 cnt); 400 u16 cnt, u16 tids, bool more_data,
401 bool agg);
379int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, 402int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
380 bool drain); 403 bool drain);
381 404
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c
index 90378c217bc7..8d18bf23e4bf 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tx.c
@@ -377,6 +377,13 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
377 tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; 377 tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload;
378 /* From now on, we cannot access info->control */ 378 /* From now on, we cannot access info->control */
379 379
380 /*
381 * we handle that entirely ourselves -- for uAPSD the firmware
382 * will always send a notification, and for PS-Poll responses
383 * we'll notify mac80211 when getting frame status
384 */
385 info->flags &= ~IEEE80211_TX_STATUS_EOSP;
386
380 spin_lock(&mvmsta->lock); 387 spin_lock(&mvmsta->lock);
381 388
382 if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) { 389 if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) {
@@ -437,6 +444,17 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,
437 444
438 lockdep_assert_held(&mvmsta->lock); 445 lockdep_assert_held(&mvmsta->lock);
439 446
447 if ((tid_data->state == IWL_AGG_ON ||
448 tid_data->state == IWL_EMPTYING_HW_QUEUE_DELBA) &&
449 iwl_mvm_tid_queued(tid_data) == 0) {
450 /*
451 * Now that this aggregation queue is empty tell mac80211 so it
452 * knows we no longer have frames buffered for the station on
453 * this TID (for the TIM bitmap calculation.)
454 */
455 ieee80211_sta_set_buffered(sta, tid, false);
456 }
457
440 if (tid_data->ssn != tid_data->next_reclaimed) 458 if (tid_data->ssn != tid_data->next_reclaimed)
441 return; 459 return;
442 460
@@ -674,6 +692,11 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
674 iwl_mvm_check_ratid_empty(mvm, sta, tid); 692 iwl_mvm_check_ratid_empty(mvm, sta, tid);
675 spin_unlock_bh(&mvmsta->lock); 693 spin_unlock_bh(&mvmsta->lock);
676 } 694 }
695
696 if (mvmsta->next_status_eosp) {
697 mvmsta->next_status_eosp = false;
698 ieee80211_sta_eosp(sta);
699 }
677 } else { 700 } else {
678 sta = NULL; 701 sta = NULL;
679 mvmsta = NULL; 702 mvmsta = NULL;