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