bwfm.c revision 1.34 1 /* $NetBSD: bwfm.c,v 1.34 2022/12/04 09:25:04 mlelstv 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 (at) 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 *);
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
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
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
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
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 *
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 *
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
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
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
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
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
640 if (ic->ic_flags & IEEE80211_F_PMGTON) {
641 sc->sc_pm = BWFM_PM_FAST_PS;
642 #ifndef IEEE80211_STA_ONLY
643 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
644 sc->sc_pm = BWFM_PM_CAM;
645 #endif
646 } else {
647 sc->sc_pm = BWFM_PM_CAM;
648 }
649 sc->sc_setpm = true;
650
651 bwfm_fwvar_var_set_int(sc, "txbf", 1);
652 bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 0);
653 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 1);
654 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 0);
655
656 /* Disable all offloading (ARP, NDP, TCP/UDP cksum). */
657 bwfm_fwvar_var_set_int(sc, "arp_ol", 0);
658 bwfm_fwvar_var_set_int(sc, "arpoe", 0);
659 bwfm_fwvar_var_set_int(sc, "ndoe", 0);
660 bwfm_fwvar_var_set_int(sc, "toe", 0);
661
662 /* Accept all multicast frames. */
663 bwfm_fwvar_var_set_int(sc, "allmulti", 1);
664
665 /* Setup promiscuous mode */
666 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PROMISC,
667 (ifp->if_flags & IFF_PROMISC) ? 1 : 0);
668
669 /*
670 * Tell the firmware supplicant that we are going to handle the
671 * WPA handshake ourselves.
672 */
673 bwfm_fwvar_var_set_int(sc, "sup_wpa", 0);
674
675 ifp->if_flags |= IFF_RUNNING;
676 ifp->if_flags &= ~IFF_OACTIVE;
677
678 if (ic->ic_opmode != IEEE80211_M_MONITOR) {
679 if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL)
680 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
681 } else {
682 ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
683 }
684
685 return 0;
686 }
687
688 void
689 bwfm_stop(struct ifnet *ifp, int disable)
690 {
691 struct bwfm_softc *sc = ifp->if_softc;
692 struct ieee80211com *ic = &sc->sc_ic;
693 struct bwfm_join_params join;
694
695 sc->sc_tx_timer = 0;
696 ifp->if_timer = 0;
697 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
698
699 ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
700
701 memset(&join, 0, sizeof(join));
702 bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID, &join, sizeof(join));
703 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, 0);
704 bwfm_fwvar_cmd_set_int(sc, BWFM_C_DOWN, 1);
705 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 0);
706 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 0);
707 bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 1);
708 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, BWFM_PM_FAST_PS);
709 bwfm_fwvar_var_set_int(sc, "mpc", 1);
710
711 if (sc->sc_bus_ops->bs_stop)
712 sc->sc_bus_ops->bs_stop(sc);
713
714 sc->sc_setpm = true;
715 }
716
717 void
718 bwfm_watchdog(struct ifnet *ifp)
719 {
720 struct bwfm_softc *sc = ifp->if_softc;
721 struct ieee80211com *ic = &sc->sc_ic;
722
723 ifp->if_timer = 0;
724
725 if (sc->sc_tx_timer > 0) {
726 if (--sc->sc_tx_timer == 0) {
727 printf("%s: device timeout\n", DEVNAME(sc));
728 if_statinc(ifp, if_oerrors);
729 return;
730 }
731 ifp->if_timer = 1;
732 }
733 ieee80211_watchdog(ic);
734 }
735
736 int
737 bwfm_ioctl(struct ifnet *ifp, u_long cmd, void *data)
738 {
739 struct bwfm_softc *sc = ifp->if_softc;
740 struct ieee80211com *ic = &sc->sc_ic;
741 int s, error = 0, oflags;
742
743 s = splnet();
744
745 switch (cmd) {
746 case SIOCSIFFLAGS:
747 oflags = ifp->if_flags;
748 if ((error = ifioctl_common(ifp, cmd, data)) != 0)
749 break;
750 switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
751 case IFF_UP | IFF_RUNNING:
752 break;
753 case IFF_UP:
754 if ((oflags & IFF_UP) == 0)
755 bwfm_init(ifp);
756 break;
757 case IFF_RUNNING:
758 if ((oflags & IFF_UP) != 0)
759 bwfm_stop(ifp, 1);
760 break;
761 case 0:
762 break;
763 }
764 break;
765
766 case SIOCADDMULTI:
767 case SIOCDELMULTI:
768 if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) {
769 /* setup multicast filter, etc */
770 error = 0;
771 }
772 break;
773
774 case SIOCGIFMEDIA:
775 error = ieee80211_ioctl(ic, cmd, data);
776 if (error == 0 && ic->ic_state == IEEE80211_S_RUN)
777 bwfm_get_sta_info(sc, (struct ifmediareq *)data);
778 break;
779
780 default:
781 error = ieee80211_ioctl(ic, cmd, data);
782 }
783
784 if (error == ENETRESET) {
785 if ((ifp->if_flags & IFF_UP) != 0 &&
786 (ifp->if_flags & IFF_RUNNING) != 0) {
787 bwfm_init(ifp);
788 }
789 error = 0;
790 }
791
792 splx(s);
793
794 return error;
795 }
796
797 int
798 bwfm_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
799 int type, int arg)
800 {
801 return 0;
802 }
803
804 void
805 bwfm_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
806 struct ieee80211_node *ni, int subtype, int rssi, uint32_t rstamp)
807 {
808 }
809
810 int
811 bwfm_key_set(struct ieee80211com *ic, const struct ieee80211_key *wk,
812 const uint8_t mac[IEEE80211_ADDR_LEN])
813 {
814 struct bwfm_softc *sc = ic->ic_ifp->if_softc;
815 struct bwfm_task *t;
816
817 t = pool_cache_get(sc->sc_freetask, PR_NOWAIT);
818 if (t == NULL) {
819 printf("%s: no free tasks\n", DEVNAME(sc));
820 return 0;
821 }
822
823 t->t_sc = sc;
824 t->t_cmd = BWFM_TASK_KEY_SET;
825 t->t_key.key = wk;
826 memcpy(t->t_key.mac, mac, sizeof(t->t_key.mac));
827 workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL);
828 return 1;
829 }
830
831 static void
832 bwfm_key_set_cb(struct bwfm_softc *sc, struct bwfm_cmd_key *ck)
833 {
834 const struct ieee80211_key *wk = ck->key;
835 const uint8_t *mac = ck->mac;
836 struct bwfm_wsec_key wsec_key;
837 uint32_t wsec_enable, wsec;
838 bool ext_key;
839
840 #ifdef BWFM_DEBUG
841 printf("key_set: key cipher %s len %d: ", wk->wk_cipher->ic_name, wk->wk_keylen);
842 for (int j = 0; j < sizeof(wk->wk_key); j++)
843 printf("%02x", wk->wk_key[j]);
844 #endif
845
846 if ((wk->wk_flags & IEEE80211_KEY_GROUP) == 0 &&
847 wk->wk_cipher->ic_cipher != IEEE80211_CIPHER_WEP) {
848 ext_key = true;
849 } else {
850 ext_key = false;
851 }
852
853 #ifdef BWFM_DEBUG
854 printf(", ext_key = %d", ext_key);
855 printf(", mac = %02x:%02x:%02x:%02x:%02x:%02x",
856 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
857 printf("\n");
858 #endif
859
860 memset(&wsec_key, 0, sizeof(wsec_key));
861 if (ext_key && !IEEE80211_IS_MULTICAST(mac))
862 memcpy(wsec_key.ea, mac, sizeof(wsec_key.ea));
863 wsec_key.index = htole32(wk->wk_keyix);
864 wsec_key.len = htole32(wk->wk_keylen);
865 memcpy(wsec_key.data, wk->wk_key, sizeof(wsec_key.data));
866 if (!ext_key)
867 wsec_key.flags = htole32(BWFM_WSEC_PRIMARY_KEY);
868
869 switch (wk->wk_cipher->ic_cipher) {
870 case IEEE80211_CIPHER_WEP:
871 if (wk->wk_keylen == 5)
872 wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_WEP1);
873 else if (wk->wk_keylen == 13)
874 wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_WEP128);
875 else
876 return;
877 wsec_enable = BWFM_WSEC_WEP;
878 break;
879 case IEEE80211_CIPHER_TKIP:
880 wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_TKIP);
881 wsec_enable = BWFM_WSEC_TKIP;
882 break;
883 case IEEE80211_CIPHER_AES_CCM:
884 wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_AES_CCM);
885 wsec_enable = BWFM_WSEC_AES;
886 break;
887 default:
888 printf("%s: %s: cipher %s not supported\n", DEVNAME(sc),
889 __func__, wk->wk_cipher->ic_name);
890 return;
891 }
892
893 if (bwfm_fwvar_var_set_data(sc, "wsec_key", &wsec_key, sizeof(wsec_key)))
894 return;
895
896 bwfm_fwvar_var_set_int(sc, "wpa_auth", BWFM_WPA_AUTH_WPA2_PSK);
897
898 bwfm_fwvar_var_get_int(sc, "wsec", &wsec);
899 wsec |= wsec_enable;
900 bwfm_fwvar_var_set_int(sc, "wsec", wsec);
901 }
902
903 int
904 bwfm_key_delete(struct ieee80211com *ic, const struct ieee80211_key *wk)
905 {
906 struct bwfm_softc *sc = ic->ic_ifp->if_softc;
907 struct bwfm_task *t;
908
909 t = pool_cache_get(sc->sc_freetask, PR_NOWAIT);
910 if (t == NULL) {
911 printf("%s: no free tasks\n", DEVNAME(sc));
912 return 0;
913 }
914
915 t->t_sc = sc;
916 t->t_cmd = BWFM_TASK_KEY_DELETE;
917 t->t_key.key = wk;
918 memset(t->t_key.mac, 0, sizeof(t->t_key.mac));
919 workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL);
920
921 return 1;
922 }
923
924 static void
925 bwfm_key_delete_cb(struct bwfm_softc *sc, struct bwfm_cmd_key *ck)
926 {
927 const struct ieee80211_key *wk = ck->key;
928 struct bwfm_wsec_key wsec_key;
929
930 memset(&wsec_key, 0, sizeof(wsec_key));
931 wsec_key.index = htole32(wk->wk_keyix);
932 wsec_key.flags = htole32(BWFM_WSEC_PRIMARY_KEY);
933
934 if (bwfm_fwvar_var_set_data(sc, "wsec_key", &wsec_key, sizeof(wsec_key)))
935 return;
936 }
937
938 int
939 bwfm_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
940 {
941 struct bwfm_softc *sc = ic->ic_ifp->if_softc;
942 struct bwfm_task *t;
943
944 t = pool_cache_get(sc->sc_freetask, PR_NOWAIT);
945 if (t == NULL) {
946 printf("%s: no free tasks\n", DEVNAME(sc));
947 return EIO;
948 }
949
950 t->t_sc = sc;
951 t->t_cmd = BWFM_TASK_NEWSTATE;
952 t->t_newstate.state = nstate;
953 t->t_newstate.arg = arg;
954 workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL);
955
956 return 0;
957 }
958
959 void
960 bwfm_newstate_cb(struct bwfm_softc *sc, struct bwfm_cmd_newstate *cmd)
961 {
962 struct ieee80211com *ic = &sc->sc_ic;
963 enum ieee80211_state ostate = ic->ic_state;
964 enum ieee80211_state nstate = cmd->state;
965 int s;
966
967 DPRINTF(("%s: newstate %d -> %d\n", DEVNAME(sc), ostate, nstate));
968
969 s = splnet();
970
971 switch (nstate) {
972 case IEEE80211_S_INIT:
973 break;
974
975 case IEEE80211_S_SCAN:
976 if (ostate != IEEE80211_S_SCAN) {
977 /* Start of scanning */
978 bwfm_scan(sc);
979 }
980 break;
981
982 case IEEE80211_S_AUTH:
983 bwfm_connect(sc);
984 break;
985
986 case IEEE80211_S_ASSOC:
987 break;
988
989 case IEEE80211_S_RUN:
990 break;
991 }
992
993 sc->sc_newstate(ic, nstate, cmd->arg);
994
995 splx(s);
996 }
997
998 void
999 bwfm_newassoc(struct ieee80211_node *ni, int isnew)
1000 {
1001 /* Firmware handles rate adaptation for us */
1002 ni->ni_txrate = 0;
1003 }
1004
1005 void
1006 bwfm_task(struct work *wk, void *arg)
1007 {
1008 struct bwfm_task *t = (struct bwfm_task *)wk;
1009 struct bwfm_softc *sc = t->t_sc;
1010
1011 switch (t->t_cmd) {
1012 case BWFM_TASK_NEWSTATE:
1013 bwfm_newstate_cb(sc, &t->t_newstate);
1014 break;
1015 case BWFM_TASK_KEY_SET:
1016 bwfm_key_set_cb(sc, &t->t_key);
1017 break;
1018 case BWFM_TASK_KEY_DELETE:
1019 bwfm_key_delete_cb(sc, &t->t_key);
1020 break;
1021 case BWFM_TASK_RX_EVENT:
1022 bwfm_rx_event_cb(sc, t->t_mbuf);
1023 break;
1024 default:
1025 panic("bwfm: unknown task command %d", t->t_cmd);
1026 }
1027
1028 pool_cache_put(sc->sc_freetask, t);
1029 }
1030
1031 int
1032 bwfm_media_change(struct ifnet *ifp)
1033 {
1034 return 0;
1035 }
1036
1037 /* Chip initialization (SDIO, PCIe) */
1038 int
1039 bwfm_chip_attach(struct bwfm_softc *sc)
1040 {
1041 struct bwfm_core *core;
1042 int need_socram = 0;
1043 int has_socram = 0;
1044 int cpu_found = 0;
1045 uint32_t val;
1046
1047 LIST_INIT(&sc->sc_chip.ch_list);
1048
1049 if (sc->sc_buscore_ops->bc_prepare(sc) != 0) {
1050 printf("%s: failed buscore prepare\n", DEVNAME(sc));
1051 return 1;
1052 }
1053
1054 val = sc->sc_buscore_ops->bc_read(sc,
1055 BWFM_CHIP_BASE + BWFM_CHIP_REG_CHIPID);
1056 sc->sc_chip.ch_chip = BWFM_CHIP_CHIPID_ID(val);
1057 sc->sc_chip.ch_chiprev = BWFM_CHIP_CHIPID_REV(val);
1058
1059 if ((sc->sc_chip.ch_chip > 0xa000) || (sc->sc_chip.ch_chip < 0x4000))
1060 snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name),
1061 "%d", sc->sc_chip.ch_chip);
1062 else
1063 snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name),
1064 "%x", sc->sc_chip.ch_chip);
1065
1066 switch (BWFM_CHIP_CHIPID_TYPE(val))
1067 {
1068 case BWFM_CHIP_CHIPID_TYPE_SOCI_SB:
1069 printf("%s: SoC interconnect SB not implemented\n",
1070 DEVNAME(sc));
1071 return 1;
1072 case BWFM_CHIP_CHIPID_TYPE_SOCI_AI:
1073 sc->sc_chip.ch_core_isup = bwfm_chip_ai_isup;
1074 sc->sc_chip.ch_core_disable = bwfm_chip_ai_disable;
1075 sc->sc_chip.ch_core_reset = bwfm_chip_ai_reset;
1076 bwfm_chip_dmp_erom_scan(sc);
1077 break;
1078 default:
1079 printf("%s: SoC interconnect %d unknown\n",
1080 DEVNAME(sc), BWFM_CHIP_CHIPID_TYPE(val));
1081 return 1;
1082 }
1083
1084 LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link) {
1085 DPRINTF(("%s: 0x%x:%-2d base 0x%08x wrap 0x%08x\n",
1086 DEVNAME(sc), core->co_id, core->co_rev,
1087 core->co_base, core->co_wrapbase));
1088
1089 switch (core->co_id) {
1090 case BWFM_AGENT_CORE_ARM_CM3:
1091 need_socram = true;
1092 /* FALLTHROUGH */
1093 case BWFM_AGENT_CORE_ARM_CR4:
1094 case BWFM_AGENT_CORE_ARM_CA7:
1095 cpu_found = true;
1096 break;
1097 case BWFM_AGENT_INTERNAL_MEM:
1098 has_socram = true;
1099 break;
1100 default:
1101 break;
1102 }
1103 }
1104
1105 if (!cpu_found) {
1106 printf("%s: CPU core not detected\n", DEVNAME(sc));
1107 return 1;
1108 }
1109 if (need_socram && !has_socram) {
1110 printf("%s: RAM core not provided\n", DEVNAME(sc));
1111 return 1;
1112 }
1113
1114 bwfm_chip_set_passive(sc);
1115
1116 if (sc->sc_buscore_ops->bc_reset) {
1117 sc->sc_buscore_ops->bc_reset(sc);
1118 bwfm_chip_set_passive(sc);
1119 }
1120
1121 if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4)) != NULL) {
1122 bwfm_chip_tcm_ramsize(sc, core);
1123 bwfm_chip_tcm_rambase(sc);
1124 } else if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_SYS_MEM)) != NULL) {
1125 bwfm_chip_sysmem_ramsize(sc, core);
1126 bwfm_chip_tcm_rambase(sc);
1127 } else if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM)) != NULL) {
1128 bwfm_chip_socram_ramsize(sc, core);
1129 }
1130
1131 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
1132 sc->sc_chip.ch_cc_caps = sc->sc_buscore_ops->bc_read(sc,
1133 core->co_base + BWFM_CHIP_REG_CAPABILITIES);
1134 sc->sc_chip.ch_cc_caps_ext = sc->sc_buscore_ops->bc_read(sc,
1135 core->co_base + BWFM_CHIP_REG_CAPABILITIES_EXT);
1136
1137 core = bwfm_chip_get_pmu(sc);
1138 if (sc->sc_chip.ch_cc_caps & BWFM_CHIP_REG_CAPABILITIES_PMU) {
1139 sc->sc_chip.ch_pmucaps = sc->sc_buscore_ops->bc_read(sc,
1140 core->co_base + BWFM_CHIP_REG_PMUCAPABILITIES);
1141 sc->sc_chip.ch_pmurev = sc->sc_chip.ch_pmucaps &
1142 BWFM_CHIP_REG_PMUCAPABILITIES_REV_MASK;
1143 }
1144
1145 if (sc->sc_buscore_ops->bc_setup)
1146 sc->sc_buscore_ops->bc_setup(sc);
1147
1148 return 0;
1149 }
1150
1151 struct bwfm_core *
1152 bwfm_chip_get_core(struct bwfm_softc *sc, int id)
1153 {
1154 struct bwfm_core *core;
1155
1156 LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link) {
1157 if (core->co_id == id)
1158 return core;
1159 }
1160
1161 return NULL;
1162 }
1163
1164 struct bwfm_core *
1165 bwfm_chip_get_pmu(struct bwfm_softc *sc)
1166 {
1167 struct bwfm_core *cc, *pmu;
1168
1169 cc = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
1170 if (cc->co_rev >= 35 && sc->sc_chip.ch_cc_caps_ext &
1171 BWFM_CHIP_REG_CAPABILITIES_EXT_AOB_PRESENT) {
1172 pmu = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_PMU);
1173 if (pmu)
1174 return pmu;
1175 }
1176
1177 return cc;
1178 }
1179
1180 /* Functions for the AI interconnect */
1181 int
1182 bwfm_chip_ai_isup(struct bwfm_softc *sc, struct bwfm_core *core)
1183 {
1184 uint32_t ioctl, reset;
1185
1186 ioctl = sc->sc_buscore_ops->bc_read(sc,
1187 core->co_wrapbase + BWFM_AGENT_IOCTL);
1188 reset = sc->sc_buscore_ops->bc_read(sc,
1189 core->co_wrapbase + BWFM_AGENT_RESET_CTL);
1190
1191 if (((ioctl & (BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK)) ==
1192 BWFM_AGENT_IOCTL_CLK) &&
1193 ((reset & BWFM_AGENT_RESET_CTL_RESET) == 0))
1194 return 1;
1195
1196 return 0;
1197 }
1198
1199 void
1200 bwfm_chip_ai_disable(struct bwfm_softc *sc, struct bwfm_core *core,
1201 uint32_t prereset, uint32_t reset)
1202 {
1203 uint32_t val;
1204 int i;
1205
1206 val = sc->sc_buscore_ops->bc_read(sc,
1207 core->co_wrapbase + BWFM_AGENT_RESET_CTL);
1208 if ((val & BWFM_AGENT_RESET_CTL_RESET) == 0) {
1209
1210 sc->sc_buscore_ops->bc_write(sc,
1211 core->co_wrapbase + BWFM_AGENT_IOCTL,
1212 prereset | BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK);
1213 sc->sc_buscore_ops->bc_read(sc,
1214 core->co_wrapbase + BWFM_AGENT_IOCTL);
1215
1216 sc->sc_buscore_ops->bc_write(sc,
1217 core->co_wrapbase + BWFM_AGENT_RESET_CTL,
1218 BWFM_AGENT_RESET_CTL_RESET);
1219 delay(20);
1220
1221 for (i = 300; i > 0; i--) {
1222 if (sc->sc_buscore_ops->bc_read(sc,
1223 core->co_wrapbase + BWFM_AGENT_RESET_CTL) ==
1224 BWFM_AGENT_RESET_CTL_RESET)
1225 break;
1226 }
1227 if (i == 0)
1228 printf("%s: timeout on core reset\n", DEVNAME(sc));
1229 }
1230
1231 sc->sc_buscore_ops->bc_write(sc,
1232 core->co_wrapbase + BWFM_AGENT_IOCTL,
1233 reset | BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK);
1234 sc->sc_buscore_ops->bc_read(sc,
1235 core->co_wrapbase + BWFM_AGENT_IOCTL);
1236 }
1237
1238 void
1239 bwfm_chip_ai_reset(struct bwfm_softc *sc, struct bwfm_core *core,
1240 uint32_t prereset, uint32_t reset, uint32_t postreset)
1241 {
1242 int i;
1243
1244 bwfm_chip_ai_disable(sc, core, prereset, reset);
1245
1246 for (i = 50; i > 0; i--) {
1247 if ((sc->sc_buscore_ops->bc_read(sc,
1248 core->co_wrapbase + BWFM_AGENT_RESET_CTL) &
1249 BWFM_AGENT_RESET_CTL_RESET) == 0)
1250 break;
1251 sc->sc_buscore_ops->bc_write(sc,
1252 core->co_wrapbase + BWFM_AGENT_RESET_CTL, 0);
1253 delay(60);
1254 }
1255 if (i == 0)
1256 printf("%s: timeout on core reset\n", DEVNAME(sc));
1257
1258 sc->sc_buscore_ops->bc_write(sc,
1259 core->co_wrapbase + BWFM_AGENT_IOCTL,
1260 postreset | BWFM_AGENT_IOCTL_CLK);
1261 sc->sc_buscore_ops->bc_read(sc,
1262 core->co_wrapbase + BWFM_AGENT_IOCTL);
1263 }
1264
1265 void
1266 bwfm_chip_dmp_erom_scan(struct bwfm_softc *sc)
1267 {
1268 uint32_t erom, val, base, wrap;
1269 uint8_t type = 0;
1270 uint16_t id;
1271 uint8_t nmw, nsw, rev;
1272 struct bwfm_core *core;
1273
1274 erom = sc->sc_buscore_ops->bc_read(sc,
1275 BWFM_CHIP_BASE + BWFM_CHIP_REG_EROMPTR);
1276 while (type != BWFM_DMP_DESC_EOT) {
1277 val = sc->sc_buscore_ops->bc_read(sc, erom);
1278 type = val & BWFM_DMP_DESC_MASK;
1279 erom += 4;
1280
1281 if (type != BWFM_DMP_DESC_COMPONENT)
1282 continue;
1283
1284 id = (val & BWFM_DMP_COMP_PARTNUM)
1285 >> BWFM_DMP_COMP_PARTNUM_S;
1286
1287 val = sc->sc_buscore_ops->bc_read(sc, erom);
1288 type = val & BWFM_DMP_DESC_MASK;
1289 erom += 4;
1290
1291 if (type != BWFM_DMP_DESC_COMPONENT) {
1292 printf("%s: not component descriptor\n", DEVNAME(sc));
1293 return;
1294 }
1295
1296 nmw = (val & BWFM_DMP_COMP_NUM_MWRAP)
1297 >> BWFM_DMP_COMP_NUM_MWRAP_S;
1298 nsw = (val & BWFM_DMP_COMP_NUM_SWRAP)
1299 >> BWFM_DMP_COMP_NUM_SWRAP_S;
1300 rev = (val & BWFM_DMP_COMP_REVISION)
1301 >> BWFM_DMP_COMP_REVISION_S;
1302
1303 if (nmw + nsw == 0 && id != BWFM_AGENT_CORE_PMU)
1304 continue;
1305
1306 if (bwfm_chip_dmp_get_regaddr(sc, &erom, &base, &wrap))
1307 continue;
1308
1309 core = kmem_alloc(sizeof(*core), KM_SLEEP);
1310 core->co_id = id;
1311 core->co_base = base;
1312 core->co_wrapbase = wrap;
1313 core->co_rev = rev;
1314 LIST_INSERT_HEAD(&sc->sc_chip.ch_list, core, co_link);
1315 }
1316 }
1317
1318 int
1319 bwfm_chip_dmp_get_regaddr(struct bwfm_softc *sc, uint32_t *erom,
1320 uint32_t *base, uint32_t *wrap)
1321 {
1322 uint8_t type = 0, mpnum __unused = 0;
1323 uint8_t stype, sztype, wraptype;
1324 uint32_t val;
1325
1326 *base = 0;
1327 *wrap = 0;
1328
1329 val = sc->sc_buscore_ops->bc_read(sc, *erom);
1330 type = val & BWFM_DMP_DESC_MASK;
1331 if (type == BWFM_DMP_DESC_MASTER_PORT) {
1332 mpnum = (val & BWFM_DMP_MASTER_PORT_NUM)
1333 >> BWFM_DMP_MASTER_PORT_NUM_S;
1334 wraptype = BWFM_DMP_SLAVE_TYPE_MWRAP;
1335 *erom += 4;
1336 } else if ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT32) ==
1337 BWFM_DMP_DESC_ADDRESS)
1338 wraptype = BWFM_DMP_SLAVE_TYPE_SWRAP;
1339 else
1340 return 1;
1341
1342 do {
1343 do {
1344 val = sc->sc_buscore_ops->bc_read(sc, *erom);
1345 type = val & BWFM_DMP_DESC_MASK;
1346 if (type == BWFM_DMP_DESC_COMPONENT)
1347 return 0;
1348 if (type == BWFM_DMP_DESC_EOT)
1349 return 1;
1350 *erom += 4;
1351 } while ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT32) !=
1352 BWFM_DMP_DESC_ADDRESS);
1353
1354 if (type & BWFM_DMP_DESC_ADDRSIZE_GT32)
1355 *erom += 4;
1356
1357 sztype = (val & BWFM_DMP_SLAVE_SIZE_TYPE)
1358 >> BWFM_DMP_SLAVE_SIZE_TYPE_S;
1359 if (sztype == BWFM_DMP_SLAVE_SIZE_DESC) {
1360 val = sc->sc_buscore_ops->bc_read(sc, *erom);
1361 type = val & BWFM_DMP_DESC_MASK;
1362 if (type & BWFM_DMP_DESC_ADDRSIZE_GT32)
1363 *erom += 8;
1364 else
1365 *erom += 4;
1366 }
1367 if (sztype != BWFM_DMP_SLAVE_SIZE_4K)
1368 continue;
1369
1370 stype = (val & BWFM_DMP_SLAVE_TYPE) >> BWFM_DMP_SLAVE_TYPE_S;
1371 if (*base == 0 && stype == BWFM_DMP_SLAVE_TYPE_SLAVE)
1372 *base = val & BWFM_DMP_SLAVE_ADDR_BASE;
1373 if (*wrap == 0 && stype == wraptype)
1374 *wrap = val & BWFM_DMP_SLAVE_ADDR_BASE;
1375 } while (*base == 0 || *wrap == 0);
1376
1377 return 0;
1378 }
1379
1380 /* Core configuration */
1381 int
1382 bwfm_chip_set_active(struct bwfm_softc *sc, const uint32_t rstvec)
1383 {
1384 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4) != NULL)
1385 return bwfm_chip_cr4_set_active(sc, rstvec);
1386 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7) != NULL)
1387 return bwfm_chip_ca7_set_active(sc, rstvec);
1388 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3) != NULL)
1389 return bwfm_chip_cm3_set_active(sc);
1390 return 1;
1391 }
1392
1393 void
1394 bwfm_chip_set_passive(struct bwfm_softc *sc)
1395 {
1396 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4) != NULL) {
1397 bwfm_chip_cr4_set_passive(sc);
1398 return;
1399 }
1400 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7) != NULL) {
1401 bwfm_chip_ca7_set_passive(sc);
1402 return;
1403 }
1404 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3) != NULL) {
1405 bwfm_chip_cm3_set_passive(sc);
1406 return;
1407 }
1408 }
1409
1410 int
1411 bwfm_chip_cr4_set_active(struct bwfm_softc *sc, const uint32_t rstvec)
1412 {
1413 struct bwfm_core *core;
1414
1415 sc->sc_buscore_ops->bc_activate(sc, rstvec);
1416 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4);
1417 sc->sc_chip.ch_core_reset(sc, core,
1418 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 0, 0);
1419
1420 return 0;
1421 }
1422
1423 void
1424 bwfm_chip_cr4_set_passive(struct bwfm_softc *sc)
1425 {
1426 struct bwfm_core *core;
1427 uint32_t val;
1428
1429 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4);
1430 val = sc->sc_buscore_ops->bc_read(sc,
1431 core->co_wrapbase + BWFM_AGENT_IOCTL);
1432 sc->sc_chip.ch_core_reset(sc, core,
1433 val & BWFM_AGENT_IOCTL_ARMCR4_CPUHALT,
1434 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT,
1435 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT);
1436
1437 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211);
1438 sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET |
1439 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN,
1440 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN);
1441 }
1442
1443 int
1444 bwfm_chip_ca7_set_active(struct bwfm_softc *sc, const uint32_t rstvec)
1445 {
1446 struct bwfm_core *core;
1447
1448 sc->sc_buscore_ops->bc_activate(sc, rstvec);
1449 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7);
1450 sc->sc_chip.ch_core_reset(sc, core,
1451 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 0, 0);
1452
1453 return 0;
1454 }
1455
1456 void
1457 bwfm_chip_ca7_set_passive(struct bwfm_softc *sc)
1458 {
1459 struct bwfm_core *core;
1460 uint32_t val;
1461
1462 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7);
1463 val = sc->sc_buscore_ops->bc_read(sc,
1464 core->co_wrapbase + BWFM_AGENT_IOCTL);
1465 sc->sc_chip.ch_core_reset(sc, core,
1466 val & BWFM_AGENT_IOCTL_ARMCR4_CPUHALT,
1467 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT,
1468 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT);
1469
1470 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211);
1471 sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET |
1472 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN,
1473 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN);
1474 }
1475
1476 int
1477 bwfm_chip_cm3_set_active(struct bwfm_softc *sc)
1478 {
1479 struct bwfm_core *core;
1480
1481 core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM);
1482 if (!sc->sc_chip.ch_core_isup(sc, core))
1483 return 1;
1484
1485 sc->sc_buscore_ops->bc_activate(sc, 0);
1486
1487 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3);
1488 sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0);
1489
1490 return 0;
1491 }
1492
1493 void
1494 bwfm_chip_cm3_set_passive(struct bwfm_softc *sc)
1495 {
1496 struct bwfm_core *core;
1497
1498 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3);
1499 sc->sc_chip.ch_core_disable(sc, core, 0, 0);
1500 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211);
1501 sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET |
1502 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN,
1503 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN);
1504 core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM);
1505 sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0);
1506
1507 if (sc->sc_chip.ch_chip == BRCM_CC_43430_CHIP_ID) {
1508 sc->sc_buscore_ops->bc_write(sc,
1509 core->co_base + BWFM_SOCRAM_BANKIDX, 3);
1510 sc->sc_buscore_ops->bc_write(sc,
1511 core->co_base + BWFM_SOCRAM_BANKPDA, 0);
1512 }
1513 }
1514
1515 int
1516 bwfm_chip_sr_capable(struct bwfm_softc *sc)
1517 {
1518 struct bwfm_core *core;
1519 uint32_t reg;
1520
1521 if (sc->sc_chip.ch_pmurev < 17)
1522 return 0;
1523
1524 switch (sc->sc_chip.ch_chip) {
1525 case BRCM_CC_4345_CHIP_ID:
1526 case BRCM_CC_4354_CHIP_ID:
1527 case BRCM_CC_4356_CHIP_ID:
1528 core = bwfm_chip_get_pmu(sc);
1529 sc->sc_buscore_ops->bc_write(sc, core->co_base +
1530 BWFM_CHIP_REG_CHIPCONTROL_ADDR, 3);
1531 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1532 BWFM_CHIP_REG_CHIPCONTROL_DATA);
1533 return (reg & (1 << 2)) != 0;
1534 case BRCM_CC_43241_CHIP_ID:
1535 case BRCM_CC_4335_CHIP_ID:
1536 case BRCM_CC_4339_CHIP_ID:
1537 core = bwfm_chip_get_pmu(sc);
1538 sc->sc_buscore_ops->bc_write(sc, core->co_base +
1539 BWFM_CHIP_REG_CHIPCONTROL_ADDR, 3);
1540 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1541 BWFM_CHIP_REG_CHIPCONTROL_DATA);
1542 return reg != 0;
1543 case BRCM_CC_43430_CHIP_ID:
1544 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
1545 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1546 BWFM_CHIP_REG_SR_CONTROL1);
1547 return reg != 0;
1548 default:
1549 core = bwfm_chip_get_pmu(sc);
1550 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1551 BWFM_CHIP_REG_PMUCAPABILITIES_EXT);
1552 if ((reg & BWFM_CHIP_REG_PMUCAPABILITIES_SR_SUPP) == 0)
1553 return 0;
1554 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1555 BWFM_CHIP_REG_RETENTION_CTL);
1556 return (reg & (BWFM_CHIP_REG_RETENTION_CTL_MACPHY_DIS |
1557 BWFM_CHIP_REG_RETENTION_CTL_LOGIC_DIS)) == 0;
1558 }
1559 }
1560
1561 /* RAM size helpers */
1562 void
1563 bwfm_chip_socram_ramsize(struct bwfm_softc *sc, struct bwfm_core *core)
1564 {
1565 uint32_t coreinfo, nb, lss, banksize, bankinfo;
1566 uint32_t ramsize = 0, srsize = 0;
1567 int i;
1568
1569 if (!sc->sc_chip.ch_core_isup(sc, core))
1570 sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0);
1571
1572 coreinfo = sc->sc_buscore_ops->bc_read(sc,
1573 core->co_base + BWFM_SOCRAM_COREINFO);
1574 nb = (coreinfo & BWFM_SOCRAM_COREINFO_SRNB_MASK)
1575 >> BWFM_SOCRAM_COREINFO_SRNB_SHIFT;
1576
1577 if (core->co_rev <= 7 || core->co_rev == 12) {
1578 banksize = coreinfo & BWFM_SOCRAM_COREINFO_SRBSZ_MASK;
1579 lss = (coreinfo & BWFM_SOCRAM_COREINFO_LSS_MASK)
1580 >> BWFM_SOCRAM_COREINFO_LSS_SHIFT;
1581 if (lss != 0)
1582 nb--;
1583 ramsize = nb * (1 << (banksize + BWFM_SOCRAM_COREINFO_SRBSZ_BASE));
1584 if (lss != 0)
1585 ramsize += (1 << ((lss - 1) + BWFM_SOCRAM_COREINFO_SRBSZ_BASE));
1586 } else {
1587 for (i = 0; i < nb; i++) {
1588 sc->sc_buscore_ops->bc_write(sc,
1589 core->co_base + BWFM_SOCRAM_BANKIDX,
1590 (BWFM_SOCRAM_BANKIDX_MEMTYPE_RAM <<
1591 BWFM_SOCRAM_BANKIDX_MEMTYPE_SHIFT) | i);
1592 bankinfo = sc->sc_buscore_ops->bc_read(sc,
1593 core->co_base + BWFM_SOCRAM_BANKINFO);
1594 banksize = ((bankinfo & BWFM_SOCRAM_BANKINFO_SZMASK) + 1)
1595 * BWFM_SOCRAM_BANKINFO_SZBASE;
1596 ramsize += banksize;
1597 if (bankinfo & BWFM_SOCRAM_BANKINFO_RETNTRAM_MASK)
1598 srsize += banksize;
1599 }
1600 }
1601
1602 switch (sc->sc_chip.ch_chip) {
1603 case BRCM_CC_4334_CHIP_ID:
1604 if (sc->sc_chip.ch_chiprev < 2)
1605 srsize = 32 * 1024;
1606 break;
1607 case BRCM_CC_43430_CHIP_ID:
1608 srsize = 64 * 1024;
1609 break;
1610 default:
1611 break;
1612 }
1613
1614 sc->sc_chip.ch_ramsize = ramsize;
1615 sc->sc_chip.ch_srsize = srsize;
1616 }
1617
1618 void
1619 bwfm_chip_sysmem_ramsize(struct bwfm_softc *sc, struct bwfm_core *core)
1620 {
1621 uint32_t coreinfo, nb, banksize, bankinfo;
1622 uint32_t ramsize = 0;
1623 int i;
1624
1625 if (!sc->sc_chip.ch_core_isup(sc, core))
1626 sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0);
1627
1628 coreinfo = sc->sc_buscore_ops->bc_read(sc,
1629 core->co_base + BWFM_SOCRAM_COREINFO);
1630 nb = (coreinfo & BWFM_SOCRAM_COREINFO_SRNB_MASK)
1631 >> BWFM_SOCRAM_COREINFO_SRNB_SHIFT;
1632
1633 for (i = 0; i < nb; i++) {
1634 sc->sc_buscore_ops->bc_write(sc,
1635 core->co_base + BWFM_SOCRAM_BANKIDX,
1636 (BWFM_SOCRAM_BANKIDX_MEMTYPE_RAM <<
1637 BWFM_SOCRAM_BANKIDX_MEMTYPE_SHIFT) | i);
1638 bankinfo = sc->sc_buscore_ops->bc_read(sc,
1639 core->co_base + BWFM_SOCRAM_BANKINFO);
1640 banksize = ((bankinfo & BWFM_SOCRAM_BANKINFO_SZMASK) + 1)
1641 * BWFM_SOCRAM_BANKINFO_SZBASE;
1642 ramsize += banksize;
1643 }
1644
1645 sc->sc_chip.ch_ramsize = ramsize;
1646 }
1647
1648 void
1649 bwfm_chip_tcm_ramsize(struct bwfm_softc *sc, struct bwfm_core *core)
1650 {
1651 uint32_t cap, nab, nbb, totb, bxinfo, ramsize = 0;
1652 int i;
1653
1654 cap = sc->sc_buscore_ops->bc_read(sc, core->co_base + BWFM_ARMCR4_CAP);
1655 nab = (cap & BWFM_ARMCR4_CAP_TCBANB_MASK) >> BWFM_ARMCR4_CAP_TCBANB_SHIFT;
1656 nbb = (cap & BWFM_ARMCR4_CAP_TCBBNB_MASK) >> BWFM_ARMCR4_CAP_TCBBNB_SHIFT;
1657 totb = nab + nbb;
1658
1659 for (i = 0; i < totb; i++) {
1660 sc->sc_buscore_ops->bc_write(sc,
1661 core->co_base + BWFM_ARMCR4_BANKIDX, i);
1662 bxinfo = sc->sc_buscore_ops->bc_read(sc,
1663 core->co_base + BWFM_ARMCR4_BANKINFO);
1664 ramsize += ((bxinfo & BWFM_ARMCR4_BANKINFO_BSZ_MASK) + 1) *
1665 BWFM_ARMCR4_BANKINFO_BSZ_MULT;
1666 }
1667
1668 sc->sc_chip.ch_ramsize = ramsize;
1669 }
1670
1671 void
1672 bwfm_chip_tcm_rambase(struct bwfm_softc *sc)
1673 {
1674 switch (sc->sc_chip.ch_chip) {
1675 case BRCM_CC_4345_CHIP_ID:
1676 sc->sc_chip.ch_rambase = 0x198000;
1677 break;
1678 case BRCM_CC_4335_CHIP_ID:
1679 case BRCM_CC_4339_CHIP_ID:
1680 case BRCM_CC_4350_CHIP_ID:
1681 case BRCM_CC_4354_CHIP_ID:
1682 case BRCM_CC_4356_CHIP_ID:
1683 case BRCM_CC_43567_CHIP_ID:
1684 case BRCM_CC_43569_CHIP_ID:
1685 case BRCM_CC_43570_CHIP_ID:
1686 case BRCM_CC_4358_CHIP_ID:
1687 case BRCM_CC_4359_CHIP_ID:
1688 case BRCM_CC_43602_CHIP_ID:
1689 case BRCM_CC_4371_CHIP_ID:
1690 sc->sc_chip.ch_rambase = 0x180000;
1691 break;
1692 case BRCM_CC_43465_CHIP_ID:
1693 case BRCM_CC_43525_CHIP_ID:
1694 case BRCM_CC_4365_CHIP_ID:
1695 case BRCM_CC_4366_CHIP_ID:
1696 sc->sc_chip.ch_rambase = 0x200000;
1697 break;
1698 case CY_CC_4373_CHIP_ID:
1699 sc->sc_chip.ch_rambase = 0x160000;
1700 break;
1701 default:
1702 printf("%s: unknown chip: %d\n", DEVNAME(sc),
1703 sc->sc_chip.ch_chip);
1704 break;
1705 }
1706 }
1707
1708 /* BCDC protocol implementation */
1709 int
1710 bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *sc, int ifidx,
1711 int cmd, char *buf, size_t *len)
1712 {
1713 struct bwfm_proto_bcdc_dcmd *dcmd;
1714 size_t size = sizeof(dcmd->hdr) + *len;
1715 int reqid;
1716 int ret = 1;
1717
1718 reqid = sc->sc_bcdc_reqid++;
1719
1720 dcmd = kmem_zalloc(sizeof(*dcmd), KM_SLEEP);
1721 if (*len > sizeof(dcmd->buf))
1722 goto err;
1723
1724 dcmd->hdr.cmd = htole32(cmd);
1725 dcmd->hdr.len = htole32(*len);
1726 dcmd->hdr.flags |= BWFM_BCDC_DCMD_GET;
1727 dcmd->hdr.flags |= BWFM_BCDC_DCMD_ID_SET(reqid);
1728 dcmd->hdr.flags |= BWFM_BCDC_DCMD_IF_SET(ifidx);
1729 dcmd->hdr.flags = htole32(dcmd->hdr.flags);
1730 memcpy(&dcmd->buf, buf, *len);
1731
1732 if (sc->sc_bus_ops->bs_txctl(sc, (void *)dcmd,
1733 sizeof(dcmd->hdr) + *len)) {
1734 DPRINTF(("%s: tx failed\n", DEVNAME(sc)));
1735 goto err;
1736 }
1737
1738 do {
1739 if (sc->sc_bus_ops->bs_rxctl(sc, (void *)dcmd, &size)) {
1740 DPRINTF(("%s: rx failed\n", DEVNAME(sc)));
1741 goto err;
1742 }
1743 dcmd->hdr.cmd = le32toh(dcmd->hdr.cmd);
1744 dcmd->hdr.len = le32toh(dcmd->hdr.len);
1745 dcmd->hdr.flags = le32toh(dcmd->hdr.flags);
1746 dcmd->hdr.status = le32toh(dcmd->hdr.status);
1747 } while (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid);
1748
1749 if (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid) {
1750 printf("%s: unexpected request id\n", DEVNAME(sc));
1751 goto err;
1752 }
1753
1754 if (buf) {
1755 if (size < *len)
1756 *len = size;
1757 memcpy(buf, dcmd->buf, *len);
1758 }
1759
1760 if (dcmd->hdr.flags & BWFM_BCDC_DCMD_ERROR)
1761 ret = dcmd->hdr.status;
1762 else
1763 ret = 0;
1764 err:
1765 kmem_free(dcmd, sizeof(*dcmd));
1766 return ret;
1767 }
1768
1769 int
1770 bwfm_proto_bcdc_set_dcmd(struct bwfm_softc *sc, int ifidx,
1771 int cmd, char *buf, size_t len)
1772 {
1773 struct bwfm_proto_bcdc_dcmd *dcmd;
1774 size_t size = sizeof(dcmd->hdr) + len;
1775 int ret = 1, reqid;
1776
1777 reqid = sc->sc_bcdc_reqid++;
1778
1779 dcmd = kmem_zalloc(sizeof(*dcmd), KM_SLEEP);
1780 if (len > sizeof(dcmd->buf))
1781 goto err;
1782
1783 dcmd->hdr.cmd = htole32(cmd);
1784 dcmd->hdr.len = htole32(len);
1785 dcmd->hdr.flags |= BWFM_BCDC_DCMD_SET;
1786 dcmd->hdr.flags |= BWFM_BCDC_DCMD_ID_SET(reqid);
1787 dcmd->hdr.flags |= BWFM_BCDC_DCMD_IF_SET(ifidx);
1788 dcmd->hdr.flags = htole32(dcmd->hdr.flags);
1789 memcpy(&dcmd->buf, buf, len);
1790
1791 if (sc->sc_bus_ops->bs_txctl(sc, (void *)dcmd, size)) {
1792 DPRINTF(("%s: tx failed\n", DEVNAME(sc)));
1793 goto err;
1794 }
1795
1796 do {
1797 if (sc->sc_bus_ops->bs_rxctl(sc, (void *)dcmd, &size)) {
1798 DPRINTF(("%s: rx failed\n", DEVNAME(sc)));
1799 goto err;
1800 }
1801 dcmd->hdr.cmd = le32toh(dcmd->hdr.cmd);
1802 dcmd->hdr.len = le32toh(dcmd->hdr.len);
1803 dcmd->hdr.flags = le32toh(dcmd->hdr.flags);
1804 dcmd->hdr.status = le32toh(dcmd->hdr.status);
1805 } while (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid);
1806
1807 if (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid) {
1808 printf("%s: unexpected request id\n", DEVNAME(sc));
1809 goto err;
1810 }
1811
1812 if (dcmd->hdr.flags & BWFM_BCDC_DCMD_ERROR)
1813 return dcmd->hdr.status;
1814
1815 ret = 0;
1816 err:
1817 kmem_free(dcmd, sizeof(*dcmd));
1818 return ret;
1819 }
1820
1821 void
1822 bwfm_process_blob(struct bwfm_softc *sc, const char *var, uint8_t **blob,
1823 size_t *blobsize)
1824 {
1825 struct bwfm_dload_data *data;
1826 size_t off, remain, len;
1827
1828 if (*blob == NULL || *blobsize == 0)
1829 return;
1830
1831 off = 0;
1832 remain = *blobsize;
1833 data = kmem_alloc(sizeof(*data) + BWFM_DLOAD_MAX_LEN, KM_SLEEP);
1834
1835 while (remain) {
1836 len = uimin(remain, BWFM_DLOAD_MAX_LEN);
1837
1838 data->flag = htole16(BWFM_DLOAD_FLAG_HANDLER_VER_1);
1839 if (off == 0)
1840 data->flag |= htole16(BWFM_DLOAD_FLAG_BEGIN);
1841 if (remain <= BWFM_DLOAD_MAX_LEN)
1842 data->flag |= htole16(BWFM_DLOAD_FLAG_END);
1843 data->type = htole16(BWFM_DLOAD_TYPE_CLM);
1844 data->len = htole32(len);
1845 data->crc = 0;
1846 memcpy(data->data, *blob + off, len);
1847
1848 if (bwfm_fwvar_var_set_data(sc, var, data,
1849 sizeof(*data) + len)) {
1850 printf("%s: could not load blob (%s)\n", DEVNAME(sc),
1851 var);
1852 break;
1853 }
1854
1855 off += len;
1856 remain -= len;
1857 }
1858
1859 kmem_free(data, sizeof(*data) + BWFM_DLOAD_MAX_LEN);
1860 // kmem_free(*blob, *blobsize);
1861 *blob = NULL;
1862 *blobsize = 0;
1863 }
1864
1865 /* FW Variable code */
1866 int
1867 bwfm_fwvar_cmd_get_data(struct bwfm_softc *sc, int cmd, void *data, size_t len)
1868 {
1869 return sc->sc_proto_ops->proto_query_dcmd(sc, 0, cmd, data, &len);
1870 }
1871
1872 int
1873 bwfm_fwvar_cmd_set_data(struct bwfm_softc *sc, int cmd, void *data, size_t len)
1874 {
1875 return sc->sc_proto_ops->proto_set_dcmd(sc, 0, cmd, data, len);
1876 }
1877
1878 int
1879 bwfm_fwvar_cmd_get_int(struct bwfm_softc *sc, int cmd, uint32_t *data)
1880 {
1881 int ret;
1882 ret = bwfm_fwvar_cmd_get_data(sc, cmd, data, sizeof(*data));
1883 *data = le32toh(*data);
1884 return ret;
1885 }
1886
1887 int
1888 bwfm_fwvar_cmd_set_int(struct bwfm_softc *sc, int cmd, uint32_t data)
1889 {
1890 data = htole32(data);
1891 return bwfm_fwvar_cmd_set_data(sc, cmd, &data, sizeof(data));
1892 }
1893
1894 int
1895 bwfm_fwvar_var_get_data(struct bwfm_softc *sc, const char *name, void *data, size_t len)
1896 {
1897 char *buf;
1898 int ret;
1899
1900 buf = kmem_alloc(strlen(name) + 1 + len, KM_SLEEP);
1901 memcpy(buf, name, strlen(name) + 1);
1902 memcpy(buf + strlen(name) + 1, data, len);
1903 ret = bwfm_fwvar_cmd_get_data(sc, BWFM_C_GET_VAR,
1904 buf, strlen(name) + 1 + len);
1905 memcpy(data, buf, len);
1906 kmem_free(buf, strlen(name) + 1 + len);
1907 return ret;
1908 }
1909
1910 int
1911 bwfm_fwvar_var_set_data(struct bwfm_softc *sc, const char *name, void *data, size_t len)
1912 {
1913 char *buf;
1914 int ret;
1915
1916 buf = kmem_alloc(strlen(name) + 1 + len, KM_SLEEP);
1917 memcpy(buf, name, strlen(name) + 1);
1918 memcpy(buf + strlen(name) + 1, data, len);
1919 ret = bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_VAR,
1920 buf, strlen(name) + 1 + len);
1921 kmem_free(buf, strlen(name) + 1 + len);
1922 return ret;
1923 }
1924
1925 int
1926 bwfm_fwvar_var_get_int(struct bwfm_softc *sc, const char *name, uint32_t *data)
1927 {
1928 int ret;
1929 ret = bwfm_fwvar_var_get_data(sc, name, data, sizeof(*data));
1930 *data = le32toh(*data);
1931 return ret;
1932 }
1933
1934 int
1935 bwfm_fwvar_var_set_int(struct bwfm_softc *sc, const char *name, uint32_t data)
1936 {
1937 data = htole32(data);
1938 return bwfm_fwvar_var_set_data(sc, name, &data, sizeof(data));
1939 }
1940
1941 /* 802.11 code */
1942 void
1943 bwfm_scan(struct bwfm_softc *sc)
1944 {
1945 struct bwfm_escan_params *params;
1946 uint32_t nssid = 0, nchannel = 0;
1947 size_t params_size;
1948
1949 #if 0
1950 /* Active scan is used for scanning for an SSID */
1951 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PASSIVE_SCAN, 0);
1952 #endif
1953 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PASSIVE_SCAN, 1);
1954
1955 params_size = sizeof(*params);
1956 params_size += sizeof(uint32_t) * ((nchannel + 1) / 2);
1957 params_size += sizeof(struct bwfm_ssid) * nssid;
1958
1959 params = kmem_zalloc(params_size, KM_SLEEP);
1960 memset(params->scan_params.bssid, 0xff,
1961 sizeof(params->scan_params.bssid));
1962 params->scan_params.bss_type = 2;
1963 params->scan_params.nprobes = htole32(-1);
1964 params->scan_params.active_time = htole32(-1);
1965 params->scan_params.passive_time = htole32(-1);
1966 params->scan_params.home_time = htole32(-1);
1967 params->version = htole32(BWFM_ESCAN_REQ_VERSION);
1968 params->action = htole16(WL_ESCAN_ACTION_START);
1969 params->sync_id = htole16(0x1234);
1970
1971 #if 0
1972 /* Scan a specific channel */
1973 params->scan_params.channel_list[0] = htole16(
1974 (1 & 0xff) << 0 |
1975 (3 & 0x3) << 8 |
1976 (2 & 0x3) << 10 |
1977 (2 & 0x3) << 12
1978 );
1979 params->scan_params.channel_num = htole32(
1980 (1 & 0xffff) << 0
1981 );
1982 #endif
1983
1984 bwfm_fwvar_var_set_data(sc, "escan", params, params_size);
1985 kmem_free(params, params_size);
1986 }
1987
1988 static __inline int
1989 bwfm_iswpaoui(const uint8_t *frm)
1990 {
1991 return frm[1] > 3 && le32dec(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
1992 }
1993
1994 /*
1995 * Derive wireless security settings from WPA/RSN IE.
1996 */
1997 static uint32_t
1998 bwfm_get_wsec(struct bwfm_softc *sc)
1999 {
2000 struct ieee80211com *ic = &sc->sc_ic;
2001 uint8_t *wpa = ic->ic_opt_ie;
2002
2003 KASSERT(ic->ic_opt_ie_len > 0);
2004
2005 if (wpa[0] != IEEE80211_ELEMID_RSN) {
2006 if (ic->ic_opt_ie_len < 12)
2007 return BWFM_WSEC_NONE;
2008
2009 /* non-RSN IE, expect that we are doing WPA1 */
2010 if ((ic->ic_flags & IEEE80211_F_WPA1) == 0)
2011 return BWFM_WSEC_NONE;
2012
2013 /* Must contain WPA OUI */
2014 if (!bwfm_iswpaoui(wpa))
2015 return BWFM_WSEC_NONE;
2016
2017 switch (le32dec(wpa + 8)) {
2018 case ((WPA_CSE_TKIP<<24)|WPA_OUI):
2019 return BWFM_WSEC_TKIP;
2020 case ((WPA_CSE_CCMP<<24)|WPA_OUI):
2021 return BWFM_WSEC_AES;
2022 default:
2023 return BWFM_WSEC_NONE;
2024 }
2025 } else {
2026 if (ic->ic_opt_ie_len < 14)
2027 return BWFM_WSEC_NONE;
2028
2029 /* RSN IE, expect that we are doing WPA2 */
2030 if ((ic->ic_flags & IEEE80211_F_WPA2) == 0)
2031 return BWFM_WSEC_NONE;
2032
2033 switch (le32dec(wpa + 10)) {
2034 case ((RSN_CSE_TKIP<<24)|RSN_OUI):
2035 return BWFM_WSEC_TKIP;
2036 case ((RSN_CSE_CCMP<<24)|RSN_OUI):
2037 return BWFM_WSEC_AES;
2038 default:
2039 return BWFM_WSEC_NONE;
2040 }
2041 }
2042 }
2043
2044 void
2045 bwfm_connect(struct bwfm_softc *sc)
2046 {
2047 struct ieee80211com *ic = &sc->sc_ic;
2048 struct ieee80211_node *ni = ic->ic_bss;
2049 struct bwfm_ext_join_params *params;
2050
2051 if (ic->ic_flags & IEEE80211_F_WPA) {
2052 uint32_t wsec = 0;
2053 uint32_t wpa = 0;
2054
2055 if (ic->ic_opt_ie_len)
2056 bwfm_fwvar_var_set_data(sc, "wpaie", ic->ic_opt_ie, ic->ic_opt_ie_len);
2057
2058 if (ic->ic_flags & IEEE80211_F_WPA1)
2059 wpa |= BWFM_WPA_AUTH_WPA_PSK;
2060 if (ic->ic_flags & IEEE80211_F_WPA2)
2061 wpa |= BWFM_WPA_AUTH_WPA2_PSK;
2062
2063 wsec |= bwfm_get_wsec(sc);
2064
2065 DPRINTF(("%s: WPA enabled, ic_flags = 0x%x, wpa 0x%x, wsec 0x%x\n",
2066 DEVNAME(sc), ic->ic_flags, wpa, wsec));
2067
2068 bwfm_fwvar_var_set_int(sc, "wpa_auth", wpa);
2069 bwfm_fwvar_var_set_int(sc, "wsec", wsec);
2070 } else {
2071 bwfm_fwvar_var_set_int(sc, "wpa_auth", BWFM_WPA_AUTH_DISABLED);
2072 bwfm_fwvar_var_set_int(sc, "wsec", BWFM_WSEC_NONE);
2073 }
2074
2075 bwfm_fwvar_var_set_int(sc, "auth", BWFM_AUTH_OPEN);
2076 bwfm_fwvar_var_set_int(sc, "mfp", BWFM_MFP_NONE);
2077
2078 if (ni->ni_esslen && ni->ni_esslen < BWFM_MAX_SSID_LEN) {
2079 params = kmem_zalloc(sizeof(*params), KM_SLEEP);
2080 memcpy(params->ssid.ssid, ni->ni_essid, ni->ni_esslen);
2081 params->ssid.len = htole32(ni->ni_esslen);
2082 memcpy(params->assoc.bssid, ni->ni_bssid, sizeof(params->assoc.bssid));
2083 params->scan.scan_type = -1;
2084 params->scan.nprobes = htole32(-1);
2085 params->scan.active_time = htole32(-1);
2086 params->scan.passive_time = htole32(-1);
2087 params->scan.home_time = htole32(-1);
2088 if (bwfm_fwvar_var_set_data(sc, "join", params, sizeof(*params))) {
2089 struct bwfm_join_params join;
2090 memset(&join, 0, sizeof(join));
2091 memcpy(join.ssid.ssid, ni->ni_essid, ni->ni_esslen);
2092 join.ssid.len = htole32(ni->ni_esslen);
2093 memcpy(join.assoc.bssid, ni->ni_bssid, sizeof(join.assoc.bssid));
2094 bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID, &join,
2095 sizeof(join));
2096 }
2097 kmem_free(params, sizeof(*params));
2098 }
2099 }
2100
2101 void
2102 bwfm_get_sta_info(struct bwfm_softc *sc, struct ifmediareq *ifmr)
2103 {
2104 struct ieee80211com *ic = &sc->sc_ic;
2105 struct ieee80211_node *ni = ic->ic_bss;
2106 struct bwfm_sta_info sta;
2107 uint32_t flags, txrate;
2108
2109 memset(&sta, 0, sizeof(sta));
2110 memcpy(&sta, ni->ni_macaddr, sizeof(ni->ni_macaddr));
2111
2112 if (bwfm_fwvar_var_get_data(sc, "sta_info", &sta, sizeof(sta)))
2113 return;
2114
2115 if (!IEEE80211_ADDR_EQ(ni->ni_macaddr, sta.ea))
2116 return;
2117
2118 if (le16toh(sta.ver) < 4)
2119 return;
2120
2121 flags = le32toh(sta.flags);
2122 if ((flags & BWFM_STA_SCBSTATS) == 0)
2123 return;
2124
2125 txrate = le32toh(sta.tx_rate);
2126 if (txrate == 0xffffffff)
2127 return;
2128
2129 if ((flags & BWFM_STA_VHT_CAP) != 0) {
2130 ifmr->ifm_active &= ~IFM_TMASK;
2131 ifmr->ifm_active |= IFM_IEEE80211_VHT;
2132 ifmr->ifm_active &= ~IFM_MMASK;
2133 ifmr->ifm_active |= IFM_IEEE80211_11AC;
2134 } else if ((flags & BWFM_STA_N_CAP) != 0) {
2135 ifmr->ifm_active &= ~IFM_TMASK;
2136 ifmr->ifm_active |= IFM_IEEE80211_MCS;
2137 ifmr->ifm_active &= ~IFM_MMASK;
2138 if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
2139 ifmr->ifm_active |= IFM_IEEE80211_11NG;
2140 else
2141 ifmr->ifm_active |= IFM_IEEE80211_11NA;
2142 }
2143 }
2144
2145 void
2146 bwfm_rx(struct bwfm_softc *sc, struct mbuf *m)
2147 {
2148 struct ieee80211com *ic = &sc->sc_ic;
2149 struct ifnet *ifp = ic->ic_ifp;
2150 struct bwfm_event *e = mtod(m, struct bwfm_event *);
2151
2152 if (m->m_len >= sizeof(e->ehdr) &&
2153 ntohs(e->ehdr.ether_type) == BWFM_ETHERTYPE_LINK_CTL &&
2154 memcmp(BWFM_BRCM_OUI, e->hdr.oui, sizeof(e->hdr.oui)) == 0 &&
2155 ntohs(e->hdr.usr_subtype) == BWFM_BRCM_SUBTYPE_EVENT) {
2156 bwfm_rx_event(sc, m);
2157 // m_freem(m);
2158 return;
2159 }
2160
2161 m_set_rcvif(m, ifp);
2162 if_percpuq_enqueue(ifp->if_percpuq, m);
2163 }
2164
2165 void
2166 bwfm_rx_event(struct bwfm_softc *sc, struct mbuf *m)
2167 {
2168 struct bwfm_task *t;
2169
2170 t = pool_cache_get(sc->sc_freetask, PR_NOWAIT);
2171 if (t == NULL) {
2172 m_freem(m);
2173 printf("%s: no free tasks\n", DEVNAME(sc));
2174 return;
2175 }
2176
2177 t->t_sc = sc;
2178 t->t_cmd = BWFM_TASK_RX_EVENT;
2179 t->t_mbuf = m;
2180 workqueue_enqueue(sc->sc_taskq, (struct work*)t, NULL);
2181 }
2182
2183 void
2184 bwfm_rx_event_cb(struct bwfm_softc *sc, struct mbuf *m)
2185 {
2186 struct ieee80211com *ic = &sc->sc_ic;
2187 struct bwfm_event *e = mtod(m, void *);
2188 size_t len = m->m_len;
2189 int s;
2190
2191 DPRINTF(("%s: event %p len %lu datalen %u code %u status %u"
2192 " reason %u\n", __func__, e, len, ntohl(e->msg.datalen),
2193 ntohl(e->msg.event_type), ntohl(e->msg.status),
2194 ntohl(e->msg.reason)));
2195
2196 if (ntohl(e->msg.event_type) >= BWFM_E_LAST) {
2197 m_freem(m);
2198 return;
2199 }
2200
2201 switch (ntohl(e->msg.event_type)) {
2202 case BWFM_E_ESCAN_RESULT: {
2203 struct bwfm_escan_results *res = (void *)&e[1];
2204 struct bwfm_bss_info *bss;
2205 int i;
2206 if (ntohl(e->msg.status) != BWFM_E_STATUS_PARTIAL) {
2207 /* Scan complete */
2208 s = splnet();
2209 if (ic->ic_opmode != IEEE80211_M_MONITOR)
2210 ieee80211_end_scan(ic);
2211 splx(s);
2212 break;
2213 }
2214 len -= sizeof(*e);
2215 if (len < sizeof(*res) || len < le32toh(res->buflen)) {
2216 m_freem(m);
2217 printf("%s: results too small\n", DEVNAME(sc));
2218 return;
2219 }
2220 len -= sizeof(*res);
2221 if (len < le16toh(res->bss_count) * sizeof(struct bwfm_bss_info)) {
2222 m_freem(m);
2223 printf("%s: results too small\n", DEVNAME(sc));
2224 return;
2225 }
2226 bss = &res->bss_info[0];
2227 for (i = 0; i < le16toh(res->bss_count); i++) {
2228 /* Fix alignment of bss_info */
2229 if (len > sizeof(sc->sc_bss_buf)) {
2230 printf("%s: bss_info buffer too big\n", DEVNAME(sc));
2231 } else {
2232 memcpy(&sc->sc_bss_buf, &res->bss_info[i], len);
2233 bwfm_scan_node(sc, &sc->sc_bss_buf.bss_info,
2234 len);
2235 }
2236 len -= sizeof(*bss) + le32toh(bss->length);
2237 bss = (void *)(((uintptr_t)bss) + le32toh(bss->length));
2238 if (len <= 0)
2239 break;
2240 }
2241 break;
2242 }
2243
2244 case BWFM_E_SET_SSID:
2245 if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS) {
2246 ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
2247 } else {
2248 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2249 }
2250 break;
2251
2252 case BWFM_E_ASSOC:
2253 if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS) {
2254 ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1);
2255 } else {
2256 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2257 }
2258 break;
2259
2260 case BWFM_E_LINK:
2261 if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS &&
2262 ntohl(e->msg.reason) == 0)
2263 break;
2264
2265 /* Link status has changed */
2266 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2267 break;
2268
2269 default:
2270 break;
2271 }
2272
2273 m_freem(m);
2274 }
2275
2276 void
2277 bwfm_scan_node(struct bwfm_softc *sc, struct bwfm_bss_info *bss, size_t len)
2278 {
2279 struct ieee80211com *ic = &sc->sc_ic;
2280 struct ieee80211_frame wh;
2281 struct ieee80211_scanparams scan;
2282 uint8_t rates[sizeof(bss->rates) + 2];
2283 uint8_t ssid[sizeof(bss->ssid) + 2];
2284 uint8_t *frm, *sfrm, *efrm;
2285 uint64_t tsf;
2286
2287 tsf = 0;
2288 sfrm = ((uint8_t *)bss) + le16toh(bss->ie_offset);
2289 efrm = sfrm + le32toh(bss->ie_length);
2290
2291 /* Fake a wireless header with the scan result's BSSID */
2292 memset(&wh, 0, sizeof(wh));
2293 IEEE80211_ADDR_COPY(wh.i_addr2, bss->bssid);
2294 IEEE80211_ADDR_COPY(wh.i_addr3, bss->bssid);
2295
2296 if (efrm - sfrm < 12) {
2297 ic->ic_stats.is_rx_elem_toosmall++;
2298 return;
2299 }
2300
2301 rates[0] = 0;
2302 rates[1] = le32toh(bss->nrates);
2303 memcpy(&rates[2], bss->rates, sizeof(bss->rates));
2304
2305 ssid[0] = 0;
2306 ssid[1] = bss->ssid_len;
2307 memcpy(&ssid[2], bss->ssid, sizeof(bss->ssid));
2308
2309 /* Build scan result */
2310 memset(&scan, 0, sizeof(scan));
2311 scan.sp_tstamp = (uint8_t *)&tsf;
2312 scan.sp_bintval = le16toh(bss->beacon_period);
2313 scan.sp_capinfo = le16toh(bss->capability);
2314 scan.sp_bchan = ieee80211_chan2ieee(ic, ic->ic_curchan);
2315 scan.sp_chan = scan.sp_bchan;
2316 scan.sp_rates = rates;
2317 scan.sp_ssid = ssid;
2318
2319 for (frm = sfrm; frm < efrm; frm += frm[1] + 2) {
2320 switch (frm[0]) {
2321 case IEEE80211_ELEMID_COUNTRY:
2322 scan.sp_country = frm;
2323 break;
2324 case IEEE80211_ELEMID_FHPARMS:
2325 if (ic->ic_phytype == IEEE80211_T_FH) {
2326 if (frm + 6 >= efrm)
2327 break;
2328 scan.sp_fhdwell = le16dec(&frm[2]);
2329 scan.sp_chan = IEEE80211_FH_CHAN(frm[4], frm[5]);
2330 scan.sp_fhindex = frm[6];
2331 }
2332 break;
2333 case IEEE80211_ELEMID_DSPARMS:
2334 if (ic->ic_phytype != IEEE80211_T_FH) {
2335 if (frm + 2 >= efrm)
2336 break;
2337 scan.sp_chan = frm[2];
2338 }
2339 break;
2340 case IEEE80211_ELEMID_TIM:
2341 scan.sp_tim = frm;
2342 scan.sp_timoff = frm - sfrm;
2343 break;
2344 case IEEE80211_ELEMID_XRATES:
2345 scan.sp_xrates = frm;
2346 break;
2347 case IEEE80211_ELEMID_ERP:
2348 if (frm + 1 >= efrm)
2349 break;
2350 if (frm[1] != 1) {
2351 ic->ic_stats.is_rx_elem_toobig++;
2352 break;
2353 }
2354 scan.sp_erp = frm[2];
2355 break;
2356 case IEEE80211_ELEMID_RSN:
2357 scan.sp_wpa = frm;
2358 break;
2359 case IEEE80211_ELEMID_VENDOR:
2360 if (frm + 1 >= efrm)
2361 break;
2362 if (frm + frm[1] + 2 >= efrm)
2363 break;
2364 if (bwfm_iswpaoui(frm))
2365 scan.sp_wpa = frm;
2366 break;
2367 }
2368 if (frm + 1 >= efrm)
2369 break;
2370 }
2371
2372 if (ic->ic_flags & IEEE80211_F_SCAN)
2373 ieee80211_add_scan(ic, &scan, &wh, IEEE80211_FC0_SUBTYPE_BEACON,
2374 le32toh(bss->rssi), 0);
2375 }
2376