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
bwn_ppr_clear(struct bwn_mac * mac,struct bwn_ppr * ppr)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
bwn_ppr_add(struct bwn_mac * mac,struct bwn_ppr * ppr,int diff)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
bwn_ppr_apply_max(struct bwn_mac * mac,struct bwn_ppr * ppr,uint8_t max)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
bwn_ppr_apply_min(struct bwn_mac * mac,struct bwn_ppr * ppr,uint8_t min)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
bwn_ppr_get_max(struct bwn_mac * mac,struct bwn_ppr * ppr)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
bwn_ppr_load_max_from_sprom(struct bwn_mac * mac,struct bwn_ppr * ppr,bwn_phy_band_t band)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