diff options
author | Sujith <Sujith.Manoharan@atheros.com> | 2008-10-29 00:49:01 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-11-10 15:17:32 -0500 |
commit | dca3edb88ef567671886a85c5e40d491ccecf934 (patch) | |
tree | 14a8a876decc06313ba548080dbb9c2740b9358f /drivers | |
parent | 7f959032bbee5eedaf4c606d11f0c5d41498644e (diff) |
ath9k: Remove internal RX A-MPDU processing
mac80211 has RX A-MPDU reordering support.
Use that and remove redundant RX processing within the driver.
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/ath9k/core.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/core.h | 43 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/main.c | 36 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/recv.c | 501 |
4 files changed, 2 insertions, 584 deletions
diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index d13844647f93..5f5184acb274 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c | |||
@@ -1189,8 +1189,6 @@ void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) | |||
1189 | 1189 | ||
1190 | if (sc->sc_flags & SC_OP_TXAGGR) | 1190 | if (sc->sc_flags & SC_OP_TXAGGR) |
1191 | ath_tx_node_init(sc, an); | 1191 | ath_tx_node_init(sc, an); |
1192 | if (sc->sc_flags & SC_OP_RXAGGR) | ||
1193 | ath_rx_node_init(sc, an); | ||
1194 | 1192 | ||
1195 | an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + | 1193 | an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + |
1196 | sta->ht_cap.ampdu_factor); | 1194 | sta->ht_cap.ampdu_factor); |
@@ -1208,8 +1206,6 @@ void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) | |||
1208 | 1206 | ||
1209 | if (sc->sc_flags & SC_OP_TXAGGR) | 1207 | if (sc->sc_flags & SC_OP_TXAGGR) |
1210 | ath_tx_node_cleanup(sc, an); | 1208 | ath_tx_node_cleanup(sc, an); |
1211 | if (sc->sc_flags & SC_OP_RXAGGR) | ||
1212 | ath_rx_node_cleanup(sc, an); | ||
1213 | } | 1209 | } |
1214 | 1210 | ||
1215 | /* | 1211 | /* |
@@ -1230,8 +1226,6 @@ void ath_newassoc(struct ath_softc *sc, | |||
1230 | for (tidno = 0; tidno < WME_NUM_TID; tidno++) { | 1226 | for (tidno = 0; tidno < WME_NUM_TID; tidno++) { |
1231 | if (sc->sc_flags & SC_OP_TXAGGR) | 1227 | if (sc->sc_flags & SC_OP_TXAGGR) |
1232 | ath_tx_aggr_teardown(sc, an, tidno); | 1228 | ath_tx_aggr_teardown(sc, an, tidno); |
1233 | if (sc->sc_flags & SC_OP_RXAGGR) | ||
1234 | ath_rx_aggr_teardown(sc, an, tidno); | ||
1235 | } | 1229 | } |
1236 | } | 1230 | } |
1237 | } | 1231 | } |
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index dd33cb7f2ca6..5b17e88ab9a9 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h | |||
@@ -304,15 +304,7 @@ void ath_descdma_cleanup(struct ath_softc *sc, | |||
304 | 304 | ||
305 | #define ATH_MAX_ANTENNA 3 | 305 | #define ATH_MAX_ANTENNA 3 |
306 | #define ATH_RXBUF 512 | 306 | #define ATH_RXBUF 512 |
307 | #define ATH_RX_TIMEOUT 40 /* 40 milliseconds */ | ||
308 | #define WME_NUM_TID 16 | 307 | #define WME_NUM_TID 16 |
309 | #define IEEE80211_BAR_CTL_TID_M 0xF000 /* tid mask */ | ||
310 | #define IEEE80211_BAR_CTL_TID_S 12 /* tid shift */ | ||
311 | |||
312 | enum ATH_RX_TYPE { | ||
313 | ATH_RX_NON_CONSUMED = 0, | ||
314 | ATH_RX_CONSUMED | ||
315 | }; | ||
316 | 308 | ||
317 | /* per frame rx status block */ | 309 | /* per frame rx status block */ |
318 | struct ath_recv_status { | 310 | struct ath_recv_status { |
@@ -346,47 +338,18 @@ struct ath_rxbuf { | |||
346 | struct ath_recv_status rx_status; /* cached rx status */ | 338 | struct ath_recv_status rx_status; /* cached rx status */ |
347 | }; | 339 | }; |
348 | 340 | ||
349 | /* Per-TID aggregate receiver state for a node */ | ||
350 | struct ath_arx_tid { | ||
351 | struct ath_node *an; | ||
352 | struct ath_rxbuf *rxbuf; /* re-ordering buffer */ | ||
353 | struct timer_list timer; | ||
354 | spinlock_t tidlock; | ||
355 | int baw_head; /* seq_next at head */ | ||
356 | int baw_tail; /* tail of block-ack window */ | ||
357 | int seq_reset; /* need to reset start sequence */ | ||
358 | int addba_exchangecomplete; | ||
359 | u16 seq_next; /* next expected sequence */ | ||
360 | u16 baw_size; /* block-ack window size */ | ||
361 | }; | ||
362 | |||
363 | /* Per-node receiver aggregate state */ | ||
364 | struct ath_arx { | ||
365 | struct ath_arx_tid tid[WME_NUM_TID]; | ||
366 | }; | ||
367 | |||
368 | int ath_startrecv(struct ath_softc *sc); | 341 | int ath_startrecv(struct ath_softc *sc); |
369 | bool ath_stoprecv(struct ath_softc *sc); | 342 | bool ath_stoprecv(struct ath_softc *sc); |
370 | void ath_flushrecv(struct ath_softc *sc); | 343 | void ath_flushrecv(struct ath_softc *sc); |
371 | u32 ath_calcrxfilter(struct ath_softc *sc); | 344 | u32 ath_calcrxfilter(struct ath_softc *sc); |
372 | void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an); | ||
373 | void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an); | ||
374 | void ath_handle_rx_intr(struct ath_softc *sc); | 345 | void ath_handle_rx_intr(struct ath_softc *sc); |
375 | int ath_rx_init(struct ath_softc *sc, int nbufs); | 346 | int ath_rx_init(struct ath_softc *sc, int nbufs); |
376 | void ath_rx_cleanup(struct ath_softc *sc); | 347 | void ath_rx_cleanup(struct ath_softc *sc); |
377 | int ath_rx_tasklet(struct ath_softc *sc, int flush); | 348 | int ath_rx_tasklet(struct ath_softc *sc, int flush); |
378 | int ath_rx_input(struct ath_softc *sc, | ||
379 | struct ath_node *node, | ||
380 | struct sk_buff *skb, | ||
381 | struct ath_recv_status *rx_status, | ||
382 | enum ATH_RX_TYPE *status); | ||
383 | int _ath_rx_indicate(struct ath_softc *sc, | 349 | int _ath_rx_indicate(struct ath_softc *sc, |
384 | struct sk_buff *skb, | 350 | struct sk_buff *skb, |
385 | struct ath_recv_status *status, | 351 | struct ath_recv_status *status, |
386 | u16 keyix); | 352 | u16 keyix); |
387 | int ath_rx_subframe(struct ath_node *an, struct sk_buff *skb, | ||
388 | struct ath_recv_status *status); | ||
389 | |||
390 | /******/ | 353 | /******/ |
391 | /* TX */ | 354 | /* TX */ |
392 | /******/ | 355 | /******/ |
@@ -599,7 +562,6 @@ struct aggr_rifs_param { | |||
599 | /* Per-node aggregation state */ | 562 | /* Per-node aggregation state */ |
600 | struct ath_node_aggr { | 563 | struct ath_node_aggr { |
601 | struct ath_atx tx; /* node transmit state */ | 564 | struct ath_atx tx; /* node transmit state */ |
602 | struct ath_arx rx; /* node receive state */ | ||
603 | }; | 565 | }; |
604 | 566 | ||
605 | /* driver-specific node state */ | 567 | /* driver-specific node state */ |
@@ -616,11 +578,6 @@ void ath_tx_resume_tid(struct ath_softc *sc, | |||
616 | bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno); | 578 | bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno); |
617 | void ath_tx_aggr_teardown(struct ath_softc *sc, | 579 | void ath_tx_aggr_teardown(struct ath_softc *sc, |
618 | struct ath_node *an, u8 tidno); | 580 | struct ath_node *an, u8 tidno); |
619 | void ath_rx_aggr_teardown(struct ath_softc *sc, | ||
620 | struct ath_node *an, u8 tidno); | ||
621 | int ath_rx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, | ||
622 | u16 tid, u16 *ssn); | ||
623 | int ath_rx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); | ||
624 | int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, | 581 | int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, |
625 | u16 tid, u16 *ssn); | 582 | u16 tid, u16 *ssn); |
626 | int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); | 583 | int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); |
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index e177de47e3e0..65a532e08ecd 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c | |||
@@ -444,12 +444,10 @@ int _ath_rx_indicate(struct ath_softc *sc, | |||
444 | u16 keyix) | 444 | u16 keyix) |
445 | { | 445 | { |
446 | struct ieee80211_hw *hw = sc->hw; | 446 | struct ieee80211_hw *hw = sc->hw; |
447 | struct ath_node *an = NULL; | ||
448 | struct ieee80211_rx_status rx_status; | 447 | struct ieee80211_rx_status rx_status; |
449 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 448 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
450 | int hdrlen = ieee80211_get_hdrlen_from_skb(skb); | 449 | int hdrlen = ieee80211_get_hdrlen_from_skb(skb); |
451 | int padsize; | 450 | int padsize; |
452 | enum ATH_RX_TYPE st; | ||
453 | 451 | ||
454 | /* see if any padding is done by the hw and remove it */ | 452 | /* see if any padding is done by the hw and remove it */ |
455 | if (hdrlen & 3) { | 453 | if (hdrlen & 3) { |
@@ -473,28 +471,6 @@ int _ath_rx_indicate(struct ath_softc *sc, | |||
473 | rx_status.flag |= RX_FLAG_DECRYPTED; | 471 | rx_status.flag |= RX_FLAG_DECRYPTED; |
474 | } | 472 | } |
475 | 473 | ||
476 | if (an) { | ||
477 | ath_rx_input(sc, an, | ||
478 | skb, status, &st); | ||
479 | } | ||
480 | if (!an || (st != ATH_RX_CONSUMED)) | ||
481 | __ieee80211_rx(hw, skb, &rx_status); | ||
482 | |||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | int ath_rx_subframe(struct ath_node *an, struct sk_buff *skb, | ||
487 | struct ath_recv_status *status) | ||
488 | { | ||
489 | struct ath_softc *sc = an->an_sc; | ||
490 | struct ieee80211_hw *hw = sc->hw; | ||
491 | struct ieee80211_rx_status rx_status; | ||
492 | |||
493 | /* Prepare rx status */ | ||
494 | ath9k_rx_prepare(sc, skb, status, &rx_status); | ||
495 | if (!(status->flags & ATH_RX_DECRYPT_ERROR)) | ||
496 | rx_status.flag |= RX_FLAG_DECRYPTED; | ||
497 | |||
498 | __ieee80211_rx(hw, skb, &rx_status); | 474 | __ieee80211_rx(hw, skb, &rx_status); |
499 | 475 | ||
500 | return 0; | 476 | return 0; |
@@ -1483,18 +1459,10 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, | |||
1483 | 1459 | ||
1484 | switch (action) { | 1460 | switch (action) { |
1485 | case IEEE80211_AMPDU_RX_START: | 1461 | case IEEE80211_AMPDU_RX_START: |
1486 | ret = ath_rx_aggr_start(sc, sta, tid, ssn); | 1462 | if (!(sc->sc_flags & SC_OP_RXAGGR)) |
1487 | if (ret < 0) | 1463 | ret = -ENOTSUPP; |
1488 | DPRINTF(sc, ATH_DBG_FATAL, | ||
1489 | "%s: Unable to start RX aggregation\n", | ||
1490 | __func__); | ||
1491 | break; | 1464 | break; |
1492 | case IEEE80211_AMPDU_RX_STOP: | 1465 | case IEEE80211_AMPDU_RX_STOP: |
1493 | ret = ath_rx_aggr_stop(sc, sta, tid); | ||
1494 | if (ret < 0) | ||
1495 | DPRINTF(sc, ATH_DBG_FATAL, | ||
1496 | "%s: Unable to stop RX aggregation\n", | ||
1497 | __func__); | ||
1498 | break; | 1466 | break; |
1499 | case IEEE80211_AMPDU_TX_START: | 1467 | case IEEE80211_AMPDU_TX_START: |
1500 | ret = ath_tx_aggr_start(sc, sta, tid, ssn); | 1468 | ret = ath_tx_aggr_start(sc, sta, tid, ssn); |
diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 80f26b4c4e06..2ecb0a010ce2 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c | |||
@@ -64,328 +64,6 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) | |||
64 | ath9k_hw_rxena(ah); | 64 | ath9k_hw_rxena(ah); |
65 | } | 65 | } |
66 | 66 | ||
67 | /* Process received BAR frame */ | ||
68 | |||
69 | static int ath_bar_rx(struct ath_softc *sc, | ||
70 | struct ath_node *an, | ||
71 | struct sk_buff *skb) | ||
72 | { | ||
73 | struct ieee80211_bar *bar; | ||
74 | struct ath_arx_tid *rxtid; | ||
75 | struct sk_buff *tskb; | ||
76 | struct ath_recv_status *rx_status; | ||
77 | int tidno, index, cindex; | ||
78 | u16 seqno; | ||
79 | |||
80 | /* look at BAR contents */ | ||
81 | |||
82 | bar = (struct ieee80211_bar *)skb->data; | ||
83 | tidno = (le16_to_cpu(bar->control) & IEEE80211_BAR_CTL_TID_M) | ||
84 | >> IEEE80211_BAR_CTL_TID_S; | ||
85 | seqno = le16_to_cpu(bar->start_seq_num) >> IEEE80211_SEQ_SEQ_SHIFT; | ||
86 | |||
87 | /* process BAR - indicate all pending RX frames till the BAR seqno */ | ||
88 | |||
89 | rxtid = &an->an_aggr.rx.tid[tidno]; | ||
90 | |||
91 | spin_lock_bh(&rxtid->tidlock); | ||
92 | |||
93 | /* get relative index */ | ||
94 | |||
95 | index = ATH_BA_INDEX(rxtid->seq_next, seqno); | ||
96 | |||
97 | /* drop BAR if old sequence (index is too large) */ | ||
98 | |||
99 | if ((index > rxtid->baw_size) && | ||
100 | (index > (IEEE80211_SEQ_MAX - (rxtid->baw_size << 2)))) | ||
101 | /* discard frame, ieee layer may not treat frame as a dup */ | ||
102 | goto unlock_and_free; | ||
103 | |||
104 | /* complete receive processing for all pending frames upto BAR seqno */ | ||
105 | |||
106 | cindex = (rxtid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); | ||
107 | while ((rxtid->baw_head != rxtid->baw_tail) && | ||
108 | (rxtid->baw_head != cindex)) { | ||
109 | tskb = rxtid->rxbuf[rxtid->baw_head].rx_wbuf; | ||
110 | rx_status = &rxtid->rxbuf[rxtid->baw_head].rx_status; | ||
111 | rxtid->rxbuf[rxtid->baw_head].rx_wbuf = NULL; | ||
112 | |||
113 | if (tskb != NULL) | ||
114 | ath_rx_subframe(an, tskb, rx_status); | ||
115 | |||
116 | INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); | ||
117 | INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); | ||
118 | } | ||
119 | |||
120 | /* ... and indicate rest of the frames in-order */ | ||
121 | |||
122 | while (rxtid->baw_head != rxtid->baw_tail && | ||
123 | rxtid->rxbuf[rxtid->baw_head].rx_wbuf != NULL) { | ||
124 | tskb = rxtid->rxbuf[rxtid->baw_head].rx_wbuf; | ||
125 | rx_status = &rxtid->rxbuf[rxtid->baw_head].rx_status; | ||
126 | rxtid->rxbuf[rxtid->baw_head].rx_wbuf = NULL; | ||
127 | |||
128 | ath_rx_subframe(an, tskb, rx_status); | ||
129 | |||
130 | INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); | ||
131 | INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); | ||
132 | } | ||
133 | |||
134 | unlock_and_free: | ||
135 | spin_unlock_bh(&rxtid->tidlock); | ||
136 | /* free bar itself */ | ||
137 | dev_kfree_skb(skb); | ||
138 | return IEEE80211_FTYPE_CTL; | ||
139 | } | ||
140 | |||
141 | /* Function to handle a subframe of aggregation when HT is enabled */ | ||
142 | |||
143 | static int ath_ampdu_input(struct ath_softc *sc, | ||
144 | struct ath_node *an, | ||
145 | struct sk_buff *skb, | ||
146 | struct ath_recv_status *rx_status) | ||
147 | { | ||
148 | struct ieee80211_hdr *hdr; | ||
149 | struct ath_arx_tid *rxtid; | ||
150 | struct ath_rxbuf *rxbuf; | ||
151 | u8 type, subtype; | ||
152 | u16 rxseq; | ||
153 | int tid = 0, index, cindex, rxdiff; | ||
154 | __le16 fc; | ||
155 | u8 *qc; | ||
156 | |||
157 | hdr = (struct ieee80211_hdr *)skb->data; | ||
158 | fc = hdr->frame_control; | ||
159 | |||
160 | /* collect stats of frames with non-zero version */ | ||
161 | |||
162 | if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_VERS) != 0) { | ||
163 | dev_kfree_skb(skb); | ||
164 | return -1; | ||
165 | } | ||
166 | |||
167 | type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE; | ||
168 | subtype = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_STYPE; | ||
169 | |||
170 | if (ieee80211_is_back_req(fc)) | ||
171 | return ath_bar_rx(sc, an, skb); | ||
172 | |||
173 | /* special aggregate processing only for qos unicast data frames */ | ||
174 | |||
175 | if (!ieee80211_is_data(fc) || | ||
176 | !ieee80211_is_data_qos(fc) || | ||
177 | is_multicast_ether_addr(hdr->addr1)) | ||
178 | return ath_rx_subframe(an, skb, rx_status); | ||
179 | |||
180 | /* lookup rx tid state */ | ||
181 | |||
182 | if (ieee80211_is_data_qos(fc)) { | ||
183 | qc = ieee80211_get_qos_ctl(hdr); | ||
184 | tid = qc[0] & 0xf; | ||
185 | } | ||
186 | |||
187 | if (sc->sc_ah->ah_opmode == ATH9K_M_STA) { | ||
188 | /* Drop the frame not belonging to me. */ | ||
189 | if (memcmp(hdr->addr1, sc->sc_myaddr, ETH_ALEN)) { | ||
190 | dev_kfree_skb(skb); | ||
191 | return -1; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | rxtid = &an->an_aggr.rx.tid[tid]; | ||
196 | |||
197 | spin_lock(&rxtid->tidlock); | ||
198 | |||
199 | rxdiff = (rxtid->baw_tail - rxtid->baw_head) & | ||
200 | (ATH_TID_MAX_BUFS - 1); | ||
201 | |||
202 | /* | ||
203 | * If the ADDBA exchange has not been completed by the source, | ||
204 | * process via legacy path (i.e. no reordering buffer is needed) | ||
205 | */ | ||
206 | if (!rxtid->addba_exchangecomplete) { | ||
207 | spin_unlock(&rxtid->tidlock); | ||
208 | return ath_rx_subframe(an, skb, rx_status); | ||
209 | } | ||
210 | |||
211 | /* extract sequence number from recvd frame */ | ||
212 | |||
213 | rxseq = le16_to_cpu(hdr->seq_ctrl) >> IEEE80211_SEQ_SEQ_SHIFT; | ||
214 | |||
215 | if (rxtid->seq_reset) { | ||
216 | rxtid->seq_reset = 0; | ||
217 | rxtid->seq_next = rxseq; | ||
218 | } | ||
219 | |||
220 | index = ATH_BA_INDEX(rxtid->seq_next, rxseq); | ||
221 | |||
222 | /* drop frame if old sequence (index is too large) */ | ||
223 | |||
224 | if (index > (IEEE80211_SEQ_MAX - (rxtid->baw_size << 2))) { | ||
225 | /* discard frame, ieee layer may not treat frame as a dup */ | ||
226 | spin_unlock(&rxtid->tidlock); | ||
227 | dev_kfree_skb(skb); | ||
228 | return IEEE80211_FTYPE_DATA; | ||
229 | } | ||
230 | |||
231 | /* sequence number is beyond block-ack window */ | ||
232 | |||
233 | if (index >= rxtid->baw_size) { | ||
234 | |||
235 | /* complete receive processing for all pending frames */ | ||
236 | |||
237 | while (index >= rxtid->baw_size) { | ||
238 | |||
239 | rxbuf = rxtid->rxbuf + rxtid->baw_head; | ||
240 | |||
241 | if (rxbuf->rx_wbuf != NULL) { | ||
242 | ath_rx_subframe(an, rxbuf->rx_wbuf, | ||
243 | &rxbuf->rx_status); | ||
244 | rxbuf->rx_wbuf = NULL; | ||
245 | } | ||
246 | |||
247 | INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); | ||
248 | INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); | ||
249 | |||
250 | index--; | ||
251 | } | ||
252 | } | ||
253 | |||
254 | /* add buffer to the recv ba window */ | ||
255 | |||
256 | cindex = (rxtid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); | ||
257 | rxbuf = rxtid->rxbuf + cindex; | ||
258 | |||
259 | if (rxbuf->rx_wbuf != NULL) { | ||
260 | spin_unlock(&rxtid->tidlock); | ||
261 | /* duplicate frame */ | ||
262 | dev_kfree_skb(skb); | ||
263 | return IEEE80211_FTYPE_DATA; | ||
264 | } | ||
265 | |||
266 | rxbuf->rx_wbuf = skb; | ||
267 | rxbuf->rx_time = get_timestamp(); | ||
268 | rxbuf->rx_status = *rx_status; | ||
269 | |||
270 | /* advance tail if sequence received is newer | ||
271 | * than any received so far */ | ||
272 | |||
273 | if (index >= rxdiff) { | ||
274 | rxtid->baw_tail = cindex; | ||
275 | INCR(rxtid->baw_tail, ATH_TID_MAX_BUFS); | ||
276 | } | ||
277 | |||
278 | /* indicate all in-order received frames */ | ||
279 | |||
280 | while (rxtid->baw_head != rxtid->baw_tail) { | ||
281 | rxbuf = rxtid->rxbuf + rxtid->baw_head; | ||
282 | if (!rxbuf->rx_wbuf) | ||
283 | break; | ||
284 | |||
285 | ath_rx_subframe(an, rxbuf->rx_wbuf, &rxbuf->rx_status); | ||
286 | rxbuf->rx_wbuf = NULL; | ||
287 | |||
288 | INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); | ||
289 | INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); | ||
290 | } | ||
291 | |||
292 | /* | ||
293 | * start a timer to flush all received frames if there are pending | ||
294 | * receive frames | ||
295 | */ | ||
296 | if (rxtid->baw_head != rxtid->baw_tail) | ||
297 | mod_timer(&rxtid->timer, ATH_RX_TIMEOUT); | ||
298 | else | ||
299 | del_timer_sync(&rxtid->timer); | ||
300 | |||
301 | spin_unlock(&rxtid->tidlock); | ||
302 | return IEEE80211_FTYPE_DATA; | ||
303 | } | ||
304 | |||
305 | /* Timer to flush all received sub-frames */ | ||
306 | |||
307 | static void ath_rx_timer(unsigned long data) | ||
308 | { | ||
309 | struct ath_arx_tid *rxtid = (struct ath_arx_tid *)data; | ||
310 | struct ath_node *an = rxtid->an; | ||
311 | struct ath_rxbuf *rxbuf; | ||
312 | int nosched; | ||
313 | |||
314 | spin_lock_bh(&rxtid->tidlock); | ||
315 | while (rxtid->baw_head != rxtid->baw_tail) { | ||
316 | rxbuf = rxtid->rxbuf + rxtid->baw_head; | ||
317 | if (!rxbuf->rx_wbuf) { | ||
318 | INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); | ||
319 | INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); | ||
320 | continue; | ||
321 | } | ||
322 | |||
323 | /* | ||
324 | * Stop if the next one is a very recent frame. | ||
325 | * | ||
326 | * Call get_timestamp in every iteration to protect against the | ||
327 | * case in which a new frame is received while we are executing | ||
328 | * this function. Using a timestamp obtained before entering | ||
329 | * the loop could lead to a very large time interval | ||
330 | * (a negative value typecast to unsigned), breaking the | ||
331 | * function's logic. | ||
332 | */ | ||
333 | if ((get_timestamp() - rxbuf->rx_time) < | ||
334 | (ATH_RX_TIMEOUT * HZ / 1000)) | ||
335 | break; | ||
336 | |||
337 | ath_rx_subframe(an, rxbuf->rx_wbuf, | ||
338 | &rxbuf->rx_status); | ||
339 | rxbuf->rx_wbuf = NULL; | ||
340 | |||
341 | INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); | ||
342 | INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); | ||
343 | } | ||
344 | |||
345 | /* | ||
346 | * start a timer to flush all received frames if there are pending | ||
347 | * receive frames | ||
348 | */ | ||
349 | if (rxtid->baw_head != rxtid->baw_tail) | ||
350 | nosched = 0; | ||
351 | else | ||
352 | nosched = 1; /* no need to re-arm the timer again */ | ||
353 | |||
354 | spin_unlock_bh(&rxtid->tidlock); | ||
355 | } | ||
356 | |||
357 | /* Free all pending sub-frames in the re-ordering buffer */ | ||
358 | |||
359 | static void ath_rx_flush_tid(struct ath_softc *sc, struct ath_arx_tid *rxtid, | ||
360 | int drop) | ||
361 | { | ||
362 | struct ath_rxbuf *rxbuf; | ||
363 | unsigned long flag; | ||
364 | |||
365 | spin_lock_irqsave(&rxtid->tidlock, flag); | ||
366 | while (rxtid->baw_head != rxtid->baw_tail) { | ||
367 | rxbuf = rxtid->rxbuf + rxtid->baw_head; | ||
368 | if (!rxbuf->rx_wbuf) { | ||
369 | INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); | ||
370 | INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); | ||
371 | continue; | ||
372 | } | ||
373 | |||
374 | if (drop) | ||
375 | dev_kfree_skb(rxbuf->rx_wbuf); | ||
376 | else | ||
377 | ath_rx_subframe(rxtid->an, | ||
378 | rxbuf->rx_wbuf, | ||
379 | &rxbuf->rx_status); | ||
380 | |||
381 | rxbuf->rx_wbuf = NULL; | ||
382 | |||
383 | INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); | ||
384 | INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); | ||
385 | } | ||
386 | spin_unlock_irqrestore(&rxtid->tidlock, flag); | ||
387 | } | ||
388 | |||
389 | static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, | 67 | static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, |
390 | u32 len) | 68 | u32 len) |
391 | { | 69 | { |
@@ -716,23 +394,6 @@ void ath_flushrecv(struct ath_softc *sc) | |||
716 | spin_unlock_bh(&sc->sc_rxflushlock); | 394 | spin_unlock_bh(&sc->sc_rxflushlock); |
717 | } | 395 | } |
718 | 396 | ||
719 | /* Process an individual frame */ | ||
720 | |||
721 | int ath_rx_input(struct ath_softc *sc, | ||
722 | struct ath_node *an, | ||
723 | struct sk_buff *skb, | ||
724 | struct ath_recv_status *rx_status, | ||
725 | enum ATH_RX_TYPE *status) | ||
726 | { | ||
727 | if (sc->sc_flags & SC_OP_RXAGGR) { | ||
728 | *status = ATH_RX_CONSUMED; | ||
729 | return ath_ampdu_input(sc, an, skb, rx_status); | ||
730 | } else { | ||
731 | *status = ATH_RX_NON_CONSUMED; | ||
732 | return -1; | ||
733 | } | ||
734 | } | ||
735 | |||
736 | /* Process receive queue, as well as LED, etc. */ | 397 | /* Process receive queue, as well as LED, etc. */ |
737 | 398 | ||
738 | int ath_rx_tasklet(struct ath_softc *sc, int flush) | 399 | int ath_rx_tasklet(struct ath_softc *sc, int flush) |
@@ -1091,165 +752,3 @@ rx_next: | |||
1091 | return 0; | 752 | return 0; |
1092 | #undef PA2DESC | 753 | #undef PA2DESC |
1093 | } | 754 | } |
1094 | |||
1095 | /* Process ADDBA request in per-TID data structure */ | ||
1096 | |||
1097 | int ath_rx_aggr_start(struct ath_softc *sc, | ||
1098 | struct ieee80211_sta *sta, | ||
1099 | u16 tid, | ||
1100 | u16 *ssn) | ||
1101 | { | ||
1102 | struct ath_arx_tid *rxtid; | ||
1103 | struct ath_node *an; | ||
1104 | struct ieee80211_hw *hw = sc->hw; | ||
1105 | struct ieee80211_supported_band *sband; | ||
1106 | u16 buffersize = 0; | ||
1107 | |||
1108 | an = (struct ath_node *)sta->drv_priv; | ||
1109 | sband = hw->wiphy->bands[hw->conf.channel->band]; | ||
1110 | buffersize = IEEE80211_MIN_AMPDU_BUF << | ||
1111 | sband->ht_cap.ampdu_factor; /* FIXME */ | ||
1112 | |||
1113 | rxtid = &an->an_aggr.rx.tid[tid]; | ||
1114 | |||
1115 | spin_lock_bh(&rxtid->tidlock); | ||
1116 | if (sc->sc_flags & SC_OP_RXAGGR) { | ||
1117 | /* Allow aggregation reception | ||
1118 | * Adjust rx BA window size. Peer might indicate a | ||
1119 | * zero buffer size for a _dont_care_ condition. | ||
1120 | */ | ||
1121 | if (buffersize) | ||
1122 | rxtid->baw_size = min(buffersize, rxtid->baw_size); | ||
1123 | |||
1124 | /* set rx sequence number */ | ||
1125 | rxtid->seq_next = *ssn; | ||
1126 | |||
1127 | /* Allocate the receive buffers for this TID */ | ||
1128 | DPRINTF(sc, ATH_DBG_AGGR, | ||
1129 | "%s: Allcating rxbuffer for TID %d\n", __func__, tid); | ||
1130 | |||
1131 | if (rxtid->rxbuf == NULL) { | ||
1132 | /* | ||
1133 | * If the rxbuff is not NULL at this point, we *probably* | ||
1134 | * already allocated the buffer on a previous ADDBA, | ||
1135 | * and this is a subsequent ADDBA that got through. | ||
1136 | * Don't allocate, but use the value in the pointer, | ||
1137 | * we zero it out when we de-allocate. | ||
1138 | */ | ||
1139 | rxtid->rxbuf = kmalloc(ATH_TID_MAX_BUFS * | ||
1140 | sizeof(struct ath_rxbuf), GFP_ATOMIC); | ||
1141 | } | ||
1142 | if (rxtid->rxbuf == NULL) { | ||
1143 | DPRINTF(sc, ATH_DBG_AGGR, | ||
1144 | "%s: Unable to allocate RX buffer, " | ||
1145 | "refusing ADDBA\n", __func__); | ||
1146 | } else { | ||
1147 | /* Ensure the memory is zeroed out (all internal | ||
1148 | * pointers are null) */ | ||
1149 | memset(rxtid->rxbuf, 0, ATH_TID_MAX_BUFS * | ||
1150 | sizeof(struct ath_rxbuf)); | ||
1151 | DPRINTF(sc, ATH_DBG_AGGR, | ||
1152 | "%s: Allocated @%p\n", __func__, rxtid->rxbuf); | ||
1153 | |||
1154 | /* Allow aggregation reception */ | ||
1155 | rxtid->addba_exchangecomplete = 1; | ||
1156 | } | ||
1157 | } | ||
1158 | spin_unlock_bh(&rxtid->tidlock); | ||
1159 | |||
1160 | return 0; | ||
1161 | } | ||
1162 | |||
1163 | /* Process DELBA */ | ||
1164 | |||
1165 | int ath_rx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) | ||
1166 | { | ||
1167 | struct ath_node *an = (struct ath_node *)sta->drv_priv; | ||
1168 | |||
1169 | ath_rx_aggr_teardown(sc, an, tid); | ||
1170 | return 0; | ||
1171 | } | ||
1172 | |||
1173 | /* Rx aggregation tear down */ | ||
1174 | |||
1175 | void ath_rx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tid) | ||
1176 | { | ||
1177 | struct ath_arx_tid *rxtid = &an->an_aggr.rx.tid[tid]; | ||
1178 | |||
1179 | if (!rxtid->addba_exchangecomplete) | ||
1180 | return; | ||
1181 | |||
1182 | del_timer_sync(&rxtid->timer); | ||
1183 | ath_rx_flush_tid(sc, rxtid, 0); | ||
1184 | rxtid->addba_exchangecomplete = 0; | ||
1185 | |||
1186 | /* De-allocate the receive buffer array allocated when addba started */ | ||
1187 | |||
1188 | if (rxtid->rxbuf) { | ||
1189 | DPRINTF(sc, ATH_DBG_AGGR, | ||
1190 | "%s: Deallocating TID %d rxbuff @%p\n", | ||
1191 | __func__, tid, rxtid->rxbuf); | ||
1192 | kfree(rxtid->rxbuf); | ||
1193 | |||
1194 | /* Set pointer to null to avoid reuse*/ | ||
1195 | rxtid->rxbuf = NULL; | ||
1196 | } | ||
1197 | } | ||
1198 | |||
1199 | /* Initialize per-node receive state */ | ||
1200 | |||
1201 | void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an) | ||
1202 | { | ||
1203 | struct ath_arx_tid *rxtid; | ||
1204 | int tidno; | ||
1205 | |||
1206 | /* Init per tid rx state */ | ||
1207 | for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno]; | ||
1208 | tidno < WME_NUM_TID; | ||
1209 | tidno++, rxtid++) { | ||
1210 | rxtid->an = an; | ||
1211 | rxtid->seq_reset = 1; | ||
1212 | rxtid->seq_next = 0; | ||
1213 | rxtid->baw_size = WME_MAX_BA; | ||
1214 | rxtid->baw_head = rxtid->baw_tail = 0; | ||
1215 | |||
1216 | /* | ||
1217 | * Ensure the buffer pointer is null at this point | ||
1218 | * (needs to be allocated when addba is received) | ||
1219 | */ | ||
1220 | |||
1221 | rxtid->rxbuf = NULL; | ||
1222 | setup_timer(&rxtid->timer, ath_rx_timer, | ||
1223 | (unsigned long)rxtid); | ||
1224 | spin_lock_init(&rxtid->tidlock); | ||
1225 | |||
1226 | /* ADDBA state */ | ||
1227 | rxtid->addba_exchangecomplete = 0; | ||
1228 | } | ||
1229 | } | ||
1230 | |||
1231 | void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an) | ||
1232 | { | ||
1233 | struct ath_arx_tid *rxtid; | ||
1234 | int tidno, i; | ||
1235 | |||
1236 | /* Init per tid rx state */ | ||
1237 | for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno]; | ||
1238 | tidno < WME_NUM_TID; | ||
1239 | tidno++, rxtid++) { | ||
1240 | |||
1241 | if (!rxtid->addba_exchangecomplete) | ||
1242 | continue; | ||
1243 | |||
1244 | /* must cancel timer first */ | ||
1245 | del_timer_sync(&rxtid->timer); | ||
1246 | |||
1247 | /* drop any pending sub-frames */ | ||
1248 | ath_rx_flush_tid(sc, rxtid, 1); | ||
1249 | |||
1250 | for (i = 0; i < ATH_TID_MAX_BUFS; i++) | ||
1251 | ASSERT(rxtid->rxbuf[i].rx_wbuf == NULL); | ||
1252 | |||
1253 | rxtid->addba_exchangecomplete = 0; | ||
1254 | } | ||
1255 | } | ||