aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2011-04-17 17:28:09 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-04-19 15:38:06 -0400
commit5519541d5a5f19893546883547e2f0f2e5934df7 (patch)
treeae581edfed4ce3382b22076cb03174756e004830
parent8e22ad323fb5b7cefb572bd8730e3abef95cdf90 (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.c12
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_mac.c12
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h6
-rw-r--r--drivers/net/wireless/ath/ath9k/hw-ops.h5
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c22
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c101
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
313static 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
314static void ar9002_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, 323static 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
352static 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
353static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, 362static 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
515void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size) 525void 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
205struct ath_frame_info { 206struct 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,
338void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); 341void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
339void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); 342void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
340 343
344void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
345bool 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
125static 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
631struct ath_nf_limits { 632struct 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
1752static 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
1752static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, 1773static 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
913bool 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
949void 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
899void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) 974void 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