1*81508fe3Sjsg /* $OpenBSD: if_mtw.c,v 1.11 2024/05/23 03:21:08 jsg Exp $ */
257a8187dShastings /*
357a8187dShastings * Copyright (c) 2008-2010 Damien Bergamini <damien.bergamini@free.fr>
457a8187dShastings * Copyright (c) 2013-2014 Kevin Lo
557a8187dShastings * Copyright (c) 2021 James Hastings
657a8187dShastings *
757a8187dShastings * Permission to use, copy, modify, and distribute this software for any
857a8187dShastings * purpose with or without fee is hereby granted, provided that the above
957a8187dShastings * copyright notice and this permission notice appear in all copies.
1057a8187dShastings *
1157a8187dShastings * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1257a8187dShastings * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1357a8187dShastings * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1457a8187dShastings * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1557a8187dShastings * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1657a8187dShastings * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1757a8187dShastings * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1857a8187dShastings */
1957a8187dShastings
2057a8187dShastings /*
2157a8187dShastings * MediaTek MT7601U 802.11b/g/n WLAN.
2257a8187dShastings */
2357a8187dShastings
2457a8187dShastings #include "bpfilter.h"
2557a8187dShastings
2657a8187dShastings #include <sys/param.h>
2757a8187dShastings #include <sys/sockio.h>
2857a8187dShastings #include <sys/mbuf.h>
2957a8187dShastings #include <sys/systm.h>
3057a8187dShastings #include <sys/timeout.h>
3157a8187dShastings #include <sys/device.h>
3257a8187dShastings #include <sys/endian.h>
3357a8187dShastings
3457a8187dShastings #include <machine/intr.h>
3557a8187dShastings
3657a8187dShastings #if NBPFILTER > 0
3757a8187dShastings #include <net/bpf.h>
3857a8187dShastings #endif
3957a8187dShastings #include <net/if.h>
4057a8187dShastings #include <net/if_dl.h>
4157a8187dShastings #include <net/if_media.h>
4257a8187dShastings
4357a8187dShastings #include <netinet/in.h>
4457a8187dShastings #include <netinet/if_ether.h>
4557a8187dShastings
4657a8187dShastings #include <net80211/ieee80211_var.h>
4757a8187dShastings #include <net80211/ieee80211_amrr.h>
4857a8187dShastings #include <net80211/ieee80211_ra.h>
4957a8187dShastings #include <net80211/ieee80211_radiotap.h>
5057a8187dShastings
5157a8187dShastings #include <dev/usb/usb.h>
5257a8187dShastings #include <dev/usb/usbdi.h>
5357a8187dShastings #include <dev/usb/usbdi_util.h>
5457a8187dShastings #include <dev/usb/usbdevs.h>
5557a8187dShastings
5657a8187dShastings #include <dev/ic/mtwreg.h>
5757a8187dShastings #include <dev/usb/if_mtwvar.h>
5857a8187dShastings
5957a8187dShastings #ifdef MTW_DEBUG
6057a8187dShastings #define DPRINTF(x) do { if (mtw_debug) printf x; } while (0)
6157a8187dShastings #define DPRINTFN(n, x) do { if (mtw_debug >= (n)) printf x; } while (0)
6257a8187dShastings int mtw_debug = 0;
6357a8187dShastings #else
6457a8187dShastings #define DPRINTF(x)
6557a8187dShastings #define DPRINTFN(n, x)
6657a8187dShastings #endif
6757a8187dShastings
6857a8187dShastings #define USB_ID(v, p) { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }
6957a8187dShastings static const struct usb_devno mtw_devs[] = {
70acaa8857Shastings USB_ID(ASUS, USBN10V2),
71acaa8857Shastings USB_ID(AZUREWAVE, MT7601_1),
72acaa8857Shastings USB_ID(AZUREWAVE, MT7601_2),
73acaa8857Shastings USB_ID(DLINK, DWA127B1),
74acaa8857Shastings USB_ID(EDIMAX, EW7711UANV2),
75acaa8857Shastings USB_ID(MEDIATEK, MT7601_1),
76acaa8857Shastings USB_ID(MEDIATEK, MT7601_2),
7757a8187dShastings USB_ID(RALINK, MT7601),
78acaa8857Shastings USB_ID(RALINK, MT7601_2),
79acaa8857Shastings USB_ID(RALINK, MT7601_3),
80acaa8857Shastings USB_ID(RALINK, MT7601_4),
81acaa8857Shastings USB_ID(RALINK, MT7601_5),
8254a76c43Skevlo USB_ID(XIAOMI, MT7601U),
8357a8187dShastings };
8457a8187dShastings
8557a8187dShastings int mtw_match(struct device *, void *, void *);
8657a8187dShastings void mtw_attach(struct device *, struct device *, void *);
8757a8187dShastings int mtw_detach(struct device *, int);
8857a8187dShastings void mtw_attachhook(struct device *);
8957a8187dShastings int mtw_alloc_rx_ring(struct mtw_softc *, int);
9057a8187dShastings void mtw_free_rx_ring(struct mtw_softc *, int);
9157a8187dShastings int mtw_alloc_tx_ring(struct mtw_softc *, int);
9257a8187dShastings void mtw_free_tx_ring(struct mtw_softc *, int);
9357a8187dShastings int mtw_alloc_mcu_ring(struct mtw_softc *);
9457a8187dShastings void mtw_free_mcu_ring(struct mtw_softc *);
9557a8187dShastings int mtw_ucode_write(struct mtw_softc *, const uint8_t *,
9657a8187dShastings uint32_t, uint32_t);
9757a8187dShastings void mtw_ucode_setup(struct mtw_softc *);
9857a8187dShastings int mtw_load_microcode(struct mtw_softc *);
9957a8187dShastings int mtw_reset(struct mtw_softc *);
10057a8187dShastings int mtw_read(struct mtw_softc *, uint16_t, uint32_t *);
10157a8187dShastings int mtw_read_cfg(struct mtw_softc *, uint16_t, uint32_t *);
10257a8187dShastings int mtw_read_region_1(struct mtw_softc *, uint16_t,
10357a8187dShastings uint8_t *, int);
10457a8187dShastings int mtw_write_2(struct mtw_softc *, uint16_t, uint16_t);
10557a8187dShastings int mtw_write(struct mtw_softc *, uint16_t, uint32_t);
10657a8187dShastings int mtw_write_cfg(struct mtw_softc *, uint16_t, uint32_t);
10757a8187dShastings int mtw_write_ivb(struct mtw_softc *, const uint8_t *, uint16_t);
10857a8187dShastings int mtw_write_region_1(struct mtw_softc *, uint16_t,
10957a8187dShastings uint8_t *, int);
11057a8187dShastings int mtw_set_region_4(struct mtw_softc *, uint16_t, uint32_t, int);
11157a8187dShastings int mtw_efuse_read_2(struct mtw_softc *, uint16_t, uint16_t *);
11257a8187dShastings int mtw_eeprom_read_2(struct mtw_softc *, uint16_t, uint16_t *);
11357a8187dShastings int mtw_rf_read(struct mtw_softc *, uint8_t, uint8_t, uint8_t *);
11457a8187dShastings int mtw_rf_write(struct mtw_softc *, uint8_t, uint8_t, uint8_t);
11557a8187dShastings int mtw_bbp_read(struct mtw_softc *, uint8_t, uint8_t *);
11657a8187dShastings int mtw_bbp_write(struct mtw_softc *, uint8_t, uint8_t);
11757a8187dShastings int mtw_usb_dma_read(struct mtw_softc *, uint32_t *);
11857a8187dShastings int mtw_usb_dma_write(struct mtw_softc *, uint32_t);
11957a8187dShastings int mtw_mcu_calibrate(struct mtw_softc *, int, uint32_t);
12057a8187dShastings int mtw_mcu_channel(struct mtw_softc *, uint32_t, uint32_t, uint32_t);
12157a8187dShastings int mtw_mcu_radio(struct mtw_softc *, int, uint32_t);
12257a8187dShastings int mtw_mcu_cmd(struct mtw_softc *, int, void *, int);
12357a8187dShastings const char * mtw_get_rf(int);
12457a8187dShastings void mtw_get_txpower(struct mtw_softc *);
12557a8187dShastings int mtw_read_eeprom(struct mtw_softc *);
12657a8187dShastings struct ieee80211_node *mtw_node_alloc(struct ieee80211com *);
12757a8187dShastings int mtw_media_change(struct ifnet *);
12857a8187dShastings void mtw_next_scan(void *);
12957a8187dShastings void mtw_task(void *);
13057a8187dShastings void mtw_do_async(struct mtw_softc *, void (*)(struct mtw_softc *,
13157a8187dShastings void *), void *, int);
13257a8187dShastings int mtw_newstate(struct ieee80211com *, enum ieee80211_state, int);
13357a8187dShastings void mtw_newstate_cb(struct mtw_softc *, void *);
13457a8187dShastings void mtw_updateedca(struct ieee80211com *);
13557a8187dShastings void mtw_updateedca_cb(struct mtw_softc *, void *);
13657a8187dShastings void mtw_updateslot(struct ieee80211com *);
13757a8187dShastings void mtw_updateslot_cb(struct mtw_softc *, void *);
13857a8187dShastings int mtw_set_key(struct ieee80211com *, struct ieee80211_node *,
13957a8187dShastings struct ieee80211_key *);
14057a8187dShastings void mtw_set_key_cb(struct mtw_softc *, void *);
14157a8187dShastings void mtw_delete_key(struct ieee80211com *, struct ieee80211_node *,
14257a8187dShastings struct ieee80211_key *);
14357a8187dShastings void mtw_delete_key_cb(struct mtw_softc *, void *);
14457a8187dShastings void mtw_calibrate_to(void *);
14557a8187dShastings void mtw_calibrate_cb(struct mtw_softc *, void *);
14657a8187dShastings void mtw_newassoc(struct ieee80211com *, struct ieee80211_node *,
14757a8187dShastings int);
14857a8187dShastings void mtw_rx_frame(struct mtw_softc *, uint8_t *, int,
14957a8187dShastings struct mbuf_list *);
15057a8187dShastings void mtw_rxeof(struct usbd_xfer *, void *, usbd_status);
15157a8187dShastings void mtw_txeof(struct usbd_xfer *, void *, usbd_status);
15257a8187dShastings int mtw_tx(struct mtw_softc *, struct mbuf *,
15357a8187dShastings struct ieee80211_node *);
15457a8187dShastings void mtw_start(struct ifnet *);
15557a8187dShastings void mtw_watchdog(struct ifnet *);
15657a8187dShastings int mtw_ioctl(struct ifnet *, u_long, caddr_t);
15757a8187dShastings void mtw_select_chan_group(struct mtw_softc *, int);
15857a8187dShastings void mt7601_set_agc(struct mtw_softc *, uint8_t);
15957a8187dShastings void mt7601_set_chan(struct mtw_softc *, u_int);
16057a8187dShastings int mtw_set_chan(struct mtw_softc *, struct ieee80211_channel *);
16157a8187dShastings void mtw_enable_tsf_sync(struct mtw_softc *);
16257a8187dShastings void mtw_abort_tsf_sync(struct mtw_softc *);
16357a8187dShastings void mtw_enable_mrr(struct mtw_softc *);
16457a8187dShastings void mtw_set_txrts(struct mtw_softc *);
16557a8187dShastings void mtw_set_txpreamble(struct mtw_softc *);
16657a8187dShastings void mtw_set_basicrates(struct mtw_softc *);
16757a8187dShastings void mtw_set_leds(struct mtw_softc *, uint16_t);
16857a8187dShastings void mtw_set_bssid(struct mtw_softc *, const uint8_t *);
16957a8187dShastings void mtw_set_macaddr(struct mtw_softc *, const uint8_t *);
17057a8187dShastings #if NBPFILTER > 0
17157a8187dShastings int8_t mtw_rssi2dbm(struct mtw_softc *, uint8_t, uint8_t);
17257a8187dShastings #endif
17357a8187dShastings int mt7601_bbp_init(struct mtw_softc *);
17457a8187dShastings int mt7601_rf_init(struct mtw_softc *);
17557a8187dShastings int mt7601_rf_setup(struct mtw_softc *);
17657a8187dShastings int mt7601_rf_temperature(struct mtw_softc *, int8_t *);
17757a8187dShastings int mt7601_r49_read(struct mtw_softc *, uint8_t, int8_t *);
17857a8187dShastings int mt7601_rxdc_cal(struct mtw_softc *);
17957a8187dShastings int mtw_wlan_enable(struct mtw_softc *, int);
18057a8187dShastings int mtw_txrx_enable(struct mtw_softc *);
18157a8187dShastings int mtw_init(struct ifnet *);
18257a8187dShastings void mtw_stop(struct ifnet *, int);
18357a8187dShastings
18457a8187dShastings struct cfdriver mtw_cd = {
18557a8187dShastings NULL, "mtw", DV_IFNET
18657a8187dShastings };
18757a8187dShastings
18857a8187dShastings const struct cfattach mtw_ca = {
18957a8187dShastings sizeof (struct mtw_softc), mtw_match, mtw_attach, mtw_detach
19057a8187dShastings };
19157a8187dShastings
19257a8187dShastings static const struct {
19357a8187dShastings uint32_t reg;
19457a8187dShastings uint32_t val;
19557a8187dShastings } mt7601_def_mac[] = {
19657a8187dShastings MT7601_DEF_MAC
19757a8187dShastings };
19857a8187dShastings
19957a8187dShastings static const struct {
20057a8187dShastings uint8_t reg;
20157a8187dShastings uint8_t val;
20257a8187dShastings } mt7601_def_bbp[] = {
20357a8187dShastings MT7601_DEF_BBP
20457a8187dShastings };
20557a8187dShastings
20657a8187dShastings static const struct {
20757a8187dShastings u_int chan;
20857a8187dShastings uint8_t r17, r18, r19, r20;
20957a8187dShastings } mt7601_rf_chan[] = {
21057a8187dShastings MT7601_RF_CHAN
21157a8187dShastings };
21257a8187dShastings
21357a8187dShastings static const struct {
21457a8187dShastings uint8_t reg;
21557a8187dShastings uint8_t val;
21657a8187dShastings } mt7601_rf_bank0[] = {
21757a8187dShastings MT7601_BANK0_RF
21857a8187dShastings },mt7601_rf_bank4[] = {
21957a8187dShastings MT7601_BANK4_RF
22057a8187dShastings },mt7601_rf_bank5[] = {
22157a8187dShastings MT7601_BANK5_RF
22257a8187dShastings };
22357a8187dShastings
22457a8187dShastings int
mtw_match(struct device * parent,void * match,void * aux)22557a8187dShastings mtw_match(struct device *parent, void *match, void *aux)
22657a8187dShastings {
22757a8187dShastings struct usb_attach_arg *uaa = aux;
22857a8187dShastings
22957a8187dShastings if (uaa->iface == NULL || uaa->configno != 1)
23057a8187dShastings return UMATCH_NONE;
23157a8187dShastings
23257a8187dShastings return (usb_lookup(mtw_devs, uaa->vendor, uaa->product) != NULL) ?
23357a8187dShastings UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE;
23457a8187dShastings }
23557a8187dShastings
23657a8187dShastings void
mtw_attach(struct device * parent,struct device * self,void * aux)23757a8187dShastings mtw_attach(struct device *parent, struct device *self, void *aux)
23857a8187dShastings {
23957a8187dShastings struct mtw_softc *sc = (struct mtw_softc *)self;
24057a8187dShastings struct usb_attach_arg *uaa = aux;
24157a8187dShastings usb_interface_descriptor_t *id;
24257a8187dShastings usb_endpoint_descriptor_t *ed;
24357a8187dShastings int i, error, nrx, ntx, ntries;
24457a8187dShastings uint32_t ver;
24557a8187dShastings
24657a8187dShastings sc->sc_udev = uaa->device;
24757a8187dShastings sc->sc_iface = uaa->iface;
24857a8187dShastings
24957a8187dShastings /*
25057a8187dShastings * Find all bulk endpoints.
25157a8187dShastings */
25257a8187dShastings nrx = ntx = 0;
25357a8187dShastings id = usbd_get_interface_descriptor(sc->sc_iface);
25457a8187dShastings for (i = 0; i < id->bNumEndpoints; i++) {
25557a8187dShastings ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
25657a8187dShastings if (ed == NULL || UE_GET_XFERTYPE(ed->bmAttributes) != UE_BULK)
25757a8187dShastings continue;
25857a8187dShastings
25957a8187dShastings if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) {
26057a8187dShastings sc->rxq[nrx].pipe_no = ed->bEndpointAddress;
26157a8187dShastings nrx++;
26257a8187dShastings } else if (ntx < 6) {
26357a8187dShastings if (ntx == 0)
26457a8187dShastings sc->txq[MTW_TXQ_MCU].pipe_no =
26557a8187dShastings ed->bEndpointAddress;
26657a8187dShastings else
26757a8187dShastings sc->txq[ntx - 1].pipe_no =
26857a8187dShastings ed->bEndpointAddress;
26957a8187dShastings ntx++;
27057a8187dShastings }
27157a8187dShastings }
27257a8187dShastings /* make sure we've got them all */
27357a8187dShastings if (nrx < 2 || ntx < 6) {
27457a8187dShastings printf("%s: missing endpoint\n", sc->sc_dev.dv_xname);
27557a8187dShastings return;
27657a8187dShastings }
27757a8187dShastings
27857a8187dShastings /* wait for the chip to settle */
27957a8187dShastings for (ntries = 0; ntries < 100; ntries++) {
28057a8187dShastings if ((error = mtw_read(sc, MTW_ASIC_VER, &ver)) != 0)
28157a8187dShastings return;
28257a8187dShastings if (ver != 0 && ver != 0xffffffff)
28357a8187dShastings break;
28457a8187dShastings DPRINTF(("%08x ", ver));
28557a8187dShastings DELAY(10);
28657a8187dShastings }
28757a8187dShastings if (ntries == 100) {
28857a8187dShastings printf("%s: timeout waiting for NIC to initialize\n",
28957a8187dShastings sc->sc_dev.dv_xname);
29057a8187dShastings return;
29157a8187dShastings }
29257a8187dShastings
29357a8187dShastings sc->asic_ver = ver >> 16;
29457a8187dShastings sc->asic_rev = ver & 0xffff;
29557a8187dShastings
29657a8187dShastings usb_init_task(&sc->sc_task, mtw_task, sc, USB_TASK_TYPE_GENERIC);
29757a8187dShastings timeout_set(&sc->scan_to, mtw_next_scan, sc);
29857a8187dShastings timeout_set(&sc->calib_to, mtw_calibrate_to, sc);
29957a8187dShastings
30057a8187dShastings sc->amrr.amrr_min_success_threshold = 1;
30157a8187dShastings sc->amrr.amrr_max_success_threshold = 10;
30257a8187dShastings
30357a8187dShastings config_mountroot(self, mtw_attachhook);
30457a8187dShastings }
30557a8187dShastings
30657a8187dShastings int
mtw_detach(struct device * self,int flags)30757a8187dShastings mtw_detach(struct device *self, int flags)
30857a8187dShastings {
30957a8187dShastings struct mtw_softc *sc = (struct mtw_softc *)self;
31057a8187dShastings struct ifnet *ifp = &sc->sc_ic.ic_if;
31157a8187dShastings int qid, s;
31257a8187dShastings
31357a8187dShastings s = splusb();
31457a8187dShastings
31557a8187dShastings if (timeout_initialized(&sc->scan_to))
31657a8187dShastings timeout_del(&sc->scan_to);
31757a8187dShastings if (timeout_initialized(&sc->calib_to))
31857a8187dShastings timeout_del(&sc->calib_to);
31957a8187dShastings
32057a8187dShastings /* wait for all queued asynchronous commands to complete */
32157a8187dShastings usb_rem_wait_task(sc->sc_udev, &sc->sc_task);
32257a8187dShastings
32357a8187dShastings usbd_ref_wait(sc->sc_udev);
32457a8187dShastings
32557a8187dShastings if (ifp->if_softc != NULL) {
32657a8187dShastings ifp->if_flags &= ~IFF_RUNNING;
32757a8187dShastings ifq_clr_oactive(&ifp->if_snd);
32857a8187dShastings ieee80211_ifdetach(ifp);
32957a8187dShastings if_detach(ifp);
33057a8187dShastings }
33157a8187dShastings
33257a8187dShastings /* free rings and close pipes */
33357a8187dShastings mtw_free_mcu_ring(sc);
33457a8187dShastings for (qid = 0; qid < MTW_TXQ_COUNT; qid++)
33557a8187dShastings mtw_free_tx_ring(sc, qid);
33657a8187dShastings mtw_free_rx_ring(sc, 0);
33757a8187dShastings mtw_free_rx_ring(sc, 1);
33857a8187dShastings
33957a8187dShastings splx(s);
34057a8187dShastings return 0;
34157a8187dShastings }
34257a8187dShastings
34357a8187dShastings void
mtw_attachhook(struct device * self)34457a8187dShastings mtw_attachhook(struct device *self)
34557a8187dShastings {
34657a8187dShastings struct mtw_softc *sc = (struct mtw_softc *)self;
34757a8187dShastings struct ieee80211com *ic = &sc->sc_ic;
34857a8187dShastings struct ifnet *ifp = &ic->ic_if;
34957a8187dShastings uint32_t tmp;
35057a8187dShastings int ntries, error, i;
35157a8187dShastings
35257a8187dShastings if (usbd_is_dying(sc->sc_udev))
35357a8187dShastings return;
35457a8187dShastings
35557a8187dShastings /* enable WLAN core */
35657a8187dShastings if ((error = mtw_wlan_enable(sc, 1)) != 0) {
35757a8187dShastings printf("%s: could not enable WLAN core\n",
35857a8187dShastings sc->sc_dev.dv_xname);
35957a8187dShastings return;
36057a8187dShastings }
36157a8187dShastings
36257a8187dShastings /* load firmware */
36357a8187dShastings if ((error = mtw_load_microcode(sc)) != 0) {
36457a8187dShastings printf("%s: could not load microcode\n",
36557a8187dShastings sc->sc_dev.dv_xname);
36657a8187dShastings goto fail;
36757a8187dShastings }
36857a8187dShastings
36957a8187dShastings mtw_usb_dma_read(sc, &tmp);
37057a8187dShastings mtw_usb_dma_write(sc, tmp | (MTW_USB_RX_EN | MTW_USB_TX_EN));
37157a8187dShastings
37257a8187dShastings /* read MAC version */
37357a8187dShastings for (ntries = 0; ntries < 100; ntries++) {
37457a8187dShastings if ((error = mtw_read(sc, MTW_MAC_VER_ID, &tmp)) != 0)
37557a8187dShastings goto fail;
37657a8187dShastings if (tmp != 0 && tmp != 0xffffffff)
37757a8187dShastings break;
37857a8187dShastings DELAY(10);
37957a8187dShastings }
38057a8187dShastings if (ntries == 100) {
38157a8187dShastings printf("%s: failed reading MAC\n", sc->sc_dev.dv_xname);
38257a8187dShastings goto fail;
38357a8187dShastings }
38457a8187dShastings
38557a8187dShastings sc->mac_ver = tmp >> 16;
38657a8187dShastings sc->mac_rev = tmp & 0xffff;
38757a8187dShastings
38857a8187dShastings /* retrieve RF rev. no and various other things from EEPROM */
38957a8187dShastings mtw_read_eeprom(sc);
39057a8187dShastings
39157a8187dShastings printf("%s: MAC/BBP MT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), "
39257a8187dShastings "address %s\n", sc->sc_dev.dv_xname, sc->mac_ver,
39357a8187dShastings sc->mac_rev, mtw_get_rf(sc->rf_rev), sc->ntxchains,
39457a8187dShastings sc->nrxchains, ether_sprintf(ic->ic_myaddr));
39557a8187dShastings
39657a8187dShastings ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
39757a8187dShastings ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
39857a8187dShastings ic->ic_state = IEEE80211_S_INIT;
39957a8187dShastings
40057a8187dShastings /* set device capabilities */
40157a8187dShastings ic->ic_caps =
40257a8187dShastings IEEE80211_C_MONITOR | /* monitor mode supported */
40357a8187dShastings IEEE80211_C_SHPREAMBLE | /* short preamble supported */
40457a8187dShastings IEEE80211_C_SHSLOT | /* short slot time supported */
40557a8187dShastings IEEE80211_C_WEP | /* WEP */
40657a8187dShastings IEEE80211_C_RSN; /* WPA/RSN */
40757a8187dShastings
40857a8187dShastings /* set supported .11b and .11g rates */
40957a8187dShastings ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
41057a8187dShastings ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
41157a8187dShastings
41257a8187dShastings /* set supported .11b and .11g channels (1 through 14) */
41357a8187dShastings for (i = 1; i <= 14; i++) {
41457a8187dShastings ic->ic_channels[i].ic_freq =
41557a8187dShastings ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
41657a8187dShastings ic->ic_channels[i].ic_flags =
41757a8187dShastings IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
41857a8187dShastings IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
41957a8187dShastings }
42057a8187dShastings
42157a8187dShastings ifp->if_softc = sc;
42257a8187dShastings ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
42357a8187dShastings ifp->if_ioctl = mtw_ioctl;
42457a8187dShastings ifp->if_start = mtw_start;
42557a8187dShastings ifp->if_watchdog = mtw_watchdog;
42657a8187dShastings memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
42757a8187dShastings
42857a8187dShastings if_attach(ifp);
42957a8187dShastings ieee80211_ifattach(ifp);
43057a8187dShastings ic->ic_node_alloc = mtw_node_alloc;
43157a8187dShastings ic->ic_newassoc = mtw_newassoc;
43257a8187dShastings ic->ic_updateslot = mtw_updateslot;
43357a8187dShastings ic->ic_updateedca = mtw_updateedca;
43457a8187dShastings ic->ic_set_key = mtw_set_key;
43557a8187dShastings ic->ic_delete_key = mtw_delete_key;
43657a8187dShastings
43757a8187dShastings /* override 802.11 state transition machine */
43857a8187dShastings sc->sc_newstate = ic->ic_newstate;
43957a8187dShastings ic->ic_newstate = mtw_newstate;
44057a8187dShastings ieee80211_media_init(ifp, mtw_media_change, ieee80211_media_status);
44157a8187dShastings
44257a8187dShastings #if NBPFILTER > 0
44357a8187dShastings bpfattach(&sc->sc_drvbpf, ifp, DLT_IEEE802_11_RADIO,
44457a8187dShastings sizeof (struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN);
44557a8187dShastings
44657a8187dShastings sc->sc_rxtap_len = sizeof sc->sc_rxtapu;
44757a8187dShastings sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
44857a8187dShastings sc->sc_rxtap.wr_ihdr.it_present = htole32(MTW_RX_RADIOTAP_PRESENT);
44957a8187dShastings
45057a8187dShastings sc->sc_txtap_len = sizeof sc->sc_txtapu;
45157a8187dShastings sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
45257a8187dShastings sc->sc_txtap.wt_ihdr.it_present = htole32(MTW_TX_RADIOTAP_PRESENT);
45357a8187dShastings #endif
45457a8187dShastings fail:
45557a8187dShastings return;
45657a8187dShastings }
45757a8187dShastings
45857a8187dShastings int
mtw_alloc_rx_ring(struct mtw_softc * sc,int qid)45957a8187dShastings mtw_alloc_rx_ring(struct mtw_softc *sc, int qid)
46057a8187dShastings {
46157a8187dShastings struct mtw_rx_ring *rxq = &sc->rxq[qid];
46257a8187dShastings int i, error;
46357a8187dShastings
46457a8187dShastings if ((error = usbd_open_pipe(sc->sc_iface, rxq->pipe_no, 0,
46557a8187dShastings &rxq->pipeh)) != 0)
46657a8187dShastings goto fail;
46757a8187dShastings
46857a8187dShastings for (i = 0; i < MTW_RX_RING_COUNT; i++) {
46957a8187dShastings struct mtw_rx_data *data = &rxq->data[i];
47057a8187dShastings
47157a8187dShastings data->sc = sc; /* backpointer for callbacks */
47257a8187dShastings
47357a8187dShastings data->xfer = usbd_alloc_xfer(sc->sc_udev);
47457a8187dShastings if (data->xfer == NULL) {
47557a8187dShastings error = ENOMEM;
47657a8187dShastings goto fail;
47757a8187dShastings }
47857a8187dShastings data->buf = usbd_alloc_buffer(data->xfer, MTW_MAX_RXSZ);
47957a8187dShastings if (data->buf == NULL) {
48057a8187dShastings error = ENOMEM;
48157a8187dShastings goto fail;
48257a8187dShastings }
48357a8187dShastings }
48457a8187dShastings if (error != 0)
48557a8187dShastings fail: mtw_free_rx_ring(sc, 0);
48657a8187dShastings return error;
48757a8187dShastings }
48857a8187dShastings
48957a8187dShastings void
mtw_free_rx_ring(struct mtw_softc * sc,int qid)49057a8187dShastings mtw_free_rx_ring(struct mtw_softc *sc, int qid)
49157a8187dShastings {
49257a8187dShastings struct mtw_rx_ring *rxq = &sc->rxq[qid];
49357a8187dShastings int i;
49457a8187dShastings
49557a8187dShastings if (rxq->pipeh != NULL) {
49657a8187dShastings usbd_close_pipe(rxq->pipeh);
49757a8187dShastings rxq->pipeh = NULL;
49857a8187dShastings }
49957a8187dShastings for (i = 0; i < MTW_RX_RING_COUNT; i++) {
50057a8187dShastings if (rxq->data[i].xfer != NULL)
50157a8187dShastings usbd_free_xfer(rxq->data[i].xfer);
50257a8187dShastings rxq->data[i].xfer = NULL;
50357a8187dShastings }
50457a8187dShastings }
50557a8187dShastings
50657a8187dShastings int
mtw_alloc_tx_ring(struct mtw_softc * sc,int qid)50757a8187dShastings mtw_alloc_tx_ring(struct mtw_softc *sc, int qid)
50857a8187dShastings {
50957a8187dShastings struct mtw_tx_ring *txq = &sc->txq[qid];
51057a8187dShastings int i, error;
51157a8187dShastings uint16_t txwisize;
51257a8187dShastings
51357a8187dShastings txwisize = sizeof(struct mtw_txwi);
51457a8187dShastings
51557a8187dShastings txq->cur = txq->queued = 0;
51657a8187dShastings
51757a8187dShastings if ((error = usbd_open_pipe(sc->sc_iface, txq->pipe_no, 0,
51857a8187dShastings &txq->pipeh)) != 0)
51957a8187dShastings goto fail;
52057a8187dShastings
52157a8187dShastings for (i = 0; i < MTW_TX_RING_COUNT; i++) {
52257a8187dShastings struct mtw_tx_data *data = &txq->data[i];
52357a8187dShastings
52457a8187dShastings data->sc = sc; /* backpointer for callbacks */
52557a8187dShastings data->qid = qid;
52657a8187dShastings
52757a8187dShastings data->xfer = usbd_alloc_xfer(sc->sc_udev);
52857a8187dShastings if (data->xfer == NULL) {
52957a8187dShastings error = ENOMEM;
53057a8187dShastings goto fail;
53157a8187dShastings }
53257a8187dShastings
53357a8187dShastings data->buf = usbd_alloc_buffer(data->xfer, MTW_MAX_TXSZ);
53457a8187dShastings if (data->buf == NULL) {
53557a8187dShastings error = ENOMEM;
53657a8187dShastings goto fail;
53757a8187dShastings }
53857a8187dShastings
53957a8187dShastings /* zeroize the TXD + TXWI part */
54057a8187dShastings memset(data->buf, 0, MTW_MAX_TXSZ);
54157a8187dShastings }
54257a8187dShastings if (error != 0)
54357a8187dShastings fail: mtw_free_tx_ring(sc, qid);
54457a8187dShastings return error;
54557a8187dShastings }
54657a8187dShastings
54757a8187dShastings void
mtw_free_tx_ring(struct mtw_softc * sc,int qid)54857a8187dShastings mtw_free_tx_ring(struct mtw_softc *sc, int qid)
54957a8187dShastings {
55057a8187dShastings struct mtw_tx_ring *txq = &sc->txq[qid];
55157a8187dShastings int i;
55257a8187dShastings
55357a8187dShastings if (txq->pipeh != NULL) {
55457a8187dShastings usbd_close_pipe(txq->pipeh);
55557a8187dShastings txq->pipeh = NULL;
55657a8187dShastings }
55757a8187dShastings for (i = 0; i < MTW_TX_RING_COUNT; i++) {
55857a8187dShastings if (txq->data[i].xfer != NULL)
55957a8187dShastings usbd_free_xfer(txq->data[i].xfer);
56057a8187dShastings txq->data[i].xfer = NULL;
56157a8187dShastings }
56257a8187dShastings }
56357a8187dShastings
56457a8187dShastings int
mtw_alloc_mcu_ring(struct mtw_softc * sc)56557a8187dShastings mtw_alloc_mcu_ring(struct mtw_softc *sc)
56657a8187dShastings {
56757a8187dShastings struct mtw_tx_ring *ring = &sc->sc_mcu;
56857a8187dShastings struct mtw_tx_data *data = &ring->data[0];
56957a8187dShastings int error = 0;
57057a8187dShastings
57157a8187dShastings ring->cur = ring->queued = 0;
57257a8187dShastings
57357a8187dShastings data->sc = sc; /* backpointer for callbacks */
57457a8187dShastings data->qid = 5;
57557a8187dShastings
57657a8187dShastings data->xfer = usbd_alloc_xfer(sc->sc_udev);
57757a8187dShastings if (data->xfer == NULL) {
57857a8187dShastings error = ENOMEM;
57957a8187dShastings goto fail;
58057a8187dShastings }
58157a8187dShastings
58257a8187dShastings data->buf = usbd_alloc_buffer(data->xfer, MTW_MAX_TXSZ);
58357a8187dShastings if (data->buf == NULL) {
58457a8187dShastings error = ENOMEM;
58557a8187dShastings goto fail;
58657a8187dShastings }
58757a8187dShastings /* zeroize the TXD */
58857a8187dShastings memset(data->buf, 0, 4);
58957a8187dShastings
59057a8187dShastings if (error != 0)
59157a8187dShastings fail: mtw_free_mcu_ring(sc);
59257a8187dShastings return error;
59357a8187dShastings
59457a8187dShastings
59557a8187dShastings }
59657a8187dShastings void
mtw_free_mcu_ring(struct mtw_softc * sc)59757a8187dShastings mtw_free_mcu_ring(struct mtw_softc *sc)
59857a8187dShastings {
59957a8187dShastings struct mtw_tx_ring *txq = &sc->sc_mcu;
60057a8187dShastings
60157a8187dShastings if (txq->data[0].xfer != NULL)
60257a8187dShastings usbd_free_xfer(txq->data[0].xfer);
60357a8187dShastings txq->data[0].xfer = NULL;
60457a8187dShastings }
60557a8187dShastings
60657a8187dShastings int
mtw_ucode_write(struct mtw_softc * sc,const uint8_t * fw,uint32_t len,uint32_t offset)60757a8187dShastings mtw_ucode_write(struct mtw_softc *sc, const uint8_t *fw, uint32_t len,
60857a8187dShastings uint32_t offset)
60957a8187dShastings {
61057a8187dShastings struct mtw_tx_ring *ring = &sc->txq[MTW_TXQ_MCU];
61157a8187dShastings struct usbd_xfer *xfer;
61257a8187dShastings struct mtw_txd *txd;
61357a8187dShastings uint8_t *buf;
61457a8187dShastings uint32_t blksz, sent, tmp, xferlen;
61557a8187dShastings int error;
61657a8187dShastings
61757a8187dShastings blksz = 0x2000;
61857a8187dShastings if (sc->asic_ver == 0x7612 && offset >= 0x90000)
61957a8187dShastings blksz = 0x800; /* MT7612 ROM Patch */
62057a8187dShastings
62157a8187dShastings xfer = usbd_alloc_xfer(sc->sc_udev);
62257a8187dShastings if (xfer == NULL) {
62357a8187dShastings error = ENOMEM;
62457a8187dShastings goto fail;
62557a8187dShastings }
62657a8187dShastings buf = usbd_alloc_buffer(xfer, blksz + 12);
62757a8187dShastings if (buf == NULL) {
62857a8187dShastings error = ENOMEM;
62957a8187dShastings goto fail;
63057a8187dShastings }
63157a8187dShastings
63257a8187dShastings sent = 0;
63357a8187dShastings for (;;) {
63457a8187dShastings xferlen = min(len - sent, blksz);
63557a8187dShastings if (xferlen == 0)
63657a8187dShastings break;
63757a8187dShastings
63857a8187dShastings txd = (struct mtw_txd *)buf;
63957a8187dShastings txd->len = htole16(xferlen);
64057a8187dShastings txd->flags = htole16(MTW_TXD_DATA | MTW_TXD_MCU);
64157a8187dShastings
64257a8187dShastings memcpy(buf + sizeof(struct mtw_txd), fw + sent, xferlen);
64357a8187dShastings memset(buf + sizeof(struct mtw_txd) + xferlen, 0, MTW_DMA_PAD);
64457a8187dShastings mtw_write_cfg(sc, MTW_MCU_DMA_ADDR, offset + sent);
64557a8187dShastings mtw_write_cfg(sc, MTW_MCU_DMA_LEN, (xferlen << 16));
64657a8187dShastings
64757a8187dShastings usbd_setup_xfer(xfer, ring->pipeh, NULL, buf,
64857a8187dShastings xferlen + sizeof(struct mtw_txd) + MTW_DMA_PAD,
64957a8187dShastings USBD_SHORT_XFER_OK | USBD_SYNCHRONOUS | USBD_NO_COPY,
65057a8187dShastings MTW_TX_TIMEOUT, NULL);
65157a8187dShastings if ((error = usbd_transfer(xfer)) != 0)
65257a8187dShastings break;
65357a8187dShastings
65457a8187dShastings mtw_read(sc, MTW_MCU_FW_IDX, &tmp);
65557a8187dShastings mtw_write(sc, MTW_MCU_FW_IDX, tmp++);
65657a8187dShastings
65757a8187dShastings sent += xferlen;
65857a8187dShastings }
65957a8187dShastings fail:
66057a8187dShastings if (xfer != NULL) {
66157a8187dShastings usbd_free_xfer(xfer);
66257a8187dShastings xfer = NULL;
66357a8187dShastings }
66457a8187dShastings return error;
66557a8187dShastings }
66657a8187dShastings
66757a8187dShastings void
mtw_ucode_setup(struct mtw_softc * sc)66857a8187dShastings mtw_ucode_setup(struct mtw_softc *sc)
66957a8187dShastings {
67057a8187dShastings mtw_usb_dma_write(sc, (MTW_USB_TX_EN | MTW_USB_RX_EN));
67157a8187dShastings mtw_write(sc, MTW_FCE_PSE_CTRL, 1);
67257a8187dShastings mtw_write(sc, MTW_TX_CPU_FCE_BASE, 0x400230);
67357a8187dShastings mtw_write(sc, MTW_TX_CPU_FCE_MAX_COUNT, 1);
67457a8187dShastings mtw_write(sc, MTW_MCU_FW_IDX, 1);
67557a8187dShastings mtw_write(sc, MTW_FCE_PDMA, 0x44);
67657a8187dShastings mtw_write(sc, MTW_FCE_SKIP_FS, 3);
67757a8187dShastings }
67857a8187dShastings
67957a8187dShastings int
mtw_load_microcode(struct mtw_softc * sc)68057a8187dShastings mtw_load_microcode(struct mtw_softc *sc)
68157a8187dShastings {
68257a8187dShastings const struct mtw_ucode_hdr *hdr;
68357a8187dShastings const struct mtw_ucode *fw;
68457a8187dShastings const char *fwname;
68557a8187dShastings u_char *ucode;
68657a8187dShastings size_t size;
68757a8187dShastings uint32_t tmp, iofs, dofs;
68857a8187dShastings int ntries, error;
68957a8187dShastings int dlen, ilen;
69057a8187dShastings
69157a8187dShastings /* is firmware already running? */
69257a8187dShastings mtw_read_cfg(sc, MTW_MCU_DMA_ADDR, &tmp);
69357a8187dShastings if (tmp == MTW_MCU_READY)
69457a8187dShastings return 0;
69557a8187dShastings
69657a8187dShastings /* open MCU pipe */
69757a8187dShastings if ((error = usbd_open_pipe(sc->sc_iface, sc->txq[MTW_TXQ_MCU].pipe_no,
69857a8187dShastings 0, &sc->txq[MTW_TXQ_MCU].pipeh)) != 0)
69957a8187dShastings return error;
70057a8187dShastings
70157a8187dShastings if (sc->asic_ver == 0x7612) {
70257a8187dShastings fwname = "mtw-mt7662u_rom_patch";
70357a8187dShastings
70457a8187dShastings if ((error = loadfirmware(fwname, &ucode, &size)) != 0) {
70557a8187dShastings printf("%s: failed loadfirmware of file %s (error %d)\n",
70657a8187dShastings sc->sc_dev.dv_xname, fwname, error);
70757a8187dShastings return error;
70857a8187dShastings }
70957a8187dShastings fw = (const struct mtw_ucode *) ucode + 0x1e;
71057a8187dShastings ilen = size - 0x1e;
71157a8187dShastings
71257a8187dShastings mtw_ucode_setup(sc);
71357a8187dShastings
71457a8187dShastings if ((error = mtw_ucode_write(sc, fw->data, ilen, 0x90000)) != 0)
71557a8187dShastings goto fail;
71657a8187dShastings
71757a8187dShastings mtw_usb_dma_write(sc, 0x00e41814);
71857a8187dShastings free(ucode, M_DEVBUF, size);
71957a8187dShastings }
72057a8187dShastings
72157a8187dShastings fwname = "mtw-mt7601u";
72257a8187dShastings iofs = 0x40;
72357a8187dShastings dofs = 0;
72457a8187dShastings if (sc->asic_ver == 0x7612) {
72557a8187dShastings fwname = "mtw-mt7662u";
72657a8187dShastings iofs = 0x80040;
72757a8187dShastings dofs = 0x110800;
72857a8187dShastings } else if (sc->asic_ver == 0x7610) {
72957a8187dShastings fwname = "mtw-mt7610u";
73057a8187dShastings dofs = 0x80000;
73157a8187dShastings }
73257a8187dShastings
73357a8187dShastings if ((error = loadfirmware(fwname, &ucode, &size)) != 0) {
73457a8187dShastings printf("%s: failed loadfirmware of file %s (error %d)\n",
73557a8187dShastings sc->sc_dev.dv_xname, fwname, error);
73657a8187dShastings return error;
73757a8187dShastings }
73857a8187dShastings
73957a8187dShastings if (size < sizeof(struct mtw_ucode_hdr)) {
74057a8187dShastings printf("%s: firmware header too short\n",
74157a8187dShastings sc->sc_dev.dv_xname);
74257a8187dShastings goto fail;
74357a8187dShastings }
74457a8187dShastings
74557a8187dShastings fw = (const struct mtw_ucode *) ucode;
74657a8187dShastings hdr = (const struct mtw_ucode_hdr *) &fw->hdr;
74757a8187dShastings
74857a8187dShastings if (size < sizeof(struct mtw_ucode_hdr) + letoh32(hdr->ilm_len) +
74957a8187dShastings letoh32(hdr->dlm_len)) {
75057a8187dShastings printf("%s: firmware payload too short\n",
75157a8187dShastings sc->sc_dev.dv_xname);
75257a8187dShastings goto fail;
75357a8187dShastings }
75457a8187dShastings
75557a8187dShastings ilen = le32toh(hdr->ilm_len) - MTW_MCU_IVB_LEN;
75657a8187dShastings dlen = le32toh(hdr->dlm_len);
75757a8187dShastings
75857a8187dShastings if (ilen > size || dlen > size) {
75957a8187dShastings printf("%s: firmware payload too large\n",
76057a8187dShastings sc->sc_dev.dv_xname);
76157a8187dShastings goto fail;
76257a8187dShastings }
76357a8187dShastings
76457a8187dShastings mtw_write(sc, MTW_FCE_PDMA, 0);
76557a8187dShastings mtw_write(sc, MTW_FCE_PSE_CTRL, 0);
76657a8187dShastings mtw_ucode_setup(sc);
76757a8187dShastings
76857a8187dShastings if ((error = mtw_ucode_write(sc, fw->data, ilen, iofs)) != 0)
76957a8187dShastings goto fail;
77057a8187dShastings if (dlen > 0 && dofs > 0) {
77157a8187dShastings if ((error = mtw_ucode_write(sc, fw->data + ilen,
77257a8187dShastings dlen, dofs)) != 0)
77357a8187dShastings goto fail;
77457a8187dShastings }
77557a8187dShastings
77657a8187dShastings /* write interrupt vectors */
77757a8187dShastings if (sc->asic_ver == 0x7612) {
77857a8187dShastings /* MT7612 */
77957a8187dShastings if ((error = mtw_ucode_write(sc, fw->ivb,
78057a8187dShastings MTW_MCU_IVB_LEN, 0x80000)) != 0)
78157a8187dShastings goto fail;
78257a8187dShastings mtw_write_cfg(sc, MTW_MCU_DMA_ADDR, 0x00095000);
78357a8187dShastings mtw_write_ivb(sc, NULL, 0);
78457a8187dShastings } else {
78557a8187dShastings /* MT7601/MT7610 */
78657a8187dShastings if ((error = mtw_write_ivb(sc, fw->ivb,
78757a8187dShastings MTW_MCU_IVB_LEN)) != 0)
78857a8187dShastings goto fail;
78957a8187dShastings }
79057a8187dShastings
79157a8187dShastings /* wait until microcontroller is ready */
79257a8187dShastings usbd_delay_ms(sc->sc_udev, 10);
79357a8187dShastings
79457a8187dShastings for (ntries = 0; ntries < 100; ntries++) {
79557a8187dShastings if ((error = mtw_read_cfg(sc, MTW_MCU_DMA_ADDR, &tmp)) != 0)
79657a8187dShastings return error;
79757a8187dShastings if (tmp & MTW_MCU_READY)
79857a8187dShastings break;
79957a8187dShastings usbd_delay_ms(sc->sc_udev, 100);
80057a8187dShastings }
80157a8187dShastings
80257a8187dShastings if (ntries == 100) {
80357a8187dShastings printf("%s: timeout waiting for MCU to initialize\n",
80457a8187dShastings sc->sc_dev.dv_xname);
80557a8187dShastings error = ETIMEDOUT;
80657a8187dShastings }
80757a8187dShastings
80857a8187dShastings DPRINTF(("%s: loaded firmware ver %d.%d\n", sc->sc_dev.dv_xname,
80957a8187dShastings le16toh(hdr->build_ver), le16toh(hdr->fw_ver)));
81057a8187dShastings fail:
81157a8187dShastings free(ucode, M_DEVBUF, size);
81257a8187dShastings usbd_close_pipe(sc->txq[MTW_TXQ_MCU].pipeh);
81357a8187dShastings sc->txq[MTW_TXQ_MCU].pipeh = NULL;
81457a8187dShastings return error;
81557a8187dShastings }
81657a8187dShastings
81757a8187dShastings int
mtw_reset(struct mtw_softc * sc)81857a8187dShastings mtw_reset(struct mtw_softc *sc)
81957a8187dShastings {
82057a8187dShastings usb_device_request_t req;
82157a8187dShastings
82257a8187dShastings req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
82357a8187dShastings req.bRequest = MTW_RESET;
82457a8187dShastings USETW(req.wValue, 1);
82557a8187dShastings USETW(req.wIndex, 0);
82657a8187dShastings USETW(req.wLength, 0);
82757a8187dShastings return usbd_do_request(sc->sc_udev, &req, NULL);
82857a8187dShastings }
82957a8187dShastings
83057a8187dShastings int
mtw_read(struct mtw_softc * sc,uint16_t reg,uint32_t * val)83157a8187dShastings mtw_read(struct mtw_softc *sc, uint16_t reg, uint32_t *val)
83257a8187dShastings {
83357a8187dShastings uint32_t tmp;
83457a8187dShastings int error;
83557a8187dShastings
83657a8187dShastings error = mtw_read_region_1(sc, reg,
83757a8187dShastings (uint8_t *)&tmp, sizeof tmp);
83857a8187dShastings if (error == 0)
83957a8187dShastings *val = letoh32(tmp);
84057a8187dShastings else
84157a8187dShastings *val = 0xffffffff;
84257a8187dShastings return error;
84357a8187dShastings }
84457a8187dShastings
84557a8187dShastings int
mtw_read_cfg(struct mtw_softc * sc,uint16_t reg,uint32_t * val)84657a8187dShastings mtw_read_cfg(struct mtw_softc *sc, uint16_t reg, uint32_t *val)
84757a8187dShastings {
84857a8187dShastings usb_device_request_t req;
84957a8187dShastings uint32_t tmp;
85057a8187dShastings int error;
85157a8187dShastings
85257a8187dShastings req.bmRequestType = UT_READ_VENDOR_DEVICE;
85357a8187dShastings req.bRequest = MTW_READ_CFG;
85457a8187dShastings USETW(req.wValue, 0);
85557a8187dShastings USETW(req.wIndex, reg);
85657a8187dShastings USETW(req.wLength, 4);
85757a8187dShastings error = usbd_do_request(sc->sc_udev, &req, &tmp);
85857a8187dShastings
85957a8187dShastings if (error == 0)
86057a8187dShastings *val = letoh32(tmp);
86157a8187dShastings else
86257a8187dShastings *val = 0xffffffff;
86357a8187dShastings return error;
86457a8187dShastings }
86557a8187dShastings
86657a8187dShastings int
mtw_read_region_1(struct mtw_softc * sc,uint16_t reg,uint8_t * buf,int len)86757a8187dShastings mtw_read_region_1(struct mtw_softc *sc, uint16_t reg,
86857a8187dShastings uint8_t *buf, int len)
86957a8187dShastings {
87057a8187dShastings usb_device_request_t req;
87157a8187dShastings
87257a8187dShastings req.bmRequestType = UT_READ_VENDOR_DEVICE;
87357a8187dShastings req.bRequest = MTW_READ_REGION_1;
87457a8187dShastings USETW(req.wValue, 0);
87557a8187dShastings USETW(req.wIndex, reg);
87657a8187dShastings USETW(req.wLength, len);
87757a8187dShastings return usbd_do_request(sc->sc_udev, &req, buf);
87857a8187dShastings }
87957a8187dShastings
88057a8187dShastings int
mtw_write_2(struct mtw_softc * sc,uint16_t reg,uint16_t val)88157a8187dShastings mtw_write_2(struct mtw_softc *sc, uint16_t reg, uint16_t val)
88257a8187dShastings {
88357a8187dShastings usb_device_request_t req;
88457a8187dShastings
88557a8187dShastings req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
88657a8187dShastings req.bRequest = MTW_WRITE_2;
88757a8187dShastings USETW(req.wValue, val);
88857a8187dShastings USETW(req.wIndex, reg);
88957a8187dShastings USETW(req.wLength, 0);
89057a8187dShastings return usbd_do_request(sc->sc_udev, &req, NULL);
89157a8187dShastings }
89257a8187dShastings
89357a8187dShastings int
mtw_write(struct mtw_softc * sc,uint16_t reg,uint32_t val)89457a8187dShastings mtw_write(struct mtw_softc *sc, uint16_t reg, uint32_t val)
89557a8187dShastings {
89657a8187dShastings int error;
89757a8187dShastings
89857a8187dShastings if ((error = mtw_write_2(sc, reg, val & 0xffff)) == 0)
89957a8187dShastings error = mtw_write_2(sc, reg + 2, val >> 16);
90057a8187dShastings return error;
90157a8187dShastings }
90257a8187dShastings
90357a8187dShastings int
mtw_write_cfg(struct mtw_softc * sc,uint16_t reg,uint32_t val)90457a8187dShastings mtw_write_cfg(struct mtw_softc *sc, uint16_t reg, uint32_t val)
90557a8187dShastings {
90657a8187dShastings usb_device_request_t req;
90757a8187dShastings int error;
90857a8187dShastings
90957a8187dShastings req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
91057a8187dShastings req.bRequest = MTW_WRITE_CFG;
91157a8187dShastings USETW(req.wValue, 0);
91257a8187dShastings USETW(req.wIndex, reg);
91357a8187dShastings USETW(req.wLength, 4);
9140fa2bdbcShastings val = htole32(val);
91557a8187dShastings error = usbd_do_request(sc->sc_udev, &req, &val);
91657a8187dShastings return error;
91757a8187dShastings }
91857a8187dShastings
91957a8187dShastings int
mtw_write_ivb(struct mtw_softc * sc,const uint8_t * buf,uint16_t len)92057a8187dShastings mtw_write_ivb(struct mtw_softc *sc, const uint8_t *buf, uint16_t len)
92157a8187dShastings {
92257a8187dShastings usb_device_request_t req;
92357a8187dShastings
92457a8187dShastings req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
92557a8187dShastings req.bRequest = MTW_RESET;
92657a8187dShastings USETW(req.wValue, 0x12);
92757a8187dShastings USETW(req.wIndex, 0);
92857a8187dShastings USETW(req.wLength, len);
92957a8187dShastings return usbd_do_request(sc->sc_udev, &req, (void *)buf);
93057a8187dShastings }
93157a8187dShastings
93257a8187dShastings int
mtw_write_region_1(struct mtw_softc * sc,uint16_t reg,uint8_t * buf,int len)93357a8187dShastings mtw_write_region_1(struct mtw_softc *sc, uint16_t reg,
93457a8187dShastings uint8_t *buf, int len)
93557a8187dShastings {
93657a8187dShastings usb_device_request_t req;
93757a8187dShastings
93857a8187dShastings req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
93957a8187dShastings req.bRequest = MTW_WRITE_REGION_1;
94057a8187dShastings USETW(req.wValue, 0);
94157a8187dShastings USETW(req.wIndex, reg);
94257a8187dShastings USETW(req.wLength, len);
94357a8187dShastings return usbd_do_request(sc->sc_udev, &req, buf);
94457a8187dShastings }
94557a8187dShastings
94657a8187dShastings int
mtw_set_region_4(struct mtw_softc * sc,uint16_t reg,uint32_t val,int count)94757a8187dShastings mtw_set_region_4(struct mtw_softc *sc, uint16_t reg, uint32_t val, int count)
94857a8187dShastings {
94957a8187dShastings int error = 0;
95057a8187dShastings
95157a8187dShastings for (; count > 0 && error == 0; count--, reg += 4)
95257a8187dShastings error = mtw_write(sc, reg, val);
95357a8187dShastings return error;
95457a8187dShastings }
95557a8187dShastings
95657a8187dShastings /* Read 16-bit from eFUSE ROM. */
95757a8187dShastings int
mtw_efuse_read_2(struct mtw_softc * sc,uint16_t addr,uint16_t * val)95857a8187dShastings mtw_efuse_read_2(struct mtw_softc *sc, uint16_t addr, uint16_t *val)
95957a8187dShastings {
96057a8187dShastings uint32_t tmp;
96157a8187dShastings uint16_t reg;
96257a8187dShastings int error, ntries;
96357a8187dShastings
96457a8187dShastings if ((error = mtw_read(sc, MTW_EFUSE_CTRL, &tmp)) != 0)
96557a8187dShastings return error;
96657a8187dShastings
96757a8187dShastings addr *= 2;
96857a8187dShastings /*
96957a8187dShastings * Read one 16-byte block into registers EFUSE_DATA[0-3]:
97057a8187dShastings * DATA0: 3 2 1 0
97157a8187dShastings * DATA1: 7 6 5 4
97257a8187dShastings * DATA2: B A 9 8
97357a8187dShastings * DATA3: F E D C
97457a8187dShastings */
97557a8187dShastings tmp &= ~(MTW_EFSROM_MODE_MASK | MTW_EFSROM_AIN_MASK);
97657a8187dShastings tmp |= (addr & ~0xf) << MTW_EFSROM_AIN_SHIFT | MTW_EFSROM_KICK;
97757a8187dShastings mtw_write(sc, MTW_EFUSE_CTRL, tmp);
97857a8187dShastings for (ntries = 0; ntries < 100; ntries++) {
97957a8187dShastings if ((error = mtw_read(sc, MTW_EFUSE_CTRL, &tmp)) != 0)
98057a8187dShastings return error;
98157a8187dShastings if (!(tmp & MTW_EFSROM_KICK))
98257a8187dShastings break;
98357a8187dShastings DELAY(2);
98457a8187dShastings }
98557a8187dShastings if (ntries == 100)
98657a8187dShastings return ETIMEDOUT;
98757a8187dShastings
98857a8187dShastings if ((tmp & MTW_EFUSE_AOUT_MASK) == MTW_EFUSE_AOUT_MASK) {
98957a8187dShastings *val = 0xffff; /* address not found */
99057a8187dShastings return 0;
99157a8187dShastings }
99257a8187dShastings /* determine to which 32-bit register our 16-bit word belongs */
99357a8187dShastings reg = MTW_EFUSE_DATA0 + (addr & 0xc);
99457a8187dShastings if ((error = mtw_read(sc, reg, &tmp)) != 0)
99557a8187dShastings return error;
99657a8187dShastings
99757a8187dShastings *val = (addr & 2) ? tmp >> 16 : tmp & 0xffff;
99857a8187dShastings return 0;
99957a8187dShastings }
100057a8187dShastings
100157a8187dShastings int
mtw_eeprom_read_2(struct mtw_softc * sc,uint16_t addr,uint16_t * val)100257a8187dShastings mtw_eeprom_read_2(struct mtw_softc *sc, uint16_t addr, uint16_t *val)
100357a8187dShastings {
100457a8187dShastings usb_device_request_t req;
100557a8187dShastings uint16_t tmp;
100657a8187dShastings int error;
100757a8187dShastings
100857a8187dShastings addr *= 2;
100957a8187dShastings req.bmRequestType = UT_READ_VENDOR_DEVICE;
101057a8187dShastings req.bRequest = MTW_EEPROM_READ;
101157a8187dShastings USETW(req.wValue, 0);
101257a8187dShastings USETW(req.wIndex, addr);
101357a8187dShastings USETW(req.wLength, sizeof tmp);
101457a8187dShastings error = usbd_do_request(sc->sc_udev, &req, &tmp);
101557a8187dShastings if (error == 0)
101657a8187dShastings *val = letoh16(tmp);
101757a8187dShastings else
101857a8187dShastings *val = 0xffff;
101957a8187dShastings return error;
102057a8187dShastings }
102157a8187dShastings
102257a8187dShastings static __inline int
mtw_srom_read(struct mtw_softc * sc,uint16_t addr,uint16_t * val)102357a8187dShastings mtw_srom_read(struct mtw_softc *sc, uint16_t addr, uint16_t *val)
102457a8187dShastings {
102557a8187dShastings /* either eFUSE ROM or EEPROM */
102657a8187dShastings return sc->sc_srom_read(sc, addr, val);
102757a8187dShastings }
102857a8187dShastings
102957a8187dShastings int
mtw_rf_read(struct mtw_softc * sc,uint8_t bank,uint8_t reg,uint8_t * val)103057a8187dShastings mtw_rf_read(struct mtw_softc *sc, uint8_t bank, uint8_t reg, uint8_t *val)
103157a8187dShastings {
103257a8187dShastings uint32_t tmp;
103357a8187dShastings int error, ntries, shift;
103457a8187dShastings
103557a8187dShastings for (ntries = 0; ntries < 100; ntries++) {
103657a8187dShastings if ((error = mtw_read(sc, MTW_RF_CSR, &tmp)) != 0)
103757a8187dShastings return error;
103857a8187dShastings if (!(tmp & MTW_RF_CSR_KICK))
103957a8187dShastings break;
104057a8187dShastings }
104157a8187dShastings if (ntries == 100)
104257a8187dShastings return ETIMEDOUT;
104357a8187dShastings
104457a8187dShastings if (sc->mac_ver == 0x7601)
104557a8187dShastings shift = MT7601_BANK_SHIFT;
104657a8187dShastings else
104757a8187dShastings shift = MT7610_BANK_SHIFT;
104857a8187dShastings
104957a8187dShastings tmp = MTW_RF_CSR_KICK | (bank & 0xf) << shift | reg << 8;
105057a8187dShastings if ((error = mtw_write(sc, MTW_RF_CSR, tmp)) != 0)
105157a8187dShastings return error;
105257a8187dShastings
105357a8187dShastings for (ntries = 0; ntries < 100; ntries++) {
105457a8187dShastings if ((error = mtw_read(sc, MTW_RF_CSR, &tmp)) != 0)
105557a8187dShastings return error;
105657a8187dShastings if (!(tmp & MTW_RF_CSR_KICK))
105757a8187dShastings break;
105857a8187dShastings }
105957a8187dShastings if (ntries == 100)
106057a8187dShastings return ETIMEDOUT;
106157a8187dShastings
106257a8187dShastings *val = tmp & 0xff;
106357a8187dShastings return 0;
106457a8187dShastings }
106557a8187dShastings
106657a8187dShastings int
mtw_rf_write(struct mtw_softc * sc,uint8_t bank,uint8_t reg,uint8_t val)106757a8187dShastings mtw_rf_write(struct mtw_softc *sc, uint8_t bank, uint8_t reg, uint8_t val)
106857a8187dShastings {
106957a8187dShastings uint32_t tmp;
107057a8187dShastings int error, ntries, shift;
107157a8187dShastings
107257a8187dShastings for (ntries = 0; ntries < 10; ntries++) {
107357a8187dShastings if ((error = mtw_read(sc, MTW_RF_CSR, &tmp)) != 0)
107457a8187dShastings return error;
107557a8187dShastings if (!(tmp & MTW_RF_CSR_KICK))
107657a8187dShastings break;
107757a8187dShastings }
107857a8187dShastings if (ntries == 10)
107957a8187dShastings return ETIMEDOUT;
108057a8187dShastings
108157a8187dShastings if (sc->mac_ver == 0x7601)
108257a8187dShastings shift = MT7601_BANK_SHIFT;
108357a8187dShastings else
108457a8187dShastings shift = MT7610_BANK_SHIFT;
108557a8187dShastings
108657a8187dShastings tmp = MTW_RF_CSR_WRITE | MTW_RF_CSR_KICK | (bank & 0xf) << shift |
108757a8187dShastings reg << 8 | val;
108857a8187dShastings return mtw_write(sc, MTW_RF_CSR, tmp);
108957a8187dShastings }
109057a8187dShastings
109157a8187dShastings int
mtw_bbp_read(struct mtw_softc * sc,uint8_t reg,uint8_t * val)109257a8187dShastings mtw_bbp_read(struct mtw_softc *sc, uint8_t reg, uint8_t *val)
109357a8187dShastings {
109457a8187dShastings uint32_t tmp;
109557a8187dShastings int ntries, error;
109657a8187dShastings
109757a8187dShastings for (ntries = 0; ntries < 10; ntries++) {
109857a8187dShastings if ((error = mtw_read(sc, MTW_BBP_CSR, &tmp)) != 0)
109957a8187dShastings return error;
110057a8187dShastings if (!(tmp & MTW_BBP_CSR_KICK))
110157a8187dShastings break;
110257a8187dShastings }
110357a8187dShastings if (ntries == 10)
110457a8187dShastings return ETIMEDOUT;
110557a8187dShastings
110657a8187dShastings tmp = MTW_BBP_CSR_READ | MTW_BBP_CSR_KICK | reg << MTW_BBP_ADDR_SHIFT;
110757a8187dShastings if ((error = mtw_write(sc, MTW_BBP_CSR, tmp)) != 0)
110857a8187dShastings return error;
110957a8187dShastings
111057a8187dShastings for (ntries = 0; ntries < 10; ntries++) {
111157a8187dShastings if ((error = mtw_read(sc, MTW_BBP_CSR, &tmp)) != 0)
111257a8187dShastings return error;
111357a8187dShastings if (!(tmp & MTW_BBP_CSR_KICK))
111457a8187dShastings break;
111557a8187dShastings }
111657a8187dShastings if (ntries == 10)
111757a8187dShastings return ETIMEDOUT;
111857a8187dShastings
111957a8187dShastings *val = tmp & 0xff;
112057a8187dShastings return 0;
112157a8187dShastings }
112257a8187dShastings
112357a8187dShastings int
mtw_bbp_write(struct mtw_softc * sc,uint8_t reg,uint8_t val)112457a8187dShastings mtw_bbp_write(struct mtw_softc *sc, uint8_t reg, uint8_t val)
112557a8187dShastings {
112657a8187dShastings uint32_t tmp;
112757a8187dShastings int ntries, error;
112857a8187dShastings
112957a8187dShastings for (ntries = 0; ntries < 10; ntries++) {
113057a8187dShastings if ((error = mtw_read(sc, MTW_BBP_CSR, &tmp)) != 0)
113157a8187dShastings return error;
113257a8187dShastings if (!(tmp & MTW_BBP_CSR_KICK))
113357a8187dShastings break;
113457a8187dShastings }
113557a8187dShastings if (ntries == 10)
113657a8187dShastings return ETIMEDOUT;
113757a8187dShastings
113857a8187dShastings tmp = MTW_BBP_CSR_KICK | reg << MTW_BBP_ADDR_SHIFT | val;
113957a8187dShastings return mtw_write(sc, MTW_BBP_CSR, tmp);
114057a8187dShastings }
114157a8187dShastings
114257a8187dShastings int
mtw_usb_dma_read(struct mtw_softc * sc,uint32_t * val)114357a8187dShastings mtw_usb_dma_read(struct mtw_softc *sc, uint32_t *val)
114457a8187dShastings {
114557a8187dShastings if (sc->asic_ver == 0x7612)
114657a8187dShastings return mtw_read_cfg(sc, MTW_USB_U3DMA_CFG, val);
114757a8187dShastings else
114857a8187dShastings return mtw_read(sc, MTW_USB_DMA_CFG, val);
114957a8187dShastings }
115057a8187dShastings
115157a8187dShastings int
mtw_usb_dma_write(struct mtw_softc * sc,uint32_t val)115257a8187dShastings mtw_usb_dma_write(struct mtw_softc *sc, uint32_t val)
115357a8187dShastings {
115457a8187dShastings if (sc->asic_ver == 0x7612)
115557a8187dShastings return mtw_write_cfg(sc, MTW_USB_U3DMA_CFG, val);
115657a8187dShastings else
115757a8187dShastings return mtw_write(sc, MTW_USB_DMA_CFG, val);
115857a8187dShastings }
115957a8187dShastings
116057a8187dShastings int
mtw_mcu_calibrate(struct mtw_softc * sc,int func,uint32_t val)116157a8187dShastings mtw_mcu_calibrate(struct mtw_softc *sc, int func, uint32_t val)
116257a8187dShastings {
116357a8187dShastings struct mtw_mcu_cmd_8 cmd;
116457a8187dShastings
116557a8187dShastings cmd.func = htole32(func);
116657a8187dShastings cmd.val = htole32(val);
116757a8187dShastings return mtw_mcu_cmd(sc, 31, &cmd, sizeof(struct mtw_mcu_cmd_8));
116857a8187dShastings }
116957a8187dShastings
117057a8187dShastings int
mtw_mcu_channel(struct mtw_softc * sc,uint32_t r1,uint32_t r2,uint32_t r4)117157a8187dShastings mtw_mcu_channel(struct mtw_softc *sc, uint32_t r1, uint32_t r2, uint32_t r4)
117257a8187dShastings {
117357a8187dShastings struct mtw_mcu_cmd_16 cmd;
117457a8187dShastings
117557a8187dShastings cmd.r1 = htole32(r1);
117657a8187dShastings cmd.r2 = htole32(r2);
117757a8187dShastings cmd.r3 = 0;
117857a8187dShastings cmd.r4 = htole32(r4);
117957a8187dShastings return mtw_mcu_cmd(sc, 30, &cmd, sizeof(struct mtw_mcu_cmd_16));
118057a8187dShastings }
118157a8187dShastings
118257a8187dShastings int
mtw_mcu_radio(struct mtw_softc * sc,int func,uint32_t val)118357a8187dShastings mtw_mcu_radio(struct mtw_softc *sc, int func, uint32_t val)
118457a8187dShastings {
118557a8187dShastings struct mtw_mcu_cmd_16 cmd;
118657a8187dShastings
118757a8187dShastings cmd.r1 = htole32(func);
118857a8187dShastings cmd.r2 = htole32(val);
118957a8187dShastings cmd.r3 = 0;
119057a8187dShastings cmd.r4 = 0;
119157a8187dShastings return mtw_mcu_cmd(sc, 20, &cmd, sizeof(struct mtw_mcu_cmd_16));
119257a8187dShastings }
119357a8187dShastings
119457a8187dShastings int
mtw_mcu_cmd(struct mtw_softc * sc,int cmd,void * buf,int len)119557a8187dShastings mtw_mcu_cmd(struct mtw_softc *sc, int cmd, void *buf, int len)
119657a8187dShastings {
119757a8187dShastings struct mtw_tx_ring *ring = &sc->sc_mcu;
119857a8187dShastings struct mtw_tx_data *data = &ring->data[0];
119957a8187dShastings struct mtw_txd *txd;
120057a8187dShastings int xferlen;
120157a8187dShastings
120257a8187dShastings txd = (struct mtw_txd *)(data->buf);
120357a8187dShastings txd->len = htole16(len);
120457a8187dShastings txd->flags = htole16(MTW_TXD_CMD | MTW_TXD_MCU |
120557a8187dShastings (cmd & 0x1f) << MTW_TXD_CMD_SHIFT | (sc->cmd_seq & 0xf));
120657a8187dShastings
120757a8187dShastings memcpy(&txd[1], buf, len);
120857a8187dShastings memset(&txd[1] + len, 0, MTW_DMA_PAD);
120957a8187dShastings xferlen = len + sizeof(struct mtw_txd) + MTW_DMA_PAD;
121057a8187dShastings
121157a8187dShastings usbd_setup_xfer(data->xfer, sc->txq[MTW_TXQ_MCU].pipeh,
121257a8187dShastings NULL, data->buf, xferlen,
121357a8187dShastings USBD_SHORT_XFER_OK | USBD_FORCE_SHORT_XFER | USBD_SYNCHRONOUS,
121457a8187dShastings MTW_TX_TIMEOUT, NULL);
121557a8187dShastings return usbd_transfer(data->xfer);
121657a8187dShastings }
121757a8187dShastings
121857a8187dShastings /*
121957a8187dShastings * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word.
122057a8187dShastings * Used to adjust per-rate Tx power registers.
122157a8187dShastings */
122257a8187dShastings static __inline uint32_t
b4inc(uint32_t b32,int8_t delta)122357a8187dShastings b4inc(uint32_t b32, int8_t delta)
122457a8187dShastings {
122557a8187dShastings int8_t i, b4;
122657a8187dShastings
122757a8187dShastings for (i = 0; i < 8; i++) {
122857a8187dShastings b4 = b32 & 0xf;
122957a8187dShastings b4 += delta;
123057a8187dShastings if (b4 < 0)
123157a8187dShastings b4 = 0;
123257a8187dShastings else if (b4 > 0xf)
123357a8187dShastings b4 = 0xf;
123457a8187dShastings b32 = b32 >> 4 | b4 << 28;
123557a8187dShastings }
123657a8187dShastings return b32;
123757a8187dShastings }
123857a8187dShastings
123957a8187dShastings const char *
mtw_get_rf(int rev)124057a8187dShastings mtw_get_rf(int rev)
124157a8187dShastings {
124257a8187dShastings switch (rev) {
124357a8187dShastings case MT7601_RF_7601: return "MT7601";
124457a8187dShastings case MT7610_RF_7610: return "MT7610";
124557a8187dShastings case MT7612_RF_7612: return "MT7612";
124657a8187dShastings }
124757a8187dShastings return "unknown";
124857a8187dShastings }
124957a8187dShastings
125057a8187dShastings void
mtw_get_txpower(struct mtw_softc * sc)125157a8187dShastings mtw_get_txpower(struct mtw_softc *sc)
125257a8187dShastings {
125357a8187dShastings uint16_t val;
125457a8187dShastings int i;
125557a8187dShastings
125657a8187dShastings /* Read power settings for 2GHz channels. */
125757a8187dShastings for (i = 0; i < 14; i += 2) {
125857a8187dShastings mtw_srom_read(sc, MTW_EEPROM_PWR2GHZ_BASE1 + i / 2, &val);
125957a8187dShastings sc->txpow1[i + 0] = (int8_t)(val & 0xff);
126057a8187dShastings sc->txpow1[i + 1] = (int8_t)(val >> 8);
126157a8187dShastings mtw_srom_read(sc, MTW_EEPROM_PWR2GHZ_BASE2 + i / 2, &val);
126257a8187dShastings sc->txpow2[i + 0] = (int8_t)(val & 0xff);
126357a8187dShastings sc->txpow2[i + 1] = (int8_t)(val >> 8);
126457a8187dShastings }
126557a8187dShastings /* Fix broken Tx power entries. */
126657a8187dShastings for (i = 0; i < 14; i++) {
126757a8187dShastings if (sc->txpow1[i] < 0 || sc->txpow1[i] > 27)
126857a8187dShastings sc->txpow1[i] = 5;
126957a8187dShastings if (sc->txpow2[i] < 0 || sc->txpow2[i] > 27)
127057a8187dShastings sc->txpow2[i] = 5;
127157a8187dShastings DPRINTF(("chan %d: power1=%d, power2=%d\n",
127257a8187dShastings mt7601_rf_chan[i].chan, sc->txpow1[i], sc->txpow2[i]));
127357a8187dShastings }
127457a8187dShastings #if 0
127557a8187dShastings /* Read power settings for 5GHz channels. */
127657a8187dShastings for (i = 0; i < 40; i += 2) {
127757a8187dShastings mtw_srom_read(sc, MTW_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
127857a8187dShastings sc->txpow1[i + 14] = (int8_t)(val & 0xff);
127957a8187dShastings sc->txpow1[i + 15] = (int8_t)(val >> 8);
128057a8187dShastings
128157a8187dShastings mtw_srom_read(sc, MTW_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
128257a8187dShastings sc->txpow2[i + 14] = (int8_t)(val & 0xff);
128357a8187dShastings sc->txpow2[i + 15] = (int8_t)(val >> 8);
128457a8187dShastings }
128557a8187dShastings /* Fix broken Tx power entries. */
128657a8187dShastings for (i = 0; i < 40; i++ ) {
128757a8187dShastings if (sc->mac_ver != 0x5592) {
128857a8187dShastings if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15)
128957a8187dShastings sc->txpow1[14 + i] = 5;
129057a8187dShastings if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15)
129157a8187dShastings sc->txpow2[14 + i] = 5;
129257a8187dShastings }
129357a8187dShastings DPRINTF(("chan %d: power1=%d, power2=%d\n",
129457a8187dShastings mt7601_rf_chan[14 + i].chan, sc->txpow1[14 + i],
129557a8187dShastings sc->txpow2[14 + i]));
129657a8187dShastings }
129757a8187dShastings #endif
129857a8187dShastings }
129957a8187dShastings
130057a8187dShastings int
mtw_read_eeprom(struct mtw_softc * sc)130157a8187dShastings mtw_read_eeprom(struct mtw_softc *sc)
130257a8187dShastings {
130357a8187dShastings struct ieee80211com *ic = &sc->sc_ic;
130457a8187dShastings int8_t delta_2ghz, delta_5ghz;
130557a8187dShastings uint16_t val;
130657a8187dShastings int ridx, ant;
130757a8187dShastings
130857a8187dShastings sc->sc_srom_read = mtw_efuse_read_2;
130957a8187dShastings
131057a8187dShastings /* read RF information */
131157a8187dShastings mtw_srom_read(sc, MTW_EEPROM_CHIPID, &val);
131257a8187dShastings sc->rf_rev = val;
131357a8187dShastings mtw_srom_read(sc, MTW_EEPROM_ANTENNA, &val);
131457a8187dShastings sc->ntxchains = (val >> 4) & 0xf;
131557a8187dShastings sc->nrxchains = val & 0xf;
131657a8187dShastings DPRINTF(("EEPROM RF rev=0x%02x chains=%dT%dR\n",
131757a8187dShastings sc->rf_rev, sc->ntxchains, sc->nrxchains));
131857a8187dShastings
131957a8187dShastings /* read ROM version */
132057a8187dShastings mtw_srom_read(sc, MTW_EEPROM_VERSION, &val);
132157a8187dShastings DPRINTF(("EEPROM rev=%d, FAE=%d\n", val & 0xff, val >> 8));
132257a8187dShastings
132357a8187dShastings /* read MAC address */
132457a8187dShastings mtw_srom_read(sc, MTW_EEPROM_MAC01, &val);
132557a8187dShastings ic->ic_myaddr[0] = val & 0xff;
132657a8187dShastings ic->ic_myaddr[1] = val >> 8;
132757a8187dShastings mtw_srom_read(sc, MTW_EEPROM_MAC23, &val);
132857a8187dShastings ic->ic_myaddr[2] = val & 0xff;
132957a8187dShastings ic->ic_myaddr[3] = val >> 8;
133057a8187dShastings mtw_srom_read(sc, MTW_EEPROM_MAC45, &val);
133157a8187dShastings ic->ic_myaddr[4] = val & 0xff;
133257a8187dShastings ic->ic_myaddr[5] = val >> 8;
133357a8187dShastings #if 0
133457a8187dShastings printf("eFUSE ROM\n00: ");
133557a8187dShastings for (int i = 0; i < 256; i++) {
133657a8187dShastings if (((i % 8) == 0) && i > 0)
133757a8187dShastings printf("\n%02x: ", i);
133857a8187dShastings mtw_srom_read(sc, i, &val);
133957a8187dShastings printf(" %04x", val);
134057a8187dShastings }
134157a8187dShastings printf("\n");
134257a8187dShastings #endif
134357a8187dShastings /* check if RF supports automatic Tx access gain control */
134457a8187dShastings mtw_srom_read(sc, MTW_EEPROM_CONFIG, &val);
134557a8187dShastings DPRINTF(("EEPROM CFG 0x%04x\n", val));
134657a8187dShastings if ((val & 0xff) != 0xff) {
134757a8187dShastings sc->ext_5ghz_lna = (val >> 3) & 1;
134857a8187dShastings sc->ext_2ghz_lna = (val >> 2) & 1;
134957a8187dShastings /* check if RF supports automatic Tx access gain control */
135057a8187dShastings sc->calib_2ghz = sc->calib_5ghz = (val >> 1) & 1;
135157a8187dShastings /* check if we have a hardware radio switch */
135257a8187dShastings sc->rfswitch = val & 1;
135357a8187dShastings }
135457a8187dShastings
135557a8187dShastings /* read RF frequency offset from EEPROM */
135657a8187dShastings mtw_srom_read(sc, MTW_EEPROM_FREQ_OFFSET, &val);
135757a8187dShastings if ((val & 0xff) != 0xff)
135857a8187dShastings sc->rf_freq_offset = val;
135957a8187dShastings else
136057a8187dShastings sc->rf_freq_offset = 0;
136157a8187dShastings DPRINTF(("frequency offset 0x%x\n", sc->rf_freq_offset));
136257a8187dShastings
136357a8187dShastings /* Read Tx power settings. */
136457a8187dShastings mtw_get_txpower(sc);
136557a8187dShastings
136657a8187dShastings /* read Tx power compensation for each Tx rate */
136757a8187dShastings mtw_srom_read(sc, MTW_EEPROM_DELTAPWR, &val);
136857a8187dShastings delta_2ghz = delta_5ghz = 0;
136957a8187dShastings if ((val & 0xff) != 0xff && (val & 0x80)) {
137057a8187dShastings delta_2ghz = val & 0xf;
137157a8187dShastings if (!(val & 0x40)) /* negative number */
137257a8187dShastings delta_2ghz = -delta_2ghz;
137357a8187dShastings }
137457a8187dShastings val >>= 8;
137557a8187dShastings if ((val & 0xff) != 0xff && (val & 0x80)) {
137657a8187dShastings delta_5ghz = val & 0xf;
137757a8187dShastings if (!(val & 0x40)) /* negative number */
137857a8187dShastings delta_5ghz = -delta_5ghz;
137957a8187dShastings }
138057a8187dShastings DPRINTF(("power compensation=%d (2GHz), %d (5GHz)\n",
138157a8187dShastings delta_2ghz, delta_5ghz));
138257a8187dShastings
138357a8187dShastings for (ridx = 0; ridx < 5; ridx++) {
138457a8187dShastings uint32_t reg;
138557a8187dShastings
138657a8187dShastings mtw_srom_read(sc, MTW_EEPROM_RPWR + ridx * 2, &val);
138757a8187dShastings reg = val;
138857a8187dShastings mtw_srom_read(sc, MTW_EEPROM_RPWR + ridx * 2 + 1, &val);
138957a8187dShastings reg |= (uint32_t)val << 16;
139057a8187dShastings
139157a8187dShastings sc->txpow20mhz[ridx] = reg;
139257a8187dShastings sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz);
139357a8187dShastings sc->txpow40mhz_5ghz[ridx] = b4inc(reg, delta_5ghz);
139457a8187dShastings
139557a8187dShastings DPRINTF(("ridx %d: power 20MHz=0x%08x, 40MHz/2GHz=0x%08x, "
139657a8187dShastings "40MHz/5GHz=0x%08x\n", ridx, sc->txpow20mhz[ridx],
139757a8187dShastings sc->txpow40mhz_2ghz[ridx], sc->txpow40mhz_5ghz[ridx]));
139857a8187dShastings }
139957a8187dShastings
140057a8187dShastings /* read RSSI offsets and LNA gains from EEPROM */
140157a8187dShastings val = 0;
140257a8187dShastings mtw_srom_read(sc, MTW_EEPROM_RSSI1_2GHZ, &val);
140357a8187dShastings sc->rssi_2ghz[0] = val & 0xff; /* Ant A */
140457a8187dShastings sc->rssi_2ghz[1] = val >> 8; /* Ant B */
140557a8187dShastings mtw_srom_read(sc, MTW_EEPROM_RSSI2_2GHZ, &val);
140657a8187dShastings /*
140757a8187dShastings * On RT3070 chips (limited to 2 Rx chains), this ROM
140857a8187dShastings * field contains the Tx mixer gain for the 2GHz band.
140957a8187dShastings */
141057a8187dShastings if ((val & 0xff) != 0xff)
141157a8187dShastings sc->txmixgain_2ghz = val & 0x7;
141257a8187dShastings DPRINTF(("tx mixer gain=%u (2GHz)\n", sc->txmixgain_2ghz));
141357a8187dShastings sc->lna[2] = val >> 8; /* channel group 2 */
141457a8187dShastings mtw_srom_read(sc, MTW_EEPROM_RSSI1_5GHZ, &val);
141557a8187dShastings sc->rssi_5ghz[0] = val & 0xff; /* Ant A */
141657a8187dShastings sc->rssi_5ghz[1] = val >> 8; /* Ant B */
141757a8187dShastings mtw_srom_read(sc, MTW_EEPROM_RSSI2_5GHZ, &val);
141857a8187dShastings sc->rssi_5ghz[2] = val & 0xff; /* Ant C */
141957a8187dShastings
142057a8187dShastings sc->lna[3] = val >> 8; /* channel group 3 */
142157a8187dShastings
142257a8187dShastings mtw_srom_read(sc, MTW_EEPROM_LNA, &val);
142357a8187dShastings sc->lna[0] = val & 0xff; /* channel group 0 */
142457a8187dShastings sc->lna[1] = val >> 8; /* channel group 1 */
142557a8187dShastings DPRINTF(("LNA0 0x%x\n", sc->lna[0]));
142657a8187dShastings
142757a8187dShastings /* fix broken 5GHz LNA entries */
142857a8187dShastings if (sc->lna[2] == 0 || sc->lna[2] == 0xff) {
142957a8187dShastings DPRINTF(("invalid LNA for channel group %d\n", 2));
143057a8187dShastings sc->lna[2] = sc->lna[1];
143157a8187dShastings }
143257a8187dShastings if (sc->lna[3] == 0 || sc->lna[3] == 0xff) {
143357a8187dShastings DPRINTF(("invalid LNA for channel group %d\n", 3));
143457a8187dShastings sc->lna[3] = sc->lna[1];
143557a8187dShastings }
143657a8187dShastings
143757a8187dShastings /* fix broken RSSI offset entries */
143857a8187dShastings for (ant = 0; ant < 3; ant++) {
143957a8187dShastings if (sc->rssi_2ghz[ant] < -10 || sc->rssi_2ghz[ant] > 10) {
144057a8187dShastings DPRINTF(("invalid RSSI%d offset: %d (2GHz)\n",
144157a8187dShastings ant + 1, sc->rssi_2ghz[ant]));
144257a8187dShastings sc->rssi_2ghz[ant] = 0;
144357a8187dShastings }
144457a8187dShastings if (sc->rssi_5ghz[ant] < -10 || sc->rssi_5ghz[ant] > 10) {
144557a8187dShastings DPRINTF(("invalid RSSI%d offset: %d (5GHz)\n",
144657a8187dShastings ant + 1, sc->rssi_5ghz[ant]));
144757a8187dShastings sc->rssi_5ghz[ant] = 0;
144857a8187dShastings }
144957a8187dShastings }
145057a8187dShastings return 0;
145157a8187dShastings }
145257a8187dShastings
145357a8187dShastings struct ieee80211_node *
mtw_node_alloc(struct ieee80211com * ic)145457a8187dShastings mtw_node_alloc(struct ieee80211com *ic)
145557a8187dShastings {
145657a8187dShastings struct mtw_node *mn;
145757a8187dShastings
145857a8187dShastings mn = malloc(sizeof (struct mtw_node), M_USBDEV, M_NOWAIT | M_ZERO);
145957a8187dShastings return (struct ieee80211_node *)mn;
146057a8187dShastings }
146157a8187dShastings
146257a8187dShastings int
mtw_media_change(struct ifnet * ifp)146357a8187dShastings mtw_media_change(struct ifnet *ifp)
146457a8187dShastings {
146557a8187dShastings struct mtw_softc *sc = ifp->if_softc;
146657a8187dShastings struct ieee80211com *ic = &sc->sc_ic;
146757a8187dShastings uint8_t rate, ridx;
146857a8187dShastings int error;
146957a8187dShastings
147057a8187dShastings error = ieee80211_media_change(ifp);
147157a8187dShastings if (error != ENETRESET)
147257a8187dShastings return error;
147357a8187dShastings
147457a8187dShastings if (ic->ic_fixed_rate != -1) {
147557a8187dShastings rate = ic->ic_sup_rates[ic->ic_curmode].
147657a8187dShastings rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
147757a8187dShastings for (ridx = 0; ridx <= MTW_RIDX_MAX; ridx++)
147857a8187dShastings if (rt2860_rates[ridx].rate == rate)
147957a8187dShastings break;
148057a8187dShastings sc->fixed_ridx = ridx;
148157a8187dShastings }
148257a8187dShastings
148357a8187dShastings if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
148457a8187dShastings (IFF_UP | IFF_RUNNING)) {
148557a8187dShastings mtw_stop(ifp, 0);
148657a8187dShastings error = mtw_init(ifp);
148757a8187dShastings }
148857a8187dShastings return error;
148957a8187dShastings }
149057a8187dShastings
149157a8187dShastings void
mtw_next_scan(void * arg)149257a8187dShastings mtw_next_scan(void *arg)
149357a8187dShastings {
149457a8187dShastings struct mtw_softc *sc = arg;
149557a8187dShastings int s;
149657a8187dShastings
149757a8187dShastings if (usbd_is_dying(sc->sc_udev))
149857a8187dShastings return;
149957a8187dShastings
150057a8187dShastings usbd_ref_incr(sc->sc_udev);
150157a8187dShastings
150257a8187dShastings s = splnet();
150357a8187dShastings if (sc->sc_ic.ic_state == IEEE80211_S_SCAN)
150457a8187dShastings ieee80211_next_scan(&sc->sc_ic.ic_if);
150557a8187dShastings splx(s);
150657a8187dShastings
150757a8187dShastings usbd_ref_decr(sc->sc_udev);
150857a8187dShastings }
150957a8187dShastings
151057a8187dShastings void
mtw_task(void * arg)151157a8187dShastings mtw_task(void *arg)
151257a8187dShastings {
151357a8187dShastings struct mtw_softc *sc = arg;
151457a8187dShastings struct mtw_host_cmd_ring *ring = &sc->cmdq;
151557a8187dShastings struct mtw_host_cmd *cmd;
151657a8187dShastings int s;
151757a8187dShastings
151857a8187dShastings if (usbd_is_dying(sc->sc_udev))
151957a8187dShastings return;
152057a8187dShastings
152157a8187dShastings /* process host commands */
152257a8187dShastings s = splusb();
152357a8187dShastings while (ring->next != ring->cur) {
152457a8187dShastings cmd = &ring->cmd[ring->next];
152557a8187dShastings splx(s);
152657a8187dShastings /* callback */
152757a8187dShastings cmd->cb(sc, cmd->data);
152857a8187dShastings s = splusb();
152957a8187dShastings ring->queued--;
153057a8187dShastings ring->next = (ring->next + 1) % MTW_HOST_CMD_RING_COUNT;
153157a8187dShastings }
153257a8187dShastings splx(s);
153357a8187dShastings }
153457a8187dShastings
153557a8187dShastings void
mtw_do_async(struct mtw_softc * sc,void (* cb)(struct mtw_softc *,void *),void * arg,int len)153657a8187dShastings mtw_do_async(struct mtw_softc *sc, void (*cb)(struct mtw_softc *, void *),
153757a8187dShastings void *arg, int len)
153857a8187dShastings {
153957a8187dShastings struct mtw_host_cmd_ring *ring = &sc->cmdq;
154057a8187dShastings struct mtw_host_cmd *cmd;
154157a8187dShastings int s;
154257a8187dShastings
154357a8187dShastings if (usbd_is_dying(sc->sc_udev))
154457a8187dShastings return;
154557a8187dShastings
154657a8187dShastings s = splusb();
154757a8187dShastings cmd = &ring->cmd[ring->cur];
154857a8187dShastings cmd->cb = cb;
154957a8187dShastings KASSERT(len <= sizeof (cmd->data));
155057a8187dShastings memcpy(cmd->data, arg, len);
155157a8187dShastings ring->cur = (ring->cur + 1) % MTW_HOST_CMD_RING_COUNT;
155257a8187dShastings
155357a8187dShastings /* if there is no pending command already, schedule a task */
155457a8187dShastings if (++ring->queued == 1)
155557a8187dShastings usb_add_task(sc->sc_udev, &sc->sc_task);
155657a8187dShastings splx(s);
155757a8187dShastings }
155857a8187dShastings
155957a8187dShastings int
mtw_newstate(struct ieee80211com * ic,enum ieee80211_state nstate,int arg)156057a8187dShastings mtw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
156157a8187dShastings {
156257a8187dShastings struct mtw_softc *sc = ic->ic_softc;
156357a8187dShastings struct mtw_cmd_newstate cmd;
156457a8187dShastings
156557a8187dShastings /* do it in a process context */
156657a8187dShastings cmd.state = nstate;
156757a8187dShastings cmd.arg = arg;
156857a8187dShastings mtw_do_async(sc, mtw_newstate_cb, &cmd, sizeof cmd);
156957a8187dShastings return 0;
157057a8187dShastings }
157157a8187dShastings
157257a8187dShastings void
mtw_newstate_cb(struct mtw_softc * sc,void * arg)157357a8187dShastings mtw_newstate_cb(struct mtw_softc *sc, void *arg)
157457a8187dShastings {
157557a8187dShastings struct mtw_cmd_newstate *cmd = arg;
157657a8187dShastings struct ieee80211com *ic = &sc->sc_ic;
157757a8187dShastings enum ieee80211_state ostate;
157857a8187dShastings struct ieee80211_node *ni;
157957a8187dShastings uint32_t sta[3];
158057a8187dShastings uint8_t wcid;
158157a8187dShastings int s;
158257a8187dShastings
158357a8187dShastings s = splnet();
158457a8187dShastings ostate = ic->ic_state;
158557a8187dShastings
158657a8187dShastings if (ostate == IEEE80211_S_RUN) {
158757a8187dShastings /* turn link LED on */
158857a8187dShastings mtw_set_leds(sc, MTW_LED_MODE_ON);
158957a8187dShastings }
159057a8187dShastings
159157a8187dShastings switch (cmd->state) {
159257a8187dShastings case IEEE80211_S_INIT:
159357a8187dShastings if (ostate == IEEE80211_S_RUN) {
159457a8187dShastings /* abort TSF synchronization */
159557a8187dShastings mtw_abort_tsf_sync(sc);
159657a8187dShastings }
159757a8187dShastings break;
159857a8187dShastings
159957a8187dShastings case IEEE80211_S_SCAN:
160057a8187dShastings mtw_set_chan(sc, ic->ic_bss->ni_chan);
160157a8187dShastings if (!usbd_is_dying(sc->sc_udev))
160257a8187dShastings timeout_add_msec(&sc->scan_to, 200);
160357a8187dShastings break;
160457a8187dShastings
160557a8187dShastings case IEEE80211_S_AUTH:
160657a8187dShastings case IEEE80211_S_ASSOC:
160757a8187dShastings mtw_set_chan(sc, ic->ic_bss->ni_chan);
160857a8187dShastings break;
160957a8187dShastings
161057a8187dShastings case IEEE80211_S_RUN:
161157a8187dShastings mtw_set_chan(sc, ic->ic_bss->ni_chan);
161257a8187dShastings
161357a8187dShastings ni = ic->ic_bss;
161457a8187dShastings
161557a8187dShastings if (ic->ic_opmode != IEEE80211_M_MONITOR) {
161657a8187dShastings mtw_updateslot(ic);
161757a8187dShastings mtw_enable_mrr(sc);
161857a8187dShastings mtw_set_txpreamble(sc);
161957a8187dShastings mtw_set_basicrates(sc);
162057a8187dShastings mtw_set_bssid(sc, ni->ni_bssid);
162157a8187dShastings }
162257a8187dShastings if (ic->ic_opmode == IEEE80211_M_STA) {
162357a8187dShastings /* add BSS entry to the WCID table */
162457a8187dShastings wcid = MTW_AID2WCID(ni->ni_associd);
162557a8187dShastings mtw_write_region_1(sc, MTW_WCID_ENTRY(wcid),
162657a8187dShastings ni->ni_macaddr, IEEE80211_ADDR_LEN);
162757a8187dShastings
162857a8187dShastings /* fake a join to init the tx rate */
162957a8187dShastings mtw_newassoc(ic, ni, 1);
163057a8187dShastings }
163157a8187dShastings if (ic->ic_opmode != IEEE80211_M_MONITOR) {
163257a8187dShastings mtw_enable_tsf_sync(sc);
163357a8187dShastings
163457a8187dShastings /* clear statistic registers used by AMRR */
163557a8187dShastings mtw_read_region_1(sc, MTW_TX_STA_CNT0,
163657a8187dShastings (uint8_t *)sta, sizeof sta);
163757a8187dShastings /* start calibration timer */
163857a8187dShastings if (!usbd_is_dying(sc->sc_udev))
163957a8187dShastings timeout_add_sec(&sc->calib_to, 1);
164057a8187dShastings }
164157a8187dShastings
164257a8187dShastings /* turn link LED on */
164357a8187dShastings mtw_set_leds(sc, MTW_LED_MODE_BLINK_TX);
164457a8187dShastings break;
164557a8187dShastings }
164657a8187dShastings (void)sc->sc_newstate(ic, cmd->state, cmd->arg);
164757a8187dShastings splx(s);
164857a8187dShastings }
164957a8187dShastings
165057a8187dShastings void
mtw_updateedca(struct ieee80211com * ic)165157a8187dShastings mtw_updateedca(struct ieee80211com *ic)
165257a8187dShastings {
165357a8187dShastings /* do it in a process context */
165457a8187dShastings mtw_do_async(ic->ic_softc, mtw_updateedca_cb, NULL, 0);
165557a8187dShastings }
165657a8187dShastings
165757a8187dShastings void
mtw_updateedca_cb(struct mtw_softc * sc,void * arg)165857a8187dShastings mtw_updateedca_cb(struct mtw_softc *sc, void *arg)
165957a8187dShastings {
166057a8187dShastings struct ieee80211com *ic = &sc->sc_ic;
166157a8187dShastings int s, aci;
166257a8187dShastings
166357a8187dShastings s = splnet();
166457a8187dShastings /* update MAC TX configuration registers */
166557a8187dShastings for (aci = 0; aci < EDCA_NUM_AC; aci++) {
166657a8187dShastings mtw_write(sc, MTW_EDCA_AC_CFG(aci),
166757a8187dShastings ic->ic_edca_ac[aci].ac_ecwmax << 16 |
166857a8187dShastings ic->ic_edca_ac[aci].ac_ecwmin << 12 |
166957a8187dShastings ic->ic_edca_ac[aci].ac_aifsn << 8 |
167057a8187dShastings ic->ic_edca_ac[aci].ac_txoplimit);
167157a8187dShastings }
167257a8187dShastings
167357a8187dShastings /* update SCH/DMA registers too */
167457a8187dShastings mtw_write(sc, MTW_WMM_AIFSN_CFG,
167557a8187dShastings ic->ic_edca_ac[EDCA_AC_VO].ac_aifsn << 12 |
167657a8187dShastings ic->ic_edca_ac[EDCA_AC_VI].ac_aifsn << 8 |
167757a8187dShastings ic->ic_edca_ac[EDCA_AC_BK].ac_aifsn << 4 |
167857a8187dShastings ic->ic_edca_ac[EDCA_AC_BE].ac_aifsn);
167957a8187dShastings mtw_write(sc, MTW_WMM_CWMIN_CFG,
168057a8187dShastings ic->ic_edca_ac[EDCA_AC_VO].ac_ecwmin << 12 |
168157a8187dShastings ic->ic_edca_ac[EDCA_AC_VI].ac_ecwmin << 8 |
168257a8187dShastings ic->ic_edca_ac[EDCA_AC_BK].ac_ecwmin << 4 |
168357a8187dShastings ic->ic_edca_ac[EDCA_AC_BE].ac_ecwmin);
168457a8187dShastings mtw_write(sc, MTW_WMM_CWMAX_CFG,
168557a8187dShastings ic->ic_edca_ac[EDCA_AC_VO].ac_ecwmax << 12 |
168657a8187dShastings ic->ic_edca_ac[EDCA_AC_VI].ac_ecwmax << 8 |
168757a8187dShastings ic->ic_edca_ac[EDCA_AC_BK].ac_ecwmax << 4 |
168857a8187dShastings ic->ic_edca_ac[EDCA_AC_BE].ac_ecwmax);
168957a8187dShastings mtw_write(sc, MTW_WMM_TXOP0_CFG,
169057a8187dShastings ic->ic_edca_ac[EDCA_AC_BK].ac_txoplimit << 16 |
169157a8187dShastings ic->ic_edca_ac[EDCA_AC_BE].ac_txoplimit);
169257a8187dShastings mtw_write(sc, MTW_WMM_TXOP1_CFG,
169357a8187dShastings ic->ic_edca_ac[EDCA_AC_VO].ac_txoplimit << 16 |
169457a8187dShastings ic->ic_edca_ac[EDCA_AC_VI].ac_txoplimit);
169557a8187dShastings splx(s);
169657a8187dShastings }
169757a8187dShastings
169857a8187dShastings void
mtw_updateslot(struct ieee80211com * ic)169957a8187dShastings mtw_updateslot(struct ieee80211com *ic)
170057a8187dShastings {
170157a8187dShastings /* do it in a process context */
170257a8187dShastings mtw_do_async(ic->ic_softc, mtw_updateslot_cb, NULL, 0);
170357a8187dShastings }
170457a8187dShastings
170557a8187dShastings void
mtw_updateslot_cb(struct mtw_softc * sc,void * arg)170657a8187dShastings mtw_updateslot_cb(struct mtw_softc *sc, void *arg)
170757a8187dShastings {
170857a8187dShastings uint32_t tmp;
170957a8187dShastings
171057a8187dShastings mtw_read(sc, MTW_BKOFF_SLOT_CFG, &tmp);
171157a8187dShastings tmp &= ~0xff;
171257a8187dShastings tmp |= (sc->sc_ic.ic_flags & IEEE80211_F_SHSLOT) ?
171357a8187dShastings IEEE80211_DUR_DS_SHSLOT : IEEE80211_DUR_DS_SLOT;
171457a8187dShastings mtw_write(sc, MTW_BKOFF_SLOT_CFG, tmp);
171557a8187dShastings }
171657a8187dShastings
171757a8187dShastings int
mtw_set_key(struct ieee80211com * ic,struct ieee80211_node * ni,struct ieee80211_key * k)171857a8187dShastings mtw_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
171957a8187dShastings struct ieee80211_key *k)
172057a8187dShastings {
172157a8187dShastings struct mtw_softc *sc = ic->ic_softc;
172257a8187dShastings struct mtw_cmd_key cmd;
172357a8187dShastings
172457a8187dShastings /* defer setting of WEP keys until interface is brought up */
172557a8187dShastings if ((ic->ic_if.if_flags & (IFF_UP | IFF_RUNNING)) !=
172657a8187dShastings (IFF_UP | IFF_RUNNING))
172757a8187dShastings return 0;
172857a8187dShastings
172957a8187dShastings /* do it in a process context */
173057a8187dShastings cmd.key = *k;
173157a8187dShastings cmd.ni = ni;
173257a8187dShastings mtw_do_async(sc, mtw_set_key_cb, &cmd, sizeof cmd);
173357a8187dShastings sc->sc_key_tasks++;
173457a8187dShastings return EBUSY;
173557a8187dShastings }
173657a8187dShastings
173757a8187dShastings void
mtw_set_key_cb(struct mtw_softc * sc,void * arg)173857a8187dShastings mtw_set_key_cb(struct mtw_softc *sc, void *arg)
173957a8187dShastings {
174057a8187dShastings struct ieee80211com *ic = &sc->sc_ic;
174157a8187dShastings struct mtw_cmd_key *cmd = arg;
174257a8187dShastings struct ieee80211_key *k = &cmd->key;
174357a8187dShastings uint32_t attr;
174457a8187dShastings uint16_t base;
174557a8187dShastings uint8_t mode, wcid, iv[8];
174657a8187dShastings
174757a8187dShastings sc->sc_key_tasks--;
174857a8187dShastings
174957a8187dShastings /* map net80211 cipher to RT2860 security mode */
175057a8187dShastings switch (k->k_cipher) {
175157a8187dShastings case IEEE80211_CIPHER_WEP40:
175257a8187dShastings mode = MTW_MODE_WEP40;
175357a8187dShastings break;
175457a8187dShastings case IEEE80211_CIPHER_WEP104:
175557a8187dShastings mode = MTW_MODE_WEP104;
175657a8187dShastings break;
175757a8187dShastings case IEEE80211_CIPHER_TKIP:
175857a8187dShastings mode = MTW_MODE_TKIP;
175957a8187dShastings break;
176057a8187dShastings case IEEE80211_CIPHER_CCMP:
176157a8187dShastings mode = MTW_MODE_AES_CCMP;
176257a8187dShastings break;
176357a8187dShastings default:
176457a8187dShastings if (cmd->ni != NULL) {
176557a8187dShastings IEEE80211_SEND_MGMT(ic, cmd->ni,
176657a8187dShastings IEEE80211_FC0_SUBTYPE_DEAUTH,
176757a8187dShastings IEEE80211_REASON_AUTH_LEAVE);
176857a8187dShastings }
176957a8187dShastings ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
177057a8187dShastings return;
177157a8187dShastings }
177257a8187dShastings
177357a8187dShastings if (k->k_flags & IEEE80211_KEY_GROUP) {
177457a8187dShastings wcid = 0; /* NB: update WCID0 for group keys */
177557a8187dShastings base = MTW_SKEY(0, k->k_id);
177657a8187dShastings } else {
177757a8187dShastings wcid = (cmd->ni != NULL) ? MTW_AID2WCID(cmd->ni->ni_associd) : 0;
177857a8187dShastings base = MTW_PKEY(wcid);
177957a8187dShastings }
178057a8187dShastings
178157a8187dShastings if (k->k_cipher == IEEE80211_CIPHER_TKIP) {
178257a8187dShastings mtw_write_region_1(sc, base, k->k_key, 16);
178357a8187dShastings mtw_write_region_1(sc, base + 16, &k->k_key[24], 8);
178457a8187dShastings mtw_write_region_1(sc, base + 24, &k->k_key[16], 8);
178557a8187dShastings } else {
178657a8187dShastings /* roundup len to 16-bit: XXX fix write_region_1() instead */
178757a8187dShastings mtw_write_region_1(sc, base, k->k_key, (k->k_len + 1) & ~1);
178857a8187dShastings }
178957a8187dShastings
179057a8187dShastings if (!(k->k_flags & IEEE80211_KEY_GROUP) ||
179157a8187dShastings (k->k_flags & IEEE80211_KEY_TX)) {
179257a8187dShastings /* set initial packet number in IV+EIV */
179357a8187dShastings if (k->k_cipher == IEEE80211_CIPHER_WEP40 ||
179457a8187dShastings k->k_cipher == IEEE80211_CIPHER_WEP104) {
179557a8187dShastings memset(iv, 0, sizeof iv);
179657a8187dShastings iv[3] = sc->sc_ic.ic_def_txkey << 6;
179757a8187dShastings } else {
179857a8187dShastings if (k->k_cipher == IEEE80211_CIPHER_TKIP) {
179957a8187dShastings iv[0] = k->k_tsc >> 8;
180057a8187dShastings iv[1] = (iv[0] | 0x20) & 0x7f;
180157a8187dShastings iv[2] = k->k_tsc;
180257a8187dShastings } else /* CCMP */ {
180357a8187dShastings iv[0] = k->k_tsc;
180457a8187dShastings iv[1] = k->k_tsc >> 8;
180557a8187dShastings iv[2] = 0;
180657a8187dShastings }
180757a8187dShastings iv[3] = k->k_id << 6 | IEEE80211_WEP_EXTIV;
180857a8187dShastings iv[4] = k->k_tsc >> 16;
180957a8187dShastings iv[5] = k->k_tsc >> 24;
181057a8187dShastings iv[6] = k->k_tsc >> 32;
181157a8187dShastings iv[7] = k->k_tsc >> 40;
181257a8187dShastings }
181357a8187dShastings mtw_write_region_1(sc, MTW_IVEIV(wcid), iv, 8);
181457a8187dShastings }
181557a8187dShastings
181657a8187dShastings if (k->k_flags & IEEE80211_KEY_GROUP) {
181757a8187dShastings /* install group key */
181857a8187dShastings mtw_read(sc, MTW_SKEY_MODE_0_7, &attr);
181957a8187dShastings attr &= ~(0xf << (k->k_id * 4));
182057a8187dShastings attr |= mode << (k->k_id * 4);
182157a8187dShastings mtw_write(sc, MTW_SKEY_MODE_0_7, attr);
182257a8187dShastings
182357a8187dShastings if (k->k_cipher & (IEEE80211_CIPHER_WEP104 |
182457a8187dShastings IEEE80211_CIPHER_WEP40)) {
182557a8187dShastings mtw_read(sc, MTW_WCID_ATTR(wcid + 1), &attr);
182657a8187dShastings attr = (attr & ~0xf) | (mode << 1);
182757a8187dShastings mtw_write(sc, MTW_WCID_ATTR(wcid + 1), attr);
182857a8187dShastings
182957a8187dShastings mtw_set_region_4(sc, MTW_IVEIV(0), 0, 4);
183057a8187dShastings
183157a8187dShastings mtw_read(sc, MTW_WCID_ATTR(wcid), &attr);
183257a8187dShastings attr = (attr & ~0xf) | (mode << 1);
183357a8187dShastings mtw_write(sc, MTW_WCID_ATTR(wcid), attr);
183457a8187dShastings }
183557a8187dShastings } else {
183657a8187dShastings /* install pairwise key */
183757a8187dShastings mtw_read(sc, MTW_WCID_ATTR(wcid), &attr);
183857a8187dShastings attr = (attr & ~0xf) | (mode << 1) | MTW_RX_PKEY_EN;
183957a8187dShastings mtw_write(sc, MTW_WCID_ATTR(wcid), attr);
184057a8187dShastings }
184157a8187dShastings
184257a8187dShastings if (sc->sc_key_tasks == 0) {
184357a8187dShastings if (cmd->ni != NULL)
184457a8187dShastings cmd->ni->ni_port_valid = 1;
184557a8187dShastings ieee80211_set_link_state(ic, LINK_STATE_UP);
184657a8187dShastings }
184757a8187dShastings }
184857a8187dShastings
184957a8187dShastings void
mtw_delete_key(struct ieee80211com * ic,struct ieee80211_node * ni,struct ieee80211_key * k)185057a8187dShastings mtw_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni,
185157a8187dShastings struct ieee80211_key *k)
185257a8187dShastings {
185357a8187dShastings struct mtw_softc *sc = ic->ic_softc;
185457a8187dShastings struct mtw_cmd_key cmd;
185557a8187dShastings
185657a8187dShastings if (!(ic->ic_if.if_flags & IFF_RUNNING) ||
185757a8187dShastings ic->ic_state != IEEE80211_S_RUN)
185857a8187dShastings return; /* nothing to do */
185957a8187dShastings
186057a8187dShastings /* do it in a process context */
186157a8187dShastings cmd.key = *k;
186257a8187dShastings cmd.ni = ni;
186357a8187dShastings mtw_do_async(sc, mtw_delete_key_cb, &cmd, sizeof cmd);
186457a8187dShastings }
186557a8187dShastings
186657a8187dShastings void
mtw_delete_key_cb(struct mtw_softc * sc,void * arg)186757a8187dShastings mtw_delete_key_cb(struct mtw_softc *sc, void *arg)
186857a8187dShastings {
186957a8187dShastings struct mtw_cmd_key *cmd = arg;
187057a8187dShastings struct ieee80211_key *k = &cmd->key;
187157a8187dShastings uint32_t attr;
187257a8187dShastings uint8_t wcid;
187357a8187dShastings
187457a8187dShastings if (k->k_flags & IEEE80211_KEY_GROUP) {
187557a8187dShastings /* remove group key */
187657a8187dShastings mtw_read(sc, MTW_SKEY_MODE_0_7, &attr);
187757a8187dShastings attr &= ~(0xf << (k->k_id * 4));
187857a8187dShastings mtw_write(sc, MTW_SKEY_MODE_0_7, attr);
187957a8187dShastings
188057a8187dShastings } else {
188157a8187dShastings /* remove pairwise key */
188257a8187dShastings wcid = (cmd->ni != NULL) ? MTW_AID2WCID(cmd->ni->ni_associd) : 0;
188357a8187dShastings mtw_read(sc, MTW_WCID_ATTR(wcid), &attr);
188457a8187dShastings attr &= ~0xf;
188557a8187dShastings mtw_write(sc, MTW_WCID_ATTR(wcid), attr);
188657a8187dShastings }
188757a8187dShastings }
188857a8187dShastings
188957a8187dShastings void
mtw_calibrate_to(void * arg)189057a8187dShastings mtw_calibrate_to(void *arg)
189157a8187dShastings {
189257a8187dShastings /* do it in a process context */
189357a8187dShastings mtw_do_async(arg, mtw_calibrate_cb, NULL, 0);
189457a8187dShastings /* next timeout will be rescheduled in the calibration task */
189557a8187dShastings }
189657a8187dShastings
189757a8187dShastings void
mtw_calibrate_cb(struct mtw_softc * sc,void * arg)189857a8187dShastings mtw_calibrate_cb(struct mtw_softc *sc, void *arg)
189957a8187dShastings {
190057a8187dShastings struct ifnet *ifp = &sc->sc_ic.ic_if;
190157a8187dShastings uint32_t sta[3];
190257a8187dShastings int s, error;
190357a8187dShastings
190457a8187dShastings /* read statistic counters (clear on read) and update AMRR state */
190557a8187dShastings error = mtw_read_region_1(sc, MTW_TX_STA_CNT0, (uint8_t *)sta,
190657a8187dShastings sizeof sta);
190757a8187dShastings if (error != 0)
190857a8187dShastings goto skip;
190957a8187dShastings
191057a8187dShastings DPRINTF(("retrycnt=%d txcnt=%d failcnt=%d\n",
191157a8187dShastings letoh32(sta[1]) >> 16, letoh32(sta[1]) & 0xffff,
191257a8187dShastings letoh32(sta[0]) & 0xffff));
191357a8187dShastings
191457a8187dShastings s = splnet();
191557a8187dShastings /* count failed TX as errors */
191657a8187dShastings ifp->if_oerrors += letoh32(sta[0]) & 0xffff;
191757a8187dShastings
191857a8187dShastings sc->amn.amn_retrycnt =
191957a8187dShastings (letoh32(sta[0]) & 0xffff) + /* failed TX count */
192057a8187dShastings (letoh32(sta[1]) >> 16); /* TX retransmission count */
192157a8187dShastings
192257a8187dShastings sc->amn.amn_txcnt =
192357a8187dShastings sc->amn.amn_retrycnt +
192457a8187dShastings (letoh32(sta[1]) & 0xffff); /* successful TX count */
192557a8187dShastings
192657a8187dShastings ieee80211_amrr_choose(&sc->amrr, sc->sc_ic.ic_bss, &sc->amn);
192757a8187dShastings
192857a8187dShastings splx(s);
192957a8187dShastings skip:
193057a8187dShastings if (!usbd_is_dying(sc->sc_udev))
193157a8187dShastings timeout_add_sec(&sc->calib_to, 1);
193257a8187dShastings }
193357a8187dShastings
193457a8187dShastings void
mtw_newassoc(struct ieee80211com * ic,struct ieee80211_node * ni,int isnew)193557a8187dShastings mtw_newassoc(struct ieee80211com *ic, struct ieee80211_node *ni, int isnew)
193657a8187dShastings {
193757a8187dShastings struct mtw_softc *sc = ic->ic_softc;
193857a8187dShastings struct mtw_node *mn = (void *)ni;
193957a8187dShastings struct ieee80211_rateset *rs = &ni->ni_rates;
194057a8187dShastings uint8_t rate;
194157a8187dShastings int ridx, i, j;
194257a8187dShastings
194357a8187dShastings DPRINTF(("new assoc isnew=%d addr=%s\n",
194457a8187dShastings isnew, ether_sprintf(ni->ni_macaddr)));
194557a8187dShastings
194657a8187dShastings ieee80211_amrr_node_init(&sc->amrr, &sc->amn);
194757a8187dShastings
194857a8187dShastings /* start at lowest available bit-rate, AMRR will raise */
194957a8187dShastings ni->ni_txrate = 0;
195057a8187dShastings
195157a8187dShastings for (i = 0; i < rs->rs_nrates; i++) {
195257a8187dShastings rate = rs->rs_rates[i] & IEEE80211_RATE_VAL;
195357a8187dShastings /* convert 802.11 rate to hardware rate index */
195457a8187dShastings for (ridx = 0; ridx < MTW_RIDX_MAX; ridx++)
195557a8187dShastings if (rt2860_rates[ridx].rate == rate)
195657a8187dShastings break;
195757a8187dShastings mn->ridx[i] = ridx;
195857a8187dShastings /* determine rate of control response frames */
195957a8187dShastings for (j = i; j >= 0; j--) {
196057a8187dShastings if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) &&
196157a8187dShastings rt2860_rates[mn->ridx[i]].phy ==
196257a8187dShastings rt2860_rates[mn->ridx[j]].phy)
196357a8187dShastings break;
196457a8187dShastings }
196557a8187dShastings if (j >= 0) {
196657a8187dShastings mn->ctl_ridx[i] = mn->ridx[j];
196757a8187dShastings } else {
196857a8187dShastings /* no basic rate found, use mandatory one */
196957a8187dShastings mn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx;
197057a8187dShastings }
197157a8187dShastings DPRINTF(("rate=0x%02x ridx=%d ctl_ridx=%d\n",
197257a8187dShastings rs->rs_rates[i], mn->ridx[i], mn->ctl_ridx[i]));
197357a8187dShastings }
197457a8187dShastings }
197557a8187dShastings
197657a8187dShastings /*
197757a8187dShastings * Return the Rx chain with the highest RSSI for a given frame.
197857a8187dShastings */
197957a8187dShastings static __inline uint8_t
mtw_maxrssi_chain(struct mtw_softc * sc,const struct mtw_rxwi * rxwi)198057a8187dShastings mtw_maxrssi_chain(struct mtw_softc *sc, const struct mtw_rxwi *rxwi)
198157a8187dShastings {
198257a8187dShastings uint8_t rxchain = 0;
198357a8187dShastings
198457a8187dShastings if (sc->nrxchains > 1) {
198557a8187dShastings if (rxwi->rssi[1] > rxwi->rssi[rxchain])
198657a8187dShastings rxchain = 1;
198757a8187dShastings }
198857a8187dShastings return rxchain;
198957a8187dShastings }
199057a8187dShastings
199157a8187dShastings void
mtw_rx_frame(struct mtw_softc * sc,uint8_t * buf,int dmalen,struct mbuf_list * ml)199257a8187dShastings mtw_rx_frame(struct mtw_softc *sc, uint8_t *buf, int dmalen,
199357a8187dShastings struct mbuf_list *ml)
199457a8187dShastings {
199557a8187dShastings struct ieee80211com *ic = &sc->sc_ic;
199657a8187dShastings struct ifnet *ifp = &ic->ic_if;
199757a8187dShastings struct ieee80211_frame *wh;
199857a8187dShastings struct ieee80211_rxinfo rxi;
199957a8187dShastings struct ieee80211_node *ni;
200057a8187dShastings struct mtw_rxwi *rxwi;
200157a8187dShastings struct mbuf *m;
200257a8187dShastings uint32_t flags;
200357a8187dShastings uint16_t len;
200457a8187dShastings #if NBPFILTER > 0
200557a8187dShastings uint16_t phy;
200657a8187dShastings #endif
200757a8187dShastings uint16_t rxwisize;
200857a8187dShastings uint8_t ant, rssi;
200957a8187dShastings int s;
201057a8187dShastings
201157a8187dShastings /* Rx Wireless Information */
201257a8187dShastings rxwi = (struct mtw_rxwi *)(buf);
201357a8187dShastings rxwisize = sizeof(struct mtw_rxwi);
201457a8187dShastings len = letoh16(rxwi->len) & 0xfff;
201557a8187dShastings
201657a8187dShastings if (__predict_false(len > dmalen)) {
201757a8187dShastings DPRINTF(("bad RXWI length %u > %u\n", len, dmalen));
201857a8187dShastings return;
201957a8187dShastings }
202057a8187dShastings if (len > MCLBYTES) {
202157a8187dShastings DPRINTF(("frame too large (length=%d)\n", len));
202257a8187dShastings ifp->if_ierrors++;
202357a8187dShastings return;
202457a8187dShastings }
202557a8187dShastings
202657a8187dShastings flags = letoh32(rxwi->flags);
202757a8187dShastings if (__predict_false(flags & (MTW_RX_CRCERR | MTW_RX_ICVERR))) {
202857a8187dShastings ifp->if_ierrors++;
202957a8187dShastings return;
203057a8187dShastings }
203157a8187dShastings if (__predict_false((flags & MTW_RX_MICERR))) {
203257a8187dShastings /* report MIC failures to net80211 for TKIP */
203357a8187dShastings ic->ic_stats.is_rx_locmicfail++;
203457a8187dShastings ieee80211_michael_mic_failure(ic, 0/* XXX */);
203557a8187dShastings ifp->if_ierrors++;
203657a8187dShastings return;
203757a8187dShastings }
203857a8187dShastings
203957a8187dShastings wh = (struct ieee80211_frame *)(buf + rxwisize);
204052a13037Sstsp memset(&rxi, 0, sizeof(rxi));
204157a8187dShastings if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
204257a8187dShastings wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
204357a8187dShastings rxi.rxi_flags |= IEEE80211_RXI_HWDEC;
204457a8187dShastings }
204557a8187dShastings
204657a8187dShastings if (flags & MTW_RX_L2PAD) {
204757a8187dShastings u_int hdrlen = ieee80211_get_hdrlen(wh);
204857a8187dShastings memmove((caddr_t)wh + 2, wh, hdrlen);
204957a8187dShastings wh = (struct ieee80211_frame *)((caddr_t)wh + 2);
205057a8187dShastings }
205157a8187dShastings
205257a8187dShastings /* could use m_devget but net80211 wants contig mgmt frames */
205357a8187dShastings MGETHDR(m, M_DONTWAIT, MT_DATA);
205457a8187dShastings if (__predict_false(m == NULL)) {
205557a8187dShastings ifp->if_ierrors++;
205657a8187dShastings return;
205757a8187dShastings }
205857a8187dShastings if (len > MHLEN) {
205957a8187dShastings MCLGET(m, M_DONTWAIT);
206057a8187dShastings if (__predict_false(!(m->m_flags & M_EXT))) {
206157a8187dShastings ifp->if_ierrors++;
206257a8187dShastings m_freem(m);
206357a8187dShastings return;
206457a8187dShastings }
206557a8187dShastings }
206657a8187dShastings /* finalize mbuf */
206757a8187dShastings memcpy(mtod(m, caddr_t), wh, len);
206857a8187dShastings m->m_pkthdr.len = m->m_len = len;
206957a8187dShastings
207057a8187dShastings ant = mtw_maxrssi_chain(sc, rxwi);
207157a8187dShastings rssi = rxwi->rssi[ant];
207257a8187dShastings
207357a8187dShastings #if NBPFILTER > 0
207457a8187dShastings if (__predict_false(sc->sc_drvbpf != NULL)) {
207557a8187dShastings struct mtw_rx_radiotap_header *tap = &sc->sc_rxtap;
207657a8187dShastings struct mbuf mb;
207757a8187dShastings
207857a8187dShastings tap->wr_flags = 0;
207957a8187dShastings tap->wr_chan_freq = htole16(ic->ic_ibss_chan->ic_freq);
208057a8187dShastings tap->wr_chan_flags = htole16(ic->ic_ibss_chan->ic_flags);
208157a8187dShastings tap->wr_antsignal = rssi;
208257a8187dShastings tap->wr_antenna = ant;
208357a8187dShastings tap->wr_dbm_antsignal = mtw_rssi2dbm(sc, rssi, ant);
208457a8187dShastings tap->wr_rate = 2; /* in case it can't be found below */
208557a8187dShastings phy = letoh16(rxwi->phy);
2086c06983aeShastings switch (phy >> MT7601_PHY_SHIFT) {
208757a8187dShastings case MTW_PHY_CCK:
208857a8187dShastings switch ((phy & MTW_PHY_MCS) & ~MTW_PHY_SHPRE) {
208957a8187dShastings case 0: tap->wr_rate = 2; break;
209057a8187dShastings case 1: tap->wr_rate = 4; break;
209157a8187dShastings case 2: tap->wr_rate = 11; break;
209257a8187dShastings case 3: tap->wr_rate = 22; break;
209357a8187dShastings }
209457a8187dShastings if (phy & MTW_PHY_SHPRE)
209557a8187dShastings tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
209657a8187dShastings break;
209757a8187dShastings case MTW_PHY_OFDM:
209857a8187dShastings switch (phy & MTW_PHY_MCS) {
209957a8187dShastings case 0: tap->wr_rate = 12; break;
210057a8187dShastings case 1: tap->wr_rate = 18; break;
210157a8187dShastings case 2: tap->wr_rate = 24; break;
210257a8187dShastings case 3: tap->wr_rate = 36; break;
210357a8187dShastings case 4: tap->wr_rate = 48; break;
210457a8187dShastings case 5: tap->wr_rate = 72; break;
210557a8187dShastings case 6: tap->wr_rate = 96; break;
210657a8187dShastings case 7: tap->wr_rate = 108; break;
210757a8187dShastings }
210857a8187dShastings break;
210957a8187dShastings }
211057a8187dShastings mb.m_data = (caddr_t)tap;
211157a8187dShastings mb.m_len = sc->sc_rxtap_len;
211257a8187dShastings mb.m_next = m;
211357a8187dShastings mb.m_nextpkt = NULL;
211457a8187dShastings mb.m_type = 0;
211557a8187dShastings mb.m_flags = 0;
211657a8187dShastings bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN);
211757a8187dShastings }
211857a8187dShastings #endif
211957a8187dShastings
212057a8187dShastings s = splnet();
212157a8187dShastings ni = ieee80211_find_rxnode(ic, wh);
212257a8187dShastings rxi.rxi_rssi = rssi;
212357a8187dShastings ieee80211_inputm(ifp, m, ni, &rxi, ml);
212457a8187dShastings
212557a8187dShastings /* node is no longer needed */
212657a8187dShastings ieee80211_release_node(ic, ni);
212757a8187dShastings splx(s);
212857a8187dShastings }
212957a8187dShastings
213057a8187dShastings void
mtw_rxeof(struct usbd_xfer * xfer,void * priv,usbd_status status)213157a8187dShastings mtw_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
213257a8187dShastings {
213357a8187dShastings struct mbuf_list ml = MBUF_LIST_INITIALIZER();
213457a8187dShastings struct mtw_rx_data *data = priv;
213557a8187dShastings struct mtw_softc *sc = data->sc;
213657a8187dShastings uint8_t *buf;
213757a8187dShastings uint32_t dmalen;
213857a8187dShastings int xferlen;
213957a8187dShastings
214057a8187dShastings if (__predict_false(status != USBD_NORMAL_COMPLETION)) {
214157a8187dShastings DPRINTF(("RX status=%d\n", status));
214257a8187dShastings if (status == USBD_STALLED)
214357a8187dShastings usbd_clear_endpoint_stall_async(sc->rxq[0].pipeh);
214457a8187dShastings if (status != USBD_CANCELLED)
214557a8187dShastings goto skip;
214657a8187dShastings return;
214757a8187dShastings }
214857a8187dShastings
214957a8187dShastings usbd_get_xfer_status(xfer, NULL, NULL, &xferlen, NULL);
215057a8187dShastings
215157a8187dShastings if (__predict_false(xferlen < sizeof(uint32_t) +
215257a8187dShastings sizeof (struct mtw_rxwi) + sizeof(struct mtw_rxd))) {
215357a8187dShastings DPRINTF(("RX xfer too short %d\n", xferlen));
215457a8187dShastings goto skip;
215557a8187dShastings }
215657a8187dShastings
215757a8187dShastings /* HW can aggregate multiple 802.11 frames in a single USB xfer */
215857a8187dShastings buf = data->buf;
215957a8187dShastings while (xferlen > 8) {
216057a8187dShastings dmalen = letoh32(*(uint32_t *)buf) & MTW_RXD_LEN;
216157a8187dShastings if (__predict_false(dmalen == 0 || (dmalen & 3) != 0)) {
216257a8187dShastings DPRINTF(("bad DMA length %u\n", dmalen));
216357a8187dShastings break;
216457a8187dShastings }
216557a8187dShastings if (__predict_false(dmalen + 8 > xferlen)) {
216657a8187dShastings DPRINTF(("bad DMA length %u > %d\n",
216757a8187dShastings dmalen + 8, xferlen));
216857a8187dShastings break;
216957a8187dShastings }
217057a8187dShastings mtw_rx_frame(sc, buf + sizeof(struct mtw_rxd), dmalen, &ml);
217157a8187dShastings buf += dmalen + 8;
217257a8187dShastings xferlen -= dmalen + 8;
217357a8187dShastings }
217457a8187dShastings if_input(&sc->sc_ic.ic_if, &ml);
217557a8187dShastings
217657a8187dShastings skip: /* setup a new transfer */
217757a8187dShastings usbd_setup_xfer(xfer, sc->rxq[0].pipeh, data, data->buf, MTW_MAX_RXSZ,
217857a8187dShastings USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT, mtw_rxeof);
217957a8187dShastings (void)usbd_transfer(data->xfer);
218057a8187dShastings }
218157a8187dShastings
218257a8187dShastings void
mtw_txeof(struct usbd_xfer * xfer,void * priv,usbd_status status)218357a8187dShastings mtw_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
218457a8187dShastings {
218557a8187dShastings struct mtw_tx_data *data = priv;
218657a8187dShastings struct mtw_softc *sc = data->sc;
218757a8187dShastings struct mtw_tx_ring *txq = &sc->txq[data->qid];
218857a8187dShastings struct ifnet *ifp = &sc->sc_ic.ic_if;
218957a8187dShastings int s;
219057a8187dShastings
219157a8187dShastings if (usbd_is_dying(sc->sc_udev))
219257a8187dShastings return;
219357a8187dShastings
219457a8187dShastings s = splnet();
219557a8187dShastings txq->queued--;
219657a8187dShastings sc->qfullmsk &= ~(1 << data->qid);
219757a8187dShastings
219857a8187dShastings if (__predict_false(status != USBD_NORMAL_COMPLETION)) {
219957a8187dShastings DPRINTF(("TX status=%d\n", status));
220057a8187dShastings if (status == USBD_STALLED)
220157a8187dShastings usbd_clear_endpoint_stall_async(txq->pipeh);
220257a8187dShastings ifp->if_oerrors++;
220357a8187dShastings splx(s);
220457a8187dShastings return;
220557a8187dShastings }
220657a8187dShastings
220757a8187dShastings sc->sc_tx_timer = 0;
220857a8187dShastings
220957a8187dShastings if (ifq_is_oactive(&ifp->if_snd)) {
221057a8187dShastings ifq_clr_oactive(&ifp->if_snd);
221157a8187dShastings mtw_start(ifp);
221257a8187dShastings }
221357a8187dShastings
221457a8187dShastings splx(s);
221557a8187dShastings }
221657a8187dShastings
221757a8187dShastings int
mtw_tx(struct mtw_softc * sc,struct mbuf * m,struct ieee80211_node * ni)221857a8187dShastings mtw_tx(struct mtw_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
221957a8187dShastings {
222057a8187dShastings struct ieee80211com *ic = &sc->sc_ic;
222157a8187dShastings struct mtw_node *mn = (void *)ni;
222257a8187dShastings struct ieee80211_frame *wh;
222357a8187dShastings struct mtw_tx_ring *ring;
222457a8187dShastings struct mtw_tx_data *data;
222557a8187dShastings struct mtw_txd *txd;
222657a8187dShastings struct mtw_txwi *txwi;
222757a8187dShastings uint16_t qos, dur;
222857a8187dShastings uint16_t txwisize;
222957a8187dShastings uint8_t type, mcs, tid, qid;
223057a8187dShastings int error, hasqos, ridx, ctl_ridx, xferlen;
223157a8187dShastings
223257a8187dShastings wh = mtod(m, struct ieee80211_frame *);
223357a8187dShastings type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
223457a8187dShastings
223557a8187dShastings /* select queue */
223657a8187dShastings if ((hasqos = ieee80211_has_qos(wh))) {
223757a8187dShastings qos = ieee80211_get_qos(wh);
223857a8187dShastings tid = qos & IEEE80211_QOS_TID;
223957a8187dShastings qid = ieee80211_up_to_ac(ic, tid);
224057a8187dShastings } else {
224157a8187dShastings qos = 0;
224257a8187dShastings tid = 0;
224357a8187dShastings qid = EDCA_AC_BE;
224457a8187dShastings }
224557a8187dShastings
224657a8187dShastings /* management frames go to MCU queue */
224757a8187dShastings if (type == IEEE80211_FC0_TYPE_MGT)
224857a8187dShastings qid = MTW_TXQ_MCU;
224957a8187dShastings
225057a8187dShastings ring = &sc->txq[qid];
225157a8187dShastings data = &ring->data[ring->cur];
225257a8187dShastings
225357a8187dShastings /* pickup a rate index */
225457a8187dShastings if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
225557a8187dShastings type != IEEE80211_FC0_TYPE_DATA) {
225657a8187dShastings ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
225757a8187dShastings MTW_RIDX_OFDM6 : MTW_RIDX_CCK1;
225857a8187dShastings ctl_ridx = rt2860_rates[ridx].ctl_ridx;
225957a8187dShastings } else if (ic->ic_fixed_rate != -1) {
226057a8187dShastings ridx = sc->fixed_ridx;
226157a8187dShastings ctl_ridx = rt2860_rates[ridx].ctl_ridx;
226257a8187dShastings } else {
226357a8187dShastings ridx = mn->ridx[ni->ni_txrate];
226457a8187dShastings ctl_ridx = mn->ctl_ridx[ni->ni_txrate];
226557a8187dShastings }
226657a8187dShastings
226757a8187dShastings txwisize = sizeof(struct mtw_txwi);
226857a8187dShastings xferlen = txwisize + m->m_pkthdr.len;
226957a8187dShastings
227057a8187dShastings /* roundup to 32-bit alignment */
227157a8187dShastings xferlen = (xferlen + 3) & ~3;
227257a8187dShastings
227357a8187dShastings /* setup TX descriptor */
227457a8187dShastings txd = (struct mtw_txd *)data->buf;
227557a8187dShastings txd->flags = htole16(MTW_TXD_DATA | MTW_TXD_80211 |
227657a8187dShastings MTW_TXD_WLAN | MTW_TXD_QSEL_EDCA);
227757a8187dShastings
227857a8187dShastings if (type != IEEE80211_FC0_TYPE_DATA)
227957a8187dShastings txd->flags |= htole16(MTW_TXD_WIV);
228057a8187dShastings txd->len = htole16(xferlen);
228157a8187dShastings xferlen += sizeof(struct mtw_txd);
228257a8187dShastings
228357a8187dShastings /* get MCS code from rate index */
228457a8187dShastings mcs = rt2860_rates[ridx].mcs;
228557a8187dShastings
228657a8187dShastings /* setup TX Wireless Information */
228757a8187dShastings txwi = (struct mtw_txwi *)(txd + 1);
228857a8187dShastings txwi->flags = 0;
228957a8187dShastings txwi->xflags = hasqos ? 0 : MTW_TX_NSEQ;
229057a8187dShastings txwi->wcid = (type == IEEE80211_FC0_TYPE_DATA) ?
229157a8187dShastings MTW_AID2WCID(ni->ni_associd) : 0xff;
229257a8187dShastings txwi->len = htole16(m->m_pkthdr.len);
229357a8187dShastings txwi->txop = MTW_TX_TXOP_BACKOFF;
229457a8187dShastings
229557a8187dShastings if (rt2860_rates[ridx].phy == IEEE80211_T_DS) {
2296c06983aeShastings txwi->phy = htole16(MTW_PHY_CCK << MT7601_PHY_SHIFT);
229757a8187dShastings if (ridx != MTW_RIDX_CCK1 &&
229857a8187dShastings (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
229957a8187dShastings mcs |= MTW_PHY_SHPRE;
230057a8187dShastings } else if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM)
2301c06983aeShastings txwi->phy = htole16(MTW_PHY_OFDM << MT7601_PHY_SHIFT);
230257a8187dShastings txwi->phy |= htole16(mcs);
230357a8187dShastings
230457a8187dShastings if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
230557a8187dShastings (!hasqos || (qos & IEEE80211_QOS_ACK_POLICY_MASK) !=
230657a8187dShastings IEEE80211_QOS_ACK_POLICY_NOACK)) {
230757a8187dShastings txwi->xflags |= MTW_TX_ACK;
230857a8187dShastings if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
230957a8187dShastings dur = rt2860_rates[ctl_ridx].sp_ack_dur;
231057a8187dShastings else
231157a8187dShastings dur = rt2860_rates[ctl_ridx].lp_ack_dur;
231257a8187dShastings *(uint16_t *)wh->i_dur = htole16(dur);
231357a8187dShastings }
231457a8187dShastings
231557a8187dShastings #if NBPFILTER > 0
231657a8187dShastings if (__predict_false(sc->sc_drvbpf != NULL)) {
231757a8187dShastings struct mtw_tx_radiotap_header *tap = &sc->sc_txtap;
231857a8187dShastings struct mbuf mb;
231957a8187dShastings
232057a8187dShastings tap->wt_flags = 0;
232157a8187dShastings tap->wt_rate = rt2860_rates[ridx].rate;
232257a8187dShastings tap->wt_chan_freq = htole16(ic->ic_bss->ni_chan->ic_freq);
232357a8187dShastings tap->wt_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags);
232457a8187dShastings if (mcs & MTW_PHY_SHPRE)
232557a8187dShastings tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
232657a8187dShastings
232757a8187dShastings mb.m_data = (caddr_t)tap;
232857a8187dShastings mb.m_len = sc->sc_txtap_len;
232957a8187dShastings mb.m_next = m;
233057a8187dShastings mb.m_nextpkt = NULL;
233157a8187dShastings mb.m_type = 0;
233257a8187dShastings mb.m_flags = 0;
233357a8187dShastings bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_OUT);
233457a8187dShastings }
233557a8187dShastings #endif
233657a8187dShastings /* copy payload */
233757a8187dShastings m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)txwi + txwisize);
233857a8187dShastings m_freem(m);
233957a8187dShastings
234057a8187dShastings /* 4-byte pad */
234157a8187dShastings memset(data->buf + xferlen, 0, MTW_DMA_PAD);
234257a8187dShastings xferlen += MTW_DMA_PAD;
234357a8187dShastings
234457a8187dShastings usbd_setup_xfer(data->xfer, ring->pipeh, data, data->buf,
234557a8187dShastings xferlen, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
234657a8187dShastings MTW_TX_TIMEOUT, mtw_txeof);
234757a8187dShastings error = usbd_transfer(data->xfer);
234857a8187dShastings if (__predict_false(error != USBD_IN_PROGRESS && error != 0))
234957a8187dShastings return error;
235057a8187dShastings
235157a8187dShastings ieee80211_release_node(ic, ni);
235257a8187dShastings
235357a8187dShastings ring->cur = (ring->cur + 1) % MTW_TX_RING_COUNT;
235457a8187dShastings if (++ring->queued >= MTW_TX_RING_COUNT)
235557a8187dShastings sc->qfullmsk |= 1 << qid;
235657a8187dShastings return 0;
235757a8187dShastings }
235857a8187dShastings
235957a8187dShastings void
mtw_start(struct ifnet * ifp)236057a8187dShastings mtw_start(struct ifnet *ifp)
236157a8187dShastings {
236257a8187dShastings struct mtw_softc *sc = ifp->if_softc;
236357a8187dShastings struct ieee80211com *ic = &sc->sc_ic;
236457a8187dShastings struct ieee80211_node *ni;
236557a8187dShastings struct mbuf *m;
236657a8187dShastings
236757a8187dShastings if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
236857a8187dShastings return;
236957a8187dShastings
237057a8187dShastings for (;;) {
237157a8187dShastings if (sc->qfullmsk != 0) {
237257a8187dShastings ifq_set_oactive(&ifp->if_snd);
237357a8187dShastings break;
237457a8187dShastings }
237557a8187dShastings
237657a8187dShastings /* send pending management frames first */
237757a8187dShastings m = mq_dequeue(&ic->ic_mgtq);
237857a8187dShastings if (m != NULL) {
237957a8187dShastings ni = m->m_pkthdr.ph_cookie;
238057a8187dShastings goto sendit;
238157a8187dShastings }
238257a8187dShastings if (ic->ic_state != IEEE80211_S_RUN)
238357a8187dShastings break;
238457a8187dShastings
238557a8187dShastings /* encapsulate and send data frames */
238657a8187dShastings m = ifq_dequeue(&ifp->if_snd);
238757a8187dShastings if (m == NULL)
238857a8187dShastings break;
238957a8187dShastings #if NBPFILTER > 0
239057a8187dShastings if (ifp->if_bpf != NULL)
239157a8187dShastings bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
239257a8187dShastings #endif
239357a8187dShastings if ((m = ieee80211_encap(ifp, m, &ni)) == NULL)
239457a8187dShastings continue;
239557a8187dShastings sendit:
239657a8187dShastings #if NBPFILTER > 0
239757a8187dShastings if (ic->ic_rawbpf != NULL)
239857a8187dShastings bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT);
239957a8187dShastings #endif
240057a8187dShastings if (mtw_tx(sc, m, ni) != 0) {
240157a8187dShastings ieee80211_release_node(ic, ni);
240257a8187dShastings ifp->if_oerrors++;
240357a8187dShastings continue;
240457a8187dShastings }
240557a8187dShastings
240657a8187dShastings sc->sc_tx_timer = 5;
240757a8187dShastings ifp->if_timer = 1;
240857a8187dShastings }
240957a8187dShastings }
241057a8187dShastings
241157a8187dShastings void
mtw_watchdog(struct ifnet * ifp)241257a8187dShastings mtw_watchdog(struct ifnet *ifp)
241357a8187dShastings {
241457a8187dShastings struct mtw_softc *sc = ifp->if_softc;
241557a8187dShastings
241657a8187dShastings ifp->if_timer = 0;
241757a8187dShastings
241857a8187dShastings if (sc->sc_tx_timer > 0) {
241957a8187dShastings if (--sc->sc_tx_timer == 0) {
242057a8187dShastings printf("%s: device timeout\n", sc->sc_dev.dv_xname);
242157a8187dShastings /* mtw_init(ifp); XXX needs a process context! */
242257a8187dShastings ifp->if_oerrors++;
242357a8187dShastings return;
242457a8187dShastings }
242557a8187dShastings ifp->if_timer = 1;
242657a8187dShastings }
242757a8187dShastings
242857a8187dShastings ieee80211_watchdog(ifp);
242957a8187dShastings }
243057a8187dShastings
243157a8187dShastings int
mtw_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data)243257a8187dShastings mtw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
243357a8187dShastings {
243457a8187dShastings struct mtw_softc *sc = ifp->if_softc;
243557a8187dShastings struct ieee80211com *ic = &sc->sc_ic;
243657a8187dShastings int s, error = 0;
243757a8187dShastings
243857a8187dShastings if (usbd_is_dying(sc->sc_udev))
243957a8187dShastings return ENXIO;
244057a8187dShastings
244157a8187dShastings usbd_ref_incr(sc->sc_udev);
244257a8187dShastings
244357a8187dShastings s = splnet();
244457a8187dShastings
244557a8187dShastings switch (cmd) {
244657a8187dShastings case SIOCSIFADDR:
244757a8187dShastings ifp->if_flags |= IFF_UP;
244857a8187dShastings /* FALLTHROUGH */
244957a8187dShastings case SIOCSIFFLAGS:
245057a8187dShastings if (ifp->if_flags & IFF_UP) {
245157a8187dShastings if (!(ifp->if_flags & IFF_RUNNING))
245257a8187dShastings mtw_init(ifp);
245357a8187dShastings } else {
245457a8187dShastings if (ifp->if_flags & IFF_RUNNING)
245557a8187dShastings mtw_stop(ifp, 1);
245657a8187dShastings }
245757a8187dShastings break;
245857a8187dShastings
245957a8187dShastings case SIOCS80211CHANNEL:
246057a8187dShastings /*
246157a8187dShastings * This allows for fast channel switching in monitor mode
246257a8187dShastings * (used by kismet).
246357a8187dShastings */
246457a8187dShastings error = ieee80211_ioctl(ifp, cmd, data);
246557a8187dShastings if (error == ENETRESET &&
246657a8187dShastings ic->ic_opmode == IEEE80211_M_MONITOR) {
246757a8187dShastings if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
246857a8187dShastings (IFF_UP | IFF_RUNNING))
246957a8187dShastings mtw_set_chan(sc, ic->ic_ibss_chan);
247057a8187dShastings error = 0;
247157a8187dShastings }
247257a8187dShastings break;
247357a8187dShastings
247457a8187dShastings default:
247557a8187dShastings error = ieee80211_ioctl(ifp, cmd, data);
247657a8187dShastings }
247757a8187dShastings
247857a8187dShastings if (error == ENETRESET) {
247957a8187dShastings if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
248057a8187dShastings (IFF_UP | IFF_RUNNING)) {
248157a8187dShastings mtw_stop(ifp, 0);
248257a8187dShastings error = mtw_init(ifp);
248357a8187dShastings } else
248457a8187dShastings error = 0;
248557a8187dShastings }
248657a8187dShastings splx(s);
248757a8187dShastings
248857a8187dShastings usbd_ref_decr(sc->sc_udev);
248957a8187dShastings
249057a8187dShastings return error;
249157a8187dShastings }
249257a8187dShastings
249357a8187dShastings void
mtw_select_chan_group(struct mtw_softc * sc,int group)249457a8187dShastings mtw_select_chan_group(struct mtw_softc *sc, int group)
249557a8187dShastings {
249657a8187dShastings uint32_t tmp;
249757a8187dShastings uint8_t bbp;
249857a8187dShastings
249957a8187dShastings /* Tx band 20MHz 2G */
250057a8187dShastings mtw_read(sc, MTW_TX_BAND_CFG, &tmp);
250157a8187dShastings tmp &= ~(MTW_TX_BAND_SEL_2G | MTW_TX_BAND_SEL_5G |
250257a8187dShastings MTW_TX_BAND_UPPER_40M);
250357a8187dShastings tmp |= (group == 0) ? MTW_TX_BAND_SEL_2G : MTW_TX_BAND_SEL_5G;
250457a8187dShastings mtw_write(sc, MTW_TX_BAND_CFG, tmp);
250557a8187dShastings
250657a8187dShastings /* select 20 MHz bandwidth */
250757a8187dShastings mtw_bbp_read(sc, 4, &bbp);
250857a8187dShastings bbp &= ~0x18;
250957a8187dShastings bbp |= 0x40;
251057a8187dShastings mtw_bbp_write(sc, 4, bbp);
251157a8187dShastings
251257a8187dShastings /* calibrate BBP */
251357a8187dShastings mtw_bbp_write(sc, 69, 0x12);
251457a8187dShastings mtw_bbp_write(sc, 91, 0x07);
251557a8187dShastings mtw_bbp_write(sc, 195, 0x23);
251657a8187dShastings mtw_bbp_write(sc, 196, 0x17);
251757a8187dShastings mtw_bbp_write(sc, 195, 0x24);
251857a8187dShastings mtw_bbp_write(sc, 196, 0x06);
251957a8187dShastings mtw_bbp_write(sc, 195, 0x81);
252057a8187dShastings mtw_bbp_write(sc, 196, 0x12);
252157a8187dShastings mtw_bbp_write(sc, 195, 0x83);
252257a8187dShastings mtw_bbp_write(sc, 196, 0x17);
252357a8187dShastings mtw_rf_write(sc, 5, 8, 0x00);
252457a8187dShastings mtw_mcu_calibrate(sc, 0x6, 0x10001);
252557a8187dShastings
252657a8187dShastings /* set initial AGC value */
252757a8187dShastings mt7601_set_agc(sc, 0x14);
252857a8187dShastings }
252957a8187dShastings
253057a8187dShastings void
mt7601_set_agc(struct mtw_softc * sc,uint8_t agc)253157a8187dShastings mt7601_set_agc(struct mtw_softc *sc, uint8_t agc)
253257a8187dShastings {
253357a8187dShastings uint8_t bbp;
253457a8187dShastings
253557a8187dShastings mtw_bbp_write(sc, 66, agc);
253657a8187dShastings mtw_bbp_write(sc, 195, 0x87);
253757a8187dShastings bbp = (agc & 0xf0) | 0x08;
253857a8187dShastings mtw_bbp_write(sc, 196, bbp);
253957a8187dShastings }
254057a8187dShastings
254157a8187dShastings void
mt7601_set_chan(struct mtw_softc * sc,u_int chan)254257a8187dShastings mt7601_set_chan(struct mtw_softc *sc, u_int chan)
254357a8187dShastings {
254457a8187dShastings uint32_t tmp;
254557a8187dShastings uint8_t bbp, rf, txpow1;
254657a8187dShastings int i;
254757a8187dShastings
254857a8187dShastings /* find the settings for this channel */
254936dba039Sjsg for (i = 0; mt7601_rf_chan[i].chan != chan; i++)
255036dba039Sjsg ;
255157a8187dShastings
255257a8187dShastings mtw_rf_write(sc, 0, 17, mt7601_rf_chan[i].r17);
255357a8187dShastings mtw_rf_write(sc, 0, 18, mt7601_rf_chan[i].r18);
255457a8187dShastings mtw_rf_write(sc, 0, 19, mt7601_rf_chan[i].r19);
255557a8187dShastings mtw_rf_write(sc, 0, 20, mt7601_rf_chan[i].r20);
255657a8187dShastings
255757a8187dShastings /* use Tx power values from EEPROM */
255857a8187dShastings txpow1 = sc->txpow1[i];
255957a8187dShastings
256057a8187dShastings /* Tx automatic level control */
256157a8187dShastings mtw_read(sc, MTW_TX_ALC_CFG0, &tmp);
256257a8187dShastings tmp &= ~0x3f3f;
256357a8187dShastings tmp |= (txpow1 & 0x3f);
256457a8187dShastings mtw_write(sc, MTW_TX_ALC_CFG0, tmp);
256557a8187dShastings
256657a8187dShastings /* LNA */
256757a8187dShastings mtw_bbp_write(sc, 62, 0x37 - sc->lna[0]);
256857a8187dShastings mtw_bbp_write(sc, 63, 0x37 - sc->lna[0]);
256957a8187dShastings mtw_bbp_write(sc, 64, 0x37 - sc->lna[0]);
257057a8187dShastings
257157a8187dShastings /* VCO calibration */
257257a8187dShastings mtw_rf_write(sc, 0, 4, 0x0a);
257357a8187dShastings mtw_rf_write(sc, 0, 5, 0x20);
257457a8187dShastings mtw_rf_read(sc, 0, 4, &rf);
257557a8187dShastings mtw_rf_write(sc, 0, 4, rf | 0x80);
257657a8187dShastings
257757a8187dShastings /* select 20 MHz bandwidth */
257857a8187dShastings mtw_bbp_read(sc, 4, &bbp);
257957a8187dShastings bbp &= ~0x18;
258057a8187dShastings bbp |= 0x40;
258157a8187dShastings mtw_bbp_write(sc, 4, bbp);
258257a8187dShastings mtw_bbp_write(sc, 178, 0xff);
258357a8187dShastings }
258457a8187dShastings
258557a8187dShastings int
mtw_set_chan(struct mtw_softc * sc,struct ieee80211_channel * c)258657a8187dShastings mtw_set_chan(struct mtw_softc *sc, struct ieee80211_channel *c)
258757a8187dShastings {
258857a8187dShastings struct ieee80211com *ic = &sc->sc_ic;
258957a8187dShastings u_int chan, group;
259057a8187dShastings
259157a8187dShastings chan = ieee80211_chan2ieee(ic, c);
259257a8187dShastings if (chan == 0 || chan == IEEE80211_CHAN_ANY)
259357a8187dShastings return EINVAL;
259457a8187dShastings
259557a8187dShastings /* determine channel group */
259657a8187dShastings if (chan <= 14)
259757a8187dShastings group = 0;
259857a8187dShastings else if (chan <= 64)
259957a8187dShastings group = 1;
260057a8187dShastings else if (chan <= 128)
260157a8187dShastings group = 2;
260257a8187dShastings else
260357a8187dShastings group = 3;
260457a8187dShastings
260557a8187dShastings if (group != sc->sc_chan_group || !sc->sc_bw_calibrated)
260657a8187dShastings mtw_select_chan_group(sc, group);
260757a8187dShastings
260857a8187dShastings sc->sc_chan_group = group;
260957a8187dShastings
261057a8187dShastings /* chipset specific */
261157a8187dShastings if (sc->mac_ver == 0x7601)
261257a8187dShastings mt7601_set_chan(sc, chan);
261357a8187dShastings
261457a8187dShastings DELAY(1000);
261557a8187dShastings return 0;
261657a8187dShastings }
261757a8187dShastings
261857a8187dShastings void
mtw_enable_tsf_sync(struct mtw_softc * sc)261957a8187dShastings mtw_enable_tsf_sync(struct mtw_softc *sc)
262057a8187dShastings {
262157a8187dShastings struct ieee80211com *ic = &sc->sc_ic;
262257a8187dShastings uint32_t tmp;
262357a8187dShastings
262457a8187dShastings mtw_read(sc, MTW_BCN_TIME_CFG, &tmp);
262557a8187dShastings tmp &= ~0x1fffff;
262657a8187dShastings tmp |= ic->ic_bss->ni_intval * 16;
262757a8187dShastings tmp |= MTW_TSF_TIMER_EN | MTW_TBTT_TIMER_EN;
262857a8187dShastings
262957a8187dShastings /* local TSF is always updated with remote TSF on beacon reception */
263057a8187dShastings tmp |= 1 << MTW_TSF_SYNC_MODE_SHIFT;
263157a8187dShastings mtw_write(sc, MTW_BCN_TIME_CFG, tmp);
263257a8187dShastings }
263357a8187dShastings
263457a8187dShastings void
mtw_abort_tsf_sync(struct mtw_softc * sc)263557a8187dShastings mtw_abort_tsf_sync(struct mtw_softc *sc)
263657a8187dShastings {
263757a8187dShastings uint32_t tmp;
263857a8187dShastings
263957a8187dShastings mtw_read(sc, MTW_BCN_TIME_CFG, &tmp);
264057a8187dShastings tmp &= ~(MTW_BCN_TX_EN | MTW_TSF_TIMER_EN | MTW_TBTT_TIMER_EN);
264157a8187dShastings mtw_write(sc, MTW_BCN_TIME_CFG, tmp);
264257a8187dShastings }
264357a8187dShastings
264457a8187dShastings void
mtw_enable_mrr(struct mtw_softc * sc)264557a8187dShastings mtw_enable_mrr(struct mtw_softc *sc)
264657a8187dShastings {
264757a8187dShastings #define CCK(mcs) (mcs)
264857a8187dShastings #define OFDM(mcs) (1 << 3 | (mcs))
264957a8187dShastings mtw_write(sc, MTW_LG_FBK_CFG0,
265057a8187dShastings OFDM(6) << 28 | /* 54->48 */
265157a8187dShastings OFDM(5) << 24 | /* 48->36 */
265257a8187dShastings OFDM(4) << 20 | /* 36->24 */
265357a8187dShastings OFDM(3) << 16 | /* 24->18 */
265457a8187dShastings OFDM(2) << 12 | /* 18->12 */
265557a8187dShastings OFDM(1) << 8 | /* 12-> 9 */
265657a8187dShastings OFDM(0) << 4 | /* 9-> 6 */
265757a8187dShastings OFDM(0)); /* 6-> 6 */
265857a8187dShastings
265957a8187dShastings mtw_write(sc, MTW_LG_FBK_CFG1,
266057a8187dShastings CCK(2) << 12 | /* 11->5.5 */
266157a8187dShastings CCK(1) << 8 | /* 5.5-> 2 */
266257a8187dShastings CCK(0) << 4 | /* 2-> 1 */
266357a8187dShastings CCK(0)); /* 1-> 1 */
266457a8187dShastings #undef OFDM
266557a8187dShastings #undef CCK
266657a8187dShastings }
266757a8187dShastings
266857a8187dShastings void
mtw_set_txrts(struct mtw_softc * sc)266957a8187dShastings mtw_set_txrts(struct mtw_softc *sc)
267057a8187dShastings {
267157a8187dShastings uint32_t tmp;
267257a8187dShastings
267357a8187dShastings /* set RTS threshold */
267457a8187dShastings mtw_read(sc, MTW_TX_RTS_CFG, &tmp);
267557a8187dShastings tmp &= ~0xffff00;
267657a8187dShastings tmp |= 0x1000 << MTW_RTS_THRES_SHIFT;
267757a8187dShastings mtw_write(sc, MTW_TX_RTS_CFG, tmp);
267857a8187dShastings }
267957a8187dShastings
268057a8187dShastings void
mtw_set_txpreamble(struct mtw_softc * sc)268157a8187dShastings mtw_set_txpreamble(struct mtw_softc *sc)
268257a8187dShastings {
268357a8187dShastings uint32_t tmp;
268457a8187dShastings
268557a8187dShastings mtw_read(sc, MTW_AUTO_RSP_CFG, &tmp);
268657a8187dShastings if (sc->sc_ic.ic_flags & IEEE80211_F_SHPREAMBLE)
268757a8187dShastings tmp |= MTW_CCK_SHORT_EN;
268857a8187dShastings else
268957a8187dShastings tmp &= ~MTW_CCK_SHORT_EN;
269057a8187dShastings mtw_write(sc, MTW_AUTO_RSP_CFG, tmp);
269157a8187dShastings }
269257a8187dShastings
269357a8187dShastings void
mtw_set_basicrates(struct mtw_softc * sc)269457a8187dShastings mtw_set_basicrates(struct mtw_softc *sc)
269557a8187dShastings {
269657a8187dShastings struct ieee80211com *ic = &sc->sc_ic;
269757a8187dShastings
269857a8187dShastings /* set basic rates mask */
269957a8187dShastings if (ic->ic_curmode == IEEE80211_MODE_11B)
270057a8187dShastings mtw_write(sc, MTW_LEGACY_BASIC_RATE, 0x003);
270157a8187dShastings else if (ic->ic_curmode == IEEE80211_MODE_11A)
270257a8187dShastings mtw_write(sc, MTW_LEGACY_BASIC_RATE, 0x150);
270357a8187dShastings else /* 11g */
270457a8187dShastings mtw_write(sc, MTW_LEGACY_BASIC_RATE, 0x17f);
270557a8187dShastings }
270657a8187dShastings
270757a8187dShastings void
mtw_set_leds(struct mtw_softc * sc,uint16_t which)270857a8187dShastings mtw_set_leds(struct mtw_softc *sc, uint16_t which)
270957a8187dShastings {
271057a8187dShastings struct mtw_mcu_cmd_8 cmd;
271157a8187dShastings
271257a8187dShastings cmd.func = htole32(0x1);
271357a8187dShastings cmd.val = htole32(which);
271457a8187dShastings mtw_mcu_cmd(sc, 16, &cmd, sizeof(struct mtw_mcu_cmd_8));
271557a8187dShastings }
271657a8187dShastings
271757a8187dShastings void
mtw_set_bssid(struct mtw_softc * sc,const uint8_t * bssid)271857a8187dShastings mtw_set_bssid(struct mtw_softc *sc, const uint8_t *bssid)
271957a8187dShastings {
272057a8187dShastings mtw_write(sc, MTW_MAC_BSSID_DW0,
272157a8187dShastings bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24);
272257a8187dShastings mtw_write(sc, MTW_MAC_BSSID_DW1,
272357a8187dShastings bssid[4] | bssid[5] << 8);
272457a8187dShastings }
272557a8187dShastings
272657a8187dShastings void
mtw_set_macaddr(struct mtw_softc * sc,const uint8_t * addr)272757a8187dShastings mtw_set_macaddr(struct mtw_softc *sc, const uint8_t *addr)
272857a8187dShastings {
272957a8187dShastings mtw_write(sc, MTW_MAC_ADDR_DW0,
273057a8187dShastings addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24);
273157a8187dShastings mtw_write(sc, MTW_MAC_ADDR_DW1,
273257a8187dShastings addr[4] | addr[5] << 8 | 0xff << 16);
273357a8187dShastings }
273457a8187dShastings
273557a8187dShastings #if NBPFILTER > 0
273657a8187dShastings int8_t
mtw_rssi2dbm(struct mtw_softc * sc,uint8_t rssi,uint8_t rxchain)273757a8187dShastings mtw_rssi2dbm(struct mtw_softc *sc, uint8_t rssi, uint8_t rxchain)
273857a8187dShastings {
273957a8187dShastings struct ieee80211com *ic = &sc->sc_ic;
274057a8187dShastings struct ieee80211_channel *c = ic->ic_ibss_chan;
274157a8187dShastings int delta;
274257a8187dShastings
274357a8187dShastings if (IEEE80211_IS_CHAN_5GHZ(c)) {
274457a8187dShastings u_int chan = ieee80211_chan2ieee(ic, c);
274557a8187dShastings delta = sc->rssi_5ghz[rxchain];
274657a8187dShastings
274757a8187dShastings /* determine channel group */
274857a8187dShastings if (chan <= 64)
274957a8187dShastings delta -= sc->lna[1];
275057a8187dShastings else if (chan <= 128)
275157a8187dShastings delta -= sc->lna[2];
275257a8187dShastings else
275357a8187dShastings delta -= sc->lna[3];
275457a8187dShastings } else
275557a8187dShastings delta = sc->rssi_2ghz[rxchain] - sc->lna[0];
275657a8187dShastings
275757a8187dShastings return -12 - delta - rssi;
275857a8187dShastings }
275957a8187dShastings #endif
276057a8187dShastings
276157a8187dShastings int
mt7601_bbp_init(struct mtw_softc * sc)276257a8187dShastings mt7601_bbp_init(struct mtw_softc *sc)
276357a8187dShastings {
276457a8187dShastings uint8_t bbp;
276557a8187dShastings int i, error, ntries;
276657a8187dShastings
276757a8187dShastings /* wait for BBP to wake up */
276857a8187dShastings for (ntries = 0; ntries < 20; ntries++) {
276957a8187dShastings if ((error = mtw_bbp_read(sc, 0, &bbp)) != 0)
277057a8187dShastings return error;
277157a8187dShastings if (bbp != 0 && bbp != 0xff)
277257a8187dShastings break;
277357a8187dShastings }
277457a8187dShastings
277557a8187dShastings if (ntries == 20)
277657a8187dShastings return ETIMEDOUT;
277757a8187dShastings
277857a8187dShastings mtw_bbp_read(sc, 3, &bbp);
277957a8187dShastings mtw_bbp_write(sc, 3, 0);
278057a8187dShastings mtw_bbp_read(sc, 105, &bbp);
278157a8187dShastings mtw_bbp_write(sc, 105, 0);
278257a8187dShastings
278357a8187dShastings /* initialize BBP registers to default values */
278457a8187dShastings for (i = 0; i < nitems(mt7601_def_bbp); i++) {
278557a8187dShastings if ((error = mtw_bbp_write(sc, mt7601_def_bbp[i].reg,
278657a8187dShastings mt7601_def_bbp[i].val)) != 0)
278757a8187dShastings return error;
278857a8187dShastings }
278957a8187dShastings
279057a8187dShastings sc->sc_bw_calibrated = 0;
279157a8187dShastings
279257a8187dShastings return 0;
279357a8187dShastings }
279457a8187dShastings
279557a8187dShastings int
mt7601_rf_init(struct mtw_softc * sc)279657a8187dShastings mt7601_rf_init(struct mtw_softc *sc)
279757a8187dShastings {
279857a8187dShastings int i, error;
279957a8187dShastings
280057a8187dShastings /* RF bank 0 */
280157a8187dShastings for (i = 0; i < nitems(mt7601_rf_bank0); i++) {
280257a8187dShastings error = mtw_rf_write(sc, 0, mt7601_rf_bank0[i].reg,
280357a8187dShastings mt7601_rf_bank0[i].val);
280457a8187dShastings if (error != 0)
280557a8187dShastings return error;
280657a8187dShastings }
280757a8187dShastings /* RF bank 4 */
280857a8187dShastings for (i = 0; i < nitems(mt7601_rf_bank4); i++) {
280957a8187dShastings error = mtw_rf_write(sc, 4, mt7601_rf_bank4[i].reg,
281057a8187dShastings mt7601_rf_bank4[i].val);
281157a8187dShastings if (error != 0)
281257a8187dShastings return error;
281357a8187dShastings }
281457a8187dShastings /* RF bank 5 */
281557a8187dShastings for (i = 0; i < nitems(mt7601_rf_bank5); i++) {
281657a8187dShastings error = mtw_rf_write(sc, 5, mt7601_rf_bank5[i].reg,
281757a8187dShastings mt7601_rf_bank5[i].val);
281857a8187dShastings if (error != 0)
281957a8187dShastings return error;
282057a8187dShastings }
282157a8187dShastings return 0;
282257a8187dShastings }
282357a8187dShastings
282457a8187dShastings int
mt7601_rf_setup(struct mtw_softc * sc)282557a8187dShastings mt7601_rf_setup(struct mtw_softc *sc)
282657a8187dShastings {
282757a8187dShastings uint32_t tmp;
282857a8187dShastings uint8_t rf;
282957a8187dShastings int error;
283057a8187dShastings
283157a8187dShastings if (sc->sc_rf_calibrated)
283257a8187dShastings return 0;
283357a8187dShastings
283457a8187dShastings /* init RF registers */
283557a8187dShastings if ((error = mt7601_rf_init(sc)) != 0)
283657a8187dShastings return error;
283757a8187dShastings
283857a8187dShastings /* init frequency offset */
283957a8187dShastings mtw_rf_write(sc, 0, 12, sc->rf_freq_offset);
284057a8187dShastings mtw_rf_read(sc, 0, 12, &rf);
284157a8187dShastings
284257a8187dShastings /* read temperature */
284357a8187dShastings mt7601_rf_temperature(sc, &rf);
284457a8187dShastings sc->bbp_temp = rf;
284557a8187dShastings DPRINTF(("BBP temp 0x%x ", rf));
284657a8187dShastings
284757a8187dShastings mtw_rf_read(sc, 0, 7, &rf);
284857a8187dShastings if ((error = mtw_mcu_calibrate(sc, 0x1, 0)) != 0)
284957a8187dShastings return error;
285057a8187dShastings usbd_delay_ms(sc->sc_udev, 100);
285157a8187dShastings mtw_rf_read(sc, 0, 7, &rf);
285257a8187dShastings
285357a8187dShastings /* Calibrate VCO RF 0/4 */
285457a8187dShastings mtw_rf_write(sc, 0, 4, 0x0a);
285557a8187dShastings mtw_rf_write(sc, 0, 4, 0x20);
285657a8187dShastings mtw_rf_read(sc, 0, 4, &rf);
285757a8187dShastings mtw_rf_write(sc, 0, 4, rf | 0x80);
285857a8187dShastings
285957a8187dShastings if ((error = mtw_mcu_calibrate(sc, 0x9, 0)) != 0)
286057a8187dShastings return error;
286157a8187dShastings if ((error = mt7601_rxdc_cal(sc)) != 0)
286257a8187dShastings return error;
286357a8187dShastings if ((error = mtw_mcu_calibrate(sc, 0x6, 1)) != 0)
286457a8187dShastings return error;
286557a8187dShastings if ((error = mtw_mcu_calibrate(sc, 0x6, 0)) != 0)
286657a8187dShastings return error;
286757a8187dShastings if ((error = mtw_mcu_calibrate(sc, 0x4, 0)) != 0)
286857a8187dShastings return error;
286957a8187dShastings if ((error = mtw_mcu_calibrate(sc, 0x5, 0)) != 0)
287057a8187dShastings return error;
287157a8187dShastings
287257a8187dShastings mtw_read(sc, MTW_LDO_CFG0, &tmp);
287357a8187dShastings tmp &= ~(1 << 4);
287457a8187dShastings tmp |= (1 << 2);
287557a8187dShastings mtw_write(sc, MTW_LDO_CFG0, tmp);
287657a8187dShastings
287757a8187dShastings if ((error = mtw_mcu_calibrate(sc, 0x8, 0)) != 0)
287857a8187dShastings return error;
287957a8187dShastings if ((error = mt7601_rxdc_cal(sc)) != 0)
288057a8187dShastings return error;
288157a8187dShastings
288257a8187dShastings sc->sc_rf_calibrated = 1;
288357a8187dShastings return 0;
288457a8187dShastings }
288557a8187dShastings
288657a8187dShastings int
mt7601_rf_temperature(struct mtw_softc * sc,int8_t * val)288757a8187dShastings mt7601_rf_temperature(struct mtw_softc *sc, int8_t *val)
288857a8187dShastings {
288957a8187dShastings uint32_t rfb, rfs;
289057a8187dShastings uint8_t bbp;
289157a8187dShastings int ntries;
289257a8187dShastings
289357a8187dShastings mtw_read(sc, MTW_RF_BYPASS0, &rfb);
289457a8187dShastings mtw_read(sc, MTW_RF_SETTING0, &rfs);
289557a8187dShastings mtw_write(sc, MTW_RF_BYPASS0, 0);
289657a8187dShastings mtw_write(sc, MTW_RF_SETTING0, 0x10);
289757a8187dShastings mtw_write(sc, MTW_RF_BYPASS0, 0x10);
289857a8187dShastings
289957a8187dShastings mtw_bbp_read(sc, 47, &bbp);
290057a8187dShastings bbp &= ~0x7f;
290157a8187dShastings bbp |= 0x10;
290257a8187dShastings mtw_bbp_write(sc, 47, bbp);
290357a8187dShastings
290457a8187dShastings mtw_bbp_write(sc, 22, 0x40);
290557a8187dShastings
290657a8187dShastings for (ntries = 0; ntries < 10; ntries++) {
290757a8187dShastings mtw_bbp_read(sc, 47, &bbp);
290857a8187dShastings if ((bbp & 0x10) == 0)
290957a8187dShastings break;
291057a8187dShastings }
291157a8187dShastings if (ntries == 10)
291257a8187dShastings return ETIMEDOUT;
291357a8187dShastings
291457a8187dShastings mt7601_r49_read(sc, MT7601_R47_TEMP, val);
291557a8187dShastings
291657a8187dShastings mtw_bbp_write(sc, 22, 0);
291757a8187dShastings
291857a8187dShastings mtw_bbp_read(sc, 21, &bbp);
291957a8187dShastings bbp |= 0x02;
292057a8187dShastings mtw_bbp_write(sc, 21, bbp);
292157a8187dShastings bbp &= ~0x02;
292257a8187dShastings mtw_bbp_write(sc, 21, bbp);
292357a8187dShastings
292457a8187dShastings mtw_write(sc, MTW_RF_BYPASS0, 0);
292557a8187dShastings mtw_write(sc, MTW_RF_SETTING0, rfs);
292657a8187dShastings mtw_write(sc, MTW_RF_BYPASS0, rfb);
292757a8187dShastings return 0;
292857a8187dShastings }
292957a8187dShastings
293057a8187dShastings int
mt7601_r49_read(struct mtw_softc * sc,uint8_t flag,int8_t * val)293157a8187dShastings mt7601_r49_read(struct mtw_softc *sc, uint8_t flag, int8_t *val)
293257a8187dShastings {
293357a8187dShastings uint8_t bbp;
293457a8187dShastings
293557a8187dShastings mtw_bbp_read(sc, 47, &bbp);
293657a8187dShastings bbp = 0x90;
293757a8187dShastings mtw_bbp_write(sc, 47, bbp);
293857a8187dShastings bbp &= ~0x0f;
293957a8187dShastings bbp |= flag;
294057a8187dShastings mtw_bbp_write(sc, 47, bbp);
294157a8187dShastings return mtw_bbp_read(sc, 49, val);
294257a8187dShastings }
294357a8187dShastings
294457a8187dShastings int
mt7601_rxdc_cal(struct mtw_softc * sc)294557a8187dShastings mt7601_rxdc_cal(struct mtw_softc *sc)
294657a8187dShastings {
294757a8187dShastings uint32_t tmp;
294857a8187dShastings uint8_t bbp;
294957a8187dShastings int ntries;
295057a8187dShastings
295157a8187dShastings mtw_read(sc, MTW_MAC_SYS_CTRL, &tmp);
295257a8187dShastings mtw_write(sc, MTW_MAC_SYS_CTRL, MTW_MAC_RX_EN);
295357a8187dShastings mtw_bbp_write(sc, 158, 0x8d);
295457a8187dShastings mtw_bbp_write(sc, 159, 0xfc);
295557a8187dShastings mtw_bbp_write(sc, 158, 0x8c);
295657a8187dShastings mtw_bbp_write(sc, 159, 0x4c);
295757a8187dShastings
295857a8187dShastings for (ntries = 0; ntries < 20; ntries++) {
295957a8187dShastings DELAY(300);
296057a8187dShastings mtw_bbp_write(sc, 158, 0x8c);
296157a8187dShastings mtw_bbp_read(sc, 159, &bbp);
296257a8187dShastings if (bbp == 0x0c)
296357a8187dShastings break;
296457a8187dShastings }
296557a8187dShastings
296657a8187dShastings if (ntries == 20)
296757a8187dShastings return ETIMEDOUT;
296857a8187dShastings
296957a8187dShastings mtw_write(sc, MTW_MAC_SYS_CTRL, 0);
297057a8187dShastings mtw_bbp_write(sc, 158, 0x8d);
297157a8187dShastings mtw_bbp_write(sc, 159, 0xe0);
297257a8187dShastings mtw_write(sc, MTW_MAC_SYS_CTRL, tmp);
297357a8187dShastings return 0;
297457a8187dShastings }
297557a8187dShastings
297657a8187dShastings int
mtw_wlan_enable(struct mtw_softc * sc,int enable)297757a8187dShastings mtw_wlan_enable(struct mtw_softc *sc, int enable)
297857a8187dShastings {
297957a8187dShastings uint32_t tmp;
298057a8187dShastings int error = 0;
298157a8187dShastings
298257a8187dShastings if (enable) {
298357a8187dShastings mtw_read(sc, MTW_WLAN_CTRL, &tmp);
298457a8187dShastings if (sc->asic_ver == 0x7612)
298557a8187dShastings tmp &= ~0xfffff000;
298657a8187dShastings
298757a8187dShastings tmp &= ~MTW_WLAN_CLK_EN;
298857a8187dShastings tmp |= MTW_WLAN_EN;
298957a8187dShastings mtw_write(sc, MTW_WLAN_CTRL, tmp);
299057a8187dShastings usbd_delay_ms(sc->sc_udev, 2);
299157a8187dShastings
299257a8187dShastings tmp |= MTW_WLAN_CLK_EN;
299357a8187dShastings if (sc->asic_ver == 0x7612) {
299457a8187dShastings tmp |= (MTW_WLAN_RESET | MTW_WLAN_RESET_RF);
299557a8187dShastings }
299657a8187dShastings mtw_write(sc, MTW_WLAN_CTRL, tmp);
299757a8187dShastings usbd_delay_ms(sc->sc_udev, 2);
299857a8187dShastings
299957a8187dShastings mtw_read(sc, MTW_OSC_CTRL, &tmp);
300057a8187dShastings tmp |= MTW_OSC_EN;
300157a8187dShastings mtw_write(sc, MTW_OSC_CTRL, tmp);
300257a8187dShastings tmp |= MTW_OSC_CAL_REQ;
300357a8187dShastings mtw_write(sc, MTW_OSC_CTRL, tmp);
300457a8187dShastings } else {
300557a8187dShastings mtw_read(sc, MTW_WLAN_CTRL, &tmp);
300657a8187dShastings tmp &= ~(MTW_WLAN_CLK_EN | MTW_WLAN_EN);
300757a8187dShastings mtw_write(sc, MTW_WLAN_CTRL, tmp);
300857a8187dShastings
300957a8187dShastings mtw_read(sc, MTW_OSC_CTRL, &tmp);
301057a8187dShastings tmp &= ~MTW_OSC_EN;
301157a8187dShastings mtw_write(sc, MTW_OSC_CTRL, tmp);
301257a8187dShastings }
301357a8187dShastings return error;
301457a8187dShastings }
301557a8187dShastings
301657a8187dShastings int
mtw_txrx_enable(struct mtw_softc * sc)301757a8187dShastings mtw_txrx_enable(struct mtw_softc *sc)
301857a8187dShastings {
301957a8187dShastings uint32_t tmp;
302057a8187dShastings int error, ntries;
302157a8187dShastings
302257a8187dShastings mtw_write(sc, MTW_MAC_SYS_CTRL, MTW_MAC_TX_EN);
302357a8187dShastings for (ntries = 0; ntries < 200; ntries++) {
302457a8187dShastings if ((error = mtw_read(sc, MTW_WPDMA_GLO_CFG, &tmp)) != 0)
302557a8187dShastings return error;
302657a8187dShastings if ((tmp & (MTW_TX_DMA_BUSY | MTW_RX_DMA_BUSY)) == 0)
302757a8187dShastings break;
302857a8187dShastings DELAY(1000);
302957a8187dShastings }
303057a8187dShastings if (ntries == 200)
303157a8187dShastings return ETIMEDOUT;
303257a8187dShastings
303357a8187dShastings DELAY(50);
303457a8187dShastings
303557a8187dShastings tmp |= MTW_RX_DMA_EN | MTW_TX_DMA_EN | MTW_TX_WB_DDONE;
303657a8187dShastings mtw_write(sc, MTW_WPDMA_GLO_CFG, tmp);
303757a8187dShastings
303857a8187dShastings /* enable Rx bulk aggregation (set timeout and limit) */
303957a8187dShastings tmp = MTW_USB_TX_EN | MTW_USB_RX_EN | MTW_USB_RX_AGG_EN |
304057a8187dShastings MTW_USB_RX_AGG_TO(128) | MTW_USB_RX_AGG_LMT(2);
304157a8187dShastings mtw_write(sc, MTW_USB_DMA_CFG, tmp);
304257a8187dShastings
304357a8187dShastings /* set Rx filter */
304457a8187dShastings tmp = MTW_DROP_CRC_ERR | MTW_DROP_PHY_ERR;
304557a8187dShastings if (sc->sc_ic.ic_opmode != IEEE80211_M_MONITOR) {
304657a8187dShastings tmp |= MTW_DROP_UC_NOME | MTW_DROP_DUPL |
304757a8187dShastings MTW_DROP_CTS | MTW_DROP_BA | MTW_DROP_ACK |
304857a8187dShastings MTW_DROP_VER_ERR | MTW_DROP_CTRL_RSV |
304957a8187dShastings MTW_DROP_CFACK | MTW_DROP_CFEND;
305057a8187dShastings if (sc->sc_ic.ic_opmode == IEEE80211_M_STA)
305157a8187dShastings tmp |= MTW_DROP_RTS | MTW_DROP_PSPOLL;
305257a8187dShastings }
305357a8187dShastings mtw_write(sc, MTW_RX_FILTR_CFG, tmp);
305457a8187dShastings
305557a8187dShastings mtw_write(sc, MTW_MAC_SYS_CTRL,
305657a8187dShastings MTW_MAC_RX_EN | MTW_MAC_TX_EN);
305757a8187dShastings return 0;
305857a8187dShastings }
305957a8187dShastings
306057a8187dShastings int
mtw_init(struct ifnet * ifp)306157a8187dShastings mtw_init(struct ifnet *ifp)
306257a8187dShastings {
306357a8187dShastings struct mtw_softc *sc = ifp->if_softc;
306457a8187dShastings struct ieee80211com *ic = &sc->sc_ic;
306557a8187dShastings uint32_t tmp;
306657a8187dShastings int i, error, ridx, ntries, qid;
306757a8187dShastings
306857a8187dShastings if (usbd_is_dying(sc->sc_udev))
306957a8187dShastings return ENXIO;
307057a8187dShastings
307157a8187dShastings /* init Tx rings (4 EDCAs, 1 HCCA, 1 MGMT) */
307257a8187dShastings for (qid = 0; qid < MTW_TXQ_COUNT; qid++) {
307357a8187dShastings if ((error = mtw_alloc_tx_ring(sc, qid)) != 0)
307457a8187dShastings goto fail;
307557a8187dShastings }
307657a8187dShastings
307757a8187dShastings /* init Rx ring */
307857a8187dShastings if ((error = mtw_alloc_rx_ring(sc, 0)) != 0)
307957a8187dShastings goto fail;
308057a8187dShastings
308157a8187dShastings /* init MCU Tx ring */
308257a8187dShastings if ((error = mtw_alloc_mcu_ring(sc)) != 0)
308357a8187dShastings goto fail;
308457a8187dShastings
308557a8187dShastings /* init host command ring */
308657a8187dShastings sc->cmdq.cur = sc->cmdq.next = sc->cmdq.queued = 0;
308757a8187dShastings
308857a8187dShastings for (ntries = 0; ntries < 100; ntries++) {
308957a8187dShastings if ((error = mtw_read(sc, MTW_WPDMA_GLO_CFG, &tmp)) != 0)
309057a8187dShastings goto fail;
309157a8187dShastings if ((tmp & (MTW_TX_DMA_BUSY | MTW_RX_DMA_BUSY)) == 0)
309257a8187dShastings break;
309357a8187dShastings DELAY(1000);
309457a8187dShastings }
309557a8187dShastings if (ntries == 100) {
309657a8187dShastings printf("%s: timeout waiting for DMA engine\n",
309757a8187dShastings sc->sc_dev.dv_xname);
309857a8187dShastings error = ETIMEDOUT;
309957a8187dShastings goto fail;
310057a8187dShastings }
310157a8187dShastings tmp &= 0xff0;
310257a8187dShastings tmp |= MTW_TX_WB_DDONE;
310357a8187dShastings mtw_write(sc, MTW_WPDMA_GLO_CFG, tmp);
310457a8187dShastings
310557a8187dShastings /* reset MAC and baseband */
310657a8187dShastings mtw_write(sc, MTW_MAC_SYS_CTRL, MTW_BBP_HRST | MTW_MAC_SRST);
310757a8187dShastings mtw_write(sc, MTW_USB_DMA_CFG, 0);
310857a8187dShastings mtw_write(sc, MTW_MAC_SYS_CTRL, 0);
310957a8187dShastings
311057a8187dShastings /* init MAC values */
311157a8187dShastings if (sc->mac_ver == 0x7601) {
311257a8187dShastings for (i = 0; i < nitems(mt7601_def_mac); i++)
311357a8187dShastings mtw_write(sc, mt7601_def_mac[i].reg,
311457a8187dShastings mt7601_def_mac[i].val);
311557a8187dShastings }
311657a8187dShastings
311757a8187dShastings /* wait while MAC is busy */
311857a8187dShastings for (ntries = 0; ntries < 100; ntries++) {
311957a8187dShastings if ((error = mtw_read(sc, MTW_MAC_STATUS_REG, &tmp)) != 0)
312057a8187dShastings goto fail;
312157a8187dShastings if (!(tmp & (MTW_RX_STATUS_BUSY | MTW_TX_STATUS_BUSY)))
312257a8187dShastings break;
312357a8187dShastings DELAY(1000);
312457a8187dShastings }
312557a8187dShastings if (ntries == 100) {
312657a8187dShastings error = ETIMEDOUT;
312757a8187dShastings goto fail;
312857a8187dShastings }
312957a8187dShastings
313057a8187dShastings /* set MAC address */
313157a8187dShastings IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
313257a8187dShastings mtw_set_macaddr(sc, ic->ic_myaddr);
313357a8187dShastings
313457a8187dShastings /* clear WCID attribute table */
313557a8187dShastings mtw_set_region_4(sc, MTW_WCID_ATTR(0), 1, 8 * 32);
313657a8187dShastings
313757a8187dShastings mtw_write(sc, 0x1648, 0x00830083);
313857a8187dShastings mtw_read(sc, MTW_FCE_L2_STUFF, &tmp);
313957a8187dShastings tmp &= ~MTW_L2S_WR_MPDU_LEN_EN;
314057a8187dShastings mtw_write(sc, MTW_FCE_L2_STUFF, tmp);
314157a8187dShastings
314257a8187dShastings /* RTS config */
314357a8187dShastings mtw_set_txrts(sc);
314457a8187dShastings
314557a8187dShastings /* clear Host to MCU mailbox */
314657a8187dShastings mtw_write(sc, MTW_BBP_CSR, 0);
314757a8187dShastings mtw_write(sc, MTW_H2M_MAILBOX, 0);
314857a8187dShastings
314957a8187dShastings /* clear RX WCID search table */
315057a8187dShastings mtw_set_region_4(sc, MTW_WCID_ENTRY(0), 0xffffffff, 512);
315157a8187dShastings
315257a8187dShastings /* abort TSF synchronization */
315357a8187dShastings mtw_abort_tsf_sync(sc);
315457a8187dShastings
315557a8187dShastings mtw_read(sc, MTW_US_CYC_CNT, &tmp);
315657a8187dShastings tmp = (tmp & ~0xff);
315757a8187dShastings if (sc->mac_ver == 0x7601)
315857a8187dShastings tmp |= 0x1e;
315957a8187dShastings mtw_write(sc, MTW_US_CYC_CNT, tmp);
316057a8187dShastings
316157a8187dShastings /* clear shared key table */
316257a8187dShastings mtw_set_region_4(sc, MTW_SKEY(0, 0), 0, 8 * 32);
316357a8187dShastings
316457a8187dShastings /* clear IV/EIV table */
316557a8187dShastings mtw_set_region_4(sc, MTW_IVEIV(0), 0, 8 * 32);
316657a8187dShastings
316757a8187dShastings /* clear shared key mode */
316857a8187dShastings mtw_write(sc, MTW_SKEY_MODE_0_7, 0);
316957a8187dShastings mtw_write(sc, MTW_SKEY_MODE_8_15, 0);
317057a8187dShastings
317157a8187dShastings /* txop truncation */
317257a8187dShastings mtw_write(sc, MTW_TXOP_CTRL_CFG, 0x0000583f);
317357a8187dShastings
317457a8187dShastings /* init Tx power for all Tx rates */
317557a8187dShastings for (ridx = 0; ridx < 5; ridx++) {
317657a8187dShastings if (sc->txpow20mhz[ridx] == 0xffffffff)
317757a8187dShastings continue;
317857a8187dShastings mtw_write(sc, MTW_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]);
317957a8187dShastings }
318057a8187dShastings mtw_write(sc, MTW_TX_PWR_CFG7, 0);
318157a8187dShastings mtw_write(sc, MTW_TX_PWR_CFG9, 0);
318257a8187dShastings
318357a8187dShastings mtw_read(sc, MTW_CMB_CTRL, &tmp);
318457a8187dShastings tmp &= ~(1 << 18 | 1 << 14);
318557a8187dShastings mtw_write(sc, MTW_CMB_CTRL, tmp);
318657a8187dShastings
318757a8187dShastings /* clear USB DMA */
318857a8187dShastings mtw_write(sc, MTW_USB_DMA_CFG, MTW_USB_TX_EN | MTW_USB_RX_EN |
318957a8187dShastings MTW_USB_RX_AGG_EN | MTW_USB_TX_CLEAR | MTW_USB_TXOP_HALT |
319057a8187dShastings MTW_USB_RX_WL_DROP);
319157a8187dShastings usbd_delay_ms(sc->sc_udev, 50);
319257a8187dShastings mtw_read(sc, MTW_USB_DMA_CFG, &tmp);
319357a8187dShastings tmp &= ~(MTW_USB_TX_CLEAR | MTW_USB_TXOP_HALT |
319457a8187dShastings MTW_USB_RX_WL_DROP);
319557a8187dShastings mtw_write(sc, MTW_USB_DMA_CFG, tmp);
319657a8187dShastings
319757a8187dShastings /* enable radio */
319857a8187dShastings mtw_mcu_radio(sc, 0x31, 0);
319957a8187dShastings
320057a8187dShastings /* init RF registers */
320157a8187dShastings if (sc->mac_ver == 0x7601)
320257a8187dShastings mt7601_rf_init(sc);
320357a8187dShastings
320457a8187dShastings /* init baseband registers */
320557a8187dShastings if (sc->mac_ver == 0x7601)
320657a8187dShastings error = mt7601_bbp_init(sc);
320757a8187dShastings
320857a8187dShastings if (error != 0) {
320957a8187dShastings printf("%s: could not initialize BBP\n", sc->sc_dev.dv_xname);
321057a8187dShastings goto fail;
321157a8187dShastings }
321257a8187dShastings
321357a8187dShastings /* setup and calibrate RF */
321457a8187dShastings if (sc->mac_ver == 0x7601)
321557a8187dShastings error = mt7601_rf_setup(sc);
321657a8187dShastings
321757a8187dShastings if (error != 0) {
321857a8187dShastings printf("%s: could not initialize RF\n", sc->sc_dev.dv_xname);
321957a8187dShastings goto fail;
322057a8187dShastings }
322157a8187dShastings
322257a8187dShastings /* select default channel */
322357a8187dShastings ic->ic_bss->ni_chan = ic->ic_ibss_chan;
322457a8187dShastings mtw_set_chan(sc, ic->ic_ibss_chan);
322557a8187dShastings
322657a8187dShastings for (i = 0; i < MTW_RX_RING_COUNT; i++) {
322757a8187dShastings struct mtw_rx_data *data = &sc->rxq[MTW_RXQ_WLAN].data[i];
322857a8187dShastings
322957a8187dShastings usbd_setup_xfer(data->xfer, sc->rxq[MTW_RXQ_WLAN].pipeh,
323057a8187dShastings data, data->buf,
323157a8187dShastings MTW_MAX_RXSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
323257a8187dShastings USBD_NO_TIMEOUT, mtw_rxeof);
323357a8187dShastings error = usbd_transfer(data->xfer);
323457a8187dShastings if (error != 0 && error != USBD_IN_PROGRESS)
323557a8187dShastings goto fail;
323657a8187dShastings }
323757a8187dShastings
323857a8187dShastings if ((error = mtw_txrx_enable(sc)) != 0)
323957a8187dShastings goto fail;
324057a8187dShastings
324157a8187dShastings /* init LEDs */
324257a8187dShastings mtw_set_leds(sc, MTW_LED_MODE_ON);
324357a8187dShastings
324457a8187dShastings ifp->if_flags |= IFF_RUNNING;
324557a8187dShastings ifq_clr_oactive(&ifp->if_snd);
324657a8187dShastings
324757a8187dShastings if (ic->ic_flags & IEEE80211_F_WEPON) {
324857a8187dShastings /* install WEP keys */
324957a8187dShastings for (i = 0; i < IEEE80211_WEP_NKID; i++) {
325057a8187dShastings if (ic->ic_nw_keys[i].k_cipher != IEEE80211_CIPHER_NONE)
325157a8187dShastings (void)mtw_set_key(ic, NULL, &ic->ic_nw_keys[i]);
325257a8187dShastings }
325357a8187dShastings }
325457a8187dShastings
325557a8187dShastings if (ic->ic_opmode == IEEE80211_M_MONITOR)
325657a8187dShastings ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
325757a8187dShastings else
325857a8187dShastings ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
325957a8187dShastings
326057a8187dShastings if (error != 0)
326157a8187dShastings fail: mtw_stop(ifp, 1);
326257a8187dShastings return error;
326357a8187dShastings }
326457a8187dShastings
326557a8187dShastings void
mtw_stop(struct ifnet * ifp,int disable)326657a8187dShastings mtw_stop(struct ifnet *ifp, int disable)
326757a8187dShastings {
326857a8187dShastings struct mtw_softc *sc = ifp->if_softc;
326957a8187dShastings struct ieee80211com *ic = &sc->sc_ic;
327057a8187dShastings uint32_t tmp;
327157a8187dShastings int s, ntries, error, qid;
327257a8187dShastings
327357a8187dShastings if (ifp->if_flags & IFF_RUNNING)
327457a8187dShastings mtw_set_leds(sc, MTW_LED_MODE_ON);
327557a8187dShastings
327657a8187dShastings sc->sc_tx_timer = 0;
327757a8187dShastings ifp->if_timer = 0;
327857a8187dShastings ifp->if_flags &= ~IFF_RUNNING;
327957a8187dShastings ifq_clr_oactive(&ifp->if_snd);
328057a8187dShastings
328157a8187dShastings timeout_del(&sc->scan_to);
328257a8187dShastings timeout_del(&sc->calib_to);
328357a8187dShastings
328457a8187dShastings s = splusb();
328557a8187dShastings ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
328657a8187dShastings /* wait for all queued asynchronous commands to complete */
328757a8187dShastings usb_wait_task(sc->sc_udev, &sc->sc_task);
328857a8187dShastings splx(s);
328957a8187dShastings
329057a8187dShastings /* Disable Tx/Rx DMA. */
329157a8187dShastings mtw_read(sc, MTW_WPDMA_GLO_CFG, &tmp);
329257a8187dShastings tmp &= ~(MTW_RX_DMA_EN | MTW_TX_DMA_EN);
329357a8187dShastings mtw_write(sc, MTW_WPDMA_GLO_CFG, tmp);
329457a8187dShastings mtw_usb_dma_write(sc, 0);
329557a8187dShastings
329657a8187dShastings for (ntries = 0; ntries < 100; ntries++) {
329757a8187dShastings if (mtw_read(sc, MTW_WPDMA_GLO_CFG, &tmp) != 0)
329857a8187dShastings break;
329957a8187dShastings if ((tmp & (MTW_TX_DMA_BUSY | MTW_RX_DMA_BUSY)) == 0)
330057a8187dShastings break;
330157a8187dShastings DELAY(10);
330257a8187dShastings }
330357a8187dShastings if (ntries == 100) {
330457a8187dShastings printf("%s: timeout waiting for DMA engine\n",
330557a8187dShastings sc->sc_dev.dv_xname);
330657a8187dShastings }
330757a8187dShastings
330857a8187dShastings /* stop MAC Tx/Rx */
330957a8187dShastings mtw_read(sc, MTW_MAC_SYS_CTRL, &tmp);
331057a8187dShastings tmp &= ~(MTW_MAC_RX_EN | MTW_MAC_TX_EN);
331157a8187dShastings mtw_write(sc, MTW_MAC_SYS_CTRL, tmp);
331257a8187dShastings
331357a8187dShastings /* disable RTS retry */
331457a8187dShastings mtw_read(sc, MTW_TX_RTS_CFG, &tmp);
331557a8187dShastings tmp &= ~0xff;
331657a8187dShastings mtw_write(sc, MTW_TX_RTS_CFG, tmp);
331757a8187dShastings
331857a8187dShastings /* US_CYC_CFG */
331957a8187dShastings mtw_read(sc, MTW_US_CYC_CNT, &tmp);
332057a8187dShastings tmp = (tmp & ~0xff);
332157a8187dShastings mtw_write(sc, MTW_US_CYC_CNT, tmp);
332257a8187dShastings
332357a8187dShastings /* stop PBF */
332457a8187dShastings mtw_read(sc, MTW_PBF_CFG, &tmp);
332557a8187dShastings tmp &= ~0x3;
332657a8187dShastings mtw_write(sc, MTW_PBF_CFG, tmp);
332757a8187dShastings
332857a8187dShastings /* wait for pending Tx to complete */
332957a8187dShastings for (ntries = 0; ntries < 100; ntries++) {
333057a8187dShastings if ((error = mtw_read(sc, MTW_TXRXQ_PCNT, &tmp)) != 0)
333157a8187dShastings break;
333257a8187dShastings if ((tmp & MTW_TX2Q_PCNT_MASK) == 0)
333357a8187dShastings break;
333457a8187dShastings }
333557a8187dShastings DELAY(1000);
333657a8187dShastings
333757a8187dShastings /* delete keys */
333857a8187dShastings for (qid = 0; qid < 4; qid++) {
333957a8187dShastings mtw_read(sc, MTW_SKEY_MODE_0_7, &tmp);
334057a8187dShastings tmp &= ~(0xf << qid * 4);
334157a8187dShastings mtw_write(sc, MTW_SKEY_MODE_0_7, tmp);
334257a8187dShastings }
334357a8187dShastings
334457a8187dShastings if (disable) {
334557a8187dShastings /* disable radio */
334657a8187dShastings error = mtw_mcu_radio(sc, 0x30, 0x1);
334757a8187dShastings usbd_delay_ms(sc->sc_udev, 10);
334857a8187dShastings }
334957a8187dShastings
335057a8187dShastings /* free Tx and Rx rings */
335157a8187dShastings sc->qfullmsk = 0;
335257a8187dShastings mtw_free_mcu_ring(sc);
335357a8187dShastings for (qid = 0; qid < MTW_TXQ_COUNT; qid++)
335457a8187dShastings mtw_free_tx_ring(sc, qid);
335557a8187dShastings mtw_free_rx_ring(sc, 0);
335657a8187dShastings }
3357