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