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