1 /*
2 * Copyright (c) 2013 Qualcomm Atheros, Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include "opt_ah.h"
18
19 #include "ah.h"
20 #include "ah_internal.h"
21
22 #include "ar9300/ar9300.h"
23
24 /* shorthands to compact tables for readability */
25 #define OFDM IEEE80211_T_OFDM
26 #define CCK IEEE80211_T_CCK
27 #define TURBO IEEE80211_T_TURBO
28 #define XR ATHEROS_T_XR
29 #define HT IEEE80211_T_HT
30
31 #define AR9300_NUM_OFDM_RATES 8
32 #define AR9300_NUM_HT_SS_RATES 8
33 #define AR9300_NUM_HT_DS_RATES 8
34 #define AR9300_NUM_HT_TS_RATES 8
35
36 /* Array Gain defined for TxBF */
37 #define AR9300_TXBF_2TX_ARRAY_GAIN 6 /* 2TX/SS 3 */
38 #define AR9300_TXBF_3TX_ARRAY_GAIN 10 /* 3TX/SS or 3TX/DS 4.8 */
39 #define AR9300_STBC_3TX_ARRAY_GAIN 10 /* 3TX/SS or 3TX/DS 4.8 */
40
41 /* MCS RATE CODES - first and last */
42 #define AR9300_MCS0_RATE_CODE 0x80
43 #define AR9300_MCS23_RATE_CODE 0x97
44
45 static inline void ar9300_init_rate_txpower_cck(struct ath_hal *ah,
46 const HAL_RATE_TABLE *rt, u_int8_t rates_array[], u_int8_t chainmask);
47 static inline void ar9300_init_rate_txpower_ofdm(struct ath_hal* ah,
48 const HAL_RATE_TABLE *rt, u_int8_t rates_array[], int rt_offset,
49 u_int8_t chainmask);
50 static inline void ar9300_init_rate_txpower_ht(struct ath_hal *ah,
51 const HAL_RATE_TABLE *rt, HAL_BOOL is40, u_int8_t rates_array[],
52 int rt_ss_offset, int rt_ds_offset,
53 int rt_ts_offset, u_int8_t chainmask);
54 static inline void ar9300_init_rate_txpower_stbc(struct ath_hal *ah,
55 const HAL_RATE_TABLE *rt, HAL_BOOL is40,
56 int rt_ss_offset, int rt_ds_offset,
57 int rt_ts_offset, u_int8_t chainmask);
58 #if 0
59 static inline void ar9300_adjust_rate_txpower_cdd(struct ath_hal *ah,
60 const HAL_RATE_TABLE *rt, HAL_BOOL is40,
61 int rt_ss_offset, int rt_ds_offset,
62 int rt_ts_offset, u_int8_t chainmask);
63 #endif
64
65 #define AR9300_11A_RT_OFDM_OFFSET 0
66 HAL_RATE_TABLE ar9300_11a_table = {
67 8, /* number of rates */
68 { 0 },
69 {
70 /* short ctrl */
71 /* valid rate_code Preamble dot11Rate Rate */
72 /* 6 Mb */ { AH_TRUE, OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0 },
73 /* 9 Mb */ { AH_TRUE, OFDM, 9000, 0x0f, 0x00, 18, 0 },
74 /* 12 Mb */ { AH_TRUE, OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2 },
75 /* 18 Mb */ { AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 2 },
76 /* 24 Mb */ { AH_TRUE, OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4 },
77 /* 36 Mb */ { AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 4 },
78 /* 48 Mb */ { AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 4 },
79 /* 54 Mb */ { AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 4 },
80 },
81 };
82
83 HAL_RATE_TABLE ar9300_11a_half_table = {
84 8, /* number of rates */
85 { 0 },
86 {
87 /* short ctrl */
88 /* valid rate_code Preamble dot11Rate Rate */
89 /* 6 Mb */ { AH_TRUE, OFDM, 3000, 0x0b, 0x00, (0x80 | 6), 0 },
90 /* 9 Mb */ { AH_TRUE, OFDM, 4500, 0x0f, 0x00, 9, 0 },
91 /* 12 Mb */ { AH_TRUE, OFDM, 6000, 0x0a, 0x00, (0x80 | 12), 2 },
92 /* 18 Mb */ { AH_TRUE, OFDM, 9000, 0x0e, 0x00, 18, 2 },
93 /* 24 Mb */ { AH_TRUE, OFDM, 12000, 0x09, 0x00, (0x80 | 24), 4 },
94 /* 36 Mb */ { AH_TRUE, OFDM, 18000, 0x0d, 0x00, 36, 4 },
95 /* 48 Mb */ { AH_TRUE, OFDM, 24000, 0x08, 0x00, 48, 4 },
96 /* 54 Mb */ { AH_TRUE, OFDM, 27000, 0x0c, 0x00, 54, 4 },
97 },
98 };
99
100 HAL_RATE_TABLE ar9300_11a_quarter_table = {
101 8, /* number of rates */
102 { 0 },
103 {
104 /* short ctrl */
105 /* valid rate_code Preamble dot11Rate Rate */
106 /* 6 Mb */ { AH_TRUE, OFDM, 1500, 0x0b, 0x00, (0x80 | 3), 0 },
107 /* 9 Mb */ { AH_TRUE, OFDM, 2250, 0x0f, 0x00, 4 , 0 },
108 /* 12 Mb */ { AH_TRUE, OFDM, 3000, 0x0a, 0x00, (0x80 | 6), 2 },
109 /* 18 Mb */ { AH_TRUE, OFDM, 4500, 0x0e, 0x00, 9, 2 },
110 /* 24 Mb */ { AH_TRUE, OFDM, 6000, 0x09, 0x00, (0x80 | 12), 4 },
111 /* 36 Mb */ { AH_TRUE, OFDM, 9000, 0x0d, 0x00, 18, 4 },
112 /* 48 Mb */ { AH_TRUE, OFDM, 12000, 0x08, 0x00, 24, 4 },
113 /* 54 Mb */ { AH_TRUE, OFDM, 13500, 0x0c, 0x00, 27, 4 },
114 },
115 };
116
117 HAL_RATE_TABLE ar9300_turbo_table = {
118 8, /* number of rates */
119 { 0 },
120 {
121 /* short ctrl */
122 /* valid rate_code Preamble dot11Rate Rate */
123 /* 6 Mb */ { AH_TRUE, TURBO, 6000, 0x0b, 0x00, (0x80 | 12), 0 },
124 /* 9 Mb */ { AH_TRUE, TURBO, 9000, 0x0f, 0x00, 18, 0 },
125 /* 12 Mb */ { AH_TRUE, TURBO, 12000, 0x0a, 0x00, (0x80 | 24), 2 },
126 /* 18 Mb */ { AH_TRUE, TURBO, 18000, 0x0e, 0x00, 36, 2 },
127 /* 24 Mb */ { AH_TRUE, TURBO, 24000, 0x09, 0x00, (0x80 | 48), 4 },
128 /* 36 Mb */ { AH_TRUE, TURBO, 36000, 0x0d, 0x00, 72, 4 },
129 /* 48 Mb */ { AH_TRUE, TURBO, 48000, 0x08, 0x00, 96, 4 },
130 /* 54 Mb */ { AH_TRUE, TURBO, 54000, 0x0c, 0x00, 108, 4 },
131 },
132 };
133
134 HAL_RATE_TABLE ar9300_11b_table = {
135 4, /* number of rates */
136 { 0 },
137 {
138 /* short ctrl */
139 /* valid rate_code Preamble dot11Rate Rate */
140 /* 1 Mb */ { AH_TRUE, CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0 },
141 /* 2 Mb */ { AH_TRUE, CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1 },
142 /* 5.5 Mb */ { AH_TRUE, CCK, 5500, 0x19, 0x04, (0x80 | 11), 1 },
143 /* 11 Mb */ { AH_TRUE, CCK, 11000, 0x18, 0x04, (0x80 | 22), 1 },
144 },
145 };
146
147
148 /* Venice TODO: round_up_rate() is broken when the rate table does not represent
149 * rates in increasing order e.g. 5.5, 11, 6, 9.
150 * An average rate of 6 Mbps will currently map to 11 Mbps.
151 */
152 #define AR9300_11G_RT_OFDM_OFFSET 4
153 HAL_RATE_TABLE ar9300_11g_table = {
154 12, /* number of rates */
155 { 0 },
156 {
157 /* short ctrl */
158 /* valid rate_code Preamble dot11Rate Rate */
159 /* 1 Mb */ { AH_TRUE, CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0 },
160 /* 2 Mb */ { AH_TRUE, CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1 },
161 /* 5.5 Mb */ { AH_TRUE, CCK, 5500, 0x19, 0x04, (0x80 | 11), 2 },
162 /* 11 Mb */ { AH_TRUE, CCK, 11000, 0x18, 0x04, (0x80 | 22), 3 },
163 /* Hardware workaround - remove rates 6, 9 from rate ctrl */
164 /* 6 Mb */ { AH_TRUE, OFDM, 6000, 0x0b, 0x00, 12, 4 },
165 /* 9 Mb */ { AH_TRUE, OFDM, 9000, 0x0f, 0x00, 18, 4 },
166 /* 12 Mb */ { AH_TRUE, OFDM, 12000, 0x0a, 0x00, 24, 6 },
167 /* 18 Mb */ { AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 6 },
168 /* 24 Mb */ { AH_TRUE, OFDM, 24000, 0x09, 0x00, 48, 8 },
169 /* 36 Mb */ { AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 8 },
170 /* 48 Mb */ { AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 8 },
171 /* 54 Mb */ { AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 8 },
172 },
173 };
174
175 #if 0
176 HAL_RATE_TABLE ar9300_xr_table = {
177 13, /* number of rates */
178 { 0 },
179 {
180 /* short ctrl */
181 /* valid rate_code Preamble dot11Rate Rate */
182 /* 0.25 Mb */ {AH_TRUE, XR, 250, 0x03, 0x00, (0x80 | 1), 0, 612, 612 },
183 /* 0.5 Mb */ {AH_TRUE, XR, 500, 0x07, 0x00, (0x80 | 1), 0, 457, 457 },
184 /* 1 Mb */ {AH_TRUE, XR, 1000, 0x02, 0x00, (0x80 | 2), 1, 228, 228 },
185 /* 2 Mb */ {AH_TRUE, XR, 2000, 0x06, 0x00, (0x80 | 4), 2, 160, 160 },
186 /* 3 Mb */ {AH_TRUE, XR, 3000, 0x01, 0x00, (0x80 | 6), 3, 140, 140 },
187 /* 6 Mb */ {AH_TRUE, OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 4, 60, 60 },
188 /* 9 Mb */ {AH_TRUE, OFDM, 9000, 0x0f, 0x00, 18, 4, 60, 60 },
189 /* 12 Mb */ {AH_TRUE, OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 6, 48, 48 },
190 /* 18 Mb */ {AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 6, 48, 48 },
191 /* 24 Mb */ {AH_TRUE, OFDM, 24000, 0x09, 0x00, 48, 8, 44, 44 },
192 /* 36 Mb */ {AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 8, 44, 44 },
193 /* 48 Mb */ {AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 8, 44, 44 },
194 /* 54 Mb */ {AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 8, 44, 44 },
195 },
196 };
197 #endif
198
199 #define AR9300_11NG_RT_OFDM_OFFSET 4
200 #define AR9300_11NG_RT_HT_SS_OFFSET 12
201 #define AR9300_11NG_RT_HT_DS_OFFSET 20
202 #define AR9300_11NG_RT_HT_TS_OFFSET 28
203 HAL_RATE_TABLE ar9300_11ng_table = {
204
205 36, /* number of rates */
206 { 0 },
207 {
208 /* short ctrl */
209 /* valid rate_code Preamble dot11Rate Rate */
210 /* 1 Mb */ { AH_TRUE, CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0 },
211 /* 2 Mb */ { AH_TRUE, CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1 },
212 /* 5.5 Mb */ { AH_TRUE, CCK, 5500, 0x19, 0x04, (0x80 | 11), 2 },
213 /* 11 Mb */ { AH_TRUE, CCK, 11000, 0x18, 0x04, (0x80 | 22), 3 },
214 /* Hardware workaround - remove rates 6, 9 from rate ctrl */
215 /* 6 Mb */ { AH_FALSE, OFDM, 6000, 0x0b, 0x00, 12, 4 },
216 /* 9 Mb */ { AH_FALSE, OFDM, 9000, 0x0f, 0x00, 18, 4 },
217 /* 12 Mb */ { AH_TRUE, OFDM, 12000, 0x0a, 0x00, 24, 6 },
218 /* 18 Mb */ { AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 6 },
219 /* 24 Mb */ { AH_TRUE, OFDM, 24000, 0x09, 0x00, 48, 8 },
220 /* 36 Mb */ { AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 8 },
221 /* 48 Mb */ { AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 8 },
222 /* 54 Mb */ { AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 8 },
223 /*--- HT SS rates ---*/
224 /* 6.5 Mb */ { AH_TRUE, HT, 6500, 0x80, 0x00, 0, 4 },
225 /* 13 Mb */ { AH_TRUE, HT, 13000, 0x81, 0x00, 1, 6 },
226 /*19.5 Mb */ { AH_TRUE, HT, 19500, 0x82, 0x00, 2, 6 },
227 /* 26 Mb */ { AH_TRUE, HT, 26000, 0x83, 0x00, 3, 8 },
228 /* 39 Mb */ { AH_TRUE, HT, 39000, 0x84, 0x00, 4, 8 },
229 /* 52 Mb */ { AH_TRUE, HT, 52000, 0x85, 0x00, 5, 8 },
230 /*58.5 Mb */ { AH_TRUE, HT, 58500, 0x86, 0x00, 6, 8 },
231 /* 65 Mb */ { AH_TRUE, HT, 65000, 0x87, 0x00, 7, 8 },
232 /*--- HT DS rates ---*/
233 /* 13 Mb */ { AH_TRUE, HT, 13000, 0x88, 0x00, 8, 4 },
234 /* 26 Mb */ { AH_TRUE, HT, 26000, 0x89, 0x00, 9, 6 },
235 /* 39 Mb */ { AH_TRUE, HT, 39000, 0x8a, 0x00, 10, 6 },
236 /* 52 Mb */ { AH_TRUE, HT, 52000, 0x8b, 0x00, 11, 8 },
237 /* 78 Mb */ { AH_TRUE, HT, 78000, 0x8c, 0x00, 12, 8 },
238 /* 104 Mb */ { AH_TRUE, HT, 104000, 0x8d, 0x00, 13, 8 },
239 /* 117 Mb */ { AH_TRUE, HT, 117000, 0x8e, 0x00, 14, 8 },
240 /* 130 Mb */ { AH_TRUE, HT, 130000, 0x8f, 0x00, 15, 8 },
241 /*--- HT TS rates ---*/
242 /*19.5 Mb */ { AH_TRUE, HT, 19500, 0x90, 0x00, 16, 4 },
243 /* 39 Mb */ { AH_TRUE, HT, 39000, 0x91, 0x00, 17, 6 },
244 /*58.5 Mb */ { AH_TRUE, HT, 58500, 0x92, 0x00, 18, 6 },
245 /* 78 Mb */ { AH_TRUE, HT, 78000, 0x93, 0x00, 19, 8 },
246 /* 117 Mb */ { AH_TRUE, HT, 117000, 0x94, 0x00, 20, 8 },
247 /* 156 Mb */ { AH_TRUE, HT, 156000, 0x95, 0x00, 21, 8 },
248 /*175.5Mb */ { AH_TRUE, HT, 175500, 0x96, 0x00, 22, 8 },
249 /* 195 Mb */ { AH_TRUE, HT, 195000, 0x97, 0x00, 23, 8 },
250 },
251 };
252
253 #define AR9300_11NA_RT_OFDM_OFFSET 0
254 #define AR9300_11NA_RT_HT_SS_OFFSET 8
255 #define AR9300_11NA_RT_HT_DS_OFFSET 16
256 #define AR9300_11NA_RT_HT_TS_OFFSET 24
257 static HAL_RATE_TABLE ar9300_11na_table = {
258
259 32, /* number of rates */
260 { 0 },
261 {
262 /* short ctrl */
263 /* valid rate_code Preamble dot11Rate Rate */
264 /* 6 Mb */ { AH_TRUE, OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0 },
265 /* 9 Mb */ { AH_TRUE, OFDM, 9000, 0x0f, 0x00, 18, 0 },
266 /* 12 Mb */ { AH_TRUE, OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2 },
267 /* 18 Mb */ { AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 2 },
268 /* 24 Mb */ { AH_TRUE, OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4 },
269 /* 36 Mb */ { AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 4 },
270 /* 48 Mb */ { AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 4 },
271 /* 54 Mb */ { AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 4 },
272 /*--- HT SS rates ---*/
273 /* 6.5 Mb */ { AH_TRUE, HT, 6500, 0x80, 0x00, 0, 0 },
274 /* 13 Mb */ { AH_TRUE, HT, 13000, 0x81, 0x00, 1, 2 },
275 /*19.5 Mb */ { AH_TRUE, HT, 19500, 0x82, 0x00, 2, 2 },
276 /* 26 Mb */ { AH_TRUE, HT, 26000, 0x83, 0x00, 3, 4 },
277 /* 39 Mb */ { AH_TRUE, HT, 39000, 0x84, 0x00, 4, 4 },
278 /* 52 Mb */ { AH_TRUE, HT, 52000, 0x85, 0x00, 5, 4 },
279 /*58.5 Mb */ { AH_TRUE, HT, 58500, 0x86, 0x00, 6, 4 },
280 /* 65 Mb */ { AH_TRUE, HT, 65000, 0x87, 0x00, 7, 4 },
281 /*--- HT DS rates ---*/
282 /* 13 Mb */ { AH_TRUE, HT, 13000, 0x88, 0x00, 8, 0 },
283 /* 26 Mb */ { AH_TRUE, HT, 26000, 0x89, 0x00, 9, 2 },
284 /* 39 Mb */ { AH_TRUE, HT, 39000, 0x8a, 0x00, 10, 2 },
285 /* 52 Mb */ { AH_TRUE, HT, 52000, 0x8b, 0x00, 11, 4 },
286 /* 78 Mb */ { AH_TRUE, HT, 78000, 0x8c, 0x00, 12, 4 },
287 /* 104 Mb */ { AH_TRUE, HT, 104000, 0x8d, 0x00, 13, 4 },
288 /* 117 Mb */ { AH_TRUE, HT, 117000, 0x8e, 0x00, 14, 4 },
289 /* 130 Mb */ { AH_TRUE, HT, 130000, 0x8f, 0x00, 15, 4 },
290 /*--- HT TS rates ---*/
291 /*19.5 Mb */ { AH_TRUE, HT, 19500, 0x90, 0x00, 16, 0 },
292 /* 39 Mb */ { AH_TRUE, HT, 39000, 0x91, 0x00, 17, 2 },
293 /*58.5 Mb */ { AH_TRUE, HT, 58500, 0x92, 0x00, 18, 2 },
294 /* 78 Mb */ { AH_TRUE, HT, 78000, 0x93, 0x00, 19, 4 },
295 /* 117 Mb */ { AH_TRUE, HT, 117000, 0x94, 0x00, 20, 4 },
296 /* 156 Mb */ { AH_TRUE, HT, 156000, 0x95, 0x00, 21, 4 },
297 /*175.5Mb */ { AH_TRUE, HT, 175500, 0x96, 0x00, 22, 4 },
298 /* 195 Mb */ { AH_TRUE, HT, 195000, 0x97, 0x00, 23, 4 },
299 },
300 };
301
302 #undef OFDM
303 #undef CCK
304 #undef TURBO
305 #undef XR
306 #undef HT
307 #undef HT_HGI
308
309 const HAL_RATE_TABLE *
ar9300_get_rate_table(struct ath_hal * ah,u_int mode)310 ar9300_get_rate_table(struct ath_hal *ah, u_int mode)
311 {
312 struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
313 HAL_CAPABILITIES *p_cap = &ahpriv->ah_caps;
314 HAL_RATE_TABLE *rt;
315
316 switch (mode) {
317 case HAL_MODE_11A:
318 rt = &ar9300_11a_table;
319 break;
320 case HAL_MODE_11A_HALF_RATE:
321 if (p_cap->halChanHalfRate) {
322 rt = &ar9300_11a_half_table;
323 break;
324 }
325 return AH_NULL;
326 case HAL_MODE_11A_QUARTER_RATE:
327 if (p_cap->halChanQuarterRate) {
328 rt = &ar9300_11a_quarter_table;
329 break;
330 }
331 return AH_NULL;
332 case HAL_MODE_11B:
333 rt = &ar9300_11b_table;
334 break;
335 case HAL_MODE_11G:
336 rt = &ar9300_11g_table;
337 break;
338 case HAL_MODE_TURBO:
339 case HAL_MODE_108G:
340 rt = &ar9300_turbo_table;
341 break;
342 #if 0
343 case HAL_MODE_XR:
344 rt = &ar9300_xr_table;
345 break;
346 #endif
347 case HAL_MODE_11NG_HT20:
348 case HAL_MODE_11NG_HT40PLUS:
349 case HAL_MODE_11NG_HT40MINUS:
350 rt = &ar9300_11ng_table;
351 break;
352 case HAL_MODE_11NA_HT20:
353 case HAL_MODE_11NA_HT40PLUS:
354 case HAL_MODE_11NA_HT40MINUS:
355 rt = &ar9300_11na_table;
356 break;
357 default:
358 HALDEBUG(ah, HAL_DEBUG_CHANNEL,
359 "%s: invalid mode 0x%x\n", __func__, mode);
360 return AH_NULL;
361 }
362 ath_hal_setupratetable(ah, rt);
363 return rt;
364 }
365
366 static HAL_BOOL
ar9300_invalid_stbc_cfg(int tx_chains,u_int8_t rate_code)367 ar9300_invalid_stbc_cfg(int tx_chains, u_int8_t rate_code)
368 {
369 switch (tx_chains) {
370 case 0: /* Single Chain */
371 return AH_TRUE;
372
373 case 1: /* 2 Chains */
374 if ((rate_code < 0x80) || (rate_code > 0x87)) {
375 return AH_TRUE;
376 } else {
377 return AH_FALSE;
378 }
379
380 case 2: /* 3 Chains */
381 if ((rate_code < 0x80) || (rate_code > 0x87)) {
382 return AH_TRUE;
383 } else {
384 return AH_FALSE;
385 }
386
387 default:
388 HALASSERT(0);
389 break;
390 }
391
392 return AH_TRUE;
393 }
394
395 int16_t
ar9300_get_rate_txpower(struct ath_hal * ah,u_int mode,u_int8_t rate_index,u_int8_t chainmask,u_int8_t xmit_mode)396 ar9300_get_rate_txpower(struct ath_hal *ah, u_int mode, u_int8_t rate_index,
397 u_int8_t chainmask, u_int8_t xmit_mode)
398 {
399 struct ath_hal_9300 *ahp = AH9300(ah);
400 int num_chains = ar9300_get_ntxchains(chainmask);
401
402 switch (xmit_mode) {
403 case AR9300_DEF_MODE:
404 return ahp->txpower[rate_index][num_chains-1];
405
406
407 case AR9300_STBC_MODE:
408 return ahp->txpower_stbc[rate_index][num_chains-1];
409
410 default:
411 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid mode 0x%x\n",
412 __func__, xmit_mode);
413 HALASSERT(0);
414 break;
415 }
416
417 return ahp->txpower[rate_index][num_chains-1];
418 }
419
420 extern void
ar9300_adjust_reg_txpower_cdd(struct ath_hal * ah,u_int8_t power_per_rate[])421 ar9300_adjust_reg_txpower_cdd(struct ath_hal *ah,
422 u_int8_t power_per_rate[])
423
424 {
425 struct ath_hal_9300 *ahp = AH9300(ah);
426 int16_t twice_array_gain, cdd_power = 0;
427 int i;
428
429 /*
430 * Adjust the upper limit for CDD factoring in the array gain .
431 * The array gain is the same as TxBF, hence reuse the same defines.
432 */
433 switch (ahp->ah_tx_chainmask) {
434
435 case OSPREY_1_CHAINMASK:
436 cdd_power = ahp->upper_limit[0];
437 break;
438
439 case OSPREY_2LOHI_CHAINMASK:
440 case OSPREY_2LOMID_CHAINMASK:
441 twice_array_gain =
442 (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
443 -(AR9300_TXBF_2TX_ARRAY_GAIN) :
444 ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
445 (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0));
446 cdd_power = ahp->upper_limit[1] + twice_array_gain;
447
448 HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: 2 chain; cdd_power=%d", __func__, cdd_power);
449 /* Adjust OFDM legacy rates as well */
450 for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) {
451 if (power_per_rate[i] > cdd_power) {
452 power_per_rate[i] = cdd_power;
453 }
454 }
455
456 /* 2Tx/(n-1) stream Adjust rates MCS0 through MCS 7 HT 20*/
457 for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_7; i++) {
458 if (power_per_rate[i] > cdd_power) {
459 power_per_rate[i] = cdd_power;
460 }
461 }
462
463 /* 2Tx/(n-1) stream Adjust rates MCS0 through MCS 7 HT 40*/
464 for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_7; i++) {
465 if (power_per_rate[i] > cdd_power) {
466 power_per_rate[i] = cdd_power;
467 }
468 }
469 break;
470
471 case OSPREY_3_CHAINMASK:
472 twice_array_gain =
473 (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
474 -(AR9300_TXBF_3TX_ARRAY_GAIN) :
475 ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
476 (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0));
477 cdd_power = ahp->upper_limit[2] + twice_array_gain;
478 HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: 3 chain; cdd_power=%d", __func__, cdd_power);
479 /* Adjust OFDM legacy rates as well */
480 for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) {
481 if (power_per_rate[i] > cdd_power) {
482 power_per_rate[i] = cdd_power;
483 }
484 }
485 /* 3Tx/(n-1)streams Adjust rates MCS0 through MCS 15 HT20 */
486 for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_15; i++) {
487 if (power_per_rate[i] > cdd_power) {
488 power_per_rate[i] = cdd_power;
489 }
490 }
491
492 /* 3Tx/(n-1)streams Adjust rates MCS0 through MCS 15 HT40 */
493 for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_15; i++) {
494 if (power_per_rate[i] > cdd_power) {
495 power_per_rate[i] = cdd_power;
496 }
497 }
498
499 break;
500
501 default:
502 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
503 __func__, ahp->ah_tx_chainmask);
504 break;
505 }
506
507 return;
508 }
509
510 extern void
ar9300_init_rate_txpower(struct ath_hal * ah,u_int mode,const struct ieee80211_channel * chan,u_int8_t power_per_rate[],u_int8_t chainmask)511 ar9300_init_rate_txpower(struct ath_hal *ah, u_int mode,
512 const struct ieee80211_channel *chan,
513 u_int8_t power_per_rate[], u_int8_t chainmask)
514 {
515 const HAL_RATE_TABLE *rt;
516 HAL_BOOL is40 = IEEE80211_IS_CHAN_HT40(chan);
517
518 rt = ar9300_get_rate_table(ah, mode);
519 HALASSERT(rt != NULL);
520
521 switch (mode) {
522 case HAL_MODE_11A:
523 ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate,
524 AR9300_11A_RT_OFDM_OFFSET, chainmask);
525 break;
526 case HAL_MODE_11NA_HT20:
527 case HAL_MODE_11NA_HT40PLUS:
528 case HAL_MODE_11NA_HT40MINUS:
529 ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate,
530 AR9300_11NA_RT_OFDM_OFFSET, chainmask);
531 ar9300_init_rate_txpower_ht(ah, rt, is40, power_per_rate,
532 AR9300_11NA_RT_HT_SS_OFFSET,
533 AR9300_11NA_RT_HT_DS_OFFSET,
534 AR9300_11NA_RT_HT_TS_OFFSET, chainmask);
535 ar9300_init_rate_txpower_stbc(ah, rt, is40,
536 AR9300_11NA_RT_HT_SS_OFFSET,
537 AR9300_11NA_RT_HT_DS_OFFSET,
538 AR9300_11NA_RT_HT_TS_OFFSET, chainmask);
539 #if 0
540 /* For FCC the array gain has to be factored for CDD mode */
541 if (is_reg_dmn_fcc(ath_hal_getctl(ah, chan))) {
542 ar9300_adjust_rate_txpower_cdd(ah, rt, is40,
543 AR9300_11NA_RT_HT_SS_OFFSET,
544 AR9300_11NA_RT_HT_DS_OFFSET,
545 AR9300_11NA_RT_HT_TS_OFFSET, chainmask);
546 }
547 #endif
548 break;
549 case HAL_MODE_11G:
550 ar9300_init_rate_txpower_cck(ah, rt, power_per_rate, chainmask);
551 ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate,
552 AR9300_11G_RT_OFDM_OFFSET, chainmask);
553 break;
554 case HAL_MODE_11B:
555 ar9300_init_rate_txpower_cck(ah, rt, power_per_rate, chainmask);
556 break;
557 case HAL_MODE_11NG_HT20:
558 case HAL_MODE_11NG_HT40PLUS:
559 case HAL_MODE_11NG_HT40MINUS:
560 ar9300_init_rate_txpower_cck(ah, rt, power_per_rate, chainmask);
561 ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate,
562 AR9300_11NG_RT_OFDM_OFFSET, chainmask);
563 ar9300_init_rate_txpower_ht(ah, rt, is40, power_per_rate,
564 AR9300_11NG_RT_HT_SS_OFFSET,
565 AR9300_11NG_RT_HT_DS_OFFSET,
566 AR9300_11NG_RT_HT_TS_OFFSET, chainmask);
567 ar9300_init_rate_txpower_stbc(ah, rt, is40,
568 AR9300_11NG_RT_HT_SS_OFFSET,
569 AR9300_11NG_RT_HT_DS_OFFSET,
570 AR9300_11NG_RT_HT_TS_OFFSET, chainmask);
571 #if 0
572 /* For FCC the array gain needs to be factored for CDD mode */
573 if (is_reg_dmn_fcc(ath_hal_getctl(ah, chan))) {
574 ar9300_adjust_rate_txpower_cdd(ah, rt, is40,
575 AR9300_11NG_RT_HT_SS_OFFSET,
576 AR9300_11NG_RT_HT_DS_OFFSET,
577 AR9300_11NG_RT_HT_TS_OFFSET, chainmask);
578 }
579 #endif
580 break;
581 default:
582 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid mode 0x%x\n",
583 __func__, mode);
584 HALASSERT(0);
585 break;
586 }
587
588 }
589
590 static inline void
ar9300_init_rate_txpower_cck(struct ath_hal * ah,const HAL_RATE_TABLE * rt,u_int8_t rates_array[],u_int8_t chainmask)591 ar9300_init_rate_txpower_cck(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
592 u_int8_t rates_array[], u_int8_t chainmask)
593 {
594 struct ath_hal_9300 *ahp = AH9300(ah);
595 /*
596 * Pick the lower of the long-preamble txpower, and short-preamble tx power.
597 * Unfortunately, the rate table doesn't have separate entries for these!.
598 */
599 switch (chainmask) {
600 case OSPREY_1_CHAINMASK:
601 ahp->txpower[0][0] = rates_array[ALL_TARGET_LEGACY_1L_5L];
602 ahp->txpower[1][0] = rates_array[ALL_TARGET_LEGACY_1L_5L];
603 ahp->txpower[2][0] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L],
604 rates_array[ALL_TARGET_LEGACY_5S]);
605 ahp->txpower[3][0] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L],
606 rates_array[ALL_TARGET_LEGACY_11S]);
607 break;
608 case OSPREY_2LOHI_CHAINMASK:
609 case OSPREY_2LOMID_CHAINMASK:
610 ahp->txpower[0][1] = rates_array[ALL_TARGET_LEGACY_1L_5L];
611 ahp->txpower[1][1] = rates_array[ALL_TARGET_LEGACY_1L_5L];
612 ahp->txpower[2][1] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L],
613 rates_array[ALL_TARGET_LEGACY_5S]);
614 ahp->txpower[3][1] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L],
615 rates_array[ALL_TARGET_LEGACY_11S]);
616 break;
617 case OSPREY_3_CHAINMASK:
618 ahp->txpower[0][2] = rates_array[ALL_TARGET_LEGACY_1L_5L];
619 ahp->txpower[1][2] = rates_array[ALL_TARGET_LEGACY_1L_5L];
620 ahp->txpower[2][2] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L],
621 rates_array[ALL_TARGET_LEGACY_5S]);
622 ahp->txpower[3][2] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L],
623 rates_array[ALL_TARGET_LEGACY_11S]);
624 break;
625 default:
626 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
627 __func__, chainmask);
628 break;
629 }
630 }
631
632 static inline void
ar9300_init_rate_txpower_ofdm(struct ath_hal * ah,const HAL_RATE_TABLE * rt,u_int8_t rates_array[],int rt_offset,u_int8_t chainmask)633 ar9300_init_rate_txpower_ofdm(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
634 u_int8_t rates_array[], int rt_offset,
635 u_int8_t chainmask)
636 {
637 struct ath_hal_9300 *ahp = AH9300(ah);
638 int16_t twice_array_gain, cdd_power = 0;
639 int i, j;
640 u_int8_t ofdm_rt_2_pwr_idx[8] =
641 {
642 ALL_TARGET_LEGACY_6_24,
643 ALL_TARGET_LEGACY_6_24,
644 ALL_TARGET_LEGACY_6_24,
645 ALL_TARGET_LEGACY_6_24,
646 ALL_TARGET_LEGACY_6_24,
647 ALL_TARGET_LEGACY_36,
648 ALL_TARGET_LEGACY_48,
649 ALL_TARGET_LEGACY_54,
650 };
651
652 /*
653 * For FCC adjust the upper limit for CDD factoring in the array gain.
654 * The array gain is the same as TxBF, hence reuse the same defines.
655 */
656 for (i = rt_offset; i < rt_offset + AR9300_NUM_OFDM_RATES; i++) {
657
658 /* Get the correct OFDM rate to Power table Index */
659 j = ofdm_rt_2_pwr_idx[i- rt_offset];
660
661 switch (chainmask) {
662 case OSPREY_1_CHAINMASK:
663 ahp->txpower[i][0] = rates_array[j];
664 break;
665 case OSPREY_2LOHI_CHAINMASK:
666 case OSPREY_2LOMID_CHAINMASK:
667 ahp->txpower[i][1] = rates_array[j];
668 if (is_reg_dmn_fcc(ahp->reg_dmn)){
669 twice_array_gain = (ahp->twice_antenna_gain >=
670 ahp->twice_antenna_reduction)?
671 -(AR9300_TXBF_2TX_ARRAY_GAIN) :
672 ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
673 (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0));
674 cdd_power = ahp->upper_limit[1] + twice_array_gain;
675 if (ahp->txpower[i][1] > cdd_power){
676 ahp->txpower[i][1] = cdd_power;
677 }
678 }
679 break;
680 case OSPREY_3_CHAINMASK:
681 ahp->txpower[i][2] = rates_array[j];
682 if (is_reg_dmn_fcc(ahp->reg_dmn)) {
683 twice_array_gain =
684 (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
685 -(AR9300_TXBF_3TX_ARRAY_GAIN):
686 ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
687 (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0));
688 cdd_power = ahp->upper_limit[2] + twice_array_gain;
689 if (ahp->txpower[i][2] > cdd_power){
690 ahp->txpower[i][2] = cdd_power;
691 }
692 }
693 break;
694 default:
695 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
696 __func__, chainmask);
697 break;
698 }
699 }
700 }
701
702 static u_int8_t mcs_rate_2_pwr_idx_ht20[24] =
703 {
704 ALL_TARGET_HT20_0_8_16,
705 ALL_TARGET_HT20_1_3_9_11_17_19,
706 ALL_TARGET_HT20_1_3_9_11_17_19,
707 ALL_TARGET_HT20_1_3_9_11_17_19,
708 ALL_TARGET_HT20_4,
709 ALL_TARGET_HT20_5,
710 ALL_TARGET_HT20_6,
711 ALL_TARGET_HT20_7,
712 ALL_TARGET_HT20_0_8_16,
713 ALL_TARGET_HT20_1_3_9_11_17_19,
714 ALL_TARGET_HT20_1_3_9_11_17_19,
715 ALL_TARGET_HT20_1_3_9_11_17_19,
716 ALL_TARGET_HT20_12,
717 ALL_TARGET_HT20_13,
718 ALL_TARGET_HT20_14,
719 ALL_TARGET_HT20_15,
720 ALL_TARGET_HT20_0_8_16,
721 ALL_TARGET_HT20_1_3_9_11_17_19,
722 ALL_TARGET_HT20_1_3_9_11_17_19,
723 ALL_TARGET_HT20_1_3_9_11_17_19,
724 ALL_TARGET_HT20_20,
725 ALL_TARGET_HT20_21,
726 ALL_TARGET_HT20_22,
727 ALL_TARGET_HT20_23
728 };
729
730 static u_int8_t mcs_rate_2_pwr_idx_ht40[24] =
731 {
732 ALL_TARGET_HT40_0_8_16,
733 ALL_TARGET_HT40_1_3_9_11_17_19,
734 ALL_TARGET_HT40_1_3_9_11_17_19,
735 ALL_TARGET_HT40_1_3_9_11_17_19,
736 ALL_TARGET_HT40_4,
737 ALL_TARGET_HT40_5,
738 ALL_TARGET_HT40_6,
739 ALL_TARGET_HT40_7,
740 ALL_TARGET_HT40_0_8_16,
741 ALL_TARGET_HT40_1_3_9_11_17_19,
742 ALL_TARGET_HT40_1_3_9_11_17_19,
743 ALL_TARGET_HT40_1_3_9_11_17_19,
744 ALL_TARGET_HT40_12,
745 ALL_TARGET_HT40_13,
746 ALL_TARGET_HT40_14,
747 ALL_TARGET_HT40_15,
748 ALL_TARGET_HT40_0_8_16,
749 ALL_TARGET_HT40_1_3_9_11_17_19,
750 ALL_TARGET_HT40_1_3_9_11_17_19,
751 ALL_TARGET_HT40_1_3_9_11_17_19,
752 ALL_TARGET_HT40_20,
753 ALL_TARGET_HT40_21,
754 ALL_TARGET_HT40_22,
755 ALL_TARGET_HT40_23,
756 };
757
758 static inline void
ar9300_init_rate_txpower_ht(struct ath_hal * ah,const HAL_RATE_TABLE * rt,HAL_BOOL is40,u_int8_t rates_array[],int rt_ss_offset,int rt_ds_offset,int rt_ts_offset,u_int8_t chainmask)759 ar9300_init_rate_txpower_ht(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
760 HAL_BOOL is40,
761 u_int8_t rates_array[],
762 int rt_ss_offset, int rt_ds_offset,
763 int rt_ts_offset, u_int8_t chainmask)
764 {
765
766 struct ath_hal_9300 *ahp = AH9300(ah);
767 int i, j;
768 u_int8_t mcs_index = 0;
769
770
771 for (i = rt_ss_offset; i < rt_ss_offset + AR9300_NUM_HT_SS_RATES; i++) {
772 /* Get the correct MCS rate to Power table Index */
773 j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] :
774 mcs_rate_2_pwr_idx_ht20[mcs_index];
775 switch (chainmask) {
776 case OSPREY_1_CHAINMASK:
777 ahp->txpower[i][0] = rates_array[j];
778 break;
779 case OSPREY_2LOHI_CHAINMASK:
780 case OSPREY_2LOMID_CHAINMASK:
781 ahp->txpower[i][1] = rates_array[j];
782 break;
783 case OSPREY_3_CHAINMASK:
784 ahp->txpower[i][2] = rates_array[j];
785 break;
786 default:
787 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
788 __func__, chainmask);
789 break;
790 }
791 mcs_index++;
792 }
793
794 for (i = rt_ds_offset; i < rt_ds_offset + AR9300_NUM_HT_DS_RATES; i++) {
795 /* Get the correct MCS rate to Power table Index */
796 j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] :
797 mcs_rate_2_pwr_idx_ht20[mcs_index];
798 switch (chainmask) {
799 case OSPREY_1_CHAINMASK:
800 ahp->txpower[i][0] = rates_array[j];
801 break;
802 case OSPREY_2LOHI_CHAINMASK:
803 case OSPREY_2LOMID_CHAINMASK:
804 ahp->txpower[i][1] = rates_array[j];
805 break;
806 case OSPREY_3_CHAINMASK:
807 ahp->txpower[i][2] = rates_array[j];
808 break;
809 default:
810 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
811 __func__, chainmask);
812 break;
813 }
814 mcs_index++;
815 }
816
817 for (i = rt_ts_offset; i < rt_ts_offset + AR9300_NUM_HT_TS_RATES; i++) {
818 /* Get the correct MCS rate to Power table Index */
819 j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] :
820 mcs_rate_2_pwr_idx_ht20[mcs_index];
821 switch (chainmask) {
822 case OSPREY_1_CHAINMASK:
823 ahp->txpower[i][0] = rates_array[j];
824 break;
825 case OSPREY_2LOHI_CHAINMASK:
826 case OSPREY_2LOMID_CHAINMASK:
827 ahp->txpower[i][1] = rates_array[j];
828 break;
829 case OSPREY_3_CHAINMASK:
830 ahp->txpower[i][2] = rates_array[j];
831 break;
832 default:
833 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
834 __func__, chainmask);
835 break;
836 }
837 mcs_index++;
838 }
839 }
840
841 static inline void
ar9300_init_rate_txpower_stbc(struct ath_hal * ah,const HAL_RATE_TABLE * rt,HAL_BOOL is40,int rt_ss_offset,int rt_ds_offset,int rt_ts_offset,u_int8_t chainmask)842 ar9300_init_rate_txpower_stbc(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
843 HAL_BOOL is40,
844 int rt_ss_offset, int rt_ds_offset,
845 int rt_ts_offset, u_int8_t chainmask)
846 {
847
848 struct ath_hal_9300 *ahp = AH9300(ah);
849 int i;
850 int16_t twice_array_gain, stbc_power = 0;
851 u_int8_t mcs_index = 0;
852
853 /* Upper Limit with STBC */
854 switch (chainmask) {
855 case OSPREY_1_CHAINMASK:
856 stbc_power = ahp->upper_limit[0];
857 break;
858 case OSPREY_2LOHI_CHAINMASK:
859 case OSPREY_2LOMID_CHAINMASK:
860 stbc_power = ahp->upper_limit[1];
861 break;
862 case OSPREY_3_CHAINMASK:
863 stbc_power = ahp->upper_limit[2];
864 /* Ony FCC requires that we back off with 3 transmit chains */
865 if (is_reg_dmn_fcc(ahp->reg_dmn)) {
866 twice_array_gain =
867 (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
868 -(AR9300_STBC_3TX_ARRAY_GAIN) :
869 ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
870 (ahp->twice_antenna_gain + AR9300_STBC_3TX_ARRAY_GAIN)), 0));
871 stbc_power = ahp->upper_limit[2] + twice_array_gain;
872 }
873 break;
874
875 default:
876 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
877 __func__, chainmask);
878 break;
879 }
880
881
882 for (i = rt_ss_offset; i < rt_ss_offset + AR9300_NUM_HT_SS_RATES; i++) {
883 switch (chainmask) {
884 case OSPREY_1_CHAINMASK:
885 ahp->txpower_stbc[i][0] = ahp->txpower[i][0];
886 break;
887 case OSPREY_2LOHI_CHAINMASK:
888 case OSPREY_2LOMID_CHAINMASK:
889 ahp->txpower_stbc[i][1] = ahp->txpower[i][1];
890 break;
891 case OSPREY_3_CHAINMASK:
892 ahp->txpower_stbc[i][2] = ahp->txpower[i][2];
893 /* 3 TX/1 stream STBC gain adjustment */
894 if (ahp->txpower_stbc[i][2] > stbc_power){
895 ahp->txpower_stbc[i][2] = stbc_power;
896 }
897 break;
898 default:
899 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
900 __func__, chainmask);
901 break;
902 }
903 mcs_index++;
904 }
905
906 for (i = rt_ds_offset; i < rt_ds_offset + AR9300_NUM_HT_DS_RATES; i++) {
907 switch (chainmask) {
908 case OSPREY_1_CHAINMASK:
909 ahp->txpower_stbc[i][0] = ahp->txpower[i][0];
910 break;
911 case OSPREY_2LOHI_CHAINMASK:
912 case OSPREY_2LOMID_CHAINMASK:
913 ahp->txpower_stbc[i][1] = ahp->txpower[i][1];
914 break;
915 case OSPREY_3_CHAINMASK:
916 ahp->txpower_stbc[i][2] = ahp->txpower[i][2];
917 /* 3 TX/2 stream STBC gain adjustment */
918 if (ahp->txpower_stbc[i][2] > stbc_power){
919 ahp->txpower_stbc[i][2] = stbc_power;
920 }
921 break;
922 default:
923 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
924 __func__, chainmask);
925 break;
926 }
927 mcs_index++;
928 }
929
930 for (i = rt_ts_offset; i < rt_ts_offset + AR9300_NUM_HT_TS_RATES; i++) {
931 switch (chainmask) {
932 case OSPREY_1_CHAINMASK:
933 ahp->txpower_stbc[i][0] = ahp->txpower[i][0];
934 break;
935 case OSPREY_2LOHI_CHAINMASK:
936 case OSPREY_2LOMID_CHAINMASK:
937 ahp->txpower_stbc[i][1] = ahp->txpower[i][1];
938 break;
939 case OSPREY_3_CHAINMASK:
940 ahp->txpower_stbc[i][2] = ahp->txpower[i][2];
941 break;
942 default:
943 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
944 __func__, chainmask);
945 break;
946 }
947 mcs_index++;
948 }
949
950 return;
951 }
952
953 /*
954 * To see why this is disabled, look at ar9300_eeprom.c for FCC/OET 13TR1003.
955 */
956 #if 0
957 static inline void
958 ar9300_adjust_rate_txpower_cdd(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
959 HAL_BOOL is40,
960 int rt_ss_offset, int rt_ds_offset,
961 int rt_ts_offset, u_int8_t chainmask)
962 {
963
964 struct ath_hal_9300 *ahp = AH9300(ah);
965 int i;
966 int16_t twice_array_gain, cdd_power = 0;
967 u_int8_t mcs_index = 0;
968
969 /*
970 * Adjust the upper limit for CDD factoring in the array gain .
971 * The array gain is the same as TxBF, hence reuse the same defines.
972 */
973 switch (chainmask) {
974 case OSPREY_1_CHAINMASK:
975 cdd_power = ahp->upper_limit[0];
976 break;
977
978 case OSPREY_2LOHI_CHAINMASK:
979 case OSPREY_2LOMID_CHAINMASK:
980 twice_array_gain =
981 (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
982 -(AR9300_TXBF_2TX_ARRAY_GAIN) :
983 ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
984 (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0));
985 cdd_power = ahp->upper_limit[1] + twice_array_gain;
986 break;
987
988 case OSPREY_3_CHAINMASK:
989 twice_array_gain =
990 (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
991 -(AR9300_TXBF_3TX_ARRAY_GAIN) :
992 ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
993 (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0));
994 cdd_power = ahp->upper_limit[2] + twice_array_gain;
995 break;
996
997 default:
998 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
999 __func__, chainmask);
1000 break;
1001 }
1002
1003
1004 for (i = rt_ss_offset; i < rt_ss_offset + AR9300_NUM_HT_SS_RATES; i++) {
1005 switch (chainmask) {
1006 case OSPREY_1_CHAINMASK:
1007 break;
1008
1009 case OSPREY_2LOHI_CHAINMASK:
1010 case OSPREY_2LOMID_CHAINMASK:
1011 /* 2 TX/1 stream CDD gain adjustment */
1012 if (ahp->txpower[i][1] > cdd_power){
1013 ahp->txpower[i][1] = cdd_power;
1014 }
1015 break;
1016 case OSPREY_3_CHAINMASK:
1017 /* 3 TX/1 stream CDD gain adjustment */
1018 if (ahp->txpower[i][2] > cdd_power){
1019 ahp->txpower[i][2] = cdd_power;
1020 }
1021 break;
1022 default:
1023 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
1024 __func__, chainmask);
1025 break;
1026 }
1027 mcs_index++;
1028 }
1029
1030 for (i = rt_ds_offset; i < rt_ds_offset + AR9300_NUM_HT_DS_RATES; i++) {
1031 switch (chainmask) {
1032 case OSPREY_1_CHAINMASK:
1033 case OSPREY_2LOHI_CHAINMASK:
1034 case OSPREY_2LOMID_CHAINMASK:
1035 break;
1036 case OSPREY_3_CHAINMASK:
1037 /* 3 TX/2 stream TxBF gain adjustment */
1038 if (ahp->txpower[i][2] > cdd_power){
1039 ahp->txpower[i][2] = cdd_power;
1040 }
1041 break;
1042 default:
1043 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
1044 __func__, chainmask);
1045 break;
1046 }
1047 mcs_index++;
1048 }
1049
1050 return;
1051
1052 }
1053 #endif
1054
ar9300_disp_tpc_tables(struct ath_hal * ah)1055 void ar9300_disp_tpc_tables(struct ath_hal *ah)
1056 {
1057 struct ath_hal_9300 *ahp = AH9300(ah);
1058 const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
1059 u_int mode = ath_hal_get_curmode(ah, chan);
1060 const HAL_RATE_TABLE *rt;
1061 int i, j;
1062
1063 /* Check whether TPC is enabled */
1064 if (!ah->ah_config.ath_hal_desc_tpc) {
1065 ath_hal_printf(ah, "\n TPC Register method in use\n");
1066 return;
1067 }
1068
1069 rt = ar9300_get_rate_table(ah, mode);
1070 HALASSERT(rt != NULL);
1071
1072 ath_hal_printf(ah, "\n===TARGET POWER TABLE===\n");
1073 for (j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) {
1074 for (i = 0; i < rt->rateCount; i++) {
1075 int16_t txpower[AR9300_MAX_CHAINS];
1076 txpower[j] = ahp->txpower[i][j];
1077 ath_hal_printf(ah, " Index[%2d] Rate[0x%02x] %6d kbps "
1078 "Power (%d Chain) [%2d.%1d dBm]\n",
1079 i, rt->info[i].rateCode, rt->info[i].rateKbps,
1080 j + 1, txpower[j] / 2, txpower[j]%2 * 5);
1081 }
1082 }
1083 ath_hal_printf(ah, "\n");
1084
1085 ath_hal_printf(ah, "\n\n===TARGET POWER TABLE with STBC===\n");
1086 for ( j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) {
1087 for (i = 0; i < rt->rateCount; i++) {
1088 int16_t txpower[AR9300_MAX_CHAINS];
1089 txpower[j] = ahp->txpower_stbc[i][j];
1090
1091 /* Do not display invalid configurations */
1092 if ((rt->info[i].rateCode < AR9300_MCS0_RATE_CODE) ||
1093 (rt->info[i].rateCode > AR9300_MCS23_RATE_CODE) ||
1094 ar9300_invalid_stbc_cfg(j, rt->info[i].rateCode) == AH_TRUE) {
1095 continue;
1096 }
1097
1098 ath_hal_printf(ah, " Index[%2d] Rate[0x%02x] %6d kbps "
1099 "Power (%d Chain) [%2d.%1d dBm]\n",
1100 i, rt->info[i].rateCode , rt->info[i].rateKbps,
1101 j + 1, txpower[j] / 2, txpower[j]%2 * 5);
1102 }
1103 }
1104 ath_hal_printf(ah, "\n");
1105 }
1106
1107 /*
1108 * The followings are customer specific APIs for querying power limit.
1109 * Power limit is based on regulatory domain, chipset, and transmission rate.
1110 * Here we only consider EEPROM values, no array gain/CTL considered here.
1111 */
1112
1113 struct rate_power_tbl {
1114 u_int8_t rateIdx; /* rate index in the rate table */
1115 u_int32_t rateKbps; /* transfer rate in kbs */
1116 u_int8_t rateCode; /* rate for h/w descriptors */
1117 u_int8_t txbf: 1, /* txbf eligible */
1118 stbc: 1, /* stbc eligible */
1119 chain1: 1, /* one-chain eligible */
1120 chain2: 1, /* two-chain eligible */
1121 chain3: 1; /* three-chain eligible */
1122 int16_t txpower[AR9300_MAX_CHAINS]; /* txpower for different chainmasks */
1123 int16_t txpower_stbc[AR9300_MAX_CHAINS];
1124 };
1125
ar9300_get_tpc_tables(struct ath_hal * ah)1126 u_int8_t *ar9300_get_tpc_tables(struct ath_hal *ah)
1127 {
1128 struct ath_hal_9300 *ahp = AH9300(ah);
1129 const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
1130 u_int mode = ath_hal_get_curmode(ah, chan);
1131 const HAL_RATE_TABLE *rt;
1132 u_int8_t *data;
1133 struct rate_power_tbl *table;
1134 int i, j;
1135
1136 /* Check whether TPC is enabled */
1137 if (! ah->ah_config.ath_hal_desc_tpc) {
1138 ath_hal_printf(ah, "\n TPC Register method in use\n");
1139 return NULL;
1140 }
1141
1142 rt = (const HAL_RATE_TABLE *)ar9300_get_rate_table(ah, mode);
1143 HALASSERT(rt != NULL);
1144
1145 data = (u_int8_t *)ath_hal_malloc(
1146 1 + rt->rateCount * sizeof(struct rate_power_tbl));
1147 if (data == NULL)
1148 return NULL;
1149
1150 OS_MEMZERO(data, 1 + rt->rateCount * sizeof(struct rate_power_tbl));
1151 /* store the rate count at the beginning */
1152 *data = rt->rateCount;
1153 table = (struct rate_power_tbl *)&data[1];
1154
1155 for (j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) {
1156 for (i = 0; i < rt->rateCount; i++) {
1157 table[i].rateIdx = i;
1158 table[i].rateCode = rt->info[i].rateCode;
1159 table[i].rateKbps = rt->info[i].rateKbps;
1160 switch (j) {
1161 case 0:
1162 table[i].chain1 = rt->info[i].rateCode <= 0x87 ? 1 : 0;
1163 break;
1164 case 1:
1165 table[i].chain2 = rt->info[i].rateCode <= 0x8f ? 1 : 0;
1166 break;
1167 case 2:
1168 table[i].chain3 = 1;
1169 break;
1170 default:
1171 break;
1172 }
1173 if ((j == 0 && table[i].chain1) ||
1174 (j == 1 && table[i].chain2) ||
1175 (j == 2 && table[i].chain3))
1176 table[i].txpower[j] = ahp->txpower[i][j];
1177 }
1178 }
1179
1180 for ( j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) {
1181 for (i = 0; i < rt->rateCount; i++) {
1182 /* Do not display invalid configurations */
1183 if ((rt->info[i].rateCode < AR9300_MCS0_RATE_CODE) ||
1184 (rt->info[i].rateCode > AR9300_MCS23_RATE_CODE) ||
1185 ar9300_invalid_stbc_cfg(j, rt->info[i].rateCode) == AH_TRUE) {
1186 continue;
1187 }
1188
1189 table[i].stbc = 1;
1190 table[i].txpower_stbc[j] = ahp->txpower_stbc[i][j];
1191 }
1192 }
1193
1194 return data;
1195 /* the caller is responsible to free data */
1196 }
1197
1198 HAL_STATUS
ath_hal_get_rate_power_limit_from_eeprom(struct ath_hal * ah,u_int16_t freq,int8_t * max_rate_power,int8_t * min_rate_power)1199 ath_hal_get_rate_power_limit_from_eeprom(struct ath_hal *ah, u_int16_t freq,
1200 int8_t *max_rate_power, int8_t *min_rate_power)
1201 {
1202 /*
1203 * Used for AR9300 series chip only
1204 */
1205 if (ah->ah_magic == AR9300_MAGIC) {
1206 u_int8_t target_rate_power_limit_val_t2[ar9300_rate_size];
1207 int i;
1208
1209 *max_rate_power = 0;
1210 *min_rate_power = AR9300_MAX_RATE_POWER;
1211
1212 ar9300_set_target_power_from_eeprom(ah, freq, target_rate_power_limit_val_t2);
1213
1214 for (i=0; i<ar9300_rate_size; i++) {
1215 if (target_rate_power_limit_val_t2[i] > *max_rate_power)
1216 *max_rate_power = target_rate_power_limit_val_t2[i];
1217 if (target_rate_power_limit_val_t2[i] < *min_rate_power)
1218 *min_rate_power = target_rate_power_limit_val_t2[i];
1219 }
1220 } else {
1221 *max_rate_power = 0;
1222 *min_rate_power = 0;
1223 }
1224
1225 return HAL_OK;
1226 }
1227