aboutsummaryrefslogtreecommitdiffstats
path: root/package/kernel/mac80211/patches/301-ath9k-limit-retries-for-powersave-response-frames.patch
blob: 33b21e6a0ae717edffc24ff39df6f067849b0cf8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
From: Felix Fietkau <nbd@openwrt.org>
Date: Thu, 2 Jul 2015 15:20:56 +0200
Subject: [PATCH] ath9k: limit retries for powersave response frames

In some cases, the channel might be busy enough that an ath9k AP's
response to PS-Poll frames might be too slow and the station has already
gone to sleep. To avoid wasting too much airtime on this, limit the
number of retries on such frames and ensure that no sample rate gets
used.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---

--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -136,10 +136,25 @@ static void ath_send_bar(struct ath_atx_
 }
 
 static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
-			  struct ath_buf *bf)
+			  struct ath_buf *bf, bool ps)
 {
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu);
+
+	if (ps) {
+		/* Clear the first rate to avoid using a sample rate for PS frames */
+		info->control.rates[0].idx = -1;
+		info->control.rates[0].count = 0;
+	}
+
 	ieee80211_get_tx_rates(vif, sta, bf->bf_mpdu, bf->rates,
 			       ARRAY_SIZE(bf->rates));
+	if (!ps)
+		return;
+
+	if (bf->rates[0].count > 2)
+		bf->rates[0].count = 2;
+
+	bf->rates[1].idx = -1;
 }
 
 static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
@@ -1419,7 +1434,7 @@ ath_tx_form_burst(struct ath_softc *sc,
 		if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
 			break;
 
-		ath_set_rates(tid->an->vif, tid->an->sta, bf);
+		ath_set_rates(tid->an->vif, tid->an->sta, bf, false);
 	} while (1);
 }
 
@@ -1450,7 +1465,7 @@ static bool ath_tx_sched_aggr(struct ath
 		return false;
 	}
 
-	ath_set_rates(tid->an->vif, tid->an->sta, bf);
+	ath_set_rates(tid->an->vif, tid->an->sta, bf, false);
 	if (aggr)
 		last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf,
 					tid_q, &aggr_len);
@@ -1632,7 +1647,7 @@ void ath9k_release_buffered_frames(struc
 
 			__skb_unlink(bf->bf_mpdu, tid_q);
 			list_add_tail(&bf->list, &bf_q);
-			ath_set_rates(tid->an->vif, tid->an->sta, bf);
+			ath_set_rates(tid->an->vif, tid->an->sta, bf, true);
 			if (bf_isampdu(bf)) {
 				ath_tx_addto_baw(sc, tid, bf);
 				bf->bf_state.bf_type &= ~BUF_AGGR;
@@ -2278,7 +2293,7 @@ int ath_tx_start(struct ieee80211_hw *hw
 	struct ath_txq *txq = txctl->txq;
 	struct ath_atx_tid *tid = NULL;
 	struct ath_buf *bf;
-	bool queue, skip_uapsd = false, ps_resp;
+	bool queue, ps_resp;
 	int q, ret;
 
 	if (vif)
@@ -2325,13 +2340,13 @@ int ath_tx_start(struct ieee80211_hw *hw
 		if (!txctl->an)
 			txctl->an = &avp->mcast_node;
 		queue = true;
-		skip_uapsd = true;
+		ps_resp = false;
 	}
 
 	if (txctl->an && queue)
 		tid = ath_get_skb_tid(sc, txctl->an, skb);
 
-	if (!skip_uapsd && ps_resp) {
+	if (ps_resp) {
 		ath_txq_unlock(sc, txq);
 		txq = sc->tx.uapsdq;
 		ath_txq_lock(sc, txq);
@@ -2369,7 +2384,7 @@ int ath_tx_start(struct ieee80211_hw *hw
 	if (txctl->paprd)
 		bf->bf_state.bfs_paprd_timestamp = jiffies;
 
-	ath_set_rates(vif, sta, bf);
+	ath_set_rates(vif, sta, bf, ps_resp);
 	ath_tx_send_normal(sc, txq, tid, skb);
 
 out:
@@ -2408,7 +2423,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw
 			break;
 
 		bf->bf_lastbf = bf;
-		ath_set_rates(vif, NULL, bf);
+		ath_set_rates(vif, NULL, bf, false);
 		ath_buf_set_rate(sc, bf, &info, fi->framelen, false);
 		duration += info.rates[0].PktDuration;
 		if (bf_tail)
@@ -2911,7 +2926,7 @@ int ath9k_tx99_send(struct ath_softc *sc
 		return -EINVAL;
 	}
 
-	ath_set_rates(sc->tx99_vif, NULL, bf);
+	ath_set_rates(sc->tx99_vif, NULL, bf, false);
 
 	ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, bf->bf_daddr);
 	ath9k_hw_tx99_start(sc->sc_ah, txctl->txq->axq_qnum);