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