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