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