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