1 /* 2 3 Broadcom B43 wireless driver 4 IEEE 802.11n PHY data tables 5 6 Copyright (c) 2008 Michael Buesch <m@bues.ch> 7 Copyright (c) 2010 Rafał Miłecki <zajec5@gmail.com> 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 2 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; see the file COPYING. If not, write to 21 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, 22 Boston, MA 02110-1301, USA. 23 24 */ 25 26 #include <sys/cdefs.h> 27 /* 28 * The Broadcom Wireless LAN controller driver. 29 */ 30 #include "opt_wlan.h" 31 #include "opt_bwn.h" 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/kernel.h> 36 #include <sys/malloc.h> 37 #include <sys/module.h> 38 #include <sys/endian.h> 39 #include <sys/errno.h> 40 #include <sys/firmware.h> 41 #include <sys/lock.h> 42 #include <sys/mutex.h> 43 #include <machine/bus.h> 44 #include <machine/resource.h> 45 #include <sys/bus.h> 46 #include <sys/rman.h> 47 #include <sys/socket.h> 48 #include <sys/sockio.h> 49 50 #include <net/ethernet.h> 51 #include <net/if.h> 52 #include <net/if_var.h> 53 #include <net/if_arp.h> 54 #include <net/if_dl.h> 55 #include <net/if_llc.h> 56 #include <net/if_media.h> 57 #include <net/if_types.h> 58 59 #include <dev/pci/pcivar.h> 60 #include <dev/pci/pcireg.h> 61 62 #include <net80211/ieee80211_var.h> 63 #include <net80211/ieee80211_radiotap.h> 64 #include <net80211/ieee80211_regdomain.h> 65 #include <net80211/ieee80211_phy.h> 66 #include <net80211/ieee80211_ratectl.h> 67 68 #include <dev/bhnd/bhnd.h> 69 #include <dev/bhnd/cores/pmu/bhnd_pmu.h> 70 71 #include <dev/bwn/if_bwnreg.h> 72 #include <dev/bwn/if_bwnvar.h> 73 #include <dev/bwn/if_bwn_debug.h> 74 #include <dev/bwn/if_bwn_util.h> 75 #include <dev/bwn/if_bwn_phy_common.h> 76 77 #include <gnu/dev/bwn/phy_n/if_bwn_phy_n_regs.h> 78 #include <gnu/dev/bwn/phy_n/if_bwn_phy_n_sprom.h> 79 #include <gnu/dev/bwn/phy_n/if_bwn_phy_n_ppr.h> 80 81 #include "bhnd_nvram_map.h" 82 83 #define ppr_for_each_entry(ppr, i, entry) \ 84 for (i = 0, entry = &(ppr)->__all_rates[i]; \ 85 i < BWN_PPR_RATES_NUM; \ 86 i++, entry++) 87 88 void bwn_ppr_clear(struct bwn_mac *mac, struct bwn_ppr *ppr) 89 { 90 memset(ppr, 0, sizeof(*ppr)); 91 92 /* Compile-time PPR check */ 93 CTASSERT(sizeof(struct bwn_ppr) == BWN_PPR_RATES_NUM * sizeof(uint8_t)); 94 } 95 96 void bwn_ppr_add(struct bwn_mac *mac, struct bwn_ppr *ppr, int diff) 97 { 98 int i; 99 uint8_t *rate; 100 101 ppr_for_each_entry(ppr, i, rate) { 102 *rate = bwn_clamp_val(*rate + diff, 0, 127); 103 } 104 } 105 106 void bwn_ppr_apply_max(struct bwn_mac *mac, struct bwn_ppr *ppr, uint8_t max) 107 { 108 int i; 109 uint8_t *rate; 110 111 ppr_for_each_entry(ppr, i, rate) { 112 *rate = min(*rate, max); 113 } 114 } 115 116 void bwn_ppr_apply_min(struct bwn_mac *mac, struct bwn_ppr *ppr, uint8_t min) 117 { 118 int i; 119 uint8_t *rate; 120 121 ppr_for_each_entry(ppr, i, rate) { 122 *rate = max(*rate, min); 123 } 124 } 125 126 uint8_t bwn_ppr_get_max(struct bwn_mac *mac, struct bwn_ppr *ppr) 127 { 128 uint8_t res = 0; 129 int i; 130 uint8_t *rate; 131 132 ppr_for_each_entry(ppr, i, rate) { 133 res = max(*rate, res); 134 } 135 136 return res; 137 } 138 139 bool bwn_ppr_load_max_from_sprom(struct bwn_mac *mac, struct bwn_ppr *ppr, 140 bwn_phy_band_t band) 141 { 142 struct bwn_softc *sc = mac->mac_sc; 143 struct bwn_phy_n_core_pwr_info core_pwr_info[4]; 144 struct bwn_ppr_rates *rates = &ppr->rates; 145 struct bwn_phy *phy = &mac->mac_phy; 146 const char *var_ofdmgpo, *var_mcsgpo_prefix; 147 uint8_t maxpwr, off; 148 uint32_t sprom_ofdm_po; 149 uint16_t sprom_mcs_po[8]; 150 uint16_t cddpo, stbcpo; 151 uint8_t extra_cdd_po, extra_stbc_po; 152 int error; 153 int i; 154 155 for (i = 0; i < 4; i++) { 156 bzero(&core_pwr_info[i], sizeof(core_pwr_info[i])); 157 if (bwn_nphy_get_core_power_info(mac, i, 158 &core_pwr_info[i]) != 0) { 159 BWN_ERRPRINTF(mac->mac_sc, 160 "%s: failed to get core_pwr_info for core %d\n", 161 __func__, 162 i); 163 } 164 } 165 166 error = bhnd_nvram_getvar_uint16(sc->sc_dev, BHND_NVAR_CDDPO, &cddpo); 167 if (error) { 168 BWN_ERRPRINTF(mac->mac_sc, "NVRAM variable %s unreadable: %d\n", 169 BHND_NVAR_CDDPO, error); 170 return (false); 171 } 172 173 error = bhnd_nvram_getvar_uint16(sc->sc_dev, BHND_NVAR_STBCPO, &stbcpo); 174 if (error) { 175 BWN_ERRPRINTF(mac->mac_sc, "NVRAM variable %s unreadable: %d\n", 176 BHND_NVAR_STBCPO, error); 177 return (false); 178 } 179 180 switch (band) { 181 case BWN_PHY_BAND_2G: 182 maxpwr = min(core_pwr_info[0].maxpwr_2g, 183 core_pwr_info[1].maxpwr_2g); 184 185 var_ofdmgpo = BHND_NVAR_OFDM2GPO; 186 var_mcsgpo_prefix = "mcs2gpo"; 187 extra_cdd_po = (cddpo >> 0) & 0xf; 188 extra_stbc_po = (stbcpo >> 0) & 0xf; 189 break; 190 case BWN_PHY_BAND_5G_LO: 191 maxpwr = min(core_pwr_info[0].maxpwr_5gl, 192 core_pwr_info[1].maxpwr_5gl); 193 var_ofdmgpo = BHND_NVAR_OFDM5GLPO; 194 var_mcsgpo_prefix = "mcs5glpo"; 195 extra_cdd_po = (cddpo >> 8) & 0xf; 196 extra_stbc_po = (stbcpo >> 8) & 0xf; 197 break; 198 case BWN_PHY_BAND_5G_MI: 199 maxpwr = min(core_pwr_info[0].maxpwr_5g, 200 core_pwr_info[1].maxpwr_5g); 201 var_ofdmgpo = BHND_NVAR_OFDM5GPO; 202 var_mcsgpo_prefix = "mcs5gpo"; 203 extra_cdd_po = (cddpo >> 4) & 0xf; 204 extra_stbc_po = (stbcpo >> 4) & 0xf; 205 break; 206 case BWN_PHY_BAND_5G_HI: 207 maxpwr = min(core_pwr_info[0].maxpwr_5gh, 208 core_pwr_info[1].maxpwr_5gh); 209 var_ofdmgpo = BHND_NVAR_OFDM5GHPO; 210 var_mcsgpo_prefix = "mcs5ghpo"; 211 extra_cdd_po = (cddpo >> 12) & 0xf; 212 extra_stbc_po = (stbcpo >> 12) & 0xf; 213 break; 214 default: 215 device_printf(mac->mac_sc->sc_dev, "%s: invalid band (%d)\n", 216 __func__, 217 band); 218 return false; 219 } 220 221 error = bhnd_nvram_getvar_uint32(sc->sc_dev, var_ofdmgpo, 222 &sprom_ofdm_po); 223 if (error) { 224 device_printf(sc->sc_dev, "NVRAM variable %s unreadable: %d\n", 225 var_ofdmgpo, error); 226 return (false); 227 } 228 229 for (size_t i = 0; i < nitems(sprom_mcs_po); i++) { 230 char var[strlen(var_mcsgpo_prefix) + sizeof("XX")]; 231 int ret; 232 233 /* mcs[25]g[lh]?po[0-9] */ 234 ret = snprintf(var, sizeof(var), "%s%zu", var_mcsgpo_prefix, i); 235 if (ret >= sizeof(var)) { 236 device_printf(sc->sc_dev, "buffer too small for " 237 "%s%zu\n", var_mcsgpo_prefix, i); 238 return (false); 239 } 240 241 error = bhnd_nvram_getvar_uint16(sc->sc_dev, var, 242 &sprom_mcs_po[i]); 243 if (error) { 244 device_printf(sc->sc_dev, "NVRAM variable %s " 245 "unreadable: %d\n", var, error); 246 return (false); 247 } 248 } 249 250 if (band == BWN_BAND_2G) { 251 uint16_t ck2gpo; 252 253 error = bhnd_nvram_getvar_uint16(sc->sc_dev, BHND_NVAR_CCK2GPO, 254 &ck2gpo); 255 if (error) { 256 device_printf(sc->sc_dev, "NVRAM variable %s " 257 "unreadable: %d\n", BHND_NVAR_CCK2GPO, error); 258 return (false); 259 } 260 261 for (i = 0; i < 4; i++) { 262 off = ((ck2gpo >> (i * 4)) & 0xf) * 2; 263 rates->cck[i] = maxpwr - off; 264 } 265 } 266 267 /* OFDM */ 268 for (i = 0; i < 8; i++) { 269 off = ((sprom_ofdm_po >> (i * 4)) & 0xf) * 2; 270 rates->ofdm[i] = maxpwr - off; 271 } 272 273 /* MCS 20 SISO */ 274 rates->mcs_20[0] = rates->ofdm[0]; 275 rates->mcs_20[1] = rates->ofdm[2]; 276 rates->mcs_20[2] = rates->ofdm[3]; 277 rates->mcs_20[3] = rates->ofdm[4]; 278 rates->mcs_20[4] = rates->ofdm[5]; 279 rates->mcs_20[5] = rates->ofdm[6]; 280 rates->mcs_20[6] = rates->ofdm[7]; 281 rates->mcs_20[7] = rates->ofdm[7]; 282 283 /* MCS 20 CDD */ 284 for (i = 0; i < 4; i++) { 285 off = ((sprom_mcs_po[0] >> (i * 4)) & 0xf) * 2; 286 rates->mcs_20_cdd[i] = maxpwr - off; 287 if (phy->type == BWN_PHYTYPE_N && phy->rev >= 3) 288 rates->mcs_20_cdd[i] -= extra_cdd_po; 289 } 290 for (i = 0; i < 4; i++) { 291 off = ((sprom_mcs_po[1] >> (i * 4)) & 0xf) * 2; 292 rates->mcs_20_cdd[4 + i] = maxpwr - off; 293 if (phy->type == BWN_PHYTYPE_N && phy->rev >= 3) 294 rates->mcs_20_cdd[4 + i] -= extra_cdd_po; 295 } 296 297 /* OFDM 20 CDD */ 298 rates->ofdm_20_cdd[0] = rates->mcs_20_cdd[0]; 299 rates->ofdm_20_cdd[1] = rates->mcs_20_cdd[0]; 300 rates->ofdm_20_cdd[2] = rates->mcs_20_cdd[1]; 301 rates->ofdm_20_cdd[3] = rates->mcs_20_cdd[2]; 302 rates->ofdm_20_cdd[4] = rates->mcs_20_cdd[3]; 303 rates->ofdm_20_cdd[5] = rates->mcs_20_cdd[4]; 304 rates->ofdm_20_cdd[6] = rates->mcs_20_cdd[5]; 305 rates->ofdm_20_cdd[7] = rates->mcs_20_cdd[6]; 306 307 /* MCS 20 STBC */ 308 for (i = 0; i < 4; i++) { 309 off = ((sprom_mcs_po[0] >> (i * 4)) & 0xf) * 2; 310 rates->mcs_20_stbc[i] = maxpwr - off; 311 if (phy->type == BWN_PHYTYPE_N && phy->rev >= 3) 312 rates->mcs_20_stbc[i] -= extra_stbc_po; 313 } 314 for (i = 0; i < 4; i++) { 315 off = ((sprom_mcs_po[1] >> (i * 4)) & 0xf) * 2; 316 rates->mcs_20_stbc[4 + i] = maxpwr - off; 317 if (phy->type == BWN_PHYTYPE_N && phy->rev >= 3) 318 rates->mcs_20_stbc[4 + i] -= extra_stbc_po; 319 } 320 321 /* MCS 20 SDM */ 322 for (i = 0; i < 4; i++) { 323 off = ((sprom_mcs_po[2] >> (i * 4)) & 0xf) * 2; 324 rates->mcs_20_sdm[i] = maxpwr - off; 325 } 326 for (i = 0; i < 4; i++) { 327 off = ((sprom_mcs_po[3] >> (i * 4)) & 0xf) * 2; 328 rates->mcs_20_sdm[4 + i] = maxpwr - off; 329 } 330 331 return true; 332 } 333