1 /* $NetBSD: bwfm.c,v 1.35 2023/08/01 07:04:15 mrg Exp $ */ 2 /* $OpenBSD: bwfm.c,v 1.5 2017/10/16 22:27:16 patrick Exp $ */ 3 /* 4 * Copyright (c) 2010-2016 Broadcom Corporation 5 * Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se> 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/param.h> 21 #include <sys/types.h> 22 23 #include <sys/buf.h> 24 #include <sys/device.h> 25 #include <sys/kernel.h> 26 #include <sys/kmem.h> 27 #include <sys/pool.h> 28 #include <sys/queue.h> 29 #include <sys/socket.h> 30 #include <sys/systm.h> 31 #include <sys/workqueue.h> 32 33 #include <net/bpf.h> 34 #include <net/if.h> 35 #include <net/if_dl.h> 36 #include <net/if_ether.h> 37 #include <net/if_media.h> 38 39 #include <netinet/in.h> 40 41 #include <net80211/ieee80211_var.h> 42 43 #include <dev/firmload.h> 44 45 #include <dev/ic/bwfmreg.h> 46 #include <dev/ic/bwfmvar.h> 47 48 /* #define BWFM_DEBUG */ 49 #ifdef BWFM_DEBUG 50 #define DPRINTF(x) do { if (bwfm_debug > 0) printf x; } while (0) 51 #define DPRINTFN(n, x) do { if (bwfm_debug >= (n)) printf x; } while (0) 52 static int bwfm_debug = 1; 53 #else 54 #define DPRINTF(x) do { ; } while (0) 55 #define DPRINTFN(n, x) do { ; } while (0) 56 #endif 57 58 #define DEVNAME(sc) device_xname((sc)->sc_dev) 59 60 void bwfm_start(struct ifnet *); 61 int bwfm_init(struct ifnet *); 62 void bwfm_stop(struct ifnet *, int); 63 void bwfm_watchdog(struct ifnet *); 64 int bwfm_ioctl(struct ifnet *, u_long, void *); 65 int bwfm_media_change(struct ifnet *); 66 67 int bwfm_send_mgmt(struct ieee80211com *, struct ieee80211_node *, 68 int, int); 69 void bwfm_recv_mgmt(struct ieee80211com *, struct mbuf *, 70 struct ieee80211_node *, int, int, uint32_t); 71 int bwfm_key_set(struct ieee80211com *, const struct ieee80211_key *, 72 const uint8_t[IEEE80211_ADDR_LEN]); 73 int bwfm_key_delete(struct ieee80211com *, const struct ieee80211_key *); 74 int bwfm_newstate(struct ieee80211com *, enum ieee80211_state, int); 75 void bwfm_newstate_cb(struct bwfm_softc *, struct bwfm_cmd_newstate *); 76 void bwfm_newassoc(struct ieee80211_node *, int); 77 void bwfm_task(struct work *, void *); 78 79 int bwfm_chip_attach(struct bwfm_softc *); 80 int bwfm_chip_detach(struct bwfm_softc *, int); 81 struct bwfm_core *bwfm_chip_get_core(struct bwfm_softc *, int); 82 struct bwfm_core *bwfm_chip_get_pmu(struct bwfm_softc *); 83 int bwfm_chip_ai_isup(struct bwfm_softc *, struct bwfm_core *); 84 void bwfm_chip_ai_disable(struct bwfm_softc *, struct bwfm_core *, 85 uint32_t, uint32_t); 86 void bwfm_chip_ai_reset(struct bwfm_softc *, struct bwfm_core *, 87 uint32_t, uint32_t, uint32_t); 88 void bwfm_chip_dmp_erom_scan(struct bwfm_softc *); 89 int bwfm_chip_dmp_get_regaddr(struct bwfm_softc *, uint32_t *, 90 uint32_t *, uint32_t *); 91 int bwfm_chip_cr4_set_active(struct bwfm_softc *, const uint32_t); 92 void bwfm_chip_cr4_set_passive(struct bwfm_softc *); 93 int bwfm_chip_ca7_set_active(struct bwfm_softc *, const uint32_t); 94 void bwfm_chip_ca7_set_passive(struct bwfm_softc *); 95 int bwfm_chip_cm3_set_active(struct bwfm_softc *); 96 void bwfm_chip_cm3_set_passive(struct bwfm_softc *); 97 void bwfm_chip_socram_ramsize(struct bwfm_softc *, struct bwfm_core *); 98 void bwfm_chip_sysmem_ramsize(struct bwfm_softc *, struct bwfm_core *); 99 void bwfm_chip_tcm_ramsize(struct bwfm_softc *, struct bwfm_core *); 100 void bwfm_chip_tcm_rambase(struct bwfm_softc *); 101 102 void bwfm_process_blob(struct bwfm_softc *, const char *, uint8_t **, 103 size_t *); 104 int bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *, int, 105 int, char *, size_t *); 106 int bwfm_proto_bcdc_set_dcmd(struct bwfm_softc *, int, 107 int, char *, size_t); 108 109 int bwfm_fwvar_cmd_get_data(struct bwfm_softc *, int, void *, size_t); 110 int bwfm_fwvar_cmd_set_data(struct bwfm_softc *, int, void *, size_t); 111 int bwfm_fwvar_cmd_get_int(struct bwfm_softc *, int, uint32_t *); 112 int bwfm_fwvar_cmd_set_int(struct bwfm_softc *, int, uint32_t); 113 int bwfm_fwvar_var_get_data(struct bwfm_softc *, const char *, void *, size_t); 114 int bwfm_fwvar_var_set_data(struct bwfm_softc *, const char *, void *, size_t); 115 int bwfm_fwvar_var_get_int(struct bwfm_softc *, const char *, uint32_t *); 116 int bwfm_fwvar_var_set_int(struct bwfm_softc *, const char *, uint32_t); 117 118 struct ieee80211_channel *bwfm_bss2chan(struct bwfm_softc *, struct bwfm_bss_info *); 119 void bwfm_scan(struct bwfm_softc *); 120 void bwfm_connect(struct bwfm_softc *); 121 void bwfm_get_sta_info(struct bwfm_softc *, struct ifmediareq *); 122 123 void bwfm_rx(struct bwfm_softc *, struct mbuf *); 124 void bwfm_rx_event(struct bwfm_softc *, struct mbuf *); 125 void bwfm_rx_event_cb(struct bwfm_softc *, struct mbuf *); 126 void bwfm_scan_node(struct bwfm_softc *, struct bwfm_bss_info *, size_t); 127 128 static const uint8_t bwfm_2ghz_channels[] = { 129 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 130 }; 131 static const uint8_t bwfm_5ghz_channels[] = { 132 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64, 100, 104, 108, 112, 133 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165, 134 }; 135 136 const struct bwfm_proto_ops bwfm_proto_bcdc_ops = { 137 .proto_query_dcmd = bwfm_proto_bcdc_query_dcmd, 138 .proto_set_dcmd = bwfm_proto_bcdc_set_dcmd, 139 }; 140 141 static const struct { 142 const char *suffix; 143 const char *description; 144 } bwfm_firmware_filetypes[] = { 145 [BWFM_FILETYPE_UCODE] = { 146 .suffix = "bin", 147 .description = "Firmware", 148 }, 149 [BWFM_FILETYPE_NVRAM] = { 150 .suffix = "txt", 151 .description = "NVRAM", 152 }, 153 [BWFM_FILETYPE_CLM] = { 154 .suffix = "clm_blob", 155 .description = "CLM", 156 }, 157 [BWFM_FILETYPE_TXCAP] = { 158 .suffix = "txcap_blob", 159 .description = "TXCAP", 160 }, 161 [BWFM_FILETYPE_CAL] = { 162 .suffix = "cal_blob", 163 .description = "CAL", 164 }, 165 }; 166 167 static void 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