diff options
author | Felix Fietkau <nbd@openwrt.org> | 2011-04-17 17:28:09 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-04-19 15:38:06 -0400 |
commit | 5519541d5a5f19893546883547e2f0f2e5934df7 (patch) | |
tree | ae581edfed4ce3382b22076cb03174756e004830 | |
parent | 8e22ad323fb5b7cefb572bd8730e3abef95cdf90 (diff) |
ath9k: fix powersave frame filtering/buffering in AP mode
This patch fixes a long standing issue of pending packets in the queue being
sent (and retransmitted many times) to sleeping stations.
This was made worse by aggregation through driver-internal retransmitting
of A-MDPU subframes.
Previously the hardware tx filter was cleared unconditionally for every
single packet - with this patch it uses the IEEE80211_TX_CTL_CLEAR_PS_FILT
for unaggregated frames.
A sta_notify driver op is added to stop aggregation for stations when they
enter powersave mode. Subframes stay buffered inside the driver, to ensure
that the BlockAck window keeps a sane state.
Since the driver uses software aggregation, the clearing of the tx filter
needs to be handled by the driver instead of mac80211 for aggregated frames.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ar9002_mac.c | 12 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ar9003_mac.c | 12 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ath9k.h | 6 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hw-ops.h | 5 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hw.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/mac.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 22 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 101 |
8 files changed, 145 insertions, 15 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index 8dd8f6308502..c338efbccf40 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c | |||
@@ -290,7 +290,6 @@ static void ar9002_hw_set11n_txdesc(struct ath_hw *ah, void *ds, | |||
290 | | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) | 290 | | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) |
291 | | SM(txPower, AR_XmitPower) | 291 | | SM(txPower, AR_XmitPower) |
292 | | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) | 292 | | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) |
293 | | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) | ||
294 | | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) | 293 | | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) |
295 | | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0); | 294 | | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0); |
296 | 295 | ||
@@ -311,6 +310,16 @@ static void ar9002_hw_set11n_txdesc(struct ath_hw *ah, void *ds, | |||
311 | } | 310 | } |
312 | } | 311 | } |
313 | 312 | ||
313 | static void ar9002_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val) | ||
314 | { | ||
315 | struct ar5416_desc *ads = AR5416DESC(ds); | ||
316 | |||
317 | if (val) | ||
318 | ads->ds_ctl0 |= AR_ClrDestMask; | ||
319 | else | ||
320 | ads->ds_ctl0 &= ~AR_ClrDestMask; | ||
321 | } | ||
322 | |||
314 | static void ar9002_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, | 323 | static void ar9002_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, |
315 | void *lastds, | 324 | void *lastds, |
316 | u32 durUpdateEn, u32 rtsctsRate, | 325 | u32 durUpdateEn, u32 rtsctsRate, |
@@ -448,4 +457,5 @@ void ar9002_hw_attach_mac_ops(struct ath_hw *ah) | |||
448 | ops->set11n_aggr_last = ar9002_hw_set11n_aggr_last; | 457 | ops->set11n_aggr_last = ar9002_hw_set11n_aggr_last; |
449 | ops->clr11n_aggr = ar9002_hw_clr11n_aggr; | 458 | ops->clr11n_aggr = ar9002_hw_clr11n_aggr; |
450 | ops->set11n_burstduration = ar9002_hw_set11n_burstduration; | 459 | ops->set11n_burstduration = ar9002_hw_set11n_burstduration; |
460 | ops->set_clrdmask = ar9002_hw_set_clrdmask; | ||
451 | } | 461 | } |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 724ac2464ad5..c1264d60c499 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c | |||
@@ -329,7 +329,6 @@ static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds, | |||
329 | | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) | 329 | | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) |
330 | | SM(txpower, AR_XmitPower) | 330 | | SM(txpower, AR_XmitPower) |
331 | | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) | 331 | | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) |
332 | | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) | ||
333 | | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) | 332 | | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) |
334 | | (flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0); | 333 | | (flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0); |
335 | 334 | ||
@@ -350,6 +349,16 @@ static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds, | |||
350 | ads->ctl22 = 0; | 349 | ads->ctl22 = 0; |
351 | } | 350 | } |
352 | 351 | ||
352 | static void ar9003_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val) | ||
353 | { | ||
354 | struct ar9003_txc *ads = (struct ar9003_txc *) ds; | ||
355 | |||
356 | if (val) | ||
357 | ads->ctl11 |= AR_ClrDestMask; | ||
358 | else | ||
359 | ads->ctl11 &= ~AR_ClrDestMask; | ||
360 | } | ||
361 | |||
353 | static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, | 362 | static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, |
354 | void *lastds, | 363 | void *lastds, |
355 | u32 durUpdateEn, u32 rtsctsRate, | 364 | u32 durUpdateEn, u32 rtsctsRate, |
@@ -510,6 +519,7 @@ void ar9003_hw_attach_mac_ops(struct ath_hw *hw) | |||
510 | ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last; | 519 | ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last; |
511 | ops->clr11n_aggr = ar9003_hw_clr11n_aggr; | 520 | ops->clr11n_aggr = ar9003_hw_clr11n_aggr; |
512 | ops->set11n_burstduration = ar9003_hw_set11n_burstduration; | 521 | ops->set11n_burstduration = ar9003_hw_set11n_burstduration; |
522 | ops->set_clrdmask = ar9003_hw_set_clrdmask; | ||
513 | } | 523 | } |
514 | 524 | ||
515 | void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size) | 525 | void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size) |
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 77ad407e9fa3..a2ddabf0ca2f 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -200,6 +200,7 @@ struct ath_atx_ac { | |||
200 | int sched; | 200 | int sched; |
201 | struct list_head list; | 201 | struct list_head list; |
202 | struct list_head tid_q; | 202 | struct list_head tid_q; |
203 | bool clear_ps_filter; | ||
203 | }; | 204 | }; |
204 | 205 | ||
205 | struct ath_frame_info { | 206 | struct ath_frame_info { |
@@ -257,6 +258,8 @@ struct ath_node { | |||
257 | struct ath_atx_ac ac[WME_NUM_AC]; | 258 | struct ath_atx_ac ac[WME_NUM_AC]; |
258 | u16 maxampdu; | 259 | u16 maxampdu; |
259 | u8 mpdudensity; | 260 | u8 mpdudensity; |
261 | |||
262 | bool sleeping; | ||
260 | }; | 263 | }; |
261 | 264 | ||
262 | #define AGGR_CLEANUP BIT(1) | 265 | #define AGGR_CLEANUP BIT(1) |
@@ -338,6 +341,9 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, | |||
338 | void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); | 341 | void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); |
339 | void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); | 342 | void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); |
340 | 343 | ||
344 | void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an); | ||
345 | bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an); | ||
346 | |||
341 | /********/ | 347 | /********/ |
342 | /* VIFs */ | 348 | /* VIFs */ |
343 | /********/ | 349 | /********/ |
diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index 22ee888b0baf..9dd90a85ad63 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h | |||
@@ -122,6 +122,11 @@ static inline void ath9k_hw_set11n_burstduration(struct ath_hw *ah, void *ds, | |||
122 | ath9k_hw_ops(ah)->set11n_burstduration(ah, ds, burstDuration); | 122 | ath9k_hw_ops(ah)->set11n_burstduration(ah, ds, burstDuration); |
123 | } | 123 | } |
124 | 124 | ||
125 | static inline void ath9k_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val) | ||
126 | { | ||
127 | ath9k_hw_ops(ah)->set_clrdmask(ah, ds, val); | ||
128 | } | ||
129 | |||
125 | /* Private hardware call ops */ | 130 | /* Private hardware call ops */ |
126 | 131 | ||
127 | /* PHY ops */ | 132 | /* PHY ops */ |
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 073bc9e1c792..1018d6cbd530 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h | |||
@@ -626,6 +626,7 @@ struct ath_hw_ops { | |||
626 | void (*clr11n_aggr)(struct ath_hw *ah, void *ds); | 626 | void (*clr11n_aggr)(struct ath_hw *ah, void *ds); |
627 | void (*set11n_burstduration)(struct ath_hw *ah, void *ds, | 627 | void (*set11n_burstduration)(struct ath_hw *ah, void *ds, |
628 | u32 burstDuration); | 628 | u32 burstDuration); |
629 | void (*set_clrdmask)(struct ath_hw *ah, void *ds, bool val); | ||
629 | }; | 630 | }; |
630 | 631 | ||
631 | struct ath_nf_limits { | 632 | struct ath_nf_limits { |
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index b2b2ff852c32..a60edb44127b 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h | |||
@@ -239,7 +239,6 @@ struct ath_desc { | |||
239 | void *ds_vdata; | 239 | void *ds_vdata; |
240 | } __packed __aligned(4); | 240 | } __packed __aligned(4); |
241 | 241 | ||
242 | #define ATH9K_TXDESC_CLRDMASK 0x0001 | ||
243 | #define ATH9K_TXDESC_NOACK 0x0002 | 242 | #define ATH9K_TXDESC_NOACK 0x0002 |
244 | #define ATH9K_TXDESC_RTSENA 0x0004 | 243 | #define ATH9K_TXDESC_RTSENA 0x0004 |
245 | #define ATH9K_TXDESC_CTSENA 0x0008 | 244 | #define ATH9K_TXDESC_CTSENA 0x0008 |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a55a8929810b..01df5876fda1 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -1749,6 +1749,27 @@ static int ath9k_sta_remove(struct ieee80211_hw *hw, | |||
1749 | return 0; | 1749 | return 0; |
1750 | } | 1750 | } |
1751 | 1751 | ||
1752 | static void ath9k_sta_notify(struct ieee80211_hw *hw, | ||
1753 | struct ieee80211_vif *vif, | ||
1754 | enum sta_notify_cmd cmd, | ||
1755 | struct ieee80211_sta *sta) | ||
1756 | { | ||
1757 | struct ath_softc *sc = hw->priv; | ||
1758 | struct ath_node *an = (struct ath_node *) sta->drv_priv; | ||
1759 | |||
1760 | switch (cmd) { | ||
1761 | case STA_NOTIFY_SLEEP: | ||
1762 | an->sleeping = true; | ||
1763 | if (ath_tx_aggr_sleep(sc, an)) | ||
1764 | ieee80211_sta_set_tim(sta); | ||
1765 | break; | ||
1766 | case STA_NOTIFY_AWAKE: | ||
1767 | an->sleeping = false; | ||
1768 | ath_tx_aggr_wakeup(sc, an); | ||
1769 | break; | ||
1770 | } | ||
1771 | } | ||
1772 | |||
1752 | static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, | 1773 | static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, |
1753 | const struct ieee80211_tx_queue_params *params) | 1774 | const struct ieee80211_tx_queue_params *params) |
1754 | { | 1775 | { |
@@ -2230,6 +2251,7 @@ struct ieee80211_ops ath9k_ops = { | |||
2230 | .configure_filter = ath9k_configure_filter, | 2251 | .configure_filter = ath9k_configure_filter, |
2231 | .sta_add = ath9k_sta_add, | 2252 | .sta_add = ath9k_sta_add, |
2232 | .sta_remove = ath9k_sta_remove, | 2253 | .sta_remove = ath9k_sta_remove, |
2254 | .sta_notify = ath9k_sta_notify, | ||
2233 | .conf_tx = ath9k_conf_tx, | 2255 | .conf_tx = ath9k_conf_tx, |
2234 | .bss_info_changed = ath9k_bss_info_changed, | 2256 | .bss_info_changed = ath9k_bss_info_changed, |
2235 | .set_key = ath9k_set_key, | 2257 | .set_key = ath9k_set_key, |
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 5943bdc4c8f9..48ff8c22ba1f 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -357,6 +357,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
357 | struct ath_frame_info *fi; | 357 | struct ath_frame_info *fi; |
358 | int nframes; | 358 | int nframes; |
359 | u8 tidno; | 359 | u8 tidno; |
360 | bool clear_filter; | ||
360 | 361 | ||
361 | skb = bf->bf_mpdu; | 362 | skb = bf->bf_mpdu; |
362 | hdr = (struct ieee80211_hdr *)skb->data; | 363 | hdr = (struct ieee80211_hdr *)skb->data; |
@@ -441,22 +442,24 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
441 | /* transmit completion */ | 442 | /* transmit completion */ |
442 | acked_cnt++; | 443 | acked_cnt++; |
443 | } else { | 444 | } else { |
444 | if (!(tid->state & AGGR_CLEANUP) && retry) { | 445 | if ((tid->state & AGGR_CLEANUP) || !retry) { |
445 | if (fi->retries < ATH_MAX_SW_RETRIES) { | ||
446 | ath_tx_set_retry(sc, txq, bf->bf_mpdu); | ||
447 | txpending = 1; | ||
448 | } else { | ||
449 | bf->bf_state.bf_type |= BUF_XRETRY; | ||
450 | txfail = 1; | ||
451 | sendbar = 1; | ||
452 | txfail_cnt++; | ||
453 | } | ||
454 | } else { | ||
455 | /* | 446 | /* |
456 | * cleanup in progress, just fail | 447 | * cleanup in progress, just fail |
457 | * the un-acked sub-frames | 448 | * the un-acked sub-frames |
458 | */ | 449 | */ |
459 | txfail = 1; | 450 | txfail = 1; |
451 | } else if (fi->retries < ATH_MAX_SW_RETRIES) { | ||
452 | if (!(ts->ts_status & ATH9K_TXERR_FILT) || | ||
453 | !an->sleeping) | ||
454 | ath_tx_set_retry(sc, txq, bf->bf_mpdu); | ||
455 | |||
456 | clear_filter = true; | ||
457 | txpending = 1; | ||
458 | } else { | ||
459 | bf->bf_state.bf_type |= BUF_XRETRY; | ||
460 | txfail = 1; | ||
461 | sendbar = 1; | ||
462 | txfail_cnt++; | ||
460 | } | 463 | } |
461 | } | 464 | } |
462 | 465 | ||
@@ -496,6 +499,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
496 | !txfail, sendbar); | 499 | !txfail, sendbar); |
497 | } else { | 500 | } else { |
498 | /* retry the un-acked ones */ | 501 | /* retry the un-acked ones */ |
502 | ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, false); | ||
499 | if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) { | 503 | if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) { |
500 | if (bf->bf_next == NULL && bf_last->bf_stale) { | 504 | if (bf->bf_next == NULL && bf_last->bf_stale) { |
501 | struct ath_buf *tbf; | 505 | struct ath_buf *tbf; |
@@ -546,7 +550,12 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
546 | 550 | ||
547 | /* prepend un-acked frames to the beginning of the pending frame queue */ | 551 | /* prepend un-acked frames to the beginning of the pending frame queue */ |
548 | if (!list_empty(&bf_pending)) { | 552 | if (!list_empty(&bf_pending)) { |
553 | if (an->sleeping) | ||
554 | ieee80211_sta_set_tim(sta); | ||
555 | |||
549 | spin_lock_bh(&txq->axq_lock); | 556 | spin_lock_bh(&txq->axq_lock); |
557 | if (clear_filter) | ||
558 | tid->ac->clear_ps_filter = true; | ||
550 | list_splice(&bf_pending, &tid->buf_q); | 559 | list_splice(&bf_pending, &tid->buf_q); |
551 | ath_tx_queue_tid(txq, tid); | 560 | ath_tx_queue_tid(txq, tid); |
552 | spin_unlock_bh(&txq->axq_lock); | 561 | spin_unlock_bh(&txq->axq_lock); |
@@ -816,6 +825,11 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
816 | bf = list_first_entry(&bf_q, struct ath_buf, list); | 825 | bf = list_first_entry(&bf_q, struct ath_buf, list); |
817 | bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list); | 826 | bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list); |
818 | 827 | ||
828 | if (tid->ac->clear_ps_filter) { | ||
829 | tid->ac->clear_ps_filter = false; | ||
830 | ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true); | ||
831 | } | ||
832 | |||
819 | /* if only one frame, send as non-aggregate */ | 833 | /* if only one frame, send as non-aggregate */ |
820 | if (bf == bf->bf_lastbf) { | 834 | if (bf == bf->bf_lastbf) { |
821 | fi = get_frame_info(bf->bf_mpdu); | 835 | fi = get_frame_info(bf->bf_mpdu); |
@@ -896,6 +910,67 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) | |||
896 | ath_tx_flush_tid(sc, txtid); | 910 | ath_tx_flush_tid(sc, txtid); |
897 | } | 911 | } |
898 | 912 | ||
913 | bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an) | ||
914 | { | ||
915 | struct ath_atx_tid *tid; | ||
916 | struct ath_atx_ac *ac; | ||
917 | struct ath_txq *txq; | ||
918 | bool buffered = false; | ||
919 | int tidno; | ||
920 | |||
921 | for (tidno = 0, tid = &an->tid[tidno]; | ||
922 | tidno < WME_NUM_TID; tidno++, tid++) { | ||
923 | |||
924 | if (!tid->sched) | ||
925 | continue; | ||
926 | |||
927 | ac = tid->ac; | ||
928 | txq = ac->txq; | ||
929 | |||
930 | spin_lock_bh(&txq->axq_lock); | ||
931 | |||
932 | if (!list_empty(&tid->buf_q)) | ||
933 | buffered = true; | ||
934 | |||
935 | tid->sched = false; | ||
936 | list_del(&tid->list); | ||
937 | |||
938 | if (ac->sched) { | ||
939 | ac->sched = false; | ||
940 | list_del(&ac->list); | ||
941 | } | ||
942 | |||
943 | spin_unlock_bh(&txq->axq_lock); | ||
944 | } | ||
945 | |||
946 | return buffered; | ||
947 | } | ||
948 | |||
949 | void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) | ||
950 | { | ||
951 | struct ath_atx_tid *tid; | ||
952 | struct ath_atx_ac *ac; | ||
953 | struct ath_txq *txq; | ||
954 | int tidno; | ||
955 | |||
956 | for (tidno = 0, tid = &an->tid[tidno]; | ||
957 | tidno < WME_NUM_TID; tidno++, tid++) { | ||
958 | |||
959 | ac = tid->ac; | ||
960 | txq = ac->txq; | ||
961 | |||
962 | spin_lock_bh(&txq->axq_lock); | ||
963 | ac->clear_ps_filter = true; | ||
964 | |||
965 | if (!list_empty(&tid->buf_q) && !tid->paused) { | ||
966 | ath_tx_queue_tid(txq, tid); | ||
967 | ath_txq_schedule(sc, txq); | ||
968 | } | ||
969 | |||
970 | spin_unlock_bh(&txq->axq_lock); | ||
971 | } | ||
972 | } | ||
973 | |||
899 | void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) | 974 | void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) |
900 | { | 975 | { |
901 | struct ath_atx_tid *txtid; | 976 | struct ath_atx_tid *txtid; |
@@ -1491,7 +1566,6 @@ static int setup_tx_flags(struct sk_buff *skb) | |||
1491 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | 1566 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); |
1492 | int flags = 0; | 1567 | int flags = 0; |
1493 | 1568 | ||
1494 | flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ | ||
1495 | flags |= ATH9K_TXDESC_INTREQ; | 1569 | flags |= ATH9K_TXDESC_INTREQ; |
1496 | 1570 | ||
1497 | if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) | 1571 | if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) |
@@ -1754,6 +1828,9 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, | |||
1754 | if (txctl->paprd) | 1828 | if (txctl->paprd) |
1755 | bf->bf_state.bfs_paprd_timestamp = jiffies; | 1829 | bf->bf_state.bfs_paprd_timestamp = jiffies; |
1756 | 1830 | ||
1831 | if (tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) | ||
1832 | ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true); | ||
1833 | |||
1757 | ath_tx_send_normal(sc, txctl->txq, tid, &bf_head); | 1834 | ath_tx_send_normal(sc, txctl->txq, tid, &bf_head); |
1758 | } | 1835 | } |
1759 | 1836 | ||