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