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