xref: /freebsd/sys/gnu/dev/bwn/phy_n/if_bwn_phy_n_ppr.c (revision 076ad2f8)
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 #include <dev/siba/siba_ids.h>
64 #include <dev/siba/sibareg.h>
65 #include <dev/siba/sibavar.h>
66 
67 #include <net80211/ieee80211_var.h>
68 #include <net80211/ieee80211_radiotap.h>
69 #include <net80211/ieee80211_regdomain.h>
70 #include <net80211/ieee80211_phy.h>
71 #include <net80211/ieee80211_ratectl.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_ppr.h>
81 
82 #define ppr_for_each_entry(ppr, i, entry)				\
83 	for (i = 0, entry = &(ppr)->__all_rates[i];			\
84 	     i < BWN_PPR_RATES_NUM;					\
85 	     i++, entry++)
86 
87 void bwn_ppr_clear(struct bwn_mac *mac, struct bwn_ppr *ppr)
88 {
89 	memset(ppr, 0, sizeof(*ppr));
90 
91 	/* Compile-time PPR check */
92 	CTASSERT(sizeof(struct bwn_ppr) == BWN_PPR_RATES_NUM * sizeof(uint8_t));
93 }
94 
95 void bwn_ppr_add(struct bwn_mac *mac, struct bwn_ppr *ppr, int diff)
96 {
97 	int i;
98 	uint8_t *rate;
99 
100 	ppr_for_each_entry(ppr, i, rate) {
101 		*rate = bwn_clamp_val(*rate + diff, 0, 127);
102 	}
103 }
104 
105 void bwn_ppr_apply_max(struct bwn_mac *mac, struct bwn_ppr *ppr, uint8_t max)
106 {
107 	int i;
108 	uint8_t *rate;
109 
110 	ppr_for_each_entry(ppr, i, rate) {
111 		*rate = min(*rate, max);
112 	}
113 }
114 
115 void bwn_ppr_apply_min(struct bwn_mac *mac, struct bwn_ppr *ppr, uint8_t min)
116 {
117 	int i;
118 	uint8_t *rate;
119 
120 	ppr_for_each_entry(ppr, i, rate) {
121 		*rate = max(*rate, min);
122 	}
123 }
124 
125 uint8_t bwn_ppr_get_max(struct bwn_mac *mac, struct bwn_ppr *ppr)
126 {
127 	uint8_t res = 0;
128 	int i;
129 	uint8_t *rate;
130 
131 	ppr_for_each_entry(ppr, i, rate) {
132 		res = max(*rate, res);
133 	}
134 
135 	return res;
136 }
137 
138 bool bwn_ppr_load_max_from_sprom(struct bwn_mac *mac, struct bwn_ppr *ppr,
139 				 bwn_phy_band_t band)
140 {
141 	struct bwn_softc *sc = mac->mac_sc;
142 	struct siba_sprom_core_pwr_info core_pwr_info[4];
143 	struct bwn_ppr_rates *rates = &ppr->rates;
144 	struct bwn_phy *phy = &mac->mac_phy;
145 	uint8_t maxpwr, off;
146 	uint32_t sprom_ofdm_po;
147 	uint16_t sprom_mcs_po[8];
148 	uint8_t extra_cdd_po, extra_stbc_po;
149 	int i;
150 
151 	for (i = 0; i < 4; i++) {
152 		bzero(&core_pwr_info[i], sizeof(core_pwr_info[i]));
153 		if (siba_sprom_get_core_power_info(sc->sc_dev, i,
154 		    &core_pwr_info[i]) != 0) {
155 			BWN_ERRPRINTF(mac->mac_sc,
156 			    "%s: failed to get core_pwr_info for core %d\n",
157 			    __func__,
158 			    i);
159 		}
160 	}
161 
162 	switch (band) {
163 	case BWN_PHY_BAND_2G:
164 		maxpwr = min(core_pwr_info[0].maxpwr_2g,
165 			     core_pwr_info[1].maxpwr_2g);
166 		sprom_ofdm_po = siba_sprom_get_ofdm2gpo(sc->sc_dev);
167 		siba_sprom_get_mcs2gpo(sc->sc_dev, sprom_mcs_po);
168 		extra_cdd_po = (siba_sprom_get_cddpo(sc->sc_dev) >> 0) & 0xf;
169 		extra_stbc_po = (siba_sprom_get_stbcpo(sc->sc_dev) >> 0) & 0xf;
170 		break;
171 	case BWN_PHY_BAND_5G_LO:
172 		maxpwr = min(core_pwr_info[0].maxpwr_5gl,
173 			     core_pwr_info[1].maxpwr_5gl);
174 		sprom_ofdm_po = siba_sprom_get_ofdm5glpo(sc->sc_dev);
175 		siba_sprom_get_mcs5glpo(sc->sc_dev, sprom_mcs_po);
176 		extra_cdd_po = (siba_sprom_get_cddpo(sc->sc_dev) >> 8) & 0xf;
177 		extra_stbc_po = (siba_sprom_get_stbcpo(sc->sc_dev) >> 8) & 0xf;
178 		break;
179 	case BWN_PHY_BAND_5G_MI:
180 		maxpwr = min(core_pwr_info[0].maxpwr_5g,
181 			     core_pwr_info[1].maxpwr_5g);
182 		sprom_ofdm_po = siba_sprom_get_ofdm5gpo(sc->sc_dev);
183 		siba_sprom_get_mcs5gpo(sc->sc_dev, sprom_mcs_po);
184 		extra_cdd_po = (siba_sprom_get_cddpo(sc->sc_dev) >> 4) & 0xf;
185 		extra_stbc_po = (siba_sprom_get_stbcpo(sc->sc_dev) >> 4) & 0xf;
186 		break;
187 	case BWN_PHY_BAND_5G_HI:
188 		maxpwr = min(core_pwr_info[0].maxpwr_5gh,
189 			     core_pwr_info[1].maxpwr_5gh);
190 		sprom_ofdm_po = siba_sprom_get_ofdm5ghpo(sc->sc_dev);
191 		siba_sprom_get_mcs5ghpo(sc->sc_dev, sprom_mcs_po);
192 		extra_cdd_po = (siba_sprom_get_cddpo(sc->sc_dev) >> 12) & 0xf;
193 		extra_stbc_po = (siba_sprom_get_stbcpo(sc->sc_dev) >> 12) & 0xf;
194 		break;
195 	default:
196 		device_printf(mac->mac_sc->sc_dev, "%s: invalid band (%d)\n",
197 		    __func__,
198 		    band);
199 		return false;
200 	}
201 
202 	if (band == BWN_BAND_2G) {
203 		for (i = 0; i < 4; i++) {
204 			off = ((siba_sprom_get_cck2gpo(sc->sc_dev) >> (i * 4)) & 0xf) * 2;
205 			rates->cck[i] = maxpwr - off;
206 		}
207 	}
208 
209 	/* OFDM */
210 	for (i = 0; i < 8; i++) {
211 		off = ((sprom_ofdm_po >> (i * 4)) & 0xf) * 2;
212 		rates->ofdm[i] = maxpwr - off;
213 	}
214 
215 	/* MCS 20 SISO */
216 	rates->mcs_20[0] = rates->ofdm[0];
217 	rates->mcs_20[1] = rates->ofdm[2];
218 	rates->mcs_20[2] = rates->ofdm[3];
219 	rates->mcs_20[3] = rates->ofdm[4];
220 	rates->mcs_20[4] = rates->ofdm[5];
221 	rates->mcs_20[5] = rates->ofdm[6];
222 	rates->mcs_20[6] = rates->ofdm[7];
223 	rates->mcs_20[7] = rates->ofdm[7];
224 
225 	/* MCS 20 CDD */
226 	for (i = 0; i < 4; i++) {
227 		off = ((sprom_mcs_po[0] >> (i * 4)) & 0xf) * 2;
228 		rates->mcs_20_cdd[i] = maxpwr - off;
229 		if (phy->type == BWN_PHYTYPE_N && phy->rev >= 3)
230 			rates->mcs_20_cdd[i] -= extra_cdd_po;
231 	}
232 	for (i = 0; i < 4; i++) {
233 		off = ((sprom_mcs_po[1] >> (i * 4)) & 0xf) * 2;
234 		rates->mcs_20_cdd[4 + i] = maxpwr - off;
235 		if (phy->type == BWN_PHYTYPE_N && phy->rev >= 3)
236 			rates->mcs_20_cdd[4 + i] -= extra_cdd_po;
237 	}
238 
239 	/* OFDM 20 CDD */
240 	rates->ofdm_20_cdd[0] = rates->mcs_20_cdd[0];
241 	rates->ofdm_20_cdd[1] = rates->mcs_20_cdd[0];
242 	rates->ofdm_20_cdd[2] = rates->mcs_20_cdd[1];
243 	rates->ofdm_20_cdd[3] = rates->mcs_20_cdd[2];
244 	rates->ofdm_20_cdd[4] = rates->mcs_20_cdd[3];
245 	rates->ofdm_20_cdd[5] = rates->mcs_20_cdd[4];
246 	rates->ofdm_20_cdd[6] = rates->mcs_20_cdd[5];
247 	rates->ofdm_20_cdd[7] = rates->mcs_20_cdd[6];
248 
249 	/* MCS 20 STBC */
250 	for (i = 0; i < 4; i++) {
251 		off = ((sprom_mcs_po[0] >> (i * 4)) & 0xf) * 2;
252 		rates->mcs_20_stbc[i] = maxpwr - off;
253 		if (phy->type == BWN_PHYTYPE_N && phy->rev >= 3)
254 			rates->mcs_20_stbc[i] -= extra_stbc_po;
255 	}
256 	for (i = 0; i < 4; i++) {
257 		off = ((sprom_mcs_po[1] >> (i * 4)) & 0xf) * 2;
258 		rates->mcs_20_stbc[4 + i] = maxpwr - off;
259 		if (phy->type == BWN_PHYTYPE_N && phy->rev >= 3)
260 			rates->mcs_20_stbc[4 + i] -= extra_stbc_po;
261 	}
262 
263 	/* MCS 20 SDM */
264 	for (i = 0; i < 4; i++) {
265 		off = ((sprom_mcs_po[2] >> (i * 4)) & 0xf) * 2;
266 		rates->mcs_20_sdm[i] = maxpwr - off;
267 	}
268 	for (i = 0; i < 4; i++) {
269 		off = ((sprom_mcs_po[3] >> (i * 4)) & 0xf) * 2;
270 		rates->mcs_20_sdm[4 + i] = maxpwr - off;
271 	}
272 
273 	return true;
274 }
275