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