1250003Sadrian/* 2250003Sadrian * Copyright (c) 2013 Qualcomm Atheros, Inc. 3250003Sadrian * 4250003Sadrian * Permission to use, copy, modify, and/or distribute this software for any 5250003Sadrian * purpose with or without fee is hereby granted, provided that the above 6250003Sadrian * copyright notice and this permission notice appear in all copies. 7250003Sadrian * 8250003Sadrian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9250003Sadrian * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10250003Sadrian * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11250003Sadrian * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12250003Sadrian * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 13250003Sadrian * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14250003Sadrian * PERFORMANCE OF THIS SOFTWARE. 15250003Sadrian */ 16250003Sadrian 17250003Sadrian#include "opt_ah.h" 18250003Sadrian 19250003Sadrian#include "ah.h" 20250003Sadrian#include "ah_internal.h" 21250003Sadrian 22250003Sadrian#include "ar9300/ar9300.h" 23250003Sadrian 24250003Sadrian/* shorthands to compact tables for readability */ 25250003Sadrian#define OFDM IEEE80211_T_OFDM 26250003Sadrian#define CCK IEEE80211_T_CCK 27250003Sadrian#define TURBO IEEE80211_T_TURBO 28250003Sadrian#define XR ATHEROS_T_XR 29250003Sadrian#define HT IEEE80211_T_HT 30250003Sadrian 31250003Sadrian#define AR9300_NUM_OFDM_RATES 8 32250003Sadrian#define AR9300_NUM_HT_SS_RATES 8 33250003Sadrian#define AR9300_NUM_HT_DS_RATES 8 34250003Sadrian#define AR9300_NUM_HT_TS_RATES 8 35250003Sadrian 36250003Sadrian/* Array Gain defined for TxBF */ 37250003Sadrian#define AR9300_TXBF_2TX_ARRAY_GAIN 6 /* 2TX/SS 3 */ 38250003Sadrian#define AR9300_TXBF_3TX_ARRAY_GAIN 10 /* 3TX/SS or 3TX/DS 4.8 */ 39250003Sadrian#define AR9300_STBC_3TX_ARRAY_GAIN 10 /* 3TX/SS or 3TX/DS 4.8 */ 40250003Sadrian 41250003Sadrian/* MCS RATE CODES - first and last */ 42250003Sadrian#define AR9300_MCS0_RATE_CODE 0x80 43250003Sadrian#define AR9300_MCS23_RATE_CODE 0x97 44250003Sadrian 45250003Sadrianstatic inline void ar9300_init_rate_txpower_cck(struct ath_hal *ah, 46250003Sadrian const HAL_RATE_TABLE *rt, u_int8_t rates_array[], u_int8_t chainmask); 47250003Sadrianstatic inline void ar9300_init_rate_txpower_ofdm(struct ath_hal* ah, 48250003Sadrian const HAL_RATE_TABLE *rt, u_int8_t rates_array[], int rt_offset, 49250003Sadrian u_int8_t chainmask); 50250003Sadrianstatic inline void ar9300_init_rate_txpower_ht(struct ath_hal *ah, 51250003Sadrian const HAL_RATE_TABLE *rt, HAL_BOOL is40, u_int8_t rates_array[], 52250003Sadrian int rt_ss_offset, int rt_ds_offset, 53250003Sadrian int rt_ts_offset, u_int8_t chainmask); 54250003Sadrianstatic inline void ar9300_init_rate_txpower_stbc(struct ath_hal *ah, 55250003Sadrian const HAL_RATE_TABLE *rt, HAL_BOOL is40, 56250003Sadrian int rt_ss_offset, int rt_ds_offset, 57250003Sadrian int rt_ts_offset, u_int8_t chainmask); 58250003Sadrianstatic inline void ar9300_adjust_rate_txpower_cdd(struct ath_hal *ah, 59250003Sadrian const HAL_RATE_TABLE *rt, HAL_BOOL is40, 60250003Sadrian int rt_ss_offset, int rt_ds_offset, 61250003Sadrian int rt_ts_offset, u_int8_t chainmask); 62250003Sadrian 63250003Sadrian#define AR9300_11A_RT_OFDM_OFFSET 0 64250003SadrianHAL_RATE_TABLE ar9300_11a_table = { 65250003Sadrian 8, /* number of rates */ 66250003Sadrian { 0 }, 67250003Sadrian { 68250003Sadrian/* short ctrl */ 69250003Sadrian/* valid rate_code Preamble dot11Rate Rate */ 70250003Sadrian/* 6 Mb */ { AH_TRUE, OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0 }, 71250003Sadrian/* 9 Mb */ { AH_TRUE, OFDM, 9000, 0x0f, 0x00, 18, 0 }, 72250003Sadrian/* 12 Mb */ { AH_TRUE, OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2 }, 73250003Sadrian/* 18 Mb */ { AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 2 }, 74250003Sadrian/* 24 Mb */ { AH_TRUE, OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4 }, 75250003Sadrian/* 36 Mb */ { AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 4 }, 76250003Sadrian/* 48 Mb */ { AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 4 }, 77250003Sadrian/* 54 Mb */ { AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 4 }, 78250003Sadrian }, 79250003Sadrian}; 80250003Sadrian 81250003SadrianHAL_RATE_TABLE ar9300_11a_half_table = { 82250003Sadrian 8, /* number of rates */ 83250003Sadrian { 0 }, 84250003Sadrian { 85250003Sadrian/* short ctrl */ 86250003Sadrian/* valid rate_code Preamble dot11Rate Rate */ 87250003Sadrian/* 6 Mb */ { AH_TRUE, OFDM, 3000, 0x0b, 0x00, (0x80 | 6), 0 }, 88250003Sadrian/* 9 Mb */ { AH_TRUE, OFDM, 4500, 0x0f, 0x00, 9, 0 }, 89250003Sadrian/* 12 Mb */ { AH_TRUE, OFDM, 6000, 0x0a, 0x00, (0x80 | 12), 2 }, 90250003Sadrian/* 18 Mb */ { AH_TRUE, OFDM, 9000, 0x0e, 0x00, 18, 2 }, 91250003Sadrian/* 24 Mb */ { AH_TRUE, OFDM, 12000, 0x09, 0x00, (0x80 | 24), 4 }, 92250003Sadrian/* 36 Mb */ { AH_TRUE, OFDM, 18000, 0x0d, 0x00, 36, 4 }, 93250003Sadrian/* 48 Mb */ { AH_TRUE, OFDM, 24000, 0x08, 0x00, 48, 4 }, 94250003Sadrian/* 54 Mb */ { AH_TRUE, OFDM, 27000, 0x0c, 0x00, 54, 4 }, 95250003Sadrian }, 96250003Sadrian}; 97250003Sadrian 98250003SadrianHAL_RATE_TABLE ar9300_11a_quarter_table = { 99250003Sadrian 8, /* number of rates */ 100250003Sadrian { 0 }, 101250003Sadrian { 102250003Sadrian/* short ctrl */ 103250003Sadrian/* valid rate_code Preamble dot11Rate Rate */ 104250003Sadrian/* 6 Mb */ { AH_TRUE, OFDM, 1500, 0x0b, 0x00, (0x80 | 3), 0 }, 105250003Sadrian/* 9 Mb */ { AH_TRUE, OFDM, 2250, 0x0f, 0x00, 4 , 0 }, 106250003Sadrian/* 12 Mb */ { AH_TRUE, OFDM, 3000, 0x0a, 0x00, (0x80 | 6), 2 }, 107250003Sadrian/* 18 Mb */ { AH_TRUE, OFDM, 4500, 0x0e, 0x00, 9, 2 }, 108250003Sadrian/* 24 Mb */ { AH_TRUE, OFDM, 6000, 0x09, 0x00, (0x80 | 12), 4 }, 109250003Sadrian/* 36 Mb */ { AH_TRUE, OFDM, 9000, 0x0d, 0x00, 18, 4 }, 110250003Sadrian/* 48 Mb */ { AH_TRUE, OFDM, 12000, 0x08, 0x00, 24, 4 }, 111250003Sadrian/* 54 Mb */ { AH_TRUE, OFDM, 13500, 0x0c, 0x00, 27, 4 }, 112250003Sadrian }, 113250003Sadrian}; 114250003Sadrian 115250003SadrianHAL_RATE_TABLE ar9300_turbo_table = { 116250003Sadrian 8, /* number of rates */ 117250003Sadrian { 0 }, 118250003Sadrian { 119250003Sadrian/* short ctrl */ 120250003Sadrian/* valid rate_code Preamble dot11Rate Rate */ 121250003Sadrian/* 6 Mb */ { AH_TRUE, TURBO, 6000, 0x0b, 0x00, (0x80 | 12), 0 }, 122250003Sadrian/* 9 Mb */ { AH_TRUE, TURBO, 9000, 0x0f, 0x00, 18, 0 }, 123250003Sadrian/* 12 Mb */ { AH_TRUE, TURBO, 12000, 0x0a, 0x00, (0x80 | 24), 2 }, 124250003Sadrian/* 18 Mb */ { AH_TRUE, TURBO, 18000, 0x0e, 0x00, 36, 2 }, 125250003Sadrian/* 24 Mb */ { AH_TRUE, TURBO, 24000, 0x09, 0x00, (0x80 | 48), 4 }, 126250003Sadrian/* 36 Mb */ { AH_TRUE, TURBO, 36000, 0x0d, 0x00, 72, 4 }, 127250003Sadrian/* 48 Mb */ { AH_TRUE, TURBO, 48000, 0x08, 0x00, 96, 4 }, 128250003Sadrian/* 54 Mb */ { AH_TRUE, TURBO, 54000, 0x0c, 0x00, 108, 4 }, 129250003Sadrian }, 130250003Sadrian}; 131250003Sadrian 132250003SadrianHAL_RATE_TABLE ar9300_11b_table = { 133250003Sadrian 4, /* number of rates */ 134250003Sadrian { 0 }, 135250003Sadrian { 136250003Sadrian/* short ctrl */ 137250003Sadrian/* valid rate_code Preamble dot11Rate Rate */ 138250003Sadrian/* 1 Mb */ { AH_TRUE, CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0 }, 139250003Sadrian/* 2 Mb */ { AH_TRUE, CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1 }, 140250003Sadrian/* 5.5 Mb */ { AH_TRUE, CCK, 5500, 0x19, 0x04, (0x80 | 11), 1 }, 141250003Sadrian/* 11 Mb */ { AH_TRUE, CCK, 11000, 0x18, 0x04, (0x80 | 22), 1 }, 142250003Sadrian }, 143250003Sadrian}; 144250003Sadrian 145250003Sadrian 146250003Sadrian/* Venice TODO: round_up_rate() is broken when the rate table does not represent 147250003Sadrian * rates in increasing order e.g. 5.5, 11, 6, 9. 148250003Sadrian * An average rate of 6 Mbps will currently map to 11 Mbps. 149250003Sadrian */ 150250003Sadrian#define AR9300_11G_RT_OFDM_OFFSET 4 151250003SadrianHAL_RATE_TABLE ar9300_11g_table = { 152250003Sadrian 12, /* number of rates */ 153250003Sadrian { 0 }, 154250003Sadrian { 155250003Sadrian/* short ctrl */ 156250003Sadrian/* valid rate_code Preamble dot11Rate Rate */ 157250003Sadrian/* 1 Mb */ { AH_TRUE, CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0 }, 158250003Sadrian/* 2 Mb */ { AH_TRUE, CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1 }, 159250003Sadrian/* 5.5 Mb */ { AH_TRUE, CCK, 5500, 0x19, 0x04, (0x80 | 11), 2 }, 160250003Sadrian/* 11 Mb */ { AH_TRUE, CCK, 11000, 0x18, 0x04, (0x80 | 22), 3 }, 161250003Sadrian/* Hardware workaround - remove rates 6, 9 from rate ctrl */ 162250008Sadrian/* 6 Mb */ { AH_TRUE, OFDM, 6000, 0x0b, 0x00, 12, 4 }, 163250008Sadrian/* 9 Mb */ { AH_TRUE, OFDM, 9000, 0x0f, 0x00, 18, 4 }, 164250003Sadrian/* 12 Mb */ { AH_TRUE, OFDM, 12000, 0x0a, 0x00, 24, 6 }, 165250003Sadrian/* 18 Mb */ { AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 6 }, 166250003Sadrian/* 24 Mb */ { AH_TRUE, OFDM, 24000, 0x09, 0x00, 48, 8 }, 167250003Sadrian/* 36 Mb */ { AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 8 }, 168250003Sadrian/* 48 Mb */ { AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 8 }, 169250003Sadrian/* 54 Mb */ { AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 8 }, 170250003Sadrian }, 171250003Sadrian}; 172250003Sadrian 173250008Sadrian#if 0 174250003SadrianHAL_RATE_TABLE ar9300_xr_table = { 175250003Sadrian 13, /* number of rates */ 176250003Sadrian { 0 }, 177250003Sadrian { 178250003Sadrian/* short ctrl */ 179250003Sadrian/* valid rate_code Preamble dot11Rate Rate */ 180250003Sadrian/* 0.25 Mb */ {AH_TRUE, XR, 250, 0x03, 0x00, (0x80 | 1), 0, 612, 612 }, 181250003Sadrian/* 0.5 Mb */ {AH_TRUE, XR, 500, 0x07, 0x00, (0x80 | 1), 0, 457, 457 }, 182250003Sadrian/* 1 Mb */ {AH_TRUE, XR, 1000, 0x02, 0x00, (0x80 | 2), 1, 228, 228 }, 183250003Sadrian/* 2 Mb */ {AH_TRUE, XR, 2000, 0x06, 0x00, (0x80 | 4), 2, 160, 160 }, 184250003Sadrian/* 3 Mb */ {AH_TRUE, XR, 3000, 0x01, 0x00, (0x80 | 6), 3, 140, 140 }, 185250003Sadrian/* 6 Mb */ {AH_TRUE, OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 4, 60, 60 }, 186250003Sadrian/* 9 Mb */ {AH_TRUE, OFDM, 9000, 0x0f, 0x00, 18, 4, 60, 60 }, 187250003Sadrian/* 12 Mb */ {AH_TRUE, OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 6, 48, 48 }, 188250003Sadrian/* 18 Mb */ {AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 6, 48, 48 }, 189250003Sadrian/* 24 Mb */ {AH_TRUE, OFDM, 24000, 0x09, 0x00, 48, 8, 44, 44 }, 190250003Sadrian/* 36 Mb */ {AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 8, 44, 44 }, 191250003Sadrian/* 48 Mb */ {AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 8, 44, 44 }, 192250003Sadrian/* 54 Mb */ {AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 8, 44, 44 }, 193250003Sadrian }, 194250003Sadrian}; 195250008Sadrian#endif 196250003Sadrian 197250003Sadrian#define AR9300_11NG_RT_OFDM_OFFSET 4 198250003Sadrian#define AR9300_11NG_RT_HT_SS_OFFSET 12 199250003Sadrian#define AR9300_11NG_RT_HT_DS_OFFSET 20 200250003Sadrian#define AR9300_11NG_RT_HT_TS_OFFSET 28 201250003SadrianHAL_RATE_TABLE ar9300_11ng_table = { 202250003Sadrian 203250003Sadrian 36, /* number of rates */ 204250003Sadrian { 0 }, 205250003Sadrian { 206250003Sadrian/* short ctrl */ 207250003Sadrian/* valid rate_code Preamble dot11Rate Rate */ 208250003Sadrian/* 1 Mb */ { AH_TRUE, CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0 }, 209250003Sadrian/* 2 Mb */ { AH_TRUE, CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1 }, 210250003Sadrian/* 5.5 Mb */ { AH_TRUE, CCK, 5500, 0x19, 0x04, (0x80 | 11), 2 }, 211250003Sadrian/* 11 Mb */ { AH_TRUE, CCK, 11000, 0x18, 0x04, (0x80 | 22), 3 }, 212250003Sadrian/* Hardware workaround - remove rates 6, 9 from rate ctrl */ 213250008Sadrian/* 6 Mb */ { AH_FALSE, OFDM, 6000, 0x0b, 0x00, 12, 4 }, 214250008Sadrian/* 9 Mb */ { AH_FALSE, OFDM, 9000, 0x0f, 0x00, 18, 4 }, 215250003Sadrian/* 12 Mb */ { AH_TRUE, OFDM, 12000, 0x0a, 0x00, 24, 6 }, 216250003Sadrian/* 18 Mb */ { AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 6 }, 217250003Sadrian/* 24 Mb */ { AH_TRUE, OFDM, 24000, 0x09, 0x00, 48, 8 }, 218250003Sadrian/* 36 Mb */ { AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 8 }, 219250003Sadrian/* 48 Mb */ { AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 8 }, 220250003Sadrian/* 54 Mb */ { AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 8 }, 221250003Sadrian/*--- HT SS rates ---*/ 222250003Sadrian/* 6.5 Mb */ { AH_TRUE, HT, 6500, 0x80, 0x00, 0, 4 }, 223250003Sadrian/* 13 Mb */ { AH_TRUE, HT, 13000, 0x81, 0x00, 1, 6 }, 224250003Sadrian/*19.5 Mb */ { AH_TRUE, HT, 19500, 0x82, 0x00, 2, 6 }, 225250003Sadrian/* 26 Mb */ { AH_TRUE, HT, 26000, 0x83, 0x00, 3, 8 }, 226250003Sadrian/* 39 Mb */ { AH_TRUE, HT, 39000, 0x84, 0x00, 4, 8 }, 227250003Sadrian/* 52 Mb */ { AH_TRUE, HT, 52000, 0x85, 0x00, 5, 8 }, 228250003Sadrian/*58.5 Mb */ { AH_TRUE, HT, 58500, 0x86, 0x00, 6, 8 }, 229250003Sadrian/* 65 Mb */ { AH_TRUE, HT, 65000, 0x87, 0x00, 7, 8 }, 230250003Sadrian/*--- HT DS rates ---*/ 231250003Sadrian/* 13 Mb */ { AH_TRUE, HT, 13000, 0x88, 0x00, 8, 4 }, 232250003Sadrian/* 26 Mb */ { AH_TRUE, HT, 26000, 0x89, 0x00, 9, 6 }, 233250003Sadrian/* 39 Mb */ { AH_TRUE, HT, 39000, 0x8a, 0x00, 10, 6 }, 234250003Sadrian/* 52 Mb */ { AH_TRUE, HT, 52000, 0x8b, 0x00, 11, 8 }, 235250003Sadrian/* 78 Mb */ { AH_TRUE, HT, 78000, 0x8c, 0x00, 12, 8 }, 236250003Sadrian/* 104 Mb */ { AH_TRUE, HT, 104000, 0x8d, 0x00, 13, 8 }, 237250003Sadrian/* 117 Mb */ { AH_TRUE, HT, 117000, 0x8e, 0x00, 14, 8 }, 238250003Sadrian/* 130 Mb */ { AH_TRUE, HT, 130000, 0x8f, 0x00, 15, 8 }, 239250003Sadrian/*--- HT TS rates ---*/ 240250003Sadrian/*19.5 Mb */ { AH_TRUE, HT, 19500, 0x90, 0x00, 16, 4 }, 241250003Sadrian/* 39 Mb */ { AH_TRUE, HT, 39000, 0x91, 0x00, 17, 6 }, 242250003Sadrian/*58.5 Mb */ { AH_TRUE, HT, 58500, 0x92, 0x00, 18, 6 }, 243250003Sadrian/* 78 Mb */ { AH_TRUE, HT, 78000, 0x93, 0x00, 19, 8 }, 244250003Sadrian/* 117 Mb */ { AH_TRUE, HT, 117000, 0x94, 0x00, 20, 8 }, 245250003Sadrian/* 156 Mb */ { AH_TRUE, HT, 156000, 0x95, 0x00, 21, 8 }, 246250003Sadrian/*175.5Mb */ { AH_TRUE, HT, 175500, 0x96, 0x00, 22, 8 }, 247250003Sadrian/* 195 Mb */ { AH_TRUE, HT, 195000, 0x97, 0x00, 23, 8 }, 248250003Sadrian }, 249250003Sadrian}; 250250003Sadrian 251250003Sadrian#define AR9300_11NA_RT_OFDM_OFFSET 0 252250003Sadrian#define AR9300_11NA_RT_HT_SS_OFFSET 8 253250003Sadrian#define AR9300_11NA_RT_HT_DS_OFFSET 16 254250003Sadrian#define AR9300_11NA_RT_HT_TS_OFFSET 24 255250003Sadrianstatic HAL_RATE_TABLE ar9300_11na_table = { 256250003Sadrian 257250003Sadrian 32, /* number of rates */ 258250003Sadrian { 0 }, 259250003Sadrian { 260250003Sadrian/* short ctrl */ 261250003Sadrian/* valid rate_code Preamble dot11Rate Rate */ 262250003Sadrian/* 6 Mb */ { AH_TRUE, OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0 }, 263250003Sadrian/* 9 Mb */ { AH_TRUE, OFDM, 9000, 0x0f, 0x00, 18, 0 }, 264250003Sadrian/* 12 Mb */ { AH_TRUE, OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2 }, 265250003Sadrian/* 18 Mb */ { AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 2 }, 266250003Sadrian/* 24 Mb */ { AH_TRUE, OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4 }, 267250003Sadrian/* 36 Mb */ { AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 4 }, 268250003Sadrian/* 48 Mb */ { AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 4 }, 269250003Sadrian/* 54 Mb */ { AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 4 }, 270250003Sadrian/*--- HT SS rates ---*/ 271250003Sadrian/* 6.5 Mb */ { AH_TRUE, HT, 6500, 0x80, 0x00, 0, 0 }, 272250003Sadrian/* 13 Mb */ { AH_TRUE, HT, 13000, 0x81, 0x00, 1, 2 }, 273250003Sadrian/*19.5 Mb */ { AH_TRUE, HT, 19500, 0x82, 0x00, 2, 2 }, 274250003Sadrian/* 26 Mb */ { AH_TRUE, HT, 26000, 0x83, 0x00, 3, 4 }, 275250003Sadrian/* 39 Mb */ { AH_TRUE, HT, 39000, 0x84, 0x00, 4, 4 }, 276250003Sadrian/* 52 Mb */ { AH_TRUE, HT, 52000, 0x85, 0x00, 5, 4 }, 277250003Sadrian/*58.5 Mb */ { AH_TRUE, HT, 58500, 0x86, 0x00, 6, 4 }, 278250003Sadrian/* 65 Mb */ { AH_TRUE, HT, 65000, 0x87, 0x00, 7, 4 }, 279250003Sadrian/*--- HT DS rates ---*/ 280250003Sadrian/* 13 Mb */ { AH_TRUE, HT, 13000, 0x88, 0x00, 8, 0 }, 281250003Sadrian/* 26 Mb */ { AH_TRUE, HT, 26000, 0x89, 0x00, 9, 2 }, 282250003Sadrian/* 39 Mb */ { AH_TRUE, HT, 39000, 0x8a, 0x00, 10, 2 }, 283250003Sadrian/* 52 Mb */ { AH_TRUE, HT, 52000, 0x8b, 0x00, 11, 4 }, 284250003Sadrian/* 78 Mb */ { AH_TRUE, HT, 78000, 0x8c, 0x00, 12, 4 }, 285250003Sadrian/* 104 Mb */ { AH_TRUE, HT, 104000, 0x8d, 0x00, 13, 4 }, 286250003Sadrian/* 117 Mb */ { AH_TRUE, HT, 117000, 0x8e, 0x00, 14, 4 }, 287250003Sadrian/* 130 Mb */ { AH_TRUE, HT, 130000, 0x8f, 0x00, 15, 4 }, 288250003Sadrian/*--- HT TS rates ---*/ 289250003Sadrian/*19.5 Mb */ { AH_TRUE, HT, 19500, 0x90, 0x00, 16, 0 }, 290250003Sadrian/* 39 Mb */ { AH_TRUE, HT, 39000, 0x91, 0x00, 17, 2 }, 291250003Sadrian/*58.5 Mb */ { AH_TRUE, HT, 58500, 0x92, 0x00, 18, 2 }, 292250003Sadrian/* 78 Mb */ { AH_TRUE, HT, 78000, 0x93, 0x00, 19, 4 }, 293250003Sadrian/* 117 Mb */ { AH_TRUE, HT, 117000, 0x94, 0x00, 20, 4 }, 294250003Sadrian/* 156 Mb */ { AH_TRUE, HT, 156000, 0x95, 0x00, 21, 4 }, 295250003Sadrian/*175.5Mb */ { AH_TRUE, HT, 175500, 0x96, 0x00, 22, 4 }, 296250003Sadrian/* 195 Mb */ { AH_TRUE, HT, 195000, 0x97, 0x00, 23, 4 }, 297250003Sadrian }, 298250003Sadrian}; 299250003Sadrian 300250003Sadrian#undef OFDM 301250003Sadrian#undef CCK 302250003Sadrian#undef TURBO 303250003Sadrian#undef XR 304250003Sadrian#undef HT 305250003Sadrian#undef HT_HGI 306250003Sadrian 307250003Sadrianconst HAL_RATE_TABLE * 308250003Sadrianar9300_get_rate_table(struct ath_hal *ah, u_int mode) 309250003Sadrian{ 310250003Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 311250003Sadrian HAL_CAPABILITIES *p_cap = &ahpriv->ah_caps; 312250003Sadrian HAL_RATE_TABLE *rt; 313250003Sadrian 314250003Sadrian switch (mode) { 315250003Sadrian case HAL_MODE_11A: 316250003Sadrian rt = &ar9300_11a_table; 317250003Sadrian break; 318250003Sadrian case HAL_MODE_11A_HALF_RATE: 319250008Sadrian if (p_cap->halChanHalfRate) { 320250003Sadrian rt = &ar9300_11a_half_table; 321250003Sadrian break; 322250003Sadrian } 323250003Sadrian return AH_NULL; 324250003Sadrian case HAL_MODE_11A_QUARTER_RATE: 325250008Sadrian if (p_cap->halChanQuarterRate) { 326250003Sadrian rt = &ar9300_11a_quarter_table; 327250003Sadrian break; 328250003Sadrian } 329250003Sadrian return AH_NULL; 330250003Sadrian case HAL_MODE_11B: 331250003Sadrian rt = &ar9300_11b_table; 332250003Sadrian break; 333250003Sadrian case HAL_MODE_11G: 334250003Sadrian rt = &ar9300_11g_table; 335250003Sadrian break; 336250003Sadrian case HAL_MODE_TURBO: 337250003Sadrian case HAL_MODE_108G: 338250003Sadrian rt = &ar9300_turbo_table; 339250003Sadrian break; 340250008Sadrian#if 0 341250003Sadrian case HAL_MODE_XR: 342250003Sadrian rt = &ar9300_xr_table; 343250003Sadrian break; 344250008Sadrian#endif 345250003Sadrian case HAL_MODE_11NG_HT20: 346250003Sadrian case HAL_MODE_11NG_HT40PLUS: 347250003Sadrian case HAL_MODE_11NG_HT40MINUS: 348250003Sadrian rt = &ar9300_11ng_table; 349250003Sadrian break; 350250003Sadrian case HAL_MODE_11NA_HT20: 351250003Sadrian case HAL_MODE_11NA_HT40PLUS: 352250003Sadrian case HAL_MODE_11NA_HT40MINUS: 353250003Sadrian rt = &ar9300_11na_table; 354250003Sadrian break; 355250003Sadrian default: 356250003Sadrian HALDEBUG(ah, HAL_DEBUG_CHANNEL, 357250003Sadrian "%s: invalid mode 0x%x\n", __func__, mode); 358250003Sadrian return AH_NULL; 359250003Sadrian } 360250003Sadrian ath_hal_setupratetable(ah, rt); 361250003Sadrian return rt; 362250003Sadrian} 363250003Sadrian 364250003Sadrianstatic HAL_BOOL 365250003Sadrianar9300_invalid_stbc_cfg(int tx_chains, u_int8_t rate_code) 366250003Sadrian{ 367250003Sadrian switch (tx_chains) { 368250003Sadrian case 0: /* Single Chain */ 369250003Sadrian return AH_TRUE; 370250003Sadrian 371250003Sadrian case 1: /* 2 Chains */ 372250003Sadrian if ((rate_code < 0x80) || (rate_code > 0x87)) { 373250003Sadrian return AH_TRUE; 374250003Sadrian } else { 375250003Sadrian return AH_FALSE; 376250003Sadrian } 377250003Sadrian 378250003Sadrian case 2: /* 3 Chains */ 379250003Sadrian if ((rate_code < 0x80) || (rate_code > 0x87)) { 380250003Sadrian return AH_TRUE; 381250003Sadrian } else { 382250003Sadrian return AH_FALSE; 383250003Sadrian } 384250003Sadrian 385250003Sadrian default: 386250003Sadrian HALASSERT(0); 387250003Sadrian break; 388250003Sadrian } 389250003Sadrian 390250003Sadrian return AH_TRUE; 391250003Sadrian} 392250003Sadrian 393250003Sadrianint16_t 394250003Sadrianar9300_get_rate_txpower(struct ath_hal *ah, u_int mode, u_int8_t rate_index, 395250003Sadrian u_int8_t chainmask, u_int8_t xmit_mode) 396250003Sadrian{ 397250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 398250003Sadrian int num_chains = ar9300_get_ntxchains(chainmask); 399250003Sadrian 400250003Sadrian switch (xmit_mode) { 401250003Sadrian case AR9300_DEF_MODE: 402250003Sadrian return ahp->txpower[rate_index][num_chains-1]; 403250003Sadrian 404250003Sadrian 405250003Sadrian case AR9300_STBC_MODE: 406250003Sadrian return ahp->txpower_stbc[rate_index][num_chains-1]; 407250003Sadrian 408250003Sadrian default: 409250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid mode 0x%x\n", 410250003Sadrian __func__, xmit_mode); 411250003Sadrian HALASSERT(0); 412250003Sadrian break; 413250003Sadrian } 414250003Sadrian 415250003Sadrian return ahp->txpower[rate_index][num_chains-1]; 416250003Sadrian} 417250003Sadrian 418250003Sadrianextern void 419250003Sadrianar9300_adjust_reg_txpower_cdd(struct ath_hal *ah, 420250003Sadrian u_int8_t power_per_rate[]) 421250003Sadrian 422250003Sadrian{ 423250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 424250003Sadrian int16_t twice_array_gain, cdd_power = 0; 425250003Sadrian int i; 426250003Sadrian 427250003Sadrian /* 428250003Sadrian * Adjust the upper limit for CDD factoring in the array gain . 429250003Sadrian * The array gain is the same as TxBF, hence reuse the same defines. 430250003Sadrian */ 431250003Sadrian switch (ahp->ah_tx_chainmask) { 432250003Sadrian 433250003Sadrian case OSPREY_1_CHAINMASK: 434250003Sadrian cdd_power = ahp->upper_limit[0]; 435250003Sadrian break; 436250003Sadrian 437250003Sadrian case OSPREY_2LOHI_CHAINMASK: 438250003Sadrian case OSPREY_2LOMID_CHAINMASK: 439250003Sadrian twice_array_gain = 440250003Sadrian (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)? 441250003Sadrian -(AR9300_TXBF_2TX_ARRAY_GAIN) : 442250003Sadrian ((int16_t)AH_MIN((ahp->twice_antenna_reduction - 443250003Sadrian (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0)); 444250003Sadrian cdd_power = ahp->upper_limit[1] + twice_array_gain; 445250003Sadrian /* Adjust OFDM legacy rates as well */ 446250003Sadrian for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) { 447250003Sadrian if (power_per_rate[i] > cdd_power) { 448250003Sadrian power_per_rate[i] = cdd_power; 449250003Sadrian } 450250003Sadrian } 451250003Sadrian 452250003Sadrian /* 2Tx/(n-1) stream Adjust rates MCS0 through MCS 7 HT 20*/ 453250003Sadrian for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_7; i++) { 454250003Sadrian if (power_per_rate[i] > cdd_power) { 455250003Sadrian power_per_rate[i] = cdd_power; 456250003Sadrian } 457250003Sadrian } 458250003Sadrian 459250003Sadrian /* 2Tx/(n-1) stream Adjust rates MCS0 through MCS 7 HT 40*/ 460250003Sadrian for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_7; i++) { 461250003Sadrian if (power_per_rate[i] > cdd_power) { 462250003Sadrian power_per_rate[i] = cdd_power; 463250003Sadrian } 464250003Sadrian } 465250003Sadrian break; 466250003Sadrian 467250003Sadrian case OSPREY_3_CHAINMASK: 468250003Sadrian twice_array_gain = 469250003Sadrian (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)? 470250003Sadrian -(AR9300_TXBF_3TX_ARRAY_GAIN) : 471250003Sadrian ((int16_t)AH_MIN((ahp->twice_antenna_reduction - 472250003Sadrian (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0)); 473250003Sadrian cdd_power = ahp->upper_limit[2] + twice_array_gain; 474250003Sadrian /* Adjust OFDM legacy rates as well */ 475250003Sadrian for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) { 476250003Sadrian if (power_per_rate[i] > cdd_power) { 477250003Sadrian power_per_rate[i] = cdd_power; 478250003Sadrian } 479250003Sadrian } 480250003Sadrian /* 3Tx/(n-1)streams Adjust rates MCS0 through MCS 15 HT20 */ 481250003Sadrian for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_15; i++) { 482250003Sadrian if (power_per_rate[i] > cdd_power) { 483250003Sadrian power_per_rate[i] = cdd_power; 484250003Sadrian } 485250003Sadrian } 486250003Sadrian 487250003Sadrian /* 3Tx/(n-1)streams Adjust rates MCS0 through MCS 15 HT40 */ 488250003Sadrian for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_15; i++) { 489250003Sadrian if (power_per_rate[i] > cdd_power) { 490250003Sadrian power_per_rate[i] = cdd_power; 491250003Sadrian } 492250003Sadrian } 493250003Sadrian 494250003Sadrian break; 495250003Sadrian 496250003Sadrian default: 497250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n", 498250003Sadrian __func__, ahp->ah_tx_chainmask); 499250003Sadrian break; 500250003Sadrian } 501250003Sadrian 502250003Sadrian return; 503250003Sadrian} 504250003Sadrian 505250003Sadrianextern void 506250003Sadrianar9300_init_rate_txpower(struct ath_hal *ah, u_int mode, 507250008Sadrian const struct ieee80211_channel *chan, 508250003Sadrian u_int8_t power_per_rate[], u_int8_t chainmask) 509250003Sadrian{ 510250003Sadrian const HAL_RATE_TABLE *rt; 511250008Sadrian HAL_BOOL is40 = IEEE80211_IS_CHAN_HT40(chan); 512250003Sadrian 513250003Sadrian rt = ar9300_get_rate_table(ah, mode); 514250003Sadrian HALASSERT(rt != NULL); 515250003Sadrian 516250003Sadrian switch (mode) { 517250003Sadrian case HAL_MODE_11A: 518250003Sadrian ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate, 519250003Sadrian AR9300_11A_RT_OFDM_OFFSET, chainmask); 520250003Sadrian break; 521250003Sadrian case HAL_MODE_11NA_HT20: 522250003Sadrian case HAL_MODE_11NA_HT40PLUS: 523250003Sadrian case HAL_MODE_11NA_HT40MINUS: 524250003Sadrian ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate, 525250003Sadrian AR9300_11NA_RT_OFDM_OFFSET, chainmask); 526250003Sadrian ar9300_init_rate_txpower_ht(ah, rt, is40, power_per_rate, 527250003Sadrian AR9300_11NA_RT_HT_SS_OFFSET, 528250003Sadrian AR9300_11NA_RT_HT_DS_OFFSET, 529250003Sadrian AR9300_11NA_RT_HT_TS_OFFSET, chainmask); 530250003Sadrian ar9300_init_rate_txpower_stbc(ah, rt, is40, 531250003Sadrian AR9300_11NA_RT_HT_SS_OFFSET, 532250003Sadrian AR9300_11NA_RT_HT_DS_OFFSET, 533250003Sadrian AR9300_11NA_RT_HT_TS_OFFSET, chainmask); 534250003Sadrian /* For FCC the array gain has to be factored for CDD mode */ 535250008Sadrian if (is_reg_dmn_fcc(ath_hal_getctl(ah, chan))) { 536250003Sadrian ar9300_adjust_rate_txpower_cdd(ah, rt, is40, 537250003Sadrian AR9300_11NA_RT_HT_SS_OFFSET, 538250003Sadrian AR9300_11NA_RT_HT_DS_OFFSET, 539250003Sadrian AR9300_11NA_RT_HT_TS_OFFSET, chainmask); 540250003Sadrian } 541250003Sadrian break; 542250003Sadrian case HAL_MODE_11G: 543250003Sadrian ar9300_init_rate_txpower_cck(ah, rt, power_per_rate, chainmask); 544250003Sadrian ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate, 545250003Sadrian AR9300_11G_RT_OFDM_OFFSET, chainmask); 546250003Sadrian break; 547250003Sadrian case HAL_MODE_11B: 548250003Sadrian ar9300_init_rate_txpower_cck(ah, rt, power_per_rate, chainmask); 549250003Sadrian break; 550250003Sadrian case HAL_MODE_11NG_HT20: 551250003Sadrian case HAL_MODE_11NG_HT40PLUS: 552250003Sadrian case HAL_MODE_11NG_HT40MINUS: 553250003Sadrian ar9300_init_rate_txpower_cck(ah, rt, power_per_rate, chainmask); 554250003Sadrian ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate, 555250003Sadrian AR9300_11NG_RT_OFDM_OFFSET, chainmask); 556250003Sadrian ar9300_init_rate_txpower_ht(ah, rt, is40, power_per_rate, 557250003Sadrian AR9300_11NG_RT_HT_SS_OFFSET, 558250003Sadrian AR9300_11NG_RT_HT_DS_OFFSET, 559250003Sadrian AR9300_11NG_RT_HT_TS_OFFSET, chainmask); 560250003Sadrian ar9300_init_rate_txpower_stbc(ah, rt, is40, 561250003Sadrian AR9300_11NG_RT_HT_SS_OFFSET, 562250003Sadrian AR9300_11NG_RT_HT_DS_OFFSET, 563250003Sadrian AR9300_11NG_RT_HT_TS_OFFSET, chainmask); 564250003Sadrian /* For FCC the array gain needs to be factored for CDD mode */ 565250008Sadrian if (is_reg_dmn_fcc(ath_hal_getctl(ah, chan))) { 566250003Sadrian ar9300_adjust_rate_txpower_cdd(ah, rt, is40, 567250003Sadrian AR9300_11NG_RT_HT_SS_OFFSET, 568250003Sadrian AR9300_11NG_RT_HT_DS_OFFSET, 569250003Sadrian AR9300_11NG_RT_HT_TS_OFFSET, chainmask); 570250003Sadrian } 571250003Sadrian break; 572250003Sadrian default: 573250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid mode 0x%x\n", 574250003Sadrian __func__, mode); 575250003Sadrian HALASSERT(0); 576250003Sadrian break; 577250003Sadrian } 578250003Sadrian 579250003Sadrian} 580250003Sadrian 581250003Sadrianstatic inline void 582250003Sadrianar9300_init_rate_txpower_cck(struct ath_hal *ah, const HAL_RATE_TABLE *rt, 583250003Sadrian u_int8_t rates_array[], u_int8_t chainmask) 584250003Sadrian{ 585250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 586250003Sadrian /* 587250003Sadrian * Pick the lower of the long-preamble txpower, and short-preamble tx power. 588250003Sadrian * Unfortunately, the rate table doesn't have separate entries for these!. 589250003Sadrian */ 590250003Sadrian switch (chainmask) { 591250003Sadrian case OSPREY_1_CHAINMASK: 592250003Sadrian ahp->txpower[0][0] = rates_array[ALL_TARGET_LEGACY_1L_5L]; 593250003Sadrian ahp->txpower[1][0] = rates_array[ALL_TARGET_LEGACY_1L_5L]; 594250003Sadrian ahp->txpower[2][0] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L], 595250003Sadrian rates_array[ALL_TARGET_LEGACY_5S]); 596250003Sadrian ahp->txpower[3][0] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L], 597250003Sadrian rates_array[ALL_TARGET_LEGACY_11S]); 598250003Sadrian break; 599250003Sadrian case OSPREY_2LOHI_CHAINMASK: 600250003Sadrian case OSPREY_2LOMID_CHAINMASK: 601250003Sadrian ahp->txpower[0][1] = rates_array[ALL_TARGET_LEGACY_1L_5L]; 602250003Sadrian ahp->txpower[1][1] = rates_array[ALL_TARGET_LEGACY_1L_5L]; 603250003Sadrian ahp->txpower[2][1] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L], 604250003Sadrian rates_array[ALL_TARGET_LEGACY_5S]); 605250003Sadrian ahp->txpower[3][1] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L], 606250003Sadrian rates_array[ALL_TARGET_LEGACY_11S]); 607250003Sadrian break; 608250003Sadrian case OSPREY_3_CHAINMASK: 609250003Sadrian ahp->txpower[0][2] = rates_array[ALL_TARGET_LEGACY_1L_5L]; 610250003Sadrian ahp->txpower[1][2] = rates_array[ALL_TARGET_LEGACY_1L_5L]; 611250003Sadrian ahp->txpower[2][2] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L], 612250003Sadrian rates_array[ALL_TARGET_LEGACY_5S]); 613250003Sadrian ahp->txpower[3][2] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L], 614250003Sadrian rates_array[ALL_TARGET_LEGACY_11S]); 615250003Sadrian break; 616250003Sadrian default: 617250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n", 618250003Sadrian __func__, chainmask); 619250003Sadrian break; 620250003Sadrian } 621250003Sadrian} 622250003Sadrian 623250003Sadrianstatic inline void 624250003Sadrianar9300_init_rate_txpower_ofdm(struct ath_hal *ah, const HAL_RATE_TABLE *rt, 625250003Sadrian u_int8_t rates_array[], int rt_offset, 626250003Sadrian u_int8_t chainmask) 627250003Sadrian{ 628250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 629250003Sadrian int16_t twice_array_gain, cdd_power = 0; 630250003Sadrian int i, j; 631250003Sadrian u_int8_t ofdm_rt_2_pwr_idx[8] = 632250003Sadrian { 633250003Sadrian ALL_TARGET_LEGACY_6_24, 634250003Sadrian ALL_TARGET_LEGACY_6_24, 635250003Sadrian ALL_TARGET_LEGACY_6_24, 636250003Sadrian ALL_TARGET_LEGACY_6_24, 637250003Sadrian ALL_TARGET_LEGACY_6_24, 638250003Sadrian ALL_TARGET_LEGACY_36, 639250003Sadrian ALL_TARGET_LEGACY_48, 640250003Sadrian ALL_TARGET_LEGACY_54, 641250003Sadrian }; 642250003Sadrian 643250003Sadrian /* 644250003Sadrian * For FCC adjust the upper limit for CDD factoring in the array gain. 645250003Sadrian * The array gain is the same as TxBF, hence reuse the same defines. 646250003Sadrian */ 647250003Sadrian for (i = rt_offset; i < rt_offset + AR9300_NUM_OFDM_RATES; i++) { 648250003Sadrian 649250003Sadrian /* Get the correct OFDM rate to Power table Index */ 650250003Sadrian j = ofdm_rt_2_pwr_idx[i- rt_offset]; 651250003Sadrian 652250003Sadrian switch (chainmask) { 653250003Sadrian case OSPREY_1_CHAINMASK: 654250003Sadrian ahp->txpower[i][0] = rates_array[j]; 655250003Sadrian break; 656250003Sadrian case OSPREY_2LOHI_CHAINMASK: 657250003Sadrian case OSPREY_2LOMID_CHAINMASK: 658250003Sadrian ahp->txpower[i][1] = rates_array[j]; 659250003Sadrian if (is_reg_dmn_fcc(ahp->reg_dmn)){ 660250003Sadrian twice_array_gain = (ahp->twice_antenna_gain >= 661250003Sadrian ahp->twice_antenna_reduction)? 662250003Sadrian -(AR9300_TXBF_2TX_ARRAY_GAIN) : 663250003Sadrian ((int16_t)AH_MIN((ahp->twice_antenna_reduction - 664250003Sadrian (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0)); 665250003Sadrian cdd_power = ahp->upper_limit[1] + twice_array_gain; 666250003Sadrian if (ahp->txpower[i][1] > cdd_power){ 667250003Sadrian ahp->txpower[i][1] = cdd_power; 668250003Sadrian } 669250003Sadrian } 670250003Sadrian break; 671250003Sadrian case OSPREY_3_CHAINMASK: 672250003Sadrian ahp->txpower[i][2] = rates_array[j]; 673250003Sadrian if (is_reg_dmn_fcc(ahp->reg_dmn)) { 674250003Sadrian twice_array_gain = 675250003Sadrian (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)? 676250003Sadrian -(AR9300_TXBF_3TX_ARRAY_GAIN): 677250003Sadrian ((int16_t)AH_MIN((ahp->twice_antenna_reduction - 678250003Sadrian (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0)); 679250003Sadrian cdd_power = ahp->upper_limit[2] + twice_array_gain; 680250003Sadrian if (ahp->txpower[i][2] > cdd_power){ 681250003Sadrian ahp->txpower[i][2] = cdd_power; 682250003Sadrian } 683250003Sadrian } 684250003Sadrian break; 685250003Sadrian default: 686250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n", 687250003Sadrian __func__, chainmask); 688250003Sadrian break; 689250003Sadrian } 690250003Sadrian } 691250003Sadrian} 692250003Sadrian 693250003Sadrianstatic u_int8_t mcs_rate_2_pwr_idx_ht20[24] = 694250003Sadrian { 695250003Sadrian ALL_TARGET_HT20_0_8_16, 696250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 697250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 698250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 699250003Sadrian ALL_TARGET_HT20_4, 700250003Sadrian ALL_TARGET_HT20_5, 701250003Sadrian ALL_TARGET_HT20_6, 702250003Sadrian ALL_TARGET_HT20_7, 703250003Sadrian ALL_TARGET_HT20_0_8_16, 704250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 705250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 706250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 707250003Sadrian ALL_TARGET_HT20_12, 708250003Sadrian ALL_TARGET_HT20_13, 709250003Sadrian ALL_TARGET_HT20_14, 710250003Sadrian ALL_TARGET_HT20_15, 711250003Sadrian ALL_TARGET_HT20_0_8_16, 712250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 713250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 714250003Sadrian ALL_TARGET_HT20_1_3_9_11_17_19, 715250003Sadrian ALL_TARGET_HT20_20, 716250003Sadrian ALL_TARGET_HT20_21, 717250003Sadrian ALL_TARGET_HT20_22, 718250003Sadrian ALL_TARGET_HT20_23 719250003Sadrian }; 720250003Sadrian 721250003Sadrianstatic u_int8_t mcs_rate_2_pwr_idx_ht40[24] = 722250003Sadrian { 723250003Sadrian ALL_TARGET_HT40_0_8_16, 724250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 725250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 726250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 727250003Sadrian ALL_TARGET_HT40_4, 728250003Sadrian ALL_TARGET_HT40_5, 729250003Sadrian ALL_TARGET_HT40_6, 730250003Sadrian ALL_TARGET_HT40_7, 731250003Sadrian ALL_TARGET_HT40_0_8_16, 732250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 733250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 734250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 735250003Sadrian ALL_TARGET_HT40_12, 736250003Sadrian ALL_TARGET_HT40_13, 737250003Sadrian ALL_TARGET_HT40_14, 738250003Sadrian ALL_TARGET_HT40_15, 739250003Sadrian ALL_TARGET_HT40_0_8_16, 740250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 741250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 742250003Sadrian ALL_TARGET_HT40_1_3_9_11_17_19, 743250003Sadrian ALL_TARGET_HT40_20, 744250003Sadrian ALL_TARGET_HT40_21, 745250003Sadrian ALL_TARGET_HT40_22, 746250003Sadrian ALL_TARGET_HT40_23, 747250003Sadrian }; 748250003Sadrian 749250003Sadrianstatic inline void 750250003Sadrianar9300_init_rate_txpower_ht(struct ath_hal *ah, const HAL_RATE_TABLE *rt, 751250003Sadrian HAL_BOOL is40, 752250003Sadrian u_int8_t rates_array[], 753250003Sadrian int rt_ss_offset, int rt_ds_offset, 754250003Sadrian int rt_ts_offset, u_int8_t chainmask) 755250003Sadrian{ 756250003Sadrian 757250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 758250003Sadrian int i, j; 759250003Sadrian u_int8_t mcs_index = 0; 760250003Sadrian 761250003Sadrian 762250003Sadrian for (i = rt_ss_offset; i < rt_ss_offset + AR9300_NUM_HT_SS_RATES; i++) { 763250003Sadrian /* Get the correct MCS rate to Power table Index */ 764250003Sadrian j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] : 765250003Sadrian mcs_rate_2_pwr_idx_ht20[mcs_index]; 766250003Sadrian switch (chainmask) { 767250003Sadrian case OSPREY_1_CHAINMASK: 768250003Sadrian ahp->txpower[i][0] = rates_array[j]; 769250003Sadrian break; 770250003Sadrian case OSPREY_2LOHI_CHAINMASK: 771250003Sadrian case OSPREY_2LOMID_CHAINMASK: 772250003Sadrian ahp->txpower[i][1] = rates_array[j]; 773250003Sadrian break; 774250003Sadrian case OSPREY_3_CHAINMASK: 775250003Sadrian ahp->txpower[i][2] = rates_array[j]; 776250003Sadrian break; 777250003Sadrian default: 778250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n", 779250003Sadrian __func__, chainmask); 780250003Sadrian break; 781250003Sadrian } 782250003Sadrian mcs_index++; 783250003Sadrian } 784250003Sadrian 785250003Sadrian for (i = rt_ds_offset; i < rt_ds_offset + AR9300_NUM_HT_DS_RATES; i++) { 786250003Sadrian /* Get the correct MCS rate to Power table Index */ 787250003Sadrian j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] : 788250003Sadrian mcs_rate_2_pwr_idx_ht20[mcs_index]; 789250003Sadrian switch (chainmask) { 790250003Sadrian case OSPREY_1_CHAINMASK: 791250003Sadrian ahp->txpower[i][0] = rates_array[j]; 792250003Sadrian break; 793250003Sadrian case OSPREY_2LOHI_CHAINMASK: 794250003Sadrian case OSPREY_2LOMID_CHAINMASK: 795250003Sadrian ahp->txpower[i][1] = rates_array[j]; 796250003Sadrian break; 797250003Sadrian case OSPREY_3_CHAINMASK: 798250003Sadrian ahp->txpower[i][2] = rates_array[j]; 799250003Sadrian break; 800250003Sadrian default: 801250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n", 802250003Sadrian __func__, chainmask); 803250003Sadrian break; 804250003Sadrian } 805250003Sadrian mcs_index++; 806250003Sadrian } 807250003Sadrian 808250003Sadrian for (i = rt_ts_offset; i < rt_ts_offset + AR9300_NUM_HT_TS_RATES; i++) { 809250003Sadrian /* Get the correct MCS rate to Power table Index */ 810250003Sadrian j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] : 811250003Sadrian mcs_rate_2_pwr_idx_ht20[mcs_index]; 812250003Sadrian switch (chainmask) { 813250003Sadrian case OSPREY_1_CHAINMASK: 814250003Sadrian ahp->txpower[i][0] = rates_array[j]; 815250003Sadrian break; 816250003Sadrian case OSPREY_2LOHI_CHAINMASK: 817250003Sadrian case OSPREY_2LOMID_CHAINMASK: 818250003Sadrian ahp->txpower[i][1] = rates_array[j]; 819250003Sadrian break; 820250003Sadrian case OSPREY_3_CHAINMASK: 821250003Sadrian ahp->txpower[i][2] = rates_array[j]; 822250003Sadrian break; 823250003Sadrian default: 824250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n", 825250003Sadrian __func__, chainmask); 826250003Sadrian break; 827250003Sadrian } 828250003Sadrian mcs_index++; 829250003Sadrian } 830250003Sadrian} 831250003Sadrian 832250003Sadrianstatic inline void 833250003Sadrianar9300_init_rate_txpower_stbc(struct ath_hal *ah, const HAL_RATE_TABLE *rt, 834250003Sadrian HAL_BOOL is40, 835250003Sadrian int rt_ss_offset, int rt_ds_offset, 836250003Sadrian int rt_ts_offset, u_int8_t chainmask) 837250003Sadrian{ 838250003Sadrian 839250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 840250003Sadrian int i; 841250003Sadrian int16_t twice_array_gain, stbc_power = 0; 842250003Sadrian u_int8_t mcs_index = 0; 843250003Sadrian 844250003Sadrian /* Upper Limit with STBC */ 845250003Sadrian switch (chainmask) { 846250003Sadrian case OSPREY_1_CHAINMASK: 847250003Sadrian stbc_power = ahp->upper_limit[0]; 848250003Sadrian break; 849250003Sadrian case OSPREY_2LOHI_CHAINMASK: 850250003Sadrian case OSPREY_2LOMID_CHAINMASK: 851250003Sadrian stbc_power = ahp->upper_limit[1]; 852250003Sadrian break; 853250003Sadrian case OSPREY_3_CHAINMASK: 854250003Sadrian stbc_power = ahp->upper_limit[2]; 855250003Sadrian /* Ony FCC requires that we back off with 3 transmit chains */ 856250003Sadrian if (is_reg_dmn_fcc(ahp->reg_dmn)) { 857250003Sadrian twice_array_gain = 858250003Sadrian (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)? 859250003Sadrian -(AR9300_STBC_3TX_ARRAY_GAIN) : 860250003Sadrian ((int16_t)AH_MIN((ahp->twice_antenna_reduction - 861250003Sadrian (ahp->twice_antenna_gain + AR9300_STBC_3TX_ARRAY_GAIN)), 0)); 862250003Sadrian stbc_power = ahp->upper_limit[2] + twice_array_gain; 863250003Sadrian } 864250003Sadrian break; 865250003Sadrian 866250003Sadrian default: 867250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n", 868250003Sadrian __func__, chainmask); 869250003Sadrian break; 870250003Sadrian } 871250003Sadrian 872250003Sadrian 873250003Sadrian for (i = rt_ss_offset; i < rt_ss_offset + AR9300_NUM_HT_SS_RATES; i++) { 874250003Sadrian switch (chainmask) { 875250003Sadrian case OSPREY_1_CHAINMASK: 876250003Sadrian ahp->txpower_stbc[i][0] = ahp->txpower[i][0]; 877250003Sadrian break; 878250003Sadrian case OSPREY_2LOHI_CHAINMASK: 879250003Sadrian case OSPREY_2LOMID_CHAINMASK: 880250003Sadrian ahp->txpower_stbc[i][1] = ahp->txpower[i][1]; 881250003Sadrian break; 882250003Sadrian case OSPREY_3_CHAINMASK: 883250003Sadrian ahp->txpower_stbc[i][2] = ahp->txpower[i][2]; 884250003Sadrian /* 3 TX/1 stream STBC gain adjustment */ 885250003Sadrian if (ahp->txpower_stbc[i][2] > stbc_power){ 886250003Sadrian ahp->txpower_stbc[i][2] = stbc_power; 887250003Sadrian } 888250003Sadrian break; 889250003Sadrian default: 890250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n", 891250003Sadrian __func__, chainmask); 892250003Sadrian break; 893250003Sadrian } 894250003Sadrian mcs_index++; 895250003Sadrian } 896250003Sadrian 897250003Sadrian for (i = rt_ds_offset; i < rt_ds_offset + AR9300_NUM_HT_DS_RATES; i++) { 898250003Sadrian switch (chainmask) { 899250003Sadrian case OSPREY_1_CHAINMASK: 900250003Sadrian ahp->txpower_stbc[i][0] = ahp->txpower[i][0]; 901250003Sadrian break; 902250003Sadrian case OSPREY_2LOHI_CHAINMASK: 903250003Sadrian case OSPREY_2LOMID_CHAINMASK: 904250003Sadrian ahp->txpower_stbc[i][1] = ahp->txpower[i][1]; 905250003Sadrian break; 906250003Sadrian case OSPREY_3_CHAINMASK: 907250003Sadrian ahp->txpower_stbc[i][2] = ahp->txpower[i][2]; 908250003Sadrian /* 3 TX/2 stream STBC gain adjustment */ 909250003Sadrian if (ahp->txpower_stbc[i][2] > stbc_power){ 910250003Sadrian ahp->txpower_stbc[i][2] = stbc_power; 911250003Sadrian } 912250003Sadrian break; 913250003Sadrian default: 914250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n", 915250003Sadrian __func__, chainmask); 916250003Sadrian break; 917250003Sadrian } 918250003Sadrian mcs_index++; 919250003Sadrian } 920250003Sadrian 921250003Sadrian for (i = rt_ts_offset; i < rt_ts_offset + AR9300_NUM_HT_TS_RATES; i++) { 922250003Sadrian switch (chainmask) { 923250003Sadrian case OSPREY_1_CHAINMASK: 924250003Sadrian ahp->txpower_stbc[i][0] = ahp->txpower[i][0]; 925250003Sadrian break; 926250003Sadrian case OSPREY_2LOHI_CHAINMASK: 927250003Sadrian case OSPREY_2LOMID_CHAINMASK: 928250003Sadrian ahp->txpower_stbc[i][1] = ahp->txpower[i][1]; 929250003Sadrian break; 930250003Sadrian case OSPREY_3_CHAINMASK: 931250003Sadrian ahp->txpower_stbc[i][2] = ahp->txpower[i][2]; 932250003Sadrian break; 933250003Sadrian default: 934250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n", 935250003Sadrian __func__, chainmask); 936250003Sadrian break; 937250003Sadrian } 938250003Sadrian mcs_index++; 939250003Sadrian } 940250003Sadrian 941250003Sadrian return; 942250003Sadrian} 943250003Sadrian 944250003Sadrianstatic inline void 945250003Sadrianar9300_adjust_rate_txpower_cdd(struct ath_hal *ah, const HAL_RATE_TABLE *rt, 946250003Sadrian HAL_BOOL is40, 947250003Sadrian int rt_ss_offset, int rt_ds_offset, 948250003Sadrian int rt_ts_offset, u_int8_t chainmask) 949250003Sadrian{ 950250003Sadrian 951250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 952250003Sadrian int i; 953250003Sadrian int16_t twice_array_gain, cdd_power = 0; 954250003Sadrian u_int8_t mcs_index = 0; 955250003Sadrian 956250003Sadrian /* 957250003Sadrian * Adjust the upper limit for CDD factoring in the array gain . 958250003Sadrian * The array gain is the same as TxBF, hence reuse the same defines. 959250003Sadrian */ 960250003Sadrian switch (chainmask) { 961250003Sadrian case OSPREY_1_CHAINMASK: 962250003Sadrian cdd_power = ahp->upper_limit[0]; 963250003Sadrian break; 964250003Sadrian 965250003Sadrian case OSPREY_2LOHI_CHAINMASK: 966250003Sadrian case OSPREY_2LOMID_CHAINMASK: 967250003Sadrian twice_array_gain = 968250003Sadrian (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)? 969250003Sadrian -(AR9300_TXBF_2TX_ARRAY_GAIN) : 970250003Sadrian ((int16_t)AH_MIN((ahp->twice_antenna_reduction - 971250003Sadrian (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0)); 972250003Sadrian cdd_power = ahp->upper_limit[1] + twice_array_gain; 973250003Sadrian break; 974250003Sadrian 975250003Sadrian case OSPREY_3_CHAINMASK: 976250003Sadrian twice_array_gain = 977250003Sadrian (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)? 978250003Sadrian -(AR9300_TXBF_3TX_ARRAY_GAIN) : 979250003Sadrian ((int16_t)AH_MIN((ahp->twice_antenna_reduction - 980250003Sadrian (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0)); 981250003Sadrian cdd_power = ahp->upper_limit[2] + twice_array_gain; 982250003Sadrian break; 983250003Sadrian 984250003Sadrian default: 985250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n", 986250003Sadrian __func__, chainmask); 987250003Sadrian break; 988250003Sadrian } 989250003Sadrian 990250003Sadrian 991250003Sadrian for (i = rt_ss_offset; i < rt_ss_offset + AR9300_NUM_HT_SS_RATES; i++) { 992250003Sadrian switch (chainmask) { 993250003Sadrian case OSPREY_1_CHAINMASK: 994250003Sadrian break; 995250003Sadrian 996250003Sadrian case OSPREY_2LOHI_CHAINMASK: 997250003Sadrian case OSPREY_2LOMID_CHAINMASK: 998250003Sadrian /* 2 TX/1 stream CDD gain adjustment */ 999250003Sadrian if (ahp->txpower[i][1] > cdd_power){ 1000250003Sadrian ahp->txpower[i][1] = cdd_power; 1001250003Sadrian } 1002250003Sadrian break; 1003250003Sadrian case OSPREY_3_CHAINMASK: 1004250003Sadrian /* 3 TX/1 stream CDD gain adjustment */ 1005250003Sadrian if (ahp->txpower[i][2] > cdd_power){ 1006250003Sadrian ahp->txpower[i][2] = cdd_power; 1007250003Sadrian } 1008250003Sadrian break; 1009250003Sadrian default: 1010250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n", 1011250003Sadrian __func__, chainmask); 1012250003Sadrian break; 1013250003Sadrian } 1014250003Sadrian mcs_index++; 1015250003Sadrian } 1016250003Sadrian 1017250003Sadrian for (i = rt_ds_offset; i < rt_ds_offset + AR9300_NUM_HT_DS_RATES; i++) { 1018250003Sadrian switch (chainmask) { 1019250003Sadrian case OSPREY_1_CHAINMASK: 1020250003Sadrian case OSPREY_2LOHI_CHAINMASK: 1021250003Sadrian case OSPREY_2LOMID_CHAINMASK: 1022250003Sadrian break; 1023250003Sadrian case OSPREY_3_CHAINMASK: 1024250003Sadrian /* 3 TX/2 stream TxBF gain adjustment */ 1025250003Sadrian if (ahp->txpower[i][2] > cdd_power){ 1026250003Sadrian ahp->txpower[i][2] = cdd_power; 1027250003Sadrian } 1028250003Sadrian break; 1029250003Sadrian default: 1030250003Sadrian HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n", 1031250003Sadrian __func__, chainmask); 1032250003Sadrian break; 1033250003Sadrian } 1034250003Sadrian mcs_index++; 1035250003Sadrian } 1036250003Sadrian 1037250003Sadrian return; 1038250003Sadrian 1039250003Sadrian} 1040250003Sadrian 1041250003Sadrianvoid ar9300_disp_tpc_tables(struct ath_hal *ah) 1042250003Sadrian{ 1043250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 1044250008Sadrian const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; 1045250003Sadrian u_int mode = ath_hal_get_curmode(ah, chan); 1046250003Sadrian const HAL_RATE_TABLE *rt; 1047250003Sadrian int i, j; 1048250003Sadrian 1049250003Sadrian /* Check whether TPC is enabled */ 1050250008Sadrian if (!ah->ah_config.ath_hal_desc_tpc) { 1051250003Sadrian ath_hal_printf(ah, "\n TPC Register method in use\n"); 1052250003Sadrian return; 1053250003Sadrian } 1054250003Sadrian 1055250003Sadrian rt = ar9300_get_rate_table(ah, mode); 1056250003Sadrian HALASSERT(rt != NULL); 1057250003Sadrian 1058250003Sadrian ath_hal_printf(ah, "\n===TARGET POWER TABLE===\n"); 1059250003Sadrian for (j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) { 1060250003Sadrian for (i = 0; i < rt->rateCount; i++) { 1061250003Sadrian int16_t txpower[AR9300_MAX_CHAINS]; 1062250003Sadrian txpower[j] = ahp->txpower[i][j]; 1063250003Sadrian ath_hal_printf(ah, " Index[%2d] Rate[0x%02x] %6d kbps " 1064250003Sadrian "Power (%d Chain) [%2d.%1d dBm]\n", 1065250008Sadrian i, rt->info[i].rateCode, rt->info[i].rateKbps, 1066250003Sadrian j + 1, txpower[j] / 2, txpower[j]%2 * 5); 1067250003Sadrian } 1068250003Sadrian } 1069250003Sadrian ath_hal_printf(ah, "\n"); 1070250003Sadrian 1071250003Sadrian ath_hal_printf(ah, "\n\n===TARGET POWER TABLE with STBC===\n"); 1072250003Sadrian for ( j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) { 1073250003Sadrian for (i = 0; i < rt->rateCount; i++) { 1074250003Sadrian int16_t txpower[AR9300_MAX_CHAINS]; 1075250003Sadrian txpower[j] = ahp->txpower_stbc[i][j]; 1076250003Sadrian 1077250003Sadrian /* Do not display invalid configurations */ 1078250008Sadrian if ((rt->info[i].rateCode < AR9300_MCS0_RATE_CODE) || 1079250008Sadrian (rt->info[i].rateCode > AR9300_MCS23_RATE_CODE) || 1080250008Sadrian ar9300_invalid_stbc_cfg(j, rt->info[i].rateCode) == AH_TRUE) { 1081250003Sadrian continue; 1082250003Sadrian } 1083250003Sadrian 1084250003Sadrian ath_hal_printf(ah, " Index[%2d] Rate[0x%02x] %6d kbps " 1085250003Sadrian "Power (%d Chain) [%2d.%1d dBm]\n", 1086250008Sadrian i, rt->info[i].rateCode , rt->info[i].rateKbps, 1087250003Sadrian j + 1, txpower[j] / 2, txpower[j]%2 * 5); 1088250003Sadrian } 1089250003Sadrian } 1090250003Sadrian ath_hal_printf(ah, "\n"); 1091250003Sadrian} 1092250003Sadrian 1093250003Sadrian/* 1094250003Sadrian * The followings are customer specific APIs for querying power limit. 1095250003Sadrian * Power limit is based on regulatory domain, chipset, and transmission rate. 1096250003Sadrian * Here we only consider EEPROM values, no array gain/CTL considered here. 1097250003Sadrian */ 1098250003Sadrian 1099250003Sadrianstruct rate_power_tbl { 1100250003Sadrian u_int8_t rateIdx; /* rate index in the rate table */ 1101250003Sadrian u_int32_t rateKbps; /* transfer rate in kbs */ 1102250003Sadrian u_int8_t rateCode; /* rate for h/w descriptors */ 1103250003Sadrian u_int8_t txbf: 1, /* txbf eligible */ 1104250003Sadrian stbc: 1, /* stbc eligible */ 1105250003Sadrian chain1: 1, /* one-chain eligible */ 1106250003Sadrian chain2: 1, /* two-chain eligible */ 1107250003Sadrian chain3: 1; /* three-chain eligible */ 1108250003Sadrian int16_t txpower[AR9300_MAX_CHAINS]; /* txpower for different chainmasks */ 1109250003Sadrian int16_t txpower_stbc[AR9300_MAX_CHAINS]; 1110250003Sadrian}; 1111250003Sadrian 1112250003Sadrianu_int8_t *ar9300_get_tpc_tables(struct ath_hal *ah) 1113250003Sadrian{ 1114250003Sadrian struct ath_hal_9300 *ahp = AH9300(ah); 1115250008Sadrian const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; 1116250003Sadrian u_int mode = ath_hal_get_curmode(ah, chan); 1117250003Sadrian const HAL_RATE_TABLE *rt; 1118250003Sadrian u_int8_t *data; 1119250003Sadrian struct rate_power_tbl *table; 1120250003Sadrian int i, j; 1121250003Sadrian 1122250003Sadrian /* Check whether TPC is enabled */ 1123250008Sadrian if (! ah->ah_config.ath_hal_desc_tpc) { 1124250003Sadrian ath_hal_printf(ah, "\n TPC Register method in use\n"); 1125250003Sadrian return NULL; 1126250003Sadrian } 1127250003Sadrian 1128250008Sadrian rt = (const HAL_RATE_TABLE *)ar9300_get_rate_table(ah, mode); 1129250003Sadrian HALASSERT(rt != NULL); 1130250003Sadrian 1131250008Sadrian data = (u_int8_t *)ath_hal_malloc( 1132250003Sadrian 1 + rt->rateCount * sizeof(struct rate_power_tbl)); 1133250003Sadrian if (data == NULL) 1134250003Sadrian return NULL; 1135250003Sadrian 1136250003Sadrian OS_MEMZERO(data, 1 + rt->rateCount * sizeof(struct rate_power_tbl)); 1137250003Sadrian /* store the rate count at the beginning */ 1138250003Sadrian *data = rt->rateCount; 1139250003Sadrian table = (struct rate_power_tbl *)&data[1]; 1140250003Sadrian 1141250003Sadrian for (j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) { 1142250003Sadrian for (i = 0; i < rt->rateCount; i++) { 1143250003Sadrian table[i].rateIdx = i; 1144250008Sadrian table[i].rateCode = rt->info[i].rateCode; 1145250003Sadrian table[i].rateKbps = rt->info[i].rateKbps; 1146250003Sadrian switch (j) { 1147250003Sadrian case 0: 1148250008Sadrian table[i].chain1 = rt->info[i].rateCode <= 0x87 ? 1 : 0; 1149250003Sadrian break; 1150250003Sadrian case 1: 1151250008Sadrian table[i].chain2 = rt->info[i].rateCode <= 0x8f ? 1 : 0; 1152250003Sadrian break; 1153250003Sadrian case 2: 1154250003Sadrian table[i].chain3 = 1; 1155250003Sadrian break; 1156250003Sadrian default: 1157250003Sadrian break; 1158250003Sadrian } 1159250003Sadrian if ((j == 0 && table[i].chain1) || 1160250003Sadrian (j == 1 && table[i].chain2) || 1161250003Sadrian (j == 2 && table[i].chain3)) 1162250003Sadrian table[i].txpower[j] = ahp->txpower[i][j]; 1163250003Sadrian } 1164250003Sadrian } 1165250003Sadrian 1166250003Sadrian for ( j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) { 1167250003Sadrian for (i = 0; i < rt->rateCount; i++) { 1168250003Sadrian /* Do not display invalid configurations */ 1169250008Sadrian if ((rt->info[i].rateCode < AR9300_MCS0_RATE_CODE) || 1170250008Sadrian (rt->info[i].rateCode > AR9300_MCS23_RATE_CODE) || 1171250008Sadrian ar9300_invalid_stbc_cfg(j, rt->info[i].rateCode) == AH_TRUE) { 1172250003Sadrian continue; 1173250003Sadrian } 1174250003Sadrian 1175250003Sadrian table[i].stbc = 1; 1176250003Sadrian table[i].txpower_stbc[j] = ahp->txpower_stbc[i][j]; 1177250003Sadrian } 1178250003Sadrian } 1179250003Sadrian 1180250003Sadrian return data; 1181250003Sadrian /* the caller is responsible to free data */ 1182250003Sadrian} 1183250003Sadrian 1184250003SadrianHAL_STATUS 1185250003Sadrianath_hal_get_rate_power_limit_from_eeprom(struct ath_hal *ah, u_int16_t freq, 1186250003Sadrian int8_t *max_rate_power, int8_t *min_rate_power) 1187250003Sadrian{ 1188250003Sadrian /* 1189250003Sadrian * Used for AR9300 series chip only 1190250003Sadrian */ 1191250008Sadrian if (ah->ah_magic == AR9300_MAGIC) { 1192250003Sadrian u_int8_t target_rate_power_limit_val_t2[ar9300_rate_size]; 1193250003Sadrian int i; 1194250003Sadrian 1195250003Sadrian *max_rate_power = 0; 1196250003Sadrian *min_rate_power = AR9300_MAX_RATE_POWER; 1197250003Sadrian 1198250003Sadrian ar9300_set_target_power_from_eeprom(ah, freq, target_rate_power_limit_val_t2); 1199250003Sadrian 1200250003Sadrian for (i=0; i<ar9300_rate_size; i++) { 1201250003Sadrian if (target_rate_power_limit_val_t2[i] > *max_rate_power) 1202250003Sadrian *max_rate_power = target_rate_power_limit_val_t2[i]; 1203250003Sadrian if (target_rate_power_limit_val_t2[i] < *min_rate_power) 1204250003Sadrian *min_rate_power = target_rate_power_limit_val_t2[i]; 1205250003Sadrian } 1206250003Sadrian } else { 1207250003Sadrian *max_rate_power = 0; 1208250003Sadrian *min_rate_power = 0; 1209250003Sadrian } 1210250003Sadrian 1211250003Sadrian return HAL_OK; 1212250003Sadrian} 1213