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 *
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
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
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
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
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
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
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
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
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 
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 
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
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