summaryrefslogtreecommitdiffstats
path: root/package/mac80211/patches/540-ath9k_limit_qlen.patch
blob: bf1811bae85c3a5d84e71a54271f6d061a9e38c2 (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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -242,6 +242,7 @@ struct ath_atx_tid {
 	struct ath_node *an;
 	struct ath_atx_ac *ac;
 	unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)];
+	int buf_pending;
 	int bar_index;
 	u16 seq_start;
 	u16 seq_next;
@@ -288,6 +289,9 @@ struct ath_tx_control {
  *  (axq_qnum).
  */
 struct ath_tx {
+	u32 qlen_single;
+	u32 qlen_aggr;
+
 	u16 seq_no;
 	u32 txqsetup;
 	spinlock_t txbuflock;
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -1666,6 +1666,10 @@ int ath9k_init_debug(struct ath_hw *ah)
 			    &fops_interrupt);
 	debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, sc,
 			    &fops_xmit);
+	debugfs_create_u32("qlen_single", S_IRUSR | S_IWUSR,
+			   sc->debug.debugfs_phy, &sc->tx.qlen_single);
+	debugfs_create_u32("qlen_aggr", S_IRUSR | S_IWUSR,
+			   sc->debug.debugfs_phy, &sc->tx.qlen_aggr);
 	debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, sc,
 			    &fops_stations);
 	debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc,
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -392,6 +392,14 @@ static void ath_tx_count_frames(struct a
 	}
 }
 
+static struct ath_atx_tid *ath_get_tid(struct ath_node *an, struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	u8 tidno;
+
+	tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
+	return ATH_AN_2_TID(an, tidno);
+}
 
 static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 				 struct ath_buf *bf, struct list_head *bf_q,
@@ -486,6 +494,8 @@ static void ath_tx_complete_aggr(struct 
 	__skb_queue_head_init(&bf_pending);
 
 	ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad);
+	tid->buf_pending -= nframes;
+
 	while (bf) {
 		u16 seqno = bf->bf_state.seqno;
 
@@ -884,6 +894,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_
 			ath_tx_addto_baw(sc, tid, seqno);
 		bf->bf_state.ndelim = ndelim;
 
+		tid->buf_pending++;
 		__skb_unlink(skb, &tid->buf_q);
 		list_add_tail(&bf->list, bf_q);
 		if (bf_prev)
@@ -1739,6 +1750,8 @@ static void ath_tx_send_ampdu(struct ath
 	/* Add sub-frame to BAW */
 	ath_tx_addto_baw(sc, tid, bf->bf_state.seqno);
 
+	tid->buf_pending++;
+
 	/* Queue to h/w without aggregation */
 	TX_STAT_INC(txctl->txq->axq_qnum, a_queued_hw);
 	bf->bf_lastbf = bf;
@@ -1863,22 +1876,11 @@ error:
 
 /* FIXME: tx power */
 static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb,
-			     struct ath_tx_control *txctl)
+			     struct ath_tx_control *txctl,
+			     struct ath_atx_tid *tid)
 {
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	struct ath_atx_tid *tid = NULL;
 	struct ath_buf *bf;
-	u8 tidno;
-
-	if ((sc->sc_flags & SC_OP_TXAGGR) && txctl->an &&
-		ieee80211_is_data_qos(hdr->frame_control)) {
-		tidno = ieee80211_get_qos_ctl(hdr)[0] &
-			IEEE80211_QOS_CTL_TID_MASK;
-		tid = ATH_AN_2_TID(txctl->an, tidno);
-
-		WARN_ON(tid->ac->txq != txctl->txq);
-	}
 
 	if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && tid) {
 		/*
@@ -1910,6 +1912,7 @@ int ath_tx_start(struct ieee80211_hw *hw
 	struct ieee80211_vif *vif = info->control.vif;
 	struct ath_softc *sc = hw->priv;
 	struct ath_txq *txq = txctl->txq;
+	struct ath_atx_tid *tid = NULL;
 	int padpos, padsize;
 	int frmlen = skb->len + FCS_LEN;
 	int q;
@@ -1952,6 +1955,24 @@ int ath_tx_start(struct ieee80211_hw *hw
 
 	setup_frame_info(hw, skb, frmlen);
 
+	if ((sc->sc_flags & SC_OP_TXAGGR) && txctl->an &&
+	    ieee80211_is_data_qos(hdr->frame_control)) {
+		tid = ath_get_tid(txctl->an, skb);
+
+		WARN_ON(tid->ac->txq != txq);
+	}
+
+	if ((info->flags & IEEE80211_TX_CTL_AMPDU) && tid) {
+		if (sc->tx.qlen_aggr > 0 && skb_queue_len(&tid->buf_q) +
+		    tid->buf_pending >= sc->tx.qlen_aggr)
+			return -ENOMEM;
+	} else {
+		if (sc->tx.qlen_single > 0 &&
+		    txq->axq_depth - txq->axq_ampdu_depth >=
+		      sc->tx.qlen_single)
+			return -ENOMEM;
+	}
+
 	/*
 	 * At this point, the vif, hw_key and sta pointers in the tx control
 	 * info are no longer valid (overwritten by the ath_frame_info data.
@@ -1966,7 +1987,7 @@ int ath_tx_start(struct ieee80211_hw *hw
 		txq->stopped = true;
 	}
 
-	ath_tx_start_dma(sc, skb, txctl);
+	ath_tx_start_dma(sc, skb, txctl, tid);
 
 	ath_txq_unlock(sc, txq);