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