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