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