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