ar9300_phy.c revision 250003
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#ifdef AH_SUPPORT_AR9300 20 21#include "ah.h" 22#include "ah_internal.h" 23 24#include "ar9300/ar9300.h" 25 26/* shorthands to compact tables for readability */ 27#define OFDM IEEE80211_T_OFDM 28#define CCK IEEE80211_T_CCK 29#define TURBO IEEE80211_T_TURBO 30#define XR ATHEROS_T_XR 31#define HT IEEE80211_T_HT 32 33#define AR9300_NUM_OFDM_RATES 8 34#define AR9300_NUM_HT_SS_RATES 8 35#define AR9300_NUM_HT_DS_RATES 8 36#define AR9300_NUM_HT_TS_RATES 8 37 38/* Array Gain defined for TxBF */ 39#define AR9300_TXBF_2TX_ARRAY_GAIN 6 /* 2TX/SS 3 */ 40#define AR9300_TXBF_3TX_ARRAY_GAIN 10 /* 3TX/SS or 3TX/DS 4.8 */ 41#define AR9300_STBC_3TX_ARRAY_GAIN 10 /* 3TX/SS or 3TX/DS 4.8 */ 42 43/* MCS RATE CODES - first and last */ 44#define AR9300_MCS0_RATE_CODE 0x80 45#define AR9300_MCS23_RATE_CODE 0x97 46 47static inline void ar9300_init_rate_txpower_cck(struct ath_hal *ah, 48 const HAL_RATE_TABLE *rt, u_int8_t rates_array[], u_int8_t chainmask); 49static inline void ar9300_init_rate_txpower_ofdm(struct ath_hal* ah, 50 const HAL_RATE_TABLE *rt, u_int8_t rates_array[], int rt_offset, 51 u_int8_t chainmask); 52static inline void ar9300_init_rate_txpower_ht(struct ath_hal *ah, 53 const HAL_RATE_TABLE *rt, HAL_BOOL is40, u_int8_t rates_array[], 54 int rt_ss_offset, int rt_ds_offset, 55 int rt_ts_offset, u_int8_t chainmask); 56static inline void ar9300_init_rate_txpower_stbc(struct ath_hal *ah, 57 const HAL_RATE_TABLE *rt, HAL_BOOL is40, 58 int rt_ss_offset, int rt_ds_offset, 59 int rt_ts_offset, u_int8_t chainmask); 60static inline void ar9300_adjust_rate_txpower_cdd(struct ath_hal *ah, 61 const HAL_RATE_TABLE *rt, HAL_BOOL is40, 62 int rt_ss_offset, int rt_ds_offset, 63 int rt_ts_offset, u_int8_t chainmask); 64 65#define AR9300_11A_RT_OFDM_OFFSET 0 66HAL_RATE_TABLE ar9300_11a_table = { 67 8, /* number of rates */ 68 { 0 }, 69 { 70/* short ctrl */ 71/* valid rate_code Preamble dot11Rate Rate */ 72/* 6 Mb */ { AH_TRUE, OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0 }, 73/* 9 Mb */ { AH_TRUE, OFDM, 9000, 0x0f, 0x00, 18, 0 }, 74/* 12 Mb */ { AH_TRUE, OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2 }, 75/* 18 Mb */ { AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 2 }, 76/* 24 Mb */ { AH_TRUE, OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4 }, 77/* 36 Mb */ { AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 4 }, 78/* 48 Mb */ { AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 4 }, 79/* 54 Mb */ { AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 4 }, 80 }, 81}; 82 83HAL_RATE_TABLE ar9300_11a_half_table = { 84 8, /* number of rates */ 85 { 0 }, 86 { 87/* short ctrl */ 88/* valid rate_code Preamble dot11Rate Rate */ 89/* 6 Mb */ { AH_TRUE, OFDM, 3000, 0x0b, 0x00, (0x80 | 6), 0 }, 90/* 9 Mb */ { AH_TRUE, OFDM, 4500, 0x0f, 0x00, 9, 0 }, 91/* 12 Mb */ { AH_TRUE, OFDM, 6000, 0x0a, 0x00, (0x80 | 12), 2 }, 92/* 18 Mb */ { AH_TRUE, OFDM, 9000, 0x0e, 0x00, 18, 2 }, 93/* 24 Mb */ { AH_TRUE, OFDM, 12000, 0x09, 0x00, (0x80 | 24), 4 }, 94/* 36 Mb */ { AH_TRUE, OFDM, 18000, 0x0d, 0x00, 36, 4 }, 95/* 48 Mb */ { AH_TRUE, OFDM, 24000, 0x08, 0x00, 48, 4 }, 96/* 54 Mb */ { AH_TRUE, OFDM, 27000, 0x0c, 0x00, 54, 4 }, 97 }, 98}; 99 100HAL_RATE_TABLE ar9300_11a_quarter_table = { 101 8, /* number of rates */ 102 { 0 }, 103 { 104/* short ctrl */ 105/* valid rate_code Preamble dot11Rate Rate */ 106/* 6 Mb */ { AH_TRUE, OFDM, 1500, 0x0b, 0x00, (0x80 | 3), 0 }, 107/* 9 Mb */ { AH_TRUE, OFDM, 2250, 0x0f, 0x00, 4 , 0 }, 108/* 12 Mb */ { AH_TRUE, OFDM, 3000, 0x0a, 0x00, (0x80 | 6), 2 }, 109/* 18 Mb */ { AH_TRUE, OFDM, 4500, 0x0e, 0x00, 9, 2 }, 110/* 24 Mb */ { AH_TRUE, OFDM, 6000, 0x09, 0x00, (0x80 | 12), 4 }, 111/* 36 Mb */ { AH_TRUE, OFDM, 9000, 0x0d, 0x00, 18, 4 }, 112/* 48 Mb */ { AH_TRUE, OFDM, 12000, 0x08, 0x00, 24, 4 }, 113/* 54 Mb */ { AH_TRUE, OFDM, 13500, 0x0c, 0x00, 27, 4 }, 114 }, 115}; 116 117HAL_RATE_TABLE ar9300_turbo_table = { 118 8, /* number of rates */ 119 { 0 }, 120 { 121/* short ctrl */ 122/* valid rate_code Preamble dot11Rate Rate */ 123/* 6 Mb */ { AH_TRUE, TURBO, 6000, 0x0b, 0x00, (0x80 | 12), 0 }, 124/* 9 Mb */ { AH_TRUE, TURBO, 9000, 0x0f, 0x00, 18, 0 }, 125/* 12 Mb */ { AH_TRUE, TURBO, 12000, 0x0a, 0x00, (0x80 | 24), 2 }, 126/* 18 Mb */ { AH_TRUE, TURBO, 18000, 0x0e, 0x00, 36, 2 }, 127/* 24 Mb */ { AH_TRUE, TURBO, 24000, 0x09, 0x00, (0x80 | 48), 4 }, 128/* 36 Mb */ { AH_TRUE, TURBO, 36000, 0x0d, 0x00, 72, 4 }, 129/* 48 Mb */ { AH_TRUE, TURBO, 48000, 0x08, 0x00, 96, 4 }, 130/* 54 Mb */ { AH_TRUE, TURBO, 54000, 0x0c, 0x00, 108, 4 }, 131 }, 132}; 133 134HAL_RATE_TABLE ar9300_11b_table = { 135 4, /* number of rates */ 136 { 0 }, 137 { 138/* short ctrl */ 139/* valid rate_code Preamble dot11Rate Rate */ 140/* 1 Mb */ { AH_TRUE, CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0 }, 141/* 2 Mb */ { AH_TRUE, CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1 }, 142/* 5.5 Mb */ { AH_TRUE, CCK, 5500, 0x19, 0x04, (0x80 | 11), 1 }, 143/* 11 Mb */ { AH_TRUE, CCK, 11000, 0x18, 0x04, (0x80 | 22), 1 }, 144 }, 145}; 146 147 148/* Venice TODO: round_up_rate() is broken when the rate table does not represent 149 * rates in increasing order e.g. 5.5, 11, 6, 9. 150 * An average rate of 6 Mbps will currently map to 11 Mbps. 151 */ 152#define AR9300_11G_RT_OFDM_OFFSET 4 153HAL_RATE_TABLE ar9300_11g_table = { 154 12, /* number of rates */ 155 { 0 }, 156 { 157/* short ctrl */ 158/* valid rate_code Preamble dot11Rate Rate */ 159/* 1 Mb */ { AH_TRUE, CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0 }, 160/* 2 Mb */ { AH_TRUE, CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1 }, 161/* 5.5 Mb */ { AH_TRUE, CCK, 5500, 0x19, 0x04, (0x80 | 11), 2 }, 162/* 11 Mb */ { AH_TRUE, CCK, 11000, 0x18, 0x04, (0x80 | 22), 3 }, 163/* Hardware workaround - remove rates 6, 9 from rate ctrl */ 164/* 6 Mb */ { AH_FALSE, OFDM, 6000, 0x0b, 0x00, 12, 4 }, 165/* 9 Mb */ { AH_FALSE, OFDM, 9000, 0x0f, 0x00, 18, 4 }, 166/* 12 Mb */ { AH_TRUE, OFDM, 12000, 0x0a, 0x00, 24, 6 }, 167/* 18 Mb */ { AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 6 }, 168/* 24 Mb */ { AH_TRUE, OFDM, 24000, 0x09, 0x00, 48, 8 }, 169/* 36 Mb */ { AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 8 }, 170/* 48 Mb */ { AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 8 }, 171/* 54 Mb */ { AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 8 }, 172 }, 173}; 174 175HAL_RATE_TABLE ar9300_xr_table = { 176 13, /* number of rates */ 177 { 0 }, 178 { 179/* short ctrl */ 180/* valid rate_code Preamble dot11Rate Rate */ 181/* 0.25 Mb */ {AH_TRUE, XR, 250, 0x03, 0x00, (0x80 | 1), 0, 612, 612 }, 182/* 0.5 Mb */ {AH_TRUE, XR, 500, 0x07, 0x00, (0x80 | 1), 0, 457, 457 }, 183/* 1 Mb */ {AH_TRUE, XR, 1000, 0x02, 0x00, (0x80 | 2), 1, 228, 228 }, 184/* 2 Mb */ {AH_TRUE, XR, 2000, 0x06, 0x00, (0x80 | 4), 2, 160, 160 }, 185/* 3 Mb */ {AH_TRUE, XR, 3000, 0x01, 0x00, (0x80 | 6), 3, 140, 140 }, 186/* 6 Mb */ {AH_TRUE, OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 4, 60, 60 }, 187/* 9 Mb */ {AH_TRUE, OFDM, 9000, 0x0f, 0x00, 18, 4, 60, 60 }, 188/* 12 Mb */ {AH_TRUE, OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 6, 48, 48 }, 189/* 18 Mb */ {AH_TRUE, OFDM, 18000, 0x0e, 0x00, 36, 6, 48, 48 }, 190/* 24 Mb */ {AH_TRUE, OFDM, 24000, 0x09, 0x00, 48, 8, 44, 44 }, 191/* 36 Mb */ {AH_TRUE, OFDM, 36000, 0x0d, 0x00, 72, 8, 44, 44 }, 192/* 48 Mb */ {AH_TRUE, OFDM, 48000, 0x08, 0x00, 96, 8, 44, 44 }, 193/* 54 Mb */ {AH_TRUE, OFDM, 54000, 0x0c, 0x00, 108, 8, 44, 44 }, 194 }, 195}; 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->hal_chan_half_rate) { 320 rt = &ar9300_11a_half_table; 321 break; 322 } 323 return AH_NULL; 324 case HAL_MODE_11A_QUARTER_RATE: 325 if (p_cap->hal_chan_quarter_rate) { 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 case HAL_MODE_XR: 341 rt = &ar9300_xr_table; 342 break; 343 case HAL_MODE_11NG_HT20: 344 case HAL_MODE_11NG_HT40PLUS: 345 case HAL_MODE_11NG_HT40MINUS: 346 rt = &ar9300_11ng_table; 347 break; 348 case HAL_MODE_11NA_HT20: 349 case HAL_MODE_11NA_HT40PLUS: 350 case HAL_MODE_11NA_HT40MINUS: 351 rt = &ar9300_11na_table; 352 break; 353 default: 354 HALDEBUG(ah, HAL_DEBUG_CHANNEL, 355 "%s: invalid mode 0x%x\n", __func__, mode); 356 return AH_NULL; 357 } 358 ath_hal_setupratetable(ah, rt); 359 return rt; 360} 361 362static HAL_BOOL 363ar9300_invalid_stbc_cfg(int tx_chains, u_int8_t rate_code) 364{ 365 switch (tx_chains) { 366 case 0: /* Single Chain */ 367 return AH_TRUE; 368 369 case 1: /* 2 Chains */ 370 if ((rate_code < 0x80) || (rate_code > 0x87)) { 371 return AH_TRUE; 372 } else { 373 return AH_FALSE; 374 } 375 376 case 2: /* 3 Chains */ 377 if ((rate_code < 0x80) || (rate_code > 0x87)) { 378 return AH_TRUE; 379 } else { 380 return AH_FALSE; 381 } 382 383 default: 384 HALASSERT(0); 385 break; 386 } 387 388 return AH_TRUE; 389} 390 391 392int16_t 393ar9300_get_rate_txpower(struct ath_hal *ah, u_int mode, u_int8_t rate_index, 394 u_int8_t chainmask, u_int8_t xmit_mode) 395{ 396 struct ath_hal_9300 *ahp = AH9300(ah); 397 int num_chains = ar9300_get_ntxchains(chainmask); 398 399 switch (xmit_mode) { 400 case AR9300_DEF_MODE: 401 return ahp->txpower[rate_index][num_chains-1]; 402 403 404 case AR9300_STBC_MODE: 405 return ahp->txpower_stbc[rate_index][num_chains-1]; 406 407 default: 408 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid mode 0x%x\n", 409 __func__, xmit_mode); 410 HALASSERT(0); 411 break; 412 } 413 414 return ahp->txpower[rate_index][num_chains-1]; 415} 416 417extern void 418ar9300_adjust_reg_txpower_cdd(struct ath_hal *ah, 419 u_int8_t power_per_rate[]) 420 421{ 422 struct ath_hal_9300 *ahp = AH9300(ah); 423 int16_t twice_array_gain, cdd_power = 0; 424 int i; 425 426 /* 427 * Adjust the upper limit for CDD factoring in the array gain . 428 * The array gain is the same as TxBF, hence reuse the same defines. 429 */ 430 switch (ahp->ah_tx_chainmask) { 431 432 case OSPREY_1_CHAINMASK: 433 cdd_power = ahp->upper_limit[0]; 434 break; 435 436 case OSPREY_2LOHI_CHAINMASK: 437 case OSPREY_2LOMID_CHAINMASK: 438 twice_array_gain = 439 (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)? 440 -(AR9300_TXBF_2TX_ARRAY_GAIN) : 441 ((int16_t)AH_MIN((ahp->twice_antenna_reduction - 442 (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0)); 443 cdd_power = ahp->upper_limit[1] + twice_array_gain; 444 /* Adjust OFDM legacy rates as well */ 445 for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) { 446 if (power_per_rate[i] > cdd_power) { 447 power_per_rate[i] = cdd_power; 448 } 449 } 450 451 /* 2Tx/(n-1) stream Adjust rates MCS0 through MCS 7 HT 20*/ 452 for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_7; i++) { 453 if (power_per_rate[i] > cdd_power) { 454 power_per_rate[i] = cdd_power; 455 } 456 } 457 458 /* 2Tx/(n-1) stream Adjust rates MCS0 through MCS 7 HT 40*/ 459 for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_7; i++) { 460 if (power_per_rate[i] > cdd_power) { 461 power_per_rate[i] = cdd_power; 462 } 463 } 464 break; 465 466 case OSPREY_3_CHAINMASK: 467 twice_array_gain = 468 (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)? 469 -(AR9300_TXBF_3TX_ARRAY_GAIN) : 470 ((int16_t)AH_MIN((ahp->twice_antenna_reduction - 471 (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0)); 472 cdd_power = ahp->upper_limit[2] + twice_array_gain; 473 /* Adjust OFDM legacy rates as well */ 474 for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) { 475 if (power_per_rate[i] > cdd_power) { 476 power_per_rate[i] = cdd_power; 477 } 478 } 479 /* 3Tx/(n-1)streams Adjust rates MCS0 through MCS 15 HT20 */ 480 for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_15; i++) { 481 if (power_per_rate[i] > cdd_power) { 482 power_per_rate[i] = cdd_power; 483 } 484 } 485 486 /* 3Tx/(n-1)streams Adjust rates MCS0 through MCS 15 HT40 */ 487 for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_15; i++) { 488 if (power_per_rate[i] > cdd_power) { 489 power_per_rate[i] = cdd_power; 490 } 491 } 492 493 break; 494 495 default: 496 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n", 497 __func__, ahp->ah_tx_chainmask); 498 break; 499 } 500 501 return; 502} 503 504extern void 505ar9300_init_rate_txpower(struct ath_hal *ah, u_int mode, 506 HAL_CHANNEL_INTERNAL *chan, 507 u_int8_t power_per_rate[], u_int8_t chainmask) 508{ 509 const HAL_RATE_TABLE *rt; 510 HAL_BOOL is40 = IS_CHAN_HT40(chan); 511 512 rt = ar9300_get_rate_table(ah, mode); 513 HALASSERT(rt != NULL); 514 515 switch (mode) { 516 case HAL_MODE_11A: 517 ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate, 518 AR9300_11A_RT_OFDM_OFFSET, chainmask); 519 break; 520 case HAL_MODE_11NA_HT20: 521 case HAL_MODE_11NA_HT40PLUS: 522 case HAL_MODE_11NA_HT40MINUS: 523 ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate, 524 AR9300_11NA_RT_OFDM_OFFSET, chainmask); 525 ar9300_init_rate_txpower_ht(ah, rt, is40, power_per_rate, 526 AR9300_11NA_RT_HT_SS_OFFSET, 527 AR9300_11NA_RT_HT_DS_OFFSET, 528 AR9300_11NA_RT_HT_TS_OFFSET, chainmask); 529 ar9300_init_rate_txpower_stbc(ah, rt, is40, 530 AR9300_11NA_RT_HT_SS_OFFSET, 531 AR9300_11NA_RT_HT_DS_OFFSET, 532 AR9300_11NA_RT_HT_TS_OFFSET, chainmask); 533 /* For FCC the array gain has to be factored for CDD mode */ 534 if (is_reg_dmn_fcc(chan->conformance_test_limit)) { 535 ar9300_adjust_rate_txpower_cdd(ah, rt, is40, 536 AR9300_11NA_RT_HT_SS_OFFSET, 537 AR9300_11NA_RT_HT_DS_OFFSET, 538 AR9300_11NA_RT_HT_TS_OFFSET, chainmask); 539 } 540 break; 541 case HAL_MODE_11G: 542 ar9300_init_rate_txpower_cck(ah, rt, power_per_rate, chainmask); 543 ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate, 544 AR9300_11G_RT_OFDM_OFFSET, chainmask); 545 break; 546 case HAL_MODE_11B: 547 ar9300_init_rate_txpower_cck(ah, rt, power_per_rate, chainmask); 548 break; 549 case HAL_MODE_11NG_HT20: 550 case HAL_MODE_11NG_HT40PLUS: 551 case HAL_MODE_11NG_HT40MINUS: 552 ar9300_init_rate_txpower_cck(ah, rt, power_per_rate, chainmask); 553 ar9300_init_rate_txpower_ofdm(ah, rt, power_per_rate, 554 AR9300_11NG_RT_OFDM_OFFSET, chainmask); 555 ar9300_init_rate_txpower_ht(ah, rt, is40, power_per_rate, 556 AR9300_11NG_RT_HT_SS_OFFSET, 557 AR9300_11NG_RT_HT_DS_OFFSET, 558 AR9300_11NG_RT_HT_TS_OFFSET, chainmask); 559 ar9300_init_rate_txpower_stbc(ah, rt, is40, 560 AR9300_11NG_RT_HT_SS_OFFSET, 561 AR9300_11NG_RT_HT_DS_OFFSET, 562 AR9300_11NG_RT_HT_TS_OFFSET, chainmask); 563 /* For FCC the array gain needs to be factored for CDD mode */ 564 if (is_reg_dmn_fcc(chan->conformance_test_limit)) { 565 ar9300_adjust_rate_txpower_cdd(ah, rt, is40, 566 AR9300_11NG_RT_HT_SS_OFFSET, 567 AR9300_11NG_RT_HT_DS_OFFSET, 568 AR9300_11NG_RT_HT_TS_OFFSET, chainmask); 569 } 570 break; 571 default: 572 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid mode 0x%x\n", 573 __func__, mode); 574 HALASSERT(0); 575 break; 576 } 577 578} 579 580static inline void 581ar9300_init_rate_txpower_cck(struct ath_hal *ah, const HAL_RATE_TABLE *rt, 582 u_int8_t rates_array[], u_int8_t chainmask) 583{ 584 struct ath_hal_9300 *ahp = AH9300(ah); 585 /* 586 * Pick the lower of the long-preamble txpower, and short-preamble tx power. 587 * Unfortunately, the rate table doesn't have separate entries for these!. 588 */ 589 switch (chainmask) { 590 case OSPREY_1_CHAINMASK: 591 ahp->txpower[0][0] = rates_array[ALL_TARGET_LEGACY_1L_5L]; 592 ahp->txpower[1][0] = rates_array[ALL_TARGET_LEGACY_1L_5L]; 593 ahp->txpower[2][0] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L], 594 rates_array[ALL_TARGET_LEGACY_5S]); 595 ahp->txpower[3][0] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L], 596 rates_array[ALL_TARGET_LEGACY_11S]); 597 break; 598 case OSPREY_2LOHI_CHAINMASK: 599 case OSPREY_2LOMID_CHAINMASK: 600 ahp->txpower[0][1] = rates_array[ALL_TARGET_LEGACY_1L_5L]; 601 ahp->txpower[1][1] = rates_array[ALL_TARGET_LEGACY_1L_5L]; 602 ahp->txpower[2][1] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L], 603 rates_array[ALL_TARGET_LEGACY_5S]); 604 ahp->txpower[3][1] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L], 605 rates_array[ALL_TARGET_LEGACY_11S]); 606 break; 607 case OSPREY_3_CHAINMASK: 608 ahp->txpower[0][2] = rates_array[ALL_TARGET_LEGACY_1L_5L]; 609 ahp->txpower[1][2] = rates_array[ALL_TARGET_LEGACY_1L_5L]; 610 ahp->txpower[2][2] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L], 611 rates_array[ALL_TARGET_LEGACY_5S]); 612 ahp->txpower[3][2] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L], 613 rates_array[ALL_TARGET_LEGACY_11S]); 614 break; 615 default: 616 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n", 617 __func__, chainmask); 618 break; 619 } 620} 621 622static inline void 623ar9300_init_rate_txpower_ofdm(struct ath_hal *ah, const HAL_RATE_TABLE *rt, 624 u_int8_t rates_array[], int rt_offset, 625 u_int8_t chainmask) 626{ 627 struct ath_hal_9300 *ahp = AH9300(ah); 628 int16_t twice_array_gain, cdd_power = 0; 629 int i, j; 630 u_int8_t ofdm_rt_2_pwr_idx[8] = 631 { 632 ALL_TARGET_LEGACY_6_24, 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_36, 638 ALL_TARGET_LEGACY_48, 639 ALL_TARGET_LEGACY_54, 640 }; 641 642 /* 643 * For FCC adjust the upper limit for CDD factoring in the array gain. 644 * The array gain is the same as TxBF, hence reuse the same defines. 645 */ 646 for (i = rt_offset; i < rt_offset + AR9300_NUM_OFDM_RATES; i++) { 647 648 /* Get the correct OFDM rate to Power table Index */ 649 j = ofdm_rt_2_pwr_idx[i- rt_offset]; 650 651 switch (chainmask) { 652 case OSPREY_1_CHAINMASK: 653 ahp->txpower[i][0] = rates_array[j]; 654 break; 655 case OSPREY_2LOHI_CHAINMASK: 656 case OSPREY_2LOMID_CHAINMASK: 657 ahp->txpower[i][1] = rates_array[j]; 658 if (is_reg_dmn_fcc(ahp->reg_dmn)){ 659 twice_array_gain = (ahp->twice_antenna_gain >= 660 ahp->twice_antenna_reduction)? 661 -(AR9300_TXBF_2TX_ARRAY_GAIN) : 662 ((int16_t)AH_MIN((ahp->twice_antenna_reduction - 663 (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0)); 664 cdd_power = ahp->upper_limit[1] + twice_array_gain; 665 if (ahp->txpower[i][1] > cdd_power){ 666 ahp->txpower[i][1] = cdd_power; 667 } 668 } 669 break; 670 case OSPREY_3_CHAINMASK: 671 ahp->txpower[i][2] = rates_array[j]; 672 if (is_reg_dmn_fcc(ahp->reg_dmn)) { 673 twice_array_gain = 674 (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)? 675 -(AR9300_TXBF_3TX_ARRAY_GAIN): 676 ((int16_t)AH_MIN((ahp->twice_antenna_reduction - 677 (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0)); 678 cdd_power = ahp->upper_limit[2] + twice_array_gain; 679 if (ahp->txpower[i][2] > cdd_power){ 680 ahp->txpower[i][2] = cdd_power; 681 } 682 } 683 break; 684 default: 685 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n", 686 __func__, chainmask); 687 break; 688 } 689 } 690} 691 692static u_int8_t mcs_rate_2_pwr_idx_ht20[24] = 693 { 694 ALL_TARGET_HT20_0_8_16, 695 ALL_TARGET_HT20_1_3_9_11_17_19, 696 ALL_TARGET_HT20_1_3_9_11_17_19, 697 ALL_TARGET_HT20_1_3_9_11_17_19, 698 ALL_TARGET_HT20_4, 699 ALL_TARGET_HT20_5, 700 ALL_TARGET_HT20_6, 701 ALL_TARGET_HT20_7, 702 ALL_TARGET_HT20_0_8_16, 703 ALL_TARGET_HT20_1_3_9_11_17_19, 704 ALL_TARGET_HT20_1_3_9_11_17_19, 705 ALL_TARGET_HT20_1_3_9_11_17_19, 706 ALL_TARGET_HT20_12, 707 ALL_TARGET_HT20_13, 708 ALL_TARGET_HT20_14, 709 ALL_TARGET_HT20_15, 710 ALL_TARGET_HT20_0_8_16, 711 ALL_TARGET_HT20_1_3_9_11_17_19, 712 ALL_TARGET_HT20_1_3_9_11_17_19, 713 ALL_TARGET_HT20_1_3_9_11_17_19, 714 ALL_TARGET_HT20_20, 715 ALL_TARGET_HT20_21, 716 ALL_TARGET_HT20_22, 717 ALL_TARGET_HT20_23 718 }; 719 720static u_int8_t mcs_rate_2_pwr_idx_ht40[24] = 721 { 722 ALL_TARGET_HT40_0_8_16, 723 ALL_TARGET_HT40_1_3_9_11_17_19, 724 ALL_TARGET_HT40_1_3_9_11_17_19, 725 ALL_TARGET_HT40_1_3_9_11_17_19, 726 ALL_TARGET_HT40_4, 727 ALL_TARGET_HT40_5, 728 ALL_TARGET_HT40_6, 729 ALL_TARGET_HT40_7, 730 ALL_TARGET_HT40_0_8_16, 731 ALL_TARGET_HT40_1_3_9_11_17_19, 732 ALL_TARGET_HT40_1_3_9_11_17_19, 733 ALL_TARGET_HT40_1_3_9_11_17_19, 734 ALL_TARGET_HT40_12, 735 ALL_TARGET_HT40_13, 736 ALL_TARGET_HT40_14, 737 ALL_TARGET_HT40_15, 738 ALL_TARGET_HT40_0_8_16, 739 ALL_TARGET_HT40_1_3_9_11_17_19, 740 ALL_TARGET_HT40_1_3_9_11_17_19, 741 ALL_TARGET_HT40_1_3_9_11_17_19, 742 ALL_TARGET_HT40_20, 743 ALL_TARGET_HT40_21, 744 ALL_TARGET_HT40_22, 745 ALL_TARGET_HT40_23, 746 }; 747 748static inline void 749ar9300_init_rate_txpower_ht(struct ath_hal *ah, const HAL_RATE_TABLE *rt, 750 HAL_BOOL is40, 751 u_int8_t rates_array[], 752 int rt_ss_offset, int rt_ds_offset, 753 int rt_ts_offset, u_int8_t chainmask) 754{ 755 756 struct ath_hal_9300 *ahp = AH9300(ah); 757 int i, j; 758 u_int8_t mcs_index = 0; 759 760 761 for (i = rt_ss_offset; i < rt_ss_offset + AR9300_NUM_HT_SS_RATES; i++) { 762 /* Get the correct MCS rate to Power table Index */ 763 j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] : 764 mcs_rate_2_pwr_idx_ht20[mcs_index]; 765 switch (chainmask) { 766 case OSPREY_1_CHAINMASK: 767 ahp->txpower[i][0] = rates_array[j]; 768 break; 769 case OSPREY_2LOHI_CHAINMASK: 770 case OSPREY_2LOMID_CHAINMASK: 771 ahp->txpower[i][1] = rates_array[j]; 772 break; 773 case OSPREY_3_CHAINMASK: 774 ahp->txpower[i][2] = rates_array[j]; 775 break; 776 default: 777 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n", 778 __func__, chainmask); 779 break; 780 } 781 mcs_index++; 782 } 783 784 for (i = rt_ds_offset; i < rt_ds_offset + AR9300_NUM_HT_DS_RATES; i++) { 785 /* Get the correct MCS rate to Power table Index */ 786 j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] : 787 mcs_rate_2_pwr_idx_ht20[mcs_index]; 788 switch (chainmask) { 789 case OSPREY_1_CHAINMASK: 790 ahp->txpower[i][0] = rates_array[j]; 791 break; 792 case OSPREY_2LOHI_CHAINMASK: 793 case OSPREY_2LOMID_CHAINMASK: 794 ahp->txpower[i][1] = rates_array[j]; 795 break; 796 case OSPREY_3_CHAINMASK: 797 ahp->txpower[i][2] = rates_array[j]; 798 break; 799 default: 800 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n", 801 __func__, chainmask); 802 break; 803 } 804 mcs_index++; 805 } 806 807 for (i = rt_ts_offset; i < rt_ts_offset + AR9300_NUM_HT_TS_RATES; i++) { 808 /* Get the correct MCS rate to Power table Index */ 809 j = (is40) ? mcs_rate_2_pwr_idx_ht40[mcs_index] : 810 mcs_rate_2_pwr_idx_ht20[mcs_index]; 811 switch (chainmask) { 812 case OSPREY_1_CHAINMASK: 813 ahp->txpower[i][0] = rates_array[j]; 814 break; 815 case OSPREY_2LOHI_CHAINMASK: 816 case OSPREY_2LOMID_CHAINMASK: 817 ahp->txpower[i][1] = rates_array[j]; 818 break; 819 case OSPREY_3_CHAINMASK: 820 ahp->txpower[i][2] = rates_array[j]; 821 break; 822 default: 823 HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n", 824 __func__, chainmask); 825 break; 826 } 827 mcs_index++; 828 } 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 HAL_CHANNEL_INTERNAL *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_PRIVATE(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].rate_code, rt->info[i].rateKbps, 1066 j + 1, txpower[j] / 2, txpower[j]%2 * 5); 1067 } 1068 } 1069 ath_hal_printf(ah, "\n"); 1070 1071 1072 ath_hal_printf(ah, "\n\n===TARGET POWER TABLE with STBC===\n"); 1073 for ( j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) { 1074 for (i = 0; i < rt->rateCount; i++) { 1075 int16_t txpower[AR9300_MAX_CHAINS]; 1076 txpower[j] = ahp->txpower_stbc[i][j]; 1077 1078 /* Do not display invalid configurations */ 1079 if ((rt->info[i].rate_code < AR9300_MCS0_RATE_CODE) || 1080 (rt->info[i].rate_code > AR9300_MCS23_RATE_CODE) || 1081 ar9300_invalid_stbc_cfg(j, rt->info[i].rate_code) == AH_TRUE) { 1082 continue; 1083 } 1084 1085 ath_hal_printf(ah, " Index[%2d] Rate[0x%02x] %6d kbps " 1086 "Power (%d Chain) [%2d.%1d dBm]\n", 1087 i, rt->info[i].rate_code, rt->info[i].rateKbps, 1088 j + 1, txpower[j] / 2, txpower[j]%2 * 5); 1089 } 1090 } 1091 ath_hal_printf(ah, "\n"); 1092} 1093 1094/* 1095 * The followings are customer specific APIs for querying power limit. 1096 * Power limit is based on regulatory domain, chipset, and transmission rate. 1097 * Here we only consider EEPROM values, no array gain/CTL considered here. 1098 */ 1099 1100struct rate_power_tbl { 1101 u_int8_t rateIdx; /* rate index in the rate table */ 1102 u_int32_t rateKbps; /* transfer rate in kbs */ 1103 u_int8_t rateCode; /* rate for h/w descriptors */ 1104 u_int8_t txbf: 1, /* txbf eligible */ 1105 stbc: 1, /* stbc eligible */ 1106 chain1: 1, /* one-chain eligible */ 1107 chain2: 1, /* two-chain eligible */ 1108 chain3: 1; /* three-chain eligible */ 1109 int16_t txpower[AR9300_MAX_CHAINS]; /* txpower for different chainmasks */ 1110 int16_t txpower_stbc[AR9300_MAX_CHAINS]; 1111}; 1112 1113u_int8_t *ar9300_get_tpc_tables(struct ath_hal *ah) 1114{ 1115 struct ath_hal_9300 *ahp = AH9300(ah); 1116 HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; 1117 u_int mode = ath_hal_get_curmode(ah, chan); 1118 const HAL_RATE_TABLE *rt; 1119 u_int8_t *data; 1120 struct rate_power_tbl *table; 1121 int i, j; 1122 1123 /* Check whether TPC is enabled */ 1124 if (!AH_PRIVATE(ah)->ah_config.ath_hal_desc_tpc) { 1125 ath_hal_printf(ah, "\n TPC Register method in use\n"); 1126 return NULL; 1127 } 1128 1129 rt = ar9300_get_rate_table(ah, mode); 1130 HALASSERT(rt != NULL); 1131 1132 data = (u_int8_t *)ath_hal_malloc(ah, 1133 1 + rt->rateCount * sizeof(struct rate_power_tbl)); 1134 if (data == NULL) 1135 return NULL; 1136 1137 OS_MEMZERO(data, 1 + rt->rateCount * sizeof(struct rate_power_tbl)); 1138 /* store the rate count at the beginning */ 1139 *data = rt->rateCount; 1140 table = (struct rate_power_tbl *)&data[1]; 1141 1142 for (j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) { 1143 for (i = 0; i < rt->rateCount; i++) { 1144 table[i].rateIdx = i; 1145 table[i].rateCode = rt->info[i].rate_code; 1146 table[i].rateKbps = rt->info[i].rateKbps; 1147 switch (j) { 1148 case 0: 1149 table[i].chain1 = rt->info[i].rate_code <= 0x87 ? 1 : 0; 1150 break; 1151 case 1: 1152 table[i].chain2 = rt->info[i].rate_code <= 0x8f ? 1 : 0; 1153 break; 1154 case 2: 1155 table[i].chain3 = 1; 1156 break; 1157 default: 1158 break; 1159 } 1160 if ((j == 0 && table[i].chain1) || 1161 (j == 1 && table[i].chain2) || 1162 (j == 2 && table[i].chain3)) 1163 table[i].txpower[j] = ahp->txpower[i][j]; 1164 } 1165 } 1166 1167 1168 for ( j = 0 ; j < ar9300_get_ntxchains(ahp->ah_tx_chainmask) ; j++ ) { 1169 for (i = 0; i < rt->rateCount; i++) { 1170 /* Do not display invalid configurations */ 1171 if ((rt->info[i].rate_code < AR9300_MCS0_RATE_CODE) || 1172 (rt->info[i].rate_code > AR9300_MCS23_RATE_CODE) || 1173 ar9300_invalid_stbc_cfg(j, rt->info[i].rate_code) == AH_TRUE) { 1174 continue; 1175 } 1176 1177 table[i].stbc = 1; 1178 table[i].txpower_stbc[j] = ahp->txpower_stbc[i][j]; 1179 } 1180 } 1181 1182 return data; 1183 /* the caller is responsible to free data */ 1184} 1185 1186HAL_STATUS 1187ath_hal_get_rate_power_limit_from_eeprom(struct ath_hal *ah, u_int16_t freq, 1188 int8_t *max_rate_power, int8_t *min_rate_power) 1189{ 1190 /* 1191 * Used for AR9300 series chip only 1192 */ 1193 if (AH_PRIVATE(ah)->ah_magic == AR9300_MAGIC) { 1194 u_int8_t target_rate_power_limit_val_t2[ar9300_rate_size]; 1195 int i; 1196 1197 *max_rate_power = 0; 1198 *min_rate_power = AR9300_MAX_RATE_POWER; 1199 1200 ar9300_set_target_power_from_eeprom(ah, freq, target_rate_power_limit_val_t2); 1201 1202 for (i=0; i<ar9300_rate_size; i++) { 1203 if (target_rate_power_limit_val_t2[i] > *max_rate_power) 1204 *max_rate_power = target_rate_power_limit_val_t2[i]; 1205 if (target_rate_power_limit_val_t2[i] < *min_rate_power) 1206 *min_rate_power = target_rate_power_limit_val_t2[i]; 1207 } 1208 } else { 1209 *max_rate_power = 0; 1210 *min_rate_power = 0; 1211 } 1212 1213 return HAL_OK; 1214} 1215#endif /* AH_SUPPORT_AR9300 */ 1216