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