diff options
| author | Baptiste Daroussin <bapt@FreeBSD.org> | 2015-10-01 09:36:43 +0000 |
|---|---|---|
| committer | Baptiste Daroussin <bapt@FreeBSD.org> | 2015-10-01 09:36:43 +0000 |
| commit | 5a2b666ce590a56f147e167aa07684af2d6b854a (patch) | |
| tree | a5914e0a02f1f78fbcece53ec11bfddc64f76781 /sys/dev | |
| parent | f94594b37a145b9b3e9ff31af2cd1dc3de8aa4d4 (diff) | |
| parent | b60a118dd88613da59c373d9a6eff5f8d35b53ea (diff) | |
Notes
Diffstat (limited to 'sys/dev')
61 files changed, 5566 insertions, 612 deletions
diff --git a/sys/dev/acpica/acpi_pcib.c b/sys/dev/acpica/acpi_pcib.c index 93dada5703ef7..c2c24992f89a5 100644 --- a/sys/dev/acpica/acpi_pcib.c +++ b/sys/dev/acpica/acpi_pcib.c @@ -150,7 +150,7 @@ acpi_pcib_attach(device_t dev, ACPI_BUFFER *prt, int busno) /* * Attach the PCI bus proper. */ - if (device_add_child(dev, "pci", busno) == NULL) { + if (device_add_child(dev, "pci", -1) == NULL) { device_printf(device_get_parent(dev), "couldn't attach pci bus\n"); return_VALUE(ENXIO); } diff --git a/sys/dev/ahci/ahci_pci.c b/sys/dev/ahci/ahci_pci.c index a8f49a1cc3659..5c236cea692c2 100644 --- a/sys/dev/ahci/ahci_pci.c +++ b/sys/dev/ahci/ahci_pci.c @@ -327,6 +327,9 @@ ahci_probe(device_t dev) pci_get_subclass(dev) == PCIS_STORAGE_SATA && pci_get_progif(dev) == PCIP_STORAGE_SATA_AHCI_1_0) valid = 1; + else if (pci_get_class(dev) == PCIC_STORAGE && + pci_get_subclass(dev) == PCIS_STORAGE_RAID) + valid = 2; /* Is this a known AHCI chip? */ for (i = 0; ahci_ids[i].id != 0; i++) { if (ahci_ids[i].id == devid && @@ -343,7 +346,7 @@ ahci_probe(device_t dev) return (BUS_PROBE_DEFAULT); } } - if (!valid) + if (valid != 1) return (ENXIO); device_set_desc_copy(dev, "AHCI SATA controller"); return (BUS_PROBE_DEFAULT); diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index 374e1d03422f1..770badd9175e2 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -4127,7 +4127,6 @@ ath_txq_init(struct ath_softc *sc, struct ath_txq *txq, int qnum) static struct ath_txq * ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) { -#define N(a) (sizeof(a)/sizeof(a[0])) struct ath_hal *ah = sc->sc_ah; HAL_TXQ_INFO qi; int qnum; @@ -4164,10 +4163,10 @@ ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) */ return NULL; } - if (qnum >= N(sc->sc_txq)) { + if (qnum >= nitems(sc->sc_txq)) { device_printf(sc->sc_dev, "hal qnum %u out of range, max %zu!\n", - qnum, N(sc->sc_txq)); + qnum, nitems(sc->sc_txq)); ath_hal_releasetxqueue(ah, qnum); return NULL; } @@ -4176,7 +4175,6 @@ ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) sc->sc_txqsetup |= 1<<qnum; } return &sc->sc_txq[qnum]; -#undef N } /* @@ -4191,12 +4189,11 @@ ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) static int ath_tx_setup(struct ath_softc *sc, int ac, int haltype) { -#define N(a) (sizeof(a)/sizeof(a[0])) struct ath_txq *txq; - if (ac >= N(sc->sc_ac2q)) { + if (ac >= nitems(sc->sc_ac2q)) { device_printf(sc->sc_dev, "AC %u out of range, max %zu!\n", - ac, N(sc->sc_ac2q)); + ac, nitems(sc->sc_ac2q)); return 0; } txq = ath_txq_setup(sc, HAL_TX_QUEUE_DATA, haltype); @@ -4206,7 +4203,6 @@ ath_tx_setup(struct ath_softc *sc, int ac, int haltype) return 1; } else return 0; -#undef N } /* @@ -4216,7 +4212,6 @@ static int ath_txq_update(struct ath_softc *sc, int ac) { #define ATH_EXPONENT_TO_VALUE(v) ((1<<v)-1) -#define ATH_TXOP_TO_US(v) (v<<5) struct ieee80211com *ic = &sc->sc_ic; struct ath_txq *txq = sc->sc_ac2q[ac]; struct wmeParams *wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[ac]; @@ -4262,7 +4257,7 @@ ath_txq_update(struct ath_softc *sc, int ac) qi.tqi_cwmin = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmin); qi.tqi_cwmax = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmax); qi.tqi_readyTime = 0; - qi.tqi_burstTime = ATH_TXOP_TO_US(wmep->wmep_txopLimit); + qi.tqi_burstTime = IEEE80211_TXOP_TO_US(wmep->wmep_txopLimit); #ifdef IEEE80211_SUPPORT_TDMA } #endif @@ -4280,7 +4275,6 @@ ath_txq_update(struct ath_softc *sc, int ac) ath_hal_resettxqueue(ah, txq->axq_qnum); /* push to h/w */ return 1; } -#undef ATH_TXOP_TO_US #undef ATH_EXPONENT_TO_VALUE } @@ -6302,7 +6296,6 @@ ath_rate_setup(struct ath_softc *sc, u_int mode) static void ath_setcurmode(struct ath_softc *sc, enum ieee80211_phymode mode) { -#define N(a) (sizeof(a)/sizeof(a[0])) /* NB: on/off times from the Atheros NDIS driver, w/ permission */ static const struct { u_int rate; /* tx/rx 802.11 rate */ @@ -6339,7 +6332,7 @@ ath_setcurmode(struct ath_softc *sc, enum ieee80211_phymode mode) sc->sc_rixmap[ieeerate | IEEE80211_RATE_MCS] = i; } memset(sc->sc_hwmap, 0, sizeof(sc->sc_hwmap)); - for (i = 0; i < N(sc->sc_hwmap); i++) { + for (i = 0; i < nitems(sc->sc_hwmap); i++) { if (i >= rt->rateCount) { sc->sc_hwmap[i].ledon = (500 * hz) / 1000; sc->sc_hwmap[i].ledoff = (130 * hz) / 1000; @@ -6354,7 +6347,7 @@ ath_setcurmode(struct ath_softc *sc, enum ieee80211_phymode mode) rt->info[i].phy == IEEE80211_T_OFDM) sc->sc_hwmap[i].txflags |= IEEE80211_RADIOTAP_F_SHORTPRE; sc->sc_hwmap[i].rxflags = sc->sc_hwmap[i].txflags; - for (j = 0; j < N(blinkrates)-1; j++) + for (j = 0; j < nitems(blinkrates)-1; j++) if (blinkrates[j].rate == sc->sc_hwmap[i].ieeerate) break; /* NB: this uses the last entry if the rate isn't found */ @@ -6373,7 +6366,6 @@ ath_setcurmode(struct ath_softc *sc, enum ieee80211_phymode mode) else sc->sc_protrix = ath_tx_findrix(sc, 2*1); /* NB: caller is responsible for resetting rate control state */ -#undef N } static void diff --git a/sys/dev/ath/if_ath_ahb.c b/sys/dev/ath/if_ath_ahb.c index fe6420c09c014..0b546a069b8b6 100644 --- a/sys/dev/ath/if_ath_ahb.c +++ b/sys/dev/ath/if_ath_ahb.c @@ -261,7 +261,6 @@ ath_ahb_attach(device_t dev) ATH_PCU_LOCK_INIT(sc); ATH_RX_LOCK_INIT(sc); ATH_TX_LOCK_INIT(sc); - ATH_TX_IC_LOCK_INIT(sc); ATH_TXSTATUS_LOCK_INIT(sc); error = ath_attach(device_id, sc); @@ -271,7 +270,6 @@ ath_ahb_attach(device_t dev) ATH_TXSTATUS_LOCK_DESTROY(sc); ATH_RX_LOCK_DESTROY(sc); ATH_TX_LOCK_DESTROY(sc); - ATH_TX_IC_LOCK_DESTROY(sc); ATH_PCU_LOCK_DESTROY(sc); ATH_LOCK_DESTROY(sc); bus_dma_tag_destroy(sc->sc_dmat); @@ -315,7 +313,6 @@ ath_ahb_detach(device_t dev) ATH_TXSTATUS_LOCK_DESTROY(sc); ATH_RX_LOCK_DESTROY(sc); ATH_TX_LOCK_DESTROY(sc); - ATH_TX_IC_LOCK_DESTROY(sc); ATH_PCU_LOCK_DESTROY(sc); ATH_LOCK_DESTROY(sc); diff --git a/sys/dev/ath/if_ath_beacon.c b/sys/dev/ath/if_ath_beacon.c index 41267b31f885b..1ef3d58d6068a 100644 --- a/sys/dev/ath/if_ath_beacon.c +++ b/sys/dev/ath/if_ath_beacon.c @@ -199,7 +199,7 @@ ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_node *ni) * we assume the mbuf routines will return us something * with this alignment (perhaps should assert). */ - m = ieee80211_beacon_alloc(ni, &avp->av_boff); + m = ieee80211_beacon_alloc(ni, &vap->iv_bcn_off); if (m == NULL) { device_printf(sc->sc_dev, "%s: cannot get mbuf\n", __func__); sc->sc_stats.ast_be_nombuf++; @@ -374,7 +374,7 @@ ath_beacon_setup(struct ath_softc *sc, struct ath_buf *bf) void ath_beacon_update(struct ieee80211vap *vap, int item) { - struct ieee80211_beacon_offsets *bo = &ATH_VAP(vap)->av_boff; + struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; setbit(bo->bo_flags, item); } @@ -713,7 +713,7 @@ ath_beacon_generate(struct ath_softc *sc, struct ieee80211vap *vap) /* XXX lock mcastq? */ nmcastq = avp->av_mcastq.axq_depth; - if (ieee80211_beacon_update(bf->bf_node, &avp->av_boff, m, nmcastq)) { + if (ieee80211_beacon_update(bf->bf_node, &vap->iv_bcn_off, m, nmcastq)) { /* XXX too conservative? */ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m, @@ -726,7 +726,7 @@ ath_beacon_generate(struct ath_softc *sc, struct ieee80211vap *vap) return NULL; } } - if ((avp->av_boff.bo_tim[4] & 1) && cabq->axq_depth) { + if ((vap->iv_bcn_off.bo_tim[4] & 1) && cabq->axq_depth) { DPRINTF(sc, ATH_DEBUG_BEACON, "%s: cabq did not drain, mcastq %u cabq %u\n", __func__, nmcastq, cabq->axq_depth); @@ -764,7 +764,7 @@ ath_beacon_generate(struct ath_softc *sc, struct ieee80211vap *vap) * Enable the CAB queue before the beacon queue to * insure cab frames are triggered by this beacon. */ - if (avp->av_boff.bo_tim[4] & 1) { + if (vap->iv_bcn_off.bo_tim[4] & 1) { /* NB: only at DTIM */ ATH_TXQ_LOCK(&avp->av_mcastq); @@ -829,7 +829,7 @@ ath_beacon_start_adhoc(struct ath_softc *sc, struct ieee80211vap *vap) */ bf = avp->av_bcbuf; m = bf->bf_m; - if (ieee80211_beacon_update(bf->bf_node, &avp->av_boff, m, 0)) { + if (ieee80211_beacon_update(bf->bf_node, &vap->iv_bcn_off, m, 0)) { /* XXX too conservative? */ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m, diff --git a/sys/dev/ath/if_ath_keycache.c b/sys/dev/ath/if_ath_keycache.c index b8a77e89343a1..f81785fa4ce16 100644 --- a/sys/dev/ath/if_ath_keycache.c +++ b/sys/dev/ath/if_ath_keycache.c @@ -184,7 +184,6 @@ ath_keyset(struct ath_softc *sc, struct ieee80211vap *vap, const struct ieee80211_key *k, struct ieee80211_node *bss) { -#define N(a) (sizeof(a)/sizeof(a[0])) static const u_int8_t ciphermap[] = { HAL_CIPHER_WEP, /* IEEE80211_CIPHER_WEP */ HAL_CIPHER_TKIP, /* IEEE80211_CIPHER_TKIP */ @@ -208,7 +207,7 @@ ath_keyset(struct ath_softc *sc, struct ieee80211vap *vap, * so that rx frames have an entry to match. */ if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) { - KASSERT(cip->ic_cipher < N(ciphermap), + KASSERT(cip->ic_cipher < nitems(ciphermap), ("invalid cipher type %u", cip->ic_cipher)); hk.kv_type = ciphermap[cip->ic_cipher]; hk.kv_len = k->wk_keylen; @@ -266,7 +265,6 @@ ath_keyset(struct ath_softc *sc, struct ieee80211vap *vap, ATH_UNLOCK(sc); return (ret); -#undef N } /* @@ -277,12 +275,11 @@ static u_int16_t key_alloc_2pair(struct ath_softc *sc, ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix) { -#define N(a) (sizeof(a)/sizeof(a[0])) u_int i, keyix; KASSERT(sc->sc_splitmic, ("key cache !split")); /* XXX could optimize */ - for (i = 0; i < N(sc->sc_keymap)/4; i++) { + for (i = 0; i < nitems(sc->sc_keymap)/4; i++) { u_int8_t b = sc->sc_keymap[i]; if (b != 0xff) { /* @@ -321,7 +318,6 @@ key_alloc_2pair(struct ath_softc *sc, } DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of pair space\n", __func__); return 0; -#undef N } /* @@ -332,12 +328,11 @@ static u_int16_t key_alloc_pair(struct ath_softc *sc, ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix) { -#define N(a) (sizeof(a)/sizeof(a[0])) u_int i, keyix; KASSERT(!sc->sc_splitmic, ("key cache split")); /* XXX could optimize */ - for (i = 0; i < N(sc->sc_keymap)/4; i++) { + for (i = 0; i < nitems(sc->sc_keymap)/4; i++) { u_int8_t b = sc->sc_keymap[i]; if (b != 0xff) { /* @@ -369,7 +364,6 @@ key_alloc_pair(struct ath_softc *sc, } DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of pair space\n", __func__); return 0; -#undef N } /* @@ -379,7 +373,6 @@ static int key_alloc_single(struct ath_softc *sc, ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix) { -#define N(a) (sizeof(a)/sizeof(a[0])) u_int i, keyix; if (sc->sc_hasclrkey == 0) { @@ -391,7 +384,7 @@ key_alloc_single(struct ath_softc *sc, } /* XXX try i,i+32,i+64,i+32+64 to minimize key pair conflicts */ - for (i = 0; i < N(sc->sc_keymap); i++) { + for (i = 0; i < nitems(sc->sc_keymap); i++) { u_int8_t b = sc->sc_keymap[i]; if (b != 0xff) { /* @@ -409,7 +402,6 @@ key_alloc_single(struct ath_softc *sc, } DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of space\n", __func__); return 0; -#undef N } /* diff --git a/sys/dev/ath/if_ath_pci.c b/sys/dev/ath/if_ath_pci.c index 5610882f315db..bc4f7f0229b7e 100644 --- a/sys/dev/ath/if_ath_pci.c +++ b/sys/dev/ath/if_ath_pci.c @@ -283,7 +283,6 @@ ath_pci_attach(device_t dev) ATH_PCU_LOCK_INIT(sc); ATH_RX_LOCK_INIT(sc); ATH_TX_LOCK_INIT(sc); - ATH_TX_IC_LOCK_INIT(sc); ATH_TXSTATUS_LOCK_INIT(sc); /* @@ -371,7 +370,6 @@ bad1: ATH_TXSTATUS_LOCK_DESTROY(sc); ATH_PCU_LOCK_DESTROY(sc); ATH_RX_LOCK_DESTROY(sc); - ATH_TX_IC_LOCK_DESTROY(sc); ATH_TX_LOCK_DESTROY(sc); ATH_LOCK_DESTROY(sc); @@ -408,7 +406,6 @@ ath_pci_detach(device_t dev) ATH_TXSTATUS_LOCK_DESTROY(sc); ATH_PCU_LOCK_DESTROY(sc); ATH_RX_LOCK_DESTROY(sc); - ATH_TX_IC_LOCK_DESTROY(sc); ATH_TX_LOCK_DESTROY(sc); ATH_LOCK_DESTROY(sc); diff --git a/sys/dev/ath/if_ath_tdma.c b/sys/dev/ath/if_ath_tdma.c index 99cd61eb51a6f..e3460c6374c3a 100644 --- a/sys/dev/ath/if_ath_tdma.c +++ b/sys/dev/ath/if_ath_tdma.c @@ -548,7 +548,7 @@ ath_tdma_update(struct ieee80211_node *ni, * slot position changes) because ieee80211_add_tdma * skips over the data. */ - memcpy(ATH_VAP(vap)->av_boff.bo_tdma + + memcpy(vap->iv_bcn_off.bo_tdma + __offsetof(struct ieee80211_tdma_param, tdma_tstamp), &ni->ni_tstamp.data, 8); #if 0 diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h index 2e71ff6374d4b..1af99aa9c334e 100644 --- a/sys/dev/ath/if_athvar.h +++ b/sys/dev/ath/if_athvar.h @@ -477,7 +477,6 @@ struct ath_vap { struct ieee80211vap av_vap; /* base class */ int av_bslot; /* beacon slot index */ struct ath_buf *av_bcbuf; /* beacon buffer */ - struct ieee80211_beacon_offsets av_boff;/* dynamic update state */ struct ath_txq av_mcastq; /* buffered mcast s/w queue */ void (*av_recv_mgmt)(struct ieee80211_node *, @@ -942,26 +941,6 @@ struct ath_softc { mtx_trylock(&(_sc)->sc_tx_mtx)) /* - * The IC TX lock is non-reentrant and serialises packet queuing from - * the upper layers. - */ -#define ATH_TX_IC_LOCK_INIT(_sc) do {\ - snprintf((_sc)->sc_tx_ic_mtx_name, \ - sizeof((_sc)->sc_tx_ic_mtx_name), \ - "%s IC TX lock", \ - device_get_nameunit((_sc)->sc_dev)); \ - mtx_init(&(_sc)->sc_tx_ic_mtx, (_sc)->sc_tx_ic_mtx_name, \ - NULL, MTX_DEF); \ - } while (0) -#define ATH_TX_IC_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_tx_ic_mtx) -#define ATH_TX_IC_LOCK(_sc) mtx_lock(&(_sc)->sc_tx_ic_mtx) -#define ATH_TX_IC_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_tx_ic_mtx) -#define ATH_TX_IC_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_tx_ic_mtx, \ - MA_OWNED) -#define ATH_TX_IC_UNLOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_tx_ic_mtx, \ - MA_NOTOWNED) - -/* * The PCU lock is non-recursive and should be treated as a spinlock. * Although currently the interrupt code is run in netisr context and * doesn't require this, this may change in the future. diff --git a/sys/dev/bwi/bwimac.c b/sys/dev/bwi/bwimac.c index baad7fef550fb..54d2fde57cc11 100644 --- a/sys/dev/bwi/bwimac.c +++ b/sys/dev/bwi/bwimac.c @@ -1657,17 +1657,15 @@ bwi_mac_attach(struct bwi_softc *sc, int id, uint8_t rev) /* * Test whether the revision of this MAC is supported */ -#define N(arr) (int)(sizeof(arr) / sizeof(arr[0])) - for (i = 0; i < N(bwi_sup_macrev); ++i) { + for (i = 0; i < nitems(bwi_sup_macrev); ++i) { if (bwi_sup_macrev[i] == rev) break; } - if (i == N(bwi_sup_macrev)) { + if (i == nitems(bwi_sup_macrev)) { device_printf(sc->sc_dev, "MAC rev %u is " "not supported\n", rev); return ENXIO; } -#undef N BWI_CREATE_MAC(mac, sc, id, rev); sc->sc_nmac++; diff --git a/sys/dev/bwi/bwiphy.c b/sys/dev/bwi/bwiphy.c index 60d6bf569bafc..60afb191d240e 100644 --- a/sys/dev/bwi/bwiphy.c +++ b/sys/dev/bwi/bwiphy.c @@ -185,19 +185,17 @@ bwi_phy_attach(struct bwi_mac *mac) phy->phy_tbl_data_hi = BWI_PHYR_TBL_DATA_HI_11A; break; case BWI_PHYINFO_TYPE_11B: -#define N(arr) (int)(sizeof(arr) / sizeof(arr[0])) - for (i = 0; i < N(bwi_sup_bphy); ++i) { + for (i = 0; i < nitems(bwi_sup_bphy); ++i) { if (phyrev == bwi_sup_bphy[i].rev) { phy->phy_init = bwi_sup_bphy[i].init; break; } } - if (i == N(bwi_sup_bphy)) { + if (i == nitems(bwi_sup_bphy)) { device_printf(sc->sc_dev, "unsupported 11B PHY, " "rev %u\n", phyrev); return ENXIO; } -#undef N phy->phy_mode = IEEE80211_MODE_11B; break; case BWI_PHYINFO_TYPE_11G: @@ -745,8 +743,6 @@ bwi_phy_init_11b_rev6(struct bwi_mac *mac) } } -#define N(arr) (int)(sizeof(arr) / sizeof(arr[0])) - static void bwi_phy_config_11g(struct bwi_mac *mac) { @@ -763,19 +759,19 @@ bwi_phy_config_11g(struct bwi_mac *mac) PHY_WRITE(mac, 0x427, 0x1a); /* Fill frequency table */ - for (i = 0; i < N(bwi_phy_freq_11g_rev1); ++i) { + for (i = 0; i < nitems(bwi_phy_freq_11g_rev1); ++i) { bwi_tbl_write_2(mac, BWI_PHYTBL_FREQ + i, bwi_phy_freq_11g_rev1[i]); } /* Fill noise table */ - for (i = 0; i < N(bwi_phy_noise_11g_rev1); ++i) { + for (i = 0; i < nitems(bwi_phy_noise_11g_rev1); ++i) { bwi_tbl_write_2(mac, BWI_PHYTBL_NOISE + i, bwi_phy_noise_11g_rev1[i]); } /* Fill rotor table */ - for (i = 0; i < N(bwi_phy_rotor_11g_rev1); ++i) { + for (i = 0; i < nitems(bwi_phy_rotor_11g_rev1); ++i) { /* NB: data length is 4 bytes */ bwi_tbl_write_4(mac, BWI_PHYTBL_ROTOR + i, bwi_phy_rotor_11g_rev1[i]); @@ -798,7 +794,7 @@ bwi_phy_config_11g(struct bwi_mac *mac) bwi_tbl_write_2(mac, BWI_PHYTBL_RSSI + i, i); /* Fill noise table */ - for (i = 0; i < N(bwi_phy_noise_11g); ++i) { + for (i = 0; i < nitems(bwi_phy_noise_11g); ++i) { bwi_tbl_write_2(mac, BWI_PHYTBL_NOISE + i, bwi_phy_noise_11g[i]); } @@ -809,13 +805,13 @@ bwi_phy_config_11g(struct bwi_mac *mac) */ if (phy->phy_rev <= 2) { tbl = bwi_phy_noise_scale_11g_rev2; - n = N(bwi_phy_noise_scale_11g_rev2); + n = nitems(bwi_phy_noise_scale_11g_rev2); } else if (phy->phy_rev >= 7 && (PHY_READ(mac, 0x449) & 0x200)) { tbl = bwi_phy_noise_scale_11g_rev7; - n = N(bwi_phy_noise_scale_11g_rev7); + n = nitems(bwi_phy_noise_scale_11g_rev7); } else { tbl = bwi_phy_noise_scale_11g; - n = N(bwi_phy_noise_scale_11g); + n = nitems(bwi_phy_noise_scale_11g); } for (i = 0; i < n; ++i) bwi_tbl_write_2(mac, BWI_PHYTBL_NOISE_SCALE + i, tbl[i]); @@ -825,10 +821,10 @@ bwi_phy_config_11g(struct bwi_mac *mac) */ if (phy->phy_rev == 2) { tbl = bwi_phy_sigma_sq_11g_rev2; - n = N(bwi_phy_sigma_sq_11g_rev2); + n = nitems(bwi_phy_sigma_sq_11g_rev2); } else if (phy->phy_rev > 2 && phy->phy_rev <= 8) { tbl = bwi_phy_sigma_sq_11g_rev7; - n = N(bwi_phy_sigma_sq_11g_rev7); + n = nitems(bwi_phy_sigma_sq_11g_rev7); } else { tbl = NULL; n = 0; @@ -838,7 +834,7 @@ bwi_phy_config_11g(struct bwi_mac *mac) if (phy->phy_rev == 1) { /* Fill delay table */ - for (i = 0; i < N(bwi_phy_delay_11g_rev1); ++i) { + for (i = 0; i < nitems(bwi_phy_delay_11g_rev1); ++i) { bwi_tbl_write_4(mac, BWI_PHYTBL_DELAY + i, bwi_phy_delay_11g_rev1[i]); } @@ -877,8 +873,6 @@ bwi_phy_config_11g(struct bwi_mac *mac) PHY_WRITE(mac, 0x46e, 0x3cf); } -#undef N - /* * Configure Automatic Gain Controller */ diff --git a/sys/dev/bwi/bwirf.c b/sys/dev/bwi/bwirf.c index 615e6dff69023..341e929f6a5fb 100644 --- a/sys/dev/bwi/bwirf.c +++ b/sys/dev/bwi/bwirf.c @@ -1155,7 +1155,6 @@ bwi_rf_map_txpower(struct bwi_mac *mac) } #define IS_VALID_PA_PARAM(p) ((p) != 0 && (p) != -1) -#define N(arr) (int)(sizeof(arr) / sizeof(arr[0])) /* * Extract PA parameters @@ -1164,10 +1163,10 @@ bwi_rf_map_txpower(struct bwi_mac *mac) sprom_ofs = BWI_SPROM_PA_PARAM_11A; else sprom_ofs = BWI_SPROM_PA_PARAM_11BG; - for (i = 0; i < N(pa_params); ++i) + for (i = 0; i < nitems(pa_params); ++i) pa_params[i] = (int16_t)bwi_read_sprom(sc, sprom_ofs + (i * 2)); - for (i = 0; i < N(pa_params); ++i) { + for (i = 0; i < nitems(pa_params); ++i) { /* * If one of the PA parameters from SPROM is not valid, * fall back to the default values, if there are any. @@ -1200,8 +1199,6 @@ bwi_rf_map_txpower(struct bwi_mac *mac) } } -#undef N - /* * All of the PA parameters from SPROM are valid. */ diff --git a/sys/dev/bwi/if_bwi.c b/sys/dev/bwi/if_bwi.c index 741f5f1d922bc..0a220a1de5764 100644 --- a/sys/dev/bwi/if_bwi.c +++ b/sys/dev/bwi/if_bwi.c @@ -762,7 +762,6 @@ bwi_regwin_info(struct bwi_softc *sc, uint16_t *type, uint8_t *rev) static int bwi_bbp_attach(struct bwi_softc *sc) { -#define N(arr) (int)(sizeof(arr) / sizeof(arr[0])) uint16_t bbp_id, rw_type; uint8_t rw_rev; uint32_t info; @@ -792,7 +791,7 @@ bwi_bbp_attach(struct bwi_softc *sc) sc->sc_cap = CSR_READ_4(sc, BWI_CAPABILITY); } else { - for (i = 0; i < N(bwi_bbpid_map); ++i) { + for (i = 0; i < nitems(bwi_bbpid_map); ++i) { if (sc->sc_pci_did >= bwi_bbpid_map[i].did_min && sc->sc_pci_did <= bwi_bbpid_map[i].did_max) { bbp_id = bwi_bbpid_map[i].bbp_id; @@ -816,7 +815,7 @@ bwi_bbp_attach(struct bwi_softc *sc) if (rw_type == BWI_REGWIN_T_COM && rw_rev >= 4) { nregwin = __SHIFTOUT(info, BWI_INFO_NREGWIN_MASK); } else { - for (i = 0; i < N(bwi_regwin_count); ++i) { + for (i = 0; i < nitems(bwi_regwin_count); ++i) { if (bwi_regwin_count[i].bbp_id == bbp_id) { nregwin = bwi_regwin_count[i].nregwin; break; @@ -898,7 +897,6 @@ bwi_bbp_attach(struct bwi_softc *sc) return error; return 0; -#undef N } int @@ -3765,9 +3763,7 @@ bwi_led_attach(struct bwi_softc *sc) uint16_t gpio, val[BWI_LED_MAX]; int i; -#define N(arr) (int)(sizeof(arr) / sizeof(arr[0])) - - for (i = 0; i < N(bwi_vendor_led_act); ++i) { + for (i = 0; i < nitems(bwi_vendor_led_act); ++i) { if (sc->sc_pci_subvid == bwi_vendor_led_act[i].vid) { led_act = bwi_vendor_led_act[i].led_act; break; @@ -3776,8 +3772,6 @@ bwi_led_attach(struct bwi_softc *sc) if (led_act == NULL) led_act = bwi_default_led_act; -#undef N - gpio = bwi_read_sprom(sc, BWI_SPROM_GPIO01); val[0] = __SHIFTOUT(gpio, BWI_SPROM_GPIO_0); val[1] = __SHIFTOUT(gpio, BWI_SPROM_GPIO_1); diff --git a/sys/dev/drm2/drm_lock.c b/sys/dev/drm2/drm_lock.c index 1bc681ca44d9f..8b593c41035b0 100644 --- a/sys/dev/drm2/drm_lock.c +++ b/sys/dev/drm2/drm_lock.c @@ -38,7 +38,9 @@ __FBSDID("$FreeBSD$"); #include <dev/drm2/drmP.h> +#if defined(__linux__) static int drm_notifier(void *priv); +#endif static int drm_lock_take(struct drm_lock_data *lock_data, unsigned int context); @@ -284,6 +286,7 @@ int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context) return 0; } +#if defined(__linux__) /** * If we get here, it means that the process has called DRM_IOCTL_LOCK * without calling DRM_IOCTL_UNLOCK. @@ -314,6 +317,7 @@ static int drm_notifier(void *priv) } while (prev != old); return 0; } +#endif /** * This function returns immediately and takes the hw lock diff --git a/sys/dev/dwc/if_dwc.c b/sys/dev/dwc/if_dwc.c index 939ce541a5b50..e25d7f5a3d20f 100644 --- a/sys/dev/dwc/if_dwc.c +++ b/sys/dev/dwc/if_dwc.c @@ -43,21 +43,14 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/bus.h> #include <sys/kernel.h> -#include <sys/module.h> -#include <sys/malloc.h> -#include <sys/rman.h> -#include <sys/endian.h> #include <sys/lock.h> +#include <sys/malloc.h> #include <sys/mbuf.h> +#include <sys/module.h> #include <sys/mutex.h> +#include <sys/rman.h> #include <sys/socket.h> #include <sys/sockio.h> -#include <sys/sysctl.h> - -#include <dev/fdt/fdt_common.h> -#include <dev/ofw/openfirm.h> -#include <dev/ofw/ofw_bus.h> -#include <dev/ofw/ofw_bus_subr.h> #include <net/bpf.h> #include <net/if.h> @@ -66,13 +59,17 @@ __FBSDID("$FreeBSD$"); #include <net/if_media.h> #include <net/if_types.h> #include <net/if_var.h> -#include <net/if_vlan_var.h> #include <machine/bus.h> -#include <machine/fdt.h> +#include <dev/dwc/if_dwc.h> +#include <dev/dwc/if_dwcvar.h> #include <dev/mii/mii.h> #include <dev/mii/miivar.h> +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> + +#include "if_dwc_if.h" #include "miibus_if.h" #define READ4(_sc, _reg) \ @@ -83,9 +80,6 @@ __FBSDID("$FreeBSD$"); #define MAC_RESET_TIMEOUT 100 #define WATCHDOG_TIMEOUT_SECS 5 #define STATS_HARVEST_INTERVAL 2 -#define MII_CLK_VAL 2 - -#include <dev/dwc/if_dwc.h> #define DWC_LOCK(sc) mtx_lock(&(sc)->mtx) #define DWC_UNLOCK(sc) mtx_unlock(&(sc)->mtx) @@ -105,77 +99,34 @@ __FBSDID("$FreeBSD$"); #define DDESC_RDES0_FL_SHIFT 16 /* Frame Length */ #define DDESC_RDES1_CHAINED (1U << 14) -struct dwc_bufmap { - bus_dmamap_t map; - struct mbuf *mbuf; -}; +/* Alt descriptor bits. */ +#define DDESC_CNTL_TXINT (1U << 31) +#define DDESC_CNTL_TXLAST (1U << 30) +#define DDESC_CNTL_TXFIRST (1U << 29) +#define DDESC_CNTL_TXCRCDIS (1U << 26) +#define DDESC_CNTL_TXRINGEND (1U << 25) +#define DDESC_CNTL_TXCHAIN (1U << 24) + +#define DDESC_CNTL_CHAINED (1U << 24) /* * A hardware buffer descriptor. Rx and Tx buffers have the same descriptor - * layout, but the bits in the flags field have different meanings. + * layout, but the bits in the fields have different meanings. */ struct dwc_hwdesc { - uint32_t tdes0; - uint32_t tdes1; + uint32_t tdes0; /* status for alt layout */ + uint32_t tdes1; /* cntl for alt layout */ uint32_t addr; /* pointer to buffer data */ uint32_t addr_next; /* link to next descriptor */ }; /* - * Driver data and defines. - */ -#define RX_DESC_COUNT 1024 -#define RX_DESC_SIZE (sizeof(struct dwc_hwdesc) * RX_DESC_COUNT) -#define TX_DESC_COUNT 1024 -#define TX_DESC_SIZE (sizeof(struct dwc_hwdesc) * TX_DESC_COUNT) - -/* * The hardware imposes alignment restrictions on various objects involved in * DMA transfers. These values are expressed in bytes (not bits). */ #define DWC_DESC_RING_ALIGN 2048 -struct dwc_softc { - struct resource *res[2]; - bus_space_tag_t bst; - bus_space_handle_t bsh; - device_t dev; - int mii_clk; - device_t miibus; - struct mii_data * mii_softc; - struct ifnet *ifp; - int if_flags; - struct mtx mtx; - void * intr_cookie; - struct callout dwc_callout; - boolean_t link_is_up; - boolean_t is_attached; - boolean_t is_detaching; - int tx_watchdog_count; - int stats_harvest_count; - - /* RX */ - bus_dma_tag_t rxdesc_tag; - bus_dmamap_t rxdesc_map; - struct dwc_hwdesc *rxdesc_ring; - bus_addr_t rxdesc_ring_paddr; - bus_dma_tag_t rxbuf_tag; - struct dwc_bufmap rxbuf_map[RX_DESC_COUNT]; - uint32_t rx_idx; - - /* TX */ - bus_dma_tag_t txdesc_tag; - bus_dmamap_t txdesc_map; - struct dwc_hwdesc *txdesc_ring; - bus_addr_t txdesc_ring_paddr; - bus_dma_tag_t txbuf_tag; - struct dwc_bufmap txbuf_map[RX_DESC_COUNT]; - uint32_t tx_idx_head; - uint32_t tx_idx_tail; - int txcount; -}; - static struct resource_spec dwc_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { SYS_RES_IRQ, 0, RF_ACTIVE }, @@ -224,14 +175,23 @@ dwc_setup_txdesc(struct dwc_softc *sc, int idx, bus_addr_t paddr, flags = 0; --sc->txcount; } else { - flags = DDESC_TDES0_TXCHAIN | DDESC_TDES0_TXFIRST - | DDESC_TDES0_TXLAST | DDESC_TDES0_TXINT; + if (sc->mactype == DWC_GMAC_ALT_DESC) + flags = DDESC_CNTL_TXCHAIN | DDESC_CNTL_TXFIRST + | DDESC_CNTL_TXLAST | DDESC_CNTL_TXINT; + else + flags = DDESC_TDES0_TXCHAIN | DDESC_TDES0_TXFIRST + | DDESC_TDES0_TXLAST | DDESC_TDES0_TXINT; ++sc->txcount; } sc->txdesc_ring[idx].addr = (uint32_t)(paddr); - sc->txdesc_ring[idx].tdes0 = flags; - sc->txdesc_ring[idx].tdes1 = len; + if (sc->mactype == DWC_GMAC_ALT_DESC) { + sc->txdesc_ring[idx].tdes0 = 0; + sc->txdesc_ring[idx].tdes1 = flags | len; + } else { + sc->txdesc_ring[idx].tdes0 = flags; + sc->txdesc_ring[idx].tdes1 = len; + } if (paddr && len) { wmb(); @@ -504,7 +464,10 @@ dwc_setup_rxdesc(struct dwc_softc *sc, int idx, bus_addr_t paddr) nidx = next_rxidx(sc, idx); sc->rxdesc_ring[idx].addr_next = sc->rxdesc_ring_paddr + \ (nidx * sizeof(struct dwc_hwdesc)); - sc->rxdesc_ring[idx].tdes1 = DDESC_RDES1_CHAINED | MCLBYTES; + if (sc->mactype == DWC_GMAC_ALT_DESC) + sc->rxdesc_ring[idx].tdes1 = DDESC_CNTL_CHAINED | RX_MAX_PACKET; + else + sc->rxdesc_ring[idx].tdes1 = DDESC_RDES1_CHAINED | MCLBYTES; wmb(); sc->rxdesc_ring[idx].tdes0 = DDESC_RDES0_OWN; @@ -821,10 +784,8 @@ dwc_intr(void *arg) DWC_LOCK(sc); reg = READ4(sc, INTERRUPT_STATUS); - if (reg) { - mii_mediachg(sc->mii_softc); + if (reg) READ4(sc, SGMII_RGMII_SMII_CTRL_STATUS); - } reg = READ4(sc, DMA_STATUS); if (reg & DMA_STATUS_NIS) { @@ -1074,10 +1035,13 @@ dwc_attach(device_t dev) sc = device_get_softc(dev); sc->dev = dev; - sc->mii_clk = MII_CLK_VAL; sc->rx_idx = 0; - sc->txcount = TX_DESC_COUNT; + sc->mii_clk = IF_DWC_MII_CLK(dev); + sc->mactype = IF_DWC_MAC_TYPE(dev); + + if (IF_DWC_INIT(dev) != 0) + return (ENXIO); if (bus_alloc_resources(dev, dwc_spec, sc->res)) { device_printf(dev, "could not allocate resources\n"); @@ -1109,8 +1073,11 @@ dwc_attach(device_t dev) return (ENXIO); } - reg = READ4(sc, BUS_MODE); - reg |= (BUS_MODE_EIGHTXPBL); + if (sc->mactype == DWC_GMAC_ALT_DESC) { + reg = BUS_MODE_FIXEDBURST; + reg |= (BUS_MODE_PRIORXTX_41 << BUS_MODE_PRIORXTX_SHIFT); + } else + reg = (BUS_MODE_EIGHTXPBL); reg |= (BUS_MODE_PBL_BEATS_8 << BUS_MODE_PBL_SHIFT); WRITE4(sc, BUS_MODE, reg); @@ -1155,7 +1122,6 @@ dwc_attach(device_t dev) IFQ_SET_MAXLEN(&ifp->if_snd, TX_DESC_COUNT - 1); ifp->if_snd.ifq_drv_maxlen = TX_DESC_COUNT - 1; IFQ_SET_READY(&ifp->if_snd); - ifp->if_hdrlen = sizeof(struct ether_vlan_header); /* Attach the mii driver. */ error = mii_attach(dev, &sc->miibus, ifp, dwc_media_change, @@ -1294,7 +1260,7 @@ static device_method_t dwc_methods[] = { { 0, 0 } }; -static driver_t dwc_driver = { +driver_t dwc_driver = { "dwc", dwc_methods, sizeof(struct dwc_softc), diff --git a/sys/dev/dwc/if_dwc.h b/sys/dev/dwc/if_dwc.h index f6179bfa68496..c9403da71000e 100644 --- a/sys/dev/dwc/if_dwc.h +++ b/sys/dev/dwc/if_dwc.h @@ -34,6 +34,9 @@ * Register names were taken almost as is from the documentation. */ +#ifndef __IF_DWC_H__ +#define __IF_DWC_H__ + #define MAC_CONFIGURATION 0x0 #define CONF_JD (1 << 22) /* jabber timer disable */ #define CONF_BE (1 << 21) /* Frame Burst Enable */ @@ -207,6 +210,12 @@ /* DMA */ #define BUS_MODE 0x1000 #define BUS_MODE_EIGHTXPBL (1 << 24) /* Multiplies PBL by 8 */ +#define BUS_MODE_FIXEDBURST (1 << 16) +#define BUS_MODE_PRIORXTX_SHIFT 14 +#define BUS_MODE_PRIORXTX_41 3 +#define BUS_MODE_PRIORXTX_31 2 +#define BUS_MODE_PRIORXTX_21 1 +#define BUS_MODE_PRIORXTX_11 0 #define BUS_MODE_PBL_SHIFT 8 /* Single block transfer size */ #define BUS_MODE_PBL_BEATS_8 8 #define BUS_MODE_SWR (1 << 0) /* Reset */ @@ -260,3 +269,22 @@ #define CURRENT_HOST_TRANSMIT_BUF_ADDR 0x1050 #define CURRENT_HOST_RECEIVE_BUF_ADDR 0x1054 #define HW_FEATURE 0x1058 + +#define DWC_GMAC 0x1 +#define DWC_GMAC_ALT_DESC 0x2 +#define GMAC_MII_CLK_60_100M_DIV42 0x0 +#define GMAC_MII_CLK_100_150M_DIV62 0x1 +#define GMAC_MII_CLK_25_35M_DIV16 0x2 +#define GMAC_MII_CLK_35_60M_DIV26 0x3 +#define GMAC_MII_CLK_150_250M_DIV102 0x4 +#define GMAC_MII_CLK_250_300M_DIV124 0x5 +#define GMAC_MII_CLK_DIV4 0x8 +#define GMAC_MII_CLK_DIV6 0x9 +#define GMAC_MII_CLK_DIV8 0xa +#define GMAC_MII_CLK_DIV10 0xb +#define GMAC_MII_CLK_DIV12 0xc +#define GMAC_MII_CLK_DIV14 0xd +#define GMAC_MII_CLK_DIV16 0xe +#define GMAC_MII_CLK_DIV18 0xf + +#endif /* __IF_DWC_H__ */ diff --git a/sys/dev/dwc/if_dwc_if.m b/sys/dev/dwc/if_dwc_if.m new file mode 100644 index 0000000000000..feecb4e1f599f --- /dev/null +++ b/sys/dev/dwc/if_dwc_if.m @@ -0,0 +1,76 @@ +#- +# Copyright (c) 2015 Luiz Otavio O Souza <loos@FreeBSD.org> +# Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +INTERFACE if_dwc; + +#include <dev/dwc/if_dwc.h> + +CODE { + static int + if_dwc_default_init(device_t dev) + { + return (0); + } + + static int + if_dwc_default_mac_type(device_t dev) + { + return (DWC_GMAC); + } + + static int + if_dwc_default_mii_clk(device_t dev) + { + return (GMAC_MII_CLK_25_35M_DIV16); + } +}; + +HEADER { +}; + +# +# Initialize the SoC specific registers. +# +METHOD int init { + device_t dev; +} DEFAULT if_dwc_default_init; + +# +# Return the DWC MAC type (descriptor type). +# +METHOD int mac_type { + device_t dev; +} DEFAULT if_dwc_default_mac_type; + +# +# Return the DWC MII clock for a specific hardware. +# +METHOD int mii_clk { + device_t dev; +} DEFAULT if_dwc_default_mii_clk; diff --git a/sys/dev/dwc/if_dwcvar.h b/sys/dev/dwc/if_dwcvar.h new file mode 100644 index 0000000000000..3dd6a8dda2b53 --- /dev/null +++ b/sys/dev/dwc/if_dwcvar.h @@ -0,0 +1,99 @@ +/*- + * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> + * All rights reserved. + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) + * ("CTSRD"), as part of the DARPA CRASH research programme. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Ethernet media access controller (EMAC) + * Chapter 17, Altera Cyclone V Device Handbook (CV-5V2 2014.07.22) + * + * EMAC is an instance of the Synopsys DesignWare 3504-0 + * Universal 10/100/1000 Ethernet MAC (DWC_gmac). + */ + +#ifndef __IF_DWCVAR_H__ +#define __IF_DWCVAR_H__ + +/* + * Driver data and defines. + */ +#define RX_MAX_PACKET 0x7ff +#define RX_DESC_COUNT 1024 +#define RX_DESC_SIZE (sizeof(struct dwc_hwdesc) * RX_DESC_COUNT) +#define TX_DESC_COUNT 1024 +#define TX_DESC_SIZE (sizeof(struct dwc_hwdesc) * TX_DESC_COUNT) + +struct dwc_bufmap { + bus_dmamap_t map; + struct mbuf *mbuf; +}; + +struct dwc_softc { + struct resource *res[2]; + bus_space_tag_t bst; + bus_space_handle_t bsh; + device_t dev; + int mactype; + int mii_clk; + device_t miibus; + struct mii_data * mii_softc; + struct ifnet *ifp; + int if_flags; + struct mtx mtx; + void * intr_cookie; + struct callout dwc_callout; + boolean_t link_is_up; + boolean_t is_attached; + boolean_t is_detaching; + int tx_watchdog_count; + int stats_harvest_count; + + /* RX */ + bus_dma_tag_t rxdesc_tag; + bus_dmamap_t rxdesc_map; + struct dwc_hwdesc *rxdesc_ring; + bus_addr_t rxdesc_ring_paddr; + bus_dma_tag_t rxbuf_tag; + struct dwc_bufmap rxbuf_map[RX_DESC_COUNT]; + uint32_t rx_idx; + + /* TX */ + bus_dma_tag_t txdesc_tag; + bus_dmamap_t txdesc_map; + struct dwc_hwdesc *txdesc_ring; + bus_addr_t txdesc_ring_paddr; + bus_dma_tag_t txbuf_tag; + struct dwc_bufmap txbuf_map[RX_DESC_COUNT]; + uint32_t tx_idx_head; + uint32_t tx_idx_tail; + int txcount; +}; + +#endif /* __IF_DWCVAR_H__ */ diff --git a/sys/dev/ipw/if_ipw.c b/sys/dev/ipw/if_ipw.c index 1ffd24c5243d6..c4f47e4deed44 100644 --- a/sys/dev/ipw/if_ipw.c +++ b/sys/dev/ipw/if_ipw.c @@ -1417,7 +1417,6 @@ ipw_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) static const char * ipw_cmdname(int cmd) { -#define N(a) (sizeof(a) / sizeof(a[0])) static const struct { int cmd; const char *name; @@ -1454,12 +1453,11 @@ ipw_cmdname(int cmd) static char buf[12]; int i; - for (i = 0; i < N(cmds); i++) + for (i = 0; i < nitems(cmds); i++) if (cmds[i].cmd == cmd) return cmds[i].name; snprintf(buf, sizeof(buf), "%u", cmd); return buf; -#undef N } /* diff --git a/sys/dev/iwi/if_iwi.c b/sys/dev/iwi/if_iwi.c index 73631eaa1e5f4..c45a37ffe55e5 100644 --- a/sys/dev/iwi/if_iwi.c +++ b/sys/dev/iwi/if_iwi.c @@ -3415,7 +3415,6 @@ iwi_led_blink(struct iwi_softc *sc, int on, int off) static void iwi_led_event(struct iwi_softc *sc, int event) { -#define N(a) (sizeof(a)/sizeof(a[0])) /* NB: on/off times from the Atheros NDIS driver, w/ permission */ static const struct { u_int rate; /* tx/rx iwi rate */ @@ -3445,13 +3444,13 @@ iwi_led_event(struct iwi_softc *sc, int event) return; switch (event) { case IWI_LED_POLL: - j = N(blinkrates)-1; + j = nitems(blinkrates)-1; break; case IWI_LED_TX: /* read current transmission rate from adapter */ txrate = CSR_READ_4(sc, IWI_CSR_CURRENT_TX_RATE); if (blinkrates[sc->sc_txrix].rate != txrate) { - for (j = 0; j < N(blinkrates)-1; j++) + for (j = 0; j < nitems(blinkrates)-1; j++) if (blinkrates[j].rate == txrate) break; sc->sc_txrix = j; @@ -3460,7 +3459,7 @@ iwi_led_event(struct iwi_softc *sc, int event) break; case IWI_LED_RX: if (blinkrates[sc->sc_rxrix].rate != sc->sc_rxrate) { - for (j = 0; j < N(blinkrates)-1; j++) + for (j = 0; j < nitems(blinkrates)-1; j++) if (blinkrates[j].rate == sc->sc_rxrate) break; sc->sc_rxrix = j; @@ -3471,7 +3470,6 @@ iwi_led_event(struct iwi_softc *sc, int event) /* XXX beware of overflow */ iwi_led_blink(sc, (blinkrates[j].timeOn * hz) / 1000, (blinkrates[j].timeOff * hz) / 1000); -#undef N } static int diff --git a/sys/dev/iwm/if_iwm.c b/sys/dev/iwm/if_iwm.c index 46abd16ed6132..cd2ccd2814f3a 100644 --- a/sys/dev/iwm/if_iwm.c +++ b/sys/dev/iwm/if_iwm.c @@ -884,7 +884,9 @@ iwm_reset_rx_ring(struct iwm_softc *sc, struct iwm_rx_ring *ring) (void) iwm_pcie_rx_stop(sc); iwm_nic_unlock(sc); } + /* Reset the ring state */ ring->cur = 0; + memset(sc->rxq.stat, 0, sizeof(*sc->rxq.stat)); } static void diff --git a/sys/dev/iwn/if_iwn.c b/sys/dev/iwn/if_iwn.c index ecaab2dea0fa3..c1ed6ab004811 100644 --- a/sys/dev/iwn/if_iwn.c +++ b/sys/dev/iwn/if_iwn.c @@ -2716,7 +2716,6 @@ static uint32_t iwn_rate_to_plcp(struct iwn_softc *sc, struct ieee80211_node *ni, uint8_t rate) { -#define RV(v) ((v) & IEEE80211_RATE_VAL) struct ieee80211com *ic = ni->ni_ic; uint32_t plcp = 0; int ridx; @@ -2731,7 +2730,7 @@ iwn_rate_to_plcp(struct iwn_softc *sc, struct ieee80211_node *ni, * MCS 0 -> MCS 31, then set the "I'm an MCS rate!" * flag. */ - plcp = RV(rate) | IWN_RFLAG_MCS; + plcp = IEEE80211_RV(rate) | IWN_RFLAG_MCS; /* * XXX the following should only occur if both @@ -2792,7 +2791,6 @@ iwn_rate_to_plcp(struct iwn_softc *sc, struct ieee80211_node *ni, plcp); return (htole32(plcp)); -#undef RV } static void @@ -4370,7 +4368,6 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[ac]; if (!IEEE80211_AMPDU_RUNNING(tap)) { - m_freem(m); return EINVAL; } @@ -4422,7 +4419,6 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) /* Retrieve key for TX. */ k = ieee80211_crypto_encap(ni, m); if (k == NULL) { - m_freem(m); return ENOBUFS; } /* 802.11 header may have moved. */ @@ -4553,7 +4549,6 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) if (error != EFBIG) { device_printf(sc->sc_dev, "%s: can't map mbuf (error %d)\n", __func__, error); - m_freem(m); return error; } /* Too many DMA segments, linearize mbuf. */ @@ -4561,7 +4556,6 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) if (m1 == NULL) { device_printf(sc->sc_dev, "%s: could not defrag mbuf\n", __func__); - m_freem(m); return ENOBUFS; } m = m1; @@ -4571,7 +4565,6 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) if (error != 0) { device_printf(sc->sc_dev, "%s: can't map mbuf (error %d)\n", __func__, error); - m_freem(m); return error; } } @@ -4757,7 +4750,6 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m, if (error != EFBIG) { device_printf(sc->sc_dev, "%s: can't map mbuf (error %d)\n", __func__, error); - m_freem(m); return error; } /* Too many DMA segments, linearize mbuf. */ @@ -4765,7 +4757,6 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m, if (m1 == NULL) { device_printf(sc->sc_dev, "%s: could not defrag mbuf\n", __func__); - m_freem(m); return ENOBUFS; } m = m1; @@ -4775,7 +4766,6 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m, if (error != 0) { device_printf(sc->sc_dev, "%s: can't map mbuf (error %d)\n", __func__, error); - m_freem(m); return error; } } @@ -4871,6 +4861,9 @@ iwn_xmit_task(void *arg0, int pending) IWN_UNLOCK(sc); } +/* + * raw frame xmit - free node/reference if failed. + */ static int iwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) @@ -4933,6 +4926,9 @@ iwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, return error; } +/* + * transmit - don't free mbuf if failed; don't free node ref if failed. + */ static int iwn_transmit(struct ieee80211com *ic, struct mbuf *m) { @@ -4940,6 +4936,8 @@ iwn_transmit(struct ieee80211com *ic, struct mbuf *m) struct ieee80211_node *ni; int error; + ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; + IWN_LOCK(sc); if ((sc->sc_flags & IWN_FLAG_RUNNING) == 0 || sc->sc_beacon_wait) { IWN_UNLOCK(sc); @@ -4951,11 +4949,9 @@ iwn_transmit(struct ieee80211com *ic, struct mbuf *m) return (ENOBUFS); } - ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; error = iwn_tx_data(sc, m, ni); if (error) { if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); - ieee80211_free_node(ni); } else sc->sc_tx_timer = 5; IWN_UNLOCK(sc); @@ -5179,7 +5175,6 @@ iwn5000_add_node(struct iwn_softc *sc, struct iwn_node_info *node, int async) static int iwn_set_link_quality(struct iwn_softc *sc, struct ieee80211_node *ni) { -#define RV(v) ((v) & IEEE80211_RATE_VAL) struct iwn_node *wn = (void *)ni; struct ieee80211_rateset *rs; struct iwn_cmd_link_quality linkq; @@ -5238,7 +5233,7 @@ iwn_set_link_quality(struct iwn_softc *sc, struct ieee80211_node *ni) if (is_11n) rate = IEEE80211_RATE_MCS | rs->rs_rates[txrate]; else - rate = RV(rs->rs_rates[txrate]); + rate = IEEE80211_RV(rs->rs_rates[txrate]); /* Do rate -> PLCP config mapping */ plcp = iwn_rate_to_plcp(sc, ni, rate); @@ -5263,7 +5258,7 @@ iwn_set_link_quality(struct iwn_softc *sc, struct ieee80211_node *ni) * entry, we're already pointing at it. */ if ((le32toh(plcp) & IWN_RFLAG_MCS) && - RV(le32toh(plcp)) > 7) + IEEE80211_RV(le32toh(plcp)) > 7) linkq.mimo = i + 1; /* Next retry at immediate lower bit-rate. */ @@ -5283,7 +5278,6 @@ iwn_set_link_quality(struct iwn_softc *sc, struct ieee80211_node *ni) DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); return iwn_cmd(sc, IWN_CMD_LINK_QUALITY, &linkq, sizeof linkq, 1); -#undef RV } /* @@ -5350,6 +5344,8 @@ iwn_updateedca(struct ieee80211com *ic) memset(&cmd, 0, sizeof cmd); cmd.flags = htole32(IWN_EDCA_UPDATE); + + IEEE80211_LOCK(ic); for (aci = 0; aci < WME_NUM_AC; aci++) { const struct wmeParams *ac = &ic->ic_wme.wme_chanParams.cap_wmeParams[aci]; @@ -5360,10 +5356,10 @@ iwn_updateedca(struct ieee80211com *ic) htole16(IEEE80211_TXOP_TO_US(ac->wmep_txopLimit)); } IEEE80211_UNLOCK(ic); + IWN_LOCK(sc); (void)iwn_cmd(sc, IWN_CMD_EDCA_PARAMS, &cmd, sizeof cmd, 1); IWN_UNLOCK(sc); - IEEE80211_LOCK(ic); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); diff --git a/sys/dev/malo/if_malo.c b/sys/dev/malo/if_malo.c index 2790fdc8400c9..251ddc60d3273 100644 --- a/sys/dev/malo/if_malo.c +++ b/sys/dev/malo/if_malo.c @@ -901,22 +901,18 @@ malo_printtxbuf(const struct malo_txbuf *bf, u_int qnum, u_int ix) static __inline void malo_updatetxrate(struct ieee80211_node *ni, int rix) { -#define N(x) (sizeof(x)/sizeof(x[0])) static const int ieeerates[] = { 2, 4, 11, 22, 44, 12, 18, 24, 36, 48, 96, 108 }; - if (rix < N(ieeerates)) + if (rix < nitems(ieeerates)) ni->ni_txrate = ieeerates[rix]; -#undef N } static int malo_fix2rate(int fix_rate) { -#define N(x) (sizeof(x)/sizeof(x[0])) static const int rates[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 96, 108 }; - return (fix_rate < N(rates) ? rates[fix_rate] : 0); -#undef N + return (fix_rate < nitems(rates) ? rates[fix_rate] : 0); } /* idiomatic shorthands: MS = mask+shift, SM = shift+mask */ @@ -1034,8 +1030,6 @@ static int malo_tx_start(struct malo_softc *sc, struct ieee80211_node *ni, struct malo_txbuf *bf, struct mbuf *m0) { -#define IEEE80211_DIR_DSTODS(wh) \ - ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) #define IS_DATA_FRAME(wh) \ ((wh->i_fc[0] & (IEEE80211_FC0_TYPE_MASK)) == IEEE80211_FC0_TYPE_DATA) int error, ismcast, iswep; @@ -1054,7 +1048,7 @@ malo_tx_start(struct malo_softc *sc, struct ieee80211_node *ni, copyhdrlen = hdrlen = ieee80211_anyhdrsize(wh); pktlen = m0->m_pkthdr.len; if (IEEE80211_QOS_HAS_SEQ(wh)) { - if (IEEE80211_DIR_DSTODS(wh)) { + if (IEEE80211_IS_DSTODS(wh)) { qos = *(uint16_t *) (((struct ieee80211_qosframe_addr4 *) wh)->i_qos); copyhdrlen -= sizeof(qos); @@ -1210,7 +1204,6 @@ malo_tx_start(struct malo_softc *sc, struct ieee80211_node *ni, sc->malo_timer = 5; MALO_TXQ_UNLOCK(txq); return 0; -#undef IEEE80211_DIR_DSTODS } static int @@ -1960,9 +1953,6 @@ malo_set_channel(struct ieee80211com *ic) static void malo_rx_proc(void *arg, int npending) { -#define IEEE80211_DIR_DSTODS(wh) \ - ((((const struct ieee80211_frame *)wh)->i_fc[1] & \ - IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) struct malo_softc *sc = arg; struct ieee80211com *ic = &sc->malo_ic; struct malo_rxbuf *bf; @@ -2080,7 +2070,7 @@ malo_rx_proc(void *arg, int npending) /* XXX special case so we can memcpy after m_devget? */ ovbcopy(data + sizeof(uint16_t), wh, hdrlen); if (IEEE80211_QOS_HAS_SEQ(wh)) { - if (IEEE80211_DIR_DSTODS(wh)) { + if (IEEE80211_IS_DSTODS(wh)) { wh4 = mtod(m, struct ieee80211_qosframe_addr4*); *(uint16_t *)wh4->i_qos = ds->qosctrl; @@ -2119,7 +2109,6 @@ rx_next: if (mbufq_first(&sc->malo_snd) != NULL) malo_start(sc); -#undef IEEE80211_DIR_DSTODS } /* diff --git a/sys/dev/malo/if_malo_pci.c b/sys/dev/malo/if_malo_pci.c index 26324c09f0916..01b519e849884 100644 --- a/sys/dev/malo/if_malo_pci.c +++ b/sys/dev/malo/if_malo_pci.c @@ -131,7 +131,6 @@ static int malo_pci_detach(device_t); static int malo_pci_probe(device_t dev) { -#define N(a) (sizeof(a) / sizeof((a)[0])) struct malo_product *mp; uint16_t vendor, devid; int i; @@ -140,7 +139,7 @@ malo_pci_probe(device_t dev) devid = pci_get_device(dev); mp = malo_products; - for (i = 0; i < N(malo_products); i++, mp++) { + for (i = 0; i < nitems(malo_products); i++, mp++) { if (vendor == mp->mp_vendorid && devid == mp->mp_deviceid) { device_set_desc(dev, mp->mp_name); return (BUS_PROBE_DEFAULT); @@ -148,7 +147,6 @@ malo_pci_probe(device_t dev) } return (ENXIO); -#undef N } static int diff --git a/sys/dev/mwl/if_mwl.c b/sys/dev/mwl/if_mwl.c index be80e465cd39c..463b5c9c15867 100644 --- a/sys/dev/mwl/if_mwl.c +++ b/sys/dev/mwl/if_mwl.c @@ -70,6 +70,7 @@ __FBSDID("$FreeBSD$"); #include <net/bpf.h> #include <net80211/ieee80211_var.h> +#include <net80211/ieee80211_input.h> #include <net80211/ieee80211_regdomain.h> #ifdef INET @@ -1707,18 +1708,6 @@ mwl_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, #undef GRPXMIT } -/* unaligned little endian access */ -#define LE_READ_2(p) \ - ((uint16_t) \ - ((((const uint8_t *)(p))[0] ) | \ - (((const uint8_t *)(p))[1] << 8))) -#define LE_READ_4(p) \ - ((uint32_t) \ - ((((const uint8_t *)(p))[0] ) | \ - (((const uint8_t *)(p))[1] << 8) | \ - (((const uint8_t *)(p))[2] << 16) | \ - (((const uint8_t *)(p))[3] << 24))) - /* * Set the multicast filter contents into the hardware. * XXX f/w has no support; just defer to the os. @@ -1845,10 +1834,10 @@ mwl_beacon_setup(struct ieee80211vap *vap) { struct mwl_hal_vap *hvap = MWL_VAP(vap)->mv_hvap; struct ieee80211_node *ni = vap->iv_bss; - struct ieee80211_beacon_offsets bo; + struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; struct mbuf *m; - m = ieee80211_beacon_alloc(ni, &bo); + m = ieee80211_beacon_alloc(ni, bo); if (m == NULL) return ENOBUFS; mwl_hal_setbeacon(hvap, mtod(m, const void *), m->m_len); @@ -2619,8 +2608,6 @@ cvtrssi(uint8_t ssi) static void mwl_rx_proc(void *arg, int npending) { -#define IEEE80211_DIR_DSTODS(wh) \ - ((((const struct ieee80211_frame *)wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) struct mwl_softc *sc = arg; struct ieee80211com *ic = &sc->sc_ic; struct mwl_rxbuf *bf; @@ -2775,7 +2762,7 @@ mwl_rx_proc(void *arg, int npending) /* XXX special case so we can memcpy after m_devget? */ ovbcopy(data + sizeof(uint16_t), wh, hdrlen); if (IEEE80211_QOS_HAS_SEQ(wh)) { - if (IEEE80211_DIR_DSTODS(wh)) { + if (IEEE80211_IS_DSTODS(wh)) { wh4 = mtod(m, struct ieee80211_qosframe_addr4*); *(uint16_t *)wh4->i_qos = ds->QosCtrl; @@ -2845,7 +2832,6 @@ rx_stop: mwl_hal_txstart(sc->sc_mh, 0); mwl_start(sc); } -#undef IEEE80211_DIR_DSTODS } static void @@ -2881,12 +2867,11 @@ mwl_txq_init(struct mwl_softc *sc, struct mwl_txq *txq, int qnum) static int mwl_tx_setup(struct mwl_softc *sc, int ac, int mvtype) { -#define N(a) (sizeof(a)/sizeof(a[0])) struct mwl_txq *txq; - if (ac >= N(sc->sc_ac2q)) { + if (ac >= nitems(sc->sc_ac2q)) { device_printf(sc->sc_dev, "AC %u out of range, max %zu!\n", - ac, N(sc->sc_ac2q)); + ac, nitems(sc->sc_ac2q)); return 0; } if (mvtype >= MWL_NUM_TX_QUEUES) { @@ -2898,7 +2883,6 @@ mwl_tx_setup(struct mwl_softc *sc, int ac, int mvtype) mwl_txq_init(sc, txq, mvtype); sc->sc_ac2q[ac] = txq; return 1; -#undef N } /* @@ -3091,8 +3075,6 @@ static int mwl_tx_start(struct mwl_softc *sc, struct ieee80211_node *ni, struct mwl_txbuf *bf, struct mbuf *m0) { -#define IEEE80211_DIR_DSTODS(wh) \ - ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = ni->ni_vap; int error, iswep, ismcast; @@ -3114,7 +3096,7 @@ mwl_tx_start(struct mwl_softc *sc, struct ieee80211_node *ni, struct mwl_txbuf * copyhdrlen = hdrlen; pktlen = m0->m_pkthdr.len; if (IEEE80211_QOS_HAS_SEQ(wh)) { - if (IEEE80211_DIR_DSTODS(wh)) { + if (IEEE80211_IS_DSTODS(wh)) { qos = *(uint16_t *) (((struct ieee80211_qosframe_addr4 *) wh)->i_qos); copyhdrlen -= sizeof(qos); @@ -3331,17 +3313,14 @@ mwl_tx_start(struct mwl_softc *sc, struct ieee80211_node *ni, struct mwl_txbuf * MWL_TXQ_UNLOCK(txq); return 0; -#undef IEEE80211_DIR_DSTODS } static __inline int mwl_cvtlegacyrix(int rix) { -#define N(x) (sizeof(x)/sizeof(x[0])) static const int ieeerates[] = { 2, 4, 11, 22, 44, 12, 18, 24, 36, 48, 72, 96, 108 }; - return (rix < N(ieeerates) ? ieeerates[rix] : 0); -#undef N + return (rix < nitems(ieeerates) ? ieeerates[rix] : 0); } /* diff --git a/sys/dev/nxge/if_nxge.c b/sys/dev/nxge/if_nxge.c index 90871aec9e88e..af95e8bc2f87d 100644 --- a/sys/dev/nxge/if_nxge.c +++ b/sys/dev/nxge/if_nxge.c @@ -1457,7 +1457,7 @@ xge_ioctl_stats(xge_lldev_t *lldev, struct ifreq *ifreqp) case XGE_READ_VERSION: info = xge_os_malloc(NULL, XGE_BUFFER_SIZE); - if(version != NULL) { + if(info != NULL) { strcpy(info, XGE_DRIVER_VERSION); if(copyout(info, ifreqp->ifr_data, XGE_BUFFER_SIZE) == 0) retValue = 0; diff --git a/sys/dev/nxge/xgehal/xgehal-fifo.c b/sys/dev/nxge/xgehal/xgehal-fifo.c index 303afafbf7ce6..78c0923dee0f4 100644 --- a/sys/dev/nxge/xgehal/xgehal-fifo.c +++ b/sys/dev/nxge/xgehal/xgehal-fifo.c @@ -464,7 +464,7 @@ __hal_fifo_hw_initialize(xge_hal_device_h devh) if (!hldev->config.fifo.queue[i].configured || !hldev->config.fifo.queue[i].intr_vector || - !hldev->config.intr_mode != XGE_HAL_INTR_MODE_MSIX) + hldev->config.intr_mode != XGE_HAL_INTR_MODE_MSIX) continue; /* find channel */ diff --git a/sys/dev/nxge/xgehal/xgehal-ring.c b/sys/dev/nxge/xgehal/xgehal-ring.c index 444e10c4f06d3..061b773842138 100644 --- a/sys/dev/nxge/xgehal/xgehal-ring.c +++ b/sys/dev/nxge/xgehal/xgehal-ring.c @@ -609,7 +609,7 @@ __hal_ring_hw_initialize(xge_hal_device_h devh) if (!hldev->config.ring.queue[i].configured || !hldev->config.ring.queue[i].intr_vector || - !hldev->config.intr_mode != XGE_HAL_INTR_MODE_MSIX) + hldev->config.intr_mode != XGE_HAL_INTR_MODE_MSIX) continue; /* find channel */ diff --git a/sys/dev/otus/if_otus.c b/sys/dev/otus/if_otus.c new file mode 100644 index 0000000000000..e60157adda9d7 --- /dev/null +++ b/sys/dev/otus/if_otus.c @@ -0,0 +1,3156 @@ +/* $OpenBSD: if_otus.c,v 1.46 2015/03/14 03:38:49 jsg Exp $ */ + +/*- + * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr> + * Copyright (c) 2015 Adrian Chadd <adrian@FreeBSD.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Driver for Atheros AR9001U chipset. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include <sys/param.h> +#include <sys/endian.h> +#include <sys/sockio.h> +#include <sys/mbuf.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/bus.h> +#include <sys/rman.h> +#include <sys/firmware.h> +#include <sys/module.h> +#include <sys/taskqueue.h> + +#include <machine/bus.h> +#include <machine/resource.h> + +#include <net/bpf.h> +#include <net/if.h> +#include <net/if_var.h> +#include <net/if_arp.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_types.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/if_ether.h> +#include <netinet/ip.h> + +#include <net80211/ieee80211_var.h> +#include <net80211/ieee80211_regdomain.h> +#include <net80211/ieee80211_radiotap.h> +#include <net80211/ieee80211_ratectl.h> +#include <net80211/ieee80211_input.h> +#ifdef IEEE80211_SUPPORT_SUPERG +#include <net80211/ieee80211_superg.h> +#endif + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> +#include "usbdevs.h" + +#define USB_DEBUG_VAR otus_debug +#include <dev/usb/usb_debug.h> + +#include "if_otusreg.h" + +static int otus_debug = 0; +static SYSCTL_NODE(_hw_usb, OID_AUTO, otus, CTLFLAG_RW, 0, "USB otus"); +SYSCTL_INT(_hw_usb_otus, OID_AUTO, debug, CTLFLAG_RWTUN, &otus_debug, 0, + "Debug level"); +#define OTUS_DEBUG_XMIT 0x00000001 +#define OTUS_DEBUG_RECV 0x00000002 +#define OTUS_DEBUG_TXDONE 0x00000004 +#define OTUS_DEBUG_RXDONE 0x00000008 +#define OTUS_DEBUG_CMD 0x00000010 +#define OTUS_DEBUG_CMDDONE 0x00000020 +#define OTUS_DEBUG_RESET 0x00000040 +#define OTUS_DEBUG_STATE 0x00000080 +#define OTUS_DEBUG_CMDNOTIFY 0x00000100 +#define OTUS_DEBUG_REGIO 0x00000200 +#define OTUS_DEBUG_IRQ 0x00000400 +#define OTUS_DEBUG_TXCOMP 0x00000800 +#define OTUS_DEBUG_ANY 0xffffffff + +#define OTUS_DPRINTF(sc, dm, ...) \ + do { \ + if ((dm == OTUS_DEBUG_ANY) || (dm & otus_debug)) \ + device_printf(sc->sc_dev, __VA_ARGS__); \ + } while (0) + +#define OTUS_DEV(v, p) { USB_VPI(v, p, 0) } +static const STRUCT_USB_HOST_ID otus_devs[] = { + OTUS_DEV(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_WN7512), + OTUS_DEV(USB_VENDOR_ATHEROS2, USB_PRODUCT_ATHEROS2_3CRUSBN275), + OTUS_DEV(USB_VENDOR_ATHEROS2, USB_PRODUCT_ATHEROS2_TG121N), + OTUS_DEV(USB_VENDOR_ATHEROS2, USB_PRODUCT_ATHEROS2_AR9170), + OTUS_DEV(USB_VENDOR_ATHEROS2, USB_PRODUCT_ATHEROS2_WN612), + OTUS_DEV(USB_VENDOR_ATHEROS2, USB_PRODUCT_ATHEROS2_WN821NV2), + OTUS_DEV(USB_VENDOR_AVM, USB_PRODUCT_AVM_FRITZWLAN), + OTUS_DEV(USB_VENDOR_CACE, USB_PRODUCT_CACE_AIRPCAPNX), + OTUS_DEV(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_DWA130D1), + OTUS_DEV(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_DWA160A1), + OTUS_DEV(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_DWA160A2), + OTUS_DEV(USB_VENDOR_IODATA, USB_PRODUCT_IODATA_WNGDNUS2), + OTUS_DEV(USB_VENDOR_NEC, USB_PRODUCT_NEC_WL300NUG), + OTUS_DEV(USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_WN111V2), + OTUS_DEV(USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_WNA1000), + OTUS_DEV(USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_WNDA3100), + OTUS_DEV(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GW_US300), + OTUS_DEV(USB_VENDOR_WISTRONNEWEB, USB_PRODUCT_WISTRONNEWEB_O8494), + OTUS_DEV(USB_VENDOR_WISTRONNEWEB, USB_PRODUCT_WISTRONNEWEB_WNC0600), + OTUS_DEV(USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_UB81), + OTUS_DEV(USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_UB82), + OTUS_DEV(USB_VENDOR_ZYDAS, USB_PRODUCT_ZYDAS_ZD1221), + OTUS_DEV(USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_NWD271N), +}; + +static device_probe_t otus_match; +static device_attach_t otus_attach; +static device_detach_t otus_detach; + +static int otus_attachhook(struct otus_softc *); +void otus_get_chanlist(struct otus_softc *); +int otus_load_firmware(struct otus_softc *, const char *, + uint32_t); +int otus_open_pipes(struct otus_softc *); +void otus_close_pipes(struct otus_softc *); + +static int otus_alloc_tx_cmd_list(struct otus_softc *); +static void otus_free_tx_cmd_list(struct otus_softc *); + +static int otus_alloc_rx_list(struct otus_softc *); +static void otus_free_rx_list(struct otus_softc *); +static int otus_alloc_tx_list(struct otus_softc *); +static void otus_free_tx_list(struct otus_softc *); +static void otus_free_list(struct otus_softc *, struct otus_data [], int); +static struct otus_data *_otus_getbuf(struct otus_softc *); +static struct otus_data *otus_getbuf(struct otus_softc *); +static void otus_freebuf(struct otus_softc *, struct otus_data *); + +static struct otus_tx_cmd *_otus_get_txcmd(struct otus_softc *); +static struct otus_tx_cmd *otus_get_txcmd(struct otus_softc *); +static void otus_free_txcmd(struct otus_softc *, struct otus_tx_cmd *); + +void otus_next_scan(void *, int); +static void otus_tx_task(void *, int pending); +static void otus_wme_update_task(void *, int pending); +void otus_do_async(struct otus_softc *, + void (*)(struct otus_softc *, void *), void *, int); +int otus_newstate(struct ieee80211vap *, enum ieee80211_state, + int); +int otus_cmd(struct otus_softc *, uint8_t, const void *, int, + void *, int); +void otus_write(struct otus_softc *, uint32_t, uint32_t); +int otus_write_barrier(struct otus_softc *); +struct ieee80211_node *otus_node_alloc(struct ieee80211com *); +int otus_media_change(struct ifnet *); +int otus_read_eeprom(struct otus_softc *); +void otus_newassoc(struct ieee80211_node *, int); +void otus_cmd_rxeof(struct otus_softc *, uint8_t *, int); +void otus_sub_rxeof(struct otus_softc *, uint8_t *, int, + struct mbufq *); +static int otus_tx(struct otus_softc *, struct ieee80211_node *, + struct mbuf *, struct otus_data *); +int otus_ioctl(struct ifnet *, u_long, caddr_t); +int otus_set_multi(struct otus_softc *); +static void otus_updateedca(struct otus_softc *sc); +static void otus_updateslot(struct otus_softc *sc); +int otus_init_mac(struct otus_softc *); +uint32_t otus_phy_get_def(struct otus_softc *, uint32_t); +int otus_set_board_values(struct otus_softc *, + struct ieee80211_channel *); +int otus_program_phy(struct otus_softc *, + struct ieee80211_channel *); +int otus_set_rf_bank4(struct otus_softc *, + struct ieee80211_channel *); +void otus_get_delta_slope(uint32_t, uint32_t *, uint32_t *); +static int otus_set_chan(struct otus_softc *, struct ieee80211_channel *, + int); +int otus_set_key(struct ieee80211com *, struct ieee80211_node *, + struct ieee80211_key *); +void otus_set_key_cb(struct otus_softc *, void *); +void otus_delete_key(struct ieee80211com *, struct ieee80211_node *, + struct ieee80211_key *); +void otus_delete_key_cb(struct otus_softc *, void *); +void otus_calibrate_to(void *, int); +int otus_set_bssid(struct otus_softc *, const uint8_t *); +int otus_set_macaddr(struct otus_softc *, const uint8_t *); +void otus_led_newstate_type1(struct otus_softc *); +void otus_led_newstate_type2(struct otus_softc *); +void otus_led_newstate_type3(struct otus_softc *); +int otus_init(struct otus_softc *sc); +void otus_stop(struct otus_softc *sc); + +static device_method_t otus_methods[] = { + DEVMETHOD(device_probe, otus_match), + DEVMETHOD(device_attach, otus_attach), + DEVMETHOD(device_detach, otus_detach), + + DEVMETHOD_END +}; + +static driver_t otus_driver = { + .name = "otus", + .methods = otus_methods, + .size = sizeof(struct otus_softc) +}; + +static devclass_t otus_devclass; + +DRIVER_MODULE(otus, uhub, otus_driver, otus_devclass, NULL, 0); +MODULE_DEPEND(otus, wlan, 1, 1, 1); +MODULE_DEPEND(otus, usb, 1, 1, 1); +MODULE_DEPEND(otus, firmware, 1, 1, 1); +MODULE_VERSION(otus, 1); + +static usb_callback_t otus_bulk_tx_callback; +static usb_callback_t otus_bulk_rx_callback; +static usb_callback_t otus_bulk_irq_callback; +static usb_callback_t otus_bulk_cmd_callback; + +static const struct usb_config otus_config[OTUS_N_XFER] = { + [OTUS_BULK_TX] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = 0x200, + .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, + .callback = otus_bulk_tx_callback, + .timeout = 5000, /* ms */ + }, + [OTUS_BULK_RX] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_IN, + .bufsize = OTUS_RXBUFSZ, + .flags = { .ext_buffer = 1, .pipe_bof = 1,.short_xfer_ok = 1,}, + .callback = otus_bulk_rx_callback, + }, + [OTUS_BULK_IRQ] = { + .type = UE_INTERRUPT, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_IN, + .bufsize = OTUS_MAX_CTRLSZ, + .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, + .callback = otus_bulk_irq_callback, + }, + [OTUS_BULK_CMD] = { + .type = UE_INTERRUPT, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = OTUS_MAX_CTRLSZ, + .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, + .callback = otus_bulk_cmd_callback, + .timeout = 5000, /* ms */ + }, +}; + +static int +otus_match(device_t self) +{ + struct usb_attach_arg *uaa = device_get_ivars(self); + + if (uaa->usb_mode != USB_MODE_HOST || + uaa->info.bIfaceIndex != 0 || + uaa->info.bConfigIndex != 0) + return (ENXIO); + + return (usbd_lookup_id_by_uaa(otus_devs, sizeof(otus_devs), uaa)); +} + +static int +otus_attach(device_t self) +{ + struct usb_attach_arg *uaa = device_get_ivars(self); + struct otus_softc *sc = device_get_softc(self); + int error; + uint8_t iface_index; + + device_set_usb_desc(self); + sc->sc_udev = uaa->device; + sc->sc_dev = self; + + mtx_init(&sc->sc_mtx, device_get_nameunit(self), MTX_NETWORK_LOCK, + MTX_DEF); + + TIMEOUT_TASK_INIT(taskqueue_thread, &sc->scan_to, 0, otus_next_scan, sc); + TIMEOUT_TASK_INIT(taskqueue_thread, &sc->calib_to, 0, otus_calibrate_to, sc); + TASK_INIT(&sc->tx_task, 0, otus_tx_task, sc); + TASK_INIT(&sc->wme_update_task, 0, otus_wme_update_task, sc); + mbufq_init(&sc->sc_snd, ifqmaxlen); + + iface_index = 0; + error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, + otus_config, OTUS_N_XFER, sc, &sc->sc_mtx); + if (error) { + device_printf(sc->sc_dev, + "could not allocate USB transfers, err=%s\n", + usbd_errstr(error)); + goto fail_usb; + } + + if ((error = otus_open_pipes(sc)) != 0) { + device_printf(sc->sc_dev, "%s: could not open pipes\n", + __func__); + goto fail; + } + + /* XXX check return status; fail out if appropriate */ + if (otus_attachhook(sc) != 0) + goto fail; + + return (0); + +fail: + otus_close_pipes(sc); +fail_usb: + mtx_destroy(&sc->sc_mtx); + return (ENXIO); +} + +static int +otus_detach(device_t self) +{ + struct otus_softc *sc = device_get_softc(self); + struct ieee80211com *ic = &sc->sc_ic; + + otus_stop(sc); + + usbd_transfer_unsetup(sc->sc_xfer, OTUS_N_XFER); + + taskqueue_drain_timeout(taskqueue_thread, &sc->scan_to); + taskqueue_drain_timeout(taskqueue_thread, &sc->calib_to); + taskqueue_drain(taskqueue_thread, &sc->tx_task); + taskqueue_drain(taskqueue_thread, &sc->wme_update_task); + + otus_close_pipes(sc); +#if 0 + /* Wait for all queued asynchronous commands to complete. */ + usb_rem_wait_task(sc->sc_udev, &sc->sc_task); + + usbd_ref_wait(sc->sc_udev); +#endif + + ieee80211_ifdetach(ic); + mtx_destroy(&sc->sc_mtx); + return 0; +} + +static void +otus_delay_ms(struct otus_softc *sc, int ms) +{ + + DELAY(1000 * ms); +} + +static struct ieee80211vap * +otus_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, + enum ieee80211_opmode opmode, int flags, + const uint8_t bssid[IEEE80211_ADDR_LEN], + const uint8_t mac[IEEE80211_ADDR_LEN]) +{ + struct otus_vap *uvp; + struct ieee80211vap *vap; + + if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ + return (NULL); + + uvp = malloc(sizeof(struct otus_vap), M_80211_VAP, M_WAITOK | M_ZERO); + vap = &uvp->vap; + + if (ieee80211_vap_setup(ic, vap, name, unit, opmode, + flags, bssid) != 0) { + /* out of memory */ + free(uvp, M_80211_VAP); + return (NULL); + } + + /* override state transition machine */ + uvp->newstate = vap->iv_newstate; + vap->iv_newstate = otus_newstate; + + /* XXX TODO: double-check */ + vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_16; + vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_32K; + + ieee80211_ratectl_init(vap); + + /* complete setup */ + ieee80211_vap_attach(vap, ieee80211_media_change, + ieee80211_media_status, mac); + ic->ic_opmode = opmode; + + return (vap); +} + +static void +otus_vap_delete(struct ieee80211vap *vap) +{ + struct otus_vap *uvp = OTUS_VAP(vap); + + ieee80211_ratectl_deinit(vap); + ieee80211_vap_detach(vap); + free(uvp, M_80211_VAP); +} + +static void +otus_parent(struct ieee80211com *ic) +{ + struct otus_softc *sc = ic->ic_softc; + int startall = 0; + + if (ic->ic_nrunning > 0) { + if (!sc->sc_running) { + otus_init(sc); + startall = 1; + } else { + (void) otus_set_multi(sc); + } + } else if (sc->sc_running) + otus_stop(sc); + + if (startall) + ieee80211_start_all(ic); +} + +static void +otus_drain_mbufq(struct otus_softc *sc) +{ + struct mbuf *m; + struct ieee80211_node *ni; + + OTUS_LOCK_ASSERT(sc); + while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; + m->m_pkthdr.rcvif = NULL; + ieee80211_free_node(ni); + m_freem(m); + } +} + +static void +otus_tx_start(struct otus_softc *sc) +{ + + taskqueue_enqueue(taskqueue_thread, &sc->tx_task); +} + +static int +otus_transmit(struct ieee80211com *ic, struct mbuf *m) +{ + struct otus_softc *sc = ic->ic_softc; + int error; + + OTUS_LOCK(sc); + if (! sc->sc_running) { + OTUS_UNLOCK(sc); + return (ENXIO); + } + + /* XXX TODO: handle fragments */ + error = mbufq_enqueue(&sc->sc_snd, m); + if (error) { + OTUS_DPRINTF(sc, OTUS_DEBUG_XMIT, + "%s: mbufq_enqueue failed: %d\n", + __func__, + error); + OTUS_UNLOCK(sc); + return (error); + } + OTUS_UNLOCK(sc); + + /* Kick TX */ + otus_tx_start(sc); + + return (0); +} + +static void +_otus_start(struct otus_softc *sc) +{ + struct ieee80211_node *ni; + struct otus_data *bf; + struct mbuf *m; + + OTUS_LOCK_ASSERT(sc); + + while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + bf = otus_getbuf(sc); + if (bf == NULL) { + OTUS_DPRINTF(sc, OTUS_DEBUG_XMIT, + "%s: failed to get buffer\n", __func__); + mbufq_prepend(&sc->sc_snd, m); + break; + } + + ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; + m->m_pkthdr.rcvif = NULL; + + if (otus_tx(sc, ni, m, bf) != 0) { + OTUS_DPRINTF(sc, OTUS_DEBUG_XMIT, + "%s: failed to transmit\n", __func__); + if_inc_counter(ni->ni_vap->iv_ifp, + IFCOUNTER_OERRORS, 1); + otus_freebuf(sc, bf); + ieee80211_free_node(ni); + m_freem(m); + break; + } + } +} + +static void +otus_tx_task(void *arg, int pending) +{ + struct otus_softc *sc = arg; + + OTUS_LOCK(sc); + _otus_start(sc); + OTUS_UNLOCK(sc); +} + +static int +otus_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, + const struct ieee80211_bpf_params *params) +{ + struct ieee80211com *ic= ni->ni_ic; + struct otus_softc *sc = ic->ic_softc; + struct otus_data *bf = NULL; + int error = 0; + + /* Don't transmit if we're not running */ + OTUS_LOCK(sc); + if (! sc->sc_running) { + error = ENETDOWN; + goto error; + } + + bf = otus_getbuf(sc); + if (bf == NULL) { + error = ENOBUFS; + goto error; + } + + /* + * XXX TODO: support TX bpf params + */ + if (otus_tx(sc, ni, m, bf) != 0) { + error = EIO; + goto error; + } + + OTUS_UNLOCK(sc); + return (0); +error: + if (bf) + otus_freebuf(sc, bf); + OTUS_UNLOCK(sc); + ieee80211_free_node(ni); + m_freem(m); + return (ENXIO); +} + +static void +otus_update_chw(struct ieee80211com *ic) +{ + + printf("%s: TODO\n", __func__); +} + +static void +otus_set_channel(struct ieee80211com *ic) +{ + struct otus_softc *sc = ic->ic_softc; + OTUS_DPRINTF(sc, OTUS_DEBUG_RESET, "%s: set channel: %d\n", + __func__, + ic->ic_curchan->ic_freq); + + OTUS_LOCK(sc); + (void) otus_set_chan(sc, ic->ic_curchan, 0); + OTUS_UNLOCK(sc); +} + +static void +otus_wme_update_task(void *arg, int pending) +{ + struct otus_softc *sc = arg; + + OTUS_LOCK(sc); + /* + * XXX TODO: take temporary copy of EDCA information + * when scheduling this so we have a more time-correct view + * of things. + */ + otus_updateedca(sc); + OTUS_UNLOCK(sc); +} + +static void +otus_wme_schedule_update(struct otus_softc *sc) +{ + + taskqueue_enqueue(taskqueue_thread, &sc->wme_update_task); +} + +/* + * This is called by net80211 in RX packet context, so we + * can't sleep here. + * + * TODO: have net80211 schedule an update itself for its + * own internal taskqueue. + */ +static int +otus_wme_update(struct ieee80211com *ic) +{ + struct otus_softc *sc = ic->ic_softc; + + otus_wme_schedule_update(sc); + return (0); +} + +static int +otus_ampdu_enable(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap) +{ + + /* For now, no A-MPDU TX support in the driver */ + return (0); +} + +static void +otus_scan_start(struct ieee80211com *ic) +{ + +// printf("%s: TODO\n", __func__); +} + +static void +otus_scan_end(struct ieee80211com *ic) +{ + +// printf("%s: TODO\n", __func__); +} + +static void +otus_update_mcast(struct ieee80211com *ic) +{ + struct otus_softc *sc = ic->ic_softc; + + (void) otus_set_multi(sc); +} + +static int +otus_attachhook(struct otus_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + usb_device_request_t req; + uint32_t in, out; + int error; + uint8_t bands; + + /* Not locked */ + error = otus_load_firmware(sc, "otusfw_init", AR_FW_INIT_ADDR); + if (error != 0) { + device_printf(sc->sc_dev, "%s: could not load %s firmware\n", + __func__, "init"); + return (ENXIO); + } + + /* XXX not locked? */ + otus_delay_ms(sc, 1000); + + /* Not locked */ + error = otus_load_firmware(sc, "otusfw_main", AR_FW_MAIN_ADDR); + if (error != 0) { + device_printf(sc->sc_dev, "%s: could not load %s firmware\n", + __func__, "main"); + return (ENXIO); + } + + OTUS_LOCK(sc); + + /* Tell device that firmware transfer is complete. */ + req.bmRequestType = UT_WRITE_VENDOR_DEVICE; + req.bRequest = AR_FW_DOWNLOAD_COMPLETE; + USETW(req.wValue, 0); + USETW(req.wIndex, 0); + USETW(req.wLength, 0); + if (usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, &req, NULL, + 0, NULL, 250) != 0) { + OTUS_UNLOCK(sc); + device_printf(sc->sc_dev, + "%s: firmware initialization failed\n", + __func__); + return (ENXIO); + } + + /* Send an ECHO command to check that everything is settled. */ + in = 0xbadc0ffe; + if (otus_cmd(sc, AR_CMD_ECHO, &in, sizeof in, &out, sizeof(out)) != 0) { + OTUS_UNLOCK(sc); + device_printf(sc->sc_dev, + "%s: echo command failed\n", __func__); + return (ENXIO); + } + if (in != out) { + OTUS_UNLOCK(sc); + device_printf(sc->sc_dev, + "%s: echo reply mismatch: 0x%08x!=0x%08x\n", + __func__, in, out); + return (ENXIO); + } + + /* Read entire EEPROM. */ + if (otus_read_eeprom(sc) != 0) { + OTUS_UNLOCK(sc); + device_printf(sc->sc_dev, + "%s: could not read EEPROM\n", + __func__); + return (ENXIO); + } + + OTUS_UNLOCK(sc); + + sc->txmask = sc->eeprom.baseEepHeader.txMask; + sc->rxmask = sc->eeprom.baseEepHeader.rxMask; + sc->capflags = sc->eeprom.baseEepHeader.opCapFlags; + IEEE80211_ADDR_COPY(ic->ic_macaddr, sc->eeprom.baseEepHeader.macAddr); + sc->sc_led_newstate = otus_led_newstate_type3; /* XXX */ + + device_printf(sc->sc_dev, + "MAC/BBP AR9170, RF AR%X, MIMO %dT%dR, address %s\n", + (sc->capflags & AR5416_OPFLAGS_11A) ? + 0x9104 : ((sc->txmask == 0x5) ? 0x9102 : 0x9101), + (sc->txmask == 0x5) ? 2 : 1, (sc->rxmask == 0x5) ? 2 : 1, + ether_sprintf(ic->ic_macaddr)); + + ic->ic_softc = sc; + ic->ic_name = device_get_nameunit(sc->sc_dev); + ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ + ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ + + /* Set device capabilities. */ + ic->ic_caps = + IEEE80211_C_STA | /* station mode */ +#if 0 + IEEE80211_C_BGSCAN | /* Background scan. */ +#endif + IEEE80211_C_SHPREAMBLE | /* Short preamble supported. */ + IEEE80211_C_WME | /* WME/QoS */ + IEEE80211_C_SHSLOT | /* Short slot time supported. */ + IEEE80211_C_FF | /* Atheros fast-frames supported. */ + IEEE80211_C_WPA; /* WPA/RSN. */ + + /* XXX TODO: 11n */ + +#if 0 + if (sc->eeprom.baseEepHeader.opCapFlags & AR5416_OPFLAGS_11G) { + /* Set supported .11b and .11g rates. */ + ic->ic_sup_rates[IEEE80211_MODE_11B] = + ieee80211_std_rateset_11b; + ic->ic_sup_rates[IEEE80211_MODE_11G] = + ieee80211_std_rateset_11g; + } + if (sc->eeprom.baseEepHeader.opCapFlags & AR5416_OPFLAGS_11A) { + /* Set supported .11a rates. */ + ic->ic_sup_rates[IEEE80211_MODE_11A] = + ieee80211_std_rateset_11a; + } +#endif + +#if 0 + /* Build the list of supported channels. */ + otus_get_chanlist(sc); +#else + /* Set supported .11b and .11g rates. */ + bands = 0; + if (sc->eeprom.baseEepHeader.opCapFlags & AR5416_OPFLAGS_11G) { + setbit(&bands, IEEE80211_MODE_11B); + setbit(&bands, IEEE80211_MODE_11G); + } + if (sc->eeprom.baseEepHeader.opCapFlags & AR5416_OPFLAGS_11A) { + setbit(&bands, IEEE80211_MODE_11A); + } +#if 0 + if (sc->sc_ht) + setbit(&bands, IEEE80211_MODE_11NG); +#endif + ieee80211_init_channels(ic, NULL, &bands); +#endif + + ieee80211_ifattach(ic); + ic->ic_raw_xmit = otus_raw_xmit; + ic->ic_scan_start = otus_scan_start; + ic->ic_scan_end = otus_scan_end; + ic->ic_set_channel = otus_set_channel; + ic->ic_vap_create = otus_vap_create; + ic->ic_vap_delete = otus_vap_delete; + ic->ic_update_mcast = otus_update_mcast; + ic->ic_update_promisc = otus_update_mcast; + ic->ic_parent = otus_parent; + ic->ic_transmit = otus_transmit; + ic->ic_update_chw = otus_update_chw; + ic->ic_ampdu_enable = otus_ampdu_enable; + ic->ic_wme.wme_update = otus_wme_update; + ic->ic_newassoc = otus_newassoc; + +#ifdef notyet + ic->ic_set_key = otus_set_key; + ic->ic_delete_key = otus_delete_key; +#endif + + ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, + sizeof(sc->sc_txtap), OTUS_TX_RADIOTAP_PRESENT, + &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), + OTUS_RX_RADIOTAP_PRESENT); + + return (0); +} + +void +otus_get_chanlist(struct otus_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + uint16_t domain; + uint8_t chan; + int i; + + /* XXX regulatory domain. */ + domain = le16toh(sc->eeprom.baseEepHeader.regDmn[0]); + OTUS_DPRINTF(sc, OTUS_DEBUG_RESET, "regdomain=0x%04x\n", domain); + + if (sc->eeprom.baseEepHeader.opCapFlags & AR5416_OPFLAGS_11G) { + for (i = 0; i < 14; i++) { + chan = ar_chans[i]; + ic->ic_channels[chan].ic_freq = + ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ); + ic->ic_channels[chan].ic_flags = + IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | + IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; + } + } + if (sc->eeprom.baseEepHeader.opCapFlags & AR5416_OPFLAGS_11A) { + for (i = 14; i < nitems(ar_chans); i++) { + chan = ar_chans[i]; + ic->ic_channels[chan].ic_freq = + ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ); + ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_A; + } + } +} + +int +otus_load_firmware(struct otus_softc *sc, const char *name, uint32_t addr) +{ + usb_device_request_t req; + char *ptr; + const struct firmware *fw; + int mlen, error, size; + + error = 0; + + /* Read firmware image from the filesystem. */ + if ((fw = firmware_get(name)) == NULL) { + device_printf(sc->sc_dev, + "%s: failed loadfirmware of file %s\n", __func__, name); + return (ENXIO); + } + req.bmRequestType = UT_WRITE_VENDOR_DEVICE; + req.bRequest = AR_FW_DOWNLOAD; + USETW(req.wIndex, 0); + + OTUS_LOCK(sc); + + /* XXX const */ + ptr = __DECONST(char *, fw->data); + size = fw->datasize; + addr >>= 8; + while (size > 0) { + mlen = MIN(size, 4096); + + USETW(req.wValue, addr); + USETW(req.wLength, mlen); + if (usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, + &req, ptr, 0, NULL, 250) != 0) { + error = EIO; + break; + } + addr += mlen >> 8; + ptr += mlen; + size -= mlen; + } + + OTUS_UNLOCK(sc); + + firmware_put(fw, FIRMWARE_UNLOAD); + if (error != 0) + device_printf(sc->sc_dev, + "%s: %s: error=%d\n", __func__, name, error); + return error; +} + +int +otus_open_pipes(struct otus_softc *sc) +{ +#if 0 + int isize, error; + int i; +#endif + int error; + + OTUS_UNLOCK_ASSERT(sc); + + if ((error = otus_alloc_tx_cmd_list(sc)) != 0) { + device_printf(sc->sc_dev, + "%s: could not allocate command xfer\n", + __func__); + goto fail; + } + + if ((error = otus_alloc_tx_list(sc)) != 0) { + device_printf(sc->sc_dev, "%s: could not allocate Tx xfers\n", + __func__); + goto fail; + } + + if ((error = otus_alloc_rx_list(sc)) != 0) { + device_printf(sc->sc_dev, "%s: could not allocate Rx xfers\n", + __func__); + goto fail; + } + + /* Enable RX transfers; needed for initial firmware messages */ + OTUS_LOCK(sc); + usbd_transfer_start(sc->sc_xfer[OTUS_BULK_RX]); + usbd_transfer_start(sc->sc_xfer[OTUS_BULK_IRQ]); + OTUS_UNLOCK(sc); + return 0; + +fail: otus_close_pipes(sc); + return error; +} + +void +otus_close_pipes(struct otus_softc *sc) +{ + + OTUS_LOCK(sc); + otus_free_tx_cmd_list(sc); + otus_free_tx_list(sc); + otus_free_rx_list(sc); + OTUS_UNLOCK(sc); + + usbd_transfer_unsetup(sc->sc_xfer, OTUS_N_XFER); +} + +static void +otus_free_cmd_list(struct otus_softc *sc, struct otus_tx_cmd cmd[], int ndata) +{ + int i; + + /* XXX TODO: someone has to have waken up waiters! */ + for (i = 0; i < ndata; i++) { + struct otus_tx_cmd *dp = &cmd[i]; + + if (dp->buf != NULL) { + free(dp->buf, M_USBDEV); + dp->buf = NULL; + } + } +} + +static int +otus_alloc_cmd_list(struct otus_softc *sc, struct otus_tx_cmd cmd[], + int ndata, int maxsz) +{ + int i, error; + + for (i = 0; i < ndata; i++) { + struct otus_tx_cmd *dp = &cmd[i]; + dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT); + dp->odata = NULL; + if (dp->buf == NULL) { + device_printf(sc->sc_dev, + "could not allocate buffer\n"); + error = ENOMEM; + goto fail; + } + } + + return (0); +fail: + otus_free_cmd_list(sc, cmd, ndata); + return (error); +} + +static int +otus_alloc_tx_cmd_list(struct otus_softc *sc) +{ + int error, i; + + error = otus_alloc_cmd_list(sc, sc->sc_cmd, OTUS_CMD_LIST_COUNT, + OTUS_MAX_TXCMDSZ); + if (error != 0) + return (error); + + STAILQ_INIT(&sc->sc_cmd_active); + STAILQ_INIT(&sc->sc_cmd_inactive); + STAILQ_INIT(&sc->sc_cmd_pending); + STAILQ_INIT(&sc->sc_cmd_waiting); + + for (i = 0; i < OTUS_CMD_LIST_COUNT; i++) + STAILQ_INSERT_HEAD(&sc->sc_cmd_inactive, &sc->sc_cmd[i], + next_cmd); + + return (0); +} + +static void +otus_free_tx_cmd_list(struct otus_softc *sc) +{ + + /* + * XXX TODO: something needs to wake up any pending/sleeping + * waiters! + */ + STAILQ_INIT(&sc->sc_cmd_active); + STAILQ_INIT(&sc->sc_cmd_inactive); + STAILQ_INIT(&sc->sc_cmd_pending); + STAILQ_INIT(&sc->sc_cmd_waiting); + + otus_free_cmd_list(sc, sc->sc_cmd, OTUS_CMD_LIST_COUNT); +} + +static int +otus_alloc_list(struct otus_softc *sc, struct otus_data data[], + int ndata, int maxsz) +{ + int i, error; + + for (i = 0; i < ndata; i++) { + struct otus_data *dp = &data[i]; + dp->sc = sc; + dp->m = NULL; + dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT); + if (dp->buf == NULL) { + device_printf(sc->sc_dev, + "could not allocate buffer\n"); + error = ENOMEM; + goto fail; + } + dp->ni = NULL; + } + + return (0); +fail: + otus_free_list(sc, data, ndata); + return (error); +} + +static int +otus_alloc_rx_list(struct otus_softc *sc) +{ + int error, i; + + error = otus_alloc_list(sc, sc->sc_rx, OTUS_RX_LIST_COUNT, + OTUS_RXBUFSZ); + if (error != 0) + return (error); + + STAILQ_INIT(&sc->sc_rx_active); + STAILQ_INIT(&sc->sc_rx_inactive); + + for (i = 0; i < OTUS_RX_LIST_COUNT; i++) + STAILQ_INSERT_HEAD(&sc->sc_rx_inactive, &sc->sc_rx[i], next); + + return (0); +} + +static int +otus_alloc_tx_list(struct otus_softc *sc) +{ + int error, i; + + error = otus_alloc_list(sc, sc->sc_tx, OTUS_TX_LIST_COUNT, + OTUS_TXBUFSZ); + if (error != 0) + return (error); + + STAILQ_INIT(&sc->sc_tx_inactive); + + for (i = 0; i != OTUS_N_XFER; i++) { + STAILQ_INIT(&sc->sc_tx_active[i]); + STAILQ_INIT(&sc->sc_tx_pending[i]); + } + + for (i = 0; i < OTUS_TX_LIST_COUNT; i++) { + STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, &sc->sc_tx[i], next); + } + + return (0); +} + +static void +otus_free_tx_list(struct otus_softc *sc) +{ + int i; + + /* prevent further allocations from TX list(s) */ + STAILQ_INIT(&sc->sc_tx_inactive); + + for (i = 0; i != OTUS_N_XFER; i++) { + STAILQ_INIT(&sc->sc_tx_active[i]); + STAILQ_INIT(&sc->sc_tx_pending[i]); + } + + otus_free_list(sc, sc->sc_tx, OTUS_TX_LIST_COUNT); +} + +static void +otus_free_rx_list(struct otus_softc *sc) +{ + /* prevent further allocations from RX list(s) */ + STAILQ_INIT(&sc->sc_rx_inactive); + STAILQ_INIT(&sc->sc_rx_active); + + otus_free_list(sc, sc->sc_rx, OTUS_RX_LIST_COUNT); +} + +static void +otus_free_list(struct otus_softc *sc, struct otus_data data[], int ndata) +{ + int i; + + for (i = 0; i < ndata; i++) { + struct otus_data *dp = &data[i]; + + if (dp->buf != NULL) { + free(dp->buf, M_USBDEV); + dp->buf = NULL; + } + if (dp->ni != NULL) { + ieee80211_free_node(dp->ni); + dp->ni = NULL; + } + } +} + +static struct otus_data * +_otus_getbuf(struct otus_softc *sc) +{ + struct otus_data *bf; + + bf = STAILQ_FIRST(&sc->sc_tx_inactive); + if (bf != NULL) + STAILQ_REMOVE_HEAD(&sc->sc_tx_inactive, next); + else + bf = NULL; + return (bf); +} + +static struct otus_data * +otus_getbuf(struct otus_softc *sc) +{ + struct otus_data *bf; + + OTUS_LOCK_ASSERT(sc); + + bf = _otus_getbuf(sc); + return (bf); +} + +static void +otus_freebuf(struct otus_softc *sc, struct otus_data *bf) +{ + + OTUS_LOCK_ASSERT(sc); + STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, bf, next); +} + +static struct otus_tx_cmd * +_otus_get_txcmd(struct otus_softc *sc) +{ + struct otus_tx_cmd *bf; + + bf = STAILQ_FIRST(&sc->sc_cmd_inactive); + if (bf != NULL) + STAILQ_REMOVE_HEAD(&sc->sc_cmd_inactive, next_cmd); + else + bf = NULL; + return (bf); +} + +static struct otus_tx_cmd * +otus_get_txcmd(struct otus_softc *sc) +{ + struct otus_tx_cmd *bf; + + OTUS_LOCK_ASSERT(sc); + + bf = _otus_get_txcmd(sc); + if (bf == NULL) { + device_printf(sc->sc_dev, "%s: no tx cmd buffers\n", + __func__); + } + return (bf); +} + +static void +otus_free_txcmd(struct otus_softc *sc, struct otus_tx_cmd *bf) +{ + + OTUS_LOCK_ASSERT(sc); + STAILQ_INSERT_TAIL(&sc->sc_cmd_inactive, bf, next_cmd); +} + +void +otus_next_scan(void *arg, int pending) +{ +#if 0 + struct otus_softc *sc = arg; + + if (usbd_is_dying(sc->sc_udev)) + return; + + usbd_ref_incr(sc->sc_udev); + + if (sc->sc_ic.ic_state == IEEE80211_S_SCAN) + ieee80211_next_scan(&sc->sc_ic.ic_if); + + usbd_ref_decr(sc->sc_udev); +#endif +} + +int +otus_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) +{ + struct otus_vap *uvp = OTUS_VAP(vap); + struct ieee80211com *ic = vap->iv_ic; + struct otus_softc *sc = ic->ic_softc; + struct ieee80211_node *ni; + enum ieee80211_state ostate; + + ostate = vap->iv_state; + OTUS_DPRINTF(sc, OTUS_DEBUG_STATE, "%s: %s -> %s\n", __func__, + ieee80211_state_name[ostate], + ieee80211_state_name[nstate]); + + IEEE80211_UNLOCK(ic); + + OTUS_LOCK(sc); + + /* XXX TODO: more fleshing out! */ + + switch (nstate) { + case IEEE80211_S_RUN: + ni = ieee80211_ref_node(vap->iv_bss); + + if (ic->ic_opmode == IEEE80211_M_STA) { + otus_updateslot(sc); + otus_set_bssid(sc, ni->ni_bssid); + + /* Start calibration timer. */ + taskqueue_enqueue_timeout(taskqueue_thread, + &sc->calib_to, hz); + } + break; + default: + break; + } + + /* XXX TODO: calibration? */ + + sc->sc_led_newstate(sc); + + OTUS_UNLOCK(sc); + IEEE80211_LOCK(ic); + return (uvp->newstate(vap, nstate, arg)); +} + +int +otus_cmd(struct otus_softc *sc, uint8_t code, const void *idata, int ilen, + void *odata, int odatalen) +{ + struct otus_tx_cmd *cmd; + struct ar_cmd_hdr *hdr; + int xferlen, error; + + OTUS_LOCK_ASSERT(sc); + + /* Always bulk-out a multiple of 4 bytes. */ + xferlen = (sizeof (*hdr) + ilen + 3) & ~3; + if (xferlen > OTUS_MAX_TXCMDSZ) { + device_printf(sc->sc_dev, "%s: command (0x%02x) size (%d) > %d\n", + __func__, + code, + xferlen, + OTUS_MAX_TXCMDSZ); + return (EIO); + } + + cmd = otus_get_txcmd(sc); + if (cmd == NULL) { + device_printf(sc->sc_dev, "%s: failed to get buf\n", + __func__); + return (EIO); + } + + hdr = (struct ar_cmd_hdr *)cmd->buf; + hdr->code = code; + hdr->len = ilen; + hdr->token = ++sc->token; /* Don't care about endianness. */ + cmd->token = hdr->token; + /* XXX TODO: check max cmd length? */ + memcpy((uint8_t *)&hdr[1], idata, ilen); + + OTUS_DPRINTF(sc, OTUS_DEBUG_CMD, + "%s: sending command code=0x%02x len=%d token=%d\n", + __func__, code, ilen, hdr->token); + + cmd->odata = odata; + cmd->odatalen = odatalen; + cmd->buflen = xferlen; + + /* Queue the command to the endpoint */ + STAILQ_INSERT_TAIL(&sc->sc_cmd_pending, cmd, next_cmd); + usbd_transfer_start(sc->sc_xfer[OTUS_BULK_CMD]); + + /* Sleep on the command; wait for it to complete */ + error = msleep(cmd, &sc->sc_mtx, PCATCH, "otuscmd", hz); + + /* + * At this point we don't own cmd any longer; it'll be + * freed by the cmd bulk path or the RX notification + * path. If the data is made available then it'll be copied + * to the caller. All that is left to do is communicate + * status back to the caller. + */ + if (error != 0) { + device_printf(sc->sc_dev, + "%s: timeout waiting for command 0x%02x reply\n", + __func__, code); + } + return error; +} + +void +otus_write(struct otus_softc *sc, uint32_t reg, uint32_t val) +{ + + OTUS_LOCK_ASSERT(sc); + + sc->write_buf[sc->write_idx].reg = htole32(reg); + sc->write_buf[sc->write_idx].val = htole32(val); + + if (++sc->write_idx > (AR_MAX_WRITE_IDX-1)) + (void)otus_write_barrier(sc); +} + +int +otus_write_barrier(struct otus_softc *sc) +{ + int error; + + OTUS_LOCK_ASSERT(sc); + + if (sc->write_idx == 0) + return 0; /* Nothing to flush. */ + + OTUS_DPRINTF(sc, OTUS_DEBUG_REGIO, "%s: called; %d updates\n", + __func__, + sc->write_idx); + + error = otus_cmd(sc, AR_CMD_WREG, sc->write_buf, + sizeof (sc->write_buf[0]) * sc->write_idx, NULL, 0); + sc->write_idx = 0; + return error; +} + +struct ieee80211_node * +otus_node_alloc(struct ieee80211com *ic) +{ + return malloc(sizeof (struct otus_node), M_DEVBUF, M_NOWAIT | M_ZERO); +} + +#if 0 +int +otus_media_change(struct ifnet *ifp) +{ + struct otus_softc *sc = ifp->if_softc; + struct ieee80211com *ic = &sc->sc_ic; + uint8_t rate, ridx; + int error; + + error = ieee80211_media_change(ifp); + if (error != ENETRESET) + return error; + + if (ic->ic_fixed_rate != -1) { + rate = ic->ic_sup_rates[ic->ic_curmode]. + rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL; + for (ridx = 0; ridx <= OTUS_RIDX_MAX; ridx++) + if (otus_rates[ridx].rate == rate) + break; + sc->fixed_ridx = ridx; + } + + if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING)) + error = otus_init(sc); + + return error; +} +#endif + +int +otus_read_eeprom(struct otus_softc *sc) +{ + uint32_t regs[8], reg; + uint8_t *eep; + int i, j, error; + + OTUS_LOCK_ASSERT(sc); + + /* Read EEPROM by blocks of 32 bytes. */ + eep = (uint8_t *)&sc->eeprom; + reg = AR_EEPROM_OFFSET; + for (i = 0; i < sizeof (sc->eeprom) / 32; i++) { + for (j = 0; j < 8; j++, reg += 4) + regs[j] = htole32(reg); + error = otus_cmd(sc, AR_CMD_RREG, regs, sizeof regs, eep, 32); + if (error != 0) + break; + eep += 32; + } + return error; +} + +void +otus_newassoc(struct ieee80211_node *ni, int isnew) +{ + struct ieee80211com *ic = ni->ni_ic; + struct otus_softc *sc = ic->ic_softc; + struct otus_node *on = OTUS_NODE(ni); + + OTUS_DPRINTF(sc, OTUS_DEBUG_STATE, "new assoc isnew=%d addr=%s\n", + isnew, ether_sprintf(ni->ni_macaddr)); + + on->tx_done = 0; + on->tx_err = 0; + on->tx_retries = 0; +} + +static void +otus_cmd_handle_response(struct otus_softc *sc, struct ar_cmd_hdr *hdr) +{ + struct otus_tx_cmd *cmd; + + OTUS_LOCK_ASSERT(sc); + + OTUS_DPRINTF(sc, OTUS_DEBUG_CMDDONE, + "%s: received reply code=0x%02x len=%d token=%d\n", + __func__, + hdr->code, hdr->len, hdr->token); + + /* + * Walk the list, freeing items that aren't ours, + * stopping when we hit our token. + */ + while ((cmd = STAILQ_FIRST(&sc->sc_cmd_waiting)) != NULL) { + STAILQ_REMOVE_HEAD(&sc->sc_cmd_waiting, next_cmd); + OTUS_DPRINTF(sc, OTUS_DEBUG_CMDDONE, + "%s: cmd=%p; hdr.token=%d, cmd.token=%d\n", + __func__, + cmd, + (int) hdr->token, + (int) cmd->token); + if (hdr->token == cmd->token) { + /* Copy answer into caller's supplied buffer. */ + if (cmd->odata != NULL) { + if (hdr->len != cmd->odatalen) { + device_printf(sc->sc_dev, + "%s: code 0x%02x, len=%d, olen=%d\n", + __func__, + (int) hdr->code, + (int) hdr->len, + (int) cmd->odatalen); + } + memcpy(cmd->odata, &hdr[1], + MIN(cmd->odatalen, hdr->len)); + } + wakeup(cmd); + } + + STAILQ_INSERT_TAIL(&sc->sc_cmd_inactive, cmd, next_cmd); + } +} + +void +otus_cmd_rxeof(struct otus_softc *sc, uint8_t *buf, int len) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ar_cmd_hdr *hdr; + + OTUS_LOCK_ASSERT(sc); + + if (__predict_false(len < sizeof (*hdr))) { + OTUS_DPRINTF(sc, OTUS_DEBUG_CMDDONE, + "cmd too small %d\n", len); + return; + } + hdr = (struct ar_cmd_hdr *)buf; + if (__predict_false(sizeof (*hdr) + hdr->len > len || + sizeof (*hdr) + hdr->len > 64)) { + OTUS_DPRINTF(sc, OTUS_DEBUG_CMDDONE, + "cmd too large %d\n", hdr->len); + return; + } + + OTUS_DPRINTF(sc, OTUS_DEBUG_RXDONE, + "%s: code=%.02x\n", + __func__, + hdr->code); + + /* + * This has to reach into the cmd queue "waiting for + * an RX response" list, grab the head entry and check + * if we need to wake anyone up. + */ + if ((hdr->code & 0xc0) != 0xc0) { + otus_cmd_handle_response(sc, hdr); + return; + } + + /* Received unsolicited notification. */ + switch (hdr->code & 0x3f) { + case AR_EVT_BEACON: + break; + case AR_EVT_TX_COMP: + { + struct ar_evt_tx_comp *tx = (struct ar_evt_tx_comp *)&hdr[1]; + struct ieee80211_node *ni; + + ni = ieee80211_find_node(&ic->ic_sta, tx->macaddr); + if (ni == NULL) { + device_printf(sc->sc_dev, + "%s: txcomp on unknown node (%s)\n", + __func__, + ether_sprintf(tx->macaddr)); + break; + } + + OTUS_DPRINTF(sc, OTUS_DEBUG_TXCOMP, + "tx completed %s status=%d phy=0x%x\n", + ether_sprintf(tx->macaddr), le16toh(tx->status), + le32toh(tx->phy)); + + switch (le16toh(tx->status)) { + case AR_TX_STATUS_COMP: +#if 0 + ackfailcnt = 0; + ieee80211_ratectl_tx_complete(ni->ni_vap, ni, + IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL); +#endif + /* + * We don't get the above; only error notifications. + * Sigh. So, don't worry about this. + */ + break; + case AR_TX_STATUS_RETRY_COMP: + OTUS_NODE(ni)->tx_retries++; + break; + case AR_TX_STATUS_FAILED: + OTUS_NODE(ni)->tx_err++; + break; + } + ieee80211_free_node(ni); + break; + } + case AR_EVT_TBTT: + break; + case AR_EVT_DO_BB_RESET: + /* + * This is "tell driver to reset baseband" from ar9170-fw. + * + * I'm not sure what we should do here, so I'm going to + * fall through; it gets generated when RTSRetryCnt internally + * reaches '5' - I guess the firmware authors thought that + * meant that the BB may have gone deaf or something. + */ + default: + device_printf(sc->sc_dev, + "%s: received notification code=0x%02x len=%d\n", + __func__, + hdr->code, hdr->len); + } +} + +void +otus_sub_rxeof(struct otus_softc *sc, uint8_t *buf, int len, struct mbufq *rxq) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_rx_stats rxs; +#if 0 + struct ieee80211_node *ni; +#endif + struct ar_rx_tail *tail; + struct ieee80211_frame *wh; + struct mbuf *m; + uint8_t *plcp; +// int s; + int mlen; + + if (__predict_false(len < AR_PLCP_HDR_LEN)) { + OTUS_DPRINTF(sc, OTUS_DEBUG_RXDONE, + "sub-xfer too short %d\n", len); + return; + } + plcp = buf; + + /* All bits in the PLCP header are set to 1 for non-MPDU. */ + if (memcmp(plcp, AR_PLCP_HDR_INTR, AR_PLCP_HDR_LEN) == 0) { + otus_cmd_rxeof(sc, plcp + AR_PLCP_HDR_LEN, + len - AR_PLCP_HDR_LEN); + return; + } + + /* Received MPDU. */ + if (__predict_false(len < AR_PLCP_HDR_LEN + sizeof (*tail))) { + OTUS_DPRINTF(sc, OTUS_DEBUG_RXDONE, "MPDU too short %d\n", len); + counter_u64_add(ic->ic_ierrors, 1); + return; + } + tail = (struct ar_rx_tail *)(plcp + len - sizeof (*tail)); + + /* Discard error frames. */ + if (__predict_false(tail->error != 0)) { + OTUS_DPRINTF(sc, OTUS_DEBUG_RXDONE, "error frame 0x%02x\n", tail->error); + if (tail->error & AR_RX_ERROR_FCS) { + OTUS_DPRINTF(sc, OTUS_DEBUG_RXDONE, "bad FCS\n"); + } else if (tail->error & AR_RX_ERROR_MMIC) { + /* Report Michael MIC failures to net80211. */ +#if 0 + ieee80211_notify_michael_failure(ni->ni_vap, wh, keyidx); +#endif + device_printf(sc->sc_dev, "%s: MIC failure\n", __func__); + } + counter_u64_add(ic->ic_ierrors, 1); + return; + } + /* Compute MPDU's length. */ + mlen = len - AR_PLCP_HDR_LEN - sizeof (*tail); + /* Make sure there's room for an 802.11 header + FCS. */ + if (__predict_false(mlen < IEEE80211_MIN_LEN)) { + counter_u64_add(ic->ic_ierrors, 1); + return; + } + mlen -= IEEE80211_CRC_LEN; /* strip 802.11 FCS */ + + wh = (struct ieee80211_frame *)(plcp + AR_PLCP_HDR_LEN); + + m = m_get2(mlen, M_NOWAIT, MT_DATA, M_PKTHDR); + if (m == NULL) { + device_printf(sc->sc_dev, "%s: failed m_get2()\n", __func__); + counter_u64_add(ic->ic_ierrors, 1); + } + + /* Finalize mbuf. */ + memcpy(mtod(m, uint8_t *), wh, mlen); + m->m_pkthdr.len = m->m_len = mlen; + +#if 0 + if (__predict_false(sc->sc_drvbpf != NULL)) { + struct otus_rx_radiotap_header *tap = &sc->sc_rxtap; + struct mbuf mb; + + tap->wr_flags = 0; + tap->wr_chan_freq = htole16(ic->ic_ibss_chan->ic_freq); + tap->wr_chan_flags = htole16(ic->ic_ibss_chan->ic_flags); + tap->wr_antsignal = tail->rssi; + tap->wr_rate = 2; /* In case it can't be found below. */ + switch (tail->status & AR_RX_STATUS_MT_MASK) { + case AR_RX_STATUS_MT_CCK: + switch (plcp[0]) { + case 10: tap->wr_rate = 2; break; + case 20: tap->wr_rate = 4; break; + case 55: tap->wr_rate = 11; break; + case 110: tap->wr_rate = 22; break; + } + if (tail->status & AR_RX_STATUS_SHPREAMBLE) + tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; + break; + case AR_RX_STATUS_MT_OFDM: + switch (plcp[0] & 0xf) { + case 0xb: tap->wr_rate = 12; break; + case 0xf: tap->wr_rate = 18; break; + case 0xa: tap->wr_rate = 24; break; + case 0xe: tap->wr_rate = 36; break; + case 0x9: tap->wr_rate = 48; break; + case 0xd: tap->wr_rate = 72; break; + case 0x8: tap->wr_rate = 96; break; + case 0xc: tap->wr_rate = 108; break; + } + break; + } + mb.m_data = (caddr_t)tap; + mb.m_len = sc->sc_rxtap_len; + mb.m_next = m; + mb.m_nextpkt = NULL; + mb.m_type = 0; + mb.m_flags = 0; + bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN); + } +#endif + + /* Add RSSI/NF to this mbuf */ + bzero(&rxs, sizeof(rxs)); + rxs.r_flags = IEEE80211_R_NF | IEEE80211_R_RSSI; + rxs.nf = sc->sc_nf[0]; /* XXX chain 0 != combined rssi/nf */ + rxs.rssi = tail->rssi; + /* XXX TODO: add MIMO RSSI/NF as well */ + ieee80211_add_rx_params(m, &rxs); + + /* XXX make a method */ + STAILQ_INSERT_TAIL(&rxq->mq_head, m, m_stailqpkt); + +#if 0 + OTUS_UNLOCK(sc); + ni = ieee80211_find_rxnode(ic, wh); + rxi.rxi_flags = 0; + rxi.rxi_rssi = tail->rssi; + rxi.rxi_tstamp = 0; /* unused */ + ieee80211_input(ifp, m, ni, &rxi); + + /* Node is no longer needed. */ + ieee80211_release_node(ic, ni); + OTUS_LOCK(sc); +#endif +} + +static void +otus_rxeof(struct usb_xfer *xfer, struct otus_data *data, struct mbufq *rxq) +{ + struct otus_softc *sc = usbd_xfer_softc(xfer); + caddr_t buf = data->buf; + struct ar_rx_head *head; + uint16_t hlen; + int len; + + usbd_xfer_status(xfer, &len, NULL, NULL, NULL); + + while (len >= sizeof (*head)) { + head = (struct ar_rx_head *)buf; + if (__predict_false(head->tag != htole16(AR_RX_HEAD_TAG))) { + OTUS_DPRINTF(sc, OTUS_DEBUG_RXDONE, + "tag not valid 0x%x\n", le16toh(head->tag)); + break; + } + hlen = le16toh(head->len); + if (__predict_false(sizeof (*head) + hlen > len)) { + OTUS_DPRINTF(sc, OTUS_DEBUG_RXDONE, + "xfer too short %d/%d\n", len, hlen); + break; + } + /* Process sub-xfer. */ + otus_sub_rxeof(sc, (uint8_t *)&head[1], hlen, rxq); + + /* Next sub-xfer is aligned on a 32-bit boundary. */ + hlen = (sizeof (*head) + hlen + 3) & ~3; + buf += hlen; + len -= hlen; + } +} + +static void +otus_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) +{ + struct otus_softc *sc = usbd_xfer_softc(xfer); + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_frame *wh; + struct ieee80211_node *ni; + struct mbuf *m; + struct mbufq scrx; + struct otus_data *data; + + OTUS_LOCK_ASSERT(sc); + + mbufq_init(&scrx, 1024); + +#if 0 + device_printf(sc->sc_dev, "%s: called; state=%d; error=%d\n", + __func__, + USB_GET_STATE(xfer), + error); +#endif + + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + data = STAILQ_FIRST(&sc->sc_rx_active); + if (data == NULL) + goto tr_setup; + STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next); + otus_rxeof(xfer, data, &scrx); + STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next); + /* FALLTHROUGH */ + case USB_ST_SETUP: +tr_setup: + /* + * XXX TODO: what if sc_rx isn't empty, but data + * is empty? Then we leak mbufs. + */ + data = STAILQ_FIRST(&sc->sc_rx_inactive); + if (data == NULL) { + //KASSERT(m == NULL, ("mbuf isn't NULL")); + return; + } + STAILQ_REMOVE_HEAD(&sc->sc_rx_inactive, next); + STAILQ_INSERT_TAIL(&sc->sc_rx_active, data, next); + usbd_xfer_set_frame_data(xfer, 0, data->buf, + usbd_xfer_max_len(xfer)); + usbd_transfer_submit(xfer); + /* + * To avoid LOR we should unlock our private mutex here to call + * ieee80211_input() because here is at the end of a USB + * callback and safe to unlock. + */ + OTUS_UNLOCK(sc); + while ((m = mbufq_dequeue(&scrx)) != NULL) { + wh = mtod(m, struct ieee80211_frame *); + ni = ieee80211_find_rxnode(ic, + (struct ieee80211_frame_min *)wh); + if (ni != NULL) { + if (ni->ni_flags & IEEE80211_NODE_HT) + m->m_flags |= M_AMPDU; + (void)ieee80211_input_mimo(ni, m, NULL); + ieee80211_free_node(ni); + } else + (void)ieee80211_input_mimo_all(ic, m, NULL); + } +#ifdef IEEE80211_SUPPORT_SUPERG + ieee80211_ff_age_all(ic, 100); +#endif + OTUS_LOCK(sc); + break; + default: + /* needs it to the inactive queue due to a error. */ + data = STAILQ_FIRST(&sc->sc_rx_active); + if (data != NULL) { + STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next); + STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next); + } + if (error != USB_ERR_CANCELLED) { + usbd_xfer_set_stall(xfer); + counter_u64_add(ic->ic_ierrors, 1); + goto tr_setup; + } + break; + } +} + +static void +otus_txeof(struct usb_xfer *xfer, struct otus_data *data) +{ + struct otus_softc *sc = usbd_xfer_softc(xfer); + + OTUS_DPRINTF(sc, OTUS_DEBUG_TXDONE, + "%s: called; data=%p\n", __func__, data); + + OTUS_LOCK_ASSERT(sc); + + if (sc->sc_tx_n_active == 0) { + device_printf(sc->sc_dev, + "%s: completed but tx_active=0\n", + __func__); + } else { + sc->sc_tx_n_active--; + } + + if (data->m) { + /* XXX status? */ + /* XXX we get TX status via the RX path.. */ + ieee80211_tx_complete(data->ni, data->m, 0); + data->m = NULL; + data->ni = NULL; + } +} + +static void +otus_txcmdeof(struct usb_xfer *xfer, struct otus_tx_cmd *cmd) +{ + struct otus_softc *sc = usbd_xfer_softc(xfer); + + OTUS_LOCK_ASSERT(sc); + + OTUS_DPRINTF(sc, OTUS_DEBUG_CMDDONE, + "%s: called; data=%p; odata=%p\n", + __func__, cmd, cmd->odata); + + /* + * Non-response commands still need wakeup so the caller + * knows it was submitted and completed OK; response commands should + * wait until they're ACKed by the firmware with a response. + */ + if (cmd->odata) { + STAILQ_INSERT_TAIL(&sc->sc_cmd_waiting, cmd, next_cmd); + } else { + wakeup(cmd); + otus_free_txcmd(sc, cmd); + } +} + +static void +otus_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error) +{ + uint8_t which = OTUS_BULK_TX; + struct otus_softc *sc = usbd_xfer_softc(xfer); + struct ieee80211com *ic = &sc->sc_ic; + struct otus_data *data; + + OTUS_LOCK_ASSERT(sc); + + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + data = STAILQ_FIRST(&sc->sc_tx_active[which]); + if (data == NULL) + goto tr_setup; + OTUS_DPRINTF(sc, OTUS_DEBUG_TXDONE, + "%s: transfer done %p\n", __func__, data); + STAILQ_REMOVE_HEAD(&sc->sc_tx_active[which], next); + otus_txeof(xfer, data); + otus_freebuf(sc, data); + /* FALLTHROUGH */ + case USB_ST_SETUP: +tr_setup: + data = STAILQ_FIRST(&sc->sc_tx_pending[which]); + if (data == NULL) { + OTUS_DPRINTF(sc, OTUS_DEBUG_XMIT, + "%s: empty pending queue sc %p\n", __func__, sc); + sc->sc_tx_n_active = 0; + goto finish; + } + STAILQ_REMOVE_HEAD(&sc->sc_tx_pending[which], next); + STAILQ_INSERT_TAIL(&sc->sc_tx_active[which], data, next); + usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); + OTUS_DPRINTF(sc, OTUS_DEBUG_XMIT, + "%s: submitting transfer %p\n", __func__, data); + usbd_transfer_submit(xfer); + sc->sc_tx_n_active++; + break; + default: + data = STAILQ_FIRST(&sc->sc_tx_active[which]); + if (data != NULL) { + STAILQ_REMOVE_HEAD(&sc->sc_tx_active[which], next); + otus_txeof(xfer, data); + otus_freebuf(sc, data); + } + counter_u64_add(ic->ic_oerrors, 1); + + if (error != USB_ERR_CANCELLED) { + usbd_xfer_set_stall(xfer); + goto tr_setup; + } + break; + } + +finish: +#ifdef IEEE80211_SUPPORT_SUPERG + /* + * If the TX active queue drops below a certain + * threshold, ensure we age fast-frames out so they're + * transmitted. + */ + if (sc->sc_tx_n_active < 2) { + /* XXX ew - net80211 should defer this for us! */ + OTUS_UNLOCK(sc); + ieee80211_ff_flush(ic, WME_AC_VO); + ieee80211_ff_flush(ic, WME_AC_VI); + ieee80211_ff_flush(ic, WME_AC_BE); + ieee80211_ff_flush(ic, WME_AC_BK); + OTUS_LOCK(sc); + } +#endif + /* Kick TX */ + otus_tx_start(sc); +} + +static void +otus_bulk_cmd_callback(struct usb_xfer *xfer, usb_error_t error) +{ + struct otus_softc *sc = usbd_xfer_softc(xfer); +#if 0 + struct ieee80211com *ic = &sc->sc_ic; +#endif + struct otus_tx_cmd *cmd; + + OTUS_LOCK_ASSERT(sc); + + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + cmd = STAILQ_FIRST(&sc->sc_cmd_active); + if (cmd == NULL) + goto tr_setup; + OTUS_DPRINTF(sc, OTUS_DEBUG_CMDDONE, + "%s: transfer done %p\n", __func__, cmd); + STAILQ_REMOVE_HEAD(&sc->sc_cmd_active, next_cmd); + otus_txcmdeof(xfer, cmd); + /* FALLTHROUGH */ + case USB_ST_SETUP: +tr_setup: + cmd = STAILQ_FIRST(&sc->sc_cmd_pending); + if (cmd == NULL) { + OTUS_DPRINTF(sc, OTUS_DEBUG_CMD, + "%s: empty pending queue sc %p\n", __func__, sc); + return; + } + STAILQ_REMOVE_HEAD(&sc->sc_cmd_pending, next_cmd); + STAILQ_INSERT_TAIL(&sc->sc_cmd_active, cmd, next_cmd); + usbd_xfer_set_frame_data(xfer, 0, cmd->buf, cmd->buflen); + OTUS_DPRINTF(sc, OTUS_DEBUG_CMD, + "%s: submitting transfer %p; buf=%p, buflen=%d\n", __func__, cmd, cmd->buf, cmd->buflen); + usbd_transfer_submit(xfer); + break; + default: + cmd = STAILQ_FIRST(&sc->sc_cmd_active); + if (cmd != NULL) { + STAILQ_REMOVE_HEAD(&sc->sc_cmd_active, next_cmd); + otus_txcmdeof(xfer, cmd); + } + + if (error != USB_ERR_CANCELLED) { + usbd_xfer_set_stall(xfer); + goto tr_setup; + } + break; + } +} + +/* + * This isn't used by carl9170; it however may be used by the + * initial bootloader. + */ +static void +otus_bulk_irq_callback(struct usb_xfer *xfer, usb_error_t error) +{ + struct otus_softc *sc = usbd_xfer_softc(xfer); + int actlen; + int sumlen; + + usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); + OTUS_DPRINTF(sc, OTUS_DEBUG_IRQ, + "%s: called; state=%d\n", __func__, USB_GET_STATE(xfer)); + + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + /* + * Read usb frame data, if any. + * "actlen" has the total length for all frames + * transferred. + */ + OTUS_DPRINTF(sc, OTUS_DEBUG_IRQ, + "%s: comp; %d bytes\n", + __func__, + actlen); +#if 0 + pc = usbd_xfer_get_frame(xfer, 0); + otus_dump_usb_rx_page(sc, pc, actlen); +#endif + /* XXX fallthrough */ + case USB_ST_SETUP: + /* + * Setup xfer frame lengths/count and data + */ + OTUS_DPRINTF(sc, OTUS_DEBUG_IRQ, "%s: setup\n", __func__); + usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); + usbd_transfer_submit(xfer); + break; + + default: /* Error */ + /* + * Print error message and clear stall + * for example. + */ + OTUS_DPRINTF(sc, OTUS_DEBUG_IRQ, "%s: ERROR?\n", __func__); + break; + } +} + +/* + * Map net80211 rate to hw rate for otus MAC/PHY. + */ +static uint8_t +otus_rate_to_hw_rate(struct otus_softc *sc, uint8_t rate) +{ + int is_2ghz; + + is_2ghz = !! (IEEE80211_IS_CHAN_2GHZ(sc->sc_ic.ic_curchan)); + + switch (rate) { + /* CCK */ + case 2: + return (0x0); + case 4: + return (0x1); + case 11: + return (0x2); + case 22: + return (0x3); + /* OFDM */ + case 12: + return (0xb); + case 18: + return (0xf); + case 24: + return (0xa); + case 36: + return (0xe); + case 48: + return (0x9); + case 72: + return (0xd); + case 96: + return (0x8); + case 108: + return (0xc); + default: + device_printf(sc->sc_dev, "%s: unknown rate '%d'\n", + __func__, (int) rate); + case 0: + if (is_2ghz) + return (0x0); /* 1MB CCK */ + else + return (0xb); /* 6MB OFDM */ + + /* XXX TODO: HT */ + } +} + +static int +otus_hw_rate_is_ofdm(struct otus_softc *sc, uint8_t hw_rate) +{ + + switch (hw_rate) { + case 0x0: + case 0x1: + case 0x2: + case 0x3: + return (0); + default: + return (1); + } +} + + +static void +otus_tx_update_ratectl(struct otus_softc *sc, struct ieee80211_node *ni) +{ + int tx, tx_success, tx_retry; + + tx = OTUS_NODE(ni)->tx_done; + tx_success = OTUS_NODE(ni)->tx_done - OTUS_NODE(ni)->tx_err; + tx_retry = OTUS_NODE(ni)->tx_retries; + + ieee80211_ratectl_tx_update(ni->ni_vap, ni, &tx, &tx_success, + &tx_retry); +} + +/* + * XXX TODO: support tx bpf parameters for configuration! + */ +static int +otus_tx(struct otus_softc *sc, struct ieee80211_node *ni, struct mbuf *m, + struct otus_data *data) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211_frame *wh; + struct ieee80211_key *k; + struct ar_tx_head *head; + uint32_t phyctl; + uint16_t macctl, qos; + uint8_t qid, rate; + int hasqos, xferlen; + + wh = mtod(m, struct ieee80211_frame *); + if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { + k = ieee80211_crypto_encap(ni, m); + if (k == NULL) { + device_printf(sc->sc_dev, + "%s: m=%p: ieee80211_crypto_encap returns NULL\n", + __func__, + m); + return (ENOBUFS); + } + wh = mtod(m, struct ieee80211_frame *); + } + + /* Calculate transfer length; ensure data buffer is large enough */ + xferlen = sizeof (*head) + m->m_pkthdr.len; + if (xferlen > OTUS_TXBUFSZ) { + device_printf(sc->sc_dev, + "%s: 802.11 TX frame is %d bytes, max %d bytes\n", + __func__, + xferlen, + OTUS_TXBUFSZ); + return (ENOBUFS); + } + + hasqos = !! IEEE80211_QOS_HAS_SEQ(wh); + + if (hasqos) { + uint8_t tid; + qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; + tid = qos & IEEE80211_QOS_TID; + qid = TID_TO_WME_AC(tid); + } else { + qos = 0; + qid = WME_AC_BE; + } + + /* Pickup a rate index. */ + if (IEEE80211_IS_MULTICAST(wh->i_addr1) || + (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA) { + /* Get lowest rate */ + rate = otus_rate_to_hw_rate(sc, 0); + } else { + (void) ieee80211_ratectl_rate(ni, NULL, 0); + rate = otus_rate_to_hw_rate(sc, ni->ni_txrate); + } + + phyctl = 0; + macctl = AR_TX_MAC_BACKOFF | AR_TX_MAC_HW_DUR | AR_TX_MAC_QID(qid); + + if (IEEE80211_IS_MULTICAST(wh->i_addr1) || + (hasqos && ((qos & IEEE80211_QOS_ACKPOLICY) == + IEEE80211_QOS_ACKPOLICY_NOACK))) + macctl |= AR_TX_MAC_NOACK; + + if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { + if (m->m_pkthdr.len + IEEE80211_CRC_LEN >= vap->iv_rtsthreshold) + macctl |= AR_TX_MAC_RTS; + else if (ic->ic_flags & IEEE80211_F_USEPROT) { + if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) + macctl |= AR_TX_MAC_CTS; + else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) + macctl |= AR_TX_MAC_RTS; + } + } + + phyctl |= AR_TX_PHY_MCS(rate); + if (otus_hw_rate_is_ofdm(sc, rate)) { + phyctl |= AR_TX_PHY_MT_OFDM; + /* Always use all tx antennas for now, just to be safe */ + phyctl |= AR_TX_PHY_ANTMSK(sc->txmask); + } else { /* CCK */ + phyctl |= AR_TX_PHY_MT_CCK; + phyctl |= AR_TX_PHY_ANTMSK(sc->txmask); + } + + /* Update net80211 with the current counters */ + otus_tx_update_ratectl(sc, ni); + + /* Update rate control stats for frames that are ACK'ed. */ + if (!(macctl & AR_TX_MAC_NOACK)) + OTUS_NODE(ni)->tx_done++; + + + /* Fill Tx descriptor. */ + head = (struct ar_tx_head *)data->buf; + head->len = htole16(m->m_pkthdr.len + IEEE80211_CRC_LEN); + head->macctl = htole16(macctl); + head->phyctl = htole32(phyctl); + + m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)&head[1]); + + data->buflen = xferlen; + data->ni = ni; + data->m = m; + + OTUS_DPRINTF(sc, OTUS_DEBUG_XMIT, + "%s: tx: m=%p; data=%p; len=%d mac=0x%04x phy=0x%08x rate=0x%02x, ni_txrate=%d\n", + __func__, m, data, head->len, head->macctl, head->phyctl, + (int) rate, (int) ni->ni_txrate); + + /* Submit transfer */ + STAILQ_INSERT_TAIL(&sc->sc_tx_pending[OTUS_BULK_TX], data, next); + usbd_transfer_start(sc->sc_xfer[OTUS_BULK_TX]); + + return 0; +} + +int +otus_set_multi(struct otus_softc *sc) +{ + uint32_t lo, hi; + struct ieee80211com *ic = &sc->sc_ic; + int r; + + if (ic->ic_allmulti > 0 || ic->ic_promisc > 0 || + ic->ic_opmode == IEEE80211_M_MONITOR) { + lo = 0xffffffff; + hi = 0xffffffff; + } else { + struct ieee80211vap *vap; + struct ifnet *ifp; + struct ifmultiaddr *ifma; + + lo = hi = 0; + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { + ifp = vap->iv_ifp; + if_maddr_rlock(ifp); + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + caddr_t dl; + uint32_t val; + + dl = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); + val = LE_READ_4(dl + 4); + /* Get address byte 5 */ + val = val & 0x0000ff00; + val = val >> 8; + + /* As per below, shift it >> 2 to get only 6 bits */ + val = val >> 2; + if (val < 32) + lo |= 1 << val; + else + hi |= 1 << (val - 32); + } + if_maddr_runlock(ifp); + } + } +#if 0 + /* XXX openbsd code */ + while (enm != NULL) { + bit = enm->enm_addrlo[5] >> 2; + if (bit < 32) + lo |= 1 << bit; + else + hi |= 1 << (bit - 32); + ETHER_NEXT_MULTI(step, enm); + } +#endif + + hi |= 1U << 31; /* Make sure the broadcast bit is set. */ + + OTUS_LOCK(sc); + otus_write(sc, AR_MAC_REG_GROUP_HASH_TBL_L, lo); + otus_write(sc, AR_MAC_REG_GROUP_HASH_TBL_H, hi); + r = otus_write_barrier(sc); + OTUS_UNLOCK(sc); + return (r); +} + +static void +otus_updateedca(struct otus_softc *sc) +{ +#define EXP2(val) ((1 << (val)) - 1) +#define AIFS(val) ((val) * 9 + 10) + struct ieee80211com *ic = &sc->sc_ic; + const struct wmeParams *edca; + + OTUS_LOCK_ASSERT(sc); + + edca = ic->ic_wme.wme_chanParams.cap_wmeParams; + + /* Set CWmin/CWmax values. */ + otus_write(sc, AR_MAC_REG_AC0_CW, + EXP2(edca[WME_AC_BE].wmep_logcwmax) << 16 | + EXP2(edca[WME_AC_BE].wmep_logcwmin)); + otus_write(sc, AR_MAC_REG_AC1_CW, + EXP2(edca[WME_AC_BK].wmep_logcwmax) << 16 | + EXP2(edca[WME_AC_BK].wmep_logcwmin)); + otus_write(sc, AR_MAC_REG_AC2_CW, + EXP2(edca[WME_AC_VI].wmep_logcwmax) << 16 | + EXP2(edca[WME_AC_VI].wmep_logcwmin)); + otus_write(sc, AR_MAC_REG_AC3_CW, + EXP2(edca[WME_AC_VO].wmep_logcwmax) << 16 | + EXP2(edca[WME_AC_VO].wmep_logcwmin)); + otus_write(sc, AR_MAC_REG_AC4_CW, /* Special TXQ. */ + EXP2(edca[WME_AC_VO].wmep_logcwmax) << 16 | + EXP2(edca[WME_AC_VO].wmep_logcwmin)); + + /* Set AIFSN values. */ + otus_write(sc, AR_MAC_REG_AC1_AC0_AIFS, + AIFS(edca[WME_AC_VI].wmep_aifsn) << 24 | + AIFS(edca[WME_AC_BK].wmep_aifsn) << 12 | + AIFS(edca[WME_AC_BE].wmep_aifsn)); + otus_write(sc, AR_MAC_REG_AC3_AC2_AIFS, + AIFS(edca[WME_AC_VO].wmep_aifsn) << 16 | /* Special TXQ. */ + AIFS(edca[WME_AC_VO].wmep_aifsn) << 4 | + AIFS(edca[WME_AC_VI].wmep_aifsn) >> 8); + + /* Set TXOP limit. */ + otus_write(sc, AR_MAC_REG_AC1_AC0_TXOP, + edca[WME_AC_BK].wmep_txopLimit << 16 | + edca[WME_AC_BE].wmep_txopLimit); + otus_write(sc, AR_MAC_REG_AC3_AC2_TXOP, + edca[WME_AC_VO].wmep_txopLimit << 16 | + edca[WME_AC_VI].wmep_txopLimit); + + /* XXX ACK policy? */ + + (void)otus_write_barrier(sc); + +#undef AIFS +#undef EXP2 +} + +static void +otus_updateslot(struct otus_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + uint32_t slottime; + + OTUS_LOCK_ASSERT(sc); + + slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; + otus_write(sc, AR_MAC_REG_SLOT_TIME, slottime << 10); + (void)otus_write_barrier(sc); +} + +int +otus_init_mac(struct otus_softc *sc) +{ + int error; + + OTUS_LOCK_ASSERT(sc); + + otus_write(sc, AR_MAC_REG_ACK_EXTENSION, 0x40); + otus_write(sc, AR_MAC_REG_RETRY_MAX, 0); + otus_write(sc, AR_MAC_REG_SNIFFER, 0x2000000); + otus_write(sc, AR_MAC_REG_RX_THRESHOLD, 0xc1f80); + otus_write(sc, AR_MAC_REG_RX_PE_DELAY, 0x70); + otus_write(sc, AR_MAC_REG_EIFS_AND_SIFS, 0xa144000); + otus_write(sc, AR_MAC_REG_SLOT_TIME, 9 << 10); + otus_write(sc, 0x1c3b2c, 0x19000000); + /* NAV protects ACK only (in TXOP). */ + otus_write(sc, 0x1c3b38, 0x201); + /* Set beacon Tx power to 0x7. */ + otus_write(sc, AR_MAC_REG_BCN_HT1, 0x8000170); + otus_write(sc, AR_MAC_REG_BACKOFF_PROTECT, 0x105); + otus_write(sc, 0x1c3b9c, 0x10000a); + /* Filter any control frames, BAR is bit 24. */ + otus_write(sc, 0x1c368c, 0x0500ffff); + otus_write(sc, 0x1c3c40, 0x1); + otus_write(sc, AR_MAC_REG_BASIC_RATE, 0x150f); + otus_write(sc, AR_MAC_REG_MANDATORY_RATE, 0x150f); + otus_write(sc, AR_MAC_REG_RTS_CTS_RATE, 0x10b01bb); + otus_write(sc, 0x1c3694, 0x4003c1e); + /* Enable LED0 and LED1. */ + otus_write(sc, 0x1d0100, 0x3); + otus_write(sc, 0x1d0104, 0x3); + /* Switch MAC to OTUS interface. */ + otus_write(sc, 0x1c3600, 0x3); + otus_write(sc, 0x1c3c50, 0xffff); + otus_write(sc, 0x1c3680, 0xf00008); + /* Disable Rx timeout (workaround). */ + otus_write(sc, 0x1c362c, 0); + + /* Set USB Rx stream mode maximum frame number to 2. */ + otus_write(sc, 0x1e1110, 0x4); + /* Set USB Rx stream mode timeout to 10us. */ + otus_write(sc, 0x1e1114, 0x80); + + /* Set clock frequency to 88/80MHz. */ + otus_write(sc, 0x1d4008, 0x73); + /* Set WLAN DMA interrupt mode: generate intr per packet. */ + otus_write(sc, 0x1c3d7c, 0x110011); + otus_write(sc, 0x1c3bb0, 0x4); + otus_write(sc, AR_MAC_REG_TXOP_NOT_ENOUGH_INDICATION, 0x141e0f48); + + /* Disable HW decryption for now. */ + otus_write(sc, 0x1c3678, 0x78); + + if ((error = otus_write_barrier(sc)) != 0) + return error; + + /* Set default EDCA parameters. */ + otus_updateedca(sc); + + return 0; +} + +/* + * Return default value for PHY register based on current operating mode. + */ +uint32_t +otus_phy_get_def(struct otus_softc *sc, uint32_t reg) +{ + int i; + + for (i = 0; i < nitems(ar5416_phy_regs); i++) + if (AR_PHY(ar5416_phy_regs[i]) == reg) + return sc->phy_vals[i]; + return 0; /* Register not found. */ +} + +/* + * Update PHY's programming based on vendor-specific data stored in EEPROM. + * This is for FEM-type devices only. + */ +int +otus_set_board_values(struct otus_softc *sc, struct ieee80211_channel *c) +{ + const struct ModalEepHeader *eep; + uint32_t tmp, offset; + + if (IEEE80211_IS_CHAN_5GHZ(c)) + eep = &sc->eeprom.modalHeader[0]; + else + eep = &sc->eeprom.modalHeader[1]; + + /* Offset of chain 2. */ + offset = 2 * 0x1000; + + tmp = le32toh(eep->antCtrlCommon); + otus_write(sc, AR_PHY_SWITCH_COM, tmp); + + tmp = le32toh(eep->antCtrlChain[0]); + otus_write(sc, AR_PHY_SWITCH_CHAIN_0, tmp); + + tmp = le32toh(eep->antCtrlChain[1]); + otus_write(sc, AR_PHY_SWITCH_CHAIN_0 + offset, tmp); + + if (1 /* sc->sc_sco == AR_SCO_SCN */) { + tmp = otus_phy_get_def(sc, AR_PHY_SETTLING); + tmp &= ~(0x7f << 7); + tmp |= (eep->switchSettling & 0x7f) << 7; + otus_write(sc, AR_PHY_SETTLING, tmp); + } + + tmp = otus_phy_get_def(sc, AR_PHY_DESIRED_SZ); + tmp &= ~0xffff; + tmp |= eep->pgaDesiredSize << 8 | eep->adcDesiredSize; + otus_write(sc, AR_PHY_DESIRED_SZ, tmp); + + tmp = eep->txEndToXpaOff << 24 | eep->txEndToXpaOff << 16 | + eep->txFrameToXpaOn << 8 | eep->txFrameToXpaOn; + otus_write(sc, AR_PHY_RF_CTL4, tmp); + + tmp = otus_phy_get_def(sc, AR_PHY_RF_CTL3); + tmp &= ~(0xff << 16); + tmp |= eep->txEndToRxOn << 16; + otus_write(sc, AR_PHY_RF_CTL3, tmp); + + tmp = otus_phy_get_def(sc, AR_PHY_CCA); + tmp &= ~(0x7f << 12); + tmp |= (eep->thresh62 & 0x7f) << 12; + otus_write(sc, AR_PHY_CCA, tmp); + + tmp = otus_phy_get_def(sc, AR_PHY_RXGAIN); + tmp &= ~(0x3f << 12); + tmp |= (eep->txRxAttenCh[0] & 0x3f) << 12; + otus_write(sc, AR_PHY_RXGAIN, tmp); + + tmp = otus_phy_get_def(sc, AR_PHY_RXGAIN + offset); + tmp &= ~(0x3f << 12); + tmp |= (eep->txRxAttenCh[1] & 0x3f) << 12; + otus_write(sc, AR_PHY_RXGAIN + offset, tmp); + + tmp = otus_phy_get_def(sc, AR_PHY_GAIN_2GHZ); + tmp &= ~(0x3f << 18); + tmp |= (eep->rxTxMarginCh[0] & 0x3f) << 18; + if (IEEE80211_IS_CHAN_5GHZ(c)) { + tmp &= ~(0xf << 10); + tmp |= (eep->bswMargin[0] & 0xf) << 10; + } + otus_write(sc, AR_PHY_GAIN_2GHZ, tmp); + + tmp = otus_phy_get_def(sc, AR_PHY_GAIN_2GHZ + offset); + tmp &= ~(0x3f << 18); + tmp |= (eep->rxTxMarginCh[1] & 0x3f) << 18; + otus_write(sc, AR_PHY_GAIN_2GHZ + offset, tmp); + + tmp = otus_phy_get_def(sc, AR_PHY_TIMING_CTRL4); + tmp &= ~(0x3f << 5 | 0x1f); + tmp |= (eep->iqCalICh[0] & 0x3f) << 5 | (eep->iqCalQCh[0] & 0x1f); + otus_write(sc, AR_PHY_TIMING_CTRL4, tmp); + + tmp = otus_phy_get_def(sc, AR_PHY_TIMING_CTRL4 + offset); + tmp &= ~(0x3f << 5 | 0x1f); + tmp |= (eep->iqCalICh[1] & 0x3f) << 5 | (eep->iqCalQCh[1] & 0x1f); + otus_write(sc, AR_PHY_TIMING_CTRL4 + offset, tmp); + + tmp = otus_phy_get_def(sc, AR_PHY_TPCRG1); + tmp &= ~(0xf << 16); + tmp |= (eep->xpd & 0xf) << 16; + otus_write(sc, AR_PHY_TPCRG1, tmp); + + return otus_write_barrier(sc); +} + +int +otus_program_phy(struct otus_softc *sc, struct ieee80211_channel *c) +{ + const uint32_t *vals; + int error, i; + + /* Select PHY programming based on band and bandwidth. */ + if (IEEE80211_IS_CHAN_2GHZ(c)) + vals = ar5416_phy_vals_2ghz_20mhz; + else + vals = ar5416_phy_vals_5ghz_20mhz; + for (i = 0; i < nitems(ar5416_phy_regs); i++) + otus_write(sc, AR_PHY(ar5416_phy_regs[i]), vals[i]); + sc->phy_vals = vals; + + if (sc->eeprom.baseEepHeader.deviceType == 0x80) /* FEM */ + if ((error = otus_set_board_values(sc, c)) != 0) + return error; + + /* Initial Tx power settings. */ + otus_write(sc, AR_PHY_POWER_TX_RATE_MAX, 0x7f); + otus_write(sc, AR_PHY_POWER_TX_RATE1, 0x3f3f3f3f); + otus_write(sc, AR_PHY_POWER_TX_RATE2, 0x3f3f3f3f); + otus_write(sc, AR_PHY_POWER_TX_RATE3, 0x3f3f3f3f); + otus_write(sc, AR_PHY_POWER_TX_RATE4, 0x3f3f3f3f); + otus_write(sc, AR_PHY_POWER_TX_RATE5, 0x3f3f3f3f); + otus_write(sc, AR_PHY_POWER_TX_RATE6, 0x3f3f3f3f); + otus_write(sc, AR_PHY_POWER_TX_RATE7, 0x3f3f3f3f); + otus_write(sc, AR_PHY_POWER_TX_RATE8, 0x3f3f3f3f); + otus_write(sc, AR_PHY_POWER_TX_RATE9, 0x3f3f3f3f); + + if (IEEE80211_IS_CHAN_2GHZ(c)) + otus_write(sc, 0x1d4014, 0x5163); + else + otus_write(sc, 0x1d4014, 0x5143); + + return otus_write_barrier(sc); +} + +static __inline uint8_t +otus_reverse_bits(uint8_t v) +{ + v = ((v >> 1) & 0x55) | ((v & 0x55) << 1); + v = ((v >> 2) & 0x33) | ((v & 0x33) << 2); + v = ((v >> 4) & 0x0f) | ((v & 0x0f) << 4); + return v; +} + +int +otus_set_rf_bank4(struct otus_softc *sc, struct ieee80211_channel *c) +{ + uint8_t chansel, d0, d1; + uint16_t data; + int error; + + OTUS_LOCK_ASSERT(sc); + + d0 = 0; + if (IEEE80211_IS_CHAN_5GHZ(c)) { + chansel = (c->ic_freq - 4800) / 5; + if (chansel & 1) + d0 |= AR_BANK4_AMODE_REFSEL(2); + else + d0 |= AR_BANK4_AMODE_REFSEL(1); + } else { + d0 |= AR_BANK4_AMODE_REFSEL(2); + if (c->ic_freq == 2484) { /* CH 14 */ + d0 |= AR_BANK4_BMODE_LF_SYNTH_FREQ; + chansel = 10 + (c->ic_freq - 2274) / 5; + } else + chansel = 16 + (c->ic_freq - 2272) / 5; + chansel <<= 2; + } + d0 |= AR_BANK4_ADDR(1) | AR_BANK4_CHUP; + d1 = otus_reverse_bits(chansel); + + /* Write bits 0-4 of d0 and d1. */ + data = (d1 & 0x1f) << 5 | (d0 & 0x1f); + otus_write(sc, AR_PHY(44), data); + /* Write bits 5-7 of d0 and d1. */ + data = (d1 >> 5) << 5 | (d0 >> 5); + otus_write(sc, AR_PHY(58), data); + + if ((error = otus_write_barrier(sc)) == 0) + otus_delay_ms(sc, 10); + return error; +} + +void +otus_get_delta_slope(uint32_t coeff, uint32_t *exponent, uint32_t *mantissa) +{ +#define COEFF_SCALE_SHIFT 24 + uint32_t exp, man; + + /* exponent = 14 - floor(log2(coeff)) */ + for (exp = 31; exp > 0; exp--) + if (coeff & (1 << exp)) + break; + KASSERT(exp != 0, ("exp")); + exp = 14 - (exp - COEFF_SCALE_SHIFT); + + /* mantissa = floor(coeff * 2^exponent + 0.5) */ + man = coeff + (1 << (COEFF_SCALE_SHIFT - exp - 1)); + + *mantissa = man >> (COEFF_SCALE_SHIFT - exp); + *exponent = exp - 16; +#undef COEFF_SCALE_SHIFT +} + +static int +otus_set_chan(struct otus_softc *sc, struct ieee80211_channel *c, int assoc) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ar_cmd_frequency cmd; + struct ar_rsp_frequency rsp; + const uint32_t *vals; + uint32_t coeff, exp, man, tmp; + uint8_t code; + int error, chan, i; + + error = 0; + chan = ieee80211_chan2ieee(ic, c); + + OTUS_DPRINTF(sc, OTUS_DEBUG_RESET, + "setting channel %d (%dMHz)\n", chan, c->ic_freq); + + tmp = IEEE80211_IS_CHAN_2GHZ(c) ? 0x105 : 0x104; + otus_write(sc, AR_MAC_REG_DYNAMIC_SIFS_ACK, tmp); + if ((error = otus_write_barrier(sc)) != 0) + goto finish; + + /* Disable BB Heavy Clip. */ + otus_write(sc, AR_PHY_HEAVY_CLIP_ENABLE, 0x200); + if ((error = otus_write_barrier(sc)) != 0) + goto finish; + + /* XXX Is that FREQ_START ? */ + error = otus_cmd(sc, AR_CMD_FREQ_STRAT, NULL, 0, NULL, 0); + if (error != 0) + goto finish; + + /* Reprogram PHY and RF on channel band or bandwidth changes. */ + if (sc->bb_reset || c->ic_flags != sc->sc_curchan->ic_flags) { + OTUS_DPRINTF(sc, OTUS_DEBUG_RESET, "band switch\n"); + + /* Cold/Warm reset BB/ADDA. */ + otus_write(sc, 0x1d4004, sc->bb_reset ? 0x800 : 0x400); + if ((error = otus_write_barrier(sc)) != 0) + goto finish; + otus_write(sc, 0x1d4004, 0); + if ((error = otus_write_barrier(sc)) != 0) + goto finish; + sc->bb_reset = 0; + + if ((error = otus_program_phy(sc, c)) != 0) { + device_printf(sc->sc_dev, + "%s: could not program PHY\n", + __func__); + goto finish; + } + + /* Select RF programming based on band. */ + if (IEEE80211_IS_CHAN_5GHZ(c)) + vals = ar5416_banks_vals_5ghz; + else + vals = ar5416_banks_vals_2ghz; + for (i = 0; i < nitems(ar5416_banks_regs); i++) + otus_write(sc, AR_PHY(ar5416_banks_regs[i]), vals[i]); + if ((error = otus_write_barrier(sc)) != 0) { + device_printf(sc->sc_dev, + "%s: could not program RF\n", + __func__); + goto finish; + } + code = AR_CMD_RF_INIT; + } else { + code = AR_CMD_FREQUENCY; + } + + if ((error = otus_set_rf_bank4(sc, c)) != 0) + goto finish; + + tmp = (sc->txmask == 0x5) ? 0x340 : 0x240; + otus_write(sc, AR_PHY_TURBO, tmp); + if ((error = otus_write_barrier(sc)) != 0) + goto finish; + + /* Send firmware command to set channel. */ + cmd.freq = htole32((uint32_t)c->ic_freq * 1000); + cmd.dynht2040 = htole32(0); + cmd.htena = htole32(1); + /* Set Delta Slope (exponent and mantissa). */ + coeff = (100 << 24) / c->ic_freq; + otus_get_delta_slope(coeff, &exp, &man); + cmd.dsc_exp = htole32(exp); + cmd.dsc_man = htole32(man); + OTUS_DPRINTF(sc, OTUS_DEBUG_RESET, + "ds coeff=%u exp=%u man=%u\n", coeff, exp, man); + /* For Short GI, coeff is 9/10 that of normal coeff. */ + coeff = (9 * coeff) / 10; + otus_get_delta_slope(coeff, &exp, &man); + cmd.dsc_shgi_exp = htole32(exp); + cmd.dsc_shgi_man = htole32(man); + OTUS_DPRINTF(sc, OTUS_DEBUG_RESET, + "ds shgi coeff=%u exp=%u man=%u\n", coeff, exp, man); + /* Set wait time for AGC and noise calibration (100 or 200ms). */ + cmd.check_loop_count = assoc ? htole32(2000) : htole32(1000); + OTUS_DPRINTF(sc, OTUS_DEBUG_RESET, + "%s\n", (code == AR_CMD_RF_INIT) ? "RF_INIT" : "FREQUENCY"); + error = otus_cmd(sc, code, &cmd, sizeof cmd, &rsp, sizeof(rsp)); + if (error != 0) + goto finish; + if ((rsp.status & htole32(AR_CAL_ERR_AGC | AR_CAL_ERR_NF_VAL)) != 0) { + OTUS_DPRINTF(sc, OTUS_DEBUG_RESET, + "status=0x%x\n", le32toh(rsp.status)); + /* Force cold reset on next channel. */ + sc->bb_reset = 1; + } +#ifdef USB_DEBUG + if (otus_debug & OTUS_DEBUG_RESET) { + device_printf(sc->sc_dev, "calibration status=0x%x\n", + le32toh(rsp.status)); + for (i = 0; i < 2; i++) { /* 2 Rx chains */ + /* Sign-extend 9-bit NF values. */ + device_printf(sc->sc_dev, + "noisefloor chain %d=%d\n", i, + (((int32_t)le32toh(rsp.nf[i])) << 4) >> 23); + device_printf(sc->sc_dev, + "noisefloor ext chain %d=%d\n", i, + ((int32_t)le32toh(rsp.nf_ext[i])) >> 23); + } + } +#endif + for (i = 0; i < OTUS_NUM_CHAINS; i++) { + sc->sc_nf[i] = ((((int32_t)le32toh(rsp.nf[i])) << 4) >> 23); + } + sc->sc_curchan = c; +finish: + return (error); +} + +#ifdef notyet +int +otus_set_key(struct ieee80211com *ic, struct ieee80211_node *ni, + struct ieee80211_key *k) +{ + struct otus_softc *sc = ic->ic_softc; + struct otus_cmd_key cmd; + + /* Defer setting of WEP keys until interface is brought up. */ + if ((ic->ic_if.if_flags & (IFF_UP | IFF_RUNNING)) != + (IFF_UP | IFF_RUNNING)) + return 0; + + /* Do it in a process context. */ + cmd.key = *k; + cmd.associd = (ni != NULL) ? ni->ni_associd : 0; + otus_do_async(sc, otus_set_key_cb, &cmd, sizeof cmd); + return 0; +} + +void +otus_set_key_cb(struct otus_softc *sc, void *arg) +{ + struct otus_cmd_key *cmd = arg; + struct ieee80211_key *k = &cmd->key; + struct ar_cmd_ekey key; + uint16_t cipher; + int error; + + memset(&key, 0, sizeof key); + if (k->k_flags & IEEE80211_KEY_GROUP) { + key.uid = htole16(k->k_id); + IEEE80211_ADDR_COPY(key.macaddr, sc->sc_ic.ic_myaddr); + key.macaddr[0] |= 0x80; + } else { + key.uid = htole16(OTUS_UID(cmd->associd)); + IEEE80211_ADDR_COPY(key.macaddr, ni->ni_macaddr); + } + key.kix = htole16(0); + /* Map net80211 cipher to hardware. */ + switch (k->k_cipher) { + case IEEE80211_CIPHER_WEP40: + cipher = AR_CIPHER_WEP64; + break; + case IEEE80211_CIPHER_WEP104: + cipher = AR_CIPHER_WEP128; + break; + case IEEE80211_CIPHER_TKIP: + cipher = AR_CIPHER_TKIP; + break; + case IEEE80211_CIPHER_CCMP: + cipher = AR_CIPHER_AES; + break; + default: + return; + } + key.cipher = htole16(cipher); + memcpy(key.key, k->k_key, MIN(k->k_len, 16)); + error = otus_cmd(sc, AR_CMD_EKEY, &key, sizeof key, NULL, 0); + if (error != 0 || k->k_cipher != IEEE80211_CIPHER_TKIP) + return; + + /* TKIP: set Tx/Rx MIC Key. */ + key.kix = htole16(1); + memcpy(key.key, k->k_key + 16, 16); + (void)otus_cmd(sc, AR_CMD_EKEY, &key, sizeof key, NULL, 0); +} + +void +otus_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni, + struct ieee80211_key *k) +{ + struct otus_softc *sc = ic->ic_softc; + struct otus_cmd_key cmd; + + if (!(ic->ic_if.if_flags & IFF_RUNNING) || + ic->ic_state != IEEE80211_S_RUN) + return; /* Nothing to do. */ + + /* Do it in a process context. */ + cmd.key = *k; + cmd.associd = (ni != NULL) ? ni->ni_associd : 0; + otus_do_async(sc, otus_delete_key_cb, &cmd, sizeof cmd); +} + +void +otus_delete_key_cb(struct otus_softc *sc, void *arg) +{ + struct otus_cmd_key *cmd = arg; + struct ieee80211_key *k = &cmd->key; + uint32_t uid; + + if (k->k_flags & IEEE80211_KEY_GROUP) + uid = htole32(k->k_id); + else + uid = htole32(OTUS_UID(cmd->associd)); + (void)otus_cmd(sc, AR_CMD_DKEY, &uid, sizeof uid, NULL, 0); +} +#endif + +/* + * XXX TODO: check if we have to be doing any calibration in the host + * or whether it's purely a firmware thing. + */ +void +otus_calibrate_to(void *arg, int pending) +{ +#if 0 + struct otus_softc *sc = arg; + + device_printf(sc->sc_dev, "%s: called\n", __func__); + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node *ni; + int s; + + if (usbd_is_dying(sc->sc_udev)) + return; + + usbd_ref_incr(sc->sc_udev); + + s = splnet(); + ni = ic->ic_bss; + ieee80211_amrr_choose(&sc->amrr, ni, &((struct otus_node *)ni)->amn); + splx(s); + + if (!usbd_is_dying(sc->sc_udev)) + timeout_add_sec(&sc->calib_to, 1); + + usbd_ref_decr(sc->sc_udev); +#endif +} + +int +otus_set_bssid(struct otus_softc *sc, const uint8_t *bssid) +{ + + OTUS_LOCK_ASSERT(sc); + + otus_write(sc, AR_MAC_REG_BSSID_L, + bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24); + otus_write(sc, AR_MAC_REG_BSSID_H, + bssid[4] | bssid[5] << 8); + return otus_write_barrier(sc); +} + +int +otus_set_macaddr(struct otus_softc *sc, const uint8_t *addr) +{ + OTUS_LOCK_ASSERT(sc); + + otus_write(sc, AR_MAC_REG_MAC_ADDR_L, + addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24); + otus_write(sc, AR_MAC_REG_MAC_ADDR_H, + addr[4] | addr[5] << 8); + return otus_write_barrier(sc); +} + +/* Default single-LED. */ +void +otus_led_newstate_type1(struct otus_softc *sc) +{ + /* TBD */ + device_printf(sc->sc_dev, "%s: TODO\n", __func__); +} + +/* NETGEAR, dual-LED. */ +void +otus_led_newstate_type2(struct otus_softc *sc) +{ + /* TBD */ + device_printf(sc->sc_dev, "%s: TODO\n", __func__); +} + +/* NETGEAR, single-LED/3 colors (blue, red, purple.) */ +void +otus_led_newstate_type3(struct otus_softc *sc) +{ +#if 0 + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + + uint32_t state = sc->led_state; + + OTUS_LOCK_ASSERT(sc); + + if (!vap) { + state = 0; /* led off */ + } else if (vap->iv_state == IEEE80211_S_INIT) { + state = 0; /* LED off. */ + } else if (vap->iv_state == IEEE80211_S_RUN) { + /* Associated, LED always on. */ + if (IEEE80211_IS_CHAN_2GHZ(sc->sc_curchan)) + state = AR_LED0_ON; /* 2GHz=>Red. */ + else + state = AR_LED1_ON; /* 5GHz=>Blue. */ + } else { + /* Scanning, blink LED. */ + state ^= AR_LED0_ON | AR_LED1_ON; + if (IEEE80211_IS_CHAN_2GHZ(sc->sc_curchan)) + state &= ~AR_LED1_ON; + else + state &= ~AR_LED0_ON; + } + if (state != sc->led_state) { + otus_write(sc, 0x1d0104, state); + if (otus_write_barrier(sc) == 0) + sc->led_state = state; + } +#endif +} + +int +otus_init(struct otus_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + int error; + + OTUS_UNLOCK_ASSERT(sc); + + OTUS_LOCK(sc); + + /* Drain any pending TX frames */ + otus_drain_mbufq(sc); + + /* Init MAC */ + if ((error = otus_init_mac(sc)) != 0) { + OTUS_UNLOCK(sc); + device_printf(sc->sc_dev, + "%s: could not initialize MAC\n", __func__); + return error; + } + + (void) otus_set_macaddr(sc, ic->ic_macaddr); + +#if 0 + switch (ic->ic_opmode) { +#ifdef notyet +#ifndef IEEE80211_STA_ONLY + case IEEE80211_M_HOSTAP: + otus_write(sc, 0x1c3700, 0x0f0000a1); + otus_write(sc, 0x1c3c40, 0x1); + break; + case IEEE80211_M_IBSS: + otus_write(sc, 0x1c3700, 0x0f000000); + otus_write(sc, 0x1c3c40, 0x1); + break; +#endif +#endif + case IEEE80211_M_STA: + otus_write(sc, 0x1c3700, 0x0f000002); + otus_write(sc, 0x1c3c40, 0x1); + break; + default: + break; + } +#endif + + /* Expect STA operation */ + otus_write(sc, 0x1c3700, 0x0f000002); + otus_write(sc, 0x1c3c40, 0x1); + + /* XXX ic_opmode? */ + otus_write(sc, AR_MAC_REG_SNIFFER, + (ic->ic_opmode == IEEE80211_M_MONITOR) ? 0x2000001 : 0x2000000); + (void)otus_write_barrier(sc); + + sc->bb_reset = 1; /* Force cold reset. */ + + if ((error = otus_set_chan(sc, ic->ic_curchan, 0)) != 0) { + OTUS_UNLOCK(sc); + device_printf(sc->sc_dev, + "%s: could not set channel\n", __func__); + return error; + } + + /* Start Rx. */ + otus_write(sc, 0x1c3d30, 0x100); + (void)otus_write_barrier(sc); + + sc->sc_running = 1; + + OTUS_UNLOCK(sc); + return 0; +} + +void +otus_stop(struct otus_softc *sc) +{ +#if 0 + int s; +#endif + + OTUS_UNLOCK_ASSERT(sc); + + OTUS_LOCK(sc); + sc->sc_running = 0; + sc->sc_tx_timer = 0; + OTUS_UNLOCK(sc); + + taskqueue_drain_timeout(taskqueue_thread, &sc->scan_to); + taskqueue_drain_timeout(taskqueue_thread, &sc->calib_to); + taskqueue_drain(taskqueue_thread, &sc->tx_task); + taskqueue_drain(taskqueue_thread, &sc->wme_update_task); + + OTUS_LOCK(sc); + sc->sc_running = 0; + /* Stop Rx. */ + otus_write(sc, 0x1c3d30, 0); + (void)otus_write_barrier(sc); + + /* Drain any pending TX frames */ + otus_drain_mbufq(sc); + + OTUS_UNLOCK(sc); +} diff --git a/sys/dev/otus/if_otusreg.h b/sys/dev/otus/if_otusreg.h new file mode 100644 index 0000000000000..4f11b8dfd772c --- /dev/null +++ b/sys/dev/otus/if_otusreg.h @@ -0,0 +1,1030 @@ +/* $OpenBSD: if_otusreg.h,v 1.9 2013/11/26 20:33:18 deraadt Exp $ */ + +/*- + * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr> + * Copyright (c) 2007-2008 Atheros Communications, Inc. + * Copyright (c) 2015 Adrian Chadd <adrian@FreeBSD.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ +#ifndef __IF_OTUSREG_H__ +#define __IF_OTUSREG_H__ + +/* USB Endpoints addresses. */ +#define AR_EPT_BULK_TX_NO (UE_DIR_OUT | 1) +#define AR_EPT_BULK_RX_NO (UE_DIR_IN | 2) +#define AR_EPT_INTR_RX_NO (UE_DIR_IN | 3) +#define AR_EPT_INTR_TX_NO (UE_DIR_OUT | 4) + +/* USB Requests. */ +#define AR_FW_DOWNLOAD 0x30 +#define AR_FW_DOWNLOAD_COMPLETE 0x31 + +/* Maximum number of writes that can fit in a single FW command is 7. */ +#define AR_MAX_WRITE_IDX 6 /* 56 bytes */ + +#define AR_FW_INIT_ADDR 0x102800 +#define AR_FW_MAIN_ADDR 0x200000 +#define AR_USB_MODE_CTRL 0x1e1108 + +/* + * AR9170 MAC registers. + */ +#define AR_MAC_REG_BASE 0x1c3000 +#define AR_MAC_REG_MAC_ADDR_L (AR_MAC_REG_BASE + 0x610) +#define AR_MAC_REG_MAC_ADDR_H (AR_MAC_REG_BASE + 0x614) +#define AR_MAC_REG_BSSID_L (AR_MAC_REG_BASE + 0x618) +#define AR_MAC_REG_BSSID_H (AR_MAC_REG_BASE + 0x61c) +#define AR_MAC_REG_GROUP_HASH_TBL_L (AR_MAC_REG_BASE + 0x624) +#define AR_MAC_REG_GROUP_HASH_TBL_H (AR_MAC_REG_BASE + 0x628) +#define AR_MAC_REG_BASIC_RATE (AR_MAC_REG_BASE + 0x630) +#define AR_MAC_REG_MANDATORY_RATE (AR_MAC_REG_BASE + 0x634) +#define AR_MAC_REG_RTS_CTS_RATE (AR_MAC_REG_BASE + 0x638) +#define AR_MAC_REG_BACKOFF_PROTECT (AR_MAC_REG_BASE + 0x63c) +#define AR_MAC_REG_RX_THRESHOLD (AR_MAC_REG_BASE + 0x640) +#define AR_MAC_REG_RX_PE_DELAY (AR_MAC_REG_BASE + 0x64c) +#define AR_MAC_REG_DYNAMIC_SIFS_ACK (AR_MAC_REG_BASE + 0x658) +#define AR_MAC_REG_SNIFFER (AR_MAC_REG_BASE + 0x674) +#define AR_MAC_REG_ACK_EXTENSION (AR_MAC_REG_BASE + 0x690) +#define AR_MAC_REG_EIFS_AND_SIFS (AR_MAC_REG_BASE + 0x698) +#define AR_MAC_REG_BUSY (AR_MAC_REG_BASE + 0x6e8) +#define AR_MAC_REG_BUSY_EXT (AR_MAC_REG_BASE + 0x6ec) +#define AR_MAC_REG_SLOT_TIME (AR_MAC_REG_BASE + 0x6f0) +#define AR_MAC_REG_AC0_CW (AR_MAC_REG_BASE + 0xb00) +#define AR_MAC_REG_AC1_CW (AR_MAC_REG_BASE + 0xb04) +#define AR_MAC_REG_AC2_CW (AR_MAC_REG_BASE + 0xb08) +#define AR_MAC_REG_AC3_CW (AR_MAC_REG_BASE + 0xb0c) +#define AR_MAC_REG_AC4_CW (AR_MAC_REG_BASE + 0xb10) +#define AR_MAC_REG_AC1_AC0_AIFS (AR_MAC_REG_BASE + 0xb14) +#define AR_MAC_REG_AC3_AC2_AIFS (AR_MAC_REG_BASE + 0xb18) +#define AR_MAC_REG_RETRY_MAX (AR_MAC_REG_BASE + 0xb28) +#define AR_MAC_REG_TXOP_NOT_ENOUGH_INDICATION \ + (AR_MAC_REG_BASE + 0xb30) +#define AR_MAC_REG_AC1_AC0_TXOP (AR_MAC_REG_BASE + 0xb44) +#define AR_MAC_REG_AC3_AC2_TXOP (AR_MAC_REG_BASE + 0xb48) +#define AR_MAC_REG_OFDM_PHY_ERRORS (AR_MAC_REG_BASE + 0xcb4) +#define AR_MAC_REG_CCK_PHY_ERRORS (AR_MAC_REG_BASE + 0xcb8) +#define AR_MAC_REG_BCN_HT1 (AR_MAC_REG_BASE + 0xda0) + +/* Possible values for register AR_USB_MODE_CTRL. */ +#define AR_USB_DS_ENA (1 << 0) +#define AR_USB_US_ENA (1 << 1) +#define AR_USB_US_PACKET_MODE (1 << 3) +#define AR_USB_RX_STREAM_4K (0 << 4) +#define AR_USB_RX_STREAM_8K (1 << 4) +#define AR_USB_RX_STREAM_16K (2 << 4) +#define AR_USB_RX_STREAM_32K (3 << 4) +#define AR_USB_TX_STREAM_MODE (1 << 6) + +#define AR_LED0_ON (1 << 0) +#define AR_LED1_ON (1 << 1) + +/* + * PHY registers. + */ +#define AR_PHY_BASE 0x1c5800 +#define AR_PHY(reg) (AR_PHY_BASE + (reg) * 4) +#define AR_PHY_TURBO (AR_PHY_BASE + 0x0004) +#define AR_PHY_RF_CTL3 (AR_PHY_BASE + 0x0028) +#define AR_PHY_RF_CTL4 (AR_PHY_BASE + 0x0034) +#define AR_PHY_SETTLING (AR_PHY_BASE + 0x0044) +#define AR_PHY_RXGAIN (AR_PHY_BASE + 0x0048) +#define AR_PHY_DESIRED_SZ (AR_PHY_BASE + 0x0050) +#define AR_PHY_FIND_SIG (AR_PHY_BASE + 0x0058) +#define AR_PHY_AGC_CTL1 (AR_PHY_BASE + 0x005c) +#define AR_PHY_SFCORR (AR_PHY_BASE + 0x0068) +#define AR_PHY_SFCORR_LOW (AR_PHY_BASE + 0x006c) +#define AR_PHY_TIMING_CTRL4 (AR_PHY_BASE + 0x0120) +#define AR_PHY_TIMING5 (AR_PHY_BASE + 0x0124) +#define AR_PHY_POWER_TX_RATE1 (AR_PHY_BASE + 0x0134) +#define AR_PHY_POWER_TX_RATE2 (AR_PHY_BASE + 0x0138) +#define AR_PHY_POWER_TX_RATE_MAX (AR_PHY_BASE + 0x013c) +#define AR_PHY_SWITCH_CHAIN_0 (AR_PHY_BASE + 0x0160) +#define AR_PHY_SWITCH_COM (AR_PHY_BASE + 0x0164) +#define AR_PHY_HEAVY_CLIP_ENABLE (AR_PHY_BASE + 0x01e0) +#define AR_PHY_CCK_DETECT (AR_PHY_BASE + 0x0a08) +#define AR_PHY_GAIN_2GHZ (AR_PHY_BASE + 0x0a0c) +#define AR_PHY_POWER_TX_RATE3 (AR_PHY_BASE + 0x0a34) +#define AR_PHY_POWER_TX_RATE4 (AR_PHY_BASE + 0x0a38) +#define AR_PHY_TPCRG1 (AR_PHY_BASE + 0x0a58) +#define AR_PHY_POWER_TX_RATE5 (AR_PHY_BASE + 0x0b8c) +#define AR_PHY_POWER_TX_RATE6 (AR_PHY_BASE + 0x0b90) +#define AR_PHY_POWER_TX_RATE7 (AR_PHY_BASE + 0x0bcc) +#define AR_PHY_POWER_TX_RATE8 (AR_PHY_BASE + 0x0bd0) +#define AR_PHY_POWER_TX_RATE9 (AR_PHY_BASE + 0x0bd4) +#define AR_PHY_CCA (AR_PHY_BASE + 0x3064) + +#define AR_SEEPROM_HW_TYPE_OFFSET 0x1374 +#define AR_EEPROM_OFFSET 0x1600 + +#define AR_BANK4_CHUP (1 << 0) +#define AR_BANK4_BMODE_LF_SYNTH_FREQ (1 << 1) +#define AR_BANK4_AMODE_REFSEL(x) ((x) << 2) +#define AR_BANK4_ADDR(x) ((x) << 5) + +/* Tx descriptor. */ +struct ar_tx_head { + uint16_t len; + uint16_t macctl; +#define AR_TX_MAC_RTS (1 << 0) +#define AR_TX_MAC_CTS (1 << 1) +#define AR_TX_MAC_BACKOFF (1 << 3) +#define AR_TX_MAC_NOACK (1 << 2) +#define AR_TX_MAC_HW_DUR (1 << 9) +#define AR_TX_MAC_QID(qid) ((qid) << 10) +#define AR_TX_MAC_RATE_PROBING (1 << 15) + + uint32_t phyctl; +/* Modulation type. */ +#define AR_TX_PHY_MT_CCK 0 +#define AR_TX_PHY_MT_OFDM 1 +#define AR_TX_PHY_MT_HT 2 +#define AR_TX_PHY_GF (1 << 2) +#define AR_TX_PHY_BW_SHIFT 3 +#define AR_TX_PHY_TPC_SHIFT 9 +#define AR_TX_PHY_ANTMSK(msk) ((msk) << 15) +#define AR_TX_PHY_MCS(mcs) ((mcs) << 18) +#define AR_TX_PHY_SHGI (1U << 31) +} __packed; + +/* USB Rx stream mode header. */ +struct ar_rx_head { + uint16_t len; + uint16_t tag; +#define AR_RX_HEAD_TAG 0x4e00 +} __packed; + +/* Rx descriptor. */ +struct ar_rx_tail { + uint8_t rssi_ant[3]; + uint8_t rssi_ant_ext[3]; + uint8_t rssi; /* Combined RSSI. */ + uint8_t evm[2][6]; /* Error Vector Magnitude. */ + uint8_t phy_err; + uint8_t sa_idx; + uint8_t da_idx; + uint8_t error; +#define AR_RX_ERROR_TIMEOUT (1 << 0) +#define AR_RX_ERROR_OVERRUN (1 << 1) +#define AR_RX_ERROR_DECRYPT (1 << 2) +#define AR_RX_ERROR_FCS (1 << 3) +#define AR_RX_ERROR_BAD_RA (1 << 4) +#define AR_RX_ERROR_PLCP (1 << 5) +#define AR_RX_ERROR_MMIC (1 << 6) + + uint8_t status; +/* Modulation type (same as AR_TX_PHY_MT). */ +#define AR_RX_STATUS_MT_MASK 0x3 +#define AR_RX_STATUS_MT_CCK 0 +#define AR_RX_STATUS_MT_OFDM 1 +#define AR_RX_STATUS_MT_HT 2 +#define AR_RX_STATUS_SHPREAMBLE (1 << 3) +} __packed; + +#define AR_PLCP_HDR_LEN 12 +/* Magic PLCP header for firmware notifications through Rx bulk pipe. */ +static uint8_t AR_PLCP_HDR_INTR[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +/* Firmware command/reply header. */ +struct ar_cmd_hdr { + uint8_t len; + uint8_t code; +#define AR_CMD_RREG 0x00 +#define AR_CMD_WREG 0x01 +#define AR_CMD_RMEM 0x02 +#define AR_CMD_WMEM 0x03 +#define AR_CMD_BITAND 0x04 +#define AR_CMD_BITOR 0x05 +#define AR_CMD_EKEY 0x28 +#define AR_CMD_DKEY 0x29 +#define AR_CMD_FREQUENCY 0x30 +#define AR_CMD_RF_INIT 0x31 +#define AR_CMD_SYNTH 0x32 +#define AR_CMD_FREQ_STRAT 0x33 +#define AR_CMD_ECHO 0x80 +#define AR_CMD_TALLY 0x81 +#define AR_CMD_TALLY_APD 0x82 +#define AR_CMD_CONFIG 0x83 +#define AR_CMD_RESET 0x90 +#define AR_CMD_DKRESET 0x91 +#define AR_CMD_DKTX_STATUS 0x92 +#define AR_CMD_FDC 0xa0 +#define AR_CMD_WREEPROM 0xb0 +#define AR_CMD_WFLASH AR_CMD_WREEPROM +#define AR_CMD_FLASH_ERASE 0xb1 +#define AR_CMD_FLASH_PROG 0xb2 +#define AR_CMD_FLASH_CHKSUM 0xb3 +#define AR_CMD_FLASH_READ 0xb4 +#define AR_CMD_FW_DL_INIT 0xb5 +#define AR_CMD_MEM_WREEPROM 0xbb +/* Those have the 2 MSB set to 1. */ +#define AR_EVT_BEACON 0x00 +#define AR_EVT_TX_COMP 0x01 +#define AR_EVT_TBTT 0x02 +#define AR_EVT_ATIM 0x03 +#define AR_EVT_DO_BB_RESET 0x09 + + uint16_t token; /* Driver private data. */ +} __packed; + +/* Structure for command AR_CMD_RF_INIT/AR_CMD_FREQUENCY. */ +struct ar_cmd_frequency { + uint32_t freq; + uint32_t dynht2040; + uint32_t htena; + uint32_t dsc_exp; + uint32_t dsc_man; + uint32_t dsc_shgi_exp; + uint32_t dsc_shgi_man; + uint32_t check_loop_count; +} __packed; + +/* Firmware reply for command AR_CMD_FREQUENCY. */ +struct ar_rsp_frequency { + uint32_t status; +#define AR_CAL_ERR_AGC (1 << 0) /* AGC cal unfinished. */ +#define AR_CAL_ERR_NF (1 << 1) /* Noise cal unfinished. */ +#define AR_CAL_ERR_NF_VAL (1 << 2) /* NF value unexpected. */ + + uint32_t nf[3]; /* Noisefloor. */ + uint32_t nf_ext[3]; /* Noisefloor ext. */ +} __packed; + +/* Structure for command AR_CMD_EKEY. */ +struct ar_cmd_ekey { + uint16_t uid; /* user ID */ + uint16_t kix; + uint16_t cipher; +#define AR_CIPHER_NONE 0 +#define AR_CIPHER_WEP64 1 +#define AR_CIPHER_TKIP 2 +#define AR_CIPHER_AES 4 +#define AR_CIPHER_WEP128 5 +#define AR_CIPHER_WEP256 6 +#define AR_CIPHER_CENC 7 + + uint8_t macaddr[IEEE80211_ADDR_LEN]; + uint8_t key[16]; +} __packed; + +/* Structure for event AR_EVT_TX_COMP. */ +struct ar_evt_tx_comp { + uint8_t macaddr[IEEE80211_ADDR_LEN]; + uint32_t phy; + uint16_t status; +#define AR_TX_STATUS_COMP 0 +#define AR_TX_STATUS_RETRY_COMP 1 +#define AR_TX_STATUS_FAILED 2 +} __packed; + +/* List of supported channels. */ +static const uint8_t ar_chans[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, + 128, 132, 136, 140, 149, 153, 157, 161, 165, 34, 38, 42, 46 +}; + +/* + * This data is automatically generated from the "otus.ini" file. + * It is stored in a different way though, to reduce kernel's .rodata + * section overhead (5.1KB instead of 8.5KB). + */ + +/* NB: apply AR_PHY(). */ +static const uint16_t ar5416_phy_regs[] = { + 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, 0x008, + 0x009, 0x00a, 0x00b, 0x00c, 0x00d, 0x00e, 0x00f, 0x010, 0x011, + 0x012, 0x013, 0x014, 0x015, 0x016, 0x017, 0x018, 0x01a, 0x01b, + 0x040, 0x041, 0x042, 0x043, 0x045, 0x046, 0x047, 0x048, 0x049, + 0x04a, 0x04b, 0x04d, 0x04e, 0x04f, 0x051, 0x052, 0x053, 0x055, + 0x056, 0x058, 0x059, 0x05c, 0x05d, 0x05e, 0x05f, 0x060, 0x061, + 0x062, 0x063, 0x064, 0x065, 0x066, 0x067, 0x068, 0x069, 0x06a, + 0x06b, 0x06c, 0x06d, 0x070, 0x071, 0x072, 0x073, 0x074, 0x075, + 0x076, 0x077, 0x078, 0x079, 0x07a, 0x07b, 0x07c, 0x07f, 0x080, + 0x081, 0x082, 0x083, 0x084, 0x085, 0x086, 0x087, 0x088, 0x089, + 0x08a, 0x08b, 0x08c, 0x08d, 0x08e, 0x08f, 0x090, 0x091, 0x092, + 0x093, 0x094, 0x095, 0x096, 0x097, 0x098, 0x099, 0x09a, 0x09b, + 0x09c, 0x09d, 0x09e, 0x09f, 0x0a0, 0x0a1, 0x0a2, 0x0a3, 0x0a4, + 0x0a5, 0x0a6, 0x0a7, 0x0a8, 0x0a9, 0x0aa, 0x0ab, 0x0ac, 0x0ad, + 0x0ae, 0x0af, 0x0b0, 0x0b1, 0x0b2, 0x0b3, 0x0b4, 0x0b5, 0x0b6, + 0x0b7, 0x0b8, 0x0b9, 0x0ba, 0x0bb, 0x0bc, 0x0bd, 0x0be, 0x0bf, + 0x0c0, 0x0c1, 0x0c2, 0x0c3, 0x0c4, 0x0c5, 0x0c6, 0x0c7, 0x0c8, + 0x0c9, 0x0ca, 0x0cb, 0x0cc, 0x0cd, 0x0ce, 0x0cf, 0x0d0, 0x0d1, + 0x0d2, 0x0d3, 0x0d4, 0x0d5, 0x0d6, 0x0d7, 0x0d8, 0x0d9, 0x0da, + 0x0db, 0x0dc, 0x0dd, 0x0de, 0x0df, 0x0e0, 0x0e1, 0x0e2, 0x0e3, + 0x0e4, 0x0e5, 0x0e6, 0x0e7, 0x0e8, 0x0e9, 0x0ea, 0x0eb, 0x0ec, + 0x0ed, 0x0ee, 0x0ef, 0x0f0, 0x0f1, 0x0f2, 0x0f3, 0x0f4, 0x0f5, + 0x0f6, 0x0f7, 0x0f8, 0x0f9, 0x0fa, 0x0fb, 0x0fc, 0x0fd, 0x0fe, + 0x0ff, 0x100, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, + 0x10a, 0x10b, 0x10c, 0x10d, 0x10e, 0x10f, 0x13c, 0x13d, 0x13e, + 0x13f, 0x280, 0x281, 0x282, 0x283, 0x284, 0x285, 0x286, 0x287, + 0x288, 0x289, 0x28a, 0x28b, 0x28c, 0x28d, 0x28e, 0x28f, 0x290, + 0x291, 0x292, 0x293, 0x294, 0x295, 0x296, 0x297, 0x298, 0x299, + 0x29a, 0x29b, 0x29d, 0x29e, 0x29f, 0x2c0, 0x2c1, 0x2c2, 0x2c3, + 0x2c4, 0x2c5, 0x2c6, 0x2c7, 0x2c8, 0x2c9, 0x2ca, 0x2cb, 0x2cc, + 0x2cd, 0x2ce, 0x2cf, 0x2d0, 0x2d1, 0x2d2, 0x2d3, 0x2d4, 0x2d5, + 0x2d6, 0x2e2, 0x2e3, 0x2e4, 0x2e5, 0x2e6, 0x2e7, 0x2e8, 0x2e9, + 0x2ea, 0x2eb, 0x2ec, 0x2ed, 0x2ee, 0x2ef, 0x2f0, 0x2f1, 0x2f2, + 0x2f3, 0x2f4, 0x2f5, 0x2f6, 0x2f7, 0x2f8, 0x412, 0x448, 0x458, + 0x683, 0x69b, 0x812, 0x848, 0x858, 0xa83, 0xa9b, 0xc19, 0xc57, + 0xc5a, 0xc6f, 0xe9c, 0xed7, 0xed8, 0xed9, 0xeda, 0xedb, 0xedc, + 0xedd, 0xede, 0xedf, 0xee0, 0xee1 +}; + +static const uint32_t ar5416_phy_vals_5ghz_20mhz[] = { + 0x00000007, 0x00000300, 0x00000000, 0xad848e19, 0x7d14e000, + 0x9c0a9f6b, 0x00000090, 0x00000000, 0x02020200, 0x00000e0e, + 0x0a020001, 0x0000a000, 0x00000000, 0x00000e0e, 0x00000007, + 0x00200400, 0x206a002e, 0x1372161e, 0x001a6a65, 0x1284233c, + 0x6c48b4e4, 0x00000859, 0x7ec80d2e, 0x31395c5e, 0x0004dd10, + 0x409a4190, 0x050cb081, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x000007d0, 0x00000118, 0x10000fff, 0x0510081c, + 0xd0058a15, 0x00000001, 0x00000004, 0x3f3f3f3f, 0x3f3f3f3f, + 0x0000007f, 0xdfb81020, 0x9280b212, 0x00020028, 0x5d50e188, + 0x00081fff, 0x00009b40, 0x00001120, 0x190fb515, 0x00000000, + 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000007, 0x001fff00, 0x006f00c4, 0x03051000, + 0x00000820, 0x038919be, 0x06336f77, 0x60f6532c, 0x08f186c8, + 0x00046384, 0x00000000, 0x00000000, 0x00000000, 0x00000200, + 0x64646464, 0x3c787878, 0x000000aa, 0x00000000, 0x00001042, + 0x00000000, 0x00000040, 0x00000080, 0x000001a1, 0x000001e1, + 0x00000021, 0x00000061, 0x00000168, 0x000001a8, 0x000001e8, + 0x00000028, 0x00000068, 0x00000189, 0x000001c9, 0x00000009, + 0x00000049, 0x00000089, 0x00000170, 0x000001b0, 0x000001f0, + 0x00000030, 0x00000070, 0x00000191, 0x000001d1, 0x00000011, + 0x00000051, 0x00000091, 0x000001b8, 0x000001f8, 0x00000038, + 0x00000078, 0x00000199, 0x000001d9, 0x00000019, 0x00000059, + 0x00000099, 0x000000d9, 0x000000f9, 0x000000f9, 0x000000f9, + 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, + 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, + 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, + 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, + 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0x00000000, + 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, + 0x00000008, 0x00000009, 0x0000000a, 0x0000000b, 0x0000000c, + 0x0000000d, 0x00000010, 0x00000011, 0x00000012, 0x00000013, + 0x00000014, 0x00000015, 0x00000018, 0x00000019, 0x0000001a, + 0x0000001b, 0x0000001c, 0x0000001d, 0x00000020, 0x00000021, + 0x00000022, 0x00000023, 0x00000024, 0x00000025, 0x00000028, + 0x00000029, 0x0000002a, 0x0000002b, 0x0000002c, 0x0000002d, + 0x00000030, 0x00000031, 0x00000032, 0x00000033, 0x00000034, + 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0x00000035, + 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0x00000035, + 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0x00000035, + 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0x00000035, + 0x00000035, 0x00000010, 0x0000001a, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000008, 0x00000440, 0xd6be4788, 0x012e8160, + 0x40806333, 0x00106c10, 0x009c4060, 0x1883800a, 0x018830c6, + 0x00000400, 0x000009b5, 0x00000000, 0x00000108, 0x3f3f3f3f, + 0x3f3f3f3f, 0x13c889af, 0x38490a20, 0x00007bb6, 0x0fff3ffc, + 0x00000001, 0x0000a000, 0x00000000, 0x0cc75380, 0x0f0f0f01, + 0xdfa91f01, 0x00418a11, 0x00000000, 0x09249126, 0x0a1a9caa, + 0x1ce739ce, 0x051701ce, 0x18010000, 0x30032602, 0x48073e06, + 0x560b4c0a, 0x641a600f, 0x7a4f6e1b, 0x8c5b7e5a, 0x9d0f96cf, + 0xb51fa69f, 0xcb3fbd07, 0x0000d7bf, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x0003ffff, 0x79a8aa1f, + 0x08000000, 0x3f3f3f3f, 0x3f3f3f3f, 0x1ce739ce, 0x000001ce, + 0x00000007, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, + 0x00000000, 0x1ce739ce, 0x000000c0, 0x00180a65, 0x0510001c, + 0x00009b40, 0x012e8160, 0x09249126, 0x00180a65, 0x0510001c, + 0x00009b40, 0x012e8160, 0x09249126, 0x0001c600, 0x004b6a8e, + 0x000003ce, 0x00181400, 0x00820820, 0x066c420f, 0x0f282207, + 0x17601685, 0x1f801104, 0x37a00c03, 0x3fc40883, 0x57c00803, + 0x5fd80682, 0x7fe00482, 0x7f3c7bba, 0xf3307ff0 +}; + +#ifdef notyet +static const uint32_t ar5416_phy_vals_5ghz_40mhz[] = { + 0x00000007, 0x000003c4, 0x00000000, 0xad848e19, 0x7d14e000, + 0x9c0a9f6b, 0x00000090, 0x00000000, 0x02020200, 0x00000e0e, + 0x0a020001, 0x0000a000, 0x00000000, 0x00000e0e, 0x00000007, + 0x00200400, 0x206a002e, 0x13721c1e, 0x001a6a65, 0x1284233c, + 0x6c48b4e4, 0x00000859, 0x7ec80d2e, 0x31395c5e, 0x0004dd10, + 0x409a4190, 0x050cb081, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x000007d0, 0x00000230, 0x10000fff, 0x0510081c, + 0xd0058a15, 0x00000001, 0x00000004, 0x3f3f3f3f, 0x3f3f3f3f, + 0x0000007f, 0xdfb81020, 0x9280b212, 0x00020028, 0x5d50e188, + 0x00081fff, 0x00009b40, 0x00001120, 0x190fb515, 0x00000000, + 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000007, 0x001fff00, 0x006f00c4, 0x03051000, + 0x00000820, 0x038919be, 0x06336f77, 0x60f6532c, 0x08f186c8, + 0x00046384, 0x00000000, 0x00000000, 0x00000000, 0x00000200, + 0x64646464, 0x3c787878, 0x000000aa, 0x00000000, 0x00001042, + 0x00000000, 0x00000040, 0x00000080, 0x000001a1, 0x000001e1, + 0x00000021, 0x00000061, 0x00000168, 0x000001a8, 0x000001e8, + 0x00000028, 0x00000068, 0x00000189, 0x000001c9, 0x00000009, + 0x00000049, 0x00000089, 0x00000170, 0x000001b0, 0x000001f0, + 0x00000030, 0x00000070, 0x00000191, 0x000001d1, 0x00000011, + 0x00000051, 0x00000091, 0x000001b8, 0x000001f8, 0x00000038, + 0x00000078, 0x00000199, 0x000001d9, 0x00000019, 0x00000059, + 0x00000099, 0x000000d9, 0x000000f9, 0x000000f9, 0x000000f9, + 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, + 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, + 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, + 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, + 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0x00000000, + 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, + 0x00000008, 0x00000009, 0x0000000a, 0x0000000b, 0x0000000c, + 0x0000000d, 0x00000010, 0x00000011, 0x00000012, 0x00000013, + 0x00000014, 0x00000015, 0x00000018, 0x00000019, 0x0000001a, + 0x0000001b, 0x0000001c, 0x0000001d, 0x00000020, 0x00000021, + 0x00000022, 0x00000023, 0x00000024, 0x00000025, 0x00000028, + 0x00000029, 0x0000002a, 0x0000002b, 0x0000002c, 0x0000002d, + 0x00000030, 0x00000031, 0x00000032, 0x00000033, 0x00000034, + 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0x00000035, + 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0x00000035, + 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0x00000035, + 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0x00000035, + 0x00000035, 0x00000010, 0x0000001a, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000008, 0x00000440, 0xd6be4788, 0x012e8160, + 0x40806333, 0x00106c10, 0x009c4060, 0x1883800a, 0x018830c6, + 0x00000400, 0x000009b5, 0x00000000, 0x00000210, 0x3f3f3f3f, + 0x3f3f3f3f, 0x13c889af, 0x38490a20, 0x00007bb6, 0x0fff3ffc, + 0x00000001, 0x0000a000, 0x00000000, 0x0cc75380, 0x0f0f0f01, + 0xdfa91f01, 0x00418a11, 0x00000000, 0x09249126, 0x0a1a9caa, + 0x1ce739ce, 0x051701ce, 0x18010000, 0x30032602, 0x48073e06, + 0x560b4c0a, 0x641a600f, 0x7a4f6e1b, 0x8c5b7e5a, 0x9d0f96cf, + 0xb51fa69f, 0xcb3fbcbf, 0x0000d7bf, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x0003ffff, 0x79a8aa1f, + 0x08000000, 0x3f3f3f3f, 0x3f3f3f3f, 0x1ce739ce, 0x000001ce, + 0x00000007, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, + 0x00000000, 0x1ce739ce, 0x000000c0, 0x00180a65, 0x0510001c, + 0x00009b40, 0x012e8160, 0x09249126, 0x00180a65, 0x0510001c, + 0x00009b40, 0x012e8160, 0x09249126, 0x0001c600, 0x004b6a8e, + 0x000003ce, 0x00181400, 0x00820820, 0x066c420f, 0x0f282207, + 0x17601685, 0x1f801104, 0x37a00c03, 0x3fc40883, 0x57c00803, + 0x5fd80682, 0x7fe00482, 0x7f3c7bba, 0xf3307ff0 +}; +#endif + +#ifdef notyet +static const uint32_t ar5416_phy_vals_2ghz_40mhz[] = { + 0x00000007, 0x000003c4, 0x00000000, 0xad848e19, 0x7d14e000, + 0x9c0a9f6b, 0x00000090, 0x00000000, 0x02020200, 0x00000e0e, + 0x0a020001, 0x0000a000, 0x00000000, 0x00000e0e, 0x00000007, + 0x00200400, 0x206a002e, 0x13721c24, 0x00197a68, 0x1284233c, + 0x6c48b0e4, 0x00000859, 0x7ec80d2e, 0x31395c5e, 0x0004dd20, + 0x409a4190, 0x050cb081, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000898, 0x00000268, 0x10000fff, 0x0510001c, + 0xd0058a15, 0x00000001, 0x00000004, 0x3f3f3f3f, 0x3f3f3f3f, + 0x0000007f, 0xdfb81020, 0x9280b212, 0x00020028, 0x5d50e188, + 0x00081fff, 0x00009b40, 0x00001120, 0x190fb515, 0x00000000, + 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000007, 0x001fff00, 0x006f00c4, 0x03051000, + 0x00000820, 0x038919be, 0x06336f77, 0x60f6532c, 0x08f186c8, + 0x00046384, 0x00000000, 0x00000000, 0x00000000, 0x00000200, + 0x64646464, 0x3c787878, 0x000000aa, 0x00000000, 0x00001042, + 0x00000000, 0x00000040, 0x00000080, 0x00000141, 0x00000181, + 0x000001c1, 0x00000001, 0x00000041, 0x000001a8, 0x000001e8, + 0x00000028, 0x00000068, 0x000000a8, 0x00000169, 0x000001a9, + 0x000001e9, 0x00000029, 0x00000069, 0x00000190, 0x000001d0, + 0x00000010, 0x00000050, 0x00000090, 0x00000151, 0x00000191, + 0x000001d1, 0x00000011, 0x00000051, 0x00000198, 0x000001d8, + 0x00000018, 0x00000058, 0x00000098, 0x00000159, 0x00000199, + 0x000001d9, 0x00000019, 0x00000059, 0x00000099, 0x000000d9, + 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, + 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, + 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, + 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, + 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0x00000000, + 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, + 0x00000008, 0x00000009, 0x0000000a, 0x0000000b, 0x0000000c, + 0x0000000d, 0x00000010, 0x00000011, 0x00000012, 0x00000013, + 0x00000014, 0x00000015, 0x00000018, 0x00000019, 0x0000001a, + 0x0000001b, 0x0000001c, 0x0000001d, 0x00000020, 0x00000021, + 0x00000022, 0x00000023, 0x00000024, 0x00000025, 0x00000028, + 0x00000029, 0x0000002a, 0x0000002b, 0x0000002c, 0x0000002d, + 0x00000030, 0x00000031, 0x00000032, 0x00000033, 0x00000034, + 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0x00000035, + 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0x00000035, + 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0x00000035, + 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0x00000035, + 0x00000035, 0x00000010, 0x0000001a, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x0000000e, 0x00000440, 0xd03e4788, 0x012a8160, + 0x40806333, 0x00106c10, 0x009c4060, 0x1883800a, 0x018830c6, + 0x00000400, 0x000009b5, 0x00000000, 0x00000210, 0x3f3f3f3f, + 0x3f3f3f3f, 0x13c889af, 0x38490a20, 0x00007bb6, 0x0fff3ffc, + 0x00000001, 0x0000a000, 0x00000000, 0x0cc75380, 0x0f0f0f01, + 0xdfa91f01, 0x00418a11, 0x00000000, 0x09249126, 0x0a1a7caa, + 0x1ce739ce, 0x051701ce, 0x18010000, 0x2e032402, 0x4a0a3c06, + 0x621a540b, 0x764f6c1b, 0x845b7a5a, 0x950f8ccf, 0xa5cf9b4f, + 0xbddfaf1f, 0xd1ffc93f, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x0003ffff, 0x79a8aa1f, + 0x08000000, 0x3f3f3f3f, 0x3f3f3f3f, 0x1ce739ce, 0x000001ce, + 0x00000007, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, + 0x00000000, 0x1ce739ce, 0x000000c0, 0x00180a68, 0x0510001c, + 0x00009b40, 0x012a8160, 0x09249126, 0x00180a68, 0x0510001c, + 0x00009b40, 0x012a8160, 0x09249126, 0x0001c600, 0x004b6a8e, + 0x000003ce, 0x00181400, 0x00820820, 0x066c420f, 0x0f282207, + 0x17601685, 0x1f801104, 0x37a00c03, 0x3fc40883, 0x57c00803, + 0x5fd80682, 0x7fe00482, 0x7f3c7bba, 0xf3307ff0 +}; +#endif + +static const uint32_t ar5416_phy_vals_2ghz_20mhz[] = { + 0x00000007, 0x00000300, 0x00000000, 0xad848e19, 0x7d14e000, + 0x9c0a9f6b, 0x00000090, 0x00000000, 0x02020200, 0x00000e0e, + 0x0a020001, 0x0000a000, 0x00000000, 0x00000e0e, 0x00000007, + 0x00200400, 0x206a002e, 0x137216a4, 0x00197a68, 0x1284233c, + 0x6c48b0e4, 0x00000859, 0x7ec80d2e, 0x31395c5e, 0x0004dd20, + 0x409a4190, 0x050cb081, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000898, 0x00000134, 0x10000fff, 0x0510001c, + 0xd0058a15, 0x00000001, 0x00000004, 0x3f3f3f3f, 0x3f3f3f3f, + 0x0000007f, 0xdfb81020, 0x9280b212, 0x00020028, 0x5d50e188, + 0x00081fff, 0x00009b40, 0x00001120, 0x190fb515, 0x00000000, + 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000007, 0x001fff00, 0x006f00c4, 0x03051000, + 0x00000820, 0x038919be, 0x06336f77, 0x60f6532c, 0x08f186c8, + 0x00046384, 0x00000000, 0x00000000, 0x00000000, 0x00000200, + 0x64646464, 0x3c787878, 0x000000aa, 0x00000000, 0x00001042, + 0x00000000, 0x00000040, 0x00000080, 0x00000141, 0x00000181, + 0x000001c1, 0x00000001, 0x00000041, 0x000001a8, 0x000001e8, + 0x00000028, 0x00000068, 0x000000a8, 0x00000169, 0x000001a9, + 0x000001e9, 0x00000029, 0x00000069, 0x00000190, 0x000001d0, + 0x00000010, 0x00000050, 0x00000090, 0x00000151, 0x00000191, + 0x000001d1, 0x00000011, 0x00000051, 0x00000198, 0x000001d8, + 0x00000018, 0x00000058, 0x00000098, 0x00000159, 0x00000199, + 0x000001d9, 0x00000019, 0x00000059, 0x00000099, 0x000000d9, + 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, + 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, + 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, + 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, + 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0x00000000, + 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, + 0x00000008, 0x00000009, 0x0000000a, 0x0000000b, 0x0000000c, + 0x0000000d, 0x00000010, 0x00000011, 0x00000012, 0x00000013, + 0x00000014, 0x00000015, 0x00000018, 0x00000019, 0x0000001a, + 0x0000001b, 0x0000001c, 0x0000001d, 0x00000020, 0x00000021, + 0x00000022, 0x00000023, 0x00000024, 0x00000025, 0x00000028, + 0x00000029, 0x0000002a, 0x0000002b, 0x0000002c, 0x0000002d, + 0x00000030, 0x00000031, 0x00000032, 0x00000033, 0x00000034, + 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0x00000035, + 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0x00000035, + 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0x00000035, + 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0x00000035, + 0x00000035, 0x00000010, 0x0000001a, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x0000000e, 0x00000440, 0xd03e4788, 0x012a8160, + 0x40806333, 0x00106c10, 0x009c4060, 0x1883800a, 0x018830c6, + 0x00000400, 0x000009b5, 0x00000000, 0x00000108, 0x3f3f3f3f, + 0x3f3f3f3f, 0x13c889af, 0x38490a20, 0x00007bb6, 0x0fff3ffc, + 0x00000001, 0x0000a000, 0x00000000, 0x0cc75380, 0x0f0f0f01, + 0xdfa91f01, 0x00418a11, 0x00000000, 0x09249126, 0x0a1a7caa, + 0x1ce739ce, 0x051701ce, 0x18010000, 0x2e032402, 0x4a0a3c06, + 0x621a540b, 0x764f6c1b, 0x845b7a5a, 0x950f8ccf, 0xa5cf9b4f, + 0xbddfaf1f, 0xd1ffc93f, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x0003ffff, 0x79a8aa1f, + 0x08000000, 0x3f3f3f3f, 0x3f3f3f3f, 0x1ce739ce, 0x000001ce, + 0x00000007, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, + 0x00000000, 0x1ce739ce, 0x000000c0, 0x00180a68, 0x0510001c, + 0x00009b40, 0x012a8160, 0x09249126, 0x00180a68, 0x0510001c, + 0x00009b40, 0x012a8160, 0x09249126, 0x0001c600, 0x004b6a8e, + 0x000003ce, 0x00181400, 0x00820820, 0x066c420f, 0x0f282207, + 0x17601685, 0x1f801104, 0x37a00c03, 0x3fc40883, 0x57c00803, + 0x5fd80682, 0x7fe00482, 0x7f3c7bba, 0xf3307ff0 +}; + +/* NB: apply AR_PHY(). */ +static const uint8_t ar5416_banks_regs[] = { + 0x2c, 0x38, 0x2c, 0x3b, 0x2c, 0x38, 0x3c, 0x2c, 0x3a, 0x2c, 0x39, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x38, 0x2c, 0x2c, + 0x2c, 0x3c +}; + +static const uint32_t ar5416_banks_vals_5ghz[] = { + 0x1e5795e5, 0x02008020, 0x02108421, 0x00000008, 0x0e73ff17, + 0x00000420, 0x01400018, 0x000001a1, 0x00000001, 0x00000013, + 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00004000, 0x00006c00, 0x00002c00, 0x00004800, + 0x00004000, 0x00006000, 0x00001000, 0x00004000, 0x00007c00, + 0x00007c00, 0x00007c00, 0x00007c00, 0x00007c00, 0x00087c00, + 0x00007c00, 0x00005400, 0x00000c00, 0x00001800, 0x00007c00, + 0x00006c00, 0x00006c00, 0x00007c00, 0x00002c00, 0x00003c00, + 0x00003800, 0x00001c00, 0x00000800, 0x00000408, 0x00004c15, + 0x00004188, 0x0000201e, 0x00010408, 0x00000801, 0x00000c08, + 0x0000181e, 0x00001016, 0x00002800, 0x00004010, 0x0000081c, + 0x00000115, 0x00000015, 0x00000066, 0x0000001c, 0x00000000, + 0x00000004, 0x00000015, 0x0000001f, 0x00000000, 0x000000a0, + 0x00000000, 0x00000040, 0x0000001c +}; + +static const uint32_t ar5416_banks_vals_2ghz[] = { + 0x1e5795e5, 0x02008020, 0x02108421, 0x00000008, 0x0e73ff17, + 0x00000420, 0x01c00018, 0x000001a1, 0x00000001, 0x00000013, + 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00004000, 0x00006c00, 0x00002c00, 0x00004800, + 0x00004000, 0x00006000, 0x00001000, 0x00004000, 0x00007c00, + 0x00007c00, 0x00007c00, 0x00007c00, 0x00007c00, 0x00087c00, + 0x00007c00, 0x00005400, 0x00000c00, 0x00001800, 0x00007c00, + 0x00006c00, 0x00006c00, 0x00007c00, 0x00002c00, 0x00003c00, + 0x00003800, 0x00001c00, 0x00000800, 0x00000408, 0x00004c15, + 0x00004188, 0x0000201e, 0x00010408, 0x00000801, 0x00000c08, + 0x0000181e, 0x00001016, 0x00002800, 0x00004010, 0x0000081c, + 0x00000115, 0x00000015, 0x00000066, 0x0000001c, 0x00000000, + 0x00000004, 0x00000015, 0x0000001f, 0x00000400, 0x000000a0, + 0x00000000, 0x00000040, 0x0000001c +}; + +/* + * EEPROM. + */ +/* Possible flags for opCapFlags. */ +#define AR5416_OPFLAGS_11A 0x01 +#define AR5416_OPFLAGS_11G 0x02 +#define AR5416_OPFLAGS_5G_HT40 0x04 +#define AR5416_OPFLAGS_2G_HT40 0x08 +#define AR5416_OPFLAGS_5G_HT20 0x10 +#define AR5416_OPFLAGS_2G_HT20 0x20 + +#define AR5416_NUM_5G_CAL_PIERS 8 +#define AR5416_NUM_2G_CAL_PIERS 4 +#define AR5416_NUM_5G_20_TARGET_POWERS 8 +#define AR5416_NUM_5G_40_TARGET_POWERS 8 +#define AR5416_NUM_2G_CCK_TARGET_POWERS 3 +#define AR5416_NUM_2G_20_TARGET_POWERS 4 +#define AR5416_NUM_2G_40_TARGET_POWERS 4 +#define AR5416_NUM_CTLS 24 +#define AR5416_NUM_BAND_EDGES 8 +#define AR5416_NUM_PD_GAINS 4 +#define AR5416_PD_GAIN_ICEPTS 5 +#define AR5416_EEPROM_MODAL_SPURS 5 +#define AR5416_MAX_CHAINS 2 + +struct BaseEepHeader { + uint16_t length; + uint16_t checksum; + uint16_t version; + uint8_t opCapFlags; + uint8_t eepMisc; + uint16_t regDmn[2]; + uint8_t macAddr[6]; + uint8_t rxMask; + uint8_t txMask; + uint16_t rfSilent; + uint16_t blueToothOptions; + uint16_t deviceCap; + uint32_t binBuildNumber; + uint8_t deviceType; + uint8_t futureBase[33]; +} __packed; + +struct spurChanStruct { + uint16_t spurChan; + uint8_t spurRangeLow; + uint8_t spurRangeHigh; +} __packed; + +struct ModalEepHeader { + uint32_t antCtrlChain[AR5416_MAX_CHAINS]; + uint32_t antCtrlCommon; + int8_t antennaGainCh[AR5416_MAX_CHAINS]; + uint8_t switchSettling; + uint8_t txRxAttenCh[AR5416_MAX_CHAINS]; + uint8_t rxTxMarginCh[AR5416_MAX_CHAINS]; + uint8_t adcDesiredSize; + int8_t pgaDesiredSize; + uint8_t xlnaGainCh[AR5416_MAX_CHAINS]; + uint8_t txEndToXpaOff; + uint8_t txEndToRxOn; + uint8_t txFrameToXpaOn; + uint8_t thresh62; + uint8_t noiseFloorThreshCh[AR5416_MAX_CHAINS]; + uint8_t xpdGain; + uint8_t xpd; + int8_t iqCalICh[AR5416_MAX_CHAINS]; + int8_t iqCalQCh[AR5416_MAX_CHAINS]; + uint8_t pdGainOverlap; + uint8_t ob; + uint8_t db; + uint8_t xpaBiasLvl; + uint8_t pwrDecreaseFor2Chain; + uint8_t pwrDecreaseFor3Chain; + uint8_t txFrameToDataStart; + uint8_t txFrameToPaOn; + uint8_t ht40PowerIncForPdadc; + uint8_t bswAtten[AR5416_MAX_CHAINS]; + uint8_t bswMargin[AR5416_MAX_CHAINS]; + uint8_t swSettleHt40; + uint8_t futureModal[22]; + struct spurChanStruct spurChans[AR5416_EEPROM_MODAL_SPURS]; +} __packed; + +struct calDataPerFreq { + uint8_t pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; + uint8_t vpdPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; +} __packed; + +struct CalTargetPowerLegacy { + uint8_t bChannel; + uint8_t tPow2x[4]; +} __packed; + +struct CalTargetPowerHt { + uint8_t bChannel; + uint8_t tPow2x[8]; +} __packed; + +struct CalCtlEdges { + uint8_t bChannel; + uint8_t tPowerFlag; +} __packed; + +struct CalCtlData { + struct CalCtlEdges ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; +} __packed; + +struct ar5416eeprom { + struct BaseEepHeader baseEepHeader; + uint8_t custData[64]; + struct ModalEepHeader modalHeader[2]; + uint8_t calFreqPier5G[AR5416_NUM_5G_CAL_PIERS]; + uint8_t calFreqPier2G[AR5416_NUM_2G_CAL_PIERS]; + struct calDataPerFreq calPierData5G[AR5416_MAX_CHAINS] + [AR5416_NUM_5G_CAL_PIERS]; + struct calDataPerFreq calPierData2G[AR5416_MAX_CHAINS] + [AR5416_NUM_2G_CAL_PIERS]; + struct CalTargetPowerLegacy calTPow5G[AR5416_NUM_5G_20_TARGET_POWERS]; + struct CalTargetPowerHt calTPow5GHT20[AR5416_NUM_5G_20_TARGET_POWERS]; + struct CalTargetPowerHt calTPow5GHT40[AR5416_NUM_5G_40_TARGET_POWERS]; + struct CalTargetPowerLegacy calTPowCck[AR5416_NUM_2G_CCK_TARGET_POWERS]; + struct CalTargetPowerLegacy calTPow2G[AR5416_NUM_2G_20_TARGET_POWERS]; + struct CalTargetPowerHt calTPow2GHT20[AR5416_NUM_2G_20_TARGET_POWERS]; + struct CalTargetPowerHt calTPow2GHT40[AR5416_NUM_2G_40_TARGET_POWERS]; + uint8_t ctlIndex[AR5416_NUM_CTLS]; + struct CalCtlData ctlData[AR5416_NUM_CTLS]; + uint8_t padding; +} __packed; + +#define OTUS_NUM_CHAINS 2 + +#define OTUS_UID(aid) (IEEE80211_AID(aid) + 4) + +#define OTUS_MAX_TXCMDSZ 64 +#define OTUS_RXBUFSZ (8 * 1024) +/* Bumped for later A-MSDU and legacy fast-frames TX support */ +#define OTUS_TXBUFSZ (8 * 1024) + +/* Default EDCA parameters for when QoS is disabled. */ +static const struct wmeParams otus_edca_def[WME_NUM_AC] = { + { 4, 10, 3, 0 }, + { 4, 10, 7, 0 }, + { 3, 4, 2, 94 }, + { 2, 3, 2, 47 } +}; + +#define OTUS_RIDX_CCK1 0 +#define OTUS_RIDX_OFDM6 4 +#define OTUS_RIDX_OFDM24 8 +#define OTUS_RIDX_MAX 11 +static const struct otus_rate { + uint8_t rate; + uint8_t mcs; +} otus_rates[] = { + { 2, 0x0 }, + { 4, 0x1 }, + { 11, 0x2 }, + { 22, 0x3 }, + { 12, 0xb }, + { 18, 0xf }, + { 24, 0xa }, + { 36, 0xe }, + { 48, 0x9 }, + { 72, 0xd }, + { 96, 0x8 }, + { 108, 0xc } +}; + +struct otus_rx_radiotap_header { + struct ieee80211_radiotap_header wr_ihdr; + uint8_t wr_flags; + uint8_t wr_rate; + uint16_t wr_chan_freq; + uint16_t wr_chan_flags; + uint8_t wr_antsignal; +} __packed; + +#define OTUS_RX_RADIOTAP_PRESENT \ + (1 << IEEE80211_RADIOTAP_FLAGS | \ + 1 << IEEE80211_RADIOTAP_RATE | \ + 1 << IEEE80211_RADIOTAP_CHANNEL | \ + 1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) + +struct otus_tx_radiotap_header { + struct ieee80211_radiotap_header wt_ihdr; + uint8_t wt_flags; + uint8_t wt_rate; + uint16_t wt_chan_freq; + uint16_t wt_chan_flags; +} __packed; + +#define OTUS_TX_RADIOTAP_PRESENT \ + (1 << IEEE80211_RADIOTAP_FLAGS | \ + 1 << IEEE80211_RADIOTAP_RATE | \ + 1 << IEEE80211_RADIOTAP_CHANNEL) + +struct otus_softc; + +/* Firmware commands */ +struct otus_tx_cmd { + uint8_t *buf; + uint16_t buflen; + void * *odata; + uint16_t odatalen; + uint16_t token; + STAILQ_ENTRY(otus_tx_cmd) next_cmd; +}; + +/* TX, RX buffers */ +struct otus_data { + struct otus_softc *sc; + uint8_t *buf; + uint16_t buflen; + struct mbuf *m; + struct ieee80211_node *ni; + STAILQ_ENTRY(otus_data) next; +}; + +struct otus_node { + struct ieee80211_node ni; + uint64_t tx_done; + uint64_t tx_err; + uint64_t tx_retries; +}; + +#define OTUS_CONFIG_INDEX 0 +#define OTUS_IFACE_INDEX 0 + +/* + * The carl9170 firmware has the following specification: + * + * 0 - USB control + * 1 - TX + * 2 - RX + * 3 - IRQ + * 4 - CMD + * .. + * 10 - end + */ +enum { + OTUS_BULK_TX, + OTUS_BULK_RX, + OTUS_BULK_IRQ, + OTUS_BULK_CMD, + OTUS_N_XFER +}; + +struct otus_vap { + struct ieee80211vap vap; + int (*newstate)(struct ieee80211vap *, + enum ieee80211_state, int); +}; +#define OTUS_VAP(vap) ((struct otus_vap *)(vap)) +#define OTUS_NODE(ni) ((struct otus_node *)(ni)) + +#define OTUS_LOCK(sc) mtx_lock(&(sc)->sc_mtx) +#define OTUS_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) +#define OTUS_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED) +#define OTUS_UNLOCK_ASSERT(sc) mtx_assert(&(sc)->sc_mtx, MA_NOTOWNED) + +/* XXX the TX/RX endpoint dump says it's 0x200, (512)? */ +#define OTUS_MAX_TXSZ 512 +#define OTUS_MAX_RXSZ 512 +/* intr/cmd endpoint dump says 0x40 */ +#define OTUS_MAX_CTRLSZ 64 + +#define OTUS_CMD_LIST_COUNT 32 +#define OTUS_RX_LIST_COUNT 128 +#define OTUS_TX_LIST_COUNT 32 + +struct otus_softc { + struct ieee80211com sc_ic; + struct mbufq sc_snd; + device_t sc_dev; + struct usb_device *sc_udev; + int (*sc_newstate)(struct ieee80211com *, + enum ieee80211_state, int); + void (*sc_led_newstate)(struct otus_softc *); + struct usbd_interface *sc_iface; + struct mtx sc_mtx; + + struct ar5416eeprom eeprom; + uint8_t capflags; + uint8_t rxmask; + uint8_t txmask; + int sc_running:1, + sc_calibrating:1, + sc_scanning:1; + + int sc_if_flags; + int sc_tx_timer; + int fixed_ridx; + int bb_reset; + + struct ieee80211_channel *sc_curchan; + + struct task tx_task; + struct task wme_update_task; + struct timeout_task scan_to; + struct timeout_task calib_to; + + /* register batch writes */ + int write_idx; + + uint32_t led_state; + + /* current firmware message serial / token number */ + int token; + + /* current noisefloor, from SET_FREQUENCY */ + int sc_nf[OTUS_NUM_CHAINS]; + + /* How many pending, active transmit frames */ + int sc_tx_n_pending; + int sc_tx_n_active; + + const uint32_t *phy_vals; + + struct { + uint32_t reg; + uint32_t val; + } __packed write_buf[AR_MAX_WRITE_IDX + 1]; + + struct otus_data sc_rx[OTUS_RX_LIST_COUNT]; + struct otus_data sc_tx[OTUS_TX_LIST_COUNT]; + struct otus_tx_cmd sc_cmd[OTUS_CMD_LIST_COUNT]; + + struct usb_xfer *sc_xfer[OTUS_N_XFER]; + + STAILQ_HEAD(, otus_data) sc_rx_active; + STAILQ_HEAD(, otus_data) sc_rx_inactive; + STAILQ_HEAD(, otus_data) sc_tx_active[OTUS_N_XFER]; + STAILQ_HEAD(, otus_data) sc_tx_inactive; + STAILQ_HEAD(, otus_data) sc_tx_pending[OTUS_N_XFER]; + + STAILQ_HEAD(, otus_tx_cmd) sc_cmd_active; + STAILQ_HEAD(, otus_tx_cmd) sc_cmd_inactive; + STAILQ_HEAD(, otus_tx_cmd) sc_cmd_pending; + STAILQ_HEAD(, otus_tx_cmd) sc_cmd_waiting; + + union { + struct otus_rx_radiotap_header th; + uint8_t pad[64]; + } sc_rxtapu; +#define sc_rxtap sc_rxtapu.th + int sc_rxtap_len; + + union { + struct otus_tx_radiotap_header th; + uint8_t pad[64]; + } sc_txtapu; +#define sc_txtap sc_txtapu.th + int sc_txtap_len; +}; + +#endif /* __IF_OTUSREG_H__ */ diff --git a/sys/dev/pci/pci_pci.c b/sys/dev/pci/pci_pci.c index 5b925c8a02e8e..11a4bcac7950f 100644 --- a/sys/dev/pci/pci_pci.c +++ b/sys/dev/pci/pci_pci.c @@ -1082,7 +1082,7 @@ pcib_attach(device_t dev) pcib_attach_common(dev); sc = device_get_softc(dev); if (sc->bus.sec != 0) { - child = device_add_child(dev, "pci", sc->bus.sec); + child = device_add_child(dev, "pci", -1); if (child != NULL) return(bus_generic_attach(dev)); } diff --git a/sys/dev/ral/rt2560.c b/sys/dev/ral/rt2560.c index ea9c4162b8f83..ef5a01c4e936e 100644 --- a/sys/dev/ral/rt2560.c +++ b/sys/dev/ral/rt2560.c @@ -768,7 +768,7 @@ rt2560_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) if (vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_IBSS || vap->iv_opmode == IEEE80211_M_MBSS) { - m = ieee80211_beacon_alloc(ni, &rvp->ral_bo); + m = ieee80211_beacon_alloc(ni, &vap->iv_bcn_off); if (m == NULL) { device_printf(sc->sc_dev, "could not allocate beacon\n"); @@ -1273,8 +1273,7 @@ rt2560_rx_intr(struct rt2560_softc *sc) static void rt2560_beacon_update(struct ieee80211vap *vap, int item) { - struct rt2560_vap *rvp = RT2560_VAP(vap); - struct ieee80211_beacon_offsets *bo = &rvp->ral_bo; + struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; setbit(bo->bo_flags, item); } @@ -1288,7 +1287,6 @@ rt2560_beacon_expire(struct rt2560_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - struct rt2560_vap *rvp = RT2560_VAP(vap); struct rt2560_tx_data *data; if (ic->ic_opmode != IEEE80211_M_IBSS && @@ -1307,7 +1305,7 @@ rt2560_beacon_expire(struct rt2560_softc *sc) bus_dmamap_unload(sc->bcnq.data_dmat, data->map); /* XXX 1 =>'s mcast frames which means all PS sta's will wakeup! */ - ieee80211_beacon_update(data->ni, &rvp->ral_bo, data->m, 1); + ieee80211_beacon_update(data->ni, &vap->iv_bcn_off, data->m, 1); rt2560_tx_bcn(sc, data->m, data->ni); @@ -2301,7 +2299,6 @@ static void rt2560_set_basicrates(struct rt2560_softc *sc, const struct ieee80211_rateset *rs) { -#define RV(r) ((r) & IEEE80211_RATE_VAL) struct ieee80211com *ic = &sc->sc_ic; uint32_t mask = 0; uint8_t rate; @@ -2313,13 +2310,13 @@ rt2560_set_basicrates(struct rt2560_softc *sc, if (!(rate & IEEE80211_RATE_BASIC)) continue; - mask |= 1 << ieee80211_legacy_rate_lookup(ic->ic_rt, RV(rate)); + mask |= 1 << ieee80211_legacy_rate_lookup(ic->ic_rt, + IEEE80211_RV(rate)); } RAL_WRITE(sc, RT2560_ARSP_PLCP_1, mask); DPRINTF(sc, "Setting basic rate mask to 0x%x\n", mask); -#undef RV } static void @@ -2478,7 +2475,6 @@ rt2560_scan_end(struct ieee80211com *ic) static int rt2560_bbp_init(struct rt2560_softc *sc) { -#define N(a) (sizeof (a) / sizeof ((a)[0])) int i, ntries; /* wait for BBP to be ready */ @@ -2493,7 +2489,7 @@ rt2560_bbp_init(struct rt2560_softc *sc) } /* initialize BBP registers to default values */ - for (i = 0; i < N(rt2560_def_bbp); i++) { + for (i = 0; i < nitems(rt2560_def_bbp); i++) { rt2560_bbp_write(sc, rt2560_def_bbp[i].reg, rt2560_def_bbp[i].val); } @@ -2507,7 +2503,6 @@ rt2560_bbp_init(struct rt2560_softc *sc) rt2560_bbp_write(sc, 17, 0x48); /* XXX restore bbp17 */ return 0; -#undef N } static void @@ -2560,7 +2555,6 @@ rt2560_set_rxantenna(struct rt2560_softc *sc, int antenna) static void rt2560_init_locked(struct rt2560_softc *sc) { -#define N(a) (sizeof (a) / sizeof ((a)[0])) struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); uint32_t tmp; @@ -2590,7 +2584,7 @@ rt2560_init_locked(struct rt2560_softc *sc) RAL_WRITE(sc, RT2560_RXCSR2, sc->rxq.physaddr); /* initialize MAC registers to default values */ - for (i = 0; i < N(rt2560_def_mac); i++) + for (i = 0; i < nitems(rt2560_def_mac); i++) RAL_WRITE(sc, rt2560_def_mac[i].reg, rt2560_def_mac[i].val); rt2560_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr); @@ -2641,7 +2635,6 @@ rt2560_init_locked(struct rt2560_softc *sc) sc->sc_flags |= RT2560_F_RUNNING; callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc); -#undef N } static void diff --git a/sys/dev/ral/rt2560var.h b/sys/dev/ral/rt2560var.h index 3a5fef981080f..12601d8ef38bc 100644 --- a/sys/dev/ral/rt2560var.h +++ b/sys/dev/ral/rt2560var.h @@ -97,7 +97,6 @@ struct rt2560_rx_ring { struct rt2560_vap { struct ieee80211vap ral_vap; - struct ieee80211_beacon_offsets ral_bo; int (*ral_newstate)(struct ieee80211vap *, enum ieee80211_state, int); diff --git a/sys/dev/ral/rt2661.c b/sys/dev/ral/rt2661.c index c77d4f88df767..5c73ba02e0c5c 100644 --- a/sys/dev/ral/rt2661.c +++ b/sys/dev/ral/rt2661.c @@ -1859,7 +1859,6 @@ static void rt2661_set_basicrates(struct rt2661_softc *sc, const struct ieee80211_rateset *rs) { -#define RV(r) ((r) & IEEE80211_RATE_VAL) struct ieee80211com *ic = &sc->sc_ic; uint32_t mask = 0; uint8_t rate; @@ -1871,13 +1870,13 @@ rt2661_set_basicrates(struct rt2661_softc *sc, if (!(rate & IEEE80211_RATE_BASIC)) continue; - mask |= 1 << ieee80211_legacy_rate_lookup(ic->ic_rt, RV(rate)); + mask |= 1 << ieee80211_legacy_rate_lookup(ic->ic_rt, + IEEE80211_RV(rate)); } RAL_WRITE(sc, RT2661_TXRX_CSR5, mask); DPRINTF(sc, "Setting basic rate mask to 0x%x\n", mask); -#undef RV } /* @@ -2208,7 +2207,6 @@ rt2661_read_eeprom(struct rt2661_softc *sc, uint8_t macaddr[IEEE80211_ADDR_LEN]) static int rt2661_bbp_init(struct rt2661_softc *sc) { -#define N(a) (sizeof (a) / sizeof ((a)[0])) int i, ntries; uint8_t val; @@ -2225,7 +2223,7 @@ rt2661_bbp_init(struct rt2661_softc *sc) } /* initialize BBP registers to default values */ - for (i = 0; i < N(rt2661_def_bbp); i++) { + for (i = 0; i < nitems(rt2661_def_bbp); i++) { rt2661_bbp_write(sc, rt2661_def_bbp[i].reg, rt2661_def_bbp[i].val); } @@ -2238,13 +2236,11 @@ rt2661_bbp_init(struct rt2661_softc *sc) } return 0; -#undef N } static void rt2661_init_locked(struct rt2661_softc *sc) { -#define N(a) (sizeof (a) / sizeof ((a)[0])) struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); uint32_t tmp, sta[3]; @@ -2305,7 +2301,7 @@ rt2661_init_locked(struct rt2661_softc *sc) RAL_WRITE(sc, RT2661_RX_CNTL_CSR, 2); /* initialize MAC registers to default values */ - for (i = 0; i < N(rt2661_def_mac); i++) + for (i = 0; i < nitems(rt2661_def_mac); i++) RAL_WRITE(sc, rt2661_def_mac[i].reg, rt2661_def_mac[i].val); rt2661_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr); @@ -2354,7 +2350,7 @@ rt2661_init_locked(struct rt2661_softc *sc) RAL_WRITE(sc, RT2661_TXRX_CSR0, tmp); /* clear STA registers */ - RAL_READ_REGION_4(sc, RT2661_STA_CSR0, sta, N(sta)); + RAL_READ_REGION_4(sc, RT2661_STA_CSR0, sta, nitems(sta)); /* initialize ASIC */ RAL_WRITE(sc, RT2661_MAC_CSR1, 4); @@ -2372,7 +2368,6 @@ rt2661_init_locked(struct rt2661_softc *sc) sc->sc_flags |= RAL_RUNNING; callout_reset(&sc->watchdog_ch, hz, rt2661_watchdog, sc); -#undef N } static void @@ -2631,12 +2626,12 @@ static int rt2661_prepare_beacon(struct rt2661_softc *sc, struct ieee80211vap *vap) { struct ieee80211com *ic = vap->iv_ic; - struct ieee80211_beacon_offsets bo; + struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; struct rt2661_tx_desc desc; struct mbuf *m0; int rate; - m0 = ieee80211_beacon_alloc(vap->iv_bss, &bo); + m0 = ieee80211_beacon_alloc(vap->iv_bss, bo); if (m0 == NULL) { device_printf(sc->sc_dev, "could not allocate beacon frame\n"); return ENOBUFS; diff --git a/sys/dev/ral/rt2860.c b/sys/dev/ral/rt2860.c index b3c737d67c66b..a6b1e26a70695 100644 --- a/sys/dev/ral/rt2860.c +++ b/sys/dev/ral/rt2860.c @@ -2260,7 +2260,6 @@ void rt2860_set_basicrates(struct rt2860_softc *sc, const struct ieee80211_rateset *rs) { -#define RV(r) ((r) & IEEE80211_RATE_VAL) struct ieee80211com *ic = &sc->sc_ic; uint32_t mask = 0; uint8_t rate; @@ -2272,11 +2271,11 @@ rt2860_set_basicrates(struct rt2860_softc *sc, if (!(rate & IEEE80211_RATE_BASIC)) continue; - mask |= 1 << ieee80211_legacy_rate_lookup(ic->ic_rt, RV(rate)); + mask |= 1 << ieee80211_legacy_rate_lookup(ic->ic_rt, + IEEE80211_RV(rate)); } RAL_WRITE(sc, RT2860_LEGACY_BASIC_RATE, mask); -#undef RV } static void @@ -3351,7 +3350,7 @@ rt2860_read_eeprom(struct rt2860_softc *sc, uint8_t macaddr[IEEE80211_ADDR_LEN]) /* read EEPROM version */ val = rt2860_srom_read(sc, RT2860_EEPROM_VERSION); - DPRINTF(("EEPROM rev=%d, FAE=%d\n", val & 0xff, val >> 8)); + DPRINTF(("EEPROM rev=%d, FAE=%d\n", val >> 8, val & 0xff)); /* read MAC address */ val = rt2860_srom_read(sc, RT2860_EEPROM_MAC01); @@ -4269,12 +4268,12 @@ static int rt2860_setup_beacon(struct rt2860_softc *sc, struct ieee80211vap *vap) { struct ieee80211com *ic = vap->iv_ic; - struct ieee80211_beacon_offsets bo; + struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; struct rt2860_txwi txwi; struct mbuf *m; int ridx; - if ((m = ieee80211_beacon_alloc(vap->iv_bss, &bo)) == NULL) + if ((m = ieee80211_beacon_alloc(vap->iv_bss, bo)) == NULL) return ENOBUFS; memset(&txwi, 0, sizeof txwi); diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c index 677d397a1c7a3..88fa5fc054efa 100644 --- a/sys/dev/re/if_re.c +++ b/sys/dev/re/if_re.c @@ -238,6 +238,7 @@ static const struct rl_hwrev re_hwrevs[] = { { RL_HWREV_8168F, RL_8169, "8168F/8111F", RL_JUMBO_MTU_9K}, { RL_HWREV_8168G, RL_8169, "8168G/8111G", RL_JUMBO_MTU_9K}, { RL_HWREV_8168GU, RL_8169, "8168GU/8111GU", RL_JUMBO_MTU_9K}, + { RL_HWREV_8168H, RL_8169, "8168H/8111H", RL_JUMBO_MTU_9K}, { RL_HWREV_8411, RL_8169, "8411", RL_JUMBO_MTU_9K}, { RL_HWREV_8411B, RL_8169, "8411B", RL_JUMBO_MTU_9K}, { 0, 0, NULL, 0 } @@ -1485,6 +1486,7 @@ re_attach(device_t dev) break; case RL_HWREV_8168EP: case RL_HWREV_8168G: + case RL_HWREV_8168H: case RL_HWREV_8411B: sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_PAR | RL_FLAG_DESCV2 | RL_FLAG_MACSTAT | RL_FLAG_CMDSTOP | diff --git a/sys/dev/rl/if_rlreg.h b/sys/dev/rl/if_rlreg.h index b0de60f49807f..4f02dcfac5dd4 100644 --- a/sys/dev/rl/if_rlreg.h +++ b/sys/dev/rl/if_rlreg.h @@ -195,6 +195,7 @@ #define RL_HWREV_8168G 0x4C000000 #define RL_HWREV_8168EP 0x50000000 #define RL_HWREV_8168GU 0x50800000 +#define RL_HWREV_8168H 0x54000000 #define RL_HWREV_8411B 0x5C800000 #define RL_HWREV_8139 0x60000000 #define RL_HWREV_8139A 0x70000000 diff --git a/sys/dev/uart/uart_bus_pci.c b/sys/dev/uart/uart_bus_pci.c index 48954a531058f..41662226f27fb 100644 --- a/sys/dev/uart/uart_bus_pci.c +++ b/sys/dev/uart/uart_bus_pci.c @@ -127,6 +127,7 @@ static const struct pci_id pci_ns8250_ids[] = { 24 * DEFAULT_RCLK, 2 }, { 0x8086, 0x1c3d, 0xffff, 0, "Intel AMT - KT Controller", 0x10 }, { 0x8086, 0x1d3d, 0xffff, 0, "Intel C600/X79 Series Chipset KT Controller", 0x10 }, +{ 0x8086, 0x1e3d, 0xffff, 0, "Intel Panther Point KT Controller", 0x10 }, { 0x8086, 0x2a07, 0xffff, 0, "Intel AMT - PM965/GM965 KT Controller", 0x10 }, { 0x8086, 0x2a47, 0xffff, 0, "Mobile 4 Series Chipset KT Controller", 0x10 }, { 0x8086, 0x2e17, 0xffff, 0, "4 Series Chipset Serial KT Controller", 0x10 }, diff --git a/sys/dev/usb/controller/uhci_pci.c b/sys/dev/usb/controller/uhci_pci.c index cd08e89a3da86..e7e4412de5efd 100644 --- a/sys/dev/usb/controller/uhci_pci.c +++ b/sys/dev/usb/controller/uhci_pci.c @@ -223,7 +223,7 @@ uhci_pci_match(device_t self) case 0x76028086: return ("Intel 82372FB/82468GX USB controller"); - case 0x3309103c: + case 0x3300103c: return ("HP iLO Standard Virtual USB controller"); case 0x30381106: diff --git a/sys/dev/usb/controller/xhci_pci.c b/sys/dev/usb/controller/xhci_pci.c index 0ad7357caf7e6..0df2e9fb60c33 100644 --- a/sys/dev/usb/controller/xhci_pci.c +++ b/sys/dev/usb/controller/xhci_pci.c @@ -113,6 +113,9 @@ xhci_pci_match(device_t self) case 0x8cb18086: return ("Intel Wildcat Point USB 3.0 controller"); + case 0xa01b177d: + return ("Cavium ThunderX USB 3.0 controller"); + default: break; } diff --git a/sys/dev/usb/quirk/usb_quirk.c b/sys/dev/usb/quirk/usb_quirk.c index 459dc2ab78009..927cec1524493 100644 --- a/sys/dev/usb/quirk/usb_quirk.c +++ b/sys/dev/usb/quirk/usb_quirk.c @@ -61,6 +61,7 @@ MODULE_VERSION(usb_quirk, 1); #define USB_DEV_QUIRKS_MAX 384 #define USB_SUB_QUIRKS_MAX 8 +#define USB_QUIRK_ENVROOT "hw.usb.quirk." struct usb_quirk_entry { uint16_t vid; @@ -608,8 +609,32 @@ static const char *usb_quirk_str[USB_QUIRK_MAX] = { static const char * usb_quirkstr(uint16_t quirk) { - return ((quirk < USB_QUIRK_MAX) ? - usb_quirk_str[quirk] : "USB_QUIRK_UNKNOWN"); + return ((quirk < USB_QUIRK_MAX && usb_quirk_str[quirk] != NULL) ? + usb_quirk_str[quirk] : "UQ_UNKNOWN"); +} + +/*------------------------------------------------------------------------* + * usb_strquirk + * + * This function converts a string into a USB quirk code. + * + * Returns: + * Less than USB_QUIRK_MAX: Quirk code + * Else: Quirk code not found + *------------------------------------------------------------------------*/ +static uint16_t +usb_strquirk(const char *str, size_t len) +{ + const char *quirk; + uint16_t x; + + for (x = 0; x != USB_QUIRK_MAX; x++) { + quirk = usb_quirkstr(x); + if (strncmp(str, quirk, len) == 0 && + quirk[len] == 0) + break; + } + return (x); } /*------------------------------------------------------------------------* @@ -854,12 +879,122 @@ usb_quirk_ioctl(unsigned long cmd, caddr_t data, return (ENOIOCTL); } +/*------------------------------------------------------------------------* + * usb_quirk_strtou16 + * + * Helper function to scan a 16-bit integer. + *------------------------------------------------------------------------*/ +static uint16_t +usb_quirk_strtou16(const char **pptr, const char *name, const char *what) +{ + unsigned long value; + char *end; + + value = strtoul(*pptr, &end, 0); + if (value > 65535 || *pptr == end || (*end != ' ' && *end != '\t')) { + printf("%s: %s 16-bit %s value set to zero\n", + name, what, *end == 0 ? "incomplete" : "invalid"); + return (0); + } + *pptr = end + 1; + return ((uint16_t)value); +} + +/*------------------------------------------------------------------------* + * usb_quirk_add_entry_from_str + * + * Add a USB quirk entry from string. + * "VENDOR PRODUCT LO_REV HI_REV QUIRK[,QUIRK[,...]]" + *------------------------------------------------------------------------*/ +static void +usb_quirk_add_entry_from_str(const char *name, const char *env) +{ + struct usb_quirk_entry entry = { }; + struct usb_quirk_entry *new; + uint16_t quirk_idx; + uint16_t quirk; + const char *end; + + /* check for invalid environment variable */ + if (name == NULL || env == NULL) + return; + + if (bootverbose) + printf("Adding USB QUIRK '%s' = '%s'\n", name, env); + + /* parse device information */ + entry.vid = usb_quirk_strtou16(&env, name, "Vendor ID"); + entry.pid = usb_quirk_strtou16(&env, name, "Product ID"); + entry.lo_rev = usb_quirk_strtou16(&env, name, "Low revision"); + entry.hi_rev = usb_quirk_strtou16(&env, name, "High revision"); + + /* parse quirk information */ + quirk_idx = 0; + while (*env != 0 && quirk_idx != USB_SUB_QUIRKS_MAX) { + /* skip whitespace before quirks */ + while (*env == ' ' || *env == '\t') + env++; + + /* look for quirk separation character */ + end = strchr(env, ','); + if (end == NULL) + end = env + strlen(env); + + /* lookup quirk in string table */ + quirk = usb_strquirk(env, end - env); + if (quirk < USB_QUIRK_MAX) { + entry.quirks[quirk_idx++] = quirk; + } else { + printf("%s: unknown USB quirk '%.*s' (skipped)\n", + name, (int)(end - env), env); + } + env = end; + + /* skip quirk delimiter, if any */ + if (*env != 0) + env++; + } + + /* register quirk */ + if (quirk_idx != 0) { + if (*env != 0) { + printf("%s: Too many USB quirks, only %d allowed!\n", + name, USB_SUB_QUIRKS_MAX); + } + mtx_lock(&usb_quirk_mtx); + new = usb_quirk_get_entry(entry.vid, entry.pid, + entry.lo_rev, entry.hi_rev, 1); + if (new == NULL) + printf("%s: USB quirks table is full!\n", name); + else + memcpy(new->quirks, entry.quirks, sizeof(entry.quirks)); + mtx_unlock(&usb_quirk_mtx); + } else { + printf("%s: No USB quirks found!\n", name); + } +} + static void usb_quirk_init(void *arg) { + char envkey[sizeof(USB_QUIRK_ENVROOT) + 2]; /* 2 digits max, 0 to 99 */ + int i; + /* initialize mutex */ mtx_init(&usb_quirk_mtx, "USB quirk", NULL, MTX_DEF); + /* look for quirks defined by the environment variable */ + for (i = 0; i != 100; i++) { + snprintf(envkey, sizeof(envkey), USB_QUIRK_ENVROOT "%d", i); + + /* Stop at first undefined var */ + if (!testenv(envkey)) + break; + + /* parse environment variable */ + usb_quirk_add_entry_from_str(envkey, kern_getenv(envkey)); + } + /* register our function */ usb_test_quirk_p = &usb_test_quirk_by_info; usb_quirk_ioctl_p = &usb_quirk_ioctl; diff --git a/sys/dev/usb/serial/u3g.c b/sys/dev/usb/serial/u3g.c index ba825aa20fb17..065da281807cb 100644 --- a/sys/dev/usb/serial/u3g.c +++ b/sys/dev/usb/serial/u3g.c @@ -525,6 +525,7 @@ static const STRUCT_USB_HOST_ID u3g_devs[] = { U3G_DEV(SIERRA, MC5727_2, 0), U3G_DEV(SIERRA, MC5728, 0), U3G_DEV(SIERRA, MC7354, 0), + U3G_DEV(SIERRA, MC7355, 0), U3G_DEV(SIERRA, MC8700, 0), U3G_DEV(SIERRA, MC8755, 0), U3G_DEV(SIERRA, MC8755_2, 0), diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs index 7b7373c553d42..42f2e855c8c80 100644 --- a/sys/dev/usb/usbdevs +++ b/sys/dev/usb/usbdevs @@ -776,6 +776,7 @@ vendor MOSCHIP 0x9710 MosChip Semiconductor vendor NETGEAR4 0x9846 Netgear vendor MARVELL 0x9e88 Marvell Technology Group Ltd. vendor 3COM3 0xa727 3Com +vendor CACE 0xcace CACE Technologies vendor EVOLUTION 0xdeee Evolution Robotics products vendor DATAAPEX 0xdaae DataApex vendor HP2 0xf003 Hewlett Packard @@ -863,6 +864,7 @@ product ACCTON RT3070_3 0xc522 RT3070 product ACCTON RT3070_5 0xd522 RT3070 product ACCTON RTL8192SU 0xc512 RTL8192SU product ACCTON ZD1211B 0xe501 ZD1211B +product ACCTON WN7512 0xf522 WN7512 /* Aceeca products */ product ACEECA MEZ1000 0x0001 MEZ1000 RDA @@ -1223,6 +1225,11 @@ product ATHEROS2 AR5523_2 0x0003 AR5523 product ATHEROS2 AR5523_2_NF 0x0004 AR5523 (no firmware) product ATHEROS2 AR5523_3 0x0005 AR5523 product ATHEROS2 AR5523_3_NF 0x0006 AR5523 (no firmware) +product ATHEROS2 TG121N 0x1001 TG121N +product ATHEROS2 WN821NV2 0x1002 WN821NV2 +product ATHEROS2 3CRUSBN275 0x1010 3CRUSBN275 +product ATHEROS2 WN612 0x1011 WN612 +product ATHEROS2 AR9170 0x9170 AR9170 /* Atmel Comp. products */ product ATMEL STK541 0x2109 Zigbee Controller @@ -1238,6 +1245,9 @@ product AUTHENTEC AES1610 0x1600 AES1610 Fingerprint Sensor /* Avision products */ product AVISION 1200U 0x0268 1200U scanner +/* AVM products */ +product AVM FRITZWLAN 0x8401 FRITZ!WLAN N + /* Axesstel products */ product AXESSTEL DATAMODEM 0x1000 Data Modem @@ -1340,6 +1350,9 @@ product BROTHER MFC8600_9650 0x0100 MFC8600/9650 multifunction device product BTC BTC6100 0x5550 6100C Keyboard product BTC BTC7932 0x6782 Keyboard with mouse port +/* CACE Technologies products */ +product CACE AIRPCAPNX 0x0300 AirPcap NX + /* Canon, Inc. products */ product CANON N656U 0x2206 CanoScan N656U product CANON N1220U 0x2207 CanoScan N1220U @@ -1640,8 +1653,10 @@ product DLINK DWA131B 0x330d DWA-131 rev B product DLINK2 RTL8192SU_1 0x3300 RTL8192SU product DLINK2 RTL8192SU_2 0x3302 RTL8192SU product DLINK2 DWA131A1 0x3303 DWA-131 A1 +product DLINK2 DWA160A2 0x3a09 DWA-160 A2 product DLINK2 DWA120 0x3a0c DWA-120 product DLINK2 DWA120_NF 0x3a0d DWA-120 (no firmware) +product DLINK2 DWA130D1 0x3a0f DWA-130 D1 product DLINK2 DWLG122C1 0x3c03 DWL-G122 c1 product DLINK2 WUA1340 0x3c04 WUA-1340 product DLINK2 DWA111 0x3c06 DWA-111 @@ -1652,6 +1667,7 @@ product DLINK2 RT3072_1 0x3c0b RT3072 product DLINK2 RT3070_1 0x3c0d RT3070 product DLINK2 RT3070_2 0x3c0e RT3070 product DLINK2 RT3070_3 0x3c0f RT3070 +product DLINK2 DWA160A1 0x3c10 DWA-160 A1 product DLINK2 RT2870_2 0x3c11 RT2870 product DLINK2 DWA130 0x3c13 DWA-130 product DLINK2 RT3070_4 0x3c15 RT3070 @@ -2469,6 +2485,7 @@ product IODATA USBETTXS 0x0913 USB ETTX product IODATA USBWNB11A 0x0919 USB WN-B11 product IODATA USBWNB11 0x0922 USB Airport WN-B11 product IODATA ETGUS2 0x0930 ETG-US2 +product IODATA WNGDNUS2 0x093f WN-GDN/US2 product IODATA RT3072_1 0x0944 RT3072 product IODATA RT3072_2 0x0945 RT3072 product IODATA RT3072_3 0x0947 RT3072 @@ -3209,6 +3226,7 @@ product NATIONAL BEARPAW2400 0x1001 BearPaw 2400 /* NEC products */ product NEC HUB_0050 0x0050 USB 2.0 7-Port Hub product NEC HUB_005A 0x005a USB 2.0 4-Port Hub +product NEC WL300NUG 0x0249 WL300NU-G product NEC HUB 0x55aa hub product NEC HUB_B 0x55ab hub @@ -3241,7 +3259,11 @@ product NETGEAR WG111V3 0x4260 WG111v3 product NETGEAR WG111U 0x4300 WG111U product NETGEAR WG111U_NF 0x4301 WG111U (no firmware) product NETGEAR WG111V2 0x6a00 WG111V2 +product NETGEAR WN111V2 0x9001 WN111V2 +product NETGEAR WNDA3100 0x9010 WNDA3100 +product NETGEAR WNDA3200 0x9018 WNDA3200 product NETGEAR RTL8192CU 0x9021 RTL8192CU +product NETGEAR WNA1000 0x9040 WNA1000 product NETGEAR WNA1000M 0x9041 WNA1000M product NETGEAR2 MA101 0x4100 MA101 product NETGEAR2 MA101B 0x4102 MA101 Rev B @@ -3505,6 +3527,7 @@ product PLANEX GW_US11H 0x14ea GW-US11H WLAN product PLANEX2 RTL8188CUS 0x1201 RTL8188CUS product PLANEX2 GW_US11S 0x3220 GW-US11S WLAN product PLANEX2 GW_US54GXS 0x5303 GW-US54GXS WLAN +product PLANEX2 GW_US300 0x5304 GW-US300 product PLANEX2 RTL8188CU_1 0xab2a RTL8188CU product PLANEX2 RTL8188CU_2 0xed17 RTL8188CU product PLANEX2 RTL8188CU_3 0x4902 RTL8188CU @@ -4044,6 +4067,7 @@ product SIERRA E6892 0x6892 E6892 product SIERRA E6893 0x6893 E6893 product SIERRA MC8700 0x68A3 MC8700 product SIERRA MC7354 0x68C0 MC7354 +product SIERRA MC7355 0x9041 MC7355 product SIERRA AC313U 0x68aa Sierra Wireless AirCard 313U product SIERRA TRUINSTALL 0x0fff Aircard Tru Installer @@ -4576,8 +4600,10 @@ product WINBOND UH104 0x5518 4-port USB Hub product WINMAXGROUP FLASH64MC 0x6660 USB Flash Disk 64M-C /* Wistron NeWeb products */ +product WISTRONNEWEB WNC0600 0x0326 WNC-0600USB product WISTRONNEWEB UR045G 0x0427 PrismGT USB 2.0 WLAN product WISTRONNEWEB UR055G 0x0711 UR055G +product WISTRONNEWEB O8494 0x0804 ORiNOCO 802.11n product WISTRONNEWEB AR5523_1 0x0826 AR5523 product WISTRONNEWEB AR5523_1_NF 0x0827 AR5523 (no firmware) product WISTRONNEWEB AR5523_2 0x082a AR5523 @@ -4626,7 +4652,9 @@ product ZCOM AR5523_NF 0x0013 AR5523 driver (no firmware) product ZCOM XM142 0x0015 XM-142 product ZCOM ZD1211B 0x001a ZD1211B product ZCOM RT2870_1 0x0022 RT2870 +product ZCOM UB81 0x0023 UB81 product ZCOM RT2870_2 0x0025 RT2870 +product ZCOM UB82 0x0026 UB82 /* Zinwell products */ product ZINWELL RT2570 0x0260 RT2570 @@ -4645,6 +4673,7 @@ product ZORAN EX20DSC 0x4343 Digital Camera EX-20 DSC /* Zydas Technology Corporation products */ product ZYDAS ZD1211 0x1211 ZD1211 WLAN abg product ZYDAS ZD1211B 0x1215 ZD1211B +product ZYDAS ZD1221 0x1221 ZD1221 /* ZyXEL Communication Co. products */ product ZYXEL OMNI56K 0x1500 Omni 56K Plus @@ -4656,6 +4685,8 @@ product ZYXEL M202 0x340a M-202 product ZYXEL G220V2 0x340f G-220 v2 product ZYXEL G202 0x3410 G-202 product ZYXEL RT2870_1 0x3416 RT2870 +product ZYXEL NWD271N 0x3417 NWD-271N +product ZYXEL NWD211AN 0x3418 NWD-211AN product ZYXEL RT2870_2 0x341a RT2870 product ZYXEL RT3070 0x341e NWD2105 product ZYXEL RTL8192CU 0x341f RTL8192CU diff --git a/sys/dev/usb/wlan/if_rsu.c b/sys/dev/usb/wlan/if_rsu.c index 463a9bdc9a08f..4fb9d85bee9dd 100644 --- a/sys/dev/usb/wlan/if_rsu.c +++ b/sys/dev/usb/wlan/if_rsu.c @@ -22,10 +22,14 @@ __FBSDID("$FreeBSD$"); * Driver for Realtek RTL8188SU/RTL8191SU/RTL8192SU. * * TODO: - * o 11n support * o h/w crypto * o hostap / ibss / mesh + * o sensible RSSI levels + * o power-save operation */ + +#include "opt_wlan.h" + #include <sys/param.h> #include <sys/endian.h> #include <sys/sockio.h> @@ -74,8 +78,31 @@ static int rsu_debug = 0; SYSCTL_NODE(_hw_usb, OID_AUTO, rsu, CTLFLAG_RW, 0, "USB rsu"); SYSCTL_INT(_hw_usb_rsu, OID_AUTO, debug, CTLFLAG_RWTUN, &rsu_debug, 0, "Debug level"); +#define RSU_DPRINTF(_sc, _flg, ...) \ + do \ + if (((_flg) == (RSU_DEBUG_ANY)) || (rsu_debug & (_flg))) \ + device_printf((_sc)->sc_dev, __VA_ARGS__); \ + while (0) +#else +#define RSU_DPRINTF(_sc, _flg, ...) #endif +static int rsu_enable_11n = 1; +TUNABLE_INT("hw.usb.rsu.enable_11n", &rsu_enable_11n); + +#define RSU_DEBUG_ANY 0xffffffff +#define RSU_DEBUG_TX 0x00000001 +#define RSU_DEBUG_RX 0x00000002 +#define RSU_DEBUG_RESET 0x00000004 +#define RSU_DEBUG_CALIB 0x00000008 +#define RSU_DEBUG_STATE 0x00000010 +#define RSU_DEBUG_SCAN 0x00000020 +#define RSU_DEBUG_FWCMD 0x00000040 +#define RSU_DEBUG_TXDONE 0x00000080 +#define RSU_DEBUG_FW 0x00000100 +#define RSU_DEBUG_FWDBG 0x00000200 +#define RSU_DEBUG_AMPDU 0x00000400 + static const STRUCT_USB_HOST_ID rsu_devs[] = { #define RSU_HT_NOT_SUPPORTED 0 #define RSU_HT_SUPPORTED 1 @@ -131,6 +158,7 @@ static device_attach_t rsu_attach; static device_detach_t rsu_detach; static usb_callback_t rsu_bulk_tx_callback_be_bk; static usb_callback_t rsu_bulk_tx_callback_vi_vo; +static usb_callback_t rsu_bulk_tx_callback_h2c; static usb_callback_t rsu_bulk_rx_callback; static usb_error_t rsu_do_request(struct rsu_softc *, struct usb_device_request *, void *); @@ -150,6 +178,7 @@ static void rsu_free_tx_list(struct rsu_softc *); static void rsu_free_list(struct rsu_softc *, struct rsu_data [], int); static struct rsu_data *_rsu_getbuf(struct rsu_softc *); static struct rsu_data *rsu_getbuf(struct rsu_softc *); +static void rsu_freebuf(struct rsu_softc *, struct rsu_data *); static int rsu_write_region_1(struct rsu_softc *, uint16_t, uint8_t *, int); static void rsu_write_1(struct rsu_softc *, uint16_t, uint8_t); @@ -165,6 +194,7 @@ static uint8_t rsu_efuse_read_1(struct rsu_softc *, uint16_t); static int rsu_read_rom(struct rsu_softc *); static int rsu_fw_cmd(struct rsu_softc *, uint8_t, void *, int); static void rsu_calib_task(void *, int); +static void rsu_tx_task(void *, int); static int rsu_newstate(struct ieee80211vap *, enum ieee80211_state, int); #ifdef notyet static void rsu_set_key(struct rsu_softc *, const struct ieee80211_key *); @@ -173,17 +203,18 @@ static void rsu_delete_key(struct rsu_softc *, const struct ieee80211_key *); static int rsu_site_survey(struct rsu_softc *, struct ieee80211vap *); static int rsu_join_bss(struct rsu_softc *, struct ieee80211_node *); static int rsu_disconnect(struct rsu_softc *); +static int rsu_hwrssi_to_rssi(struct rsu_softc *, int hw_rssi); static void rsu_event_survey(struct rsu_softc *, uint8_t *, int); static void rsu_event_join_bss(struct rsu_softc *, uint8_t *, int); static void rsu_rx_event(struct rsu_softc *, uint8_t, uint8_t *, int); static void rsu_rx_multi_event(struct rsu_softc *, uint8_t *, int); +#if 0 static int8_t rsu_get_rssi(struct rsu_softc *, int, void *); +#endif +static struct mbuf * rsu_rx_frame(struct rsu_softc *, uint8_t *, int); +static struct mbuf * rsu_rx_multi_frame(struct rsu_softc *, uint8_t *, int); static struct mbuf * - rsu_rx_frame(struct rsu_softc *, uint8_t *, int, int *); -static struct mbuf * - rsu_rx_multi_frame(struct rsu_softc *, uint8_t *, int, int *); -static struct mbuf * - rsu_rxeof(struct usb_xfer *, struct rsu_data *, int *); + rsu_rxeof(struct usb_xfer *, struct rsu_data *); static void rsu_txeof(struct usb_xfer *, struct rsu_data *); static int rsu_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); @@ -192,9 +223,10 @@ static int rsu_tx_start(struct rsu_softc *, struct ieee80211_node *, struct mbuf *, struct rsu_data *); static int rsu_transmit(struct ieee80211com *, struct mbuf *); static void rsu_start(struct rsu_softc *); +static void _rsu_start(struct rsu_softc *); static void rsu_parent(struct ieee80211com *); static void rsu_stop(struct rsu_softc *); -static void rsu_ms_delay(struct rsu_softc *); +static void rsu_ms_delay(struct rsu_softc *, int); static device_method_t rsu_methods[] = { DEVMETHOD(device_probe, rsu_match), @@ -225,6 +257,9 @@ static uint8_t rsu_wme_ac_xfer_map[4] = { [WME_AC_VO] = RSU_BULK_TX_VI_VO, }; +/* XXX hard-coded */ +#define RSU_H2C_ENDPOINT 3 + static const struct usb_config rsu_config[RSU_N_TRANSFER] = { [RSU_BULK_RX] = { .type = UE_BULK, @@ -263,6 +298,19 @@ static const struct usb_config rsu_config[RSU_N_TRANSFER] = { .callback = rsu_bulk_tx_callback_vi_vo, .timeout = RSU_TX_TIMEOUT }, + [RSU_BULK_TX_H2C] = { + .type = UE_BULK, + .endpoint = 0x0d, + .direction = UE_DIR_OUT, + .bufsize = RSU_TXBUFSZ, + .flags = { + .ext_buffer = 1, + .pipe_bof = 1, + .short_xfer_ok = 1 + }, + .callback = rsu_bulk_tx_callback_h2c, + .timeout = RSU_TX_TIMEOUT + }, }; static int @@ -279,6 +327,75 @@ rsu_match(device_t self) } static int +rsu_send_mgmt(struct ieee80211_node *ni, int type, int arg) +{ + + return (ENOTSUP); +} + +static void +rsu_update_chw(struct ieee80211com *ic) +{ + +} + +/* + * notification from net80211 that it'd like to do A-MPDU on the given TID. + * + * Note: this actually hangs traffic at the present moment, so don't use it. + * The firmware debug does indiciate it's sending and establishing a TX AMPDU + * session, but then no traffic flows. + */ +static int +rsu_ampdu_enable(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap) +{ +#if 0 + struct rsu_softc *sc = ni->ni_ic->ic_softc; + struct r92s_add_ba_req req; + + /* Don't enable if it's requested or running */ + if (IEEE80211_AMPDU_REQUESTED(tap)) + return (0); + if (IEEE80211_AMPDU_RUNNING(tap)) + return (0); + + /* We've decided to send addba; so send it */ + req.tid = htole32(tap->txa_tid); + + /* Attempt net80211 state */ + if (ieee80211_ampdu_tx_request_ext(ni, tap->txa_tid) != 1) + return (0); + + /* Send the firmware command */ + RSU_DPRINTF(sc, RSU_DEBUG_AMPDU, "%s: establishing AMPDU TX for TID %d\n", + __func__, + tap->txa_tid); + + RSU_LOCK(sc); + if (rsu_fw_cmd(sc, R92S_CMD_ADDBA_REQ, &req, sizeof(req)) != 1) { + RSU_UNLOCK(sc); + /* Mark failure */ + (void) ieee80211_ampdu_tx_request_active_ext(ni, tap->txa_tid, 0); + return (0); + } + RSU_UNLOCK(sc); + + /* Mark success; we don't get any further notifications */ + (void) ieee80211_ampdu_tx_request_active_ext(ni, tap->txa_tid, 1); +#endif + /* Return 0, we're driving this ourselves */ + return (0); +} + +static int +rsu_wme_update(struct ieee80211com *ic) +{ + + /* Firmware handles this; not our problem */ + return (0); +} + +static int rsu_attach(device_t self) { struct usb_attach_arg *uaa = device_get_ivars(self); @@ -286,15 +403,31 @@ rsu_attach(device_t self) struct ieee80211com *ic = &sc->sc_ic; int error; uint8_t iface_index, bands; + struct usb_interface *iface; + const char *rft; device_set_usb_desc(self); sc->sc_udev = uaa->device; sc->sc_dev = self; + if (rsu_enable_11n) + sc->sc_ht = !! (USB_GET_DRIVER_INFO(uaa) & RSU_HT_SUPPORTED); + + /* Get number of endpoints */ + iface = usbd_get_iface(sc->sc_udev, 0); + sc->sc_nendpoints = iface->idesc->bNumEndpoints; + + /* Endpoints are hard-coded for now, so enforce 4-endpoint only */ + if (sc->sc_nendpoints != 4) { + device_printf(sc->sc_dev, + "the driver currently only supports 4-endpoint devices\n"); + return (ENXIO); + } mtx_init(&sc->sc_mtx, device_get_nameunit(self), MTX_NETWORK_LOCK, MTX_DEF); TIMEOUT_TASK_INIT(taskqueue_thread, &sc->calib_task, 0, rsu_calib_task, sc); + TASK_INIT(&sc->tx_task, 0, rsu_tx_task, sc); mbufq_init(&sc->sc_snd, ifqmaxlen); /* Allocate Tx/Rx buffers. */ @@ -331,8 +464,37 @@ rsu_attach(device_t self) device_printf(self, "could not read ROM\n"); goto fail_rom; } + + /* Figure out TX/RX streams */ + switch (sc->rom[84]) { + case 0x0: + sc->sc_rftype = RTL8712_RFCONFIG_1T1R; + sc->sc_nrxstream = 1; + sc->sc_ntxstream = 1; + rft = "1T1R"; + break; + case 0x1: + sc->sc_rftype = RTL8712_RFCONFIG_1T2R; + sc->sc_nrxstream = 2; + sc->sc_ntxstream = 1; + rft = "1T2R"; + break; + case 0x2: + sc->sc_rftype = RTL8712_RFCONFIG_2T2R; + sc->sc_nrxstream = 2; + sc->sc_ntxstream = 2; + rft = "2T2R"; + break; + default: + device_printf(sc->sc_dev, + "%s: unknown board type (rfconfig=0x%02x)\n", + __func__, + sc->rom[84]); + goto fail_rom; + } + IEEE80211_ADDR_COPY(ic->ic_macaddr, &sc->rom[0x12]); - device_printf(self, "MAC/BB RTL8712 cut %d\n", sc->cut); + device_printf(self, "MAC/BB RTL8712 cut %d %s\n", sc->cut, rft); ic->ic_softc = sc; ic->ic_name = device_get_nameunit(self); @@ -342,28 +504,37 @@ rsu_attach(device_t self) /* Set device capabilities. */ ic->ic_caps = IEEE80211_C_STA | /* station mode */ +#if 0 IEEE80211_C_BGSCAN | /* Background scan. */ +#endif IEEE80211_C_SHPREAMBLE | /* Short preamble supported. */ + IEEE80211_C_WME | /* WME/QoS */ IEEE80211_C_SHSLOT | /* Short slot time supported. */ IEEE80211_C_WPA; /* WPA/RSN. */ -#if 0 /* Check if HT support is present. */ - if (usb_lookup(rsu_devs_noht, uaa->vendor, uaa->product) == NULL) { - /* Set HT capabilities. */ - ic->ic_htcaps = - IEEE80211_HTCAP_CBW20_40 | - IEEE80211_HTCAP_DSSSCCK40; - /* Set supported HT rates. */ - for (i = 0; i < 2; i++) - ic->ic_sup_mcs[i] = 0xff; + if (sc->sc_ht) { + device_printf(sc->sc_dev, "%s: enabling 11n\n", __func__); + + /* Enable basic HT */ + ic->ic_htcaps = IEEE80211_HTC_HT | + IEEE80211_HTC_AMPDU | + IEEE80211_HTC_AMSDU | + IEEE80211_HTCAP_MAXAMSDU_3839 | + IEEE80211_HTCAP_SMPS_OFF; + ic->ic_htcaps |= IEEE80211_HTCAP_CHWIDTH40; + + /* set number of spatial streams */ + ic->ic_txstream = sc->sc_ntxstream; + ic->ic_rxstream = sc->sc_nrxstream; } -#endif /* Set supported .11b and .11g rates. */ bands = 0; setbit(&bands, IEEE80211_MODE_11B); setbit(&bands, IEEE80211_MODE_11G); + if (sc->sc_ht) + setbit(&bands, IEEE80211_MODE_11NG); ieee80211_init_channels(ic, NULL, &bands); ieee80211_ifattach(ic); @@ -376,6 +547,10 @@ rsu_attach(device_t self) ic->ic_update_mcast = rsu_update_mcast; ic->ic_parent = rsu_parent; ic->ic_transmit = rsu_transmit; + ic->ic_send_mgmt = rsu_send_mgmt; + ic->ic_update_chw = rsu_update_chw; + ic->ic_ampdu_enable = rsu_ampdu_enable; + ic->ic_wme.wme_update = rsu_wme_update; ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), RSU_TX_RADIOTAP_PRESENT, @@ -403,16 +578,25 @@ rsu_detach(device_t self) RSU_LOCK(sc); rsu_stop(sc); RSU_UNLOCK(sc); - usbd_transfer_unsetup(sc->sc_xfer, RSU_N_TRANSFER); - ieee80211_ifdetach(ic); - taskqueue_drain_timeout(taskqueue_thread, &sc->calib_task); + usbd_transfer_unsetup(sc->sc_xfer, RSU_N_TRANSFER); + /* + * Free buffers /before/ we detach from net80211, else node + * references to destroyed vaps will lead to a panic. + */ /* Free Tx/Rx buffers. */ + RSU_LOCK(sc); rsu_free_tx_list(sc); rsu_free_rx_list(sc); + RSU_UNLOCK(sc); + + /* Frames are freed; detach from net80211 */ + ieee80211_ifdetach(ic); + + taskqueue_drain_timeout(taskqueue_thread, &sc->calib_task); + taskqueue_drain(taskqueue_thread, &sc->tx_task); - mbufq_drain(&sc->sc_snd); mtx_destroy(&sc->sc_mtx); return (0); @@ -434,7 +618,7 @@ rsu_do_request(struct rsu_softc *sc, struct usb_device_request *req, break; DPRINTFN(1, "Control request failed, %s (retrying)\n", usbd_errstr(err)); - usb_pause_mtx(&sc->sc_mtx, hz / 100); + rsu_ms_delay(sc, 10); } return (err); @@ -466,6 +650,10 @@ rsu_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, uvp->newstate = vap->iv_newstate; vap->iv_newstate = rsu_newstate; + /* Limits from the r92su driver */ + vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_16; + vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_32K; + /* complete setup */ ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status, mac); @@ -491,6 +679,7 @@ rsu_scan_start(struct ieee80211com *ic) /* Scanning is done by the firmware. */ RSU_LOCK(sc); + /* XXX TODO: force awake if in in network-sleep? */ error = rsu_site_survey(sc, TAILQ_FIRST(&ic->ic_vaps)); RSU_UNLOCK(sc); if (error != 0) @@ -640,9 +829,7 @@ _rsu_getbuf(struct rsu_softc *sc) STAILQ_REMOVE_HEAD(&sc->sc_tx_inactive, next); else bf = NULL; - if (bf == NULL) - DPRINTF("out of xmit buffers\n"); - return (bf); + return (bf); } static struct rsu_data * @@ -653,11 +840,20 @@ rsu_getbuf(struct rsu_softc *sc) RSU_ASSERT_LOCKED(sc); bf = _rsu_getbuf(sc); - if (bf == NULL) - DPRINTF("stop queue\n"); + if (bf == NULL) { + RSU_DPRINTF(sc, RSU_DEBUG_TX, "%s: no buffers\n", __func__); + } return (bf); } +static void +rsu_freebuf(struct rsu_softc *sc, struct rsu_data *bf) +{ + + RSU_ASSERT_LOCKED(sc); + STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, bf, next); +} + static int rsu_write_region_1(struct rsu_softc *sc, uint16_t addr, uint8_t *buf, int len) @@ -744,11 +940,11 @@ rsu_fw_iocmd(struct rsu_softc *sc, uint32_t iocmd) int ntries; rsu_write_4(sc, R92S_IOCMD_CTRL, iocmd); - rsu_ms_delay(sc); + rsu_ms_delay(sc, 1); for (ntries = 0; ntries < 50; ntries++) { if (rsu_read_4(sc, R92S_IOCMD_CTRL) == 0) return (0); - rsu_ms_delay(sc); + rsu_ms_delay(sc, 1); } return (ETIMEDOUT); } @@ -768,7 +964,7 @@ rsu_efuse_read_1(struct rsu_softc *sc, uint16_t addr) reg = rsu_read_4(sc, R92S_EFUSE_CTRL); if (reg & R92S_EFUSE_CTRL_VALID) return (MS(reg, R92S_EFUSE_CTRL_DATA)); - rsu_ms_delay(sc); + rsu_ms_delay(sc, 1); } device_printf(sc->sc_dev, "could not read efuse byte at address 0x%x\n", addr); @@ -792,7 +988,7 @@ rsu_read_rom(struct rsu_softc *sc) /* Turn on 2.5V to prevent eFuse leakage. */ reg = rsu_read_1(sc, R92S_EFUSE_TEST + 3); rsu_write_1(sc, R92S_EFUSE_TEST + 3, reg | 0x80); - rsu_ms_delay(sc); + rsu_ms_delay(sc, 1); rsu_write_1(sc, R92S_EFUSE_TEST + 3, reg & ~0x80); /* Read full ROM image. */ @@ -830,18 +1026,24 @@ rsu_read_rom(struct rsu_softc *sc) static int rsu_fw_cmd(struct rsu_softc *sc, uint8_t code, void *buf, int len) { - const uint8_t which = rsu_wme_ac_xfer_map[WME_AC_VO]; + const uint8_t which = RSU_H2C_ENDPOINT; struct rsu_data *data; struct r92s_tx_desc *txd; struct r92s_fw_cmd_hdr *cmd; int cmdsz; int xferlen; + RSU_ASSERT_LOCKED(sc); + data = rsu_getbuf(sc); if (data == NULL) return (ENOMEM); + /* Blank the entire payload, just to be safe */ + memset(data->buf, '\0', RSU_TXBUFSZ); + /* Round-up command length to a multiple of 8 bytes. */ + /* XXX TODO: is this required? */ cmdsz = (len + 7) & ~7; xferlen = sizeof(*txd) + sizeof(*cmd) + cmdsz; @@ -866,7 +1068,9 @@ rsu_fw_cmd(struct rsu_softc *sc, uint8_t code, void *buf, int len) /* Copy command payload. */ memcpy(&cmd[1], buf, len); - DPRINTFN(2, "Tx cmd code=0x%x len=0x%x\n", code, cmdsz); + RSU_DPRINTF(sc, RSU_DEBUG_TX | RSU_DEBUG_FWCMD, + "%s: Tx cmd code=0x%x len=0x%x\n", + __func__, code, cmdsz); data->buflen = xferlen; STAILQ_INSERT_TAIL(&sc->sc_tx_pending[which], data, next); usbd_transfer_start(sc->sc_xfer[which]); @@ -879,9 +1083,12 @@ static void rsu_calib_task(void *arg, int pending __unused) { struct rsu_softc *sc = arg; +#ifdef notyet uint32_t reg; +#endif - DPRINTFN(6, "running calibration task\n"); + RSU_DPRINTF(sc, RSU_DEBUG_CALIB, "%s: running calibration task\n", + __func__); RSU_LOCK(sc); #ifdef notyet @@ -896,14 +1103,95 @@ rsu_calib_task(void *arg, int pending __unused) #endif /* Read current signal level. */ if (rsu_fw_iocmd(sc, 0xf4000001) == 0) { - reg = rsu_read_4(sc, R92S_IOCMD_DATA); - DPRINTFN(8, "RSSI=%d%%\n", reg >> 4); + sc->sc_currssi = rsu_read_4(sc, R92S_IOCMD_DATA); + RSU_DPRINTF(sc, RSU_DEBUG_CALIB, "%s: RSSI=%d (%d)\n", + __func__, sc->sc_currssi, + rsu_hwrssi_to_rssi(sc, sc->sc_currssi)); } if (sc->sc_calibrating) taskqueue_enqueue_timeout(taskqueue_thread, &sc->calib_task, hz); RSU_UNLOCK(sc); } +static void +rsu_tx_task(void *arg, int pending __unused) +{ + struct rsu_softc *sc = arg; + + RSU_LOCK(sc); + _rsu_start(sc); + RSU_UNLOCK(sc); +} + +#define RSU_PWR_UNKNOWN 0x0 +#define RSU_PWR_ACTIVE 0x1 +#define RSU_PWR_OFF 0x2 +#define RSU_PWR_SLEEP 0x3 + +/* + * Set the current power state. + * + * The rtlwifi code doesn't do this so aggressively; it + * waits for an idle period after association with + * no traffic before doing this. + * + * For now - it's on in all states except RUN, and + * in RUN it'll transition to allow sleep. + */ + +struct r92s_pwr_cmd { + uint8_t mode; + uint8_t smart_ps; + uint8_t bcn_pass_time; +}; + +static int +rsu_set_fw_power_state(struct rsu_softc *sc, int state) +{ + struct r92s_set_pwr_mode cmd; + //struct r92s_pwr_cmd cmd; + int error; + + RSU_ASSERT_LOCKED(sc); + + /* only change state if required */ + if (sc->sc_curpwrstate == state) + return (0); + + memset(&cmd, 0, sizeof(cmd)); + + switch (state) { + case RSU_PWR_ACTIVE: + /* Force the hardware awake */ + rsu_write_1(sc, R92S_USB_HRPWM, + R92S_USB_HRPWM_PS_ST_ACTIVE | R92S_USB_HRPWM_PS_ALL_ON); + cmd.mode = R92S_PS_MODE_ACTIVE; + break; + case RSU_PWR_SLEEP: + cmd.mode = R92S_PS_MODE_DTIM; /* XXX configurable? */ + cmd.smart_ps = 1; /* XXX 2 if doing p2p */ + cmd.bcn_pass_time = 5; /* in 100mS usb.c, linux/rtlwifi */ + break; + case RSU_PWR_OFF: + cmd.mode = R92S_PS_MODE_RADIOOFF; + break; + default: + device_printf(sc->sc_dev, "%s: unknown ps mode (%d)\n", + __func__, + state); + return (ENXIO); + } + + RSU_DPRINTF(sc, RSU_DEBUG_RESET, + "%s: setting ps mode to %d (mode %d)\n", + __func__, state, cmd.mode); + error = rsu_fw_cmd(sc, R92S_CMD_SET_PWR_MODE, &cmd, sizeof(cmd)); + if (error == 0) + sc->sc_curpwrstate = state; + + return (error); +} + static int rsu_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { @@ -916,7 +1204,9 @@ rsu_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) int error, startcal = 0; ostate = vap->iv_state; - DPRINTF("%s -> %s\n", ieee80211_state_name[ostate], + RSU_DPRINTF(sc, RSU_DEBUG_STATE, "%s: %s -> %s\n", + __func__, + ieee80211_state_name[ostate], ieee80211_state_name[nstate]); IEEE80211_UNLOCK(ic); @@ -926,6 +1216,7 @@ rsu_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) sc->sc_calibrating = 0; RSU_UNLOCK(sc); taskqueue_drain_timeout(taskqueue_thread, &sc->calib_task); + taskqueue_drain(taskqueue_thread, &sc->tx_task); /* Disassociate from our current BSS. */ RSU_LOCK(sc); rsu_disconnect(sc); @@ -933,9 +1224,11 @@ rsu_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) RSU_LOCK(sc); switch (nstate) { case IEEE80211_S_INIT: + (void) rsu_set_fw_power_state(sc, RSU_PWR_ACTIVE); break; case IEEE80211_S_AUTH: ni = ieee80211_ref_node(vap->iv_bss); + (void) rsu_set_fw_power_state(sc, RSU_PWR_ACTIVE); error = rsu_join_bss(sc, ni); ieee80211_free_node(ni); if (error != 0) { @@ -948,6 +1241,7 @@ rsu_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) rs = &ni->ni_rates; /* Indicate highest supported rate. */ ni->ni_txrate = rs->rs_rates[rs->rs_nrates - 1]; + (void) rsu_set_fw_power_state(sc, RSU_PWR_SLEEP); ieee80211_free_node(ni); startcal = 1; break; @@ -1008,6 +1302,9 @@ rsu_site_survey(struct rsu_softc *sc, struct ieee80211vap *vap) { struct r92s_fw_cmd_sitesurvey cmd; struct ieee80211com *ic = &sc->sc_ic; + int r; + + RSU_ASSERT_LOCKED(sc); memset(&cmd, 0, sizeof(cmd)); if ((ic->ic_flags & IEEE80211_F_ASCAN) || sc->sc_scan_pass == 1) @@ -1021,7 +1318,11 @@ rsu_site_survey(struct rsu_softc *sc, struct ieee80211vap *vap) } DPRINTF("sending site survey command, pass=%d\n", sc->sc_scan_pass); - return (rsu_fw_cmd(sc, R92S_CMD_SITE_SURVEY, &cmd, sizeof(cmd))); + r = rsu_fw_cmd(sc, R92S_CMD_SITE_SURVEY, &cmd, sizeof(cmd)); + if (r == 0) { + sc->sc_scanning = 1; + } + return (r); } static int @@ -1036,10 +1337,33 @@ rsu_join_bss(struct rsu_softc *sc, struct ieee80211_node *ni) uint8_t *frm; uint8_t opmode; int error; + int cnt; + char *msg = "rsujoin"; + + RSU_ASSERT_LOCKED(sc); + + /* + * Until net80211 scanning doesn't automatically finish + * before we tell it to, let's just wait until any pending + * scan is done. + * + * XXX TODO: yes, this releases and re-acquires the lock. + * We should re-verify the state whenever we re-attempt this! + */ + cnt = 0; + while (sc->sc_scanning && cnt < 10) { + device_printf(sc->sc_dev, + "%s: still scanning! (attempt %d)\n", + __func__, cnt); + msleep(msg, &sc->sc_mtx, 0, msg, hz / 2); + cnt++; + } /* Let the FW decide the opmode based on the capinfo field. */ opmode = NDIS802_11AUTOUNKNOWN; - DPRINTF("setting operating mode to %d\n", opmode); + RSU_DPRINTF(sc, RSU_DEBUG_RESET, + "%s: setting operating mode to %d\n", + __func__, opmode); error = rsu_fw_cmd(sc, R92S_CMD_SET_OPMODE, &opmode, sizeof(opmode)); if (error != 0) return (error); @@ -1050,7 +1374,9 @@ rsu_join_bss(struct rsu_softc *sc, struct ieee80211_node *ni) auth.dot1x = (ni->ni_authmode == IEEE80211_AUTH_8021X); } else auth.mode = R92S_AUTHMODE_OPEN; - DPRINTF("setting auth mode to %d\n", auth.mode); + RSU_DPRINTF(sc, RSU_DEBUG_RESET, + "%s: setting auth mode to %d\n", + __func__, auth.mode); error = rsu_fw_cmd(sc, R92S_CMD_SET_AUTH, &auth, sizeof(auth)); if (error != 0) return (error); @@ -1071,6 +1397,7 @@ rsu_join_bss(struct rsu_softc *sc, struct ieee80211_node *ni) bss->config.bintval = htole32(ni->ni_intval); bss->config.dsconfig = htole32(ieee80211_chan2ieee(ic, ni->ni_chan)); bss->inframode = htole32(NDIS802_11INFRASTRUCTURE); + /* XXX verify how this is supposed to look! */ memcpy(bss->supprates, ni->ni_rates.rs_rates, ni->ni_rates.rs_nrates); /* Write the fixed fields of the beacon frame. */ @@ -1083,11 +1410,18 @@ rsu_join_bss(struct rsu_softc *sc, struct ieee80211_node *ni) frm = ieee80211_add_rsn(frm, vap); frm = ieee80211_add_wpa(frm, vap); frm = ieee80211_add_qos(frm, ni); - if (ni->ni_flags & IEEE80211_NODE_HT) + if ((ic->ic_flags & IEEE80211_F_WME) && + (ni->ni_ies.wme_ie != NULL)) + frm = ieee80211_add_wme_info(frm, &ic->ic_wme); + if (ni->ni_flags & IEEE80211_NODE_HT) { frm = ieee80211_add_htcap(frm, ni); + frm = ieee80211_add_htinfo(frm, ni); + } bss->ieslen = htole32(frm - (uint8_t *)fixed); bss->len = htole32(((frm - buf) + 3) & ~3); - DPRINTF("sending join bss command to %s chan %d\n", + RSU_DPRINTF(sc, RSU_DEBUG_RESET | RSU_DEBUG_FWCMD, + "%s: sending join bss command to %s chan %d\n", + __func__, ether_sprintf(bss->macaddr), le32toh(bss->config.dsconfig)); return (rsu_fw_cmd(sc, R92S_CMD_JOIN_BSS, buf, sizeof(buf))); } @@ -1098,17 +1432,36 @@ rsu_disconnect(struct rsu_softc *sc) uint32_t zero = 0; /* :-) */ /* Disassociate from our current BSS. */ - DPRINTF("sending disconnect command\n"); + RSU_DPRINTF(sc, RSU_DEBUG_STATE | RSU_DEBUG_FWCMD, + "%s: sending disconnect command\n", __func__); return (rsu_fw_cmd(sc, R92S_CMD_DISCONNECT, &zero, sizeof(zero))); } +/* + * Map the hardware provided RSSI value to a signal level. + * For the most part it's just something we divide by and cap + * so it doesn't overflow the representation by net80211. + */ +static int +rsu_hwrssi_to_rssi(struct rsu_softc *sc, int hw_rssi) +{ + int v; + + if (hw_rssi == 0) + return (0); + v = hw_rssi >> 4; + if (v > 80) + v = 80; + return (v); +} + static void rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, int len) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_frame *wh; - struct ieee80211_channel *c; struct ndis_wlan_bssid_ex *bss; + struct ieee80211_rx_stats rxs; struct mbuf *m; int pktlen; @@ -1118,13 +1471,17 @@ rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, int len) if (__predict_false(len < sizeof(*bss) + le32toh(bss->ieslen))) return; - DPRINTFN(2, "found BSS %s: len=%d chan=%d inframode=%d " - "networktype=%d privacy=%d\n", + RSU_DPRINTF(sc, RSU_DEBUG_SCAN, + "%s: found BSS %s: len=%d chan=%d inframode=%d " + "networktype=%d privacy=%d, RSSI=%d\n", + __func__, ether_sprintf(bss->macaddr), le32toh(bss->len), le32toh(bss->config.dsconfig), le32toh(bss->inframode), - le32toh(bss->networktype), le32toh(bss->privacy)); + le32toh(bss->networktype), le32toh(bss->privacy), + le32toh(bss->rssi)); /* Build a fake beacon frame to let net80211 do all the parsing. */ + /* XXX TODO: just call the new scan API methods! */ pktlen = sizeof(*wh) + le32toh(bss->ieslen); if (__predict_false(pktlen > MCLBYTES)) return; @@ -1144,17 +1501,20 @@ rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, int len) /* Finalize mbuf. */ m->m_pkthdr.len = m->m_len = pktlen; - /* Fix the channel. */ - c = ieee80211_find_channel_byieee(ic, - le32toh(bss->config.dsconfig), - IEEE80211_CHAN_G); - if (c) { - ic->ic_curchan = c; - ieee80211_radiotap_chan_change(ic); - } + + /* Set channel flags for input path */ + bzero(&rxs, sizeof(rxs)); + rxs.r_flags |= IEEE80211_R_IEEE | IEEE80211_R_FREQ; + rxs.r_flags |= IEEE80211_R_NF | IEEE80211_R_RSSI; + rxs.c_ieee = le32toh(bss->config.dsconfig); + rxs.c_freq = ieee80211_ieee2mhz(rxs.c_ieee, IEEE80211_CHAN_2GHZ); + /* This is a number from 0..100; so let's just divide it down a bit */ + rxs.rssi = le32toh(bss->rssi) / 2; + rxs.nf = -96; + /* XXX avoid a LOR */ RSU_UNLOCK(sc); - ieee80211_input_all(ic, m, le32toh(bss->rssi), 0); + ieee80211_input_mimo_all(ic, m, &rxs); RSU_LOCK(sc); } @@ -1173,20 +1533,30 @@ rsu_event_join_bss(struct rsu_softc *sc, uint8_t *buf, int len) rsp = (struct r92s_event_join_bss *)buf; res = (int)le32toh(rsp->join_res); - DPRINTF("Rx join BSS event len=%d res=%d\n", len, res); + RSU_DPRINTF(sc, RSU_DEBUG_STATE | RSU_DEBUG_FWCMD, + "%s: Rx join BSS event len=%d res=%d\n", + __func__, len, res); + + /* + * XXX Don't do this; there's likely a better way to tell + * the caller we failed. + */ if (res <= 0) { RSU_UNLOCK(sc); ieee80211_new_state(vap, IEEE80211_S_SCAN, -1); RSU_LOCK(sc); return; } + tmp = le32toh(rsp->associd); if (tmp >= vap->iv_max_aid) { DPRINTF("Assoc ID overflow\n"); tmp = 1; } - DPRINTF("associated with %s associd=%d\n", - ether_sprintf(rsp->bss.macaddr), tmp); + RSU_DPRINTF(sc, RSU_DEBUG_STATE | RSU_DEBUG_FWCMD, + "%s: associated with %s associd=%d\n", + __func__, ether_sprintf(rsp->bss.macaddr), tmp); + /* XXX is this required? What's the top two bits for again? */ ni->ni_associd = tmp | 0xc000; RSU_UNLOCK(sc); ieee80211_new_state(vap, IEEE80211_S_RUN, @@ -1195,24 +1565,61 @@ rsu_event_join_bss(struct rsu_softc *sc, uint8_t *buf, int len) } static void +rsu_event_addba_req_report(struct rsu_softc *sc, uint8_t *buf, int len) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct r92s_add_ba_event *ba = (void *) buf; + struct ieee80211_node *ni; + + if (len < sizeof(*ba)) { + device_printf(sc->sc_dev, "%s: short read (%d)\n", __func__, len); + return; + } + + if (vap == NULL) + return; + + RSU_DPRINTF(sc, RSU_DEBUG_AMPDU, "%s: mac=%s, tid=%d, ssn=%d\n", + __func__, + ether_sprintf(ba->mac_addr), + (int) ba->tid, + (int) le16toh(ba->ssn)); + + /* XXX do node lookup; this is STA specific */ + + ni = ieee80211_ref_node(vap->iv_bss); + ieee80211_ampdu_rx_start_ext(ni, ba->tid, le16toh(ba->ssn) >> 4, 32); + ieee80211_free_node(ni); +} + +static void rsu_rx_event(struct rsu_softc *sc, uint8_t code, uint8_t *buf, int len) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - DPRINTFN(4, "Rx event code=%d len=%d\n", code, len); + RSU_DPRINTF(sc, RSU_DEBUG_RX | RSU_DEBUG_FWCMD, + "%s: Rx event code=%d len=%d\n", __func__, code, len); switch (code) { case R92S_EVT_SURVEY: - if (vap->iv_state == IEEE80211_S_SCAN) - rsu_event_survey(sc, buf, len); + rsu_event_survey(sc, buf, len); break; case R92S_EVT_SURVEY_DONE: - DPRINTF("site survey pass %d done, found %d BSS\n", - sc->sc_scan_pass, le32toh(*(uint32_t *)buf)); + RSU_DPRINTF(sc, RSU_DEBUG_SCAN, + "%s: site survey pass %d done, found %d BSS\n", + __func__, sc->sc_scan_pass, le32toh(*(uint32_t *)buf)); + sc->sc_scanning = 0; if (vap->iv_state != IEEE80211_S_SCAN) break; /* Ignore if not scanning. */ + + /* + * XXX TODO: This needs to be done without a transition to + * the SCAN state again. Grr. + */ if (sc->sc_scan_pass == 0 && vap->iv_des_nssid != 0) { /* Schedule a directed scan for hidden APs. */ + /* XXX bad! */ sc->sc_scan_pass = 1; RSU_UNLOCK(sc); ieee80211_new_state(vap, IEEE80211_S_SCAN, -1); @@ -1225,11 +1632,10 @@ rsu_rx_event(struct rsu_softc *sc, uint8_t code, uint8_t *buf, int len) if (vap->iv_state == IEEE80211_S_AUTH) rsu_event_join_bss(sc, buf, len); break; -#if 0 -XXX This event is occurring regularly, possibly due to some power saving event -XXX and disrupts the WLAN traffic. Disable for now. case R92S_EVT_DEL_STA: - DPRINTF("disassociated from %s\n", ether_sprintf(buf)); + RSU_DPRINTF(sc, RSU_DEBUG_FWCMD | RSU_DEBUG_STATE, + "%s: disassociated from %s\n", __func__, + ether_sprintf(buf)); if (vap->iv_state == IEEE80211_S_RUN && IEEE80211_ADDR_EQ(vap->iv_bss->ni_bssid, buf)) { RSU_UNLOCK(sc); @@ -1237,17 +1643,19 @@ XXX and disrupts the WLAN traffic. Disable for now. RSU_LOCK(sc); } break; -#endif case R92S_EVT_WPS_PBC: - DPRINTF("WPS PBC pushed.\n"); + RSU_DPRINTF(sc, RSU_DEBUG_RX | RSU_DEBUG_FWCMD, + "%s: WPS PBC pushed.\n", __func__); break; case R92S_EVT_FWDBG: - if (vap->iv_ifp->if_flags & IFF_DEBUG) { - buf[60] = '\0'; - printf("FWDBG: %s\n", (char *)buf); - } + buf[60] = '\0'; + RSU_DPRINTF(sc, RSU_DEBUG_FWDBG, "FWDBG: %s\n", (char *)buf); + break; + case R92S_EVT_ADDBA_REQ_REPORT: + rsu_event_addba_req_report(sc, buf, len); break; default: + device_printf(sc->sc_dev, "%s: unhandled code (%d)\n", __func__, code); break; } } @@ -1258,7 +1666,7 @@ rsu_rx_multi_event(struct rsu_softc *sc, uint8_t *buf, int len) struct r92s_fw_cmd_hdr *cmd; int cmdsz; - DPRINTFN(6, "Rx events len=%d\n", len); + RSU_DPRINTF(sc, RSU_DEBUG_RX, "%s: Rx events len=%d\n", __func__, len); /* Skip Rx status. */ buf += sizeof(struct r92s_rx_stat); @@ -1285,6 +1693,7 @@ rsu_rx_multi_event(struct rsu_softc *sc, uint8_t *buf, int len) } } +#if 0 static int8_t rsu_get_rssi(struct rsu_softc *sc, int rate, void *physt) { @@ -1305,9 +1714,10 @@ rsu_get_rssi(struct rsu_softc *sc, int rate, void *physt) } return (rssi); } +#endif static struct mbuf * -rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int pktlen, int *rssi) +rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int pktlen) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_frame *wh; @@ -1333,14 +1743,17 @@ rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int pktlen, int *rssi) rate = MS(rxdw3, R92S_RXDW3_RATE); infosz = MS(rxdw0, R92S_RXDW0_INFOSZ) * 8; +#if 0 /* Get RSSI from PHY status descriptor if present. */ if (infosz != 0) *rssi = rsu_get_rssi(sc, rate, &stat[1]); else *rssi = 0; +#endif - DPRINTFN(5, "Rx frame len=%d rate=%d infosz=%d rssi=%d\n", - pktlen, rate, infosz, *rssi); + RSU_DPRINTF(sc, RSU_DEBUG_RX, + "%s: Rx frame len=%d rate=%d infosz=%d\n", + __func__, pktlen, rate, infosz); m = m_get2(pktlen, M_NOWAIT, MT_DATA, M_PKTHDR); if (__predict_false(m == NULL)) { @@ -1382,7 +1795,11 @@ rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int pktlen, int *rssi) /* Bit 7 set means HT MCS instead of rate. */ tap->wr_rate = 0x80 | (rate - 12); } +#if 0 tap->wr_dbm_antsignal = *rssi; +#endif + /* XXX not nice */ + tap->wr_dbm_antsignal = rsu_hwrssi_to_rssi(sc, sc->sc_currssi); tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq); tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); } @@ -1391,7 +1808,7 @@ rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int pktlen, int *rssi) } static struct mbuf * -rsu_rx_multi_frame(struct rsu_softc *sc, uint8_t *buf, int len, int *rssi) +rsu_rx_multi_frame(struct rsu_softc *sc, uint8_t *buf, int len) { struct r92s_rx_stat *stat; uint32_t rxdw0; @@ -1401,7 +1818,8 @@ rsu_rx_multi_frame(struct rsu_softc *sc, uint8_t *buf, int len, int *rssi) /* Get the number of encapsulated frames. */ stat = (struct r92s_rx_stat *)buf; npkts = MS(le32toh(stat->rxdw2), R92S_RXDW2_PKTCNT); - DPRINTFN(6, "Rx %d frames in one chunk\n", npkts); + RSU_DPRINTF(sc, RSU_DEBUG_RX, + "%s: Rx %d frames in one chunk\n", __func__, npkts); /* Process all of them. */ while (npkts-- > 0) { @@ -1422,7 +1840,7 @@ rsu_rx_multi_frame(struct rsu_softc *sc, uint8_t *buf, int len, int *rssi) break; /* Process 802.11 frame. */ - m = rsu_rx_frame(sc, buf, pktlen, rssi); + m = rsu_rx_frame(sc, buf, pktlen); if (m0 == NULL) m0 = m; if (prevm == NULL) @@ -1441,7 +1859,7 @@ rsu_rx_multi_frame(struct rsu_softc *sc, uint8_t *buf, int len, int *rssi) } static struct mbuf * -rsu_rxeof(struct usb_xfer *xfer, struct rsu_data *data, int *rssi) +rsu_rxeof(struct usb_xfer *xfer, struct rsu_data *data) { struct rsu_softc *sc = data->sc; struct ieee80211com *ic = &sc->sc_ic; @@ -1462,7 +1880,7 @@ rsu_rxeof(struct usb_xfer *xfer, struct rsu_data *data, int *rssi) /* No packets to process. */ return (NULL); } else - return (rsu_rx_multi_frame(sc, data->buf, len, rssi)); + return (rsu_rx_multi_frame(sc, data->buf, len)); } static void @@ -1474,7 +1892,6 @@ rsu_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) struct ieee80211_node *ni; struct mbuf *m = NULL, *next; struct rsu_data *data; - int rssi = 1; RSU_ASSERT_LOCKED(sc); @@ -1484,11 +1901,15 @@ rsu_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) if (data == NULL) goto tr_setup; STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next); - m = rsu_rxeof(xfer, data, &rssi); + m = rsu_rxeof(xfer, data); STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next); /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: + /* + * XXX TODO: if we have an mbuf list, but then + * we hit data == NULL, what now? + */ data = STAILQ_FIRST(&sc->sc_rx_inactive); if (data == NULL) { KASSERT(m == NULL, ("mbuf isn't NULL")); @@ -1506,16 +1927,23 @@ tr_setup: */ RSU_UNLOCK(sc); while (m != NULL) { + int rssi; + + /* Cheat and get the last calibrated RSSI */ + rssi = rsu_hwrssi_to_rssi(sc, sc->sc_currssi); + next = m->m_next; m->m_next = NULL; wh = mtod(m, struct ieee80211_frame *); ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); if (ni != NULL) { - (void)ieee80211_input(ni, m, rssi, 0); + if (ni->ni_flags & IEEE80211_NODE_HT) + m->m_flags |= M_AMPDU; + (void)ieee80211_input(ni, m, rssi, -96); ieee80211_free_node(ni); } else - (void)ieee80211_input_all(ic, m, rssi, 0); + (void)ieee80211_input_all(ic, m, rssi, -96); m = next; } RSU_LOCK(sc); @@ -1540,6 +1968,13 @@ tr_setup: static void rsu_txeof(struct usb_xfer *xfer, struct rsu_data *data) { +#ifdef USB_DEBUG + struct rsu_softc *sc = usbd_xfer_softc(xfer); +#endif + + RSU_DPRINTF(sc, RSU_DEBUG_TXDONE, "%s: called; data=%p\n", + __func__, + data); if (data->m) { /* XXX status? */ @@ -1564,22 +1999,27 @@ rsu_bulk_tx_callback_sub(struct usb_xfer *xfer, usb_error_t error, data = STAILQ_FIRST(&sc->sc_tx_active[which]); if (data == NULL) goto tr_setup; - DPRINTF("transfer done %p\n", data); + RSU_DPRINTF(sc, RSU_DEBUG_TXDONE, "%s: transfer done %p\n", + __func__, data); STAILQ_REMOVE_HEAD(&sc->sc_tx_active[which], next); rsu_txeof(xfer, data); - STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next); + rsu_freebuf(sc, data); /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: data = STAILQ_FIRST(&sc->sc_tx_pending[which]); if (data == NULL) { - DPRINTF("empty pending queue sc %p\n", sc); + RSU_DPRINTF(sc, RSU_DEBUG_TXDONE, + "%s: empty pending queue sc %p\n", __func__, sc); return; } STAILQ_REMOVE_HEAD(&sc->sc_tx_pending[which], next); STAILQ_INSERT_TAIL(&sc->sc_tx_active[which], data, next); usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); - DPRINTF("submitting transfer %p\n", data); + RSU_DPRINTF(sc, RSU_DEBUG_TXDONE, + "%s: submitting transfer %p\n", + __func__, + data); usbd_transfer_submit(xfer); break; default: @@ -1587,7 +2027,7 @@ tr_setup: if (data != NULL) { STAILQ_REMOVE_HEAD(&sc->sc_tx_active[which], next); rsu_txeof(xfer, data); - STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next); + rsu_freebuf(sc, data); } counter_u64_add(ic->ic_oerrors, 1); @@ -1597,20 +2037,52 @@ tr_setup: } break; } + + /* + * XXX TODO: if the queue is low, flush out FF TX frames. + * Remember to unlock the driver for now; net80211 doesn't + * defer it for us. + */ } static void rsu_bulk_tx_callback_be_bk(struct usb_xfer *xfer, usb_error_t error) { + struct rsu_softc *sc = usbd_xfer_softc(xfer); + rsu_bulk_tx_callback_sub(xfer, error, RSU_BULK_TX_BE_BK); + + /* This kicks the TX taskqueue */ + rsu_start(sc); } static void rsu_bulk_tx_callback_vi_vo(struct usb_xfer *xfer, usb_error_t error) { + struct rsu_softc *sc = usbd_xfer_softc(xfer); + rsu_bulk_tx_callback_sub(xfer, error, RSU_BULK_TX_VI_VO); + + /* This kicks the TX taskqueue */ + rsu_start(sc); +} + +static void +rsu_bulk_tx_callback_h2c(struct usb_xfer *xfer, usb_error_t error) +{ + struct rsu_softc *sc = usbd_xfer_softc(xfer); + + rsu_bulk_tx_callback_sub(xfer, error, RSU_BULK_TX_H2C); + + /* This kicks the TX taskqueue */ + rsu_start(sc); } +/* + * Transmit the given frame. + * + * This doesn't free the node or mbuf upon failure. + */ static int rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni, struct mbuf *m0, struct rsu_data *data) @@ -1621,27 +2093,47 @@ rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni, struct ieee80211_key *k = NULL; struct r92s_tx_desc *txd; uint8_t type; - uint8_t tid = 0; + int prio = 0; uint8_t which; int hasqos; int xferlen; + int qid; RSU_ASSERT_LOCKED(sc); wh = mtod(m0, struct ieee80211_frame *); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + RSU_DPRINTF(sc, RSU_DEBUG_TX, "%s: data=%p, m=%p\n", + __func__, data, m0); + if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { k = ieee80211_crypto_encap(ni, m0); if (k == NULL) { device_printf(sc->sc_dev, "ieee80211_crypto_encap returns NULL.\n"); /* XXX we don't expect the fragmented frames */ - m_freem(m0); return (ENOBUFS); } wh = mtod(m0, struct ieee80211_frame *); } + /* If we have QoS then use it */ + /* XXX TODO: mbuf WME/PRI versus TID? */ + if (IEEE80211_QOS_HAS_SEQ(wh)) { + /* Has QoS */ + prio = M_WME_GETAC(m0); + which = rsu_wme_ac_xfer_map[prio]; + hasqos = 1; + } else { + /* Non-QoS TID */ + /* XXX TODO: tid=0 for non-qos TID? */ + which = rsu_wme_ac_xfer_map[WME_AC_BE]; + hasqos = 0; + prio = 0; + } + + qid = rsu_ac2qid[prio]; +#if 0 switch (type) { case IEEE80211_FC0_TYPE_CTL: case IEEE80211_FC0_TYPE_MGT: @@ -1652,6 +2144,13 @@ rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni, break; } hasqos = 0; +#endif + + RSU_DPRINTF(sc, RSU_DEBUG_TX, "%s: pri=%d, which=%d, hasqos=%d\n", + __func__, + prio, + which, + hasqos); /* Fill Tx descriptor. */ txd = (struct r92s_tx_desc *)data->buf; @@ -1663,8 +2162,7 @@ rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni, R92S_TXDW0_OWN | R92S_TXDW0_FSG | R92S_TXDW0_LSG); txd->txdw1 |= htole32( - SM(R92S_TXDW1_MACID, R92S_MACID_BSS) | - SM(R92S_TXDW1_QSEL, R92S_TXDW1_QSEL_BE)); + SM(R92S_TXDW1_MACID, R92S_MACID_BSS) | SM(R92S_TXDW1_QSEL, qid)); if (!hasqos) txd->txdw1 |= htole32(R92S_TXDW1_NONQOS); #ifdef notyet @@ -1687,14 +2185,15 @@ rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni, SM(R92S_TXDW1_KEYIDX, k->k_id)); } #endif + /* XXX todo: set AGGEN bit if appropriate? */ txd->txdw2 |= htole32(R92S_TXDW2_BK); if (IEEE80211_IS_MULTICAST(wh->i_addr1)) txd->txdw2 |= htole32(R92S_TXDW2_BMCAST); /* * Firmware will use and increment the sequence number for the - * specified TID. + * specified priority. */ - txd->txdw3 |= htole32(SM(R92S_TXDW3_SEQ, tid)); + txd->txdw3 |= htole32(SM(R92S_TXDW3_SEQ, prio)); if (ieee80211_radiotap_active_vap(vap)) { struct rsu_tx_radiotap_header *tap = &sc->sc_txtap; @@ -1704,6 +2203,7 @@ rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni, tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); ieee80211_radiotap_tx(vap, m0); } + xferlen = sizeof(*txd) + m0->m_pkthdr.len; m_copydata(m0, 0, m0->m_pkthdr.len, (caddr_t)&txd[1]); @@ -1728,19 +2228,45 @@ rsu_transmit(struct ieee80211com *ic, struct mbuf *m) RSU_UNLOCK(sc); return (ENXIO); } + + /* + * XXX TODO: ensure that we treat 'm' as a list of frames + * to transmit! + */ error = mbufq_enqueue(&sc->sc_snd, m); if (error) { + RSU_DPRINTF(sc, RSU_DEBUG_TX, + "%s: mbufq_enable: failed (%d)\n", + __func__, + error); RSU_UNLOCK(sc); return (error); } - rsu_start(sc); RSU_UNLOCK(sc); + /* This kicks the TX taskqueue */ + rsu_start(sc); + return (0); } static void -rsu_start(struct rsu_softc *sc) +rsu_drain_mbufq(struct rsu_softc *sc) +{ + struct mbuf *m; + struct ieee80211_node *ni; + + RSU_ASSERT_LOCKED(sc); + while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; + m->m_pkthdr.rcvif = NULL; + ieee80211_free_node(ni); + m_freem(m); + } +} + +static void +_rsu_start(struct rsu_softc *sc) { struct ieee80211_node *ni; struct rsu_data *bf; @@ -1751,6 +2277,8 @@ rsu_start(struct rsu_softc *sc) while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { bf = rsu_getbuf(sc); if (bf == NULL) { + RSU_DPRINTF(sc, RSU_DEBUG_TX, + "%s: failed to get buffer\n", __func__); mbufq_prepend(&sc->sc_snd, m); break; } @@ -1759,16 +2287,26 @@ rsu_start(struct rsu_softc *sc) m->m_pkthdr.rcvif = NULL; if (rsu_tx_start(sc, ni, m, bf) != 0) { + RSU_DPRINTF(sc, RSU_DEBUG_TX, + "%s: failed to transmit\n", __func__); if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); - STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); + rsu_freebuf(sc, bf); ieee80211_free_node(ni); + m_freem(m); break; } } } static void +rsu_start(struct rsu_softc *sc) +{ + + taskqueue_enqueue(taskqueue_thread, &sc->tx_task); +} + +static void rsu_parent(struct ieee80211com *ic) { struct rsu_softc *sc = ic->ic_softc; @@ -1809,7 +2347,7 @@ rsu_power_on_acut(struct rsu_softc *sc) rsu_write_1(sc, R92S_SPS1_CTRL, rsu_read_1(sc, R92S_SPS1_CTRL) | R92S_SPS1_LDEN); - usb_pause_mtx(&sc->sc_mtx, 2 * hz); + rsu_ms_delay(sc, 2000); /* Enable switch regulator block. */ rsu_write_1(sc, R92S_SPS1_CTRL, rsu_read_1(sc, R92S_SPS1_CTRL) | R92S_SPS1_SWEN); @@ -1881,7 +2419,7 @@ rsu_power_on_bcut(struct rsu_softc *sc) /* Prevent eFuse leakage. */ rsu_write_1(sc, 0x37, 0xb0); - usb_pause_mtx(&sc->sc_mtx, hz / 100); + rsu_ms_delay(sc, 10); rsu_write_1(sc, 0x37, 0x30); /* Switch the control path to hardware. */ @@ -1892,7 +2430,7 @@ rsu_power_on_bcut(struct rsu_softc *sc) } rsu_write_1(sc, R92S_SYS_FUNC_EN + 1, rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) & ~0x8c); - rsu_ms_delay(sc); + rsu_ms_delay(sc, 1); rsu_write_1(sc, R92S_SPS0_CTRL + 1, 0x53); rsu_write_1(sc, R92S_SPS0_CTRL + 0, 0x57); @@ -1925,11 +2463,11 @@ rsu_power_on_bcut(struct rsu_softc *sc) /* Enable AFE PLL macro block. */ reg = rsu_read_1(sc, R92S_AFE_PLL_CTRL); rsu_write_1(sc, R92S_AFE_PLL_CTRL, reg | 0x11); - rsu_ms_delay(sc); + rsu_ms_delay(sc, 1); rsu_write_1(sc, R92S_AFE_PLL_CTRL, reg | 0x51); - rsu_ms_delay(sc); + rsu_ms_delay(sc, 1); rsu_write_1(sc, R92S_AFE_PLL_CTRL, reg | 0x11); - rsu_ms_delay(sc); + rsu_ms_delay(sc, 1); /* Attach AFE PLL to MACTOP/BB. */ rsu_write_1(sc, R92S_SYS_ISO_CTRL, @@ -1976,14 +2514,16 @@ rsu_power_on_bcut(struct rsu_softc *sc) if ((reg & (R92S_TCR_IMEM_CHK_RPT | R92S_TCR_EMEM_CHK_RPT)) == (R92S_TCR_IMEM_CHK_RPT | R92S_TCR_EMEM_CHK_RPT)) break; - rsu_ms_delay(sc); + rsu_ms_delay(sc, 1); } if (ntries == 20) { - DPRINTF("TxDMA is not ready\n"); + RSU_DPRINTF(sc, RSU_DEBUG_RESET | RSU_DEBUG_TX, + "%s: TxDMA is not ready\n", + __func__); /* Reset TxDMA. */ reg = rsu_read_1(sc, R92S_CR); rsu_write_1(sc, R92S_CR, reg & ~R92S_CR_TXDMA_EN); - rsu_ms_delay(sc); + rsu_ms_delay(sc, 1); rsu_write_1(sc, R92S_CR, reg | R92S_CR_TXDMA_EN); } } @@ -1993,7 +2533,7 @@ rsu_power_off(struct rsu_softc *sc) { /* Turn RF off. */ rsu_write_1(sc, R92S_RF_CTRL, 0x00); - usb_pause_mtx(&sc->sc_mtx, hz / 200); + rsu_ms_delay(sc, 5); /* Turn MAC off. */ /* Switch control path. */ @@ -2016,6 +2556,9 @@ rsu_power_off(struct rsu_softc *sc) /* Disable 1.6V LDO. */ rsu_write_1(sc, R92S_SPS0_CTRL + 0, 0x56); rsu_write_1(sc, R92S_SPS0_CTRL + 1, 0x43); + + /* Firmware - tell it to switch things off */ + (void) rsu_set_fw_power_state(sc, RSU_PWR_OFF); } static int @@ -2041,7 +2584,9 @@ rsu_fw_loadsection(struct rsu_softc *sc, const uint8_t *buf, int len) txd->txdw0 |= htole32(SM(R92S_TXDW0_PKTLEN, mlen)); memcpy(&txd[1], buf, mlen); data->buflen = sizeof(*txd) + mlen; - DPRINTF("starting transfer %p\n", data); + RSU_DPRINTF(sc, RSU_DEBUG_TX | RSU_DEBUG_FW | RSU_DEBUG_RESET, + "%s: starting transfer %p\n", + __func__, data); STAILQ_INSERT_TAIL(&sc->sc_tx_pending[which], data, next); buf += mlen; len -= mlen; @@ -2055,6 +2600,7 @@ rsu_load_firmware(struct rsu_softc *sc) { const struct r92s_fw_hdr *hdr; struct r92s_fw_priv *dmem; + struct ieee80211com *ic = &sc->sc_ic; const uint8_t *imem, *emem; int imemsz, ememsz; const struct firmware *fw; @@ -2063,7 +2609,9 @@ rsu_load_firmware(struct rsu_softc *sc) int ntries, error; if (rsu_read_1(sc, R92S_TCR) & R92S_TCR_FWRDY) { - DPRINTF("Firmware already loaded\n"); + RSU_DPRINTF(sc, RSU_DEBUG_ANY, + "%s: Firmware already loaded\n", + __func__); return (0); } @@ -2122,7 +2670,7 @@ rsu_load_firmware(struct rsu_softc *sc) } /* Wait for load to complete. */ for (ntries = 0; ntries != 50; ntries++) { - usb_pause_mtx(&sc->sc_mtx, hz / 100); + rsu_ms_delay(sc, 10); reg = rsu_read_1(sc, R92S_TCR); if (reg & R92S_TCR_IMEM_CODE_DONE) break; @@ -2141,7 +2689,7 @@ rsu_load_firmware(struct rsu_softc *sc) } /* Wait for load to complete. */ for (ntries = 0; ntries != 50; ntries++) { - usb_pause_mtx(&sc->sc_mtx, hz / 100); + rsu_ms_delay(sc, 10); reg = rsu_read_2(sc, R92S_TCR); if (reg & R92S_TCR_EMEM_CODE_DONE) break; @@ -2171,7 +2719,7 @@ rsu_load_firmware(struct rsu_softc *sc) for (ntries = 0; ntries < 100; ntries++) { if (rsu_read_1(sc, R92S_TCR) & R92S_TCR_IMEM_RDY) break; - rsu_ms_delay(sc); + rsu_ms_delay(sc, 1); } if (ntries == 100) { device_printf(sc->sc_dev, @@ -2184,14 +2732,19 @@ rsu_load_firmware(struct rsu_softc *sc) dmem = __DECONST(struct r92s_fw_priv *, &hdr->priv); memset(dmem, 0, sizeof(*dmem)); dmem->hci_sel = R92S_HCI_SEL_USB | R92S_HCI_SEL_8172; - dmem->nendpoints = 0; - dmem->rf_config = 0x12; /* 1T2R */ + dmem->nendpoints = sc->sc_nendpoints; + dmem->chip_version = sc->cut; + dmem->rf_config = sc->sc_rftype; dmem->vcs_type = R92S_VCS_TYPE_AUTO; dmem->vcs_mode = R92S_VCS_MODE_RTS_CTS; -#ifdef notyet - dmem->bw40_en = (ic->ic_htcaps & IEEE80211_HTCAP_CBW20_40) != 0; -#endif - dmem->turbo_mode = 1; + dmem->turbo_mode = 0; + dmem->bw40_en = !! (ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40); + dmem->amsdu2ampdu_en = !! (sc->sc_ht); + dmem->ampdu_en = !! (sc->sc_ht); + dmem->agg_offload = !! (sc->sc_ht); + dmem->qos_en = 1; + dmem->ps_offload = 1; + dmem->lowpower_mode = 1; /* XXX TODO: configurable? */ /* Load DMEM section. */ error = rsu_fw_loadsection(sc, (uint8_t *)dmem, sizeof(*dmem)); if (error != 0) { @@ -2203,7 +2756,7 @@ rsu_load_firmware(struct rsu_softc *sc) for (ntries = 0; ntries < 100; ntries++) { if (rsu_read_1(sc, R92S_TCR) & R92S_TCR_DMEM_CODE_DONE) break; - rsu_ms_delay(sc); + rsu_ms_delay(sc, 1); } if (ntries == 100) { device_printf(sc->sc_dev, "timeout waiting for %s transfer\n", @@ -2215,7 +2768,7 @@ rsu_load_firmware(struct rsu_softc *sc) for (ntries = 0; ntries < 60; ntries++) { if (!(rsu_read_1(sc, R92S_TCR) & R92S_TCR_FWRDY)) break; - rsu_ms_delay(sc); + rsu_ms_delay(sc, 1); } if (ntries == 60) { device_printf(sc->sc_dev, @@ -2253,7 +2806,8 @@ rsu_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, } if (rsu_tx_start(sc, ni, m, bf) != 0) { ieee80211_free_node(ni); - STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); + m_freem(m); + rsu_freebuf(sc, bf); RSU_UNLOCK(sc); return (EIO); } @@ -2268,15 +2822,20 @@ rsu_init(struct rsu_softc *sc) struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); uint8_t macaddr[IEEE80211_ADDR_LEN]; - struct r92s_set_pwr_mode cmd; int error; int i; RSU_ASSERT_LOCKED(sc); + /* Ensure the mbuf queue is drained */ + rsu_drain_mbufq(sc); + /* Init host async commands ring. */ sc->cmdq.cur = sc->cmdq.next = sc->cmdq.queued = 0; + /* Reset power management state. */ + rsu_write_1(sc, R92S_USB_HRPWM, 0); + /* Power on adapter. */ if (sc->cut == 1) rsu_power_on_acut(sc); @@ -2317,9 +2876,11 @@ rsu_init(struct rsu_softc *sc) rsu_write_region_1(sc, R92S_MACID, macaddr, IEEE80211_ADDR_LEN); /* It really takes 1.5 seconds for the firmware to boot: */ - usb_pause_mtx(&sc->sc_mtx, (3 * hz) / 2); + rsu_ms_delay(sc, 2000); - DPRINTF("setting MAC address to %s\n", ether_sprintf(macaddr)); + RSU_DPRINTF(sc, RSU_DEBUG_RESET, "%s: setting MAC address to %s\n", + __func__, + ether_sprintf(macaddr)); error = rsu_fw_cmd(sc, R92S_CMD_SET_MAC_ADDRESS, macaddr, IEEE80211_ADDR_LEN); if (error != 0) { @@ -2327,40 +2888,20 @@ rsu_init(struct rsu_softc *sc) goto fail; } - rsu_write_1(sc, R92S_USB_HRPWM, - R92S_USB_HRPWM_PS_ST_ACTIVE | R92S_USB_HRPWM_PS_ALL_ON); + /* Set PS mode fully active */ + error = rsu_set_fw_power_state(sc, RSU_PWR_ACTIVE); - memset(&cmd, 0, sizeof(cmd)); - cmd.mode = R92S_PS_MODE_ACTIVE; - DPRINTF("setting ps mode to %d\n", cmd.mode); - error = rsu_fw_cmd(sc, R92S_CMD_SET_PWR_MODE, &cmd, sizeof(cmd)); if (error != 0) { device_printf(sc->sc_dev, "could not set PS mode\n"); goto fail; } -#if 0 - if (ic->ic_htcaps & IEEE80211_HTCAP_CBW20_40) { - /* Enable 40MHz mode. */ - error = rsu_fw_iocmd(sc, - SM(R92S_IOCMD_CLASS, 0xf4) | - SM(R92S_IOCMD_INDEX, 0x00) | - SM(R92S_IOCMD_VALUE, 0x0007)); - if (error != 0) { - device_printf(sc->sc_dev, - "could not enable 40MHz mode\n"); - goto fail; - } - } - - /* Set default channel. */ - ic->ic_bss->ni_chan = ic->ic_ibss_chan; -#endif sc->sc_scan_pass = 0; usbd_transfer_start(sc->sc_xfer[RSU_BULK_RX]); /* We're ready to go. */ sc->sc_running = 1; + sc->sc_scanning = 0; return; fail: /* Need to stop all failed transfers, if any */ @@ -2373,19 +2914,31 @@ rsu_stop(struct rsu_softc *sc) { int i; + RSU_ASSERT_LOCKED(sc); + sc->sc_running = 0; sc->sc_calibrating = 0; taskqueue_cancel_timeout(taskqueue_thread, &sc->calib_task, NULL); + taskqueue_cancel(taskqueue_thread, &sc->tx_task, NULL); /* Power off adapter. */ rsu_power_off(sc); for (i = 0; i < RSU_N_TRANSFER; i++) usbd_transfer_stop(sc->sc_xfer[i]); + + /* Ensure the mbuf queue is drained */ + rsu_drain_mbufq(sc); } +/* + * Note: usb_pause_mtx() actually releases the mutex before calling pause(), + * which breaks any kind of driver serialisation. + */ static void -rsu_ms_delay(struct rsu_softc *sc) +rsu_ms_delay(struct rsu_softc *sc, int ms) { - usb_pause_mtx(&sc->sc_mtx, hz / 1000); + + //usb_pause_mtx(&sc->sc_mtx, hz / 1000); + DELAY(ms * 1000); } diff --git a/sys/dev/usb/wlan/if_rsureg.h b/sys/dev/usb/wlan/if_rsureg.h index 4e6cd884fab88..ddb29a36770ef 100644 --- a/sys/dev/usb/wlan/if_rsureg.h +++ b/sys/dev/usb/wlan/if_rsureg.h @@ -158,6 +158,20 @@ (((var) & ~field##_M) | SM(field, val)) /* + * ROM field with RF config. + */ +enum { + RTL8712_RFCONFIG_1T = 0x10, + RTL8712_RFCONFIG_2T = 0x20, + RTL8712_RFCONFIG_1R = 0x01, + RTL8712_RFCONFIG_2R = 0x02, + RTL8712_RFCONFIG_1T1R = 0x11, + RTL8712_RFCONFIG_1T2R = 0x12, + RTL8712_RFCONFIG_TURBO = 0x92, + RTL8712_RFCONFIG_2T2R = 0x22 +}; + +/* * Firmware image header. */ struct r92s_fw_priv { @@ -173,6 +187,7 @@ struct r92s_fw_priv { uint8_t chip_version; uint16_t custid; uint8_t rf_config; +//0x11: 1T1R, 0x12: 1T2R, 0x92: 1T2R turbo, 0x22: 2T2R uint8_t nendpoints; /* QWORD1 */ uint32_t regulatory; @@ -593,11 +608,20 @@ struct r92s_tx_desc { uint16_t reserved1; } __packed __aligned(4); +struct r92s_add_ba_event { + uint8_t mac_addr[IEEE80211_ADDR_LEN]; + uint16_t ssn; + uint8_t tid; +}; + +struct r92s_add_ba_req { + uint32_t tid; +}; /* * Driver definitions. */ -#define RSU_RX_LIST_COUNT 1 +#define RSU_RX_LIST_COUNT 100 #define RSU_TX_LIST_COUNT 32 #define RSU_HOST_CMD_RING_COUNT 32 @@ -700,6 +724,7 @@ enum { RSU_BULK_RX, RSU_BULK_TX_BE_BK, /* = WME_AC_BE/BK */ RSU_BULK_TX_VI_VO, /* = WME_AC_VI/VO */ + RSU_BULK_TX_H2C, /* H2C */ RSU_N_TRANSFER, }; @@ -714,7 +739,6 @@ struct rsu_data { struct rsu_vap { struct ieee80211vap vap; - struct ieee80211_beacon_offsets bo; int (*newstate)(struct ieee80211vap *, enum ieee80211_state, int); @@ -734,13 +758,22 @@ struct rsu_softc { enum ieee80211_state, int); struct usbd_interface *sc_iface; struct timeout_task calib_task; + struct task tx_task; const uint8_t *qid2idx; struct mtx sc_mtx; + int sc_ht; + int sc_nendpoints; + int sc_curpwrstate; + int sc_currssi; u_int sc_running:1, sc_calibrating:1, + sc_scanning:1, sc_scan_pass:1; u_int cut; + uint8_t sc_rftype; + int8_t sc_nrxstream; + int8_t sc_ntxstream; struct rsu_host_cmd_ring cmdq; struct rsu_data sc_rx[RSU_RX_LIST_COUNT]; struct rsu_data sc_tx[RSU_TX_LIST_COUNT]; diff --git a/sys/dev/usb/wlan/if_run.c b/sys/dev/usb/wlan/if_run.c index b787c03429345..c8707c4b6427a 100644 --- a/sys/dev/usb/wlan/if_run.c +++ b/sys/dev/usb/wlan/if_run.c @@ -1730,7 +1730,7 @@ run_read_eeprom(struct run_softc *sc) /* read ROM version */ run_srom_read(sc, RT2860_EEPROM_VERSION, &val); - DPRINTF("EEPROM rev=%d, FAE=%d\n", val & 0xff, val >> 8); + DPRINTF("EEPROM rev=%d, FAE=%d\n", val >> 8, val & 0xff); /* read MAC address */ run_srom_read(sc, RT2860_EEPROM_MAC01, &val); @@ -4811,13 +4811,13 @@ static void run_update_beacon(struct ieee80211vap *vap, int item) { struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; + struct ieee80211_node *ni = vap->iv_bss; struct run_softc *sc = ic->ic_softc; struct run_vap *rvp = RUN_VAP(vap); int mcast = 0; uint32_t i; - KASSERT(vap != NULL, ("no beacon")); - switch (item) { case IEEE80211_BEACON_ERP: run_updateslot(ic); @@ -4832,14 +4832,13 @@ run_update_beacon(struct ieee80211vap *vap, int item) break; } - setbit(rvp->bo.bo_flags, item); + setbit(bo->bo_flags, item); if (rvp->beacon_mbuf == NULL) { - rvp->beacon_mbuf = ieee80211_beacon_alloc(vap->iv_bss, - &rvp->bo); + rvp->beacon_mbuf = ieee80211_beacon_alloc(ni, bo); if (rvp->beacon_mbuf == NULL) return; } - ieee80211_beacon_update(vap->iv_bss, &rvp->bo, rvp->beacon_mbuf, mcast); + ieee80211_beacon_update(ni, bo, rvp->beacon_mbuf, mcast); i = RUN_CMDQ_GET(&sc->cmdq_store); DPRINTF("cmdq_store=%d\n", i); @@ -4854,6 +4853,7 @@ static void run_update_beacon_cb(void *arg) { struct ieee80211vap *vap = arg; + struct ieee80211_node *ni = vap->iv_bss; struct run_vap *rvp = RUN_VAP(vap); struct ieee80211com *ic = vap->iv_ic; struct run_softc *sc = ic->ic_softc; @@ -4862,7 +4862,7 @@ run_update_beacon_cb(void *arg) uint16_t txwisize; uint8_t ridx; - if (vap->iv_bss->ni_chan == IEEE80211_CHAN_ANYC) + if (ni->ni_chan == IEEE80211_CHAN_ANYC) return; if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) return; @@ -4872,8 +4872,8 @@ run_update_beacon_cb(void *arg) * is taking care of apropriate calls. */ if (rvp->beacon_mbuf == NULL) { - rvp->beacon_mbuf = ieee80211_beacon_alloc(vap->iv_bss, - &rvp->bo); + rvp->beacon_mbuf = ieee80211_beacon_alloc(ni, + &vap->iv_bcn_off); if (rvp->beacon_mbuf == NULL) return; } diff --git a/sys/dev/usb/wlan/if_runvar.h b/sys/dev/usb/wlan/if_runvar.h index 71e29ba1e65c3..bbefbb0bde396 100644 --- a/sys/dev/usb/wlan/if_runvar.h +++ b/sys/dev/usb/wlan/if_runvar.h @@ -119,7 +119,6 @@ struct run_cmdq { struct run_vap { struct ieee80211vap vap; - struct ieee80211_beacon_offsets bo; struct mbuf *beacon_mbuf; int (*newstate)(struct ieee80211vap *, diff --git a/sys/dev/usb/wlan/if_uath.c b/sys/dev/usb/wlan/if_uath.c index 04e092040c145..39fa71b286388 100644 --- a/sys/dev/usb/wlan/if_uath.c +++ b/sys/dev/usb/wlan/if_uath.c @@ -102,6 +102,7 @@ __FBSDID("$FreeBSD$"); #endif #include <net80211/ieee80211_var.h> +#include <net80211/ieee80211_input.h> #include <net80211/ieee80211_regdomain.h> #include <net80211/ieee80211_radiotap.h> @@ -156,15 +157,6 @@ enum { } while (0) #endif -/* unaligned little endian access */ -#define LE_READ_2(p) \ - ((u_int16_t) \ - ((((u_int8_t *)(p))[0] ) | (((u_int8_t *)(p))[1] << 8))) -#define LE_READ_4(p) \ - ((u_int32_t) \ - ((((u_int8_t *)(p))[0] ) | (((u_int8_t *)(p))[1] << 8) | \ - (((u_int8_t *)(p))[2] << 16) | (((u_int8_t *)(p))[3] << 24))) - /* recognized device vendors/products */ static const STRUCT_USB_HOST_ID uath_devs[] = { #define UATH_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } @@ -599,7 +591,6 @@ uath_dump_cmd(const uint8_t *buf, int len, char prefix) static const char * uath_codename(int code) { -#define N(a) (sizeof(a)/sizeof(a[0])) static const char *names[] = { "0x00", "HOST_AVAILABLE", @@ -662,13 +653,12 @@ uath_codename(int code) }; static char buf[8]; - if (code < N(names)) + if (code < nitems(names)) return names[code]; if (code == WDCMSG_SET_DEFAULT_KEY) return "SET_DEFAULT_KEY"; snprintf(buf, sizeof(buf), "0x%02x", code); return buf; -#undef N } #endif @@ -1486,7 +1476,7 @@ uath_wme_init(struct uath_softc *sc) qinfo.attr.aifs = htobe32(uath_wme_11g[ac].aifsn); qinfo.attr.logcwmin = htobe32(uath_wme_11g[ac].logcwmin); qinfo.attr.logcwmax = htobe32(uath_wme_11g[ac].logcwmax); - qinfo.attr.bursttime = htobe32(UATH_TXOP_TO_US( + qinfo.attr.bursttime = htobe32(IEEE80211_TXOP_TO_US( uath_wme_11g[ac].txop)); qinfo.attr.mode = htobe32(uath_wme_11g[ac].acm);/*XXX? */ qinfo.attr.qflags = htobe32(1); /* XXX? */ diff --git a/sys/dev/usb/wlan/if_uathvar.h b/sys/dev/usb/wlan/if_uathvar.h index 56b5ba35a2b66..4b4d9fc36dc4f 100644 --- a/sys/dev/usb/wlan/if_uathvar.h +++ b/sys/dev/usb/wlan/if_uathvar.h @@ -102,7 +102,6 @@ struct uath_wme_settings { uint8_t logcwmin; uint8_t logcwmax; uint16_t txop; -#define UATH_TXOP_TO_US(txop) ((txop) << 5) uint8_t acm; }; diff --git a/sys/dev/usb/wlan/if_ural.c b/sys/dev/usb/wlan/if_ural.c index e8224ba3f1498..bff4de54d6671 100644 --- a/sys/dev/usb/wlan/if_ural.c +++ b/sys/dev/usb/wlan/if_ural.c @@ -566,10 +566,7 @@ ural_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ return NULL; - uvp = (struct ural_vap *) malloc(sizeof(struct ural_vap), - M_80211_VAP, M_NOWAIT | M_ZERO); - if (uvp == NULL) - return NULL; + uvp = malloc(sizeof(struct ural_vap), M_80211_VAP, M_WAITOK | M_ZERO); vap = &uvp->vap; /* enable s/w bmiss handling for sta mode */ @@ -716,7 +713,7 @@ ural_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) if (vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_IBSS) { - m = ieee80211_beacon_alloc(ni, &uvp->bo); + m = ieee80211_beacon_alloc(ni, &vap->iv_bcn_off); if (m == NULL) { device_printf(sc->sc_dev, "could not allocate beacon\n"); @@ -1932,7 +1929,6 @@ ural_read_eeprom(struct ural_softc *sc) static int ural_bbp_init(struct ural_softc *sc) { -#define N(a) ((int)(sizeof (a) / sizeof ((a)[0]))) int i, ntries; /* wait for BBP to be ready */ @@ -1948,7 +1944,7 @@ ural_bbp_init(struct ural_softc *sc) } /* initialize BBP registers to default values */ - for (i = 0; i < N(ural_def_bbp); i++) + for (i = 0; i < nitems(ural_def_bbp); i++) ural_bbp_write(sc, ural_def_bbp[i].reg, ural_def_bbp[i].val); #if 0 @@ -1961,7 +1957,6 @@ ural_bbp_init(struct ural_softc *sc) #endif return 0; -#undef N } static void @@ -2016,7 +2011,6 @@ ural_set_rxantenna(struct ural_softc *sc, int antenna) static void ural_init(struct ural_softc *sc) { -#define N(a) ((int)(sizeof (a) / sizeof ((a)[0]))) struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); uint16_t tmp; @@ -2030,7 +2024,7 @@ ural_init(struct ural_softc *sc) ural_stop(sc); /* initialize MAC registers to default values */ - for (i = 0; i < N(ural_def_mac); i++) + for (i = 0; i < nitems(ural_def_mac); i++) ural_write(sc, ural_def_mac[i].reg, ural_def_mac[i].val); /* wait for BBP and RF to wake up (this can take a long time!) */ @@ -2089,7 +2083,6 @@ ural_init(struct ural_softc *sc) return; fail: ural_stop(sc); -#undef N } static void diff --git a/sys/dev/usb/wlan/if_uralvar.h b/sys/dev/usb/wlan/if_uralvar.h index f40f71d9de08f..5461e87a75c58 100644 --- a/sys/dev/usb/wlan/if_uralvar.h +++ b/sys/dev/usb/wlan/if_uralvar.h @@ -73,7 +73,7 @@ typedef STAILQ_HEAD(, ural_tx_data) ural_txdhead; struct ural_vap { struct ieee80211vap vap; - struct ieee80211_beacon_offsets bo; + struct usb_callout ratectl_ch; struct task ratectl_task; diff --git a/sys/dev/usb/wlan/if_urtw.c b/sys/dev/usb/wlan/if_urtw.c index f0d2674e56e73..040ba867df305 100644 --- a/sys/dev/usb/wlan/if_urtw.c +++ b/sys/dev/usb/wlan/if_urtw.c @@ -1093,7 +1093,6 @@ fail: static usb_error_t urtw_adapter_start_b(struct urtw_softc *sc) { -#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) uint8_t data8; usb_error_t error; @@ -1176,7 +1175,6 @@ urtw_adapter_start_b(struct urtw_softc *sc) urtw_write16_m(sc, 0x1ec, 0x800); /* RX MAX SIZE */ fail: return (error); -#undef N } static usb_error_t @@ -1914,31 +1912,27 @@ fail: static uint16_t urtw_rate2rtl(uint32_t rate) { -#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) int i; - for (i = 0; i < N(urtw_ratetable); i++) { + for (i = 0; i < nitems(urtw_ratetable); i++) { if (rate == urtw_ratetable[i].reg) return urtw_ratetable[i].val; } return (3); -#undef N } static uint16_t urtw_rtl2rate(uint32_t rate) { -#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) int i; - for (i = 0; i < N(urtw_ratetable); i++) { + for (i = 0; i < nitems(urtw_ratetable); i++) { if (rate == urtw_ratetable[i].val) return urtw_ratetable[i].reg; } return (0); -#undef N } static usb_error_t @@ -2458,7 +2452,6 @@ fail: static usb_error_t urtw_8225_rf_init(struct urtw_softc *sc) { -#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) int i; uint16_t data; usb_error_t error; @@ -2489,7 +2482,7 @@ urtw_8225_rf_init(struct urtw_softc *sc) goto fail; usb_pause_mtx(&sc->sc_mtx, 1000); - for (i = 0; i < N(urtw_8225_rf_part1); i++) { + for (i = 0; i < nitems(urtw_8225_rf_part1); i++) { urtw_8225_write(sc, urtw_8225_rf_part1[i].reg, urtw_8225_rf_part1[i].val); usb_pause_mtx(&sc->sc_mtx, 1); @@ -2521,7 +2514,7 @@ urtw_8225_rf_init(struct urtw_softc *sc) usb_pause_mtx(&sc->sc_mtx, 1); } - for (i = 0; i < N(urtw_8225_rf_part2); i++) { + for (i = 0; i < nitems(urtw_8225_rf_part2); i++) { urtw_8187_write_phy_ofdm(sc, urtw_8225_rf_part2[i].reg, urtw_8225_rf_part2[i].val); usb_pause_mtx(&sc->sc_mtx, 1); @@ -2531,7 +2524,7 @@ urtw_8225_rf_init(struct urtw_softc *sc) if (error) goto fail; - for (i = 0; i < N(urtw_8225_rf_part3); i++) { + for (i = 0; i < nitems(urtw_8225_rf_part3); i++) { urtw_8187_write_phy_cck(sc, urtw_8225_rf_part3[i].reg, urtw_8225_rf_part3[i].val); usb_pause_mtx(&sc->sc_mtx, 1); @@ -2557,7 +2550,6 @@ urtw_8225_rf_init(struct urtw_softc *sc) error = urtw_8225_rf_set_chan(sc, 1); fail: return (error); -#undef N } static usb_error_t @@ -2841,7 +2833,6 @@ fail: static usb_error_t urtw_8225v2_rf_init(struct urtw_softc *sc) { -#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) int i; uint16_t data; uint32_t data32; @@ -2874,7 +2865,7 @@ urtw_8225v2_rf_init(struct urtw_softc *sc) usb_pause_mtx(&sc->sc_mtx, 500); - for (i = 0; i < N(urtw_8225v2_rf_part1); i++) { + for (i = 0; i < nitems(urtw_8225v2_rf_part1); i++) { urtw_8225_write(sc, urtw_8225v2_rf_part1[i].reg, urtw_8225v2_rf_part1[i].val); } @@ -2929,7 +2920,7 @@ urtw_8225v2_rf_init(struct urtw_softc *sc) urtw_8187_write_phy_ofdm(sc, 0xa, (uint8_t)i + 0x80); } - for (i = 0; i < N(urtw_8225v2_rf_part2); i++) { + for (i = 0; i < nitems(urtw_8225v2_rf_part2); i++) { urtw_8187_write_phy_ofdm(sc, urtw_8225v2_rf_part2[i].reg, urtw_8225v2_rf_part2[i].val); } @@ -2938,7 +2929,7 @@ urtw_8225v2_rf_init(struct urtw_softc *sc) if (error) goto fail; - for (i = 0; i < N(urtw_8225v2_rf_part3); i++) { + for (i = 0; i < nitems(urtw_8225v2_rf_part3); i++) { urtw_8187_write_phy_cck(sc, urtw_8225v2_rf_part3[i].reg, urtw_8225v2_rf_part3[i].val); } @@ -2961,7 +2952,6 @@ urtw_8225v2_rf_init(struct urtw_softc *sc) error = urtw_8225_rf_set_chan(sc, 1); fail: return (error); -#undef N } static usb_error_t @@ -3329,7 +3319,6 @@ urtw_8225v2b_rf_init(struct urtw_softc *sc) fail: return (error); -#undef N } static usb_error_t diff --git a/sys/dev/usb/wlan/if_urtwn.c b/sys/dev/usb/wlan/if_urtwn.c index 457a88526516b..b1e3804ea889c 100644 --- a/sys/dev/usb/wlan/if_urtwn.c +++ b/sys/dev/usb/wlan/if_urtwn.c @@ -24,6 +24,8 @@ __FBSDID("$FreeBSD$"); * Driver for Realtek RTL8188CE-VAU/RTL8188CUS/RTL8188EU/RTL8188RU/RTL8192CU. */ +#include "opt_wlan.h" + #include <sys/param.h> #include <sys/sockio.h> #include <sys/sysctl.h> @@ -61,6 +63,7 @@ __FBSDID("$FreeBSD$"); #include <netinet/ip.h> #include <net80211/ieee80211_var.h> +#include <net80211/ieee80211_input.h> #include <net80211/ieee80211_regdomain.h> #include <net80211/ieee80211_radiotap.h> #include <net80211/ieee80211_ratectl.h> @@ -83,8 +86,7 @@ SYSCTL_INT(_hw_usb_urtwn, OID_AUTO, debug, CTLFLAG_RWTUN, &urtwn_debug, 0, #endif #define URTWN_RSSI(r) (r) - 110 -#define IEEE80211_HAS_ADDR4(wh) \ - (((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) +#define IEEE80211_HAS_ADDR4(wh) IEEE80211_IS_DSTODS(wh) /* various supported device vendors/products */ static const STRUCT_USB_HOST_ID urtwn_devs[] = { @@ -169,6 +171,7 @@ static device_detach_t urtwn_detach; static usb_callback_t urtwn_bulk_tx_callback; static usb_callback_t urtwn_bulk_rx_callback; +static void urtwn_drain_mbufq(struct urtwn_softc *sc); static usb_error_t urtwn_do_request(struct urtwn_softc *, struct usb_device_request *, void *); static struct ieee80211vap *urtwn_vap_create(struct ieee80211com *, @@ -467,6 +470,20 @@ detach: return (ENXIO); /* failure */ } +static void +urtwn_drain_mbufq(struct urtwn_softc *sc) +{ + struct mbuf *m; + struct ieee80211_node *ni; + URTWN_ASSERT_LOCKED(sc); + while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; + m->m_pkthdr.rcvif = NULL; + ieee80211_free_node(ni); + m_freem(m); + } +} + static int urtwn_detach(device_t self) { @@ -482,6 +499,9 @@ urtwn_detach(device_t self) callout_drain(&sc->sc_watchdog_ch); + /* stop all USB transfers */ + usbd_transfer_unsetup(sc->sc_xfer, URTWN_N_TRANSFER); + /* Prevent further allocations from RX/TX data lists. */ URTWN_LOCK(sc); STAILQ_INIT(&sc->sc_tx_active); @@ -502,10 +522,7 @@ urtwn_detach(device_t self) urtwn_free_rx_list(sc); URTWN_UNLOCK(sc); - /* stop all USB transfers */ - usbd_transfer_unsetup(sc->sc_xfer, URTWN_N_TRANSFER); ieee80211_ifdetach(ic); - mbufq_drain(&sc->sc_snd); mtx_destroy(&sc->sc_mtx); return (0); @@ -879,13 +896,12 @@ tr_setup: data = STAILQ_FIRST(&sc->sc_tx_pending); if (data == NULL) { DPRINTF("%s: empty pending queue\n", __func__); - return; + goto finish; } STAILQ_REMOVE_HEAD(&sc->sc_tx_pending, next); STAILQ_INSERT_TAIL(&sc->sc_tx_active, data, next); usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); usbd_transfer_submit(xfer); - urtwn_start(sc); break; default: data = STAILQ_FIRST(&sc->sc_tx_active); @@ -903,6 +919,9 @@ tr_setup: } break; } +finish: + /* Kick-start more transmit */ + urtwn_start(sc); } static struct urtwn_data * @@ -1778,7 +1797,6 @@ urtwn_tx_start(struct urtwn_softc *sc, struct ieee80211_node *ni, device_printf(sc->sc_dev, "ieee80211_crypto_encap returns NULL.\n"); /* XXX we don't expect the fragmented frames */ - m_freem(m0); return (ENOBUFS); } @@ -1931,6 +1949,7 @@ urtwn_start(struct urtwn_softc *sc) if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); + m_freem(m); ieee80211_free_node(ni); break; } @@ -3417,6 +3436,8 @@ urtwn_stop(struct urtwn_softc *sc) sc->sc_flags &= ~URTWN_RUNNING; callout_stop(&sc->sc_watchdog_ch); urtwn_abort_xfers(sc); + + urtwn_drain_mbufq(sc); } static void @@ -3455,14 +3476,15 @@ urtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, } if (urtwn_tx_start(sc, ni, m, bf) != 0) { + m_freem(m); ieee80211_free_node(ni); STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); URTWN_UNLOCK(sc); return (EIO); } + sc->sc_txtimer = 5; URTWN_UNLOCK(sc); - sc->sc_txtimer = 5; return (0); } diff --git a/sys/dev/usb/wlan/if_urtwnreg.h b/sys/dev/usb/wlan/if_urtwnreg.h index 3c212794a763c..ece356da86aaf 100644 --- a/sys/dev/usb/wlan/if_urtwnreg.h +++ b/sys/dev/usb/wlan/if_urtwnreg.h @@ -801,10 +801,6 @@ #define R92C_RAID_11B 6 -/* Macros to access unaligned little-endian memory. */ -#define LE_READ_2(x) ((x)[0] | (x)[1] << 8) -#define LE_READ_4(x) ((x)[0] | (x)[1] << 8 | (x)[2] << 16 | (x)[3] << 24) - /* * Macros to access subfields in registers. */ @@ -1138,7 +1134,6 @@ struct urtwn_fw_info { struct urtwn_vap { struct ieee80211vap vap; - struct ieee80211_beacon_offsets bo; int (*newstate)(struct ieee80211vap *, enum ieee80211_state, int); diff --git a/sys/dev/usb/wlan/if_zyd.c b/sys/dev/usb/wlan/if_zyd.c index a86ab8a3f0619..5a59d37946922 100644 --- a/sys/dev/usb/wlan/if_zyd.c +++ b/sys/dev/usb/wlan/if_zyd.c @@ -930,25 +930,23 @@ fail: static int zyd_rfmd_init(struct zyd_rf *rf) { -#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phyini[] = ZYD_RFMD_PHY; static const uint32_t rfini[] = ZYD_RFMD_RF; int i, error; /* init RF-dependent PHY registers */ - for (i = 0; i < N(phyini); i++) { + for (i = 0; i < nitems(phyini); i++) { zyd_write16_m(sc, phyini[i].reg, phyini[i].val); } /* init RFMD radio */ - for (i = 0; i < N(rfini); i++) { + for (i = 0; i < nitems(rfini); i++) { if ((error = zyd_rfwrite(sc, rfini[i])) != 0) return (error); } fail: return (error); -#undef N } static int @@ -989,7 +987,6 @@ fail: static int zyd_al2230_init(struct zyd_rf *rf) { -#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phyini[] = ZYD_AL2230_PHY; static const struct zyd_phy_pair phy2230s[] = ZYD_AL2230S_PHY_INIT; @@ -1003,16 +1000,16 @@ zyd_al2230_init(struct zyd_rf *rf) int i, error; /* init RF-dependent PHY registers */ - for (i = 0; i < N(phyini); i++) + for (i = 0; i < nitems(phyini); i++) zyd_write16_m(sc, phyini[i].reg, phyini[i].val); if (sc->sc_rfrev == ZYD_RF_AL2230S || sc->sc_al2230s != 0) { - for (i = 0; i < N(phy2230s); i++) + for (i = 0; i < nitems(phy2230s); i++) zyd_write16_m(sc, phy2230s[i].reg, phy2230s[i].val); } /* init AL2230 radio */ - for (i = 0; i < N(rfini1); i++) { + for (i = 0; i < nitems(rfini1); i++) { error = zyd_rfwrite(sc, rfini1[i]); if (error != 0) goto fail; @@ -1025,34 +1022,32 @@ zyd_al2230_init(struct zyd_rf *rf) if (error != 0) goto fail; - for (i = 0; i < N(rfini2); i++) { + for (i = 0; i < nitems(rfini2); i++) { error = zyd_rfwrite(sc, rfini2[i]); if (error != 0) goto fail; } - for (i = 0; i < N(phypll); i++) + for (i = 0; i < nitems(phypll); i++) zyd_write16_m(sc, phypll[i].reg, phypll[i].val); - for (i = 0; i < N(rfini3); i++) { + for (i = 0; i < nitems(rfini3); i++) { error = zyd_rfwrite(sc, rfini3[i]); if (error != 0) goto fail; } fail: return (error); -#undef N } static int zyd_al2230_fini(struct zyd_rf *rf) { -#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) int error, i; struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phy[] = ZYD_AL2230_PHY_FINI_PART1; - for (i = 0; i < N(phy); i++) + for (i = 0; i < nitems(phy); i++) zyd_write16_m(sc, phy[i].reg, phy[i].val); if (sc->sc_newphy != 0) @@ -1061,13 +1056,11 @@ zyd_al2230_fini(struct zyd_rf *rf) zyd_write16_m(sc, ZYD_CR203, 0x6); fail: return (error); -#undef N } static int zyd_al2230_init_b(struct zyd_rf *rf) { -#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phy1[] = ZYD_AL2230_PHY_PART1; static const struct zyd_phy_pair phy2[] = ZYD_AL2230_PHY_PART2; @@ -1080,15 +1073,15 @@ zyd_al2230_init_b(struct zyd_rf *rf) static const uint32_t zyd_al2230_chtable[][3] = ZYD_AL2230_CHANTABLE; int i, error; - for (i = 0; i < N(phy1); i++) + for (i = 0; i < nitems(phy1); i++) zyd_write16_m(sc, phy1[i].reg, phy1[i].val); /* init RF-dependent PHY registers */ - for (i = 0; i < N(phyini); i++) + for (i = 0; i < nitems(phyini); i++) zyd_write16_m(sc, phyini[i].reg, phyini[i].val); if (sc->sc_rfrev == ZYD_RF_AL2230S || sc->sc_al2230s != 0) { - for (i = 0; i < N(phy2230s); i++) + for (i = 0; i < nitems(phy2230s); i++) zyd_write16_m(sc, phy2230s[i].reg, phy2230s[i].val); } @@ -1098,7 +1091,7 @@ zyd_al2230_init_b(struct zyd_rf *rf) return (error); } - for (i = 0; i < N(rfini_part1); i++) { + for (i = 0; i < nitems(rfini_part1); i++) { error = zyd_rfwrite_cr(sc, rfini_part1[i]); if (error != 0) return (error); @@ -1111,28 +1104,27 @@ zyd_al2230_init_b(struct zyd_rf *rf) if (error != 0) goto fail; - for (i = 0; i < N(rfini_part2); i++) { + for (i = 0; i < nitems(rfini_part2); i++) { error = zyd_rfwrite_cr(sc, rfini_part2[i]); if (error != 0) return (error); } - for (i = 0; i < N(phy2); i++) + for (i = 0; i < nitems(phy2); i++) zyd_write16_m(sc, phy2[i].reg, phy2[i].val); - for (i = 0; i < N(rfini_part3); i++) { + for (i = 0; i < nitems(rfini_part3); i++) { error = zyd_rfwrite_cr(sc, rfini_part3[i]); if (error != 0) return (error); } - for (i = 0; i < N(phy3); i++) + for (i = 0; i < nitems(phy3); i++) zyd_write16_m(sc, phy3[i].reg, phy3[i].val); error = zyd_al2230_fini(rf); fail: return (error); -#undef N } static int @@ -1150,7 +1142,6 @@ fail: static int zyd_al2230_set_channel(struct zyd_rf *rf, uint8_t chan) { -#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) int error, i; struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phy1[] = { @@ -1170,17 +1161,15 @@ zyd_al2230_set_channel(struct zyd_rf *rf, uint8_t chan) if (error != 0) goto fail; - for (i = 0; i < N(phy1); i++) + for (i = 0; i < nitems(phy1); i++) zyd_write16_m(sc, phy1[i].reg, phy1[i].val); fail: return (error); -#undef N } static int zyd_al2230_set_channel_b(struct zyd_rf *rf, uint8_t chan) { -#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) int error, i; struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phy1[] = ZYD_AL2230_PHY_PART1; @@ -1188,7 +1177,7 @@ zyd_al2230_set_channel_b(struct zyd_rf *rf, uint8_t chan) uint32_t r1, r2, r3; } rfprog[] = ZYD_AL2230_CHANTABLE_B; - for (i = 0; i < N(phy1); i++) + for (i = 0; i < nitems(phy1); i++) zyd_write16_m(sc, phy1[i].reg, phy1[i].val); error = zyd_rfwrite_cr(sc, rfprog[chan - 1].r1); @@ -1203,7 +1192,6 @@ zyd_al2230_set_channel_b(struct zyd_rf *rf, uint8_t chan) error = zyd_al2230_fini(rf); fail: return (error); -#undef N } #define ZYD_AL2230_PHY_BANDEDGE6 \ @@ -1215,7 +1203,6 @@ fail: static int zyd_al2230_bandedge6(struct zyd_rf *rf, struct ieee80211_channel *c) { -#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) int error = 0, i; struct zyd_softc *sc = rf->rf_sc; struct ieee80211com *ic = &sc->sc_ic; @@ -1225,11 +1212,10 @@ zyd_al2230_bandedge6(struct zyd_rf *rf, struct ieee80211_channel *c) if (chan == 1 || chan == 11) r[0].val = 0x12; - for (i = 0; i < N(r); i++) + for (i = 0; i < nitems(r); i++) zyd_write16_m(sc, r[i].reg, r[i].val); fail: return (error); -#undef N } /* @@ -1238,7 +1224,6 @@ fail: static int zyd_al7230B_init(struct zyd_rf *rf) { -#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phyini_1[] = ZYD_AL7230B_PHY_1; static const struct zyd_phy_pair phyini_2[] = ZYD_AL7230B_PHY_2; @@ -1250,29 +1235,28 @@ zyd_al7230B_init(struct zyd_rf *rf) /* for AL7230B, PHY and RF need to be initialized in "phases" */ /* init RF-dependent PHY registers, part one */ - for (i = 0; i < N(phyini_1); i++) + for (i = 0; i < nitems(phyini_1); i++) zyd_write16_m(sc, phyini_1[i].reg, phyini_1[i].val); /* init AL7230B radio, part one */ - for (i = 0; i < N(rfini_1); i++) { + for (i = 0; i < nitems(rfini_1); i++) { if ((error = zyd_rfwrite(sc, rfini_1[i])) != 0) return (error); } /* init RF-dependent PHY registers, part two */ - for (i = 0; i < N(phyini_2); i++) + for (i = 0; i < nitems(phyini_2); i++) zyd_write16_m(sc, phyini_2[i].reg, phyini_2[i].val); /* init AL7230B radio, part two */ - for (i = 0; i < N(rfini_2); i++) { + for (i = 0; i < nitems(rfini_2); i++) { if ((error = zyd_rfwrite(sc, rfini_2[i])) != 0) return (error); } /* init RF-dependent PHY registers, part three */ - for (i = 0; i < N(phyini_3); i++) + for (i = 0; i < nitems(phyini_3); i++) zyd_write16_m(sc, phyini_3[i].reg, phyini_3[i].val); fail: return (error); -#undef N } static int @@ -1290,7 +1274,6 @@ fail: static int zyd_al7230B_set_channel(struct zyd_rf *rf, uint8_t chan) { -#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) struct zyd_softc *sc = rf->rf_sc; static const struct { uint32_t r1, r2; @@ -1301,7 +1284,7 @@ zyd_al7230B_set_channel(struct zyd_rf *rf, uint8_t chan) zyd_write16_m(sc, ZYD_CR240, 0x57); zyd_write16_m(sc, ZYD_CR251, 0x2f); - for (i = 0; i < N(rfsc); i++) { + for (i = 0; i < nitems(rfsc); i++) { if ((error = zyd_rfwrite(sc, rfsc[i])) != 0) return (error); } @@ -1327,7 +1310,6 @@ zyd_al7230B_set_channel(struct zyd_rf *rf, uint8_t chan) zyd_write16_m(sc, ZYD_CR240, 0x08); fail: return (error); -#undef N } /* @@ -1336,7 +1318,6 @@ fail: static int zyd_al2210_init(struct zyd_rf *rf) { -#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phyini[] = ZYD_AL2210_PHY; static const uint32_t rfini[] = ZYD_AL2210_RF; @@ -1346,11 +1327,11 @@ zyd_al2210_init(struct zyd_rf *rf) zyd_write32_m(sc, ZYD_CR18, 2); /* init RF-dependent PHY registers */ - for (i = 0; i < N(phyini); i++) + for (i = 0; i < nitems(phyini); i++) zyd_write16_m(sc, phyini[i].reg, phyini[i].val); /* init AL2210 radio */ - for (i = 0; i < N(rfini); i++) { + for (i = 0; i < nitems(rfini); i++) { if ((error = zyd_rfwrite(sc, rfini[i])) != 0) return (error); } @@ -1364,7 +1345,6 @@ zyd_al2210_init(struct zyd_rf *rf) zyd_write32_m(sc, ZYD_CR18, 3); fail: return (error); -#undef N } static int @@ -1409,7 +1389,6 @@ static int zyd_gct_init(struct zyd_rf *rf) { #define ZYD_GCT_INTR_REG 0x85c1 -#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phyini[] = ZYD_GCT_PHY; static const uint32_t rfini[] = ZYD_GCT_RF; @@ -1418,11 +1397,11 @@ zyd_gct_init(struct zyd_rf *rf) uint16_t data; /* init RF-dependent PHY registers */ - for (i = 0; i < N(phyini); i++) + for (i = 0; i < nitems(phyini); i++) zyd_write16_m(sc, phyini[i].reg, phyini[i].val); /* init cgt radio */ - for (i = 0; i < N(rfini); i++) { + for (i = 0; i < nitems(rfini); i++) { if ((error = zyd_rfwrite(sc, rfini[i])) != 0) return (error); } @@ -1431,7 +1410,7 @@ zyd_gct_init(struct zyd_rf *rf) if (error != 0) return (error); - for (i = 0; i < (int)(N(vco) - 1); i++) { + for (i = 0; i < (int)(nitems(vco) - 1); i++) { error = zyd_gct_set_channel_synth(rf, 1, 0); if (error != 0) goto fail; @@ -1458,26 +1437,23 @@ zyd_gct_init(struct zyd_rf *rf) zyd_write16_m(sc, ZYD_CR203, 0x6); fail: return (error); -#undef N #undef ZYD_GCT_INTR_REG } static int zyd_gct_mode(struct zyd_rf *rf) { -#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) struct zyd_softc *sc = rf->rf_sc; static const uint32_t mode[] = { 0x25f98, 0x25f9a, 0x25f94, 0x27fd4 }; int i, error; - for (i = 0; i < N(mode); i++) { + for (i = 0; i < nitems(mode); i++) { if ((error = zyd_rfwrite(sc, mode[i])) != 0) break; } return (error); -#undef N } static int @@ -1524,7 +1500,6 @@ fail: static int zyd_gct_set_channel(struct zyd_rf *rf, uint8_t chan) { -#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) int error, i; struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair cmd[] = { @@ -1543,7 +1518,7 @@ zyd_gct_set_channel(struct zyd_rf *rf, uint8_t chan) error = zyd_gct_mode(rf); if (error != 0) return (error); - for (i = 0; i < N(cmd); i++) + for (i = 0; i < nitems(cmd); i++) zyd_write16_m(sc, cmd[i].reg, cmd[i].val); error = zyd_gct_txgain(rf, chan); if (error != 0) @@ -1551,25 +1526,22 @@ zyd_gct_set_channel(struct zyd_rf *rf, uint8_t chan) zyd_write16_m(sc, ZYD_CR203, 0x6); fail: return (error); -#undef N } static int zyd_gct_txgain(struct zyd_rf *rf, uint8_t chan) { -#define N(a) (sizeof(a) / sizeof((a)[0])) struct zyd_softc *sc = rf->rf_sc; static uint32_t txgain[] = ZYD_GCT_TXGAIN; uint8_t idx = sc->sc_pwrint[chan - 1]; - if (idx >= N(txgain)) { + if (idx >= nitems(txgain)) { device_printf(sc->sc_dev, "could not set TX gain (%d %#x)\n", chan, idx); return 0; } return zyd_rfwrite(sc, 0x700000 | txgain[idx]); -#undef N } /* @@ -1578,7 +1550,6 @@ zyd_gct_txgain(struct zyd_rf *rf, uint8_t chan) static int zyd_maxim2_init(struct zyd_rf *rf) { -#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phyini[] = ZYD_MAXIM2_PHY; static const uint32_t rfini[] = ZYD_MAXIM2_RF; @@ -1586,14 +1557,14 @@ zyd_maxim2_init(struct zyd_rf *rf) int i, error; /* init RF-dependent PHY registers */ - for (i = 0; i < N(phyini); i++) + for (i = 0; i < nitems(phyini); i++) zyd_write16_m(sc, phyini[i].reg, phyini[i].val); zyd_read16_m(sc, ZYD_CR203, &tmp); zyd_write16_m(sc, ZYD_CR203, tmp & ~(1 << 4)); /* init maxim2 radio */ - for (i = 0; i < N(rfini); i++) { + for (i = 0; i < nitems(rfini); i++) { if ((error = zyd_rfwrite(sc, rfini[i])) != 0) return (error); } @@ -1601,7 +1572,6 @@ zyd_maxim2_init(struct zyd_rf *rf) zyd_write16_m(sc, ZYD_CR203, tmp | (1 << 4)); fail: return (error); -#undef N } static int @@ -1615,7 +1585,6 @@ zyd_maxim2_switch_radio(struct zyd_rf *rf, int on) static int zyd_maxim2_set_channel(struct zyd_rf *rf, uint8_t chan) { -#define N(a) ((int)(sizeof(a) / sizeof((a)[0]))) struct zyd_softc *sc = rf->rf_sc; static const struct zyd_phy_pair phyini[] = ZYD_MAXIM2_PHY; static const uint32_t rfini[] = ZYD_MAXIM2_RF; @@ -1631,7 +1600,7 @@ zyd_maxim2_set_channel(struct zyd_rf *rf, uint8_t chan) */ /* init RF-dependent PHY registers */ - for (i = 0; i < N(phyini); i++) + for (i = 0; i < nitems(phyini); i++) zyd_write16_m(sc, phyini[i].reg, phyini[i].val); zyd_read16_m(sc, ZYD_CR203, &tmp); @@ -1646,7 +1615,7 @@ zyd_maxim2_set_channel(struct zyd_rf *rf, uint8_t chan) goto fail; /* init maxim2 radio - skipping the two first values */ - for (i = 2; i < N(rfini); i++) { + for (i = 2; i < nitems(rfini); i++) { if ((error = zyd_rfwrite(sc, rfini[i])) != 0) return (error); } @@ -1654,7 +1623,6 @@ zyd_maxim2_set_channel(struct zyd_rf *rf, uint8_t chan) zyd_write16_m(sc, ZYD_CR203, tmp | (1 << 4)); fail: return (error); -#undef N } static int diff --git a/sys/dev/wi/if_wivar.h b/sys/dev/wi/if_wivar.h index 9b668cc0e1149..8cc320d50b60f 100644 --- a/sys/dev/wi/if_wivar.h +++ b/sys/dev/wi/if_wivar.h @@ -58,7 +58,6 @@ struct wi_vap { struct ieee80211vap wv_vap; - struct ieee80211_beacon_offsets wv_bo; void (*wv_recv_mgmt)(struct ieee80211_node *, struct mbuf *, int, const struct ieee80211_rx_stats *rxs, int, int); diff --git a/sys/dev/wpi/if_wpi.c b/sys/dev/wpi/if_wpi.c index 01ce3e4676953..abb3bd5baef15 100644 --- a/sys/dev/wpi/if_wpi.c +++ b/sys/dev/wpi/if_wpi.c @@ -3954,14 +3954,6 @@ wpi_config(struct wpi_softc *sc) sc->rxon.cck_mask = 0x0f; /* not yet negotiated */ sc->rxon.ofdm_mask = 0xff; /* not yet negotiated */ - /* XXX Current configuration may be unusable. */ - if (IEEE80211_IS_CHAN_NOADHOC(c) && sc->rxon.mode == WPI_MODE_IBSS) { - device_printf(sc->sc_dev, - "%s: invalid channel (%d) selected for IBSS mode\n", - __func__, ieee80211_chan2ieee(ic, c)); - return EINVAL; - } - if ((error = wpi_send_rxon(sc, 0, 0)) != 0) { device_printf(sc->sc_dev, "%s: could not send RXON\n", __func__); @@ -4309,8 +4301,9 @@ wpi_auth(struct wpi_softc *sc, struct ieee80211vap *vap) static int wpi_config_beacon(struct wpi_vap *wvp) { - struct ieee80211com *ic = wvp->wv_vap.iv_ic; - struct ieee80211_beacon_offsets *bo = &wvp->wv_boff; + struct ieee80211vap *vap = &wvp->wv_vap; + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; struct wpi_buf *bcn = &wvp->wv_bcbuf; struct wpi_softc *sc = ic->ic_softc; struct wpi_cmd_beacon *cmd = (struct wpi_cmd_beacon *)&bcn->data; @@ -4361,9 +4354,10 @@ end: bcn->m = m; static int wpi_setup_beacon(struct wpi_softc *sc, struct ieee80211_node *ni) { - struct wpi_vap *wvp = WPI_VAP(ni->ni_vap); + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; + struct wpi_vap *wvp = WPI_VAP(vap); struct wpi_buf *bcn = &wvp->wv_bcbuf; - struct ieee80211_beacon_offsets *bo = &wvp->wv_boff; struct mbuf *m; int error; @@ -4397,7 +4391,7 @@ wpi_update_beacon(struct ieee80211vap *vap, int item) struct wpi_softc *sc = vap->iv_ic->ic_softc; struct wpi_vap *wvp = WPI_VAP(vap); struct wpi_buf *bcn = &wvp->wv_bcbuf; - struct ieee80211_beacon_offsets *bo = &wvp->wv_boff; + struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; struct ieee80211_node *ni = vap->iv_bss; int mcast = 0; diff --git a/sys/dev/wpi/if_wpivar.h b/sys/dev/wpi/if_wpivar.h index 4e1baa5fdc50c..0934eaa68ace7 100644 --- a/sys/dev/wpi/if_wpivar.h +++ b/sys/dev/wpi/if_wpivar.h @@ -125,7 +125,6 @@ struct wpi_vap { struct ieee80211vap wv_vap; struct wpi_buf wv_bcbuf; - struct ieee80211_beacon_offsets wv_boff; struct mtx wv_mtx; uint32_t wv_gtk; diff --git a/sys/dev/wtap/if_wtap.c b/sys/dev/wtap/if_wtap.c index 526ce54928d47..7c15c358de83f 100644 --- a/sys/dev/wtap/if_wtap.c +++ b/sys/dev/wtap/if_wtap.c @@ -183,7 +183,7 @@ wtap_reset_vap(struct ieee80211vap *vap, u_long cmd) static void wtap_beacon_update(struct ieee80211vap *vap, int item) { - struct ieee80211_beacon_offsets *bo = &WTAP_VAP(vap)->av_boff; + struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; DWTAP_PRINTF("%s\n", __func__); setbit(bo->bo_flags, item); @@ -205,7 +205,7 @@ wtap_beacon_alloc(struct wtap_softc *sc, struct ieee80211_node *ni) * we assume the mbuf routines will return us something * with this alignment (perhaps should assert). */ - avp->beacon = ieee80211_beacon_alloc(ni, &avp->av_boff); + avp->beacon = ieee80211_beacon_alloc(ni, &vap->iv_bcn_off); if (avp->beacon == NULL) { printf("%s: cannot get mbuf\n", __func__); return ENOMEM; @@ -242,7 +242,7 @@ wtap_beacon_intrp(void *arg) * of the TIM bitmap). */ m = m_dup(avp->beacon, M_NOWAIT); - if (ieee80211_beacon_update(avp->bf_node, &avp->av_boff, m, 0)) { + if (ieee80211_beacon_update(avp->bf_node, &vap->iv_bcn_off, m, 0)) { printf("%s, need to remap the memory because the beacon frame" " changed size.\n",__func__); } diff --git a/sys/dev/wtap/if_wtapvar.h b/sys/dev/wtap/if_wtapvar.h index 04a1818d5c415..5ba55cbb3080c 100644 --- a/sys/dev/wtap/if_wtapvar.h +++ b/sys/dev/wtap/if_wtapvar.h @@ -116,7 +116,6 @@ struct wtap_vap { struct wtap_medium *av_md; /* back pointer */ struct mbuf *beacon; /* beacon */ struct ieee80211_node *bf_node; /* pointer to the node */ - struct ieee80211_beacon_offsets av_boff;/* dynamic update state */ struct callout av_swba; /* software beacon alert */ uint32_t av_bcinterval; /* beacon interval */ void (*av_recv_mgmt)(struct ieee80211_node *, diff --git a/sys/dev/xen/pcifront/pcifront.c b/sys/dev/xen/pcifront/pcifront.c index 1730bf8fc09f6..833e38bd7e2f9 100644 --- a/sys/dev/xen/pcifront/pcifront.c +++ b/sys/dev/xen/pcifront/pcifront.c @@ -559,7 +559,7 @@ xpcib_attach(device_t dev) DPRINTF("xpcib attach (bus=%d)\n", sc->bus); - device_add_child(dev, "pci", sc->bus); + device_add_child(dev, "pci", -1); return bus_generic_attach(dev); } |
