xref: /freebsd/sys/dev/ath/if_ath_tx_ht.c (revision 045bc7882e5c2f6bfae19a9d693b1f93a5c0b48d)
14b44f6f2SAdrian Chadd /*-
24b44f6f2SAdrian Chadd  * Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd.
34b44f6f2SAdrian Chadd  * All rights reserved.
44b44f6f2SAdrian Chadd  *
54b44f6f2SAdrian Chadd  * Redistribution and use in source and binary forms, with or without
64b44f6f2SAdrian Chadd  * modification, are permitted provided that the following conditions
74b44f6f2SAdrian Chadd  * are met:
84b44f6f2SAdrian Chadd  * 1. Redistributions of source code must retain the above copyright
94b44f6f2SAdrian Chadd  *    notice, this list of conditions and the following disclaimer,
104b44f6f2SAdrian Chadd  *    without modification.
114b44f6f2SAdrian Chadd  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
124b44f6f2SAdrian Chadd  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
134b44f6f2SAdrian Chadd  *    redistribution must be conditioned upon including a substantially
144b44f6f2SAdrian Chadd  *    similar Disclaimer requirement for further binary redistribution.
154b44f6f2SAdrian Chadd  *
164b44f6f2SAdrian Chadd  * NO WARRANTY
174b44f6f2SAdrian Chadd  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
184b44f6f2SAdrian Chadd  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
194b44f6f2SAdrian Chadd  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
204b44f6f2SAdrian Chadd  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
214b44f6f2SAdrian Chadd  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
224b44f6f2SAdrian Chadd  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
234b44f6f2SAdrian Chadd  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
244b44f6f2SAdrian Chadd  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
254b44f6f2SAdrian Chadd  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
264b44f6f2SAdrian Chadd  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
274b44f6f2SAdrian Chadd  * THE POSSIBILITY OF SUCH DAMAGES.
284b44f6f2SAdrian Chadd  */
294b44f6f2SAdrian Chadd 
304b44f6f2SAdrian Chadd #include <sys/cdefs.h>
314b44f6f2SAdrian Chadd __FBSDID("$FreeBSD$");
324b44f6f2SAdrian Chadd 
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 */
101eb6f0de0SAdrian Chadd #define	ATH_AGGR_ENCRYPTDELIM	10	/* number of delimiters for encryption padding */
102eb6f0de0SAdrian Chadd 
103eb6f0de0SAdrian Chadd /*
104eb6f0de0SAdrian Chadd  * returns delimiter padding required given the packet length
105eb6f0de0SAdrian Chadd  */
106eb6f0de0SAdrian Chadd #define	ATH_AGGR_GET_NDELIM(_len)					\
107eb6f0de0SAdrian Chadd 	    (((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ?	\
108eb6f0de0SAdrian Chadd 	    (ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2)
109eb6f0de0SAdrian Chadd 
110eb6f0de0SAdrian Chadd #define	PADBYTES(_len)		((4 - ((_len) % 4)) % 4)
111eb6f0de0SAdrian Chadd 
112eb6f0de0SAdrian Chadd int ath_max_4ms_framelen[4][32] = {
113eb6f0de0SAdrian Chadd 	[MCS_HT20] = {
114eb6f0de0SAdrian Chadd 		3212,  6432,  9648,  12864,  19300,  25736,  28952,  32172,
115eb6f0de0SAdrian Chadd 		6424,  12852, 19280, 25708,  38568,  51424,  57852,  64280,
116eb6f0de0SAdrian Chadd 		9628,  19260, 28896, 38528,  57792,  65532,  65532,  65532,
117eb6f0de0SAdrian Chadd 		12828, 25656, 38488, 51320,  65532,  65532,  65532,  65532,
118eb6f0de0SAdrian Chadd 	},
119eb6f0de0SAdrian Chadd 	[MCS_HT20_SGI] = {
120eb6f0de0SAdrian Chadd 		3572,  7144,  10720,  14296,  21444,  28596,  32172,  35744,
121eb6f0de0SAdrian Chadd 		7140,  14284, 21428,  28568,  42856,  57144,  64288,  65532,
122eb6f0de0SAdrian Chadd 		10700, 21408, 32112,  42816,  64228,  65532,  65532,  65532,
123eb6f0de0SAdrian Chadd 		14256, 28516, 42780,  57040,  65532,  65532,  65532,  65532,
124eb6f0de0SAdrian Chadd 	},
125eb6f0de0SAdrian Chadd 	[MCS_HT40] = {
126eb6f0de0SAdrian Chadd 		6680,  13360,  20044,  26724,  40092,  53456,  60140,  65532,
127eb6f0de0SAdrian Chadd 		13348, 26700,  40052,  53400,  65532,  65532,  65532,  65532,
128eb6f0de0SAdrian Chadd 		20004, 40008,  60016,  65532,  65532,  65532,  65532,  65532,
129eb6f0de0SAdrian Chadd 		26644, 53292,  65532,  65532,  65532,  65532,  65532,  65532,
130eb6f0de0SAdrian Chadd 	},
131eb6f0de0SAdrian Chadd 	[MCS_HT40_SGI] = {
132eb6f0de0SAdrian Chadd 		7420,  14844,  22272,  29696,  44544,  59396,  65532,  65532,
133eb6f0de0SAdrian Chadd 		14832, 29668,  44504,  59340,  65532,  65532,  65532,  65532,
134eb6f0de0SAdrian Chadd 		22232, 44464,  65532,  65532,  65532,  65532,  65532,  65532,
135eb6f0de0SAdrian Chadd 		29616, 59232,  65532,  65532,  65532,  65532,  65532,  65532,
136eb6f0de0SAdrian Chadd 	}
137eb6f0de0SAdrian Chadd };
138eb6f0de0SAdrian Chadd 
139eb6f0de0SAdrian Chadd /*
140eb6f0de0SAdrian Chadd  * XXX should be in net80211
141eb6f0de0SAdrian Chadd  */
142eb6f0de0SAdrian Chadd static int ieee80211_mpdudensity_map[] = {
143eb6f0de0SAdrian Chadd 	0,		/* IEEE80211_HTCAP_MPDUDENSITY_NA */
144eb6f0de0SAdrian Chadd 	25,		/* IEEE80211_HTCAP_MPDUDENSITY_025 */
145eb6f0de0SAdrian Chadd 	50,		/* IEEE80211_HTCAP_MPDUDENSITY_05 */
146eb6f0de0SAdrian Chadd 	100,		/* IEEE80211_HTCAP_MPDUDENSITY_1 */
147eb6f0de0SAdrian Chadd 	200,		/* IEEE80211_HTCAP_MPDUDENSITY_2 */
148eb6f0de0SAdrian Chadd 	400,		/* IEEE80211_HTCAP_MPDUDENSITY_4 */
149eb6f0de0SAdrian Chadd 	800,		/* IEEE80211_HTCAP_MPDUDENSITY_8 */
150eb6f0de0SAdrian Chadd 	1600,		/* IEEE80211_HTCAP_MPDUDENSITY_16 */
151eb6f0de0SAdrian Chadd };
152eb6f0de0SAdrian Chadd 
153eb6f0de0SAdrian Chadd /*
154eb6f0de0SAdrian Chadd  * XXX should be in the HAL/net80211 ?
155eb6f0de0SAdrian Chadd  */
156eb6f0de0SAdrian Chadd #define	BITS_PER_BYTE		8
157eb6f0de0SAdrian Chadd #define	OFDM_PLCP_BITS		22
158eb6f0de0SAdrian Chadd #define	HT_RC_2_MCS(_rc)	((_rc) & 0x7f)
159eb6f0de0SAdrian Chadd #define	HT_RC_2_STREAMS(_rc)	((((_rc) & 0x78) >> 3) + 1)
160eb6f0de0SAdrian Chadd #define	L_STF			8
161eb6f0de0SAdrian Chadd #define	L_LTF			8
162eb6f0de0SAdrian Chadd #define	L_SIG			4
163eb6f0de0SAdrian Chadd #define	HT_SIG			8
164eb6f0de0SAdrian Chadd #define	HT_STF			4
165eb6f0de0SAdrian Chadd #define	HT_LTF(_ns)		(4 * (_ns))
166eb6f0de0SAdrian Chadd #define	SYMBOL_TIME(_ns)	((_ns) << 2)		// ns * 4 us
167eb6f0de0SAdrian Chadd #define	SYMBOL_TIME_HALFGI(_ns)	(((_ns) * 18 + 4) / 5)	// ns * 3.6 us
168eb6f0de0SAdrian Chadd #define	NUM_SYMBOLS_PER_USEC(_usec)	(_usec >> 2)
169eb6f0de0SAdrian Chadd #define	NUM_SYMBOLS_PER_USEC_HALFGI(_usec)	(((_usec*5)-4)/18)
170eb6f0de0SAdrian Chadd #define	IS_HT_RATE(_rate)	((_rate) & 0x80)
171eb6f0de0SAdrian Chadd 
172eb6f0de0SAdrian Chadd const uint32_t bits_per_symbol[][2] = {
173eb6f0de0SAdrian Chadd     /* 20MHz 40MHz */
174eb6f0de0SAdrian Chadd     {    26,   54 },     //  0: BPSK
175eb6f0de0SAdrian Chadd     {    52,  108 },     //  1: QPSK 1/2
176eb6f0de0SAdrian Chadd     {    78,  162 },     //  2: QPSK 3/4
177eb6f0de0SAdrian Chadd     {   104,  216 },     //  3: 16-QAM 1/2
178eb6f0de0SAdrian Chadd     {   156,  324 },     //  4: 16-QAM 3/4
179eb6f0de0SAdrian Chadd     {   208,  432 },     //  5: 64-QAM 2/3
180eb6f0de0SAdrian Chadd     {   234,  486 },     //  6: 64-QAM 3/4
181eb6f0de0SAdrian Chadd     {   260,  540 },     //  7: 64-QAM 5/6
182eb6f0de0SAdrian Chadd     {    52,  108 },     //  8: BPSK
183eb6f0de0SAdrian Chadd     {   104,  216 },     //  9: QPSK 1/2
184eb6f0de0SAdrian Chadd     {   156,  324 },     // 10: QPSK 3/4
185eb6f0de0SAdrian Chadd     {   208,  432 },     // 11: 16-QAM 1/2
186eb6f0de0SAdrian Chadd     {   312,  648 },     // 12: 16-QAM 3/4
187eb6f0de0SAdrian Chadd     {   416,  864 },     // 13: 64-QAM 2/3
188eb6f0de0SAdrian Chadd     {   468,  972 },     // 14: 64-QAM 3/4
189eb6f0de0SAdrian Chadd     {   520, 1080 },     // 15: 64-QAM 5/6
190eb6f0de0SAdrian Chadd     {    78,  162 },     // 16: BPSK
191eb6f0de0SAdrian Chadd     {   156,  324 },     // 17: QPSK 1/2
192eb6f0de0SAdrian Chadd     {   234,  486 },     // 18: QPSK 3/4
193eb6f0de0SAdrian Chadd     {   312,  648 },     // 19: 16-QAM 1/2
194eb6f0de0SAdrian Chadd     {   468,  972 },     // 20: 16-QAM 3/4
195eb6f0de0SAdrian Chadd     {   624, 1296 },     // 21: 64-QAM 2/3
196eb6f0de0SAdrian Chadd     {   702, 1458 },     // 22: 64-QAM 3/4
197eb6f0de0SAdrian Chadd     {   780, 1620 },     // 23: 64-QAM 5/6
198eb6f0de0SAdrian Chadd     {   104,  216 },     // 24: BPSK
199eb6f0de0SAdrian Chadd     {   208,  432 },     // 25: QPSK 1/2
200eb6f0de0SAdrian Chadd     {   312,  648 },     // 26: QPSK 3/4
201eb6f0de0SAdrian Chadd     {   416,  864 },     // 27: 16-QAM 1/2
202eb6f0de0SAdrian Chadd     {   624, 1296 },     // 28: 16-QAM 3/4
203eb6f0de0SAdrian Chadd     {   832, 1728 },     // 29: 64-QAM 2/3
204eb6f0de0SAdrian Chadd     {   936, 1944 },     // 30: 64-QAM 3/4
205eb6f0de0SAdrian Chadd     {  1040, 2160 },     // 31: 64-QAM 5/6
206eb6f0de0SAdrian Chadd };
207eb6f0de0SAdrian Chadd 
208eb6f0de0SAdrian Chadd /*
209eb6f0de0SAdrian Chadd  * Fill in the rate array information based on the current
210eb6f0de0SAdrian Chadd  * node configuration and the choices made by the rate
211eb6f0de0SAdrian Chadd  * selection code and ath_buf setup code.
212eb6f0de0SAdrian Chadd  *
213eb6f0de0SAdrian Chadd  * Later on, this may end up also being made by the
214eb6f0de0SAdrian Chadd  * rate control code, but for now it can live here.
215eb6f0de0SAdrian Chadd  *
216eb6f0de0SAdrian Chadd  * This needs to be called just before the packet is
217eb6f0de0SAdrian Chadd  * queued to the software queue or hardware queue,
218eb6f0de0SAdrian Chadd  * so all of the needed fields in bf_state are setup.
219eb6f0de0SAdrian Chadd  */
220eb6f0de0SAdrian Chadd void
221eb6f0de0SAdrian Chadd ath_tx_rate_fill_rcflags(struct ath_softc *sc, struct ath_buf *bf)
222eb6f0de0SAdrian Chadd {
223eb6f0de0SAdrian Chadd 	struct ieee80211_node *ni = bf->bf_node;
224eb6f0de0SAdrian Chadd 	struct ieee80211com *ic = ni->ni_ic;
225eb6f0de0SAdrian Chadd 	const HAL_RATE_TABLE *rt = sc->sc_currates;
226eb6f0de0SAdrian Chadd 	struct ath_rc_series *rc = bf->bf_state.bfs_rc;
227eb6f0de0SAdrian Chadd 	uint8_t rate;
228eb6f0de0SAdrian Chadd 	int i;
229eb6f0de0SAdrian Chadd 
230eb6f0de0SAdrian Chadd 	for (i = 0; i < ATH_RC_NUM; i++) {
231eb6f0de0SAdrian Chadd 		rc[i].flags = 0;
232eb6f0de0SAdrian Chadd 		if (rc[i].tries == 0)
233eb6f0de0SAdrian Chadd 			continue;
234eb6f0de0SAdrian Chadd 
235eb6f0de0SAdrian Chadd 		rate = rt->info[rc[i].rix].rateCode;
236eb6f0de0SAdrian Chadd 
237eb6f0de0SAdrian Chadd 		/*
238eb6f0de0SAdrian Chadd 		 * XXX only do this for legacy rates?
239eb6f0de0SAdrian Chadd 		 */
240eb6f0de0SAdrian Chadd 		if (bf->bf_state.bfs_shpream)
241eb6f0de0SAdrian Chadd 			rate |= rt->info[rc[i].rix].shortPreamble;
242eb6f0de0SAdrian Chadd 
243eb6f0de0SAdrian Chadd 		/*
244eb6f0de0SAdrian Chadd 		 * Save this, used by the TX and completion code
245eb6f0de0SAdrian Chadd 		 */
246eb6f0de0SAdrian Chadd 		rc[i].ratecode = rate;
247eb6f0de0SAdrian Chadd 
248875a9451SAdrian Chadd 		if (bf->bf_state.bfs_txflags &
249eb6f0de0SAdrian Chadd 		    (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA))
250eb6f0de0SAdrian Chadd 			rc[i].flags |= ATH_RC_RTSCTS_FLAG;
251eb6f0de0SAdrian Chadd 
252eb6f0de0SAdrian Chadd 		/* Only enable shortgi, 2040, dual-stream if HT is set */
253eb6f0de0SAdrian Chadd 		if (IS_HT_RATE(rate)) {
254eb6f0de0SAdrian Chadd 			rc[i].flags |= ATH_RC_HT_FLAG;
255eb6f0de0SAdrian Chadd 
256eb6f0de0SAdrian Chadd 			if (ni->ni_chw == 40)
257eb6f0de0SAdrian Chadd 				rc[i].flags |= ATH_RC_CW40_FLAG;
258eb6f0de0SAdrian Chadd 
259eb6f0de0SAdrian Chadd 			if (ni->ni_chw == 40 &&
260eb6f0de0SAdrian Chadd 			    ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40 &&
261eb6f0de0SAdrian Chadd 			    ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40)
262eb6f0de0SAdrian Chadd 				rc[i].flags |= ATH_RC_SGI_FLAG;
263eb6f0de0SAdrian Chadd 
264eb6f0de0SAdrian Chadd 			if (ni->ni_chw == 20 &&
265eb6f0de0SAdrian Chadd 			    ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20 &&
266eb6f0de0SAdrian Chadd 			    ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20)
267eb6f0de0SAdrian Chadd 				rc[i].flags |= ATH_RC_SGI_FLAG;
268eb6f0de0SAdrian Chadd 
269eb6f0de0SAdrian Chadd 			/* XXX dual stream? and 3-stream? */
270eb6f0de0SAdrian Chadd 		}
271eb6f0de0SAdrian Chadd 
272eb6f0de0SAdrian Chadd 		/*
273eb6f0de0SAdrian Chadd 		 * Calculate the maximum 4ms frame length based
274eb6f0de0SAdrian Chadd 		 * on the MCS rate, SGI and channel width flags.
275eb6f0de0SAdrian Chadd 		 */
276eb6f0de0SAdrian Chadd 		if ((rc[i].flags & ATH_RC_HT_FLAG) &&
277eb6f0de0SAdrian Chadd 		    (HT_RC_2_MCS(rate) < 32)) {
278eb6f0de0SAdrian Chadd 			int j;
279eb6f0de0SAdrian Chadd 			if (rc[i].flags & ATH_RC_CW40_FLAG) {
280eb6f0de0SAdrian Chadd 				if (rc[i].flags & ATH_RC_SGI_FLAG)
281eb6f0de0SAdrian Chadd 					j = MCS_HT40_SGI;
282eb6f0de0SAdrian Chadd 				else
283eb6f0de0SAdrian Chadd 					j = MCS_HT40;
284eb6f0de0SAdrian Chadd 			} else {
285eb6f0de0SAdrian Chadd 				if (rc[i].flags & ATH_RC_SGI_FLAG)
286eb6f0de0SAdrian Chadd 					j = MCS_HT20_SGI;
287eb6f0de0SAdrian Chadd 				else
288eb6f0de0SAdrian Chadd 					j = MCS_HT20;
289eb6f0de0SAdrian Chadd 			}
290eb6f0de0SAdrian Chadd 			rc[i].max4msframelen =
291eb6f0de0SAdrian Chadd 			    ath_max_4ms_framelen[j][HT_RC_2_MCS(rate)];
292eb6f0de0SAdrian Chadd 		} else
293eb6f0de0SAdrian Chadd 			rc[i].max4msframelen = 0;
294eb6f0de0SAdrian Chadd 		DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
295eb6f0de0SAdrian Chadd 		    "%s: i=%d, rate=0x%x, flags=0x%x, max4ms=%d\n",
296eb6f0de0SAdrian Chadd 		    __func__, i, rate, rc[i].flags, rc[i].max4msframelen);
297eb6f0de0SAdrian Chadd 	}
298eb6f0de0SAdrian Chadd }
299eb6f0de0SAdrian Chadd 
300eb6f0de0SAdrian Chadd /*
301eb6f0de0SAdrian Chadd  * Return the number of delimiters to be added to
302eb6f0de0SAdrian Chadd  * meet the minimum required mpdudensity.
303eb6f0de0SAdrian Chadd  *
304eb6f0de0SAdrian Chadd  * Caller should make sure that the rate is HT.
305eb6f0de0SAdrian Chadd  *
306eb6f0de0SAdrian Chadd  * TODO: is this delimiter calculation supposed to be the
307eb6f0de0SAdrian Chadd  * total frame length, the hdr length, the data length (including
308eb6f0de0SAdrian Chadd  * delimiters, padding, CRC, etc) or ?
309eb6f0de0SAdrian Chadd  *
310eb6f0de0SAdrian Chadd  * TODO: this should ensure that the rate control information
311eb6f0de0SAdrian Chadd  * HAS been setup for the first rate.
312eb6f0de0SAdrian Chadd  *
313eb6f0de0SAdrian Chadd  * TODO: ensure this is only called for MCS rates.
314eb6f0de0SAdrian Chadd  *
315eb6f0de0SAdrian Chadd  * TODO: enforce MCS < 31
316eb6f0de0SAdrian Chadd  */
317eb6f0de0SAdrian Chadd static int
318eb6f0de0SAdrian Chadd ath_compute_num_delims(struct ath_softc *sc, struct ath_buf *first_bf,
319eb6f0de0SAdrian Chadd     uint16_t pktlen)
320eb6f0de0SAdrian Chadd {
321eb6f0de0SAdrian Chadd 	const HAL_RATE_TABLE *rt = sc->sc_currates;
322eb6f0de0SAdrian Chadd 	struct ieee80211_node *ni = first_bf->bf_node;
323eb6f0de0SAdrian Chadd 	struct ieee80211vap *vap = ni->ni_vap;
324eb6f0de0SAdrian Chadd 	int ndelim, mindelim = 0;
325eb6f0de0SAdrian Chadd 	int mpdudensity;	 /* in 1/100'th of a microsecond */
326eb6f0de0SAdrian Chadd 	uint8_t rc, rix, flags;
327eb6f0de0SAdrian Chadd 	int width, half_gi;
328eb6f0de0SAdrian Chadd 	uint32_t nsymbits, nsymbols;
329eb6f0de0SAdrian Chadd 	uint16_t minlen;
330eb6f0de0SAdrian Chadd 
331eb6f0de0SAdrian Chadd 	/*
332eb6f0de0SAdrian Chadd 	 * vap->iv_ampdu_density is a value, rather than the actual
333eb6f0de0SAdrian Chadd 	 * density.
334eb6f0de0SAdrian Chadd 	 */
335eb6f0de0SAdrian Chadd 	if (vap->iv_ampdu_density > IEEE80211_HTCAP_MPDUDENSITY_16)
336eb6f0de0SAdrian Chadd 		mpdudensity = 1600;		/* maximum density */
337eb6f0de0SAdrian Chadd 	else
338eb6f0de0SAdrian Chadd 		mpdudensity = ieee80211_mpdudensity_map[vap->iv_ampdu_density];
339eb6f0de0SAdrian Chadd 
340eb6f0de0SAdrian Chadd 	/* Select standard number of delimiters based on frame length */
341eb6f0de0SAdrian Chadd 	ndelim = ATH_AGGR_GET_NDELIM(pktlen);
342eb6f0de0SAdrian Chadd 
343eb6f0de0SAdrian Chadd 	/*
344eb6f0de0SAdrian Chadd 	 * If encryption is enabled, add extra delimiters to let the
345eb6f0de0SAdrian Chadd 	 * crypto hardware catch up. This could be tuned per-MAC and
346eb6f0de0SAdrian Chadd 	 * per-rate, but for now we'll simply assume encryption is
347eb6f0de0SAdrian Chadd 	 * always enabled.
348eb6f0de0SAdrian Chadd 	 */
349eb6f0de0SAdrian Chadd 	ndelim += ATH_AGGR_ENCRYPTDELIM;
350eb6f0de0SAdrian Chadd 
351eb6f0de0SAdrian Chadd 	DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
352eb6f0de0SAdrian Chadd 	    "%s: pktlen=%d, ndelim=%d, mpdudensity=%d\n",
353eb6f0de0SAdrian Chadd 	    __func__, pktlen, ndelim, mpdudensity);
354eb6f0de0SAdrian Chadd 
355eb6f0de0SAdrian Chadd 	/*
356eb6f0de0SAdrian Chadd 	 * If the MPDU density is 0, we can return here.
357eb6f0de0SAdrian Chadd 	 * Otherwise, we need to convert the desired mpdudensity
358eb6f0de0SAdrian Chadd 	 * into a byte length, based on the rate in the subframe.
359eb6f0de0SAdrian Chadd 	 */
360eb6f0de0SAdrian Chadd 	if (mpdudensity == 0)
361eb6f0de0SAdrian Chadd 		return ndelim;
362eb6f0de0SAdrian Chadd 
363eb6f0de0SAdrian Chadd 	/*
364eb6f0de0SAdrian Chadd 	 * Convert desired mpdu density from microeconds to bytes based
365eb6f0de0SAdrian Chadd 	 * on highest rate in rate series (i.e. first rate) to determine
366eb6f0de0SAdrian Chadd 	 * required minimum length for subframe. Take into account
367eb6f0de0SAdrian Chadd 	 * whether high rate is 20 or 40Mhz and half or full GI.
368eb6f0de0SAdrian Chadd 	 */
369eb6f0de0SAdrian Chadd 	rix = first_bf->bf_state.bfs_rc[0].rix;
370eb6f0de0SAdrian Chadd 	rc = rt->info[rix].rateCode;
371eb6f0de0SAdrian Chadd 	flags = first_bf->bf_state.bfs_rc[0].flags;
372eb6f0de0SAdrian Chadd 	width = !! (flags & ATH_RC_CW40_FLAG);
373eb6f0de0SAdrian Chadd 	half_gi = !! (flags & ATH_RC_SGI_FLAG);
374eb6f0de0SAdrian Chadd 
375eb6f0de0SAdrian Chadd 	/*
376eb6f0de0SAdrian Chadd 	 * mpdudensity is in 1/100th of a usec, so divide by 100
377eb6f0de0SAdrian Chadd 	 */
378eb6f0de0SAdrian Chadd 	if (half_gi)
379eb6f0de0SAdrian Chadd 		nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(mpdudensity);
380eb6f0de0SAdrian Chadd 	else
381eb6f0de0SAdrian Chadd 		nsymbols = NUM_SYMBOLS_PER_USEC(mpdudensity);
382eb6f0de0SAdrian Chadd 	nsymbols /= 100;
383eb6f0de0SAdrian Chadd 
384eb6f0de0SAdrian Chadd 	if (nsymbols == 0)
385eb6f0de0SAdrian Chadd 		nsymbols = 1;
386eb6f0de0SAdrian Chadd 
387eb6f0de0SAdrian Chadd 	nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width];
388eb6f0de0SAdrian Chadd 	minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
389eb6f0de0SAdrian Chadd 
390eb6f0de0SAdrian Chadd 	/*
391eb6f0de0SAdrian Chadd 	 * Min length is the minimum frame length for the
392eb6f0de0SAdrian Chadd 	 * required MPDU density.
393eb6f0de0SAdrian Chadd 	 */
394eb6f0de0SAdrian Chadd 	if (pktlen < minlen) {
395eb6f0de0SAdrian Chadd 		mindelim = (minlen - pktlen) / ATH_AGGR_DELIM_SZ;
396eb6f0de0SAdrian Chadd 		ndelim = MAX(mindelim, ndelim);
397eb6f0de0SAdrian Chadd 	}
398eb6f0de0SAdrian Chadd 
399eb6f0de0SAdrian Chadd 	DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
400eb6f0de0SAdrian Chadd 	    "%s: pktlen=%d, minlen=%d, rix=%x, rc=%x, width=%d, hgi=%d, ndelim=%d\n",
401eb6f0de0SAdrian Chadd 	    __func__, pktlen, minlen, rix, rc, width, half_gi, ndelim);
402eb6f0de0SAdrian Chadd 
403eb6f0de0SAdrian Chadd 	return ndelim;
404eb6f0de0SAdrian Chadd }
405eb6f0de0SAdrian Chadd 
406eb6f0de0SAdrian Chadd /*
407eb6f0de0SAdrian Chadd  * Fetch the aggregation limit.
408eb6f0de0SAdrian Chadd  *
409eb6f0de0SAdrian Chadd  * It's the lowest of the four rate series 4ms frame length.
410eb6f0de0SAdrian Chadd  */
411eb6f0de0SAdrian Chadd static int
412eb6f0de0SAdrian Chadd ath_get_aggr_limit(struct ath_softc *sc, struct ath_buf *bf)
413eb6f0de0SAdrian Chadd {
414eb6f0de0SAdrian Chadd 	int amin = 65530;
415eb6f0de0SAdrian Chadd 	int i;
416eb6f0de0SAdrian Chadd 
417eb6f0de0SAdrian Chadd 	for (i = 0; i < 4; i++) {
418eb6f0de0SAdrian Chadd 		if (bf->bf_state.bfs_rc[i].tries == 0)
419eb6f0de0SAdrian Chadd 			continue;
420eb6f0de0SAdrian Chadd 		amin = MIN(amin, bf->bf_state.bfs_rc[i].max4msframelen);
421eb6f0de0SAdrian Chadd 	}
422eb6f0de0SAdrian Chadd 
423eb6f0de0SAdrian Chadd 	DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, "%s: max frame len= %d\n",
424eb6f0de0SAdrian Chadd 	    __func__, amin);
425eb6f0de0SAdrian Chadd 
426eb6f0de0SAdrian Chadd 	return amin;
427eb6f0de0SAdrian Chadd }
4284b44f6f2SAdrian Chadd 
4294b44f6f2SAdrian Chadd /*
4304b44f6f2SAdrian Chadd  * Setup a 11n rate series structure
4314b44f6f2SAdrian Chadd  *
4324b44f6f2SAdrian Chadd  * This should be called for both legacy and MCS rates.
433eb6f0de0SAdrian Chadd  *
434eb6f0de0SAdrian Chadd  * It, along with ath_buf_set_rate, must be called -after- a burst
435eb6f0de0SAdrian Chadd  * or aggregate is setup.
4364b44f6f2SAdrian Chadd  */
4374b44f6f2SAdrian Chadd static void
4384b44f6f2SAdrian Chadd ath_rateseries_setup(struct ath_softc *sc, struct ieee80211_node *ni,
439eb6f0de0SAdrian Chadd     struct ath_buf *bf, HAL_11N_RATE_SERIES *series)
4404b44f6f2SAdrian Chadd {
441fce6d676SAdrian Chadd #define	HT_RC_2_STREAMS(_rc)	((((_rc) & 0x78) >> 3) + 1)
4424b44f6f2SAdrian Chadd 	struct ieee80211com *ic = ni->ni_ic;
4434b44f6f2SAdrian Chadd 	struct ath_hal *ah = sc->sc_ah;
4444b44f6f2SAdrian Chadd 	HAL_BOOL shortPreamble = AH_FALSE;
4454b44f6f2SAdrian Chadd 	const HAL_RATE_TABLE *rt = sc->sc_currates;
4464b44f6f2SAdrian Chadd 	int i;
447eb6f0de0SAdrian Chadd 	int pktlen;
448875a9451SAdrian Chadd 	int flags = bf->bf_state.bfs_txflags;
449eb6f0de0SAdrian Chadd 	struct ath_rc_series *rc = bf->bf_state.bfs_rc;
4504b44f6f2SAdrian Chadd 
4514b44f6f2SAdrian Chadd 	if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
4524b44f6f2SAdrian Chadd 	    (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE))
4534b44f6f2SAdrian Chadd 		shortPreamble = AH_TRUE;
4544b44f6f2SAdrian Chadd 
455eb6f0de0SAdrian Chadd 	/*
456eb6f0de0SAdrian Chadd 	 * If this is the first frame in an aggregate series,
457eb6f0de0SAdrian Chadd 	 * use the aggregate length.
458eb6f0de0SAdrian Chadd 	 */
459eb6f0de0SAdrian Chadd 	if (bf->bf_state.bfs_aggr)
460eb6f0de0SAdrian Chadd 		pktlen = bf->bf_state.bfs_al;
461eb6f0de0SAdrian Chadd 	else
462eb6f0de0SAdrian Chadd 		pktlen = bf->bf_state.bfs_pktlen;
463eb6f0de0SAdrian Chadd 
464eb6f0de0SAdrian Chadd 	/*
465eb6f0de0SAdrian Chadd 	 * XXX TODO: modify this routine to use the bfs_rc[x].flags
466eb6f0de0SAdrian Chadd 	 * XXX fields.
467eb6f0de0SAdrian Chadd 	 */
4684b44f6f2SAdrian Chadd 	memset(series, 0, sizeof(HAL_11N_RATE_SERIES) * 4);
4694b44f6f2SAdrian Chadd 	for (i = 0; i < 4;  i++) {
470146b49d8SAdrian Chadd 		/* Only set flags for actual TX attempts */
471eb6f0de0SAdrian Chadd 		if (rc[i].tries == 0)
472146b49d8SAdrian Chadd 			continue;
473146b49d8SAdrian Chadd 
474eb6f0de0SAdrian Chadd 		series[i].Tries = rc[i].tries;
475146b49d8SAdrian Chadd 
476146b49d8SAdrian Chadd 		/*
477146b49d8SAdrian Chadd 		 * XXX this isn't strictly correct - sc_txchainmask
478146b49d8SAdrian Chadd 		 * XXX isn't the currently active chainmask;
479146b49d8SAdrian Chadd 		 * XXX it's the interface chainmask at startup.
480146b49d8SAdrian Chadd 		 * XXX It's overridden in the HAL rate scenario function
481146b49d8SAdrian Chadd 		 * XXX for now.
482146b49d8SAdrian Chadd 		 */
4834b44f6f2SAdrian Chadd 		series[i].ChSel = sc->sc_txchainmask;
484146b49d8SAdrian Chadd 
4852b5684a8SAdrian Chadd 		if (flags & (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA))
4864b44f6f2SAdrian Chadd 			series[i].RateFlags |= HAL_RATESERIES_RTS_CTS;
487146b49d8SAdrian Chadd 
488532f2442SAdrian Chadd 		/*
489532f2442SAdrian Chadd 		 * Transmit 40MHz frames only if the node has negotiated
490532f2442SAdrian Chadd 		 * it rather than whether the node is capable of it or not.
491532f2442SAdrian Chadd 	 	 * It's subtly different in the hostap case.
492532f2442SAdrian Chadd 	 	 */
493532f2442SAdrian Chadd 		if (ni->ni_chw == 40)
4944b44f6f2SAdrian Chadd 			series[i].RateFlags |= HAL_RATESERIES_2040;
4956246be6eSAdrian Chadd 
4967842451aSAdrian Chadd 		/*
4976246be6eSAdrian Chadd 		 * Set short-GI only if the node has advertised it
4986246be6eSAdrian Chadd 		 * the channel width is suitable, and we support it.
4996246be6eSAdrian Chadd 		 * We don't currently have a "negotiated" set of bits -
5006246be6eSAdrian Chadd 		 * ni_htcap is what the remote end sends, not what this
5016246be6eSAdrian Chadd 		 * node is capable of.
5027842451aSAdrian Chadd 		 */
5036246be6eSAdrian Chadd 		if (ni->ni_chw == 40 &&
5046246be6eSAdrian Chadd 		    ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40 &&
5056246be6eSAdrian Chadd 		    ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40)
5064b44f6f2SAdrian Chadd 			series[i].RateFlags |= HAL_RATESERIES_HALFGI;
5076246be6eSAdrian Chadd 
5086246be6eSAdrian Chadd 		if (ni->ni_chw == 20 &&
5096246be6eSAdrian Chadd 		    ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20 &&
5106246be6eSAdrian Chadd 		    ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20)
5116246be6eSAdrian Chadd 			series[i].RateFlags |= HAL_RATESERIES_HALFGI;
5124b44f6f2SAdrian Chadd 
513eb6f0de0SAdrian Chadd 		series[i].Rate = rt->info[rc[i].rix].rateCode;
5144b44f6f2SAdrian Chadd 
5154b44f6f2SAdrian Chadd 		/* PktDuration doesn't include slot, ACK, RTS, etc timing - it's just the packet duration */
5169a97e25eSAdrian Chadd 		if (series[i].Rate & IEEE80211_RATE_MCS) {
5174b44f6f2SAdrian Chadd 			series[i].PktDuration =
5184b44f6f2SAdrian Chadd 			    ath_computedur_ht(pktlen
5199a97e25eSAdrian Chadd 				, series[i].Rate
520fce6d676SAdrian Chadd 				, HT_RC_2_STREAMS(series[i].Rate)
521fce6d676SAdrian Chadd 				, series[i].RateFlags & HAL_RATESERIES_2040
522f449ab1cSAdrian Chadd 				, series[i].RateFlags & HAL_RATESERIES_HALFGI);
5234b44f6f2SAdrian Chadd 		} else {
5241198947aSAdrian Chadd 			if (shortPreamble)
525eb6f0de0SAdrian Chadd 				series[i].Rate |=
526eb6f0de0SAdrian Chadd 				    rt->info[rc[i].rix].shortPreamble;
5274b44f6f2SAdrian Chadd 			series[i].PktDuration = ath_hal_computetxtime(ah,
528eb6f0de0SAdrian Chadd 			    rt, pktlen, rc[i].rix, shortPreamble);
5294b44f6f2SAdrian Chadd 		}
5304b44f6f2SAdrian Chadd 	}
531fce6d676SAdrian Chadd #undef	HT_RC_2_STREAMS
5324b44f6f2SAdrian Chadd }
5334b44f6f2SAdrian Chadd 
5344b44f6f2SAdrian Chadd #if 0
5354b44f6f2SAdrian Chadd static void
5364b44f6f2SAdrian Chadd ath_rateseries_print(HAL_11N_RATE_SERIES *series)
5374b44f6f2SAdrian Chadd {
5384b44f6f2SAdrian Chadd 	int i;
5394b44f6f2SAdrian Chadd 	for (i = 0; i < 4; i++) {
5404b44f6f2SAdrian Chadd 		printf("series %d: rate %x; tries %d; pktDuration %d; chSel %d; rateFlags %x\n",
5414b44f6f2SAdrian Chadd 		    i,
5424b44f6f2SAdrian Chadd 		    series[i].Rate,
5434b44f6f2SAdrian Chadd 		    series[i].Tries,
5444b44f6f2SAdrian Chadd 		    series[i].PktDuration,
5454b44f6f2SAdrian Chadd 		    series[i].ChSel,
5464b44f6f2SAdrian Chadd 		    series[i].RateFlags);
5474b44f6f2SAdrian Chadd 	}
5484b44f6f2SAdrian Chadd }
5494b44f6f2SAdrian Chadd #endif
5504b44f6f2SAdrian Chadd 
5514b44f6f2SAdrian Chadd /*
5524b44f6f2SAdrian Chadd  * Setup the 11n rate scenario and burst duration for the given TX descriptor
5534b44f6f2SAdrian Chadd  * list.
5544b44f6f2SAdrian Chadd  *
5554b44f6f2SAdrian Chadd  * This isn't useful for sending beacon frames, which has different needs
5564b44f6f2SAdrian Chadd  * wrt what's passed into the rate scenario function.
5574b44f6f2SAdrian Chadd  */
5584b44f6f2SAdrian Chadd 
5594b44f6f2SAdrian Chadd void
560eb6f0de0SAdrian Chadd ath_buf_set_rate(struct ath_softc *sc, struct ieee80211_node *ni,
561eb6f0de0SAdrian Chadd     struct ath_buf *bf)
5624b44f6f2SAdrian Chadd {
5634b44f6f2SAdrian Chadd 	HAL_11N_RATE_SERIES series[4];
5644b44f6f2SAdrian Chadd 	struct ath_desc *ds = bf->bf_desc;
5654b44f6f2SAdrian Chadd 	struct ath_desc *lastds = NULL;
5664b44f6f2SAdrian Chadd 	struct ath_hal *ah = sc->sc_ah;
567eb6f0de0SAdrian Chadd 	int is_pspoll = (bf->bf_state.bfs_atype == HAL_PKT_TYPE_PSPOLL);
568eb6f0de0SAdrian Chadd 	int ctsrate = bf->bf_state.bfs_ctsrate;
569875a9451SAdrian Chadd 	int flags = bf->bf_state.bfs_txflags;
5704b44f6f2SAdrian Chadd 
5714b44f6f2SAdrian Chadd 	/* Setup rate scenario */
5724b44f6f2SAdrian Chadd 	memset(&series, 0, sizeof(series));
5734b44f6f2SAdrian Chadd 
574eb6f0de0SAdrian Chadd 	ath_rateseries_setup(sc, ni, bf, series);
5754b44f6f2SAdrian Chadd 
5764b44f6f2SAdrian Chadd 	/* Enforce AR5416 aggregate limit - can't do RTS w/ an agg frame > 8k */
5774b44f6f2SAdrian Chadd 
5784b44f6f2SAdrian Chadd 	/* Enforce RTS and CTS are mutually exclusive */
5794b44f6f2SAdrian Chadd 
5804b44f6f2SAdrian Chadd 	/* Get a pointer to the last tx descriptor in the list */
581eb6f0de0SAdrian Chadd 	lastds = bf->bf_lastds;
5824b44f6f2SAdrian Chadd 
5832b5684a8SAdrian Chadd #if 0
5842b5684a8SAdrian Chadd 	printf("pktlen: %d; flags 0x%x\n", pktlen, flags);
5852b5684a8SAdrian Chadd 	ath_rateseries_print(series);
5862b5684a8SAdrian Chadd #endif
5872b5684a8SAdrian Chadd 
5884b44f6f2SAdrian Chadd 	/* Set rate scenario */
5894b44f6f2SAdrian Chadd 	ath_hal_set11nratescenario(ah, ds,
590bf26df36SAdrian Chadd 	    !is_pspoll,	/* whether to override the duration or not */
591bf26df36SAdrian Chadd 			/* don't allow hardware to override the duration on ps-poll packets */
5924b44f6f2SAdrian Chadd 	    ctsrate,	/* rts/cts rate */
5934b44f6f2SAdrian Chadd 	    series,	/* 11n rate series */
5944b44f6f2SAdrian Chadd 	    4,		/* number of series */
5954b44f6f2SAdrian Chadd 	    flags);
5964b44f6f2SAdrian Chadd 
5974b44f6f2SAdrian Chadd 	/* Setup the last descriptor in the chain */
5984b44f6f2SAdrian Chadd 	ath_hal_setuplasttxdesc(ah, lastds, ds);
5994b44f6f2SAdrian Chadd 
6004b44f6f2SAdrian Chadd 	/* Set burst duration */
601eb6f0de0SAdrian Chadd 	/*
602eb6f0de0SAdrian Chadd 	 * This is only required when doing 11n burst, not aggregation
603eb6f0de0SAdrian Chadd 	 * ie, if there's a second frame in a RIFS or A-MPDU burst
604eb6f0de0SAdrian Chadd 	 * w/ >1 A-MPDU frame bursting back to back.
605eb6f0de0SAdrian Chadd 	 * Normal A-MPDU doesn't do bursting -between- aggregates.
606eb6f0de0SAdrian Chadd 	 *
607eb6f0de0SAdrian Chadd 	 * .. and it's highly likely this won't ever be implemented
608eb6f0de0SAdrian Chadd 	 */
6094b44f6f2SAdrian Chadd 	//ath_hal_set11nburstduration(ah, ds, 8192);
6104b44f6f2SAdrian Chadd }
611eb6f0de0SAdrian Chadd 
612eb6f0de0SAdrian Chadd /*
613eb6f0de0SAdrian Chadd  * Form an aggregate packet list.
614eb6f0de0SAdrian Chadd  *
615eb6f0de0SAdrian Chadd  * This function enforces the aggregate restrictions/requirements.
616eb6f0de0SAdrian Chadd  *
617eb6f0de0SAdrian Chadd  * These are:
618eb6f0de0SAdrian Chadd  *
619eb6f0de0SAdrian Chadd  * + The aggregate size maximum (64k for AR9160 and later, 8K for
620eb6f0de0SAdrian Chadd  *   AR5416 when doing RTS frame protection.)
621eb6f0de0SAdrian Chadd  * + Maximum number of sub-frames for an aggregate
622eb6f0de0SAdrian Chadd  * + The aggregate delimiter size, giving MACs time to do whatever is
623eb6f0de0SAdrian Chadd  *   needed before each frame
624eb6f0de0SAdrian Chadd  * + Enforce the BAW limit
625eb6f0de0SAdrian Chadd  *
626eb6f0de0SAdrian Chadd  * Each descriptor queued should have the DMA setup.
627eb6f0de0SAdrian Chadd  * The rate series, descriptor setup, linking, etc is all done
628eb6f0de0SAdrian Chadd  * externally. This routine simply chains them together.
629eb6f0de0SAdrian Chadd  * ath_tx_setds_11n() will take care of configuring the per-
630eb6f0de0SAdrian Chadd  * descriptor setup, and ath_buf_set_rate() will configure the
631eb6f0de0SAdrian Chadd  * rate control.
632eb6f0de0SAdrian Chadd  *
633eb6f0de0SAdrian Chadd  * Note that the TID lock is only grabbed when dequeuing packets from
634eb6f0de0SAdrian Chadd  * the TID queue. If some code in another thread adds to the head of this
635eb6f0de0SAdrian Chadd  * list, very strange behaviour will occur. Since retransmission is the
636eb6f0de0SAdrian Chadd  * only reason this will occur, and this routine is designed to be called
637eb6f0de0SAdrian Chadd  * from within the scheduler task, it won't ever clash with the completion
638eb6f0de0SAdrian Chadd  * task.
639eb6f0de0SAdrian Chadd  *
640eb6f0de0SAdrian Chadd  * So if you want to call this from an upper layer context (eg, to direct-
641eb6f0de0SAdrian Chadd  * dispatch aggregate frames to the hardware), please keep this in mind.
642eb6f0de0SAdrian Chadd  */
643eb6f0de0SAdrian Chadd ATH_AGGR_STATUS
644eb6f0de0SAdrian Chadd ath_tx_form_aggr(struct ath_softc *sc, struct ath_node *an, struct ath_tid *tid,
645eb6f0de0SAdrian Chadd     ath_bufhead *bf_q)
646eb6f0de0SAdrian Chadd {
6470b96ef63SAdrian Chadd 	struct ieee80211_node *ni = &an->an_node;
648eb6f0de0SAdrian Chadd 	struct ath_buf *bf, *bf_first = NULL, *bf_prev = NULL;
649eb6f0de0SAdrian Chadd 	int nframes = 0;
650eb6f0de0SAdrian Chadd 	uint16_t aggr_limit = 0, al = 0, bpad = 0, al_delta, h_baw;
651eb6f0de0SAdrian Chadd 	struct ieee80211_tx_ampdu *tap;
652eb6f0de0SAdrian Chadd 	int status = ATH_AGGR_DONE;
653eb6f0de0SAdrian Chadd 	int prev_frames = 0;	/* XXX for AR5416 burst, not done here */
654eb6f0de0SAdrian Chadd 	int prev_al = 0;	/* XXX also for AR5416 burst */
655eb6f0de0SAdrian Chadd 
656eb6f0de0SAdrian Chadd 	ATH_TXQ_LOCK_ASSERT(sc->sc_ac2q[tid->ac]);
657eb6f0de0SAdrian Chadd 
658eb6f0de0SAdrian Chadd 	tap = ath_tx_get_tx_tid(an, tid->tid);
659eb6f0de0SAdrian Chadd 	if (tap == NULL) {
660eb6f0de0SAdrian Chadd 		status = ATH_AGGR_ERROR;
661eb6f0de0SAdrian Chadd 		goto finish;
662eb6f0de0SAdrian Chadd 	}
663eb6f0de0SAdrian Chadd 
664eb6f0de0SAdrian Chadd 	h_baw = tap->txa_wnd / 2;
665eb6f0de0SAdrian Chadd 
666eb6f0de0SAdrian Chadd 	for (;;) {
667eb6f0de0SAdrian Chadd 		bf = TAILQ_FIRST(&tid->axq_q);
668eb6f0de0SAdrian Chadd 		if (bf_first == NULL)
669eb6f0de0SAdrian Chadd 			bf_first = bf;
670eb6f0de0SAdrian Chadd 		if (bf == NULL) {
671eb6f0de0SAdrian Chadd 			status = ATH_AGGR_DONE;
672eb6f0de0SAdrian Chadd 			break;
673eb6f0de0SAdrian Chadd 		} else {
674eb6f0de0SAdrian Chadd 			/*
675eb6f0de0SAdrian Chadd 			 * It's the first frame;
676eb6f0de0SAdrian Chadd 			 * set the aggregation limit based on the
677eb6f0de0SAdrian Chadd 			 * rate control decision that has been made.
678eb6f0de0SAdrian Chadd 			 */
679eb6f0de0SAdrian Chadd 			aggr_limit = ath_get_aggr_limit(sc, bf_first);
680eb6f0de0SAdrian Chadd 		}
681eb6f0de0SAdrian Chadd 
682eb6f0de0SAdrian Chadd 		/* Set this early just so things don't get confused */
683eb6f0de0SAdrian Chadd 		bf->bf_next = NULL;
684eb6f0de0SAdrian Chadd 
685eb6f0de0SAdrian Chadd 		/*
686eb6f0de0SAdrian Chadd 		 * Don't unlock the tid lock until we're sure we are going
687eb6f0de0SAdrian Chadd 		 * to queue this frame.
688eb6f0de0SAdrian Chadd 		 */
689eb6f0de0SAdrian Chadd 
690eb6f0de0SAdrian Chadd 		/*
691eb6f0de0SAdrian Chadd 		 * If the frame doesn't have a sequence number that we're
692eb6f0de0SAdrian Chadd 		 * tracking in the BAW (eg NULL QOS data frame), we can't
693eb6f0de0SAdrian Chadd 		 * aggregate it. Stop the aggregation process; the sender
694eb6f0de0SAdrian Chadd 		 * can then TX what's in the list thus far and then
695eb6f0de0SAdrian Chadd 		 * TX the frame individually.
696eb6f0de0SAdrian Chadd 		 */
697eb6f0de0SAdrian Chadd 		if (! bf->bf_state.bfs_dobaw) {
698eb6f0de0SAdrian Chadd 			status = ATH_AGGR_NONAGGR;
699eb6f0de0SAdrian Chadd 			break;
700eb6f0de0SAdrian Chadd 		}
701eb6f0de0SAdrian Chadd 
702eb6f0de0SAdrian Chadd 		/*
703eb6f0de0SAdrian Chadd 		 * If any of the rates are non-HT, this packet
704eb6f0de0SAdrian Chadd 		 * can't be aggregated.
705eb6f0de0SAdrian Chadd 		 * XXX TODO: add a bf_state flag which gets marked
706eb6f0de0SAdrian Chadd 		 * if any active rate is non-HT.
707eb6f0de0SAdrian Chadd 		 */
708eb6f0de0SAdrian Chadd 
709eb6f0de0SAdrian Chadd 		/*
710eb6f0de0SAdrian Chadd 		 * do not exceed aggregation limit
711eb6f0de0SAdrian Chadd 		 */
712eb6f0de0SAdrian Chadd 		al_delta = ATH_AGGR_DELIM_SZ + bf->bf_state.bfs_pktlen;
713eb6f0de0SAdrian Chadd 		if (nframes &&
714eb6f0de0SAdrian Chadd 		    (aggr_limit < (al + bpad + al_delta + prev_al))) {
715eb6f0de0SAdrian Chadd 			status = ATH_AGGR_LIMITED;
716eb6f0de0SAdrian Chadd 			break;
717eb6f0de0SAdrian Chadd 		}
718eb6f0de0SAdrian Chadd 
719eb6f0de0SAdrian Chadd 		/*
720*045bc788SAdrian Chadd 		 * If RTS/CTS is set on the first frame, enforce
721*045bc788SAdrian Chadd 		 * the RTS aggregate limit.
722*045bc788SAdrian Chadd 		 */
723*045bc788SAdrian Chadd 		if (bf_first->bf_state.bfs_txflags &
724*045bc788SAdrian Chadd 		    (HAL_TXDESC_CTSENA | HAL_TXDESC_RTSENA)) {
725*045bc788SAdrian Chadd 			if (nframes &&
726*045bc788SAdrian Chadd 			   (sc->sc_rts_aggr_limit <
727*045bc788SAdrian Chadd 			     (al + bpad + al_delta + prev_al))) {
728*045bc788SAdrian Chadd 				status = ATH_AGGR_8K_LIMITED;
729*045bc788SAdrian Chadd 				break;
730*045bc788SAdrian Chadd 			}
731*045bc788SAdrian Chadd 		}
732*045bc788SAdrian Chadd 
733*045bc788SAdrian Chadd 		/*
734eb6f0de0SAdrian Chadd 		 * Do not exceed subframe limit.
735eb6f0de0SAdrian Chadd 		 */
736eb6f0de0SAdrian Chadd 		if ((nframes + prev_frames) >= MIN((h_baw),
737eb6f0de0SAdrian Chadd 		    IEEE80211_AMPDU_SUBFRAME_DEFAULT)) {
738eb6f0de0SAdrian Chadd 			status = ATH_AGGR_LIMITED;
739eb6f0de0SAdrian Chadd 			break;
740eb6f0de0SAdrian Chadd 		}
741eb6f0de0SAdrian Chadd 
742eb6f0de0SAdrian Chadd 		/*
743*045bc788SAdrian Chadd 		 * If the current frame has an RTS/CTS configuration
744*045bc788SAdrian Chadd 		 * that differs from the first frame, don't include
745*045bc788SAdrian Chadd 		 * this in the aggregate.  It's possible that the
746*045bc788SAdrian Chadd 		 * "right" thing to do here is enforce the aggregate
747*045bc788SAdrian Chadd 		 * configuration.
748*045bc788SAdrian Chadd 		 */
749*045bc788SAdrian Chadd 		if ((bf_first->bf_state.bfs_txflags &
750*045bc788SAdrian Chadd 		    (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA)) !=
751*045bc788SAdrian Chadd 		   (bf->bf_state.bfs_txflags &
752*045bc788SAdrian Chadd 		    (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA))) {
753*045bc788SAdrian Chadd 			status = ATH_AGGR_NONAGGR;
754*045bc788SAdrian Chadd 			break;
755*045bc788SAdrian Chadd 		}
756*045bc788SAdrian Chadd 
757*045bc788SAdrian Chadd 		/*
758*045bc788SAdrian Chadd 		 * TODO: If it's _before_ the BAW left edge, complain very
759*045bc788SAdrian Chadd 		 * loudly.
760*045bc788SAdrian Chadd 		 *
7610b96ef63SAdrian Chadd 		 * This means something (else) has slid the left edge along
7620b96ef63SAdrian Chadd 		 * before we got a chance to be TXed.
7630b96ef63SAdrian Chadd 		 */
7640b96ef63SAdrian Chadd 
7650b96ef63SAdrian Chadd 		/*
7660b96ef63SAdrian Chadd 		 * Check if we have space in the BAW for this frame before
7670b96ef63SAdrian Chadd 		 * we add it.
7680b96ef63SAdrian Chadd 		 *
7690b96ef63SAdrian Chadd 		 * see ath_tx_xmit_aggr() for more info.
7700b96ef63SAdrian Chadd 		 */
7710b96ef63SAdrian Chadd 		if (bf->bf_state.bfs_dobaw) {
772091e146cSAdrian Chadd 			ieee80211_seq seqno;
773091e146cSAdrian Chadd 
774091e146cSAdrian Chadd 			/*
775091e146cSAdrian Chadd 			 * If the sequence number is allocated, use it.
776091e146cSAdrian Chadd 			 * Otherwise, use the sequence number we WOULD
777091e146cSAdrian Chadd 			 * allocate.
778091e146cSAdrian Chadd 			 */
779091e146cSAdrian Chadd 			if (bf->bf_state.bfs_seqno_assigned)
780091e146cSAdrian Chadd 				seqno = SEQNO(bf->bf_state.bfs_seqno);
781091e146cSAdrian Chadd 			else
782091e146cSAdrian Chadd 				seqno = ni->ni_txseqs[bf->bf_state.bfs_tid];
783091e146cSAdrian Chadd 
784091e146cSAdrian Chadd 			/*
785091e146cSAdrian Chadd 			 * Check whether either the currently allocated
786091e146cSAdrian Chadd 			 * sequence number _OR_ the to-be allocated
787091e146cSAdrian Chadd 			 * sequence number is inside the BAW.
788091e146cSAdrian Chadd 			 */
7890b96ef63SAdrian Chadd 			if (! BAW_WITHIN(tap->txa_start, tap->txa_wnd,
790091e146cSAdrian Chadd 			    seqno)) {
7910b96ef63SAdrian Chadd 				status = ATH_AGGR_BAW_CLOSED;
7920b96ef63SAdrian Chadd 				break;
7930b96ef63SAdrian Chadd 			}
794091e146cSAdrian Chadd 
7950b96ef63SAdrian Chadd 			/* XXX check for bfs_need_seqno? */
7960b96ef63SAdrian Chadd 			if (! bf->bf_state.bfs_seqno_assigned) {
797091e146cSAdrian Chadd 				int seqno;
7980b96ef63SAdrian Chadd 				seqno = ath_tx_tid_seqno_assign(sc, ni, bf, bf->bf_m);
7990b96ef63SAdrian Chadd 				if (seqno < 0) {
8000b96ef63SAdrian Chadd 					device_printf(sc->sc_dev,
8010b96ef63SAdrian Chadd 					    "%s: bf=%p, huh, seqno=-1?\n",
8020b96ef63SAdrian Chadd 					    __func__,
8030b96ef63SAdrian Chadd 					    bf);
8040b96ef63SAdrian Chadd 					/* XXX what can we even do here? */
8050b96ef63SAdrian Chadd 				}
8060b96ef63SAdrian Chadd 				/* Flush seqno update to RAM */
8070b96ef63SAdrian Chadd 				/*
8080b96ef63SAdrian Chadd 				 * XXX This is required because the dmasetup
8090b96ef63SAdrian Chadd 				 * XXX is done early rather than at dispatch
8100b96ef63SAdrian Chadd 				 * XXX time. Ew, we should fix this!
8110b96ef63SAdrian Chadd 				 */
8120b96ef63SAdrian Chadd 				bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
8130b96ef63SAdrian Chadd 				    BUS_DMASYNC_PREWRITE);
8140b96ef63SAdrian Chadd 			}
8150b96ef63SAdrian Chadd 		}
8160b96ef63SAdrian Chadd 
8170b96ef63SAdrian Chadd 		/*
8180b96ef63SAdrian Chadd 		 * If the packet has a sequence number, do not
8190b96ef63SAdrian Chadd 		 * step outside of the block-ack window.
8200b96ef63SAdrian Chadd 		 */
8210b96ef63SAdrian Chadd 		if (! BAW_WITHIN(tap->txa_start, tap->txa_wnd,
8220b96ef63SAdrian Chadd 		    SEQNO(bf->bf_state.bfs_seqno))) {
8230b96ef63SAdrian Chadd 			device_printf(sc->sc_dev,
8240b96ef63SAdrian Chadd 			    "%s: bf=%p, seqno=%d, outside?!\n",
8250b96ef63SAdrian Chadd 			    __func__, bf, SEQNO(bf->bf_state.bfs_seqno));
8260b96ef63SAdrian Chadd 			status = ATH_AGGR_BAW_CLOSED;
8270b96ef63SAdrian Chadd 			break;
8280b96ef63SAdrian Chadd 		}
8290b96ef63SAdrian Chadd 
8300b96ef63SAdrian Chadd 		/*
831eb6f0de0SAdrian Chadd 		 * this packet is part of an aggregate.
832eb6f0de0SAdrian Chadd 		 */
833eb6f0de0SAdrian Chadd 		ATH_TXQ_REMOVE(tid, bf, bf_list);
834eb6f0de0SAdrian Chadd 
835eb6f0de0SAdrian Chadd 		/* The TID lock is required for the BAW update */
836eb6f0de0SAdrian Chadd 		ath_tx_addto_baw(sc, an, tid, bf);
837eb6f0de0SAdrian Chadd 		bf->bf_state.bfs_addedbaw = 1;
838eb6f0de0SAdrian Chadd 
839eb6f0de0SAdrian Chadd 		/*
840eb6f0de0SAdrian Chadd 		 * XXX enforce ACK for aggregate frames (this needs to be
841eb6f0de0SAdrian Chadd 		 * XXX handled more gracefully?
842eb6f0de0SAdrian Chadd 		 */
843875a9451SAdrian Chadd 		if (bf->bf_state.bfs_txflags & HAL_TXDESC_NOACK) {
844eb6f0de0SAdrian Chadd 			device_printf(sc->sc_dev,
845eb6f0de0SAdrian Chadd 			    "%s: HAL_TXDESC_NOACK set for an aggregate frame?\n",
846eb6f0de0SAdrian Chadd 			    __func__);
847875a9451SAdrian Chadd 			bf->bf_state.bfs_txflags &= (~HAL_TXDESC_NOACK);
848eb6f0de0SAdrian Chadd 		}
849eb6f0de0SAdrian Chadd 
850eb6f0de0SAdrian Chadd 		/*
851eb6f0de0SAdrian Chadd 		 * Add the now owned buffer (which isn't
852eb6f0de0SAdrian Chadd 		 * on the software TXQ any longer) to our
853eb6f0de0SAdrian Chadd 		 * aggregate frame list.
854eb6f0de0SAdrian Chadd 		 */
855eb6f0de0SAdrian Chadd 		TAILQ_INSERT_TAIL(bf_q, bf, bf_list);
856eb6f0de0SAdrian Chadd 		nframes ++;
857eb6f0de0SAdrian Chadd 
858eb6f0de0SAdrian Chadd 		/* Completion handler */
859eb6f0de0SAdrian Chadd 		bf->bf_comp = ath_tx_aggr_comp;
860eb6f0de0SAdrian Chadd 
861eb6f0de0SAdrian Chadd 		/*
862eb6f0de0SAdrian Chadd 		 * add padding for previous frame to aggregation length
863eb6f0de0SAdrian Chadd 		 */
864eb6f0de0SAdrian Chadd 		al += bpad + al_delta;
865eb6f0de0SAdrian Chadd 
866eb6f0de0SAdrian Chadd 		/*
867eb6f0de0SAdrian Chadd 		 * Calculate delimiters needed for the current frame
868eb6f0de0SAdrian Chadd 		 */
869eb6f0de0SAdrian Chadd 		bf->bf_state.bfs_ndelim =
870eb6f0de0SAdrian Chadd 		    ath_compute_num_delims(sc, bf_first,
871eb6f0de0SAdrian Chadd 		    bf->bf_state.bfs_pktlen);
872eb6f0de0SAdrian Chadd 
873eb6f0de0SAdrian Chadd 		/*
874eb6f0de0SAdrian Chadd 		 * Calculate the padding needed from this set of delimiters,
875eb6f0de0SAdrian Chadd 		 * used when calculating if the next frame will fit in
876eb6f0de0SAdrian Chadd 		 * the aggregate.
877eb6f0de0SAdrian Chadd 		 */
878eb6f0de0SAdrian Chadd 		bpad = PADBYTES(al_delta) + (bf->bf_state.bfs_ndelim << 2);
879eb6f0de0SAdrian Chadd 
880eb6f0de0SAdrian Chadd 		/*
881eb6f0de0SAdrian Chadd 		 * Chain the buffers together
882eb6f0de0SAdrian Chadd 		 */
883eb6f0de0SAdrian Chadd 		if (bf_prev)
884eb6f0de0SAdrian Chadd 			bf_prev->bf_next = bf;
885eb6f0de0SAdrian Chadd 		bf_prev = bf;
886eb6f0de0SAdrian Chadd 
887eb6f0de0SAdrian Chadd 		/*
888eb6f0de0SAdrian Chadd 		 * XXX TODO: if any sub-frames have RTS/CTS enabled;
889eb6f0de0SAdrian Chadd 		 * enable it for the entire aggregate.
890eb6f0de0SAdrian Chadd 		 */
891eb6f0de0SAdrian Chadd 
892eb6f0de0SAdrian Chadd #if 0
893eb6f0de0SAdrian Chadd 		/*
894eb6f0de0SAdrian Chadd 		 * terminate aggregation on a small packet boundary
895eb6f0de0SAdrian Chadd 		 */
896eb6f0de0SAdrian Chadd 		if (bf->bf_state.bfs_pktlen < ATH_AGGR_MINPLEN) {
897eb6f0de0SAdrian Chadd 			status = ATH_AGGR_SHORTPKT;
898eb6f0de0SAdrian Chadd 			break;
899eb6f0de0SAdrian Chadd 		}
900eb6f0de0SAdrian Chadd #endif
901eb6f0de0SAdrian Chadd 
902eb6f0de0SAdrian Chadd 	}
903eb6f0de0SAdrian Chadd 
904eb6f0de0SAdrian Chadd finish:
905eb6f0de0SAdrian Chadd 	/*
906eb6f0de0SAdrian Chadd 	 * Just in case the list was empty when we tried to
907eb6f0de0SAdrian Chadd 	 * dequeue a packet ..
908eb6f0de0SAdrian Chadd 	 */
909eb6f0de0SAdrian Chadd 	if (bf_first) {
910eb6f0de0SAdrian Chadd 		bf_first->bf_state.bfs_al = al;
911eb6f0de0SAdrian Chadd 		bf_first->bf_state.bfs_nframes = nframes;
912eb6f0de0SAdrian Chadd 	}
913eb6f0de0SAdrian Chadd 	return status;
914eb6f0de0SAdrian Chadd }
915