diff options
-rw-r--r-- | net/mac80211/rx.c | 2 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 65 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 7 | ||||
-rw-r--r-- | net/mac80211/tx.c | 6 |
4 files changed, 51 insertions, 29 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 394e201cde6d..5f572bed1761 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1107,6 +1107,8 @@ static void sta_ps_end(struct sta_info *sta) | |||
1107 | return; | 1107 | return; |
1108 | } | 1108 | } |
1109 | 1109 | ||
1110 | set_sta_flag(sta, WLAN_STA_PS_DELIVER); | ||
1111 | clear_sta_flag(sta, WLAN_STA_PS_STA); | ||
1110 | ieee80211_sta_ps_deliver_wakeup(sta); | 1112 | ieee80211_sta_ps_deliver_wakeup(sta); |
1111 | } | 1113 | } |
1112 | 1114 | ||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a9b46d8ea22f..ae7c16ad5f22 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -100,7 +100,8 @@ static void __cleanup_single_sta(struct sta_info *sta) | |||
100 | struct ps_data *ps; | 100 | struct ps_data *ps; |
101 | 101 | ||
102 | if (test_sta_flag(sta, WLAN_STA_PS_STA) || | 102 | if (test_sta_flag(sta, WLAN_STA_PS_STA) || |
103 | test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { | 103 | test_sta_flag(sta, WLAN_STA_PS_DRIVER) || |
104 | test_sta_flag(sta, WLAN_STA_PS_DELIVER)) { | ||
104 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP || | 105 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP || |
105 | sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 106 | sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
106 | ps = &sdata->bss->ps; | 107 | ps = &sdata->bss->ps; |
@@ -111,6 +112,7 @@ static void __cleanup_single_sta(struct sta_info *sta) | |||
111 | 112 | ||
112 | clear_sta_flag(sta, WLAN_STA_PS_STA); | 113 | clear_sta_flag(sta, WLAN_STA_PS_STA); |
113 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | 114 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); |
115 | clear_sta_flag(sta, WLAN_STA_PS_DELIVER); | ||
114 | 116 | ||
115 | atomic_dec(&ps->num_sta_ps); | 117 | atomic_dec(&ps->num_sta_ps); |
116 | sta_info_recalc_tim(sta); | 118 | sta_info_recalc_tim(sta); |
@@ -125,7 +127,7 @@ static void __cleanup_single_sta(struct sta_info *sta) | |||
125 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 127 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
126 | mesh_sta_cleanup(sta); | 128 | mesh_sta_cleanup(sta); |
127 | 129 | ||
128 | cancel_work_sync(&sta->drv_unblock_wk); | 130 | cancel_work_sync(&sta->drv_deliver_wk); |
129 | 131 | ||
130 | /* | 132 | /* |
131 | * Destroy aggregation state here. It would be nice to wait for the | 133 | * Destroy aggregation state here. It would be nice to wait for the |
@@ -253,33 +255,23 @@ static void sta_info_hash_add(struct ieee80211_local *local, | |||
253 | rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta); | 255 | rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta); |
254 | } | 256 | } |
255 | 257 | ||
256 | static void sta_unblock(struct work_struct *wk) | 258 | static void sta_deliver_ps_frames(struct work_struct *wk) |
257 | { | 259 | { |
258 | struct sta_info *sta; | 260 | struct sta_info *sta; |
259 | 261 | ||
260 | sta = container_of(wk, struct sta_info, drv_unblock_wk); | 262 | sta = container_of(wk, struct sta_info, drv_deliver_wk); |
261 | 263 | ||
262 | if (sta->dead) | 264 | if (sta->dead) |
263 | return; | 265 | return; |
264 | 266 | ||
265 | if (!test_sta_flag(sta, WLAN_STA_PS_STA)) { | 267 | local_bh_disable(); |
266 | local_bh_disable(); | 268 | if (!test_sta_flag(sta, WLAN_STA_PS_STA)) |
267 | ieee80211_sta_ps_deliver_wakeup(sta); | 269 | ieee80211_sta_ps_deliver_wakeup(sta); |
268 | local_bh_enable(); | 270 | else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL)) |
269 | } else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL)) { | ||
270 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
271 | |||
272 | local_bh_disable(); | ||
273 | ieee80211_sta_ps_deliver_poll_response(sta); | 271 | ieee80211_sta_ps_deliver_poll_response(sta); |
274 | local_bh_enable(); | 272 | else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD)) |
275 | } else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD)) { | ||
276 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
277 | |||
278 | local_bh_disable(); | ||
279 | ieee80211_sta_ps_deliver_uapsd(sta); | 273 | ieee80211_sta_ps_deliver_uapsd(sta); |
280 | local_bh_enable(); | 274 | local_bh_enable(); |
281 | } else | ||
282 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
283 | } | 275 | } |
284 | 276 | ||
285 | static int sta_prepare_rate_control(struct ieee80211_local *local, | 277 | static int sta_prepare_rate_control(struct ieee80211_local *local, |
@@ -341,7 +333,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
341 | 333 | ||
342 | spin_lock_init(&sta->lock); | 334 | spin_lock_init(&sta->lock); |
343 | spin_lock_init(&sta->ps_lock); | 335 | spin_lock_init(&sta->ps_lock); |
344 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); | 336 | INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames); |
345 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); | 337 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); |
346 | mutex_init(&sta->ampdu_mlme.mtx); | 338 | mutex_init(&sta->ampdu_mlme.mtx); |
347 | #ifdef CONFIG_MAC80211_MESH | 339 | #ifdef CONFIG_MAC80211_MESH |
@@ -1141,8 +1133,15 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
1141 | } | 1133 | } |
1142 | 1134 | ||
1143 | ieee80211_add_pending_skbs(local, &pending); | 1135 | ieee80211_add_pending_skbs(local, &pending); |
1144 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | 1136 | |
1145 | clear_sta_flag(sta, WLAN_STA_PS_STA); | 1137 | /* now we're no longer in the deliver code */ |
1138 | clear_sta_flag(sta, WLAN_STA_PS_DELIVER); | ||
1139 | |||
1140 | /* The station might have polled and then woken up before we responded, | ||
1141 | * so clear these flags now to avoid them sticking around. | ||
1142 | */ | ||
1143 | clear_sta_flag(sta, WLAN_STA_PSPOLL); | ||
1144 | clear_sta_flag(sta, WLAN_STA_UAPSD); | ||
1146 | spin_unlock(&sta->ps_lock); | 1145 | spin_unlock(&sta->ps_lock); |
1147 | 1146 | ||
1148 | atomic_dec(&ps->num_sta_ps); | 1147 | atomic_dec(&ps->num_sta_ps); |
@@ -1543,10 +1542,26 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, | |||
1543 | 1542 | ||
1544 | trace_api_sta_block_awake(sta->local, pubsta, block); | 1543 | trace_api_sta_block_awake(sta->local, pubsta, block); |
1545 | 1544 | ||
1546 | if (block) | 1545 | if (block) { |
1547 | set_sta_flag(sta, WLAN_STA_PS_DRIVER); | 1546 | set_sta_flag(sta, WLAN_STA_PS_DRIVER); |
1548 | else if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) | 1547 | return; |
1549 | ieee80211_queue_work(hw, &sta->drv_unblock_wk); | 1548 | } |
1549 | |||
1550 | if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER)) | ||
1551 | return; | ||
1552 | |||
1553 | if (!test_sta_flag(sta, WLAN_STA_PS_STA)) { | ||
1554 | set_sta_flag(sta, WLAN_STA_PS_DELIVER); | ||
1555 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
1556 | ieee80211_queue_work(hw, &sta->drv_deliver_wk); | ||
1557 | } else if (test_sta_flag(sta, WLAN_STA_PSPOLL) || | ||
1558 | test_sta_flag(sta, WLAN_STA_UAPSD)) { | ||
1559 | /* must be asleep in this case */ | ||
1560 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
1561 | ieee80211_queue_work(hw, &sta->drv_deliver_wk); | ||
1562 | } else { | ||
1563 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
1564 | } | ||
1550 | } | 1565 | } |
1551 | EXPORT_SYMBOL(ieee80211_sta_block_awake); | 1566 | EXPORT_SYMBOL(ieee80211_sta_block_awake); |
1552 | 1567 | ||
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 4acc5fc402fa..dee0b645b34c 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -58,6 +58,8 @@ | |||
58 | * @WLAN_STA_TOFFSET_KNOWN: toffset calculated for this station is valid. | 58 | * @WLAN_STA_TOFFSET_KNOWN: toffset calculated for this station is valid. |
59 | * @WLAN_STA_MPSP_OWNER: local STA is owner of a mesh Peer Service Period. | 59 | * @WLAN_STA_MPSP_OWNER: local STA is owner of a mesh Peer Service Period. |
60 | * @WLAN_STA_MPSP_RECIPIENT: local STA is recipient of a MPSP. | 60 | * @WLAN_STA_MPSP_RECIPIENT: local STA is recipient of a MPSP. |
61 | * @WLAN_STA_PS_DELIVER: station woke up, but we're still blocking TX | ||
62 | * until pending frames are delivered | ||
61 | */ | 63 | */ |
62 | enum ieee80211_sta_info_flags { | 64 | enum ieee80211_sta_info_flags { |
63 | WLAN_STA_AUTH, | 65 | WLAN_STA_AUTH, |
@@ -82,6 +84,7 @@ enum ieee80211_sta_info_flags { | |||
82 | WLAN_STA_TOFFSET_KNOWN, | 84 | WLAN_STA_TOFFSET_KNOWN, |
83 | WLAN_STA_MPSP_OWNER, | 85 | WLAN_STA_MPSP_OWNER, |
84 | WLAN_STA_MPSP_RECIPIENT, | 86 | WLAN_STA_MPSP_RECIPIENT, |
87 | WLAN_STA_PS_DELIVER, | ||
85 | }; | 88 | }; |
86 | 89 | ||
87 | #define ADDBA_RESP_INTERVAL HZ | 90 | #define ADDBA_RESP_INTERVAL HZ |
@@ -265,7 +268,7 @@ struct ieee80211_tx_latency_stat { | |||
265 | * @last_rx_rate_vht_nss: rx status nss of last data packet | 268 | * @last_rx_rate_vht_nss: rx status nss of last data packet |
266 | * @lock: used for locking all fields that require locking, see comments | 269 | * @lock: used for locking all fields that require locking, see comments |
267 | * in the header file. | 270 | * in the header file. |
268 | * @drv_unblock_wk: used for driver PS unblocking | 271 | * @drv_deliver_wk: used for delivering frames after driver PS unblocking |
269 | * @listen_interval: listen interval of this station, when we're acting as AP | 272 | * @listen_interval: listen interval of this station, when we're acting as AP |
270 | * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly | 273 | * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly |
271 | * @ps_lock: used for powersave (when mac80211 is the AP) related locking | 274 | * @ps_lock: used for powersave (when mac80211 is the AP) related locking |
@@ -345,7 +348,7 @@ struct sta_info { | |||
345 | void *rate_ctrl_priv; | 348 | void *rate_ctrl_priv; |
346 | spinlock_t lock; | 349 | spinlock_t lock; |
347 | 350 | ||
348 | struct work_struct drv_unblock_wk; | 351 | struct work_struct drv_deliver_wk; |
349 | 352 | ||
350 | u16 listen_interval; | 353 | u16 listen_interval; |
351 | 354 | ||
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 5214686d9fd1..8170d9945d6d 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -469,7 +469,8 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) | |||
469 | return TX_CONTINUE; | 469 | return TX_CONTINUE; |
470 | 470 | ||
471 | if (unlikely((test_sta_flag(sta, WLAN_STA_PS_STA) || | 471 | if (unlikely((test_sta_flag(sta, WLAN_STA_PS_STA) || |
472 | test_sta_flag(sta, WLAN_STA_PS_DRIVER)) && | 472 | test_sta_flag(sta, WLAN_STA_PS_DRIVER) || |
473 | test_sta_flag(sta, WLAN_STA_PS_DELIVER)) && | ||
473 | !(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) { | 474 | !(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) { |
474 | int ac = skb_get_queue_mapping(tx->skb); | 475 | int ac = skb_get_queue_mapping(tx->skb); |
475 | 476 | ||
@@ -486,7 +487,8 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) | |||
486 | * ahead and Tx the packet. | 487 | * ahead and Tx the packet. |
487 | */ | 488 | */ |
488 | if (!test_sta_flag(sta, WLAN_STA_PS_STA) && | 489 | if (!test_sta_flag(sta, WLAN_STA_PS_STA) && |
489 | !test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { | 490 | !test_sta_flag(sta, WLAN_STA_PS_DRIVER) && |
491 | !test_sta_flag(sta, WLAN_STA_PS_DELIVER)) { | ||
490 | spin_unlock(&sta->ps_lock); | 492 | spin_unlock(&sta->ps_lock); |
491 | return TX_CONTINUE; | 493 | return TX_CONTINUE; |
492 | } | 494 | } |