[BACK]Return to bwfm.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / ic

Annotation of src/sys/dev/ic/bwfm.c, Revision 1.15

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

CVSweb <webmaster@jp.NetBSD.org>