aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm/mac80211.c
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/iwlwifi/mvm/mac80211.c
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/iwlwifi/mvm/mac80211.c')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c59
1 files changed, 50 insertions, 9 deletions
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,