14b44f6f2SAdrian Chadd /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
44b44f6f2SAdrian Chadd * Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd.
54b44f6f2SAdrian Chadd * All rights reserved.
64b44f6f2SAdrian Chadd *
74b44f6f2SAdrian Chadd * Redistribution and use in source and binary forms, with or without
84b44f6f2SAdrian Chadd * modification, are permitted provided that the following conditions
94b44f6f2SAdrian Chadd * are met:
104b44f6f2SAdrian Chadd * 1. Redistributions of source code must retain the above copyright
114b44f6f2SAdrian Chadd * notice, this list of conditions and the following disclaimer,
124b44f6f2SAdrian Chadd * without modification.
134b44f6f2SAdrian Chadd * 2. Redistributions in binary form must reproduce at minimum a disclaimer
144b44f6f2SAdrian Chadd * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
154b44f6f2SAdrian Chadd * redistribution must be conditioned upon including a substantially
164b44f6f2SAdrian Chadd * similar Disclaimer requirement for further binary redistribution.
174b44f6f2SAdrian Chadd *
184b44f6f2SAdrian Chadd * NO WARRANTY
194b44f6f2SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
204b44f6f2SAdrian Chadd * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
214b44f6f2SAdrian Chadd * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
224b44f6f2SAdrian Chadd * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
234b44f6f2SAdrian Chadd * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
244b44f6f2SAdrian Chadd * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
254b44f6f2SAdrian Chadd * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
264b44f6f2SAdrian Chadd * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
274b44f6f2SAdrian Chadd * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
284b44f6f2SAdrian Chadd * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
294b44f6f2SAdrian Chadd * THE POSSIBILITY OF SUCH DAMAGES.
304b44f6f2SAdrian Chadd */
314b44f6f2SAdrian Chadd
324b44f6f2SAdrian Chadd #include <sys/cdefs.h>
334b44f6f2SAdrian Chadd #include "opt_inet.h"
344b44f6f2SAdrian Chadd #include "opt_ath.h"
354b44f6f2SAdrian Chadd #include "opt_wlan.h"
364b44f6f2SAdrian Chadd
374b44f6f2SAdrian Chadd #include <sys/param.h>
384b44f6f2SAdrian Chadd #include <sys/systm.h>
394b44f6f2SAdrian Chadd #include <sys/sysctl.h>
404b44f6f2SAdrian Chadd #include <sys/mbuf.h>
414b44f6f2SAdrian Chadd #include <sys/malloc.h>
424b44f6f2SAdrian Chadd #include <sys/lock.h>
434b44f6f2SAdrian Chadd #include <sys/mutex.h>
444b44f6f2SAdrian Chadd #include <sys/kernel.h>
454b44f6f2SAdrian Chadd #include <sys/socket.h>
464b44f6f2SAdrian Chadd #include <sys/sockio.h>
474b44f6f2SAdrian Chadd #include <sys/errno.h>
484b44f6f2SAdrian Chadd #include <sys/callout.h>
494b44f6f2SAdrian Chadd #include <sys/bus.h>
504b44f6f2SAdrian Chadd #include <sys/endian.h>
514b44f6f2SAdrian Chadd #include <sys/kthread.h>
524b44f6f2SAdrian Chadd #include <sys/taskqueue.h>
534b44f6f2SAdrian Chadd #include <sys/priv.h>
544b44f6f2SAdrian Chadd
554b44f6f2SAdrian Chadd #include <machine/bus.h>
564b44f6f2SAdrian Chadd
574b44f6f2SAdrian Chadd #include <net/if.h>
584b44f6f2SAdrian Chadd #include <net/if_dl.h>
594b44f6f2SAdrian Chadd #include <net/if_media.h>
604b44f6f2SAdrian Chadd #include <net/if_types.h>
614b44f6f2SAdrian Chadd #include <net/if_arp.h>
624b44f6f2SAdrian Chadd #include <net/ethernet.h>
634b44f6f2SAdrian Chadd #include <net/if_llc.h>
644b44f6f2SAdrian Chadd
654b44f6f2SAdrian Chadd #include <net80211/ieee80211_var.h>
664b44f6f2SAdrian Chadd #include <net80211/ieee80211_regdomain.h>
674b44f6f2SAdrian Chadd #ifdef IEEE80211_SUPPORT_SUPERG
684b44f6f2SAdrian Chadd #include <net80211/ieee80211_superg.h>
694b44f6f2SAdrian Chadd #endif
704b44f6f2SAdrian Chadd #ifdef IEEE80211_SUPPORT_TDMA
714b44f6f2SAdrian Chadd #include <net80211/ieee80211_tdma.h>
724b44f6f2SAdrian Chadd #endif
734b44f6f2SAdrian Chadd
744b44f6f2SAdrian Chadd #include <net/bpf.h>
754b44f6f2SAdrian Chadd
764b44f6f2SAdrian Chadd #ifdef INET
774b44f6f2SAdrian Chadd #include <netinet/in.h>
784b44f6f2SAdrian Chadd #include <netinet/if_ether.h>
794b44f6f2SAdrian Chadd #endif
804b44f6f2SAdrian Chadd
814b44f6f2SAdrian Chadd #include <dev/ath/if_athvar.h>
824b44f6f2SAdrian Chadd #include <dev/ath/ath_hal/ah_devid.h> /* XXX for softled */
834b44f6f2SAdrian Chadd #include <dev/ath/ath_hal/ah_diagcodes.h>
844b44f6f2SAdrian Chadd
854b44f6f2SAdrian Chadd #ifdef ATH_TX99_DIAG
864b44f6f2SAdrian Chadd #include <dev/ath/ath_tx99/ath_tx99.h>
874b44f6f2SAdrian Chadd #endif
884b44f6f2SAdrian Chadd
89eb6f0de0SAdrian Chadd #include <dev/ath/if_ath_tx.h> /* XXX for some support functions */
904b44f6f2SAdrian Chadd #include <dev/ath/if_ath_tx_ht.h>
91eb6f0de0SAdrian Chadd #include <dev/ath/if_athrate.h>
92eb6f0de0SAdrian Chadd #include <dev/ath/if_ath_debug.h>
93eb6f0de0SAdrian Chadd
94eb6f0de0SAdrian Chadd /*
95eb6f0de0SAdrian Chadd * XXX net80211?
96eb6f0de0SAdrian Chadd */
97eb6f0de0SAdrian Chadd #define IEEE80211_AMPDU_SUBFRAME_DEFAULT 32
98eb6f0de0SAdrian Chadd
99eb6f0de0SAdrian Chadd #define ATH_AGGR_DELIM_SZ 4 /* delimiter size */
100eb6f0de0SAdrian Chadd #define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */
101b25c1f2aSAdrian Chadd /* number of delimiters for encryption padding */
102b25c1f2aSAdrian Chadd #define ATH_AGGR_ENCRYPTDELIM 10
103eb6f0de0SAdrian Chadd
104eb6f0de0SAdrian Chadd /*
105eb6f0de0SAdrian Chadd * returns delimiter padding required given the packet length
106eb6f0de0SAdrian Chadd */
107eb6f0de0SAdrian Chadd #define ATH_AGGR_GET_NDELIM(_len) \
108eb6f0de0SAdrian Chadd (((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ? \
109eb6f0de0SAdrian Chadd (ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2)
110eb6f0de0SAdrian Chadd
111eb6f0de0SAdrian Chadd #define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
112eb6f0de0SAdrian Chadd
113eb6f0de0SAdrian Chadd int ath_max_4ms_framelen[4][32] = {
114eb6f0de0SAdrian Chadd [MCS_HT20] = {
115eb6f0de0SAdrian Chadd 3212, 6432, 9648, 12864, 19300, 25736, 28952, 32172,
116eb6f0de0SAdrian Chadd 6424, 12852, 19280, 25708, 38568, 51424, 57852, 64280,
117eb6f0de0SAdrian Chadd 9628, 19260, 28896, 38528, 57792, 65532, 65532, 65532,
118eb6f0de0SAdrian Chadd 12828, 25656, 38488, 51320, 65532, 65532, 65532, 65532,
119eb6f0de0SAdrian Chadd },
120eb6f0de0SAdrian Chadd [MCS_HT20_SGI] = {
121eb6f0de0SAdrian Chadd 3572, 7144, 10720, 14296, 21444, 28596, 32172, 35744,
122eb6f0de0SAdrian Chadd 7140, 14284, 21428, 28568, 42856, 57144, 64288, 65532,
123eb6f0de0SAdrian Chadd 10700, 21408, 32112, 42816, 64228, 65532, 65532, 65532,
124eb6f0de0SAdrian Chadd 14256, 28516, 42780, 57040, 65532, 65532, 65532, 65532,
125eb6f0de0SAdrian Chadd },
126eb6f0de0SAdrian Chadd [MCS_HT40] = {
127eb6f0de0SAdrian Chadd 6680, 13360, 20044, 26724, 40092, 53456, 60140, 65532,
128eb6f0de0SAdrian Chadd 13348, 26700, 40052, 53400, 65532, 65532, 65532, 65532,
129eb6f0de0SAdrian Chadd 20004, 40008, 60016, 65532, 65532, 65532, 65532, 65532,
130eb6f0de0SAdrian Chadd 26644, 53292, 65532, 65532, 65532, 65532, 65532, 65532,
131eb6f0de0SAdrian Chadd },
132eb6f0de0SAdrian Chadd [MCS_HT40_SGI] = {
133eb6f0de0SAdrian Chadd 7420, 14844, 22272, 29696, 44544, 59396, 65532, 65532,
134eb6f0de0SAdrian Chadd 14832, 29668, 44504, 59340, 65532, 65532, 65532, 65532,
135eb6f0de0SAdrian Chadd 22232, 44464, 65532, 65532, 65532, 65532, 65532, 65532,
136eb6f0de0SAdrian Chadd 29616, 59232, 65532, 65532, 65532, 65532, 65532, 65532,
137eb6f0de0SAdrian Chadd }
138eb6f0de0SAdrian Chadd };
139eb6f0de0SAdrian Chadd
140eb6f0de0SAdrian Chadd /*
141eb6f0de0SAdrian Chadd * XXX should be in net80211
142eb6f0de0SAdrian Chadd */
143eb6f0de0SAdrian Chadd static int ieee80211_mpdudensity_map[] = {
144eb6f0de0SAdrian Chadd 0, /* IEEE80211_HTCAP_MPDUDENSITY_NA */
145eb6f0de0SAdrian Chadd 25, /* IEEE80211_HTCAP_MPDUDENSITY_025 */
146eb6f0de0SAdrian Chadd 50, /* IEEE80211_HTCAP_MPDUDENSITY_05 */
147eb6f0de0SAdrian Chadd 100, /* IEEE80211_HTCAP_MPDUDENSITY_1 */
148eb6f0de0SAdrian Chadd 200, /* IEEE80211_HTCAP_MPDUDENSITY_2 */
149eb6f0de0SAdrian Chadd 400, /* IEEE80211_HTCAP_MPDUDENSITY_4 */
150eb6f0de0SAdrian Chadd 800, /* IEEE80211_HTCAP_MPDUDENSITY_8 */
151eb6f0de0SAdrian Chadd 1600, /* IEEE80211_HTCAP_MPDUDENSITY_16 */
152eb6f0de0SAdrian Chadd };
153eb6f0de0SAdrian Chadd
154eb6f0de0SAdrian Chadd /*
155eb6f0de0SAdrian Chadd * XXX should be in the HAL/net80211 ?
156eb6f0de0SAdrian Chadd */
157eb6f0de0SAdrian Chadd #define BITS_PER_BYTE 8
158eb6f0de0SAdrian Chadd #define OFDM_PLCP_BITS 22
159eb6f0de0SAdrian Chadd #define HT_RC_2_MCS(_rc) ((_rc) & 0x7f)
160eb6f0de0SAdrian Chadd #define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1)
161eb6f0de0SAdrian Chadd #define L_STF 8
162eb6f0de0SAdrian Chadd #define L_LTF 8
163eb6f0de0SAdrian Chadd #define L_SIG 4
164eb6f0de0SAdrian Chadd #define HT_SIG 8
165eb6f0de0SAdrian Chadd #define HT_STF 4
166eb6f0de0SAdrian Chadd #define HT_LTF(_ns) (4 * (_ns))
167eb6f0de0SAdrian Chadd #define SYMBOL_TIME(_ns) ((_ns) << 2) // ns * 4 us
168eb6f0de0SAdrian Chadd #define SYMBOL_TIME_HALFGI(_ns) (((_ns) * 18 + 4) / 5) // ns * 3.6 us
169eb6f0de0SAdrian Chadd #define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2)
170eb6f0de0SAdrian Chadd #define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4)/18)
171eb6f0de0SAdrian Chadd #define IS_HT_RATE(_rate) ((_rate) & 0x80)
172eb6f0de0SAdrian Chadd
173eb6f0de0SAdrian Chadd const uint32_t bits_per_symbol[][2] = {
174eb6f0de0SAdrian Chadd /* 20MHz 40MHz */
175eb6f0de0SAdrian Chadd { 26, 54 }, // 0: BPSK
176eb6f0de0SAdrian Chadd { 52, 108 }, // 1: QPSK 1/2
177eb6f0de0SAdrian Chadd { 78, 162 }, // 2: QPSK 3/4
178eb6f0de0SAdrian Chadd { 104, 216 }, // 3: 16-QAM 1/2
179eb6f0de0SAdrian Chadd { 156, 324 }, // 4: 16-QAM 3/4
180eb6f0de0SAdrian Chadd { 208, 432 }, // 5: 64-QAM 2/3
181eb6f0de0SAdrian Chadd { 234, 486 }, // 6: 64-QAM 3/4
182eb6f0de0SAdrian Chadd { 260, 540 }, // 7: 64-QAM 5/6
183eb6f0de0SAdrian Chadd { 52, 108 }, // 8: BPSK
184eb6f0de0SAdrian Chadd { 104, 216 }, // 9: QPSK 1/2
185eb6f0de0SAdrian Chadd { 156, 324 }, // 10: QPSK 3/4
186eb6f0de0SAdrian Chadd { 208, 432 }, // 11: 16-QAM 1/2
187eb6f0de0SAdrian Chadd { 312, 648 }, // 12: 16-QAM 3/4
188eb6f0de0SAdrian Chadd { 416, 864 }, // 13: 64-QAM 2/3
189eb6f0de0SAdrian Chadd { 468, 972 }, // 14: 64-QAM 3/4
190eb6f0de0SAdrian Chadd { 520, 1080 }, // 15: 64-QAM 5/6
191eb6f0de0SAdrian Chadd { 78, 162 }, // 16: BPSK
192eb6f0de0SAdrian Chadd { 156, 324 }, // 17: QPSK 1/2
193eb6f0de0SAdrian Chadd { 234, 486 }, // 18: QPSK 3/4
194eb6f0de0SAdrian Chadd { 312, 648 }, // 19: 16-QAM 1/2
195eb6f0de0SAdrian Chadd { 468, 972 }, // 20: 16-QAM 3/4
196eb6f0de0SAdrian Chadd { 624, 1296 }, // 21: 64-QAM 2/3
197eb6f0de0SAdrian Chadd { 702, 1458 }, // 22: 64-QAM 3/4
198eb6f0de0SAdrian Chadd { 780, 1620 }, // 23: 64-QAM 5/6
199eb6f0de0SAdrian Chadd { 104, 216 }, // 24: BPSK
200eb6f0de0SAdrian Chadd { 208, 432 }, // 25: QPSK 1/2
201eb6f0de0SAdrian Chadd { 312, 648 }, // 26: QPSK 3/4
202eb6f0de0SAdrian Chadd { 416, 864 }, // 27: 16-QAM 1/2
203eb6f0de0SAdrian Chadd { 624, 1296 }, // 28: 16-QAM 3/4
204eb6f0de0SAdrian Chadd { 832, 1728 }, // 29: 64-QAM 2/3
205eb6f0de0SAdrian Chadd { 936, 1944 }, // 30: 64-QAM 3/4
206eb6f0de0SAdrian Chadd { 1040, 2160 }, // 31: 64-QAM 5/6
207eb6f0de0SAdrian Chadd };
208eb6f0de0SAdrian Chadd
209eb6f0de0SAdrian Chadd /*
210eb6f0de0SAdrian Chadd * Fill in the rate array information based on the current
211eb6f0de0SAdrian Chadd * node configuration and the choices made by the rate
212eb6f0de0SAdrian Chadd * selection code and ath_buf setup code.
213eb6f0de0SAdrian Chadd *
214eb6f0de0SAdrian Chadd * Later on, this may end up also being made by the
215eb6f0de0SAdrian Chadd * rate control code, but for now it can live here.
216eb6f0de0SAdrian Chadd *
217eb6f0de0SAdrian Chadd * This needs to be called just before the packet is
218eb6f0de0SAdrian Chadd * queued to the software queue or hardware queue,
219eb6f0de0SAdrian Chadd * so all of the needed fields in bf_state are setup.
220eb6f0de0SAdrian Chadd */
221eb6f0de0SAdrian Chadd void
ath_tx_rate_fill_rcflags(struct ath_softc * sc,struct ath_buf * bf)222eb6f0de0SAdrian Chadd ath_tx_rate_fill_rcflags(struct ath_softc *sc, struct ath_buf *bf)
223eb6f0de0SAdrian Chadd {
224eb6f0de0SAdrian Chadd struct ieee80211_node *ni = bf->bf_node;
225eb6f0de0SAdrian Chadd struct ieee80211com *ic = ni->ni_ic;
226eb6f0de0SAdrian Chadd const HAL_RATE_TABLE *rt = sc->sc_currates;
227eb6f0de0SAdrian Chadd struct ath_rc_series *rc = bf->bf_state.bfs_rc;
228eb6f0de0SAdrian Chadd uint8_t rate;
229eb6f0de0SAdrian Chadd int i;
230ce725c8eSAdrian Chadd int do_ldpc;
231ce725c8eSAdrian Chadd int do_stbc;
232ce725c8eSAdrian Chadd
233ce725c8eSAdrian Chadd /*
234ce725c8eSAdrian Chadd * We only do LDPC if the rate is 11n, both we and the
235ce725c8eSAdrian Chadd * receiver support LDPC and it's enabled.
236ce725c8eSAdrian Chadd *
237ce725c8eSAdrian Chadd * It's a global flag, not a per-try flag, so we clear
238ce725c8eSAdrian Chadd * it if any of the rate entries aren't 11n.
239ce725c8eSAdrian Chadd */
240a0391187SAdrian Chadd do_ldpc = 0;
2418f1e1139SAndriy Voskoboinyk if ((ni->ni_vap->iv_flags_ht & IEEE80211_FHT_LDPC_TX) &&
242ce725c8eSAdrian Chadd (ni->ni_htcap & IEEE80211_HTCAP_LDPC))
243ce725c8eSAdrian Chadd do_ldpc = 1;
244ffa25becSAdrian Chadd
245ffa25becSAdrian Chadd /*
246ffa25becSAdrian Chadd * The 11n duration calculation doesn't know about LDPC,
247ffa25becSAdrian Chadd * so don't enable it for positioning.
248ffa25becSAdrian Chadd */
249ffa25becSAdrian Chadd if (bf->bf_flags & ATH_BUF_TOA_PROBE)
250ffa25becSAdrian Chadd do_ldpc = 0;
251ffa25becSAdrian Chadd
252ce725c8eSAdrian Chadd do_stbc = 0;
253eb6f0de0SAdrian Chadd
254eb6f0de0SAdrian Chadd for (i = 0; i < ATH_RC_NUM; i++) {
255eb6f0de0SAdrian Chadd rc[i].flags = 0;
256eb6f0de0SAdrian Chadd if (rc[i].tries == 0)
257eb6f0de0SAdrian Chadd continue;
258eb6f0de0SAdrian Chadd
259eb6f0de0SAdrian Chadd rate = rt->info[rc[i].rix].rateCode;
260eb6f0de0SAdrian Chadd
261eb6f0de0SAdrian Chadd /*
26256129906SAdrian Chadd * Only enable short preamble for legacy rates
263eb6f0de0SAdrian Chadd */
2647a27f0a3SAdrian Chadd if ((! IS_HT_RATE(rate)) && bf->bf_state.bfs_shpream)
265eb6f0de0SAdrian Chadd rate |= rt->info[rc[i].rix].shortPreamble;
266eb6f0de0SAdrian Chadd
267eb6f0de0SAdrian Chadd /*
268eb6f0de0SAdrian Chadd * Save this, used by the TX and completion code
269eb6f0de0SAdrian Chadd */
270eb6f0de0SAdrian Chadd rc[i].ratecode = rate;
271eb6f0de0SAdrian Chadd
272875a9451SAdrian Chadd if (bf->bf_state.bfs_txflags &
273eb6f0de0SAdrian Chadd (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA))
274eb6f0de0SAdrian Chadd rc[i].flags |= ATH_RC_RTSCTS_FLAG;
275eb6f0de0SAdrian Chadd
276ce725c8eSAdrian Chadd /*
277ce725c8eSAdrian Chadd * If we can't do LDPC, don't.
278ce725c8eSAdrian Chadd */
279ce725c8eSAdrian Chadd if (! IS_HT_RATE(rate))
280ce725c8eSAdrian Chadd do_ldpc = 0;
281ce725c8eSAdrian Chadd
282eb6f0de0SAdrian Chadd /* Only enable shortgi, 2040, dual-stream if HT is set */
283eb6f0de0SAdrian Chadd if (IS_HT_RATE(rate)) {
284eb6f0de0SAdrian Chadd rc[i].flags |= ATH_RC_HT_FLAG;
285eb6f0de0SAdrian Chadd
286ca389486SBjoern A. Zeeb if (ni->ni_chw == IEEE80211_STA_RX_BW_40)
287eb6f0de0SAdrian Chadd rc[i].flags |= ATH_RC_CW40_FLAG;
288eb6f0de0SAdrian Chadd
289ffa25becSAdrian Chadd /*
290ffa25becSAdrian Chadd * NOTE: Don't do short-gi for positioning frames.
291ffa25becSAdrian Chadd *
292ffa25becSAdrian Chadd * For now, the ath_hal and net80211 HT duration
293ffa25becSAdrian Chadd * calculation rounds up the 11n data txtime
294ffa25becSAdrian Chadd * to the nearest multiple of 3.6 microseconds
295ffa25becSAdrian Chadd * and doesn't return the fractional part, so
296ffa25becSAdrian Chadd * we are always "out" by some amount.
297ffa25becSAdrian Chadd */
298ca389486SBjoern A. Zeeb if (ni->ni_chw == IEEE80211_STA_RX_BW_40 &&
2993d54d9e3SAdrian Chadd ieee80211_ht_check_tx_shortgi_40(ni) &&
300ffa25becSAdrian Chadd (bf->bf_flags & ATH_BUF_TOA_PROBE) == 0) {
301eb6f0de0SAdrian Chadd rc[i].flags |= ATH_RC_SGI_FLAG;
302ffa25becSAdrian Chadd }
303eb6f0de0SAdrian Chadd
304*50ec1e7aSAdrian Chadd if (ni->ni_chw == IEEE80211_STA_RX_BW_20 &&
3053d54d9e3SAdrian Chadd ieee80211_ht_check_tx_shortgi_20(ni) &&
306ffa25becSAdrian Chadd (bf->bf_flags & ATH_BUF_TOA_PROBE) == 0) {
307eb6f0de0SAdrian Chadd rc[i].flags |= ATH_RC_SGI_FLAG;
308ffa25becSAdrian Chadd }
309eb6f0de0SAdrian Chadd
31056129906SAdrian Chadd /*
31156129906SAdrian Chadd * If we have STBC TX enabled and the receiver
31256129906SAdrian Chadd * can receive (at least) 1 stream STBC, AND it's
31356129906SAdrian Chadd * MCS 0-7, AND we have at least two chains enabled,
314ffa25becSAdrian Chadd * and we're not doing positioning, enable STBC.
31556129906SAdrian Chadd */
31656129906SAdrian Chadd if (ic->ic_htcaps & IEEE80211_HTCAP_TXSTBC &&
317c969f82dSAdrian Chadd (ni->ni_vap->iv_flags_ht & IEEE80211_FHT_STBC_TX) &&
318c969f82dSAdrian Chadd (ni->ni_htcap & IEEE80211_HTCAP_RXSTBC) &&
31956129906SAdrian Chadd (sc->sc_cur_txchainmask > 1) &&
320ffa25becSAdrian Chadd (HT_RC_2_STREAMS(rate) == 1) &&
321ffa25becSAdrian Chadd (bf->bf_flags & ATH_BUF_TOA_PROBE) == 0) {
32256129906SAdrian Chadd rc[i].flags |= ATH_RC_STBC_FLAG;
323ce725c8eSAdrian Chadd do_stbc = 1;
32456129906SAdrian Chadd }
32556129906SAdrian Chadd
326de00e5cbSAdrian Chadd /*
327de00e5cbSAdrian Chadd * Dual / Triple stream rate?
328de00e5cbSAdrian Chadd */
329de00e5cbSAdrian Chadd if (HT_RC_2_STREAMS(rate) == 2)
330de00e5cbSAdrian Chadd rc[i].flags |= ATH_RC_DS_FLAG;
331de00e5cbSAdrian Chadd else if (HT_RC_2_STREAMS(rate) == 3)
332de00e5cbSAdrian Chadd rc[i].flags |= ATH_RC_TS_FLAG;
333eb6f0de0SAdrian Chadd }
334eb6f0de0SAdrian Chadd
335eb6f0de0SAdrian Chadd /*
336de00e5cbSAdrian Chadd * Calculate the maximum TX power cap for the current
337de00e5cbSAdrian Chadd * node.
338de00e5cbSAdrian Chadd */
339de00e5cbSAdrian Chadd rc[i].tx_power_cap = ieee80211_get_node_txpower(ni);
340de00e5cbSAdrian Chadd
341de00e5cbSAdrian Chadd /*
342eb6f0de0SAdrian Chadd * Calculate the maximum 4ms frame length based
343eb6f0de0SAdrian Chadd * on the MCS rate, SGI and channel width flags.
344eb6f0de0SAdrian Chadd */
345eb6f0de0SAdrian Chadd if ((rc[i].flags & ATH_RC_HT_FLAG) &&
346eb6f0de0SAdrian Chadd (HT_RC_2_MCS(rate) < 32)) {
347eb6f0de0SAdrian Chadd int j;
348eb6f0de0SAdrian Chadd if (rc[i].flags & ATH_RC_CW40_FLAG) {
349eb6f0de0SAdrian Chadd if (rc[i].flags & ATH_RC_SGI_FLAG)
350eb6f0de0SAdrian Chadd j = MCS_HT40_SGI;
351eb6f0de0SAdrian Chadd else
352eb6f0de0SAdrian Chadd j = MCS_HT40;
353eb6f0de0SAdrian Chadd } else {
354eb6f0de0SAdrian Chadd if (rc[i].flags & ATH_RC_SGI_FLAG)
355eb6f0de0SAdrian Chadd j = MCS_HT20_SGI;
356eb6f0de0SAdrian Chadd else
357eb6f0de0SAdrian Chadd j = MCS_HT20;
358eb6f0de0SAdrian Chadd }
359eb6f0de0SAdrian Chadd rc[i].max4msframelen =
360eb6f0de0SAdrian Chadd ath_max_4ms_framelen[j][HT_RC_2_MCS(rate)];
361eb6f0de0SAdrian Chadd } else
362eb6f0de0SAdrian Chadd rc[i].max4msframelen = 0;
363eb6f0de0SAdrian Chadd DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
364eb6f0de0SAdrian Chadd "%s: i=%d, rate=0x%x, flags=0x%x, max4ms=%d\n",
365eb6f0de0SAdrian Chadd __func__, i, rate, rc[i].flags, rc[i].max4msframelen);
366eb6f0de0SAdrian Chadd }
367ce725c8eSAdrian Chadd
368ce725c8eSAdrian Chadd /*
369ce725c8eSAdrian Chadd * LDPC is a global flag, so ...
370ce725c8eSAdrian Chadd */
371ce725c8eSAdrian Chadd if (do_ldpc) {
372ce725c8eSAdrian Chadd bf->bf_state.bfs_txflags |= HAL_TXDESC_LDPC;
373ce725c8eSAdrian Chadd sc->sc_stats.ast_tx_ldpc++;
374ce725c8eSAdrian Chadd }
375ce725c8eSAdrian Chadd
376ce725c8eSAdrian Chadd if (do_stbc) {
377ce725c8eSAdrian Chadd sc->sc_stats.ast_tx_stbc++;
378ce725c8eSAdrian Chadd }
379eb6f0de0SAdrian Chadd }
380eb6f0de0SAdrian Chadd
381eb6f0de0SAdrian Chadd /*
382eb6f0de0SAdrian Chadd * Return the number of delimiters to be added to
383eb6f0de0SAdrian Chadd * meet the minimum required mpdudensity.
384eb6f0de0SAdrian Chadd *
385eb6f0de0SAdrian Chadd * Caller should make sure that the rate is HT.
386eb6f0de0SAdrian Chadd *
387eb6f0de0SAdrian Chadd * TODO: is this delimiter calculation supposed to be the
388eb6f0de0SAdrian Chadd * total frame length, the hdr length, the data length (including
389eb6f0de0SAdrian Chadd * delimiters, padding, CRC, etc) or ?
390eb6f0de0SAdrian Chadd *
391eb6f0de0SAdrian Chadd * TODO: this should ensure that the rate control information
392eb6f0de0SAdrian Chadd * HAS been setup for the first rate.
393eb6f0de0SAdrian Chadd *
394eb6f0de0SAdrian Chadd * TODO: ensure this is only called for MCS rates.
395eb6f0de0SAdrian Chadd *
396eb6f0de0SAdrian Chadd * TODO: enforce MCS < 31
397eb6f0de0SAdrian Chadd */
398eb6f0de0SAdrian Chadd static int
ath_compute_num_delims(struct ath_softc * sc,struct ath_buf * first_bf,uint16_t pktlen,int is_first)399eb6f0de0SAdrian Chadd ath_compute_num_delims(struct ath_softc *sc, struct ath_buf *first_bf,
400a2d74cc3SAdrian Chadd uint16_t pktlen, int is_first)
401eb6f0de0SAdrian Chadd {
402eb6f0de0SAdrian Chadd const HAL_RATE_TABLE *rt = sc->sc_currates;
403eb6f0de0SAdrian Chadd struct ieee80211_node *ni = first_bf->bf_node;
404eb6f0de0SAdrian Chadd int ndelim, mindelim = 0;
405eb6f0de0SAdrian Chadd int mpdudensity; /* in 1/100'th of a microsecond */
406c969f82dSAdrian Chadd int peer_mpdudensity; /* net80211 value */
407eb6f0de0SAdrian Chadd uint8_t rc, rix, flags;
408eb6f0de0SAdrian Chadd int width, half_gi;
409eb6f0de0SAdrian Chadd uint32_t nsymbits, nsymbols;
410eb6f0de0SAdrian Chadd uint16_t minlen;
411eb6f0de0SAdrian Chadd
412eb6f0de0SAdrian Chadd /*
413c969f82dSAdrian Chadd * Get the advertised density from the node.
414eb6f0de0SAdrian Chadd */
4153d54d9e3SAdrian Chadd peer_mpdudensity = ieee80211_ht_get_node_ampdu_density(ni);
416c969f82dSAdrian Chadd
417c969f82dSAdrian Chadd /*
418c969f82dSAdrian Chadd * Convert the A-MPDU density net80211 value to a 1/100 microsecond
419c969f82dSAdrian Chadd * value for subsequent calculations.
420c969f82dSAdrian Chadd */
421c969f82dSAdrian Chadd if (peer_mpdudensity > IEEE80211_HTCAP_MPDUDENSITY_16)
422eb6f0de0SAdrian Chadd mpdudensity = 1600; /* maximum density */
423eb6f0de0SAdrian Chadd else
424c969f82dSAdrian Chadd mpdudensity = ieee80211_mpdudensity_map[peer_mpdudensity];
425eb6f0de0SAdrian Chadd
426eb6f0de0SAdrian Chadd /* Select standard number of delimiters based on frame length */
427eb6f0de0SAdrian Chadd ndelim = ATH_AGGR_GET_NDELIM(pktlen);
428eb6f0de0SAdrian Chadd
429eb6f0de0SAdrian Chadd /*
430eb6f0de0SAdrian Chadd * If encryption is enabled, add extra delimiters to let the
431eb6f0de0SAdrian Chadd * crypto hardware catch up. This could be tuned per-MAC and
432eb6f0de0SAdrian Chadd * per-rate, but for now we'll simply assume encryption is
433eb6f0de0SAdrian Chadd * always enabled.
4344a502c33SAdrian Chadd *
4354a502c33SAdrian Chadd * Also note that the Atheros reference driver inserts two
4364a502c33SAdrian Chadd * delimiters by default for pre-AR9380 peers. This will
4374a502c33SAdrian Chadd * include "that" required delimiter.
438eb6f0de0SAdrian Chadd */
439eb6f0de0SAdrian Chadd ndelim += ATH_AGGR_ENCRYPTDELIM;
440eb6f0de0SAdrian Chadd
44164dbfc6dSAdrian Chadd /*
442e4b7980cSGordon Bergling * For AR9380, there's a minimum number of delimiters
44364dbfc6dSAdrian Chadd * required when doing RTS.
4444a502c33SAdrian Chadd *
445a2d74cc3SAdrian Chadd * XXX TODO: this is only needed if (a) RTS/CTS is enabled for
446a2d74cc3SAdrian Chadd * this exchange, and (b) (done) this is the first sub-frame
447a2d74cc3SAdrian Chadd * in the aggregate.
44864dbfc6dSAdrian Chadd */
44964dbfc6dSAdrian Chadd if (sc->sc_use_ent && (sc->sc_ent_cfg & AH_ENT_RTSCTS_DELIM_WAR)
450a2d74cc3SAdrian Chadd && ndelim < AH_FIRST_DESC_NDELIMS && is_first)
45164dbfc6dSAdrian Chadd ndelim = AH_FIRST_DESC_NDELIMS;
45264dbfc6dSAdrian Chadd
453a54ecf78SAdrian Chadd /*
454a54ecf78SAdrian Chadd * If sc_delim_min_pad is non-zero, enforce it as the minimum
455a54ecf78SAdrian Chadd * pad delimiter count.
456a54ecf78SAdrian Chadd */
457a54ecf78SAdrian Chadd if (sc->sc_delim_min_pad != 0)
458a54ecf78SAdrian Chadd ndelim = MAX(ndelim, sc->sc_delim_min_pad);
459a54ecf78SAdrian Chadd
460eb6f0de0SAdrian Chadd DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
461eb6f0de0SAdrian Chadd "%s: pktlen=%d, ndelim=%d, mpdudensity=%d\n",
462eb6f0de0SAdrian Chadd __func__, pktlen, ndelim, mpdudensity);
463eb6f0de0SAdrian Chadd
464eb6f0de0SAdrian Chadd /*
465eb6f0de0SAdrian Chadd * If the MPDU density is 0, we can return here.
466eb6f0de0SAdrian Chadd * Otherwise, we need to convert the desired mpdudensity
467eb6f0de0SAdrian Chadd * into a byte length, based on the rate in the subframe.
468eb6f0de0SAdrian Chadd */
469eb6f0de0SAdrian Chadd if (mpdudensity == 0)
470eb6f0de0SAdrian Chadd return ndelim;
471eb6f0de0SAdrian Chadd
472eb6f0de0SAdrian Chadd /*
473eb6f0de0SAdrian Chadd * Convert desired mpdu density from microeconds to bytes based
474eb6f0de0SAdrian Chadd * on highest rate in rate series (i.e. first rate) to determine
475eb6f0de0SAdrian Chadd * required minimum length for subframe. Take into account
476eb6f0de0SAdrian Chadd * whether high rate is 20 or 40Mhz and half or full GI.
477eb6f0de0SAdrian Chadd */
478eb6f0de0SAdrian Chadd rix = first_bf->bf_state.bfs_rc[0].rix;
479eb6f0de0SAdrian Chadd rc = rt->info[rix].rateCode;
480eb6f0de0SAdrian Chadd flags = first_bf->bf_state.bfs_rc[0].flags;
481eb6f0de0SAdrian Chadd width = !! (flags & ATH_RC_CW40_FLAG);
482eb6f0de0SAdrian Chadd half_gi = !! (flags & ATH_RC_SGI_FLAG);
483eb6f0de0SAdrian Chadd
484eb6f0de0SAdrian Chadd /*
485eb6f0de0SAdrian Chadd * mpdudensity is in 1/100th of a usec, so divide by 100
486eb6f0de0SAdrian Chadd */
487eb6f0de0SAdrian Chadd if (half_gi)
488eb6f0de0SAdrian Chadd nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(mpdudensity);
489eb6f0de0SAdrian Chadd else
490eb6f0de0SAdrian Chadd nsymbols = NUM_SYMBOLS_PER_USEC(mpdudensity);
491eb6f0de0SAdrian Chadd nsymbols /= 100;
492eb6f0de0SAdrian Chadd
493eb6f0de0SAdrian Chadd if (nsymbols == 0)
494eb6f0de0SAdrian Chadd nsymbols = 1;
495eb6f0de0SAdrian Chadd
496eb6f0de0SAdrian Chadd nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width];
497eb6f0de0SAdrian Chadd minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
498eb6f0de0SAdrian Chadd
499eb6f0de0SAdrian Chadd /*
500eb6f0de0SAdrian Chadd * Min length is the minimum frame length for the
501eb6f0de0SAdrian Chadd * required MPDU density.
502eb6f0de0SAdrian Chadd */
503eb6f0de0SAdrian Chadd if (pktlen < minlen) {
504eb6f0de0SAdrian Chadd mindelim = (minlen - pktlen) / ATH_AGGR_DELIM_SZ;
505eb6f0de0SAdrian Chadd ndelim = MAX(mindelim, ndelim);
506eb6f0de0SAdrian Chadd }
507eb6f0de0SAdrian Chadd
508eb6f0de0SAdrian Chadd DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
509eb6f0de0SAdrian Chadd "%s: pktlen=%d, minlen=%d, rix=%x, rc=%x, width=%d, hgi=%d, ndelim=%d\n",
510eb6f0de0SAdrian Chadd __func__, pktlen, minlen, rix, rc, width, half_gi, ndelim);
511eb6f0de0SAdrian Chadd
512eb6f0de0SAdrian Chadd return ndelim;
513eb6f0de0SAdrian Chadd }
514eb6f0de0SAdrian Chadd
515eb6f0de0SAdrian Chadd /*
516707210ffSAdrian Chadd * XXX TODO: put into net80211
517707210ffSAdrian Chadd */
518707210ffSAdrian Chadd static int
ath_rx_ampdu_to_byte(char a)519707210ffSAdrian Chadd ath_rx_ampdu_to_byte(char a)
520707210ffSAdrian Chadd {
521707210ffSAdrian Chadd switch (a) {
522707210ffSAdrian Chadd case IEEE80211_HTCAP_MAXRXAMPDU_16K:
523707210ffSAdrian Chadd return 16384;
524707210ffSAdrian Chadd break;
525707210ffSAdrian Chadd case IEEE80211_HTCAP_MAXRXAMPDU_32K:
526707210ffSAdrian Chadd return 32768;
527707210ffSAdrian Chadd break;
528707210ffSAdrian Chadd case IEEE80211_HTCAP_MAXRXAMPDU_64K:
529707210ffSAdrian Chadd return 65536;
530707210ffSAdrian Chadd break;
531707210ffSAdrian Chadd case IEEE80211_HTCAP_MAXRXAMPDU_8K:
532707210ffSAdrian Chadd default:
533707210ffSAdrian Chadd return 8192;
534707210ffSAdrian Chadd break;
535707210ffSAdrian Chadd }
536707210ffSAdrian Chadd }
537707210ffSAdrian Chadd
538707210ffSAdrian Chadd /*
539eb6f0de0SAdrian Chadd * Fetch the aggregation limit.
540eb6f0de0SAdrian Chadd *
541eb6f0de0SAdrian Chadd * It's the lowest of the four rate series 4ms frame length.
542c969f82dSAdrian Chadd *
543c969f82dSAdrian Chadd * Also take into account the hardware specific limits (8KiB on AR5416)
544c969f82dSAdrian Chadd * and per-peer limits in non-STA mode.
545eb6f0de0SAdrian Chadd */
546eb6f0de0SAdrian Chadd static int
ath_get_aggr_limit(struct ath_softc * sc,struct ieee80211_node * ni,struct ath_buf * bf)547c969f82dSAdrian Chadd ath_get_aggr_limit(struct ath_softc *sc, struct ieee80211_node *ni,
548c969f82dSAdrian Chadd struct ath_buf *bf)
549eb6f0de0SAdrian Chadd {
5504a502c33SAdrian Chadd int amin = ATH_AGGR_MAXSIZE;
551eb6f0de0SAdrian Chadd int i;
552eb6f0de0SAdrian Chadd
553c969f82dSAdrian Chadd /* Extract out the maximum configured driver A-MPDU limit */
5544a502c33SAdrian Chadd if (sc->sc_aggr_limit > 0 && sc->sc_aggr_limit < ATH_AGGR_MAXSIZE)
5554a502c33SAdrian Chadd amin = sc->sc_aggr_limit;
5564a502c33SAdrian Chadd
5573d54d9e3SAdrian Chadd /* Check the vap and node configured transmit limit */
5583d54d9e3SAdrian Chadd amin = MIN(amin,
5593d54d9e3SAdrian Chadd ath_rx_ampdu_to_byte(ieee80211_ht_get_node_ampdu_limit(ni)));
560c969f82dSAdrian Chadd
561b25c1f2aSAdrian Chadd for (i = 0; i < ATH_RC_NUM; i++) {
562eb6f0de0SAdrian Chadd if (bf->bf_state.bfs_rc[i].tries == 0)
563eb6f0de0SAdrian Chadd continue;
564eb6f0de0SAdrian Chadd amin = MIN(amin, bf->bf_state.bfs_rc[i].max4msframelen);
565eb6f0de0SAdrian Chadd }
566eb6f0de0SAdrian Chadd
56728dc144eSAdrian Chadd DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
56828dc144eSAdrian Chadd "%s: aggr_limit=%d, iv_ampdu_limit=%d, "
56928dc144eSAdrian Chadd "peer maxrxampdu=%d, max frame len=%d\n",
57028dc144eSAdrian Chadd __func__,
57128dc144eSAdrian Chadd sc->sc_aggr_limit,
5723d54d9e3SAdrian Chadd ni->ni_vap->iv_ampdu_limit,
573fe5ebb23SBjoern A. Zeeb _IEEE80211_MASKSHIFT(ni->ni_htparam, IEEE80211_HTCAP_MAXRXAMPDU),
57428dc144eSAdrian Chadd amin);
575eb6f0de0SAdrian Chadd
576eb6f0de0SAdrian Chadd return amin;
577eb6f0de0SAdrian Chadd }
5784b44f6f2SAdrian Chadd
5794b44f6f2SAdrian Chadd /*
5804b44f6f2SAdrian Chadd * Setup a 11n rate series structure
5814b44f6f2SAdrian Chadd *
5824b44f6f2SAdrian Chadd * This should be called for both legacy and MCS rates.
583eb6f0de0SAdrian Chadd *
584de00e5cbSAdrian Chadd * This uses the rate series stuf from ath_tx_rate_fill_rcflags().
585de00e5cbSAdrian Chadd *
586eb6f0de0SAdrian Chadd * It, along with ath_buf_set_rate, must be called -after- a burst
587eb6f0de0SAdrian Chadd * or aggregate is setup.
5884b44f6f2SAdrian Chadd */
5894b44f6f2SAdrian Chadd static void
ath_rateseries_setup(struct ath_softc * sc,struct ieee80211_node * ni,struct ath_buf * bf,HAL_11N_RATE_SERIES * series)5904b44f6f2SAdrian Chadd ath_rateseries_setup(struct ath_softc *sc, struct ieee80211_node *ni,
591eb6f0de0SAdrian Chadd struct ath_buf *bf, HAL_11N_RATE_SERIES *series)
5924b44f6f2SAdrian Chadd {
5934b44f6f2SAdrian Chadd struct ieee80211com *ic = ni->ni_ic;
5944b44f6f2SAdrian Chadd struct ath_hal *ah = sc->sc_ah;
5954b44f6f2SAdrian Chadd HAL_BOOL shortPreamble = AH_FALSE;
5964b44f6f2SAdrian Chadd const HAL_RATE_TABLE *rt = sc->sc_currates;
5974b44f6f2SAdrian Chadd int i;
598eb6f0de0SAdrian Chadd int pktlen;
599eb6f0de0SAdrian Chadd struct ath_rc_series *rc = bf->bf_state.bfs_rc;
6004b44f6f2SAdrian Chadd
6014b44f6f2SAdrian Chadd if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
6024b44f6f2SAdrian Chadd (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE))
6034b44f6f2SAdrian Chadd shortPreamble = AH_TRUE;
6044b44f6f2SAdrian Chadd
605eb6f0de0SAdrian Chadd /*
606eb6f0de0SAdrian Chadd * If this is the first frame in an aggregate series,
607eb6f0de0SAdrian Chadd * use the aggregate length.
608eb6f0de0SAdrian Chadd */
609eb6f0de0SAdrian Chadd if (bf->bf_state.bfs_aggr)
610eb6f0de0SAdrian Chadd pktlen = bf->bf_state.bfs_al;
611eb6f0de0SAdrian Chadd else
612eb6f0de0SAdrian Chadd pktlen = bf->bf_state.bfs_pktlen;
613eb6f0de0SAdrian Chadd
614eb6f0de0SAdrian Chadd /*
615eb6f0de0SAdrian Chadd * XXX TODO: modify this routine to use the bfs_rc[x].flags
616eb6f0de0SAdrian Chadd * XXX fields.
617eb6f0de0SAdrian Chadd */
6184b44f6f2SAdrian Chadd memset(series, 0, sizeof(HAL_11N_RATE_SERIES) * 4);
619b25c1f2aSAdrian Chadd for (i = 0; i < ATH_RC_NUM; i++) {
620146b49d8SAdrian Chadd /* Only set flags for actual TX attempts */
621eb6f0de0SAdrian Chadd if (rc[i].tries == 0)
622146b49d8SAdrian Chadd continue;
623146b49d8SAdrian Chadd
624eb6f0de0SAdrian Chadd series[i].Tries = rc[i].tries;
625146b49d8SAdrian Chadd
626146b49d8SAdrian Chadd /*
6274a502c33SAdrian Chadd * XXX TODO: When the NIC is capable of three stream TX,
6284a502c33SAdrian Chadd * transmit 1/2 stream rates on two streams.
6294a502c33SAdrian Chadd *
6304a502c33SAdrian Chadd * This reduces the power consumption of the NIC and
6314a502c33SAdrian Chadd * keeps it within the PCIe slot power limits.
6324a502c33SAdrian Chadd */
6336322256bSAdrian Chadd series[i].ChSel = sc->sc_cur_txchainmask;
634146b49d8SAdrian Chadd
63556129906SAdrian Chadd /*
63656129906SAdrian Chadd * Setup rate and TX power cap for this series.
63756129906SAdrian Chadd */
63856129906SAdrian Chadd series[i].Rate = rt->info[rc[i].rix].rateCode;
63956129906SAdrian Chadd series[i].RateIndex = rc[i].rix;
640de00e5cbSAdrian Chadd series[i].tx_power_cap = rc[i].tx_power_cap;
64156129906SAdrian Chadd
64256129906SAdrian Chadd /*
64356129906SAdrian Chadd * Enable RTS/CTS as appropriate.
64456129906SAdrian Chadd */
645de00e5cbSAdrian Chadd if (rc[i].flags & ATH_RC_RTSCTS_FLAG)
6464b44f6f2SAdrian Chadd series[i].RateFlags |= HAL_RATESERIES_RTS_CTS;
647146b49d8SAdrian Chadd
648532f2442SAdrian Chadd /*
649de00e5cbSAdrian Chadd * 11n rate? Update 11n flags.
650532f2442SAdrian Chadd */
651de00e5cbSAdrian Chadd if (rc[i].flags & ATH_RC_HT_FLAG) {
652de00e5cbSAdrian Chadd if (rc[i].flags & ATH_RC_CW40_FLAG)
6534b44f6f2SAdrian Chadd series[i].RateFlags |= HAL_RATESERIES_2040;
6546246be6eSAdrian Chadd
655de00e5cbSAdrian Chadd if (rc[i].flags & ATH_RC_SGI_FLAG)
6564b44f6f2SAdrian Chadd series[i].RateFlags |= HAL_RATESERIES_HALFGI;
6576246be6eSAdrian Chadd
658de00e5cbSAdrian Chadd if (rc[i].flags & ATH_RC_STBC_FLAG)
6591a3a5607SAdrian Chadd series[i].RateFlags |= HAL_RATESERIES_STBC;
6601a3a5607SAdrian Chadd }
6616322256bSAdrian Chadd
662b25c1f2aSAdrian Chadd /*
663f026d693SAdrian Chadd * TODO: If we're all doing 11n rates then we can set LDPC.
664f026d693SAdrian Chadd * If we've been asked to /do/ LDPC but we are handed a
665f026d693SAdrian Chadd * legacy rate, then we should complain. Loudly.
666f026d693SAdrian Chadd */
667f026d693SAdrian Chadd
668f026d693SAdrian Chadd /*
669b25c1f2aSAdrian Chadd * PktDuration doesn't include slot, ACK, RTS, etc timing -
670b25c1f2aSAdrian Chadd * it's just the packet duration
671b25c1f2aSAdrian Chadd */
672de00e5cbSAdrian Chadd if (rc[i].flags & ATH_RC_HT_FLAG) {
6734b44f6f2SAdrian Chadd series[i].PktDuration =
6744b44f6f2SAdrian Chadd ath_computedur_ht(pktlen
6759a97e25eSAdrian Chadd , series[i].Rate
676fce6d676SAdrian Chadd , HT_RC_2_STREAMS(series[i].Rate)
677fce6d676SAdrian Chadd , series[i].RateFlags & HAL_RATESERIES_2040
678f449ab1cSAdrian Chadd , series[i].RateFlags & HAL_RATESERIES_HALFGI);
6794b44f6f2SAdrian Chadd } else {
6801198947aSAdrian Chadd if (shortPreamble)
681eb6f0de0SAdrian Chadd series[i].Rate |=
682eb6f0de0SAdrian Chadd rt->info[rc[i].rix].shortPreamble;
6837ff1939dSAdrian Chadd /* XXX TODO: don't include SIFS */
6844b44f6f2SAdrian Chadd series[i].PktDuration = ath_hal_computetxtime(ah,
6857ff1939dSAdrian Chadd rt, pktlen, rc[i].rix, shortPreamble, AH_TRUE);
6864b44f6f2SAdrian Chadd }
6874b44f6f2SAdrian Chadd }
6884b44f6f2SAdrian Chadd }
6894b44f6f2SAdrian Chadd
69019b34b56SAdrian Chadd #ifdef ATH_DEBUG
6914b44f6f2SAdrian Chadd static void
ath_rateseries_print(struct ath_softc * sc,HAL_11N_RATE_SERIES * series)692b25c1f2aSAdrian Chadd ath_rateseries_print(struct ath_softc *sc, HAL_11N_RATE_SERIES *series)
6934b44f6f2SAdrian Chadd {
6944b44f6f2SAdrian Chadd int i;
695b25c1f2aSAdrian Chadd for (i = 0; i < ATH_RC_NUM; i++) {
696b25c1f2aSAdrian Chadd device_printf(sc->sc_dev ,"series %d: rate %x; tries %d; "
69764dbfc6dSAdrian Chadd "pktDuration %d; chSel %d; txpowcap %d, rateFlags %x\n",
6984b44f6f2SAdrian Chadd i,
6994b44f6f2SAdrian Chadd series[i].Rate,
7004b44f6f2SAdrian Chadd series[i].Tries,
7014b44f6f2SAdrian Chadd series[i].PktDuration,
7024b44f6f2SAdrian Chadd series[i].ChSel,
70364dbfc6dSAdrian Chadd series[i].tx_power_cap,
7044b44f6f2SAdrian Chadd series[i].RateFlags);
7054b44f6f2SAdrian Chadd }
7064b44f6f2SAdrian Chadd }
7074b44f6f2SAdrian Chadd #endif
7084b44f6f2SAdrian Chadd
7094b44f6f2SAdrian Chadd /*
7104b44f6f2SAdrian Chadd * Setup the 11n rate scenario and burst duration for the given TX descriptor
7114b44f6f2SAdrian Chadd * list.
7124b44f6f2SAdrian Chadd *
7134b44f6f2SAdrian Chadd * This isn't useful for sending beacon frames, which has different needs
7144b44f6f2SAdrian Chadd * wrt what's passed into the rate scenario function.
7154b44f6f2SAdrian Chadd */
7164b44f6f2SAdrian Chadd void
ath_buf_set_rate(struct ath_softc * sc,struct ieee80211_node * ni,struct ath_buf * bf)717eb6f0de0SAdrian Chadd ath_buf_set_rate(struct ath_softc *sc, struct ieee80211_node *ni,
718eb6f0de0SAdrian Chadd struct ath_buf *bf)
7194b44f6f2SAdrian Chadd {
7204b44f6f2SAdrian Chadd HAL_11N_RATE_SERIES series[4];
7214b44f6f2SAdrian Chadd struct ath_desc *ds = bf->bf_desc;
7224b44f6f2SAdrian Chadd struct ath_hal *ah = sc->sc_ah;
723eb6f0de0SAdrian Chadd int is_pspoll = (bf->bf_state.bfs_atype == HAL_PKT_TYPE_PSPOLL);
724eb6f0de0SAdrian Chadd int ctsrate = bf->bf_state.bfs_ctsrate;
725875a9451SAdrian Chadd int flags = bf->bf_state.bfs_txflags;
7264b44f6f2SAdrian Chadd
7274b44f6f2SAdrian Chadd /* Setup rate scenario */
7284b44f6f2SAdrian Chadd memset(&series, 0, sizeof(series));
7294b44f6f2SAdrian Chadd
730eb6f0de0SAdrian Chadd ath_rateseries_setup(sc, ni, bf, series);
7314b44f6f2SAdrian Chadd
73219b34b56SAdrian Chadd #ifdef ATH_DEBUG
73320b0b9eaSAdrian Chadd if (sc->sc_debug & ATH_DEBUG_XMIT)
734b25c1f2aSAdrian Chadd ath_rateseries_print(sc, series);
7352b5684a8SAdrian Chadd #endif
7362b5684a8SAdrian Chadd
7374b44f6f2SAdrian Chadd /* Set rate scenario */
738b25c1f2aSAdrian Chadd /*
739b25c1f2aSAdrian Chadd * Note: Don't allow hardware to override the duration on
740b25c1f2aSAdrian Chadd * ps-poll packets.
741b25c1f2aSAdrian Chadd */
7424b44f6f2SAdrian Chadd ath_hal_set11nratescenario(ah, ds,
743bf26df36SAdrian Chadd !is_pspoll, /* whether to override the duration or not */
7444b44f6f2SAdrian Chadd ctsrate, /* rts/cts rate */
7454b44f6f2SAdrian Chadd series, /* 11n rate series */
7464b44f6f2SAdrian Chadd 4, /* number of series */
7474b44f6f2SAdrian Chadd flags);
7484b44f6f2SAdrian Chadd
7494b44f6f2SAdrian Chadd /* Set burst duration */
750eb6f0de0SAdrian Chadd /*
751eb6f0de0SAdrian Chadd * This is only required when doing 11n burst, not aggregation
752eb6f0de0SAdrian Chadd * ie, if there's a second frame in a RIFS or A-MPDU burst
753eb6f0de0SAdrian Chadd * w/ >1 A-MPDU frame bursting back to back.
754eb6f0de0SAdrian Chadd * Normal A-MPDU doesn't do bursting -between- aggregates.
755eb6f0de0SAdrian Chadd *
756eb6f0de0SAdrian Chadd * .. and it's highly likely this won't ever be implemented
757eb6f0de0SAdrian Chadd */
7584b44f6f2SAdrian Chadd //ath_hal_set11nburstduration(ah, ds, 8192);
7594b44f6f2SAdrian Chadd }
760eb6f0de0SAdrian Chadd
761eb6f0de0SAdrian Chadd /*
762eb6f0de0SAdrian Chadd * Form an aggregate packet list.
763eb6f0de0SAdrian Chadd *
764eb6f0de0SAdrian Chadd * This function enforces the aggregate restrictions/requirements.
765eb6f0de0SAdrian Chadd *
766eb6f0de0SAdrian Chadd * These are:
767eb6f0de0SAdrian Chadd *
768eb6f0de0SAdrian Chadd * + The aggregate size maximum (64k for AR9160 and later, 8K for
769eb6f0de0SAdrian Chadd * AR5416 when doing RTS frame protection.)
770eb6f0de0SAdrian Chadd * + Maximum number of sub-frames for an aggregate
771eb6f0de0SAdrian Chadd * + The aggregate delimiter size, giving MACs time to do whatever is
772eb6f0de0SAdrian Chadd * needed before each frame
773eb6f0de0SAdrian Chadd * + Enforce the BAW limit
774eb6f0de0SAdrian Chadd *
775eb6f0de0SAdrian Chadd * Each descriptor queued should have the DMA setup.
776eb6f0de0SAdrian Chadd * The rate series, descriptor setup, linking, etc is all done
777eb6f0de0SAdrian Chadd * externally. This routine simply chains them together.
778eb6f0de0SAdrian Chadd * ath_tx_setds_11n() will take care of configuring the per-
779eb6f0de0SAdrian Chadd * descriptor setup, and ath_buf_set_rate() will configure the
780eb6f0de0SAdrian Chadd * rate control.
781eb6f0de0SAdrian Chadd *
782b25c1f2aSAdrian Chadd * The TID lock is required for the entirety of this function.
783b25c1f2aSAdrian Chadd *
784b25c1f2aSAdrian Chadd * If some code in another thread adds to the head of this
785eb6f0de0SAdrian Chadd * list, very strange behaviour will occur. Since retransmission is the
786eb6f0de0SAdrian Chadd * only reason this will occur, and this routine is designed to be called
787eb6f0de0SAdrian Chadd * from within the scheduler task, it won't ever clash with the completion
788eb6f0de0SAdrian Chadd * task.
789eb6f0de0SAdrian Chadd *
790eb6f0de0SAdrian Chadd * So if you want to call this from an upper layer context (eg, to direct-
791eb6f0de0SAdrian Chadd * dispatch aggregate frames to the hardware), please keep this in mind.
792eb6f0de0SAdrian Chadd */
793eb6f0de0SAdrian Chadd ATH_AGGR_STATUS
ath_tx_form_aggr(struct ath_softc * sc,struct ath_node * an,struct ath_tid * tid,ath_bufhead * bf_q)794b25c1f2aSAdrian Chadd ath_tx_form_aggr(struct ath_softc *sc, struct ath_node *an,
795b25c1f2aSAdrian Chadd struct ath_tid *tid, ath_bufhead *bf_q)
796eb6f0de0SAdrian Chadd {
797a108d2d6SAdrian Chadd //struct ieee80211_node *ni = &an->an_node;
798eb6f0de0SAdrian Chadd struct ath_buf *bf, *bf_first = NULL, *bf_prev = NULL;
799eb6f0de0SAdrian Chadd int nframes = 0;
800eb6f0de0SAdrian Chadd uint16_t aggr_limit = 0, al = 0, bpad = 0, al_delta, h_baw;
801eb6f0de0SAdrian Chadd struct ieee80211_tx_ampdu *tap;
802eb6f0de0SAdrian Chadd int status = ATH_AGGR_DONE;
803eb6f0de0SAdrian Chadd int prev_frames = 0; /* XXX for AR5416 burst, not done here */
804eb6f0de0SAdrian Chadd int prev_al = 0; /* XXX also for AR5416 burst */
805eb6f0de0SAdrian Chadd
806375307d4SAdrian Chadd ATH_TX_LOCK_ASSERT(sc);
807eb6f0de0SAdrian Chadd
808eb6f0de0SAdrian Chadd tap = ath_tx_get_tx_tid(an, tid->tid);
809eb6f0de0SAdrian Chadd if (tap == NULL) {
810eb6f0de0SAdrian Chadd status = ATH_AGGR_ERROR;
811eb6f0de0SAdrian Chadd goto finish;
812eb6f0de0SAdrian Chadd }
813eb6f0de0SAdrian Chadd
814cce63444SAdrian Chadd /*
815cce63444SAdrian Chadd * Limit the maximum number of frames in this A-MPDU
816cce63444SAdrian Chadd * to half of the window size. This is done to prevent
817cce63444SAdrian Chadd * sending a LOT of frames that may fail in one batch
818cce63444SAdrian Chadd * when operating in higher MCS rates. If there are more
819cce63444SAdrian Chadd * frames available to send then up to two A-MPDUs will
820cce63444SAdrian Chadd * be queued per hardware queue, so we'll "just" get
821cce63444SAdrian Chadd * a second A-MPDU.
822cce63444SAdrian Chadd */
823eb6f0de0SAdrian Chadd h_baw = tap->txa_wnd / 2;
824eb6f0de0SAdrian Chadd
825eb6f0de0SAdrian Chadd for (;;) {
8263e6cc97fSAdrian Chadd bf = ATH_TID_FIRST(tid);
827eb6f0de0SAdrian Chadd if (bf == NULL) {
828eb6f0de0SAdrian Chadd status = ATH_AGGR_DONE;
829eb6f0de0SAdrian Chadd break;
830cce63444SAdrian Chadd }
831cce63444SAdrian Chadd if (bf_first == NULL) {
832cce63444SAdrian Chadd bf_first = bf;
833eb6f0de0SAdrian Chadd /*
834eb6f0de0SAdrian Chadd * It's the first frame;
835eb6f0de0SAdrian Chadd * set the aggregation limit based on the
836eb6f0de0SAdrian Chadd * rate control decision that has been made.
837eb6f0de0SAdrian Chadd */
838c969f82dSAdrian Chadd aggr_limit = ath_get_aggr_limit(sc, &an->an_node,
839c969f82dSAdrian Chadd bf_first);
840cce63444SAdrian Chadd if (bf_first->bf_state.bfs_rc_maxpktlen > 0) {
841cce63444SAdrian Chadd aggr_limit = MIN(aggr_limit,
842cce63444SAdrian Chadd bf_first->bf_state.bfs_rc_maxpktlen);
843cce63444SAdrian Chadd }
844eb6f0de0SAdrian Chadd }
845eb6f0de0SAdrian Chadd
846eb6f0de0SAdrian Chadd /* Set this early just so things don't get confused */
847eb6f0de0SAdrian Chadd bf->bf_next = NULL;
848eb6f0de0SAdrian Chadd
849eb6f0de0SAdrian Chadd /*
850eb6f0de0SAdrian Chadd * If the frame doesn't have a sequence number that we're
851eb6f0de0SAdrian Chadd * tracking in the BAW (eg NULL QOS data frame), we can't
852eb6f0de0SAdrian Chadd * aggregate it. Stop the aggregation process; the sender
853eb6f0de0SAdrian Chadd * can then TX what's in the list thus far and then
854eb6f0de0SAdrian Chadd * TX the frame individually.
855eb6f0de0SAdrian Chadd */
856eb6f0de0SAdrian Chadd if (! bf->bf_state.bfs_dobaw) {
857eb6f0de0SAdrian Chadd status = ATH_AGGR_NONAGGR;
858eb6f0de0SAdrian Chadd break;
859eb6f0de0SAdrian Chadd }
860eb6f0de0SAdrian Chadd
861eb6f0de0SAdrian Chadd /*
862eb6f0de0SAdrian Chadd * If any of the rates are non-HT, this packet
863eb6f0de0SAdrian Chadd * can't be aggregated.
864eb6f0de0SAdrian Chadd * XXX TODO: add a bf_state flag which gets marked
865eb6f0de0SAdrian Chadd * if any active rate is non-HT.
866eb6f0de0SAdrian Chadd */
867eb6f0de0SAdrian Chadd
868eb6f0de0SAdrian Chadd /*
869eb6f0de0SAdrian Chadd * do not exceed aggregation limit
870eb6f0de0SAdrian Chadd */
871eb6f0de0SAdrian Chadd al_delta = ATH_AGGR_DELIM_SZ + bf->bf_state.bfs_pktlen;
872eb6f0de0SAdrian Chadd if (nframes &&
873eb6f0de0SAdrian Chadd (aggr_limit < (al + bpad + al_delta + prev_al))) {
874eb6f0de0SAdrian Chadd status = ATH_AGGR_LIMITED;
875eb6f0de0SAdrian Chadd break;
876eb6f0de0SAdrian Chadd }
877eb6f0de0SAdrian Chadd
878eb6f0de0SAdrian Chadd /*
879045bc788SAdrian Chadd * If RTS/CTS is set on the first frame, enforce
880045bc788SAdrian Chadd * the RTS aggregate limit.
881045bc788SAdrian Chadd */
882045bc788SAdrian Chadd if (bf_first->bf_state.bfs_txflags &
883045bc788SAdrian Chadd (HAL_TXDESC_CTSENA | HAL_TXDESC_RTSENA)) {
884045bc788SAdrian Chadd if (nframes &&
885045bc788SAdrian Chadd (sc->sc_rts_aggr_limit <
886045bc788SAdrian Chadd (al + bpad + al_delta + prev_al))) {
887045bc788SAdrian Chadd status = ATH_AGGR_8K_LIMITED;
888045bc788SAdrian Chadd break;
889045bc788SAdrian Chadd }
890045bc788SAdrian Chadd }
891045bc788SAdrian Chadd
892045bc788SAdrian Chadd /*
893eb6f0de0SAdrian Chadd * Do not exceed subframe limit.
894eb6f0de0SAdrian Chadd */
895eb6f0de0SAdrian Chadd if ((nframes + prev_frames) >= MIN((h_baw),
896eb6f0de0SAdrian Chadd IEEE80211_AMPDU_SUBFRAME_DEFAULT)) {
897eb6f0de0SAdrian Chadd status = ATH_AGGR_LIMITED;
898eb6f0de0SAdrian Chadd break;
899eb6f0de0SAdrian Chadd }
900eb6f0de0SAdrian Chadd
901eb6f0de0SAdrian Chadd /*
902045bc788SAdrian Chadd * If the current frame has an RTS/CTS configuration
903781e7eafSAdrian Chadd * that differs from the first frame, override the
904781e7eafSAdrian Chadd * subsequent frame with this config.
905045bc788SAdrian Chadd */
906d03904f1SAdrian Chadd if (bf != bf_first) {
907781e7eafSAdrian Chadd bf->bf_state.bfs_txflags &=
90876af1a93SAdrian Chadd ~ (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA);
909781e7eafSAdrian Chadd bf->bf_state.bfs_txflags |=
910781e7eafSAdrian Chadd bf_first->bf_state.bfs_txflags &
911781e7eafSAdrian Chadd (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA);
912d03904f1SAdrian Chadd }
913045bc788SAdrian Chadd
914045bc788SAdrian Chadd /*
9150b96ef63SAdrian Chadd * If the packet has a sequence number, do not
9160b96ef63SAdrian Chadd * step outside of the block-ack window.
9170b96ef63SAdrian Chadd */
9180b96ef63SAdrian Chadd if (! BAW_WITHIN(tap->txa_start, tap->txa_wnd,
9190b96ef63SAdrian Chadd SEQNO(bf->bf_state.bfs_seqno))) {
9200b96ef63SAdrian Chadd status = ATH_AGGR_BAW_CLOSED;
9210b96ef63SAdrian Chadd break;
9220b96ef63SAdrian Chadd }
9230b96ef63SAdrian Chadd
9240b96ef63SAdrian Chadd /*
925eb6f0de0SAdrian Chadd * this packet is part of an aggregate.
926eb6f0de0SAdrian Chadd */
9273e6cc97fSAdrian Chadd ATH_TID_REMOVE(tid, bf, bf_list);
928eb6f0de0SAdrian Chadd
929eb6f0de0SAdrian Chadd /* The TID lock is required for the BAW update */
930eb6f0de0SAdrian Chadd ath_tx_addto_baw(sc, an, tid, bf);
931eb6f0de0SAdrian Chadd bf->bf_state.bfs_addedbaw = 1;
932eb6f0de0SAdrian Chadd
933eb6f0de0SAdrian Chadd /*
934eb6f0de0SAdrian Chadd * XXX enforce ACK for aggregate frames (this needs to be
935eb6f0de0SAdrian Chadd * XXX handled more gracefully?
936eb6f0de0SAdrian Chadd */
937875a9451SAdrian Chadd if (bf->bf_state.bfs_txflags & HAL_TXDESC_NOACK) {
938eb6f0de0SAdrian Chadd device_printf(sc->sc_dev,
939eb6f0de0SAdrian Chadd "%s: HAL_TXDESC_NOACK set for an aggregate frame?\n",
940eb6f0de0SAdrian Chadd __func__);
941875a9451SAdrian Chadd bf->bf_state.bfs_txflags &= (~HAL_TXDESC_NOACK);
942eb6f0de0SAdrian Chadd }
943eb6f0de0SAdrian Chadd
944eb6f0de0SAdrian Chadd /*
945eb6f0de0SAdrian Chadd * Add the now owned buffer (which isn't
946eb6f0de0SAdrian Chadd * on the software TXQ any longer) to our
947eb6f0de0SAdrian Chadd * aggregate frame list.
948eb6f0de0SAdrian Chadd */
949eb6f0de0SAdrian Chadd TAILQ_INSERT_TAIL(bf_q, bf, bf_list);
950eb6f0de0SAdrian Chadd nframes ++;
951eb6f0de0SAdrian Chadd
952eb6f0de0SAdrian Chadd /* Completion handler */
953eb6f0de0SAdrian Chadd bf->bf_comp = ath_tx_aggr_comp;
954eb6f0de0SAdrian Chadd
955eb6f0de0SAdrian Chadd /*
956eb6f0de0SAdrian Chadd * add padding for previous frame to aggregation length
957eb6f0de0SAdrian Chadd */
958eb6f0de0SAdrian Chadd al += bpad + al_delta;
959eb6f0de0SAdrian Chadd
960eb6f0de0SAdrian Chadd /*
961eb6f0de0SAdrian Chadd * Calculate delimiters needed for the current frame
962eb6f0de0SAdrian Chadd */
963eb6f0de0SAdrian Chadd bf->bf_state.bfs_ndelim =
964eb6f0de0SAdrian Chadd ath_compute_num_delims(sc, bf_first,
965a2d74cc3SAdrian Chadd bf->bf_state.bfs_pktlen, (bf_first == bf));
966eb6f0de0SAdrian Chadd
967eb6f0de0SAdrian Chadd /*
968eb6f0de0SAdrian Chadd * Calculate the padding needed from this set of delimiters,
969eb6f0de0SAdrian Chadd * used when calculating if the next frame will fit in
970eb6f0de0SAdrian Chadd * the aggregate.
971eb6f0de0SAdrian Chadd */
972eb6f0de0SAdrian Chadd bpad = PADBYTES(al_delta) + (bf->bf_state.bfs_ndelim << 2);
973eb6f0de0SAdrian Chadd
974eb6f0de0SAdrian Chadd /*
975eb6f0de0SAdrian Chadd * Chain the buffers together
976eb6f0de0SAdrian Chadd */
977eb6f0de0SAdrian Chadd if (bf_prev)
978eb6f0de0SAdrian Chadd bf_prev->bf_next = bf;
979eb6f0de0SAdrian Chadd bf_prev = bf;
980eb6f0de0SAdrian Chadd
981eb6f0de0SAdrian Chadd /*
98222a3aee6SAdrian Chadd * If we're leaking frames, just return at this point;
98322a3aee6SAdrian Chadd * we've queued a single frame and we don't want to add
98422a3aee6SAdrian Chadd * any more.
985eb6f0de0SAdrian Chadd */
98622a3aee6SAdrian Chadd if (tid->an->an_leak_count) {
98722a3aee6SAdrian Chadd status = ATH_AGGR_LEAK_CLOSED;
98822a3aee6SAdrian Chadd break;
98922a3aee6SAdrian Chadd }
990eb6f0de0SAdrian Chadd
991eb6f0de0SAdrian Chadd #if 0
992eb6f0de0SAdrian Chadd /*
993eb6f0de0SAdrian Chadd * terminate aggregation on a small packet boundary
994eb6f0de0SAdrian Chadd */
995eb6f0de0SAdrian Chadd if (bf->bf_state.bfs_pktlen < ATH_AGGR_MINPLEN) {
996eb6f0de0SAdrian Chadd status = ATH_AGGR_SHORTPKT;
997eb6f0de0SAdrian Chadd break;
998eb6f0de0SAdrian Chadd }
999eb6f0de0SAdrian Chadd #endif
1000eb6f0de0SAdrian Chadd }
1001eb6f0de0SAdrian Chadd
1002eb6f0de0SAdrian Chadd finish:
1003eb6f0de0SAdrian Chadd /*
1004eb6f0de0SAdrian Chadd * Just in case the list was empty when we tried to
1005eb6f0de0SAdrian Chadd * dequeue a packet ..
1006eb6f0de0SAdrian Chadd */
1007eb6f0de0SAdrian Chadd if (bf_first) {
1008cce63444SAdrian Chadd DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
1009cce63444SAdrian Chadd "%s: al=%d bytes; requested %d bytes\n",
1010cce63444SAdrian Chadd __func__, al, bf_first->bf_state.bfs_rc_maxpktlen);
1011cce63444SAdrian Chadd
1012eb6f0de0SAdrian Chadd bf_first->bf_state.bfs_al = al;
1013eb6f0de0SAdrian Chadd bf_first->bf_state.bfs_nframes = nframes;
1014eb6f0de0SAdrian Chadd }
1015eb6f0de0SAdrian Chadd return status;
1016eb6f0de0SAdrian Chadd }
1017