xref: /netbsd-src/sys/dev/ic/bwfm.c (revision 6cf13ecd855d2c3fc71aaaf1ceaa21bada988fa1)
1 /* $NetBSD: bwfm.c,v 1.36 2023/12/31 21:32:43 gutteridge Exp $ */
2 /* $OpenBSD: bwfm.c,v 1.5 2017/10/16 22:27:16 patrick Exp $ */
3 /*
4  * Copyright (c) 2010-2016 Broadcom Corporation
5  * Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se>
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/param.h>
21 #include <sys/types.h>
22 
23 #include <sys/buf.h>
24 #include <sys/device.h>
25 #include <sys/kernel.h>
26 #include <sys/kmem.h>
27 #include <sys/pool.h>
28 #include <sys/queue.h>
29 #include <sys/socket.h>
30 #include <sys/systm.h>
31 #include <sys/workqueue.h>
32 
33 #include <net/bpf.h>
34 #include <net/if.h>
35 #include <net/if_dl.h>
36 #include <net/if_ether.h>
37 #include <net/if_media.h>
38 
39 #include <netinet/in.h>
40 
41 #include <net80211/ieee80211_var.h>
42 
43 #include <dev/firmload.h>
44 
45 #include <dev/ic/bwfmreg.h>
46 #include <dev/ic/bwfmvar.h>
47 
48 /* #define BWFM_DEBUG */
49 #ifdef BWFM_DEBUG
50 #define DPRINTF(x)	do { if (bwfm_debug > 0) printf x; } while (0)
51 #define DPRINTFN(n, x)	do { if (bwfm_debug >= (n)) printf x; } while (0)
52 static int bwfm_debug = 1;
53 #else
54 #define DPRINTF(x)	do { ; } while (0)
55 #define DPRINTFN(n, x)	do { ; } while (0)
56 #endif
57 
58 #define DEVNAME(sc)	device_xname((sc)->sc_dev)
59 
60 void	 bwfm_start(struct ifnet *);
61 int	 bwfm_init(struct ifnet *);
62 void	 bwfm_stop(struct ifnet *, int);
63 void	 bwfm_watchdog(struct ifnet *);
64 int	 bwfm_ioctl(struct ifnet *, u_long, void *);
65 int	 bwfm_media_change(struct ifnet *);
66 
67 int	 bwfm_send_mgmt(struct ieee80211com *, struct ieee80211_node *,
68 	     int, int);
69 void	 bwfm_recv_mgmt(struct ieee80211com *, struct mbuf *,
70 	     struct ieee80211_node *, int, int, uint32_t);
71 int	 bwfm_key_set(struct ieee80211com *, const struct ieee80211_key *,
72 	     const uint8_t[IEEE80211_ADDR_LEN]);
73 int	 bwfm_key_delete(struct ieee80211com *, const struct ieee80211_key *);
74 int	 bwfm_newstate(struct ieee80211com *, enum ieee80211_state, int);
75 void	 bwfm_newstate_cb(struct bwfm_softc *, struct bwfm_cmd_newstate *);
76 void	 bwfm_newassoc(struct ieee80211_node *, int);
77 void	 bwfm_task(struct work *, void *);
78 
79 int	 bwfm_chip_attach(struct bwfm_softc *);
80 int	 bwfm_chip_detach(struct bwfm_softc *, int);
81 struct bwfm_core *bwfm_chip_get_core(struct bwfm_softc *, int);
82 struct bwfm_core *bwfm_chip_get_pmu(struct bwfm_softc *);
83 int	 bwfm_chip_ai_isup(struct bwfm_softc *, struct bwfm_core *);
84 void	 bwfm_chip_ai_disable(struct bwfm_softc *, struct bwfm_core *,
85 	     uint32_t, uint32_t);
86 void	 bwfm_chip_ai_reset(struct bwfm_softc *, struct bwfm_core *,
87 	     uint32_t, uint32_t, uint32_t);
88 void	 bwfm_chip_dmp_erom_scan(struct bwfm_softc *);
89 int	 bwfm_chip_dmp_get_regaddr(struct bwfm_softc *, uint32_t *,
90 	     uint32_t *, uint32_t *);
91 int	 bwfm_chip_cr4_set_active(struct bwfm_softc *, const uint32_t);
92 void	 bwfm_chip_cr4_set_passive(struct bwfm_softc *);
93 int	 bwfm_chip_ca7_set_active(struct bwfm_softc *, const uint32_t);
94 void	 bwfm_chip_ca7_set_passive(struct bwfm_softc *);
95 int	 bwfm_chip_cm3_set_active(struct bwfm_softc *);
96 void	 bwfm_chip_cm3_set_passive(struct bwfm_softc *);
97 void	 bwfm_chip_socram_ramsize(struct bwfm_softc *, struct bwfm_core *);
98 void	 bwfm_chip_sysmem_ramsize(struct bwfm_softc *, struct bwfm_core *);
99 void	 bwfm_chip_tcm_ramsize(struct bwfm_softc *, struct bwfm_core *);
100 void	 bwfm_chip_tcm_rambase(struct bwfm_softc *);
101 
102 void     bwfm_process_blob(struct bwfm_softc *, const char *, uint8_t **,
103 	     size_t *);
104 int	 bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *, int,
105 	     int, char *, size_t *);
106 int	 bwfm_proto_bcdc_set_dcmd(struct bwfm_softc *, int,
107 	     int, char *, size_t);
108 
109 int	 bwfm_fwvar_cmd_get_data(struct bwfm_softc *, int, void *, size_t);
110 int	 bwfm_fwvar_cmd_set_data(struct bwfm_softc *, int, void *, size_t);
111 int	 bwfm_fwvar_cmd_get_int(struct bwfm_softc *, int, uint32_t *);
112 int	 bwfm_fwvar_cmd_set_int(struct bwfm_softc *, int, uint32_t);
113 int	 bwfm_fwvar_var_get_data(struct bwfm_softc *, const char *, void *, size_t);
114 int	 bwfm_fwvar_var_set_data(struct bwfm_softc *, const char *, void *, size_t);
115 int	 bwfm_fwvar_var_get_int(struct bwfm_softc *, const char *, uint32_t *);
116 int	 bwfm_fwvar_var_set_int(struct bwfm_softc *, const char *, uint32_t);
117 
118 struct ieee80211_channel *bwfm_bss2chan(struct bwfm_softc *, struct bwfm_bss_info *);
119 void	 bwfm_scan(struct bwfm_softc *);
120 void	 bwfm_connect(struct bwfm_softc *);
121 void	 bwfm_get_sta_info(struct bwfm_softc *, struct ifmediareq *);
122 
123 void	 bwfm_rx(struct bwfm_softc *, struct mbuf *);
124 void	 bwfm_rx_event(struct bwfm_softc *, struct mbuf *);
125 void	 bwfm_rx_event_cb(struct bwfm_softc *, struct mbuf *);
126 void	 bwfm_scan_node(struct bwfm_softc *, struct bwfm_bss_info *, size_t);
127 
128 static const uint8_t bwfm_2ghz_channels[] = {
129 	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
130 };
131 static const uint8_t bwfm_5ghz_channels[] = {
132 	34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64, 100, 104, 108, 112,
133 	116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165,
134 };
135 
136 const struct bwfm_proto_ops bwfm_proto_bcdc_ops = {
137 	.proto_query_dcmd = bwfm_proto_bcdc_query_dcmd,
138 	.proto_set_dcmd = bwfm_proto_bcdc_set_dcmd,
139 };
140 
141 static const struct {
142 	const char *suffix;
143 	const char *description;
144 } bwfm_firmware_filetypes[] = {
145 	[BWFM_FILETYPE_UCODE] = {
146 		.suffix = "bin",
147 		.description = "Firmware",
148 	},
149 	[BWFM_FILETYPE_NVRAM] = {
150 		.suffix = "txt",
151 		.description = "NVRAM",
152 	},
153 	[BWFM_FILETYPE_CLM] = {
154 		.suffix = "clm_blob",
155 		.description = "CLM",
156 	},
157 	[BWFM_FILETYPE_TXCAP] = {
158 		.suffix = "txcap_blob",
159 		.description = "TXCAP",
160 	},
161 	[BWFM_FILETYPE_CAL] = {
162 		.suffix = "cal_blob",
163 		.description = "CAL",
164 	},
165 };
166 
167 static void
bwfm_firmware_read_file(struct bwfm_softc * const sc,const struct bwfm_firmware_selector * const fwp,struct bwfm_firmware_context * const ctx,unsigned int const which)168 bwfm_firmware_read_file(struct bwfm_softc * const sc,
169     const struct bwfm_firmware_selector * const fwp,
170     struct bwfm_firmware_context * const ctx,
171     unsigned int const which)
172 {
173 	firmware_handle_t fwh;
174 	char *names[2];
175 	int i, error;
176 
177 	names[1] = kmem_asprintf("%s.%s", fwp->fwsel_basename,
178 	    bwfm_firmware_filetypes[which].suffix);
179 	names[0] = ctx->ctx_model ? kmem_asprintf("%s.%s.%s",
180 	    fwp->fwsel_basename, ctx->ctx_model,
181 	    bwfm_firmware_filetypes[which].suffix) : NULL;
182 
183 	aprint_verbose_dev(sc->sc_dev, "%s file default:    %s\n",
184 	    bwfm_firmware_filetypes[which].description, names[1]);
185 	if (names[0]) {
186 		aprint_verbose_dev(sc->sc_dev, "%s file model-spec: %s\n",
187 		    bwfm_firmware_filetypes[which].description, names[0]);
188 	}
189 
190 	for (i = 0; i < 2; i++) {
191 		if (names[i] == NULL)
192 			continue;
193 		error = firmware_open("if_bwfm", names[i], &fwh);
194 		if (error == 0)
195 			break;
196 	}
197 	if (i == 2)
198 		goto out;
199 
200 	aprint_verbose_dev(sc->sc_dev, "Found %s file: %s\n",
201 	    bwfm_firmware_filetypes[which].description, names[i]);
202 
203 	size_t size = firmware_get_size(fwh);
204 	void *data = firmware_malloc(size);
205 	if (data == NULL) {
206 		aprint_error_dev(sc->sc_dev,
207 		    "unable to allocate %zu bytes for %s image\n", size,
208 		    bwfm_firmware_filetypes[which].description);
209 		firmware_close(fwh);
210 		goto out;
211 	}
212 	error = firmware_read(fwh, 0, data, size);
213 	firmware_close(fwh);
214 	if (error) {
215 		aprint_error_dev(sc->sc_dev,
216 		    "failed to read %s file, error %d\n",
217 		    bwfm_firmware_filetypes[which].description,
218 		    error);
219 		firmware_free(data, size);
220 		goto out;
221 	}
222 
223 	ctx->ctx_file[which].ctx_f_data = data;
224 	ctx->ctx_file[which].ctx_f_size = size;
225  out:
226 	for (i = 0; i < 2; i++) {
227 		if (names[i])
228 			kmem_free(names[i], strlen(names[i])+1);
229 	}
230 }
231 
232 void
bwfm_firmware_context_init(struct bwfm_firmware_context * const ctx,uint32_t const chip,uint32_t const chiprev,const char * const model,uint32_t req)233 bwfm_firmware_context_init(struct bwfm_firmware_context * const ctx,
234     uint32_t const chip, uint32_t const chiprev, const char * const model,
235     uint32_t req)
236 {
237 	memset(ctx, 0, sizeof(*ctx));
238 	ctx->ctx_chip = chip;
239 	ctx->ctx_chiprev = chiprev;
240 	ctx->ctx_model = model;
241 
242 	/* all devices require ucode */
243 	ctx->ctx_req = req | BWFM_FWREQ(BWFM_FILETYPE_UCODE);
244 }
245 
246 bool
bwfm_firmware_open(struct bwfm_softc * const sc,const struct bwfm_firmware_selector * const fwtab,struct bwfm_firmware_context * const ctx)247 bwfm_firmware_open(struct bwfm_softc * const sc,
248     const struct bwfm_firmware_selector * const fwtab,
249     struct bwfm_firmware_context * const ctx)
250 {
251 	const struct bwfm_firmware_selector *fwp;
252 	unsigned int i;
253 
254 	KASSERT(fwtab != NULL);
255 	KASSERT(ctx != NULL);
256 
257 	/* First locate the appropriate entry for this chip / rev. */
258 	for (fwp = fwtab; fwp->fwsel_basename != NULL; fwp++) {
259 		if (fwp->fwsel_chip == ctx->ctx_chip &&
260 		    fwp->fwsel_revmask & __BIT(ctx->ctx_chiprev))
261 		    	break;
262 	}
263 	if (fwp->fwsel_basename == NULL) {
264 		aprint_error_dev(sc->sc_dev,
265 		    "No firmware entry for chip 0x%x/%u rev %u model %s\n",
266 		    ctx->ctx_chip, ctx->ctx_chip, ctx->ctx_chiprev,
267 		    ctx->ctx_model);
268 		return false;
269 	}
270 
271 	bool rv = true;
272 
273 	/*
274 	 * Read in each file that the front-end has requested as
275 	 * either required or optional.
276 	 */
277 	for (i = 0; i < BWFM_NFILETYPES; i++) {
278 		if (ctx->ctx_req & (BWFM_FWREQ(i) | BWFM_FWOPT(i)))
279 			bwfm_firmware_read_file(sc, fwp, ctx, i);
280 		if ((ctx->ctx_req & BWFM_FWREQ(i)) &&
281 		    ctx->ctx_file[i].ctx_f_data == NULL) {
282 			aprint_error_dev(sc->sc_dev,
283 			    "%s file not available\n",
284 			    bwfm_firmware_filetypes[i].description);
285 			rv = false;
286 		}
287 	}
288 
289 	if (rv == false)
290 		bwfm_firmware_close(ctx);
291 
292 	return rv;
293 }
294 
295 void
bwfm_firmware_close(struct bwfm_firmware_context * const ctx)296 bwfm_firmware_close(struct bwfm_firmware_context * const ctx)
297 {
298 	for (int i = 0; i < BWFM_NFILETYPES; i++) {
299 		if (ctx->ctx_file[i].ctx_f_data == NULL)
300 			continue;
301 		firmware_free(ctx->ctx_file[i].ctx_f_data,
302 			      ctx->ctx_file[i].ctx_f_size);
303 		ctx->ctx_file[i].ctx_f_data = NULL;
304 	}
305 }
306 
307 void *
bwfm_firmware_data(struct bwfm_firmware_context * const ctx,unsigned int const which,size_t * sizep)308 bwfm_firmware_data(struct bwfm_firmware_context * const ctx,
309     unsigned int const which, size_t *sizep)
310 {
311 	KASSERT(which < BWFM_NFILETYPES);
312 	KASSERT(sizep != NULL);
313 
314 	*sizep = ctx->ctx_file[which].ctx_f_size;
315 	return ctx->ctx_file[which].ctx_f_data;
316 }
317 
318 const char *
bwfm_firmware_description(unsigned int const which)319 bwfm_firmware_description(unsigned int const which)
320 {
321 	KASSERT(which < BWFM_NFILETYPES);
322 
323 	return bwfm_firmware_filetypes[which].description;
324 }
325 
326 void
bwfm_attach(struct bwfm_softc * sc)327 bwfm_attach(struct bwfm_softc *sc)
328 {
329 	struct ieee80211com *ic = &sc->sc_ic;
330 	struct ifnet *ifp = &sc->sc_if;
331 	char fw_version[BWFM_DCMD_SMLEN];
332 	uint32_t bandlist[3];
333 	int nmode, vhtmode;
334 	uint32_t tmp;
335 	int i, j, error;
336 
337 	error = workqueue_create(&sc->sc_taskq, DEVNAME(sc),
338 	    bwfm_task, sc, PRI_NONE, IPL_NET, 0);
339 	if (error != 0) {
340 		printf("%s: could not create workqueue\n", DEVNAME(sc));
341 		return;
342 	}
343 	sc->sc_freetask = pool_cache_init(sizeof(struct bwfm_task), 0, 0, 0,
344 	    "bwfmtask", NULL, IPL_NET /* XXX IPL_SOFTNET? */,
345 	    NULL, NULL, NULL);
346 	pool_cache_prime(sc->sc_freetask, BWFM_TASK_COUNT);
347 
348 	/* Stop the device in case it was previously initialized */
349 	bwfm_fwvar_cmd_set_int(sc, BWFM_C_DOWN, 1);
350 
351 	if (bwfm_fwvar_cmd_get_int(sc, BWFM_C_GET_VERSION, &tmp)) {
352 		printf("%s: could not read io type\n", DEVNAME(sc));
353 		return;
354 	} else
355 		sc->sc_io_type = tmp;
356 	if (bwfm_fwvar_var_get_data(sc, "cur_etheraddr", ic->ic_myaddr,
357 	    sizeof(ic->ic_myaddr))) {
358 		printf("%s: could not read mac address\n", DEVNAME(sc));
359 		return;
360 	}
361 
362 	printf("%s: address %s\n", DEVNAME(sc), ether_sprintf(ic->ic_myaddr));
363 
364 	bwfm_process_blob(sc, "clmload", &sc->sc_clm, &sc->sc_clmsize);
365 	bwfm_process_blob(sc, "txcapload", &sc->sc_txcap, &sc->sc_txcapsize);
366 	bwfm_process_blob(sc, "calload", &sc->sc_cal, &sc->sc_calsize);
367 
368 	memset(fw_version, 0, sizeof(fw_version));
369 	if (bwfm_fwvar_var_get_data(sc, "ver", fw_version, sizeof(fw_version)) == 0)
370 		printf("%s: %s", DEVNAME(sc), fw_version);
371 
372 	ic->ic_ifp = ifp;
373 	ic->ic_phytype = IEEE80211_T_OFDM;
374 	ic->ic_opmode = IEEE80211_M_STA;
375 	ic->ic_state = IEEE80211_S_INIT;
376 
377 	ic->ic_caps =
378 	    IEEE80211_C_WEP |
379 	    IEEE80211_C_TKIP |
380 	    IEEE80211_C_AES |
381 	    IEEE80211_C_AES_CCM |
382 	    IEEE80211_C_PMGT |
383 #if notyet
384 	    IEEE80211_C_MONITOR |		/* monitor mode supported */
385 	    IEEE80211_C_IBSS |
386 	    IEEE80211_C_TXPMGT |
387 	    IEEE80211_C_WME |
388 #endif
389 	    IEEE80211_C_SHSLOT |		/* short slot time supported */
390 	    IEEE80211_C_SHPREAMBLE |		/* short preamble supported */
391 	    IEEE80211_C_WPA |			/* 802.11i */
392 	    /* IEEE80211_C_WPA_4WAY */0;		/* WPA 4-way handshake in hw */
393 
394 	/* IBSS channel undefined for now. */
395 	ic->ic_ibss_chan = &ic->ic_channels[0];
396 
397 	if (bwfm_fwvar_var_get_int(sc, "nmode", &nmode))
398 		nmode = 0;
399 	if (bwfm_fwvar_var_get_int(sc, "vhtmode", &vhtmode))
400 		vhtmode = 0;
401 	if (bwfm_fwvar_cmd_get_data(sc, BWFM_C_GET_BANDLIST, bandlist,
402 	    sizeof(bandlist))) {
403 		printf("%s: couldn't get supported band list\n", DEVNAME(sc));
404 		return;
405 	}
406 	const u_int nbands = le32toh(bandlist[0]);
407 	for (i = 1; i <= MIN(nbands, __arraycount(bandlist) - 1); i++) {
408 		switch (le32toh(bandlist[i])) {
409 		case BWFM_BAND_2G:
410 			ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
411 			ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
412 
413 			for (j = 0; j < __arraycount(bwfm_2ghz_channels); j++) {
414 				uint8_t chan = bwfm_2ghz_channels[j];
415 				ic->ic_channels[chan].ic_freq =
416 				    ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ);
417 				ic->ic_channels[chan].ic_flags =
418 				    IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
419 				    IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
420 				if (nmode)
421 					ic->ic_channels[chan].ic_flags |=
422 					    IEEE80211_CHAN_HT;
423 			}
424 			break;
425 		case BWFM_BAND_5G:
426 			ic->ic_sup_rates[IEEE80211_MODE_11A] = ieee80211_std_rateset_11a;
427 
428 			for (j = 0; j < __arraycount(bwfm_5ghz_channels); j++) {
429 				uint8_t chan = bwfm_5ghz_channels[j];
430 				ic->ic_channels[chan].ic_freq =
431 				    ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ);
432 				ic->ic_channels[chan].ic_flags =
433 				    IEEE80211_CHAN_A;
434 				if (nmode)
435 					ic->ic_channels[chan].ic_flags |=
436 					    IEEE80211_CHAN_HT;
437 				if (vhtmode)
438 					ic->ic_channels[chan].ic_flags |=
439 					    IEEE80211_CHAN_VHT;
440 			}
441 			break;
442 		default:
443 			printf("%s: unsupported band 0x%x\n", DEVNAME(sc),
444 			    le32toh(bandlist[i]));
445 			break;
446 		}
447 	}
448 
449 	ifp->if_softc = sc;
450 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
451 	ifp->if_init = bwfm_init;
452 	ifp->if_ioctl = bwfm_ioctl;
453 	ifp->if_start = bwfm_start;
454 	ifp->if_stop = bwfm_stop;
455 	ifp->if_watchdog = bwfm_watchdog;
456 	IFQ_SET_READY(&ifp->if_snd);
457 	memcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
458 
459 	if_initialize(ifp);
460 	ieee80211_ifattach(ic);
461 	sc->sc_newstate = ic->ic_newstate;
462 	ic->ic_newstate = bwfm_newstate;
463 	ic->ic_newassoc = bwfm_newassoc;
464 	ic->ic_send_mgmt = bwfm_send_mgmt;
465 	ic->ic_recv_mgmt = bwfm_recv_mgmt;
466 	ic->ic_crypto.cs_key_set = bwfm_key_set;
467 	ic->ic_crypto.cs_key_delete = bwfm_key_delete;
468 
469 	ifp->if_percpuq = if_percpuq_create(ifp);
470 	if_deferred_start_init(ifp, NULL);
471 	if_register(ifp);
472 	ieee80211_media_init(ic, bwfm_media_change, ieee80211_media_status);
473 
474 	ieee80211_announce(ic);
475 
476 	sc->sc_if_attached = true;
477 }
478 
479 int
bwfm_detach(struct bwfm_softc * sc,int flags)480 bwfm_detach(struct bwfm_softc *sc, int flags)
481 {
482 	struct ieee80211com *ic = &sc->sc_ic;
483 	struct ifnet *ifp = ic->ic_ifp;
484 
485 	if (sc->sc_if_attached) {
486 		bpf_detach(ifp);
487 		ieee80211_ifdetach(ic);
488 		if_detach(ifp);
489 	}
490 
491 	if (sc->sc_taskq)
492 		workqueue_destroy(sc->sc_taskq);
493 	if (sc->sc_freetask)
494 		pool_cache_destroy(sc->sc_freetask);
495 
496 	return 0;
497 }
498 
499 void
bwfm_start(struct ifnet * ifp)500 bwfm_start(struct ifnet *ifp)
501 {
502 	struct bwfm_softc *sc = ifp->if_softc;
503 	struct ieee80211com *ic = &sc->sc_ic;
504 	struct mbuf *m;
505 	int error;
506 
507 	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
508 		return;
509 
510 	/* TODO: return if no link? */
511 
512 	if (sc->sc_setpm) {
513 		sc->sc_setpm = false;
514 		if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, sc->sc_pm))
515 			printf("%s: could not set power\n", DEVNAME(sc));
516 	}
517 
518 	for (;;) {
519 		/* Discard management packets (fw handles this for us) */
520 		IF_DEQUEUE(&ic->ic_mgtq, m);
521 		if (m != NULL) {
522 			m_freem(m);
523 			continue;
524 		}
525 
526 		if (sc->sc_bus_ops->bs_txcheck(sc)) {
527 			ifp->if_flags |= IFF_OACTIVE;
528 			break;
529 		}
530 
531 		IFQ_DEQUEUE(&ifp->if_snd, m);
532 		if (m == NULL)
533 			break;
534 
535 		error = sc->sc_bus_ops->bs_txdata(sc, &m);
536 		if (error == ENOBUFS) {
537 			IF_PREPEND(&ifp->if_snd, m);
538 			ifp->if_flags |= IFF_OACTIVE;
539 			break;
540 		}
541 		if (error != 0) {
542 			if_statinc(ifp, if_oerrors);
543 			m_freem(m);
544 			continue;
545 		}
546 
547 		bpf_mtap(ifp, m, BPF_D_OUT);
548 	}
549 }
550 
551 int
bwfm_init(struct ifnet * ifp)552 bwfm_init(struct ifnet *ifp)
553 {
554 	struct bwfm_softc *sc = ifp->if_softc;
555 	struct ieee80211com *ic = &sc->sc_ic;
556 	uint8_t evmask[BWFM_EVENT_MASK_LEN];
557 	struct bwfm_join_pref_params join_pref[2];
558 
559 	if (bwfm_fwvar_var_set_int(sc, "mpc", 1)) {
560 		printf("%s: could not set mpc\n", DEVNAME(sc));
561 		return EIO;
562 	}
563 
564 	/* Select target by RSSI (boost on 5GHz) */
565 	join_pref[0].type = BWFM_JOIN_PREF_RSSI_DELTA;
566 	join_pref[0].len = 2;
567 	join_pref[0].rssi_gain = BWFM_JOIN_PREF_RSSI_BOOST;
568 	join_pref[0].band = BWFM_JOIN_PREF_BAND_5G;
569 	join_pref[1].type = BWFM_JOIN_PREF_RSSI;
570 	join_pref[1].len = 2;
571 	join_pref[1].rssi_gain = 0;
572 	join_pref[1].band = 0;
573 	if (bwfm_fwvar_var_set_data(sc, "join_pref", join_pref,
574 	    sizeof(join_pref))) {
575 		printf("%s: could not set join pref\n", DEVNAME(sc));
576 		return EIO;
577 	}
578 
579 	memset(evmask, 0, sizeof(evmask));
580 
581 #define	ENABLE_EVENT(e)		evmask[(e) / 8] |= 1 << ((e) % 8)
582 	/* Events used to drive the state machine */
583 	switch (ic->ic_opmode) {
584 	case IEEE80211_M_STA:
585 		ENABLE_EVENT(BWFM_E_IF);
586 		ENABLE_EVENT(BWFM_E_LINK);
587 		ENABLE_EVENT(BWFM_E_AUTH);
588 		ENABLE_EVENT(BWFM_E_ASSOC);
589 		ENABLE_EVENT(BWFM_E_DEAUTH);
590 		ENABLE_EVENT(BWFM_E_DISASSOC);
591 		ENABLE_EVENT(BWFM_E_SET_SSID);
592 		ENABLE_EVENT(BWFM_E_ESCAN_RESULT);
593 		break;
594 #ifndef IEEE80211_STA_ONLY
595 	case IEEE80211_M_HOSTAP:
596 		ENABLE_EVENT(BWFM_E_AUTH_IND);
597 		ENABLE_EVENT(BWFM_E_ASSOC_IND);
598 		ENABLE_EVENT(BWFM_E_REASSOC_IND);
599 		ENABLE_EVENT(BWFM_E_DEAUTH_IND);
600 		ENABLE_EVENT(BWFM_E_DISASSOC_IND);
601 		ENABLE_EVENT(BWFM_E_ESCAN_RESULT);
602 		ENABLE_EVENT(BWFM_E_ESCAN_RESULT);
603 		break;
604 #endif
605 	default:
606 		break;
607 	}
608 #undef	ENABLE_EVENT
609 
610 #ifdef BWFM_DEBUG
611 	memset(evmask, 0xff, sizeof(evmask));
612 #endif
613 
614 	if (bwfm_fwvar_var_set_data(sc, "event_msgs", evmask, sizeof(evmask))) {
615 		printf("%s: could not set event mask\n", DEVNAME(sc));
616 		return EIO;
617 	}
618 
619 	if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_CHANNEL_TIME,
620 	    BWFM_DEFAULT_SCAN_CHANNEL_TIME)) {
621 		printf("%s: could not set scan channel time\n", DEVNAME(sc));
622 		return EIO;
623 	}
624 	if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_UNASSOC_TIME,
625 	    BWFM_DEFAULT_SCAN_UNASSOC_TIME)) {
626 		printf("%s: could not set scan unassoc time\n", DEVNAME(sc));
627 		return EIO;
628 	}
629 	if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_PASSIVE_TIME,
630 	    BWFM_DEFAULT_SCAN_PASSIVE_TIME)) {
631 		printf("%s: could not set scan passive time\n", DEVNAME(sc));
632 		return EIO;
633 	}
634 
635 	/*
636 	 * Use CAM (constantly awake) when we are running as AP
637 	 * otherwise use fast power saving.
638 	 */
639 	if (ic->ic_flags & IEEE80211_F_PMGTON) {
640 		sc->sc_pm = BWFM_PM_FAST_PS;
641 #ifndef IEEE80211_STA_ONLY
642 		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
643 			sc->sc_pm = BWFM_PM_CAM;
644 #endif
645 	} else {
646 		sc->sc_pm = BWFM_PM_CAM;
647 	}
648 	sc->sc_setpm = true;
649 
650 	bwfm_fwvar_var_set_int(sc, "txbf", 1);
651 	bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 0);
652 	bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 1);
653 	bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 0);
654 
655 	/* Disable all offloading (ARP, NDP, TCP/UDP cksum). */
656 	bwfm_fwvar_var_set_int(sc, "arp_ol", 0);
657 	bwfm_fwvar_var_set_int(sc, "arpoe", 0);
658 	bwfm_fwvar_var_set_int(sc, "ndoe", 0);
659 	bwfm_fwvar_var_set_int(sc, "toe", 0);
660 
661 	/* Accept all multicast frames. */
662 	bwfm_fwvar_var_set_int(sc, "allmulti", 1);
663 
664 	/* Setup promiscuous mode */
665 	bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PROMISC,
666 	    (ifp->if_flags & IFF_PROMISC) ? 1 : 0);
667 
668 	/*
669 	 * Tell the firmware supplicant that we are going to handle the
670 	 * WPA handshake ourselves.
671 	 */
672 	bwfm_fwvar_var_set_int(sc, "sup_wpa", 0);
673 
674 	ifp->if_flags |= IFF_RUNNING;
675 	ifp->if_flags &= ~IFF_OACTIVE;
676 
677 	if (ic->ic_opmode != IEEE80211_M_MONITOR) {
678 		if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL)
679 			ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
680 	} else {
681 		ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
682 	}
683 
684 	return 0;
685 }
686 
687 void
bwfm_stop(struct ifnet * ifp,int disable)688 bwfm_stop(struct ifnet *ifp, int disable)
689 {
690 	struct bwfm_softc *sc = ifp->if_softc;
691 	struct ieee80211com *ic = &sc->sc_ic;
692 	struct bwfm_join_params join;
693 
694 	sc->sc_tx_timer = 0;
695 	ifp->if_timer = 0;
696 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
697 
698 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
699 
700 	memset(&join, 0, sizeof(join));
701 	bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID, &join, sizeof(join));
702 	bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, 0);
703 	bwfm_fwvar_cmd_set_int(sc, BWFM_C_DOWN, 1);
704 	bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 0);
705 	bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 0);
706 	bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 1);
707 	bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, BWFM_PM_FAST_PS);
708 	bwfm_fwvar_var_set_int(sc, "mpc", 1);
709 
710 	if (sc->sc_bus_ops->bs_stop)
711 		sc->sc_bus_ops->bs_stop(sc);
712 
713 	sc->sc_setpm = true;
714 }
715 
716 void
bwfm_watchdog(struct ifnet * ifp)717 bwfm_watchdog(struct ifnet *ifp)
718 {
719 	struct bwfm_softc *sc = ifp->if_softc;
720 	struct ieee80211com *ic = &sc->sc_ic;
721 
722 	ifp->if_timer = 0;
723 
724 	if (sc->sc_tx_timer > 0) {
725 		if (--sc->sc_tx_timer == 0) {
726 			printf("%s: device timeout\n", DEVNAME(sc));
727 			if_statinc(ifp, if_oerrors);
728 			return;
729 		}
730 		ifp->if_timer = 1;
731 	}
732 	ieee80211_watchdog(ic);
733 }
734 
735 int
bwfm_ioctl(struct ifnet * ifp,u_long cmd,void * data)736 bwfm_ioctl(struct ifnet *ifp, u_long cmd, void *data)
737 {
738 	struct bwfm_softc *sc = ifp->if_softc;
739 	struct ieee80211com *ic = &sc->sc_ic;
740 	int s, error = 0, oflags;
741 
742 	s = splnet();
743 
744 	switch (cmd) {
745 	case SIOCSIFFLAGS:
746 		oflags = ifp->if_flags;
747 		if ((error = ifioctl_common(ifp, cmd, data)) != 0)
748 			break;
749 		switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
750 		case IFF_UP | IFF_RUNNING:
751 			break;
752 		case IFF_UP:
753 			if ((oflags & IFF_UP) == 0)
754 				bwfm_init(ifp);
755 			break;
756 		case IFF_RUNNING:
757 			if ((oflags & IFF_UP) != 0)
758 				bwfm_stop(ifp, 1);
759 			break;
760 		case 0:
761 			break;
762 		}
763 		break;
764 
765 	case SIOCADDMULTI:
766 	case SIOCDELMULTI:
767 		if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) {
768 			/* setup multicast filter, etc */
769 			error = 0;
770 		}
771 		break;
772 
773 	case SIOCGIFMEDIA:
774 		error = ieee80211_ioctl(ic, cmd, data);
775 		if (error == 0 && ic->ic_state == IEEE80211_S_RUN)
776 			bwfm_get_sta_info(sc, (struct ifmediareq *)data);
777 		break;
778 
779 	default:
780 		error = ieee80211_ioctl(ic, cmd, data);
781 	}
782 
783 	if (error == ENETRESET) {
784 		if ((ifp->if_flags & IFF_UP) != 0 &&
785 		    (ifp->if_flags & IFF_RUNNING) != 0) {
786 			bwfm_init(ifp);
787 		}
788 		error = 0;
789 	}
790 
791 	splx(s);
792 
793 	return error;
794 }
795 
796 int
bwfm_send_mgmt(struct ieee80211com * ic,struct ieee80211_node * ni,int type,int arg)797 bwfm_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
798     int type, int arg)
799 {
800 	return 0;
801 }
802 
803 void
bwfm_recv_mgmt(struct ieee80211com * ic,struct mbuf * m0,struct ieee80211_node * ni,int subtype,int rssi,uint32_t rstamp)804 bwfm_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
805     struct ieee80211_node *ni, int subtype, int rssi, uint32_t rstamp)
806 {
807 }
808 
809 int
bwfm_key_set(struct ieee80211com * ic,const struct ieee80211_key * wk,const uint8_t mac[IEEE80211_ADDR_LEN])810 bwfm_key_set(struct ieee80211com *ic, const struct ieee80211_key *wk,
811     const uint8_t mac[IEEE80211_ADDR_LEN])
812 {
813 	struct bwfm_softc *sc = ic->ic_ifp->if_softc;
814 	struct bwfm_task *t;
815 
816 	t = pool_cache_get(sc->sc_freetask, PR_NOWAIT);
817 	if (t == NULL) {
818 		printf("%s: no free tasks\n", DEVNAME(sc));
819 		return 0;
820 	}
821 
822 	t->t_sc = sc;
823 	t->t_cmd = BWFM_TASK_KEY_SET;
824 	t->t_key.key = wk;
825 	memcpy(t->t_key.mac, mac, sizeof(t->t_key.mac));
826 	workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL);
827 	return 1;
828 }
829 
830 static void
bwfm_key_set_cb(struct bwfm_softc * sc,struct bwfm_cmd_key * ck)831 bwfm_key_set_cb(struct bwfm_softc *sc, struct bwfm_cmd_key *ck)
832 {
833 	const struct ieee80211_key *wk = ck->key;
834 	const uint8_t *mac = ck->mac;
835 	struct bwfm_wsec_key wsec_key;
836 	uint32_t wsec_enable, wsec;
837 	bool ext_key;
838 
839 #ifdef BWFM_DEBUG
840 	printf("key_set: key cipher %s len %d: ", wk->wk_cipher->ic_name, wk->wk_keylen);
841 	for (int j = 0; j < sizeof(wk->wk_key); j++)
842 		printf("%02x", wk->wk_key[j]);
843 #endif
844 
845 	if ((wk->wk_flags & IEEE80211_KEY_GROUP) == 0 &&
846 	    wk->wk_cipher->ic_cipher != IEEE80211_CIPHER_WEP) {
847 		ext_key = true;
848 	} else {
849 		ext_key = false;
850 	}
851 
852 #ifdef BWFM_DEBUG
853 	printf(", ext_key = %d", ext_key);
854 	printf(", mac = %02x:%02x:%02x:%02x:%02x:%02x",
855 	    mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
856 	printf("\n");
857 #endif
858 
859 	memset(&wsec_key, 0, sizeof(wsec_key));
860 	if (ext_key && !IEEE80211_IS_MULTICAST(mac))
861 		memcpy(wsec_key.ea, mac, sizeof(wsec_key.ea));
862 	wsec_key.index = htole32(wk->wk_keyix);
863 	wsec_key.len = htole32(wk->wk_keylen);
864 	memcpy(wsec_key.data, wk->wk_key, sizeof(wsec_key.data));
865 	if (!ext_key)
866 		wsec_key.flags = htole32(BWFM_WSEC_PRIMARY_KEY);
867 
868 	switch (wk->wk_cipher->ic_cipher) {
869 	case IEEE80211_CIPHER_WEP:
870 		if (wk->wk_keylen == 5)
871 			wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_WEP1);
872 		else if (wk->wk_keylen == 13)
873 			wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_WEP128);
874 		else
875 			return;
876 		wsec_enable = BWFM_WSEC_WEP;
877 		break;
878 	case IEEE80211_CIPHER_TKIP:
879 		wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_TKIP);
880 		wsec_enable = BWFM_WSEC_TKIP;
881 		break;
882 	case IEEE80211_CIPHER_AES_CCM:
883 		wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_AES_CCM);
884 		wsec_enable = BWFM_WSEC_AES;
885 		break;
886 	default:
887 		printf("%s: %s: cipher %s not supported\n", DEVNAME(sc),
888 		    __func__, wk->wk_cipher->ic_name);
889 		return;
890 	}
891 
892 	if (bwfm_fwvar_var_set_data(sc, "wsec_key", &wsec_key, sizeof(wsec_key)))
893 		return;
894 
895 	bwfm_fwvar_var_set_int(sc, "wpa_auth", BWFM_WPA_AUTH_WPA2_PSK);
896 
897 	bwfm_fwvar_var_get_int(sc, "wsec", &wsec);
898 	wsec |= wsec_enable;
899 	bwfm_fwvar_var_set_int(sc, "wsec", wsec);
900 }
901 
902 int
bwfm_key_delete(struct ieee80211com * ic,const struct ieee80211_key * wk)903 bwfm_key_delete(struct ieee80211com *ic, const struct ieee80211_key *wk)
904 {
905 	struct bwfm_softc *sc = ic->ic_ifp->if_softc;
906 	struct bwfm_task *t;
907 
908 	t = pool_cache_get(sc->sc_freetask, PR_NOWAIT);
909 	if (t == NULL) {
910 		printf("%s: no free tasks\n", DEVNAME(sc));
911 		return 0;
912 	}
913 
914 	t->t_sc = sc;
915 	t->t_cmd = BWFM_TASK_KEY_DELETE;
916 	t->t_key.key = wk;
917 	memset(t->t_key.mac, 0, sizeof(t->t_key.mac));
918 	workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL);
919 
920 	return 1;
921 }
922 
923 static void
bwfm_key_delete_cb(struct bwfm_softc * sc,struct bwfm_cmd_key * ck)924 bwfm_key_delete_cb(struct bwfm_softc *sc, struct bwfm_cmd_key *ck)
925 {
926 	const struct ieee80211_key *wk = ck->key;
927 	struct bwfm_wsec_key wsec_key;
928 
929 	memset(&wsec_key, 0, sizeof(wsec_key));
930 	wsec_key.index = htole32(wk->wk_keyix);
931 	wsec_key.flags = htole32(BWFM_WSEC_PRIMARY_KEY);
932 
933 	if (bwfm_fwvar_var_set_data(sc, "wsec_key", &wsec_key, sizeof(wsec_key)))
934 		return;
935 }
936 
937 int
bwfm_newstate(struct ieee80211com * ic,enum ieee80211_state nstate,int arg)938 bwfm_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
939 {
940 	struct bwfm_softc *sc = ic->ic_ifp->if_softc;
941 	struct bwfm_task *t;
942 
943 	t = pool_cache_get(sc->sc_freetask, PR_NOWAIT);
944 	if (t == NULL) {
945 		printf("%s: no free tasks\n", DEVNAME(sc));
946 		return EIO;
947 	}
948 
949 	t->t_sc = sc;
950 	t->t_cmd = BWFM_TASK_NEWSTATE;
951 	t->t_newstate.state = nstate;
952 	t->t_newstate.arg = arg;
953 	workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL);
954 
955 	return 0;
956 }
957 
958 void
bwfm_newstate_cb(struct bwfm_softc * sc,struct bwfm_cmd_newstate * cmd)959 bwfm_newstate_cb(struct bwfm_softc *sc, struct bwfm_cmd_newstate *cmd)
960 {
961 	struct ieee80211com *ic = &sc->sc_ic;
962 	enum ieee80211_state ostate = ic->ic_state;
963 	enum ieee80211_state nstate = cmd->state;
964 	int s;
965 
966 	DPRINTF(("%s: newstate %d -> %d\n", DEVNAME(sc), ostate, nstate));
967 
968 	s = splnet();
969 
970 	switch (nstate) {
971 	case IEEE80211_S_INIT:
972 		break;
973 
974 	case IEEE80211_S_SCAN:
975 		if (ostate != IEEE80211_S_SCAN) {
976 			/* Start of scanning */
977 			bwfm_scan(sc);
978 		}
979 		break;
980 
981 	case IEEE80211_S_AUTH:
982 		bwfm_connect(sc);
983 		break;
984 
985 	case IEEE80211_S_ASSOC:
986 		break;
987 
988 	case IEEE80211_S_RUN:
989 		break;
990 	}
991 
992 	sc->sc_newstate(ic, nstate, cmd->arg);
993 
994 	splx(s);
995 }
996 
997 void
bwfm_newassoc(struct ieee80211_node * ni,int isnew)998 bwfm_newassoc(struct ieee80211_node *ni, int isnew)
999 {
1000 	/* Firmware handles rate adaptation for us */
1001 	ni->ni_txrate = 0;
1002 }
1003 
1004 void
bwfm_task(struct work * wk,void * arg)1005 bwfm_task(struct work *wk, void *arg)
1006 {
1007 	struct bwfm_task *t = (struct bwfm_task *)wk;
1008 	struct bwfm_softc *sc = t->t_sc;
1009 
1010 	switch (t->t_cmd) {
1011 	case BWFM_TASK_NEWSTATE:
1012 		bwfm_newstate_cb(sc, &t->t_newstate);
1013 		break;
1014 	case BWFM_TASK_KEY_SET:
1015 		bwfm_key_set_cb(sc, &t->t_key);
1016 		break;
1017 	case BWFM_TASK_KEY_DELETE:
1018 		bwfm_key_delete_cb(sc, &t->t_key);
1019 		break;
1020 	case BWFM_TASK_RX_EVENT:
1021 		bwfm_rx_event_cb(sc, t->t_mbuf);
1022 		break;
1023 	default:
1024 		panic("bwfm: unknown task command %d", t->t_cmd);
1025 	}
1026 
1027 	pool_cache_put(sc->sc_freetask, t);
1028 }
1029 
1030 int
bwfm_media_change(struct ifnet * ifp)1031 bwfm_media_change(struct ifnet *ifp)
1032 {
1033 	return 0;
1034 }
1035 
1036 /* Chip initialization (SDIO, PCIe) */
1037 int
bwfm_chip_attach(struct bwfm_softc * sc)1038 bwfm_chip_attach(struct bwfm_softc *sc)
1039 {
1040 	struct bwfm_core *core;
1041 	int need_socram = 0;
1042 	int has_socram = 0;
1043 	int cpu_found = 0;
1044 	uint32_t val;
1045 
1046 	LIST_INIT(&sc->sc_chip.ch_list);
1047 
1048 	if (sc->sc_buscore_ops->bc_prepare(sc) != 0) {
1049 		printf("%s: failed buscore prepare\n", DEVNAME(sc));
1050 		return 1;
1051 	}
1052 
1053 	val = sc->sc_buscore_ops->bc_read(sc,
1054 	    BWFM_CHIP_BASE + BWFM_CHIP_REG_CHIPID);
1055 	sc->sc_chip.ch_chip = BWFM_CHIP_CHIPID_ID(val);
1056 	sc->sc_chip.ch_chiprev = BWFM_CHIP_CHIPID_REV(val);
1057 
1058 	if ((sc->sc_chip.ch_chip > 0xa000) || (sc->sc_chip.ch_chip < 0x4000))
1059 		snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name),
1060 		    "%d", sc->sc_chip.ch_chip);
1061 	else
1062 		snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name),
1063 		    "%x", sc->sc_chip.ch_chip);
1064 
1065 	switch (BWFM_CHIP_CHIPID_TYPE(val))
1066 	{
1067 	case BWFM_CHIP_CHIPID_TYPE_SOCI_SB:
1068 		printf("%s: SoC interconnect SB not implemented\n",
1069 		    DEVNAME(sc));
1070 		return 1;
1071 	case BWFM_CHIP_CHIPID_TYPE_SOCI_AI:
1072 		sc->sc_chip.ch_core_isup = bwfm_chip_ai_isup;
1073 		sc->sc_chip.ch_core_disable = bwfm_chip_ai_disable;
1074 		sc->sc_chip.ch_core_reset = bwfm_chip_ai_reset;
1075 		bwfm_chip_dmp_erom_scan(sc);
1076 		break;
1077 	default:
1078 		printf("%s: SoC interconnect %d unknown\n",
1079 		    DEVNAME(sc), BWFM_CHIP_CHIPID_TYPE(val));
1080 		return 1;
1081 	}
1082 
1083 	LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link) {
1084 		DPRINTF(("%s: 0x%x:%-2d base 0x%08x wrap 0x%08x\n",
1085 		    DEVNAME(sc), core->co_id, core->co_rev,
1086 		    core->co_base, core->co_wrapbase));
1087 
1088 		switch (core->co_id) {
1089 		case BWFM_AGENT_CORE_ARM_CM3:
1090 			need_socram = true;
1091 			/* FALLTHROUGH */
1092 		case BWFM_AGENT_CORE_ARM_CR4:
1093 		case BWFM_AGENT_CORE_ARM_CA7:
1094 			cpu_found = true;
1095 			break;
1096 		case BWFM_AGENT_INTERNAL_MEM:
1097 			has_socram = true;
1098 			break;
1099 		default:
1100 			break;
1101 		}
1102 	}
1103 
1104 	if (!cpu_found) {
1105 		printf("%s: CPU core not detected\n", DEVNAME(sc));
1106 		return 1;
1107 	}
1108 	if (need_socram && !has_socram) {
1109 		printf("%s: RAM core not provided\n", DEVNAME(sc));
1110 		return 1;
1111 	}
1112 
1113 	bwfm_chip_set_passive(sc);
1114 
1115 	if (sc->sc_buscore_ops->bc_reset) {
1116 		sc->sc_buscore_ops->bc_reset(sc);
1117 		bwfm_chip_set_passive(sc);
1118 	}
1119 
1120 	if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4)) != NULL) {
1121 		bwfm_chip_tcm_ramsize(sc, core);
1122 		bwfm_chip_tcm_rambase(sc);
1123 	} else if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_SYS_MEM)) != NULL) {
1124 		bwfm_chip_sysmem_ramsize(sc, core);
1125 		bwfm_chip_tcm_rambase(sc);
1126 	} else if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM)) != NULL) {
1127 		bwfm_chip_socram_ramsize(sc, core);
1128 	}
1129 
1130 	core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
1131 	sc->sc_chip.ch_cc_caps = sc->sc_buscore_ops->bc_read(sc,
1132 	    core->co_base + BWFM_CHIP_REG_CAPABILITIES);
1133 	sc->sc_chip.ch_cc_caps_ext = sc->sc_buscore_ops->bc_read(sc,
1134 	    core->co_base + BWFM_CHIP_REG_CAPABILITIES_EXT);
1135 
1136 	core = bwfm_chip_get_pmu(sc);
1137 	if (sc->sc_chip.ch_cc_caps & BWFM_CHIP_REG_CAPABILITIES_PMU) {
1138 		sc->sc_chip.ch_pmucaps = sc->sc_buscore_ops->bc_read(sc,
1139 		    core->co_base + BWFM_CHIP_REG_PMUCAPABILITIES);
1140 		sc->sc_chip.ch_pmurev = sc->sc_chip.ch_pmucaps &
1141 		    BWFM_CHIP_REG_PMUCAPABILITIES_REV_MASK;
1142 	}
1143 
1144 	if (sc->sc_buscore_ops->bc_setup)
1145 		sc->sc_buscore_ops->bc_setup(sc);
1146 
1147 	return 0;
1148 }
1149 
1150 struct bwfm_core *
bwfm_chip_get_core(struct bwfm_softc * sc,int id)1151 bwfm_chip_get_core(struct bwfm_softc *sc, int id)
1152 {
1153 	struct bwfm_core *core;
1154 
1155 	LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link) {
1156 		if (core->co_id == id)
1157 			return core;
1158 	}
1159 
1160 	return NULL;
1161 }
1162 
1163 struct bwfm_core *
bwfm_chip_get_pmu(struct bwfm_softc * sc)1164 bwfm_chip_get_pmu(struct bwfm_softc *sc)
1165 {
1166 	struct bwfm_core *cc, *pmu;
1167 
1168 	cc = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
1169 	if (cc->co_rev >= 35 && sc->sc_chip.ch_cc_caps_ext &
1170 	    BWFM_CHIP_REG_CAPABILITIES_EXT_AOB_PRESENT) {
1171 		pmu = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_PMU);
1172 		if (pmu)
1173 			return pmu;
1174 	}
1175 
1176 	return cc;
1177 }
1178 
1179 /* Functions for the AI interconnect */
1180 int
bwfm_chip_ai_isup(struct bwfm_softc * sc,struct bwfm_core * core)1181 bwfm_chip_ai_isup(struct bwfm_softc *sc, struct bwfm_core *core)
1182 {
1183 	uint32_t ioctl, reset;
1184 
1185 	ioctl = sc->sc_buscore_ops->bc_read(sc,
1186 	    core->co_wrapbase + BWFM_AGENT_IOCTL);
1187 	reset = sc->sc_buscore_ops->bc_read(sc,
1188 	    core->co_wrapbase + BWFM_AGENT_RESET_CTL);
1189 
1190 	if (((ioctl & (BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK)) ==
1191 	    BWFM_AGENT_IOCTL_CLK) &&
1192 	    ((reset & BWFM_AGENT_RESET_CTL_RESET) == 0))
1193 		return 1;
1194 
1195 	return 0;
1196 }
1197 
1198 void
bwfm_chip_ai_disable(struct bwfm_softc * sc,struct bwfm_core * core,uint32_t prereset,uint32_t reset)1199 bwfm_chip_ai_disable(struct bwfm_softc *sc, struct bwfm_core *core,
1200     uint32_t prereset, uint32_t reset)
1201 {
1202 	uint32_t val;
1203 	int i;
1204 
1205 	val = sc->sc_buscore_ops->bc_read(sc,
1206 	    core->co_wrapbase + BWFM_AGENT_RESET_CTL);
1207 	if ((val & BWFM_AGENT_RESET_CTL_RESET) == 0) {
1208 
1209 		sc->sc_buscore_ops->bc_write(sc,
1210 		    core->co_wrapbase + BWFM_AGENT_IOCTL,
1211 		    prereset | BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK);
1212 		sc->sc_buscore_ops->bc_read(sc,
1213 		    core->co_wrapbase + BWFM_AGENT_IOCTL);
1214 
1215 		sc->sc_buscore_ops->bc_write(sc,
1216 		    core->co_wrapbase + BWFM_AGENT_RESET_CTL,
1217 		    BWFM_AGENT_RESET_CTL_RESET);
1218 		delay(20);
1219 
1220 		for (i = 300; i > 0; i--) {
1221 			if (sc->sc_buscore_ops->bc_read(sc,
1222 			    core->co_wrapbase + BWFM_AGENT_RESET_CTL) ==
1223 			    BWFM_AGENT_RESET_CTL_RESET)
1224 				break;
1225 		}
1226 		if (i == 0)
1227 			printf("%s: timeout on core reset\n", DEVNAME(sc));
1228 	}
1229 
1230 	sc->sc_buscore_ops->bc_write(sc,
1231 	    core->co_wrapbase + BWFM_AGENT_IOCTL,
1232 	    reset | BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK);
1233 	sc->sc_buscore_ops->bc_read(sc,
1234 	    core->co_wrapbase + BWFM_AGENT_IOCTL);
1235 }
1236 
1237 void
bwfm_chip_ai_reset(struct bwfm_softc * sc,struct bwfm_core * core,uint32_t prereset,uint32_t reset,uint32_t postreset)1238 bwfm_chip_ai_reset(struct bwfm_softc *sc, struct bwfm_core *core,
1239     uint32_t prereset, uint32_t reset, uint32_t postreset)
1240 {
1241 	int i;
1242 
1243 	bwfm_chip_ai_disable(sc, core, prereset, reset);
1244 
1245 	for (i = 50; i > 0; i--) {
1246 		if ((sc->sc_buscore_ops->bc_read(sc,
1247 		    core->co_wrapbase + BWFM_AGENT_RESET_CTL) &
1248 		    BWFM_AGENT_RESET_CTL_RESET) == 0)
1249 			break;
1250 		sc->sc_buscore_ops->bc_write(sc,
1251 		    core->co_wrapbase + BWFM_AGENT_RESET_CTL, 0);
1252 		delay(60);
1253 	}
1254 	if (i == 0)
1255 		printf("%s: timeout on core reset\n", DEVNAME(sc));
1256 
1257 	sc->sc_buscore_ops->bc_write(sc,
1258 	    core->co_wrapbase + BWFM_AGENT_IOCTL,
1259 	    postreset | BWFM_AGENT_IOCTL_CLK);
1260 	sc->sc_buscore_ops->bc_read(sc,
1261 	    core->co_wrapbase + BWFM_AGENT_IOCTL);
1262 }
1263 
1264 void
bwfm_chip_dmp_erom_scan(struct bwfm_softc * sc)1265 bwfm_chip_dmp_erom_scan(struct bwfm_softc *sc)
1266 {
1267 	uint32_t erom, val, base, wrap;
1268 	uint8_t type = 0;
1269 	uint16_t id;
1270 	uint8_t nmw, nsw, rev;
1271 	struct bwfm_core *core;
1272 
1273 	erom = sc->sc_buscore_ops->bc_read(sc,
1274 	    BWFM_CHIP_BASE + BWFM_CHIP_REG_EROMPTR);
1275 	while (type != BWFM_DMP_DESC_EOT) {
1276 		val = sc->sc_buscore_ops->bc_read(sc, erom);
1277 		type = val & BWFM_DMP_DESC_MASK;
1278 		erom += 4;
1279 
1280 		if (type != BWFM_DMP_DESC_COMPONENT)
1281 			continue;
1282 
1283 		id = (val & BWFM_DMP_COMP_PARTNUM)
1284 		    >> BWFM_DMP_COMP_PARTNUM_S;
1285 
1286 		val = sc->sc_buscore_ops->bc_read(sc, erom);
1287 		type = val & BWFM_DMP_DESC_MASK;
1288 		erom += 4;
1289 
1290 		if (type != BWFM_DMP_DESC_COMPONENT) {
1291 			printf("%s: not component descriptor\n", DEVNAME(sc));
1292 			return;
1293 		}
1294 
1295 		nmw = (val & BWFM_DMP_COMP_NUM_MWRAP)
1296 		    >> BWFM_DMP_COMP_NUM_MWRAP_S;
1297 		nsw = (val & BWFM_DMP_COMP_NUM_SWRAP)
1298 		    >> BWFM_DMP_COMP_NUM_SWRAP_S;
1299 		rev = (val & BWFM_DMP_COMP_REVISION)
1300 		    >> BWFM_DMP_COMP_REVISION_S;
1301 
1302 		if (nmw + nsw == 0 && id != BWFM_AGENT_CORE_PMU)
1303 			continue;
1304 
1305 		if (bwfm_chip_dmp_get_regaddr(sc, &erom, &base, &wrap))
1306 			continue;
1307 
1308 		core = kmem_alloc(sizeof(*core), KM_SLEEP);
1309 		core->co_id = id;
1310 		core->co_base = base;
1311 		core->co_wrapbase = wrap;
1312 		core->co_rev = rev;
1313 		LIST_INSERT_HEAD(&sc->sc_chip.ch_list, core, co_link);
1314 	}
1315 }
1316 
1317 int
bwfm_chip_dmp_get_regaddr(struct bwfm_softc * sc,uint32_t * erom,uint32_t * base,uint32_t * wrap)1318 bwfm_chip_dmp_get_regaddr(struct bwfm_softc *sc, uint32_t *erom,
1319     uint32_t *base, uint32_t *wrap)
1320 {
1321 	uint8_t type = 0, mpnum __unused = 0;
1322 	uint8_t stype, sztype, wraptype;
1323 	uint32_t val;
1324 
1325 	*base = 0;
1326 	*wrap = 0;
1327 
1328 	val = sc->sc_buscore_ops->bc_read(sc, *erom);
1329 	type = val & BWFM_DMP_DESC_MASK;
1330 	if (type == BWFM_DMP_DESC_MASTER_PORT) {
1331 		mpnum = (val & BWFM_DMP_MASTER_PORT_NUM)
1332 		    >> BWFM_DMP_MASTER_PORT_NUM_S;
1333 		wraptype = BWFM_DMP_SLAVE_TYPE_MWRAP;
1334 		*erom += 4;
1335 	} else if ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT32) ==
1336 	    BWFM_DMP_DESC_ADDRESS)
1337 		wraptype = BWFM_DMP_SLAVE_TYPE_SWRAP;
1338 	else
1339 		return 1;
1340 
1341 	do {
1342 		do {
1343 			val = sc->sc_buscore_ops->bc_read(sc, *erom);
1344 			type = val & BWFM_DMP_DESC_MASK;
1345 			if (type == BWFM_DMP_DESC_COMPONENT)
1346 				return 0;
1347 			if (type == BWFM_DMP_DESC_EOT)
1348 				return 1;
1349 			*erom += 4;
1350 		} while ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT32) !=
1351 		     BWFM_DMP_DESC_ADDRESS);
1352 
1353 		if (type & BWFM_DMP_DESC_ADDRSIZE_GT32)
1354 			*erom += 4;
1355 
1356 		sztype = (val & BWFM_DMP_SLAVE_SIZE_TYPE)
1357 		    >> BWFM_DMP_SLAVE_SIZE_TYPE_S;
1358 		if (sztype == BWFM_DMP_SLAVE_SIZE_DESC) {
1359 			val = sc->sc_buscore_ops->bc_read(sc, *erom);
1360 			type = val & BWFM_DMP_DESC_MASK;
1361 			if (type & BWFM_DMP_DESC_ADDRSIZE_GT32)
1362 				*erom += 8;
1363 			else
1364 				*erom += 4;
1365 		}
1366 		if (sztype != BWFM_DMP_SLAVE_SIZE_4K)
1367 			continue;
1368 
1369 		stype = (val & BWFM_DMP_SLAVE_TYPE) >> BWFM_DMP_SLAVE_TYPE_S;
1370 		if (*base == 0 && stype == BWFM_DMP_SLAVE_TYPE_SLAVE)
1371 			*base = val & BWFM_DMP_SLAVE_ADDR_BASE;
1372 		if (*wrap == 0 && stype == wraptype)
1373 			*wrap = val & BWFM_DMP_SLAVE_ADDR_BASE;
1374 	} while (*base == 0 || *wrap == 0);
1375 
1376 	return 0;
1377 }
1378 
1379 /* Core configuration */
1380 int
bwfm_chip_set_active(struct bwfm_softc * sc,const uint32_t rstvec)1381 bwfm_chip_set_active(struct bwfm_softc *sc, const uint32_t rstvec)
1382 {
1383 	if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4) != NULL)
1384 		return bwfm_chip_cr4_set_active(sc, rstvec);
1385 	if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7) != NULL)
1386 		return bwfm_chip_ca7_set_active(sc, rstvec);
1387 	if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3) != NULL)
1388 		return bwfm_chip_cm3_set_active(sc);
1389 	return 1;
1390 }
1391 
1392 void
bwfm_chip_set_passive(struct bwfm_softc * sc)1393 bwfm_chip_set_passive(struct bwfm_softc *sc)
1394 {
1395 	if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4) != NULL) {
1396 		bwfm_chip_cr4_set_passive(sc);
1397 		return;
1398 	}
1399 	if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7) != NULL) {
1400 		bwfm_chip_ca7_set_passive(sc);
1401 		return;
1402 	}
1403 	if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3) != NULL) {
1404 		bwfm_chip_cm3_set_passive(sc);
1405 		return;
1406 	}
1407 }
1408 
1409 int
bwfm_chip_cr4_set_active(struct bwfm_softc * sc,const uint32_t rstvec)1410 bwfm_chip_cr4_set_active(struct bwfm_softc *sc, const uint32_t rstvec)
1411 {
1412 	struct bwfm_core *core;
1413 
1414 	sc->sc_buscore_ops->bc_activate(sc, rstvec);
1415 	core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4);
1416 	sc->sc_chip.ch_core_reset(sc, core,
1417 	    BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 0, 0);
1418 
1419 	return 0;
1420 }
1421 
1422 void
bwfm_chip_cr4_set_passive(struct bwfm_softc * sc)1423 bwfm_chip_cr4_set_passive(struct bwfm_softc *sc)
1424 {
1425 	struct bwfm_core *core;
1426 	uint32_t val;
1427 
1428 	core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4);
1429 	val = sc->sc_buscore_ops->bc_read(sc,
1430 	    core->co_wrapbase + BWFM_AGENT_IOCTL);
1431 	sc->sc_chip.ch_core_reset(sc, core,
1432 	    val & BWFM_AGENT_IOCTL_ARMCR4_CPUHALT,
1433 	    BWFM_AGENT_IOCTL_ARMCR4_CPUHALT,
1434 	    BWFM_AGENT_IOCTL_ARMCR4_CPUHALT);
1435 
1436 	core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211);
1437 	sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET |
1438 	    BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN,
1439 	    BWFM_AGENT_D11_IOCTL_PHYCLOCKEN);
1440 }
1441 
1442 int
bwfm_chip_ca7_set_active(struct bwfm_softc * sc,const uint32_t rstvec)1443 bwfm_chip_ca7_set_active(struct bwfm_softc *sc, const uint32_t rstvec)
1444 {
1445 	struct bwfm_core *core;
1446 
1447 	sc->sc_buscore_ops->bc_activate(sc, rstvec);
1448 	core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7);
1449 	sc->sc_chip.ch_core_reset(sc, core,
1450 	    BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 0, 0);
1451 
1452 	return 0;
1453 }
1454 
1455 void
bwfm_chip_ca7_set_passive(struct bwfm_softc * sc)1456 bwfm_chip_ca7_set_passive(struct bwfm_softc *sc)
1457 {
1458 	struct bwfm_core *core;
1459 	uint32_t val;
1460 
1461 	core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7);
1462 	val = sc->sc_buscore_ops->bc_read(sc,
1463 	    core->co_wrapbase + BWFM_AGENT_IOCTL);
1464 	sc->sc_chip.ch_core_reset(sc, core,
1465 	    val & BWFM_AGENT_IOCTL_ARMCR4_CPUHALT,
1466 	    BWFM_AGENT_IOCTL_ARMCR4_CPUHALT,
1467 	    BWFM_AGENT_IOCTL_ARMCR4_CPUHALT);
1468 
1469 	core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211);
1470 	sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET |
1471 	    BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN,
1472 	    BWFM_AGENT_D11_IOCTL_PHYCLOCKEN);
1473 }
1474 
1475 int
bwfm_chip_cm3_set_active(struct bwfm_softc * sc)1476 bwfm_chip_cm3_set_active(struct bwfm_softc *sc)
1477 {
1478 	struct bwfm_core *core;
1479 
1480 	core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM);
1481 	if (!sc->sc_chip.ch_core_isup(sc, core))
1482 		return 1;
1483 
1484 	sc->sc_buscore_ops->bc_activate(sc, 0);
1485 
1486 	core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3);
1487 	sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0);
1488 
1489 	return 0;
1490 }
1491 
1492 void
bwfm_chip_cm3_set_passive(struct bwfm_softc * sc)1493 bwfm_chip_cm3_set_passive(struct bwfm_softc *sc)
1494 {
1495 	struct bwfm_core *core;
1496 
1497 	core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3);
1498 	sc->sc_chip.ch_core_disable(sc, core, 0, 0);
1499 	core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211);
1500 	sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET |
1501 	    BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN,
1502 	    BWFM_AGENT_D11_IOCTL_PHYCLOCKEN);
1503 	core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM);
1504 	sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0);
1505 
1506 	if (sc->sc_chip.ch_chip == BRCM_CC_43430_CHIP_ID) {
1507 		sc->sc_buscore_ops->bc_write(sc,
1508 		    core->co_base + BWFM_SOCRAM_BANKIDX, 3);
1509 		sc->sc_buscore_ops->bc_write(sc,
1510 		    core->co_base + BWFM_SOCRAM_BANKPDA, 0);
1511 	}
1512 }
1513 
1514 int
bwfm_chip_sr_capable(struct bwfm_softc * sc)1515 bwfm_chip_sr_capable(struct bwfm_softc *sc)
1516 {
1517 	struct bwfm_core *core;
1518 	uint32_t reg;
1519 
1520 	if (sc->sc_chip.ch_pmurev < 17)
1521 		return 0;
1522 
1523 	switch (sc->sc_chip.ch_chip) {
1524 	case BRCM_CC_4345_CHIP_ID:
1525 	case BRCM_CC_4354_CHIP_ID:
1526 	case BRCM_CC_4356_CHIP_ID:
1527 		core = bwfm_chip_get_pmu(sc);
1528 		sc->sc_buscore_ops->bc_write(sc, core->co_base +
1529 		    BWFM_CHIP_REG_CHIPCONTROL_ADDR, 3);
1530 		reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1531 		    BWFM_CHIP_REG_CHIPCONTROL_DATA);
1532 		return (reg & (1 << 2)) != 0;
1533 	case BRCM_CC_43241_CHIP_ID:
1534 	case BRCM_CC_4335_CHIP_ID:
1535 	case BRCM_CC_4339_CHIP_ID:
1536 		core = bwfm_chip_get_pmu(sc);
1537 		sc->sc_buscore_ops->bc_write(sc, core->co_base +
1538 		    BWFM_CHIP_REG_CHIPCONTROL_ADDR, 3);
1539 		reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1540 		    BWFM_CHIP_REG_CHIPCONTROL_DATA);
1541 		return reg != 0;
1542 	case BRCM_CC_43430_CHIP_ID:
1543 		core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
1544 		reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1545 		    BWFM_CHIP_REG_SR_CONTROL1);
1546 		return reg != 0;
1547 	default:
1548 		core = bwfm_chip_get_pmu(sc);
1549 		reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1550 		    BWFM_CHIP_REG_PMUCAPABILITIES_EXT);
1551 		if ((reg & BWFM_CHIP_REG_PMUCAPABILITIES_SR_SUPP) == 0)
1552 			return 0;
1553 		reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1554 		    BWFM_CHIP_REG_RETENTION_CTL);
1555 		return (reg & (BWFM_CHIP_REG_RETENTION_CTL_MACPHY_DIS |
1556 		               BWFM_CHIP_REG_RETENTION_CTL_LOGIC_DIS)) == 0;
1557 	}
1558 }
1559 
1560 /* RAM size helpers */
1561 void
bwfm_chip_socram_ramsize(struct bwfm_softc * sc,struct bwfm_core * core)1562 bwfm_chip_socram_ramsize(struct bwfm_softc *sc, struct bwfm_core *core)
1563 {
1564 	uint32_t coreinfo, nb, lss, banksize, bankinfo;
1565 	uint32_t ramsize = 0, srsize = 0;
1566 	int i;
1567 
1568 	if (!sc->sc_chip.ch_core_isup(sc, core))
1569 		sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0);
1570 
1571 	coreinfo = sc->sc_buscore_ops->bc_read(sc,
1572 	    core->co_base + BWFM_SOCRAM_COREINFO);
1573 	nb = (coreinfo & BWFM_SOCRAM_COREINFO_SRNB_MASK)
1574 	    >> BWFM_SOCRAM_COREINFO_SRNB_SHIFT;
1575 
1576 	if (core->co_rev <= 7 || core->co_rev == 12) {
1577 		banksize = coreinfo & BWFM_SOCRAM_COREINFO_SRBSZ_MASK;
1578 		lss = (coreinfo & BWFM_SOCRAM_COREINFO_LSS_MASK)
1579 		    >> BWFM_SOCRAM_COREINFO_LSS_SHIFT;
1580 		if (lss != 0)
1581 			nb--;
1582 		ramsize = nb * (1 << (banksize + BWFM_SOCRAM_COREINFO_SRBSZ_BASE));
1583 		if (lss != 0)
1584 			ramsize += (1 << ((lss - 1) + BWFM_SOCRAM_COREINFO_SRBSZ_BASE));
1585 	} else {
1586 		for (i = 0; i < nb; i++) {
1587 			sc->sc_buscore_ops->bc_write(sc,
1588 			    core->co_base + BWFM_SOCRAM_BANKIDX,
1589 			    (BWFM_SOCRAM_BANKIDX_MEMTYPE_RAM <<
1590 			    BWFM_SOCRAM_BANKIDX_MEMTYPE_SHIFT) | i);
1591 			bankinfo = sc->sc_buscore_ops->bc_read(sc,
1592 			    core->co_base + BWFM_SOCRAM_BANKINFO);
1593 			banksize = ((bankinfo & BWFM_SOCRAM_BANKINFO_SZMASK) + 1)
1594 			    * BWFM_SOCRAM_BANKINFO_SZBASE;
1595 			ramsize += banksize;
1596 			if (bankinfo & BWFM_SOCRAM_BANKINFO_RETNTRAM_MASK)
1597 				srsize += banksize;
1598 		}
1599 	}
1600 
1601 	switch (sc->sc_chip.ch_chip) {
1602 	case BRCM_CC_4334_CHIP_ID:
1603 		if (sc->sc_chip.ch_chiprev < 2)
1604 			srsize = 32 * 1024;
1605 		break;
1606 	case BRCM_CC_43430_CHIP_ID:
1607 		srsize = 64 * 1024;
1608 		break;
1609 	default:
1610 		break;
1611 	}
1612 
1613 	sc->sc_chip.ch_ramsize = ramsize;
1614 	sc->sc_chip.ch_srsize = srsize;
1615 }
1616 
1617 void
bwfm_chip_sysmem_ramsize(struct bwfm_softc * sc,struct bwfm_core * core)1618 bwfm_chip_sysmem_ramsize(struct bwfm_softc *sc, struct bwfm_core *core)
1619 {
1620 	uint32_t coreinfo, nb, banksize, bankinfo;
1621 	uint32_t ramsize = 0;
1622 	int i;
1623 
1624 	if (!sc->sc_chip.ch_core_isup(sc, core))
1625 		sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0);
1626 
1627 	coreinfo = sc->sc_buscore_ops->bc_read(sc,
1628 	    core->co_base + BWFM_SOCRAM_COREINFO);
1629 	nb = (coreinfo & BWFM_SOCRAM_COREINFO_SRNB_MASK)
1630 	    >> BWFM_SOCRAM_COREINFO_SRNB_SHIFT;
1631 
1632 	for (i = 0; i < nb; i++) {
1633 		sc->sc_buscore_ops->bc_write(sc,
1634 		    core->co_base + BWFM_SOCRAM_BANKIDX,
1635 		    (BWFM_SOCRAM_BANKIDX_MEMTYPE_RAM <<
1636 		    BWFM_SOCRAM_BANKIDX_MEMTYPE_SHIFT) | i);
1637 		bankinfo = sc->sc_buscore_ops->bc_read(sc,
1638 		    core->co_base + BWFM_SOCRAM_BANKINFO);
1639 		banksize = ((bankinfo & BWFM_SOCRAM_BANKINFO_SZMASK) + 1)
1640 		    * BWFM_SOCRAM_BANKINFO_SZBASE;
1641 		ramsize += banksize;
1642 	}
1643 
1644 	sc->sc_chip.ch_ramsize = ramsize;
1645 }
1646 
1647 void
bwfm_chip_tcm_ramsize(struct bwfm_softc * sc,struct bwfm_core * core)1648 bwfm_chip_tcm_ramsize(struct bwfm_softc *sc, struct bwfm_core *core)
1649 {
1650 	uint32_t cap, nab, nbb, totb, bxinfo, ramsize = 0;
1651 	int i;
1652 
1653 	cap = sc->sc_buscore_ops->bc_read(sc, core->co_base + BWFM_ARMCR4_CAP);
1654 	nab = (cap & BWFM_ARMCR4_CAP_TCBANB_MASK) >> BWFM_ARMCR4_CAP_TCBANB_SHIFT;
1655 	nbb = (cap & BWFM_ARMCR4_CAP_TCBBNB_MASK) >> BWFM_ARMCR4_CAP_TCBBNB_SHIFT;
1656 	totb = nab + nbb;
1657 
1658 	for (i = 0; i < totb; i++) {
1659 		sc->sc_buscore_ops->bc_write(sc,
1660 		    core->co_base + BWFM_ARMCR4_BANKIDX, i);
1661 		bxinfo = sc->sc_buscore_ops->bc_read(sc,
1662 		    core->co_base + BWFM_ARMCR4_BANKINFO);
1663 		ramsize += ((bxinfo & BWFM_ARMCR4_BANKINFO_BSZ_MASK) + 1) *
1664 		    BWFM_ARMCR4_BANKINFO_BSZ_MULT;
1665 	}
1666 
1667 	sc->sc_chip.ch_ramsize = ramsize;
1668 }
1669 
1670 void
bwfm_chip_tcm_rambase(struct bwfm_softc * sc)1671 bwfm_chip_tcm_rambase(struct bwfm_softc *sc)
1672 {
1673 	switch (sc->sc_chip.ch_chip) {
1674 	case BRCM_CC_4345_CHIP_ID:
1675 		sc->sc_chip.ch_rambase = 0x198000;
1676 		break;
1677 	case BRCM_CC_4335_CHIP_ID:
1678 	case BRCM_CC_4339_CHIP_ID:
1679 	case BRCM_CC_4350_CHIP_ID:
1680 	case BRCM_CC_4354_CHIP_ID:
1681 	case BRCM_CC_4356_CHIP_ID:
1682 	case BRCM_CC_43567_CHIP_ID:
1683 	case BRCM_CC_43569_CHIP_ID:
1684 	case BRCM_CC_43570_CHIP_ID:
1685 	case BRCM_CC_4358_CHIP_ID:
1686 	case BRCM_CC_4359_CHIP_ID:
1687 	case BRCM_CC_43602_CHIP_ID:
1688 	case BRCM_CC_4371_CHIP_ID:
1689 		sc->sc_chip.ch_rambase = 0x180000;
1690 		break;
1691 	case BRCM_CC_43465_CHIP_ID:
1692 	case BRCM_CC_43525_CHIP_ID:
1693 	case BRCM_CC_4365_CHIP_ID:
1694 	case BRCM_CC_4366_CHIP_ID:
1695 		sc->sc_chip.ch_rambase = 0x200000;
1696 		break;
1697 	case CY_CC_4373_CHIP_ID:
1698 		sc->sc_chip.ch_rambase = 0x160000;
1699 		break;
1700 	default:
1701 		printf("%s: unknown chip: %d\n", DEVNAME(sc),
1702 		    sc->sc_chip.ch_chip);
1703 		break;
1704 	}
1705 }
1706 
1707 /* BCDC protocol implementation */
1708 int
bwfm_proto_bcdc_query_dcmd(struct bwfm_softc * sc,int ifidx,int cmd,char * buf,size_t * len)1709 bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *sc, int ifidx,
1710     int cmd, char *buf, size_t *len)
1711 {
1712 	struct bwfm_proto_bcdc_dcmd *dcmd;
1713 	size_t size = sizeof(dcmd->hdr) + *len;
1714 	int reqid;
1715 	int ret = 1;
1716 
1717 	reqid = sc->sc_bcdc_reqid++;
1718 
1719 	dcmd = kmem_zalloc(sizeof(*dcmd), KM_SLEEP);
1720 	if (*len > sizeof(dcmd->buf))
1721 		goto err;
1722 
1723 	dcmd->hdr.cmd = htole32(cmd);
1724 	dcmd->hdr.len = htole32(*len);
1725 	dcmd->hdr.flags |= BWFM_BCDC_DCMD_GET;
1726 	dcmd->hdr.flags |= BWFM_BCDC_DCMD_ID_SET(reqid);
1727 	dcmd->hdr.flags |= BWFM_BCDC_DCMD_IF_SET(ifidx);
1728 	dcmd->hdr.flags = htole32(dcmd->hdr.flags);
1729 	memcpy(&dcmd->buf, buf, *len);
1730 
1731 	if (sc->sc_bus_ops->bs_txctl(sc, (void *)dcmd,
1732 	     sizeof(dcmd->hdr) + *len)) {
1733 		DPRINTF(("%s: tx failed\n", DEVNAME(sc)));
1734 		goto err;
1735 	}
1736 
1737 	do {
1738 		if (sc->sc_bus_ops->bs_rxctl(sc, (void *)dcmd, &size)) {
1739 			DPRINTF(("%s: rx failed\n", DEVNAME(sc)));
1740 			goto err;
1741 		}
1742 		dcmd->hdr.cmd = le32toh(dcmd->hdr.cmd);
1743 		dcmd->hdr.len = le32toh(dcmd->hdr.len);
1744 		dcmd->hdr.flags = le32toh(dcmd->hdr.flags);
1745 		dcmd->hdr.status = le32toh(dcmd->hdr.status);
1746 	} while (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid);
1747 
1748 	if (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid) {
1749 		printf("%s: unexpected request id\n", DEVNAME(sc));
1750 		goto err;
1751 	}
1752 
1753 	if (buf) {
1754 		if (size < *len)
1755 			*len = size;
1756 		memcpy(buf, dcmd->buf, *len);
1757 	}
1758 
1759 	if (dcmd->hdr.flags & BWFM_BCDC_DCMD_ERROR)
1760 		ret = dcmd->hdr.status;
1761 	else
1762 		ret = 0;
1763 err:
1764 	kmem_free(dcmd, sizeof(*dcmd));
1765 	return ret;
1766 }
1767 
1768 int
bwfm_proto_bcdc_set_dcmd(struct bwfm_softc * sc,int ifidx,int cmd,char * buf,size_t len)1769 bwfm_proto_bcdc_set_dcmd(struct bwfm_softc *sc, int ifidx,
1770     int cmd, char *buf, size_t len)
1771 {
1772 	struct bwfm_proto_bcdc_dcmd *dcmd;
1773 	size_t size = sizeof(dcmd->hdr) + len;
1774 	int ret = 1, reqid;
1775 
1776 	reqid = sc->sc_bcdc_reqid++;
1777 
1778 	dcmd = kmem_zalloc(sizeof(*dcmd), KM_SLEEP);
1779 	if (len > sizeof(dcmd->buf))
1780 		goto err;
1781 
1782 	dcmd->hdr.cmd = htole32(cmd);
1783 	dcmd->hdr.len = htole32(len);
1784 	dcmd->hdr.flags |= BWFM_BCDC_DCMD_SET;
1785 	dcmd->hdr.flags |= BWFM_BCDC_DCMD_ID_SET(reqid);
1786 	dcmd->hdr.flags |= BWFM_BCDC_DCMD_IF_SET(ifidx);
1787 	dcmd->hdr.flags = htole32(dcmd->hdr.flags);
1788 	memcpy(&dcmd->buf, buf, len);
1789 
1790 	if (sc->sc_bus_ops->bs_txctl(sc, (void *)dcmd, size)) {
1791 		DPRINTF(("%s: tx failed\n", DEVNAME(sc)));
1792 		goto err;
1793 	}
1794 
1795 	do {
1796 		if (sc->sc_bus_ops->bs_rxctl(sc, (void *)dcmd, &size)) {
1797 			DPRINTF(("%s: rx failed\n", DEVNAME(sc)));
1798 			goto err;
1799 		}
1800 		dcmd->hdr.cmd = le32toh(dcmd->hdr.cmd);
1801 		dcmd->hdr.len = le32toh(dcmd->hdr.len);
1802 		dcmd->hdr.flags = le32toh(dcmd->hdr.flags);
1803 		dcmd->hdr.status = le32toh(dcmd->hdr.status);
1804 	} while (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid);
1805 
1806 	if (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid) {
1807 		printf("%s: unexpected request id\n", DEVNAME(sc));
1808 		goto err;
1809 	}
1810 
1811 	if (dcmd->hdr.flags & BWFM_BCDC_DCMD_ERROR)
1812 		return dcmd->hdr.status;
1813 
1814 	ret = 0;
1815 err:
1816 	kmem_free(dcmd, sizeof(*dcmd));
1817 	return ret;
1818 }
1819 
1820 void
bwfm_process_blob(struct bwfm_softc * sc,const char * var,uint8_t ** blob,size_t * blobsize)1821 bwfm_process_blob(struct bwfm_softc *sc, const char *var, uint8_t **blob,
1822     size_t *blobsize)
1823 {
1824 	struct bwfm_dload_data *data;
1825 	size_t off, remain, len;
1826 
1827 	if (*blob == NULL || *blobsize == 0)
1828 		return;
1829 
1830 	off = 0;
1831 	remain = *blobsize;
1832 	data = kmem_alloc(sizeof(*data) + BWFM_DLOAD_MAX_LEN, KM_SLEEP);
1833 
1834 	while (remain) {
1835 		len = uimin(remain, BWFM_DLOAD_MAX_LEN);
1836 
1837 		data->flag = htole16(BWFM_DLOAD_FLAG_HANDLER_VER_1);
1838 		if (off == 0)
1839 			data->flag |= htole16(BWFM_DLOAD_FLAG_BEGIN);
1840 		if (remain <= BWFM_DLOAD_MAX_LEN)
1841 			data->flag |= htole16(BWFM_DLOAD_FLAG_END);
1842 		data->type = htole16(BWFM_DLOAD_TYPE_CLM);
1843 		data->len = htole32(len);
1844 		data->crc = 0;
1845 		memcpy(data->data, *blob + off, len);
1846 
1847 		if (bwfm_fwvar_var_set_data(sc, var, data,
1848 		    sizeof(*data) + len)) {
1849 			printf("%s: could not load blob (%s)\n", DEVNAME(sc),
1850 			    var);
1851 			break;
1852 		}
1853 
1854 		off += len;
1855 		remain -= len;
1856 	}
1857 
1858 	kmem_free(data, sizeof(*data) + BWFM_DLOAD_MAX_LEN);
1859 	// kmem_free(*blob, *blobsize);
1860 	*blob = NULL;
1861 	*blobsize = 0;
1862 }
1863 
1864 /* FW Variable code */
1865 int
bwfm_fwvar_cmd_get_data(struct bwfm_softc * sc,int cmd,void * data,size_t len)1866 bwfm_fwvar_cmd_get_data(struct bwfm_softc *sc, int cmd, void *data, size_t len)
1867 {
1868 	return sc->sc_proto_ops->proto_query_dcmd(sc, 0, cmd, data, &len);
1869 }
1870 
1871 int
bwfm_fwvar_cmd_set_data(struct bwfm_softc * sc,int cmd,void * data,size_t len)1872 bwfm_fwvar_cmd_set_data(struct bwfm_softc *sc, int cmd, void *data, size_t len)
1873 {
1874 	return sc->sc_proto_ops->proto_set_dcmd(sc, 0, cmd, data, len);
1875 }
1876 
1877 int
bwfm_fwvar_cmd_get_int(struct bwfm_softc * sc,int cmd,uint32_t * data)1878 bwfm_fwvar_cmd_get_int(struct bwfm_softc *sc, int cmd, uint32_t *data)
1879 {
1880 	int ret;
1881 	ret = bwfm_fwvar_cmd_get_data(sc, cmd, data, sizeof(*data));
1882 	*data = le32toh(*data);
1883 	return ret;
1884 }
1885 
1886 int
bwfm_fwvar_cmd_set_int(struct bwfm_softc * sc,int cmd,uint32_t data)1887 bwfm_fwvar_cmd_set_int(struct bwfm_softc *sc, int cmd, uint32_t data)
1888 {
1889 	data = htole32(data);
1890 	return bwfm_fwvar_cmd_set_data(sc, cmd, &data, sizeof(data));
1891 }
1892 
1893 int
bwfm_fwvar_var_get_data(struct bwfm_softc * sc,const char * name,void * data,size_t len)1894 bwfm_fwvar_var_get_data(struct bwfm_softc *sc, const char *name, void *data, size_t len)
1895 {
1896 	char *buf;
1897 	int ret;
1898 
1899 	buf = kmem_alloc(strlen(name) + 1 + len, KM_SLEEP);
1900 	memcpy(buf, name, strlen(name) + 1);
1901 	memcpy(buf + strlen(name) + 1, data, len);
1902 	ret = bwfm_fwvar_cmd_get_data(sc, BWFM_C_GET_VAR,
1903 	    buf, strlen(name) + 1 + len);
1904 	memcpy(data, buf, len);
1905 	kmem_free(buf, strlen(name) + 1 + len);
1906 	return ret;
1907 }
1908 
1909 int
bwfm_fwvar_var_set_data(struct bwfm_softc * sc,const char * name,void * data,size_t len)1910 bwfm_fwvar_var_set_data(struct bwfm_softc *sc, const char *name, void *data, size_t len)
1911 {
1912 	char *buf;
1913 	int ret;
1914 
1915 	buf = kmem_alloc(strlen(name) + 1 + len, KM_SLEEP);
1916 	memcpy(buf, name, strlen(name) + 1);
1917 	memcpy(buf + strlen(name) + 1, data, len);
1918 	ret = bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_VAR,
1919 	    buf, strlen(name) + 1 + len);
1920 	kmem_free(buf, strlen(name) + 1 + len);
1921 	return ret;
1922 }
1923 
1924 int
bwfm_fwvar_var_get_int(struct bwfm_softc * sc,const char * name,uint32_t * data)1925 bwfm_fwvar_var_get_int(struct bwfm_softc *sc, const char *name, uint32_t *data)
1926 {
1927 	int ret;
1928 	ret = bwfm_fwvar_var_get_data(sc, name, data, sizeof(*data));
1929 	*data = le32toh(*data);
1930 	return ret;
1931 }
1932 
1933 int
bwfm_fwvar_var_set_int(struct bwfm_softc * sc,const char * name,uint32_t data)1934 bwfm_fwvar_var_set_int(struct bwfm_softc *sc, const char *name, uint32_t data)
1935 {
1936 	data = htole32(data);
1937 	return bwfm_fwvar_var_set_data(sc, name, &data, sizeof(data));
1938 }
1939 
1940 /* 802.11 code */
1941 void
bwfm_scan(struct bwfm_softc * sc)1942 bwfm_scan(struct bwfm_softc *sc)
1943 {
1944 	struct bwfm_escan_params *params;
1945 	uint32_t nssid = 0, nchannel = 0;
1946 	size_t params_size;
1947 
1948 #if 0
1949 	/* Active scan is used for scanning for an SSID */
1950 	bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PASSIVE_SCAN, 0);
1951 #endif
1952 	bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PASSIVE_SCAN, 1);
1953 
1954 	params_size = sizeof(*params);
1955 	params_size += sizeof(uint32_t) * ((nchannel + 1) / 2);
1956 	params_size += sizeof(struct bwfm_ssid) * nssid;
1957 
1958 	params = kmem_zalloc(params_size, KM_SLEEP);
1959 	memset(params->scan_params.bssid, 0xff,
1960 	    sizeof(params->scan_params.bssid));
1961 	params->scan_params.bss_type = 2;
1962 	params->scan_params.nprobes = htole32(-1);
1963 	params->scan_params.active_time = htole32(-1);
1964 	params->scan_params.passive_time = htole32(-1);
1965 	params->scan_params.home_time = htole32(-1);
1966 	params->version = htole32(BWFM_ESCAN_REQ_VERSION);
1967 	params->action = htole16(WL_ESCAN_ACTION_START);
1968 	params->sync_id = htole16(0x1234);
1969 
1970 #if 0
1971 	/* Scan a specific channel */
1972 	params->scan_params.channel_list[0] = htole16(
1973 	    (1 & 0xff) << 0 |
1974 	    (3 & 0x3) << 8 |
1975 	    (2 & 0x3) << 10 |
1976 	    (2 & 0x3) << 12
1977 	    );
1978 	params->scan_params.channel_num = htole32(
1979 	    (1 & 0xffff) << 0
1980 	    );
1981 #endif
1982 
1983 	bwfm_fwvar_var_set_data(sc, "escan", params, params_size);
1984 	kmem_free(params, params_size);
1985 }
1986 
1987 static __inline int
bwfm_iswpaoui(const uint8_t * frm)1988 bwfm_iswpaoui(const uint8_t *frm)
1989 {
1990 	return frm[1] > 3 && le32dec(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
1991 }
1992 
1993 /*
1994  * Derive wireless security settings from WPA/RSN IE.
1995  */
1996 static uint32_t
bwfm_get_wsec(struct bwfm_softc * sc)1997 bwfm_get_wsec(struct bwfm_softc *sc)
1998 {
1999 	struct ieee80211com *ic = &sc->sc_ic;
2000 	uint8_t *wpa = ic->ic_opt_ie;
2001 
2002 	KASSERT(ic->ic_opt_ie_len > 0);
2003 
2004 	if (wpa[0] != IEEE80211_ELEMID_RSN) {
2005 		if (ic->ic_opt_ie_len < 12)
2006 			return BWFM_WSEC_NONE;
2007 
2008 		/* non-RSN IE, expect that we are doing WPA1 */
2009 		if ((ic->ic_flags & IEEE80211_F_WPA1) == 0)
2010 			return BWFM_WSEC_NONE;
2011 
2012 		/* Must contain WPA OUI */
2013 		if (!bwfm_iswpaoui(wpa))
2014 			return BWFM_WSEC_NONE;
2015 
2016 		switch (le32dec(wpa + 8)) {
2017 		case ((WPA_CSE_TKIP<<24)|WPA_OUI):
2018 			return BWFM_WSEC_TKIP;
2019 		case ((WPA_CSE_CCMP<<24)|WPA_OUI):
2020 			return BWFM_WSEC_AES;
2021 		default:
2022 			return BWFM_WSEC_NONE;
2023 		}
2024 	} else {
2025 		if (ic->ic_opt_ie_len < 14)
2026 			return BWFM_WSEC_NONE;
2027 
2028 		/* RSN IE, expect that we are doing WPA2 */
2029 		if ((ic->ic_flags & IEEE80211_F_WPA2) == 0)
2030 			return BWFM_WSEC_NONE;
2031 
2032 		switch (le32dec(wpa + 10)) {
2033 		case ((RSN_CSE_TKIP<<24)|RSN_OUI):
2034 			return BWFM_WSEC_TKIP;
2035 		case ((RSN_CSE_CCMP<<24)|RSN_OUI):
2036 			return BWFM_WSEC_AES;
2037 		default:
2038 			return BWFM_WSEC_NONE;
2039 		}
2040 	}
2041 }
2042 
2043 void
bwfm_connect(struct bwfm_softc * sc)2044 bwfm_connect(struct bwfm_softc *sc)
2045 {
2046 	struct ieee80211com *ic = &sc->sc_ic;
2047 	struct ieee80211_node *ni = ic->ic_bss;
2048 	struct bwfm_ext_join_params *params;
2049 
2050 	if (ic->ic_flags & IEEE80211_F_WPA) {
2051 		uint32_t wsec = 0;
2052 		uint32_t wpa = 0;
2053 
2054 		if (ic->ic_opt_ie_len)
2055 			bwfm_fwvar_var_set_data(sc, "wpaie", ic->ic_opt_ie, ic->ic_opt_ie_len);
2056 
2057 		if (ic->ic_flags & IEEE80211_F_WPA1)
2058 			wpa |= BWFM_WPA_AUTH_WPA_PSK;
2059 		if (ic->ic_flags & IEEE80211_F_WPA2)
2060 			wpa |= BWFM_WPA_AUTH_WPA2_PSK;
2061 
2062 		wsec |= bwfm_get_wsec(sc);
2063 
2064 		DPRINTF(("%s: WPA enabled, ic_flags = 0x%x, wpa 0x%x, wsec 0x%x\n",
2065 		    DEVNAME(sc), ic->ic_flags, wpa, wsec));
2066 
2067 		bwfm_fwvar_var_set_int(sc, "wpa_auth", wpa);
2068 		bwfm_fwvar_var_set_int(sc, "wsec", wsec);
2069 	} else {
2070 		bwfm_fwvar_var_set_int(sc, "wpa_auth", BWFM_WPA_AUTH_DISABLED);
2071 		bwfm_fwvar_var_set_int(sc, "wsec", BWFM_WSEC_NONE);
2072 	}
2073 
2074 	bwfm_fwvar_var_set_int(sc, "auth", BWFM_AUTH_OPEN);
2075 	bwfm_fwvar_var_set_int(sc, "mfp", BWFM_MFP_NONE);
2076 
2077 	if (ni->ni_esslen && ni->ni_esslen < BWFM_MAX_SSID_LEN) {
2078 		params = kmem_zalloc(sizeof(*params), KM_SLEEP);
2079 		memcpy(params->ssid.ssid, ni->ni_essid, ni->ni_esslen);
2080 		params->ssid.len = htole32(ni->ni_esslen);
2081 		memcpy(params->assoc.bssid, ni->ni_bssid, sizeof(params->assoc.bssid));
2082 		params->scan.scan_type = -1;
2083 		params->scan.nprobes = htole32(-1);
2084 		params->scan.active_time = htole32(-1);
2085 		params->scan.passive_time = htole32(-1);
2086 		params->scan.home_time = htole32(-1);
2087 		if (bwfm_fwvar_var_set_data(sc, "join", params, sizeof(*params))) {
2088 			struct bwfm_join_params join;
2089 			memset(&join, 0, sizeof(join));
2090 			memcpy(join.ssid.ssid, ni->ni_essid, ni->ni_esslen);
2091 			join.ssid.len = htole32(ni->ni_esslen);
2092 			memcpy(join.assoc.bssid, ni->ni_bssid, sizeof(join.assoc.bssid));
2093 			bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID, &join,
2094 			    sizeof(join));
2095 		}
2096 		kmem_free(params, sizeof(*params));
2097 	}
2098 }
2099 
2100 void
bwfm_get_sta_info(struct bwfm_softc * sc,struct ifmediareq * ifmr)2101 bwfm_get_sta_info(struct bwfm_softc *sc, struct ifmediareq *ifmr)
2102 {
2103 	struct ieee80211com *ic = &sc->sc_ic;
2104 	struct ieee80211_node *ni = ic->ic_bss;
2105 	struct bwfm_sta_info sta;
2106 	uint32_t flags, txrate;
2107 
2108 	memset(&sta, 0, sizeof(sta));
2109 	memcpy(&sta, ni->ni_macaddr, sizeof(ni->ni_macaddr));
2110 
2111 	if (bwfm_fwvar_var_get_data(sc, "sta_info", &sta, sizeof(sta)))
2112 		return;
2113 
2114 	if (!IEEE80211_ADDR_EQ(ni->ni_macaddr, sta.ea))
2115 		return;
2116 
2117 	if (le16toh(sta.ver) < 4)
2118 		return;
2119 
2120 	flags = le32toh(sta.flags);
2121 	if ((flags & BWFM_STA_SCBSTATS) == 0)
2122 		return;
2123 
2124 	txrate = le32toh(sta.tx_rate);
2125 	if (txrate == 0xffffffff)
2126 		return;
2127 
2128 	if ((flags & BWFM_STA_VHT_CAP) != 0) {
2129 		ifmr->ifm_active &= ~IFM_TMASK;
2130 		ifmr->ifm_active |= IFM_IEEE80211_VHT;
2131 		ifmr->ifm_active &= ~IFM_MMASK;
2132 		ifmr->ifm_active |= IFM_IEEE80211_11AC;
2133 	} else if ((flags & BWFM_STA_N_CAP) != 0) {
2134 		ifmr->ifm_active &= ~IFM_TMASK;
2135 		ifmr->ifm_active |= IFM_IEEE80211_MCS;
2136 		ifmr->ifm_active &= ~IFM_MMASK;
2137 		if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
2138 			ifmr->ifm_active |= IFM_IEEE80211_11NG;
2139 		else
2140 			ifmr->ifm_active |= IFM_IEEE80211_11NA;
2141 	}
2142 }
2143 
2144 void
bwfm_rx(struct bwfm_softc * sc,struct mbuf * m)2145 bwfm_rx(struct bwfm_softc *sc, struct mbuf *m)
2146 {
2147 	struct ieee80211com *ic = &sc->sc_ic;
2148 	struct ifnet *ifp = ic->ic_ifp;
2149 	struct bwfm_event *e = mtod(m, struct bwfm_event *);
2150 
2151 	if (m->m_len >= sizeof(e->ehdr) &&
2152 	    ntohs(e->ehdr.ether_type) == BWFM_ETHERTYPE_LINK_CTL &&
2153 	    memcmp(BWFM_BRCM_OUI, e->hdr.oui, sizeof(e->hdr.oui)) == 0 &&
2154 	    ntohs(e->hdr.usr_subtype) == BWFM_BRCM_SUBTYPE_EVENT) {
2155 		bwfm_rx_event(sc, m);
2156 		// m_freem(m);
2157 		return;
2158 	}
2159 
2160 	m_set_rcvif(m, ifp);
2161 	if_percpuq_enqueue(ifp->if_percpuq, m);
2162 }
2163 
2164 void
bwfm_rx_event(struct bwfm_softc * sc,struct mbuf * m)2165 bwfm_rx_event(struct bwfm_softc *sc, struct mbuf *m)
2166 {
2167 	struct bwfm_task *t;
2168 
2169 	t = pool_cache_get(sc->sc_freetask, PR_NOWAIT);
2170 	if (t == NULL) {
2171 		m_freem(m);
2172 		printf("%s: no free tasks\n", DEVNAME(sc));
2173 		return;
2174 	}
2175 
2176 	t->t_sc = sc;
2177 	t->t_cmd = BWFM_TASK_RX_EVENT;
2178 	t->t_mbuf = m;
2179 	workqueue_enqueue(sc->sc_taskq, (struct work*)t, NULL);
2180 }
2181 
2182 void
bwfm_rx_event_cb(struct bwfm_softc * sc,struct mbuf * m)2183 bwfm_rx_event_cb(struct bwfm_softc *sc, struct mbuf *m)
2184 {
2185 	struct ieee80211com *ic = &sc->sc_ic;
2186 	struct bwfm_event *e = mtod(m, void *);
2187 	size_t len = m->m_len;
2188 	int s;
2189 
2190 	DPRINTF(("%s: event %p len %lu datalen %u code %u status %u"
2191 	    " reason %u\n", __func__, e, len, ntohl(e->msg.datalen),
2192 	    ntohl(e->msg.event_type), ntohl(e->msg.status),
2193 	    ntohl(e->msg.reason)));
2194 
2195 	if (ntohl(e->msg.event_type) >= BWFM_E_LAST) {
2196 		m_freem(m);
2197 		return;
2198 	}
2199 
2200 	switch (ntohl(e->msg.event_type)) {
2201 	case BWFM_E_ESCAN_RESULT: {
2202 		struct bwfm_escan_results *res = (void *)&e[1];
2203 		struct bwfm_bss_info *bss;
2204 		int i;
2205 		if (ntohl(e->msg.status) != BWFM_E_STATUS_PARTIAL) {
2206 			/* Scan complete */
2207 			s = splnet();
2208 			if (ic->ic_opmode != IEEE80211_M_MONITOR)
2209 				ieee80211_end_scan(ic);
2210 			splx(s);
2211 			break;
2212 		}
2213 		len -= sizeof(*e);
2214 		if (len < sizeof(*res) || len < le32toh(res->buflen)) {
2215 			m_freem(m);
2216 			printf("%s: results too small\n", DEVNAME(sc));
2217 			return;
2218 		}
2219 		len -= sizeof(*res);
2220 		if (len < le16toh(res->bss_count) * sizeof(struct bwfm_bss_info)) {
2221 			m_freem(m);
2222 			printf("%s: results too small\n", DEVNAME(sc));
2223 			return;
2224 		}
2225 		bss = &res->bss_info[0];
2226 		for (i = 0; i < le16toh(res->bss_count); i++) {
2227 			/* Fix alignment of bss_info */
2228 			if (len > sizeof(sc->sc_bss_buf)) {
2229 				printf("%s: bss_info buffer too big\n", DEVNAME(sc));
2230 			} else {
2231 				memcpy(&sc->sc_bss_buf, &res->bss_info[i], len);
2232 				bwfm_scan_node(sc, &sc->sc_bss_buf.bss_info,
2233 				    len);
2234 			}
2235 			len -= sizeof(*bss) + le32toh(bss->length);
2236 			bss = (void *)(((uintptr_t)bss) + le32toh(bss->length));
2237 			if (len <= 0)
2238 				break;
2239 		}
2240 		break;
2241 		}
2242 
2243 	case BWFM_E_SET_SSID:
2244 		if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS) {
2245 			ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
2246 		} else {
2247 			ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2248 		}
2249 		break;
2250 
2251 	case BWFM_E_ASSOC:
2252 		if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS) {
2253 			ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1);
2254 		} else {
2255 			ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2256 		}
2257 		break;
2258 
2259 	case BWFM_E_LINK:
2260 		if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS &&
2261 		    ntohl(e->msg.reason) == 0)
2262 			break;
2263 
2264 		/* Link status has changed */
2265 		ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2266 		break;
2267 
2268 	default:
2269 		break;
2270 	}
2271 
2272 	m_freem(m);
2273 }
2274 
2275 void
bwfm_scan_node(struct bwfm_softc * sc,struct bwfm_bss_info * bss,size_t len)2276 bwfm_scan_node(struct bwfm_softc *sc, struct bwfm_bss_info *bss, size_t len)
2277 {
2278 	struct ieee80211com *ic = &sc->sc_ic;
2279 	struct ieee80211_frame wh;
2280 	struct ieee80211_scanparams scan;
2281 	uint8_t rates[sizeof(bss->rates) + 2];
2282 	uint8_t ssid[sizeof(bss->ssid) + 2];
2283 	uint8_t *frm, *sfrm, *efrm;
2284 	uint64_t tsf;
2285 
2286 	tsf = 0;
2287 	sfrm = ((uint8_t *)bss) + le16toh(bss->ie_offset);
2288 	efrm = sfrm + le32toh(bss->ie_length);
2289 
2290 	/* Fake a wireless header with the scan result's BSSID */
2291 	memset(&wh, 0, sizeof(wh));
2292 	IEEE80211_ADDR_COPY(wh.i_addr2, bss->bssid);
2293 	IEEE80211_ADDR_COPY(wh.i_addr3, bss->bssid);
2294 
2295 	if (efrm - sfrm < 12) {
2296 		ic->ic_stats.is_rx_elem_toosmall++;
2297 		return;
2298 	}
2299 
2300 	rates[0] = 0;
2301 	rates[1] = le32toh(bss->nrates);
2302 	memcpy(&rates[2], bss->rates, sizeof(bss->rates));
2303 
2304 	ssid[0] = 0;
2305 	ssid[1] = bss->ssid_len;
2306 	memcpy(&ssid[2], bss->ssid, sizeof(bss->ssid));
2307 
2308 	/* Build scan result */
2309 	memset(&scan, 0, sizeof(scan));
2310 	scan.sp_tstamp  = (uint8_t *)&tsf;
2311 	scan.sp_bintval = le16toh(bss->beacon_period);
2312 	scan.sp_capinfo = le16toh(bss->capability);
2313 	scan.sp_bchan   = ieee80211_chan2ieee(ic, ic->ic_curchan);
2314 	scan.sp_chan    = scan.sp_bchan;
2315 	scan.sp_rates   = rates;
2316 	scan.sp_ssid    = ssid;
2317 
2318 	for (frm = sfrm; frm < efrm; frm += frm[1] + 2) {
2319 		switch (frm[0]) {
2320 		case IEEE80211_ELEMID_COUNTRY:
2321 			scan.sp_country = frm;
2322 			break;
2323 		case IEEE80211_ELEMID_FHPARMS:
2324 			if (ic->ic_phytype == IEEE80211_T_FH) {
2325 				if (frm + 6 >= efrm)
2326 					break;
2327 				scan.sp_fhdwell = le16dec(&frm[2]);
2328 				scan.sp_chan = IEEE80211_FH_CHAN(frm[4], frm[5]);
2329 				scan.sp_fhindex = frm[6];
2330 			}
2331 			break;
2332 		case IEEE80211_ELEMID_DSPARMS:
2333 			if (ic->ic_phytype != IEEE80211_T_FH) {
2334 				if (frm + 2 >= efrm)
2335 					break;
2336 				scan.sp_chan = frm[2];
2337 			}
2338 			break;
2339 		case IEEE80211_ELEMID_TIM:
2340 			scan.sp_tim = frm;
2341 			scan.sp_timoff = frm - sfrm;
2342 			break;
2343 		case IEEE80211_ELEMID_XRATES:
2344 			scan.sp_xrates = frm;
2345 			break;
2346 		case IEEE80211_ELEMID_ERP:
2347 			if (frm + 1 >= efrm)
2348 				break;
2349 			if (frm[1] != 1) {
2350 				ic->ic_stats.is_rx_elem_toobig++;
2351 				break;
2352 			}
2353 			scan.sp_erp = frm[2];
2354 			break;
2355 		case IEEE80211_ELEMID_RSN:
2356 			scan.sp_wpa = frm;
2357 			break;
2358 		case IEEE80211_ELEMID_VENDOR:
2359 			if (frm + 1 >= efrm)
2360 				break;
2361 			if (frm + frm[1] + 2 >= efrm)
2362 				break;
2363 			if (bwfm_iswpaoui(frm))
2364 				scan.sp_wpa = frm;
2365 			break;
2366 		}
2367 		if (frm + 1 >= efrm)
2368 			break;
2369 	}
2370 
2371 	if (ic->ic_flags & IEEE80211_F_SCAN)
2372 		ieee80211_add_scan(ic, &scan, &wh, IEEE80211_FC0_SUBTYPE_BEACON,
2373 		    le32toh(bss->rssi), 0);
2374 }
2375