14310d6deSBernhard Schmidt /*- 24310d6deSBernhard Schmidt * Copyright (c) 2007-2010 Damien Bergamini <damien.bergamini@free.fr> 34310d6deSBernhard Schmidt * Copyright (c) 2012 Bernhard Schmidt <bschmidt@FreeBSD.org> 44310d6deSBernhard Schmidt * 54310d6deSBernhard Schmidt * Permission to use, copy, modify, and distribute this software for any 64310d6deSBernhard Schmidt * purpose with or without fee is hereby granted, provided that the above 74310d6deSBernhard Schmidt * copyright notice and this permission notice appear in all copies. 84310d6deSBernhard Schmidt * 94310d6deSBernhard Schmidt * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 104310d6deSBernhard Schmidt * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 114310d6deSBernhard Schmidt * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 124310d6deSBernhard Schmidt * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 134310d6deSBernhard Schmidt * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 144310d6deSBernhard Schmidt * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 154310d6deSBernhard Schmidt * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 164310d6deSBernhard Schmidt * 174310d6deSBernhard Schmidt * $OpenBSD: rt2860.c,v 1.65 2010/10/23 14:24:54 damien Exp $ 184310d6deSBernhard Schmidt */ 194310d6deSBernhard Schmidt 204310d6deSBernhard Schmidt #include <sys/cdefs.h> 214310d6deSBernhard Schmidt /*- 226fc44dabSKevin Lo * Ralink Technology RT2860/RT3090/RT3390/RT3562/RT5390/RT5392 chipset driver 234310d6deSBernhard Schmidt * http://www.ralinktech.com/ 244310d6deSBernhard Schmidt */ 254310d6deSBernhard Schmidt 264310d6deSBernhard Schmidt #include <sys/param.h> 274310d6deSBernhard Schmidt #include <sys/sysctl.h> 284310d6deSBernhard Schmidt #include <sys/sockio.h> 294310d6deSBernhard Schmidt #include <sys/mbuf.h> 304310d6deSBernhard Schmidt #include <sys/kernel.h> 314310d6deSBernhard Schmidt #include <sys/socket.h> 324310d6deSBernhard Schmidt #include <sys/systm.h> 334310d6deSBernhard Schmidt #include <sys/malloc.h> 344310d6deSBernhard Schmidt #include <sys/lock.h> 354310d6deSBernhard Schmidt #include <sys/mutex.h> 364310d6deSBernhard Schmidt #include <sys/module.h> 374310d6deSBernhard Schmidt #include <sys/bus.h> 384310d6deSBernhard Schmidt #include <sys/endian.h> 394310d6deSBernhard Schmidt #include <sys/firmware.h> 404310d6deSBernhard Schmidt 414310d6deSBernhard Schmidt #include <machine/bus.h> 424310d6deSBernhard Schmidt #include <machine/resource.h> 434310d6deSBernhard Schmidt #include <sys/rman.h> 444310d6deSBernhard Schmidt 454310d6deSBernhard Schmidt #include <net/bpf.h> 464310d6deSBernhard Schmidt #include <net/if.h> 4776039bc8SGleb Smirnoff #include <net/if_var.h> 484310d6deSBernhard Schmidt #include <net/if_arp.h> 494310d6deSBernhard Schmidt #include <net/ethernet.h> 504310d6deSBernhard Schmidt #include <net/if_dl.h> 514310d6deSBernhard Schmidt #include <net/if_media.h> 524310d6deSBernhard Schmidt #include <net/if_types.h> 534310d6deSBernhard Schmidt 544310d6deSBernhard Schmidt #include <net80211/ieee80211_var.h> 554310d6deSBernhard Schmidt #include <net80211/ieee80211_radiotap.h> 564310d6deSBernhard Schmidt #include <net80211/ieee80211_regdomain.h> 574310d6deSBernhard Schmidt #include <net80211/ieee80211_ratectl.h> 584310d6deSBernhard Schmidt 594310d6deSBernhard Schmidt #include <netinet/in.h> 604310d6deSBernhard Schmidt #include <netinet/in_systm.h> 614310d6deSBernhard Schmidt #include <netinet/in_var.h> 624310d6deSBernhard Schmidt #include <netinet/ip.h> 634310d6deSBernhard Schmidt #include <netinet/if_ether.h> 644310d6deSBernhard Schmidt 654310d6deSBernhard Schmidt #include <dev/ral/rt2860reg.h> 664310d6deSBernhard Schmidt #include <dev/ral/rt2860var.h> 674310d6deSBernhard Schmidt 684310d6deSBernhard Schmidt #define RAL_DEBUG 694310d6deSBernhard Schmidt #ifdef RAL_DEBUG 704310d6deSBernhard Schmidt #define DPRINTF(x) do { if (sc->sc_debug > 0) printf x; } while (0) 714310d6deSBernhard Schmidt #define DPRINTFN(n, x) do { if (sc->sc_debug >= (n)) printf x; } while (0) 724310d6deSBernhard Schmidt #else 734310d6deSBernhard Schmidt #define DPRINTF(x) 744310d6deSBernhard Schmidt #define DPRINTFN(n, x) 754310d6deSBernhard Schmidt #endif 764310d6deSBernhard Schmidt 774310d6deSBernhard Schmidt static struct ieee80211vap *rt2860_vap_create(struct ieee80211com *, 784310d6deSBernhard Schmidt const char [IFNAMSIZ], int, enum ieee80211_opmode, 794310d6deSBernhard Schmidt int, const uint8_t [IEEE80211_ADDR_LEN], 804310d6deSBernhard Schmidt const uint8_t [IEEE80211_ADDR_LEN]); 814310d6deSBernhard Schmidt static void rt2860_vap_delete(struct ieee80211vap *); 824310d6deSBernhard Schmidt static void rt2860_dma_map_addr(void *, bus_dma_segment_t *, int, int); 834310d6deSBernhard Schmidt static int rt2860_alloc_tx_ring(struct rt2860_softc *, 844310d6deSBernhard Schmidt struct rt2860_tx_ring *); 854310d6deSBernhard Schmidt static void rt2860_reset_tx_ring(struct rt2860_softc *, 864310d6deSBernhard Schmidt struct rt2860_tx_ring *); 874310d6deSBernhard Schmidt static void rt2860_free_tx_ring(struct rt2860_softc *, 884310d6deSBernhard Schmidt struct rt2860_tx_ring *); 894310d6deSBernhard Schmidt static int rt2860_alloc_tx_pool(struct rt2860_softc *); 904310d6deSBernhard Schmidt static void rt2860_free_tx_pool(struct rt2860_softc *); 914310d6deSBernhard Schmidt static int rt2860_alloc_rx_ring(struct rt2860_softc *, 924310d6deSBernhard Schmidt struct rt2860_rx_ring *); 934310d6deSBernhard Schmidt static void rt2860_reset_rx_ring(struct rt2860_softc *, 944310d6deSBernhard Schmidt struct rt2860_rx_ring *); 954310d6deSBernhard Schmidt static void rt2860_free_rx_ring(struct rt2860_softc *, 964310d6deSBernhard Schmidt struct rt2860_rx_ring *); 974310d6deSBernhard Schmidt static void rt2860_updatestats(struct rt2860_softc *); 984310d6deSBernhard Schmidt static void rt2860_newassoc(struct ieee80211_node *, int); 994310d6deSBernhard Schmidt static void rt2860_node_free(struct ieee80211_node *); 1004310d6deSBernhard Schmidt #ifdef IEEE80211_HT 1014310d6deSBernhard Schmidt static int rt2860_ampdu_rx_start(struct ieee80211com *, 1024310d6deSBernhard Schmidt struct ieee80211_node *, uint8_t); 1034310d6deSBernhard Schmidt static void rt2860_ampdu_rx_stop(struct ieee80211com *, 1044310d6deSBernhard Schmidt struct ieee80211_node *, uint8_t); 1054310d6deSBernhard Schmidt #endif 1064310d6deSBernhard Schmidt static int rt2860_newstate(struct ieee80211vap *, enum ieee80211_state, 1074310d6deSBernhard Schmidt int); 1084310d6deSBernhard Schmidt static uint16_t rt3090_efuse_read_2(struct rt2860_softc *, uint16_t); 1094310d6deSBernhard Schmidt static uint16_t rt2860_eeprom_read_2(struct rt2860_softc *, uint16_t); 1104310d6deSBernhard Schmidt static void rt2860_intr_coherent(struct rt2860_softc *); 1114310d6deSBernhard Schmidt static void rt2860_drain_stats_fifo(struct rt2860_softc *); 1124310d6deSBernhard Schmidt static void rt2860_tx_intr(struct rt2860_softc *, int); 1134310d6deSBernhard Schmidt static void rt2860_rx_intr(struct rt2860_softc *); 1144310d6deSBernhard Schmidt static void rt2860_tbtt_intr(struct rt2860_softc *); 1154310d6deSBernhard Schmidt static void rt2860_gp_intr(struct rt2860_softc *); 1164310d6deSBernhard Schmidt static int rt2860_tx(struct rt2860_softc *, struct mbuf *, 1174310d6deSBernhard Schmidt struct ieee80211_node *); 1184310d6deSBernhard Schmidt static int rt2860_raw_xmit(struct ieee80211_node *, struct mbuf *, 1194310d6deSBernhard Schmidt const struct ieee80211_bpf_params *); 1204310d6deSBernhard Schmidt static int rt2860_tx_raw(struct rt2860_softc *, struct mbuf *, 1214310d6deSBernhard Schmidt struct ieee80211_node *, 1224310d6deSBernhard Schmidt const struct ieee80211_bpf_params *params); 1237a79cebfSGleb Smirnoff static int rt2860_transmit(struct ieee80211com *, struct mbuf *); 1247a79cebfSGleb Smirnoff static void rt2860_start(struct rt2860_softc *); 1254310d6deSBernhard Schmidt static void rt2860_watchdog(void *); 1267a79cebfSGleb Smirnoff static void rt2860_parent(struct ieee80211com *); 1274310d6deSBernhard Schmidt static void rt2860_mcu_bbp_write(struct rt2860_softc *, uint8_t, uint8_t); 1284310d6deSBernhard Schmidt static uint8_t rt2860_mcu_bbp_read(struct rt2860_softc *, uint8_t); 1294310d6deSBernhard Schmidt static void rt2860_rf_write(struct rt2860_softc *, uint8_t, uint32_t); 1304310d6deSBernhard Schmidt static uint8_t rt3090_rf_read(struct rt2860_softc *, uint8_t); 1314310d6deSBernhard Schmidt static void rt3090_rf_write(struct rt2860_softc *, uint8_t, uint8_t); 1324310d6deSBernhard Schmidt static int rt2860_mcu_cmd(struct rt2860_softc *, uint8_t, uint16_t, int); 1334310d6deSBernhard Schmidt static void rt2860_enable_mrr(struct rt2860_softc *); 1344310d6deSBernhard Schmidt static void rt2860_set_txpreamble(struct rt2860_softc *); 1354310d6deSBernhard Schmidt static void rt2860_set_basicrates(struct rt2860_softc *, 1364310d6deSBernhard Schmidt const struct ieee80211_rateset *); 1374310d6deSBernhard Schmidt static void rt2860_scan_start(struct ieee80211com *); 1384310d6deSBernhard Schmidt static void rt2860_scan_end(struct ieee80211com *); 1390a02496fSAndriy Voskoboinyk static void rt2860_getradiocaps(struct ieee80211com *, int, int *, 1400a02496fSAndriy Voskoboinyk struct ieee80211_channel[]); 1414310d6deSBernhard Schmidt static void rt2860_set_channel(struct ieee80211com *); 1424310d6deSBernhard Schmidt static void rt2860_select_chan_group(struct rt2860_softc *, int); 1434310d6deSBernhard Schmidt static void rt2860_set_chan(struct rt2860_softc *, u_int); 1444310d6deSBernhard Schmidt static void rt3090_set_chan(struct rt2860_softc *, u_int); 1456fc44dabSKevin Lo static void rt5390_set_chan(struct rt2860_softc *, u_int); 1464310d6deSBernhard Schmidt static int rt3090_rf_init(struct rt2860_softc *); 1476fc44dabSKevin Lo static void rt5390_rf_init(struct rt2860_softc *); 1484310d6deSBernhard Schmidt static void rt3090_rf_wakeup(struct rt2860_softc *); 1496fc44dabSKevin Lo static void rt5390_rf_wakeup(struct rt2860_softc *); 1504310d6deSBernhard Schmidt static int rt3090_filter_calib(struct rt2860_softc *, uint8_t, uint8_t, 1514310d6deSBernhard Schmidt uint8_t *); 1524310d6deSBernhard Schmidt static void rt3090_rf_setup(struct rt2860_softc *); 1534310d6deSBernhard Schmidt static void rt2860_set_leds(struct rt2860_softc *, uint16_t); 1544310d6deSBernhard Schmidt static void rt2860_set_gp_timer(struct rt2860_softc *, int); 1554310d6deSBernhard Schmidt static void rt2860_set_bssid(struct rt2860_softc *, const uint8_t *); 1564310d6deSBernhard Schmidt static void rt2860_set_macaddr(struct rt2860_softc *, const uint8_t *); 157272f6adeSGleb Smirnoff static void rt2860_update_promisc(struct ieee80211com *); 158272f6adeSGleb Smirnoff static void rt2860_updateslot(struct ieee80211com *); 1597a79cebfSGleb Smirnoff static void rt2860_updateprot(struct rt2860_softc *); 1604310d6deSBernhard Schmidt static int rt2860_updateedca(struct ieee80211com *); 1614310d6deSBernhard Schmidt #ifdef HW_CRYPTO 1624310d6deSBernhard Schmidt static int rt2860_set_key(struct ieee80211com *, struct ieee80211_node *, 1634310d6deSBernhard Schmidt struct ieee80211_key *); 1644310d6deSBernhard Schmidt static void rt2860_delete_key(struct ieee80211com *, 1654310d6deSBernhard Schmidt struct ieee80211_node *, struct ieee80211_key *); 1664310d6deSBernhard Schmidt #endif 1674310d6deSBernhard Schmidt static int8_t rt2860_rssi2dbm(struct rt2860_softc *, uint8_t, uint8_t); 168b0f7be91SKevin Lo static const char *rt2860_get_rf(uint16_t); 1694310d6deSBernhard Schmidt static int rt2860_read_eeprom(struct rt2860_softc *, 1704310d6deSBernhard Schmidt uint8_t macaddr[IEEE80211_ADDR_LEN]); 1714310d6deSBernhard Schmidt static int rt2860_bbp_init(struct rt2860_softc *); 1726fc44dabSKevin Lo static void rt5390_bbp_init(struct rt2860_softc *); 1734310d6deSBernhard Schmidt static int rt2860_txrx_enable(struct rt2860_softc *); 1744310d6deSBernhard Schmidt static void rt2860_init(void *); 1754310d6deSBernhard Schmidt static void rt2860_init_locked(struct rt2860_softc *); 1764310d6deSBernhard Schmidt static void rt2860_stop(void *); 1774310d6deSBernhard Schmidt static void rt2860_stop_locked(struct rt2860_softc *); 1784310d6deSBernhard Schmidt static int rt2860_load_microcode(struct rt2860_softc *); 1794310d6deSBernhard Schmidt #ifdef NOT_YET 1804310d6deSBernhard Schmidt static void rt2860_calib(struct rt2860_softc *); 1814310d6deSBernhard Schmidt #endif 1824310d6deSBernhard Schmidt static void rt3090_set_rx_antenna(struct rt2860_softc *, int); 1834310d6deSBernhard Schmidt static void rt2860_switch_chan(struct rt2860_softc *, 1844310d6deSBernhard Schmidt struct ieee80211_channel *); 1854310d6deSBernhard Schmidt static int rt2860_setup_beacon(struct rt2860_softc *, 1864310d6deSBernhard Schmidt struct ieee80211vap *); 1874310d6deSBernhard Schmidt static void rt2860_enable_tsf_sync(struct rt2860_softc *); 1884310d6deSBernhard Schmidt 1894310d6deSBernhard Schmidt static const struct { 1904310d6deSBernhard Schmidt uint32_t reg; 1914310d6deSBernhard Schmidt uint32_t val; 1924310d6deSBernhard Schmidt } rt2860_def_mac[] = { 1934310d6deSBernhard Schmidt RT2860_DEF_MAC 1944310d6deSBernhard Schmidt }; 1954310d6deSBernhard Schmidt 1964310d6deSBernhard Schmidt static const struct { 1974310d6deSBernhard Schmidt uint8_t reg; 1984310d6deSBernhard Schmidt uint8_t val; 1994310d6deSBernhard Schmidt } rt2860_def_bbp[] = { 2004310d6deSBernhard Schmidt RT2860_DEF_BBP 2016fc44dabSKevin Lo }, rt5390_def_bbp[] = { 2026fc44dabSKevin Lo RT5390_DEF_BBP 2034310d6deSBernhard Schmidt }; 2044310d6deSBernhard Schmidt 2054310d6deSBernhard Schmidt static const struct rfprog { 2064310d6deSBernhard Schmidt uint8_t chan; 2074310d6deSBernhard Schmidt uint32_t r1, r2, r3, r4; 2084310d6deSBernhard Schmidt } rt2860_rf2850[] = { 2094310d6deSBernhard Schmidt RT2860_RF2850 2104310d6deSBernhard Schmidt }; 2114310d6deSBernhard Schmidt 2124310d6deSBernhard Schmidt struct { 2134310d6deSBernhard Schmidt uint8_t n, r, k; 2144310d6deSBernhard Schmidt } rt3090_freqs[] = { 2154310d6deSBernhard Schmidt RT3070_RF3052 2164310d6deSBernhard Schmidt }; 2174310d6deSBernhard Schmidt 2184310d6deSBernhard Schmidt static const struct { 2194310d6deSBernhard Schmidt uint8_t reg; 2204310d6deSBernhard Schmidt uint8_t val; 2214310d6deSBernhard Schmidt } rt3090_def_rf[] = { 2224310d6deSBernhard Schmidt RT3070_DEF_RF 2236fc44dabSKevin Lo }, rt5390_def_rf[] = { 2246fc44dabSKevin Lo RT5390_DEF_RF 2256fc44dabSKevin Lo }, rt5392_def_rf[] = { 2266fc44dabSKevin Lo RT5392_DEF_RF 2274310d6deSBernhard Schmidt }; 2284310d6deSBernhard Schmidt 2290a02496fSAndriy Voskoboinyk static const uint8_t rt2860_chan_5ghz[] = 2300a02496fSAndriy Voskoboinyk { 36, 38, 40, 44, 46, 48, 52, 54, 56, 60, 62, 64, 100, 102, 104, 2310a02496fSAndriy Voskoboinyk 108, 110, 112, 116, 118, 120, 124, 126, 128, 132, 134, 136, 140, 2320a02496fSAndriy Voskoboinyk 149, 151, 153, 157, 159, 161, 165, 167, 169, 171, 173 }; 2330a02496fSAndriy Voskoboinyk 2344310d6deSBernhard Schmidt int 2354310d6deSBernhard Schmidt rt2860_attach(device_t dev, int id) 2364310d6deSBernhard Schmidt { 2374310d6deSBernhard Schmidt struct rt2860_softc *sc = device_get_softc(dev); 2387a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 2394310d6deSBernhard Schmidt uint32_t tmp; 2404310d6deSBernhard Schmidt int error, ntries, qid; 2414310d6deSBernhard Schmidt 2424310d6deSBernhard Schmidt sc->sc_dev = dev; 2434310d6deSBernhard Schmidt sc->sc_debug = 0; 2444310d6deSBernhard Schmidt 2454310d6deSBernhard Schmidt mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 2464310d6deSBernhard Schmidt MTX_DEF | MTX_RECURSE); 2474310d6deSBernhard Schmidt 2484310d6deSBernhard Schmidt callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0); 2497a79cebfSGleb Smirnoff mbufq_init(&sc->sc_snd, ifqmaxlen); 2504310d6deSBernhard Schmidt 2514310d6deSBernhard Schmidt /* wait for NIC to initialize */ 2524310d6deSBernhard Schmidt for (ntries = 0; ntries < 100; ntries++) { 2534310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_ASIC_VER_ID); 2544310d6deSBernhard Schmidt if (tmp != 0 && tmp != 0xffffffff) 2554310d6deSBernhard Schmidt break; 2564310d6deSBernhard Schmidt DELAY(10); 2574310d6deSBernhard Schmidt } 2584310d6deSBernhard Schmidt if (ntries == 100) { 2594310d6deSBernhard Schmidt device_printf(sc->sc_dev, 2604310d6deSBernhard Schmidt "timeout waiting for NIC to initialize\n"); 2614310d6deSBernhard Schmidt error = EIO; 2624310d6deSBernhard Schmidt goto fail1; 2634310d6deSBernhard Schmidt } 2644310d6deSBernhard Schmidt sc->mac_ver = tmp >> 16; 2654310d6deSBernhard Schmidt sc->mac_rev = tmp & 0xffff; 2664310d6deSBernhard Schmidt 2674310d6deSBernhard Schmidt if (sc->mac_ver != 0x2860 && 2684310d6deSBernhard Schmidt (id == 0x0681 || id == 0x0781 || id == 0x1059)) 2694310d6deSBernhard Schmidt sc->sc_flags |= RT2860_ADVANCED_PS; 2704310d6deSBernhard Schmidt 2714310d6deSBernhard Schmidt /* retrieve RF rev. no and various other things from EEPROM */ 2727a79cebfSGleb Smirnoff rt2860_read_eeprom(sc, ic->ic_macaddr); 2734310d6deSBernhard Schmidt device_printf(sc->sc_dev, "MAC/BBP RT%X (rev 0x%04X), " 2744310d6deSBernhard Schmidt "RF %s (MIMO %dT%dR), address %6D\n", 2754310d6deSBernhard Schmidt sc->mac_ver, sc->mac_rev, rt2860_get_rf(sc->rf_rev), 2767a79cebfSGleb Smirnoff sc->ntxchains, sc->nrxchains, ic->ic_macaddr, ":"); 2774310d6deSBernhard Schmidt 2784310d6deSBernhard Schmidt /* 2794310d6deSBernhard Schmidt * Allocate Tx (4 EDCAs + HCCA + Mgt) and Rx rings. 2804310d6deSBernhard Schmidt */ 2814310d6deSBernhard Schmidt for (qid = 0; qid < 6; qid++) { 2824310d6deSBernhard Schmidt if ((error = rt2860_alloc_tx_ring(sc, &sc->txq[qid])) != 0) { 2834310d6deSBernhard Schmidt device_printf(sc->sc_dev, 2844310d6deSBernhard Schmidt "could not allocate Tx ring %d\n", qid); 2854310d6deSBernhard Schmidt goto fail2; 2864310d6deSBernhard Schmidt } 2874310d6deSBernhard Schmidt } 2884310d6deSBernhard Schmidt 2894310d6deSBernhard Schmidt if ((error = rt2860_alloc_rx_ring(sc, &sc->rxq)) != 0) { 2904310d6deSBernhard Schmidt device_printf(sc->sc_dev, "could not allocate Rx ring\n"); 2914310d6deSBernhard Schmidt goto fail2; 2924310d6deSBernhard Schmidt } 2934310d6deSBernhard Schmidt 2944310d6deSBernhard Schmidt if ((error = rt2860_alloc_tx_pool(sc)) != 0) { 2954310d6deSBernhard Schmidt device_printf(sc->sc_dev, "could not allocate Tx pool\n"); 2964310d6deSBernhard Schmidt goto fail3; 2974310d6deSBernhard Schmidt } 2984310d6deSBernhard Schmidt 2994310d6deSBernhard Schmidt /* mgmt ring is broken on RT2860C, use EDCA AC VO ring instead */ 3004310d6deSBernhard Schmidt sc->mgtqid = (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) ? 3014310d6deSBernhard Schmidt WME_AC_VO : 5; 3024310d6deSBernhard Schmidt 30359686fe9SGleb Smirnoff ic->ic_softc = sc; 304c8550c02SGleb Smirnoff ic->ic_name = device_get_nameunit(dev); 3054310d6deSBernhard Schmidt ic->ic_opmode = IEEE80211_M_STA; 3064310d6deSBernhard Schmidt ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 3074310d6deSBernhard Schmidt 3084310d6deSBernhard Schmidt /* set device capabilities */ 3094310d6deSBernhard Schmidt ic->ic_caps = 3104310d6deSBernhard Schmidt IEEE80211_C_STA /* station mode */ 3114310d6deSBernhard Schmidt | IEEE80211_C_IBSS /* ibss, nee adhoc, mode */ 3124310d6deSBernhard Schmidt | IEEE80211_C_HOSTAP /* hostap mode */ 3134310d6deSBernhard Schmidt | IEEE80211_C_MONITOR /* monitor mode */ 3144310d6deSBernhard Schmidt | IEEE80211_C_AHDEMO /* adhoc demo mode */ 3154310d6deSBernhard Schmidt | IEEE80211_C_WDS /* 4-address traffic works */ 3164310d6deSBernhard Schmidt | IEEE80211_C_MBSS /* mesh point link mode */ 3174310d6deSBernhard Schmidt | IEEE80211_C_SHPREAMBLE /* short preamble supported */ 3184310d6deSBernhard Schmidt | IEEE80211_C_SHSLOT /* short slot time supported */ 3194310d6deSBernhard Schmidt | IEEE80211_C_WPA /* capable of WPA1+WPA2 */ 3204310d6deSBernhard Schmidt #if 0 3214310d6deSBernhard Schmidt | IEEE80211_C_BGSCAN /* capable of bg scanning */ 3224310d6deSBernhard Schmidt #endif 3234310d6deSBernhard Schmidt | IEEE80211_C_WME /* 802.11e */ 3244310d6deSBernhard Schmidt ; 3254310d6deSBernhard Schmidt 3260a02496fSAndriy Voskoboinyk rt2860_getradiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans, 3270a02496fSAndriy Voskoboinyk ic->ic_channels); 3284310d6deSBernhard Schmidt 3297a79cebfSGleb Smirnoff ieee80211_ifattach(ic); 3304310d6deSBernhard Schmidt 3314310d6deSBernhard Schmidt ic->ic_wme.wme_update = rt2860_updateedca; 3324310d6deSBernhard Schmidt ic->ic_scan_start = rt2860_scan_start; 3334310d6deSBernhard Schmidt ic->ic_scan_end = rt2860_scan_end; 3340a02496fSAndriy Voskoboinyk ic->ic_getradiocaps = rt2860_getradiocaps; 3354310d6deSBernhard Schmidt ic->ic_set_channel = rt2860_set_channel; 3364310d6deSBernhard Schmidt ic->ic_updateslot = rt2860_updateslot; 3374310d6deSBernhard Schmidt ic->ic_update_promisc = rt2860_update_promisc; 3384310d6deSBernhard Schmidt ic->ic_raw_xmit = rt2860_raw_xmit; 3394310d6deSBernhard Schmidt sc->sc_node_free = ic->ic_node_free; 3404310d6deSBernhard Schmidt ic->ic_node_free = rt2860_node_free; 3414310d6deSBernhard Schmidt ic->ic_newassoc = rt2860_newassoc; 3427a79cebfSGleb Smirnoff ic->ic_transmit = rt2860_transmit; 3437a79cebfSGleb Smirnoff ic->ic_parent = rt2860_parent; 3444310d6deSBernhard Schmidt ic->ic_vap_create = rt2860_vap_create; 3454310d6deSBernhard Schmidt ic->ic_vap_delete = rt2860_vap_delete; 3464310d6deSBernhard Schmidt 3474310d6deSBernhard Schmidt ieee80211_radiotap_attach(ic, 3484310d6deSBernhard Schmidt &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), 3494310d6deSBernhard Schmidt RT2860_TX_RADIOTAP_PRESENT, 3504310d6deSBernhard Schmidt &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), 3514310d6deSBernhard Schmidt RT2860_RX_RADIOTAP_PRESENT); 3524310d6deSBernhard Schmidt 3534310d6deSBernhard Schmidt #ifdef RAL_DEBUG 3544310d6deSBernhard Schmidt SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 3554310d6deSBernhard Schmidt SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 3564310d6deSBernhard Schmidt "debug", CTLFLAG_RW, &sc->sc_debug, 0, "debug msgs"); 3574310d6deSBernhard Schmidt #endif 3584310d6deSBernhard Schmidt if (bootverbose) 3594310d6deSBernhard Schmidt ieee80211_announce(ic); 3604310d6deSBernhard Schmidt 3614310d6deSBernhard Schmidt return 0; 3624310d6deSBernhard Schmidt 3634310d6deSBernhard Schmidt fail3: rt2860_free_rx_ring(sc, &sc->rxq); 3644310d6deSBernhard Schmidt fail2: while (--qid >= 0) 3654310d6deSBernhard Schmidt rt2860_free_tx_ring(sc, &sc->txq[qid]); 3664310d6deSBernhard Schmidt fail1: mtx_destroy(&sc->sc_mtx); 3674310d6deSBernhard Schmidt return error; 3684310d6deSBernhard Schmidt } 3694310d6deSBernhard Schmidt 3704310d6deSBernhard Schmidt int 3714310d6deSBernhard Schmidt rt2860_detach(void *xsc) 3724310d6deSBernhard Schmidt { 3734310d6deSBernhard Schmidt struct rt2860_softc *sc = xsc; 3747a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 3754310d6deSBernhard Schmidt int qid; 3764310d6deSBernhard Schmidt 3774310d6deSBernhard Schmidt RAL_LOCK(sc); 3784310d6deSBernhard Schmidt rt2860_stop_locked(sc); 3794310d6deSBernhard Schmidt RAL_UNLOCK(sc); 3804310d6deSBernhard Schmidt 3814310d6deSBernhard Schmidt ieee80211_ifdetach(ic); 3827a79cebfSGleb Smirnoff mbufq_drain(&sc->sc_snd); 3834310d6deSBernhard Schmidt for (qid = 0; qid < 6; qid++) 3844310d6deSBernhard Schmidt rt2860_free_tx_ring(sc, &sc->txq[qid]); 3854310d6deSBernhard Schmidt rt2860_free_rx_ring(sc, &sc->rxq); 3864310d6deSBernhard Schmidt rt2860_free_tx_pool(sc); 3874310d6deSBernhard Schmidt 3884310d6deSBernhard Schmidt mtx_destroy(&sc->sc_mtx); 3894310d6deSBernhard Schmidt 3904310d6deSBernhard Schmidt return 0; 3914310d6deSBernhard Schmidt } 3924310d6deSBernhard Schmidt 3934310d6deSBernhard Schmidt void 3944310d6deSBernhard Schmidt rt2860_shutdown(void *xsc) 3954310d6deSBernhard Schmidt { 3964310d6deSBernhard Schmidt struct rt2860_softc *sc = xsc; 3974310d6deSBernhard Schmidt 3984310d6deSBernhard Schmidt rt2860_stop(sc); 3994310d6deSBernhard Schmidt } 4004310d6deSBernhard Schmidt 4014310d6deSBernhard Schmidt void 4024310d6deSBernhard Schmidt rt2860_suspend(void *xsc) 4034310d6deSBernhard Schmidt { 4044310d6deSBernhard Schmidt struct rt2860_softc *sc = xsc; 4054310d6deSBernhard Schmidt 4064310d6deSBernhard Schmidt rt2860_stop(sc); 4074310d6deSBernhard Schmidt } 4084310d6deSBernhard Schmidt 4094310d6deSBernhard Schmidt void 4104310d6deSBernhard Schmidt rt2860_resume(void *xsc) 4114310d6deSBernhard Schmidt { 4124310d6deSBernhard Schmidt struct rt2860_softc *sc = xsc; 4134310d6deSBernhard Schmidt 4147a79cebfSGleb Smirnoff if (sc->sc_ic.ic_nrunning > 0) 4154310d6deSBernhard Schmidt rt2860_init(sc); 4164310d6deSBernhard Schmidt } 4174310d6deSBernhard Schmidt 4184310d6deSBernhard Schmidt static struct ieee80211vap * 4194310d6deSBernhard Schmidt rt2860_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, 4204310d6deSBernhard Schmidt enum ieee80211_opmode opmode, int flags, 4214310d6deSBernhard Schmidt const uint8_t bssid[IEEE80211_ADDR_LEN], 4224310d6deSBernhard Schmidt const uint8_t mac[IEEE80211_ADDR_LEN]) 4234310d6deSBernhard Schmidt { 4247a79cebfSGleb Smirnoff struct rt2860_softc *sc = ic->ic_softc; 4254310d6deSBernhard Schmidt struct rt2860_vap *rvp; 4264310d6deSBernhard Schmidt struct ieee80211vap *vap; 4274310d6deSBernhard Schmidt 4284310d6deSBernhard Schmidt switch (opmode) { 4294310d6deSBernhard Schmidt case IEEE80211_M_STA: 4304310d6deSBernhard Schmidt case IEEE80211_M_IBSS: 4314310d6deSBernhard Schmidt case IEEE80211_M_AHDEMO: 4324310d6deSBernhard Schmidt case IEEE80211_M_MONITOR: 4334310d6deSBernhard Schmidt case IEEE80211_M_HOSTAP: 4344310d6deSBernhard Schmidt case IEEE80211_M_MBSS: 4354310d6deSBernhard Schmidt /* XXXRP: TBD */ 4364310d6deSBernhard Schmidt if (!TAILQ_EMPTY(&ic->ic_vaps)) { 4377a79cebfSGleb Smirnoff device_printf(sc->sc_dev, "only 1 vap supported\n"); 4384310d6deSBernhard Schmidt return NULL; 4394310d6deSBernhard Schmidt } 4404310d6deSBernhard Schmidt if (opmode == IEEE80211_M_STA) 4414310d6deSBernhard Schmidt flags |= IEEE80211_CLONE_NOBEACONS; 4424310d6deSBernhard Schmidt break; 4434310d6deSBernhard Schmidt case IEEE80211_M_WDS: 4444310d6deSBernhard Schmidt if (TAILQ_EMPTY(&ic->ic_vaps) || 4454310d6deSBernhard Schmidt ic->ic_opmode != IEEE80211_M_HOSTAP) { 4467a79cebfSGleb Smirnoff device_printf(sc->sc_dev, 4477a79cebfSGleb Smirnoff "wds only supported in ap mode\n"); 4484310d6deSBernhard Schmidt return NULL; 4494310d6deSBernhard Schmidt } 4504310d6deSBernhard Schmidt /* 4514310d6deSBernhard Schmidt * Silently remove any request for a unique 4524310d6deSBernhard Schmidt * bssid; WDS vap's always share the local 4534310d6deSBernhard Schmidt * mac address. 4544310d6deSBernhard Schmidt */ 4554310d6deSBernhard Schmidt flags &= ~IEEE80211_CLONE_BSSID; 4564310d6deSBernhard Schmidt break; 4574310d6deSBernhard Schmidt default: 4587a79cebfSGleb Smirnoff device_printf(sc->sc_dev, "unknown opmode %d\n", opmode); 4594310d6deSBernhard Schmidt return NULL; 4604310d6deSBernhard Schmidt } 4617a79cebfSGleb Smirnoff rvp = malloc(sizeof(struct rt2860_vap), M_80211_VAP, M_WAITOK | M_ZERO); 4624310d6deSBernhard Schmidt vap = &rvp->ral_vap; 4637a79cebfSGleb Smirnoff ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); 4644310d6deSBernhard Schmidt 4654310d6deSBernhard Schmidt /* override state transition machine */ 4664310d6deSBernhard Schmidt rvp->ral_newstate = vap->iv_newstate; 4674310d6deSBernhard Schmidt vap->iv_newstate = rt2860_newstate; 4684310d6deSBernhard Schmidt #if 0 4694310d6deSBernhard Schmidt vap->iv_update_beacon = rt2860_beacon_update; 4704310d6deSBernhard Schmidt #endif 4714310d6deSBernhard Schmidt 4724310d6deSBernhard Schmidt /* HW supports up to 255 STAs (0-254) in HostAP and IBSS modes */ 4734310d6deSBernhard Schmidt vap->iv_max_aid = min(IEEE80211_AID_MAX, RT2860_WCID_MAX); 4744310d6deSBernhard Schmidt 4754310d6deSBernhard Schmidt ieee80211_ratectl_init(vap); 4764310d6deSBernhard Schmidt /* complete setup */ 4777a79cebfSGleb Smirnoff ieee80211_vap_attach(vap, ieee80211_media_change, 4787a79cebfSGleb Smirnoff ieee80211_media_status, mac); 4794310d6deSBernhard Schmidt if (TAILQ_FIRST(&ic->ic_vaps) == vap) 4804310d6deSBernhard Schmidt ic->ic_opmode = opmode; 4814310d6deSBernhard Schmidt return vap; 4824310d6deSBernhard Schmidt } 4834310d6deSBernhard Schmidt 4844310d6deSBernhard Schmidt static void 4854310d6deSBernhard Schmidt rt2860_vap_delete(struct ieee80211vap *vap) 4864310d6deSBernhard Schmidt { 4874310d6deSBernhard Schmidt struct rt2860_vap *rvp = RT2860_VAP(vap); 4884310d6deSBernhard Schmidt 4894310d6deSBernhard Schmidt ieee80211_ratectl_deinit(vap); 4904310d6deSBernhard Schmidt ieee80211_vap_detach(vap); 4914310d6deSBernhard Schmidt free(rvp, M_80211_VAP); 4924310d6deSBernhard Schmidt } 4934310d6deSBernhard Schmidt 4944310d6deSBernhard Schmidt static void 4954310d6deSBernhard Schmidt rt2860_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 4964310d6deSBernhard Schmidt { 4974310d6deSBernhard Schmidt if (error != 0) 4984310d6deSBernhard Schmidt return; 4994310d6deSBernhard Schmidt 5004310d6deSBernhard Schmidt KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 5014310d6deSBernhard Schmidt 5024310d6deSBernhard Schmidt *(bus_addr_t *)arg = segs[0].ds_addr; 5034310d6deSBernhard Schmidt } 5044310d6deSBernhard Schmidt 5054310d6deSBernhard Schmidt static int 5064310d6deSBernhard Schmidt rt2860_alloc_tx_ring(struct rt2860_softc *sc, struct rt2860_tx_ring *ring) 5074310d6deSBernhard Schmidt { 5084310d6deSBernhard Schmidt int size, error; 5094310d6deSBernhard Schmidt 5104310d6deSBernhard Schmidt size = RT2860_TX_RING_COUNT * sizeof (struct rt2860_txd); 5114310d6deSBernhard Schmidt 5124310d6deSBernhard Schmidt error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 16, 0, 5134310d6deSBernhard Schmidt BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 5144310d6deSBernhard Schmidt size, 1, size, 0, NULL, NULL, &ring->desc_dmat); 5154310d6deSBernhard Schmidt if (error != 0) { 5161c1cd920SKevin Lo device_printf(sc->sc_dev, "could not create desc DMA tag\n"); 5174310d6deSBernhard Schmidt goto fail; 5184310d6deSBernhard Schmidt } 5194310d6deSBernhard Schmidt 5204310d6deSBernhard Schmidt error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->txd, 5214310d6deSBernhard Schmidt BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); 5224310d6deSBernhard Schmidt if (error != 0) { 5234310d6deSBernhard Schmidt device_printf(sc->sc_dev, "could not allocate DMA memory\n"); 5244310d6deSBernhard Schmidt goto fail; 5254310d6deSBernhard Schmidt } 5264310d6deSBernhard Schmidt 5274310d6deSBernhard Schmidt error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->txd, 5284310d6deSBernhard Schmidt size, rt2860_dma_map_addr, &ring->paddr, 0); 5294310d6deSBernhard Schmidt if (error != 0) { 5304310d6deSBernhard Schmidt device_printf(sc->sc_dev, "could not load desc DMA map\n"); 5314310d6deSBernhard Schmidt goto fail; 5324310d6deSBernhard Schmidt } 5334310d6deSBernhard Schmidt 5344310d6deSBernhard Schmidt bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 5354310d6deSBernhard Schmidt 5364310d6deSBernhard Schmidt return 0; 5374310d6deSBernhard Schmidt 5384310d6deSBernhard Schmidt fail: rt2860_free_tx_ring(sc, ring); 5394310d6deSBernhard Schmidt return error; 5404310d6deSBernhard Schmidt } 5414310d6deSBernhard Schmidt 5424310d6deSBernhard Schmidt void 5434310d6deSBernhard Schmidt rt2860_reset_tx_ring(struct rt2860_softc *sc, struct rt2860_tx_ring *ring) 5444310d6deSBernhard Schmidt { 5454310d6deSBernhard Schmidt struct rt2860_tx_data *data; 5464310d6deSBernhard Schmidt int i; 5474310d6deSBernhard Schmidt 5484310d6deSBernhard Schmidt for (i = 0; i < RT2860_TX_RING_COUNT; i++) { 5494310d6deSBernhard Schmidt if ((data = ring->data[i]) == NULL) 5504310d6deSBernhard Schmidt continue; /* nothing mapped in this slot */ 5514310d6deSBernhard Schmidt 5524310d6deSBernhard Schmidt if (data->m != NULL) { 5534310d6deSBernhard Schmidt bus_dmamap_sync(sc->txwi_dmat, data->map, 5544310d6deSBernhard Schmidt BUS_DMASYNC_POSTWRITE); 5554310d6deSBernhard Schmidt bus_dmamap_unload(sc->txwi_dmat, data->map); 5564310d6deSBernhard Schmidt m_freem(data->m); 5574310d6deSBernhard Schmidt data->m = NULL; 5584310d6deSBernhard Schmidt } 5594310d6deSBernhard Schmidt if (data->ni != NULL) { 5604310d6deSBernhard Schmidt ieee80211_free_node(data->ni); 5614310d6deSBernhard Schmidt data->ni = NULL; 5624310d6deSBernhard Schmidt } 5634310d6deSBernhard Schmidt 5644310d6deSBernhard Schmidt SLIST_INSERT_HEAD(&sc->data_pool, data, next); 5654310d6deSBernhard Schmidt ring->data[i] = NULL; 5664310d6deSBernhard Schmidt } 5674310d6deSBernhard Schmidt 5684310d6deSBernhard Schmidt ring->queued = 0; 5694310d6deSBernhard Schmidt ring->cur = ring->next = 0; 5704310d6deSBernhard Schmidt } 5714310d6deSBernhard Schmidt 5724310d6deSBernhard Schmidt void 5734310d6deSBernhard Schmidt rt2860_free_tx_ring(struct rt2860_softc *sc, struct rt2860_tx_ring *ring) 5744310d6deSBernhard Schmidt { 5754310d6deSBernhard Schmidt struct rt2860_tx_data *data; 5764310d6deSBernhard Schmidt int i; 5774310d6deSBernhard Schmidt 5784310d6deSBernhard Schmidt if (ring->txd != NULL) { 5794310d6deSBernhard Schmidt bus_dmamap_sync(ring->desc_dmat, ring->desc_map, 5804310d6deSBernhard Schmidt BUS_DMASYNC_POSTWRITE); 5814310d6deSBernhard Schmidt bus_dmamap_unload(ring->desc_dmat, ring->desc_map); 5824310d6deSBernhard Schmidt bus_dmamem_free(ring->desc_dmat, ring->txd, ring->desc_map); 5834310d6deSBernhard Schmidt } 5844310d6deSBernhard Schmidt if (ring->desc_dmat != NULL) 5854310d6deSBernhard Schmidt bus_dma_tag_destroy(ring->desc_dmat); 5864310d6deSBernhard Schmidt 5874310d6deSBernhard Schmidt for (i = 0; i < RT2860_TX_RING_COUNT; i++) { 5884310d6deSBernhard Schmidt if ((data = ring->data[i]) == NULL) 5894310d6deSBernhard Schmidt continue; /* nothing mapped in this slot */ 5904310d6deSBernhard Schmidt 5914310d6deSBernhard Schmidt if (data->m != NULL) { 5924310d6deSBernhard Schmidt bus_dmamap_sync(sc->txwi_dmat, data->map, 5934310d6deSBernhard Schmidt BUS_DMASYNC_POSTWRITE); 5944310d6deSBernhard Schmidt bus_dmamap_unload(sc->txwi_dmat, data->map); 5954310d6deSBernhard Schmidt m_freem(data->m); 5964310d6deSBernhard Schmidt } 5974310d6deSBernhard Schmidt if (data->ni != NULL) 5984310d6deSBernhard Schmidt ieee80211_free_node(data->ni); 5994310d6deSBernhard Schmidt 6004310d6deSBernhard Schmidt SLIST_INSERT_HEAD(&sc->data_pool, data, next); 6014310d6deSBernhard Schmidt } 6024310d6deSBernhard Schmidt } 6034310d6deSBernhard Schmidt 6044310d6deSBernhard Schmidt /* 6054310d6deSBernhard Schmidt * Allocate a pool of TX Wireless Information blocks. 6064310d6deSBernhard Schmidt */ 6074310d6deSBernhard Schmidt int 6084310d6deSBernhard Schmidt rt2860_alloc_tx_pool(struct rt2860_softc *sc) 6094310d6deSBernhard Schmidt { 6104310d6deSBernhard Schmidt caddr_t vaddr; 6114310d6deSBernhard Schmidt bus_addr_t paddr; 6124310d6deSBernhard Schmidt int i, size, error; 6134310d6deSBernhard Schmidt 6144310d6deSBernhard Schmidt size = RT2860_TX_POOL_COUNT * RT2860_TXWI_DMASZ; 6154310d6deSBernhard Schmidt 6164310d6deSBernhard Schmidt /* init data_pool early in case of failure.. */ 6174310d6deSBernhard Schmidt SLIST_INIT(&sc->data_pool); 6184310d6deSBernhard Schmidt 6194310d6deSBernhard Schmidt error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, 6204310d6deSBernhard Schmidt BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 6214310d6deSBernhard Schmidt size, 1, size, 0, NULL, NULL, &sc->txwi_dmat); 6224310d6deSBernhard Schmidt if (error != 0) { 6234310d6deSBernhard Schmidt device_printf(sc->sc_dev, "could not create txwi DMA tag\n"); 6244310d6deSBernhard Schmidt goto fail; 6254310d6deSBernhard Schmidt } 6264310d6deSBernhard Schmidt 6274310d6deSBernhard Schmidt error = bus_dmamem_alloc(sc->txwi_dmat, (void **)&sc->txwi_vaddr, 6284310d6deSBernhard Schmidt BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sc->txwi_map); 6294310d6deSBernhard Schmidt if (error != 0) { 6304310d6deSBernhard Schmidt device_printf(sc->sc_dev, "could not allocate DMA memory\n"); 6314310d6deSBernhard Schmidt goto fail; 6324310d6deSBernhard Schmidt } 6334310d6deSBernhard Schmidt 6344310d6deSBernhard Schmidt error = bus_dmamap_load(sc->txwi_dmat, sc->txwi_map, 6354310d6deSBernhard Schmidt sc->txwi_vaddr, size, rt2860_dma_map_addr, &paddr, 0); 6364310d6deSBernhard Schmidt if (error != 0) { 6374310d6deSBernhard Schmidt device_printf(sc->sc_dev, "could not load txwi DMA map\n"); 6384310d6deSBernhard Schmidt goto fail; 6394310d6deSBernhard Schmidt } 6404310d6deSBernhard Schmidt 6414310d6deSBernhard Schmidt bus_dmamap_sync(sc->txwi_dmat, sc->txwi_map, BUS_DMASYNC_PREWRITE); 6424310d6deSBernhard Schmidt 6434310d6deSBernhard Schmidt vaddr = sc->txwi_vaddr; 6444310d6deSBernhard Schmidt for (i = 0; i < RT2860_TX_POOL_COUNT; i++) { 6454310d6deSBernhard Schmidt struct rt2860_tx_data *data = &sc->data[i]; 6464310d6deSBernhard Schmidt 6474310d6deSBernhard Schmidt error = bus_dmamap_create(sc->txwi_dmat, 0, &data->map); 6484310d6deSBernhard Schmidt if (error != 0) { 6494310d6deSBernhard Schmidt device_printf(sc->sc_dev, "could not create DMA map\n"); 6504310d6deSBernhard Schmidt goto fail; 6514310d6deSBernhard Schmidt } 6524310d6deSBernhard Schmidt data->txwi = (struct rt2860_txwi *)vaddr; 6534310d6deSBernhard Schmidt data->paddr = paddr; 6544310d6deSBernhard Schmidt vaddr += RT2860_TXWI_DMASZ; 6554310d6deSBernhard Schmidt paddr += RT2860_TXWI_DMASZ; 6564310d6deSBernhard Schmidt 6574310d6deSBernhard Schmidt SLIST_INSERT_HEAD(&sc->data_pool, data, next); 6584310d6deSBernhard Schmidt } 6594310d6deSBernhard Schmidt 6604310d6deSBernhard Schmidt return 0; 6614310d6deSBernhard Schmidt 6624310d6deSBernhard Schmidt fail: rt2860_free_tx_pool(sc); 6634310d6deSBernhard Schmidt return error; 6644310d6deSBernhard Schmidt } 6654310d6deSBernhard Schmidt 6664310d6deSBernhard Schmidt void 6674310d6deSBernhard Schmidt rt2860_free_tx_pool(struct rt2860_softc *sc) 6684310d6deSBernhard Schmidt { 6694310d6deSBernhard Schmidt if (sc->txwi_vaddr != NULL) { 6704310d6deSBernhard Schmidt bus_dmamap_sync(sc->txwi_dmat, sc->txwi_map, 6714310d6deSBernhard Schmidt BUS_DMASYNC_POSTWRITE); 6724310d6deSBernhard Schmidt bus_dmamap_unload(sc->txwi_dmat, sc->txwi_map); 6734310d6deSBernhard Schmidt bus_dmamem_free(sc->txwi_dmat, sc->txwi_vaddr, sc->txwi_map); 6744310d6deSBernhard Schmidt } 6754310d6deSBernhard Schmidt if (sc->txwi_dmat != NULL) 6764310d6deSBernhard Schmidt bus_dma_tag_destroy(sc->txwi_dmat); 6774310d6deSBernhard Schmidt 6784310d6deSBernhard Schmidt while (!SLIST_EMPTY(&sc->data_pool)) { 6794310d6deSBernhard Schmidt struct rt2860_tx_data *data; 6804310d6deSBernhard Schmidt data = SLIST_FIRST(&sc->data_pool); 6814310d6deSBernhard Schmidt bus_dmamap_destroy(sc->txwi_dmat, data->map); 6824310d6deSBernhard Schmidt SLIST_REMOVE_HEAD(&sc->data_pool, next); 6834310d6deSBernhard Schmidt } 6844310d6deSBernhard Schmidt } 6854310d6deSBernhard Schmidt 6864310d6deSBernhard Schmidt int 6874310d6deSBernhard Schmidt rt2860_alloc_rx_ring(struct rt2860_softc *sc, struct rt2860_rx_ring *ring) 6884310d6deSBernhard Schmidt { 6894310d6deSBernhard Schmidt bus_addr_t physaddr; 6904310d6deSBernhard Schmidt int i, size, error; 6914310d6deSBernhard Schmidt 6924310d6deSBernhard Schmidt size = RT2860_RX_RING_COUNT * sizeof (struct rt2860_rxd); 6934310d6deSBernhard Schmidt 6944310d6deSBernhard Schmidt error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 16, 0, 6954310d6deSBernhard Schmidt BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 6964310d6deSBernhard Schmidt size, 1, size, 0, NULL, NULL, &ring->desc_dmat); 6974310d6deSBernhard Schmidt if (error != 0) { 6984310d6deSBernhard Schmidt device_printf(sc->sc_dev, "could not create desc DMA tag\n"); 6994310d6deSBernhard Schmidt goto fail; 7004310d6deSBernhard Schmidt } 7014310d6deSBernhard Schmidt 7024310d6deSBernhard Schmidt error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->rxd, 7034310d6deSBernhard Schmidt BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); 7044310d6deSBernhard Schmidt if (error != 0) { 7054310d6deSBernhard Schmidt device_printf(sc->sc_dev, "could not allocate DMA memory\n"); 7064310d6deSBernhard Schmidt goto fail; 7074310d6deSBernhard Schmidt } 7084310d6deSBernhard Schmidt 7094310d6deSBernhard Schmidt error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->rxd, 7104310d6deSBernhard Schmidt size, rt2860_dma_map_addr, &ring->paddr, 0); 7114310d6deSBernhard Schmidt if (error != 0) { 7124310d6deSBernhard Schmidt device_printf(sc->sc_dev, "could not load desc DMA map\n"); 7134310d6deSBernhard Schmidt goto fail; 7144310d6deSBernhard Schmidt } 7154310d6deSBernhard Schmidt 7164310d6deSBernhard Schmidt error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, 7174310d6deSBernhard Schmidt BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 7184310d6deSBernhard Schmidt 1, MCLBYTES, 0, NULL, NULL, &ring->data_dmat); 7194310d6deSBernhard Schmidt if (error != 0) { 7204310d6deSBernhard Schmidt device_printf(sc->sc_dev, "could not create data DMA tag\n"); 7214310d6deSBernhard Schmidt goto fail; 7224310d6deSBernhard Schmidt } 7234310d6deSBernhard Schmidt 7244310d6deSBernhard Schmidt for (i = 0; i < RT2860_RX_RING_COUNT; i++) { 7254310d6deSBernhard Schmidt struct rt2860_rx_data *data = &ring->data[i]; 7264310d6deSBernhard Schmidt struct rt2860_rxd *rxd = &ring->rxd[i]; 7274310d6deSBernhard Schmidt 7284310d6deSBernhard Schmidt error = bus_dmamap_create(ring->data_dmat, 0, &data->map); 7294310d6deSBernhard Schmidt if (error != 0) { 7304310d6deSBernhard Schmidt device_printf(sc->sc_dev, "could not create DMA map\n"); 7314310d6deSBernhard Schmidt goto fail; 7324310d6deSBernhard Schmidt } 7334310d6deSBernhard Schmidt 734c6499eccSGleb Smirnoff data->m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 7354310d6deSBernhard Schmidt if (data->m == NULL) { 7364310d6deSBernhard Schmidt device_printf(sc->sc_dev, 7374310d6deSBernhard Schmidt "could not allocate rx mbuf\n"); 7384310d6deSBernhard Schmidt error = ENOMEM; 7394310d6deSBernhard Schmidt goto fail; 7404310d6deSBernhard Schmidt } 7414310d6deSBernhard Schmidt 7424310d6deSBernhard Schmidt error = bus_dmamap_load(ring->data_dmat, data->map, 7434310d6deSBernhard Schmidt mtod(data->m, void *), MCLBYTES, rt2860_dma_map_addr, 7444310d6deSBernhard Schmidt &physaddr, 0); 7454310d6deSBernhard Schmidt if (error != 0) { 7464310d6deSBernhard Schmidt device_printf(sc->sc_dev, 7474310d6deSBernhard Schmidt "could not load rx buf DMA map"); 7484310d6deSBernhard Schmidt goto fail; 7494310d6deSBernhard Schmidt } 7504310d6deSBernhard Schmidt 7514310d6deSBernhard Schmidt rxd->sdp0 = htole32(physaddr); 7524310d6deSBernhard Schmidt rxd->sdl0 = htole16(MCLBYTES); 7534310d6deSBernhard Schmidt } 7544310d6deSBernhard Schmidt 7554310d6deSBernhard Schmidt bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 7564310d6deSBernhard Schmidt 7574310d6deSBernhard Schmidt return 0; 7584310d6deSBernhard Schmidt 7594310d6deSBernhard Schmidt fail: rt2860_free_rx_ring(sc, ring); 7604310d6deSBernhard Schmidt return error; 7614310d6deSBernhard Schmidt } 7624310d6deSBernhard Schmidt 7634310d6deSBernhard Schmidt void 7644310d6deSBernhard Schmidt rt2860_reset_rx_ring(struct rt2860_softc *sc, struct rt2860_rx_ring *ring) 7654310d6deSBernhard Schmidt { 7664310d6deSBernhard Schmidt int i; 7674310d6deSBernhard Schmidt 7684310d6deSBernhard Schmidt for (i = 0; i < RT2860_RX_RING_COUNT; i++) 7694310d6deSBernhard Schmidt ring->rxd[i].sdl0 &= ~htole16(RT2860_RX_DDONE); 7704310d6deSBernhard Schmidt 7714310d6deSBernhard Schmidt bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 7724310d6deSBernhard Schmidt 7734310d6deSBernhard Schmidt ring->cur = 0; 7744310d6deSBernhard Schmidt } 7754310d6deSBernhard Schmidt 7764310d6deSBernhard Schmidt void 7774310d6deSBernhard Schmidt rt2860_free_rx_ring(struct rt2860_softc *sc, struct rt2860_rx_ring *ring) 7784310d6deSBernhard Schmidt { 7794310d6deSBernhard Schmidt int i; 7804310d6deSBernhard Schmidt 7814310d6deSBernhard Schmidt if (ring->rxd != NULL) { 7824310d6deSBernhard Schmidt bus_dmamap_sync(ring->desc_dmat, ring->desc_map, 7834310d6deSBernhard Schmidt BUS_DMASYNC_POSTWRITE); 7844310d6deSBernhard Schmidt bus_dmamap_unload(ring->desc_dmat, ring->desc_map); 7854310d6deSBernhard Schmidt bus_dmamem_free(ring->desc_dmat, ring->rxd, ring->desc_map); 7864310d6deSBernhard Schmidt } 7874310d6deSBernhard Schmidt if (ring->desc_dmat != NULL) 7884310d6deSBernhard Schmidt bus_dma_tag_destroy(ring->desc_dmat); 7894310d6deSBernhard Schmidt 7904310d6deSBernhard Schmidt for (i = 0; i < RT2860_RX_RING_COUNT; i++) { 7914310d6deSBernhard Schmidt struct rt2860_rx_data *data = &ring->data[i]; 7924310d6deSBernhard Schmidt 7934310d6deSBernhard Schmidt if (data->m != NULL) { 7944310d6deSBernhard Schmidt bus_dmamap_sync(ring->data_dmat, data->map, 7954310d6deSBernhard Schmidt BUS_DMASYNC_POSTREAD); 7964310d6deSBernhard Schmidt bus_dmamap_unload(ring->data_dmat, data->map); 7974310d6deSBernhard Schmidt m_freem(data->m); 7984310d6deSBernhard Schmidt } 7994310d6deSBernhard Schmidt if (data->map != NULL) 8004310d6deSBernhard Schmidt bus_dmamap_destroy(ring->data_dmat, data->map); 8014310d6deSBernhard Schmidt } 8024310d6deSBernhard Schmidt if (ring->data_dmat != NULL) 8034310d6deSBernhard Schmidt bus_dma_tag_destroy(ring->data_dmat); 8044310d6deSBernhard Schmidt } 8054310d6deSBernhard Schmidt 8064310d6deSBernhard Schmidt static void 8074310d6deSBernhard Schmidt rt2860_updatestats(struct rt2860_softc *sc) 8084310d6deSBernhard Schmidt { 8097a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 8104310d6deSBernhard Schmidt 8114310d6deSBernhard Schmidt /* 8124310d6deSBernhard Schmidt * In IBSS or HostAP modes (when the hardware sends beacons), the 8134310d6deSBernhard Schmidt * MAC can run into a livelock and start sending CTS-to-self frames 8144310d6deSBernhard Schmidt * like crazy if protection is enabled. Fortunately, we can detect 8154310d6deSBernhard Schmidt * when such a situation occurs and reset the MAC. 8164310d6deSBernhard Schmidt */ 8174310d6deSBernhard Schmidt if (ic->ic_curmode != IEEE80211_M_STA) { 8184310d6deSBernhard Schmidt /* check if we're in a livelock situation.. */ 8194310d6deSBernhard Schmidt uint32_t tmp = RAL_READ(sc, RT2860_DEBUG); 8204310d6deSBernhard Schmidt if ((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))) { 8214310d6deSBernhard Schmidt /* ..and reset MAC/BBP for a while.. */ 8224310d6deSBernhard Schmidt DPRINTF(("CTS-to-self livelock detected\n")); 8234310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST); 8244310d6deSBernhard Schmidt RAL_BARRIER_WRITE(sc); 8254310d6deSBernhard Schmidt DELAY(1); 8264310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_MAC_SYS_CTRL, 8274310d6deSBernhard Schmidt RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 8284310d6deSBernhard Schmidt } 8294310d6deSBernhard Schmidt } 8304310d6deSBernhard Schmidt } 8314310d6deSBernhard Schmidt 8324310d6deSBernhard Schmidt static void 8334310d6deSBernhard Schmidt rt2860_newassoc(struct ieee80211_node *ni, int isnew) 8344310d6deSBernhard Schmidt { 8354310d6deSBernhard Schmidt struct ieee80211com *ic = ni->ni_ic; 8367a79cebfSGleb Smirnoff struct rt2860_softc *sc = ic->ic_softc; 8374310d6deSBernhard Schmidt uint8_t wcid; 8384310d6deSBernhard Schmidt 8394310d6deSBernhard Schmidt wcid = IEEE80211_AID(ni->ni_associd); 8404310d6deSBernhard Schmidt if (isnew && ni->ni_associd != 0) { 8414310d6deSBernhard Schmidt sc->wcid2ni[wcid] = ni; 8424310d6deSBernhard Schmidt 8434310d6deSBernhard Schmidt /* init WCID table entry */ 8444310d6deSBernhard Schmidt RAL_WRITE_REGION_1(sc, RT2860_WCID_ENTRY(wcid), 8454310d6deSBernhard Schmidt ni->ni_macaddr, IEEE80211_ADDR_LEN); 8464310d6deSBernhard Schmidt } 8474310d6deSBernhard Schmidt DPRINTF(("new assoc isnew=%d addr=%s WCID=%d\n", 8484310d6deSBernhard Schmidt isnew, ether_sprintf(ni->ni_macaddr), wcid)); 8494310d6deSBernhard Schmidt } 8504310d6deSBernhard Schmidt 8514310d6deSBernhard Schmidt static void 8524310d6deSBernhard Schmidt rt2860_node_free(struct ieee80211_node *ni) 8534310d6deSBernhard Schmidt { 8544310d6deSBernhard Schmidt struct ieee80211com *ic = ni->ni_ic; 8557a79cebfSGleb Smirnoff struct rt2860_softc *sc = ic->ic_softc; 8564310d6deSBernhard Schmidt uint8_t wcid; 8574310d6deSBernhard Schmidt 8584310d6deSBernhard Schmidt if (ni->ni_associd != 0) { 8594310d6deSBernhard Schmidt wcid = IEEE80211_AID(ni->ni_associd); 8604310d6deSBernhard Schmidt 8614310d6deSBernhard Schmidt /* clear Rx WCID search table entry */ 8624310d6deSBernhard Schmidt RAL_SET_REGION_4(sc, RT2860_WCID_ENTRY(wcid), 0, 2); 8634310d6deSBernhard Schmidt } 8644310d6deSBernhard Schmidt sc->sc_node_free(ni); 8654310d6deSBernhard Schmidt } 8664310d6deSBernhard Schmidt 8674310d6deSBernhard Schmidt #ifdef IEEE80211_HT 8684310d6deSBernhard Schmidt static int 8694310d6deSBernhard Schmidt rt2860_ampdu_rx_start(struct ieee80211com *ic, struct ieee80211_node *ni, 8704310d6deSBernhard Schmidt uint8_t tid) 8714310d6deSBernhard Schmidt { 8724310d6deSBernhard Schmidt struct rt2860_softc *sc = ic->ic_softc; 8734310d6deSBernhard Schmidt uint8_t wcid = ((struct rt2860_node *)ni)->wcid; 8744310d6deSBernhard Schmidt uint32_t tmp; 8754310d6deSBernhard Schmidt 8764310d6deSBernhard Schmidt /* update BA session mask */ 8774310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_WCID_ENTRY(wcid) + 4); 8784310d6deSBernhard Schmidt tmp |= (1 << tid) << 16; 8794310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_WCID_ENTRY(wcid) + 4, tmp); 8804310d6deSBernhard Schmidt return 0; 8814310d6deSBernhard Schmidt } 8824310d6deSBernhard Schmidt 8834310d6deSBernhard Schmidt static void 8844310d6deSBernhard Schmidt rt2860_ampdu_rx_stop(struct ieee80211com *ic, struct ieee80211_node *ni, 8854310d6deSBernhard Schmidt uint8_t tid) 8864310d6deSBernhard Schmidt { 8874310d6deSBernhard Schmidt struct rt2860_softc *sc = ic->ic_softc; 8884310d6deSBernhard Schmidt uint8_t wcid = ((struct rt2860_node *)ni)->wcid; 8894310d6deSBernhard Schmidt uint32_t tmp; 8904310d6deSBernhard Schmidt 8914310d6deSBernhard Schmidt /* update BA session mask */ 8924310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_WCID_ENTRY(wcid) + 4); 8934310d6deSBernhard Schmidt tmp &= ~((1 << tid) << 16); 8944310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_WCID_ENTRY(wcid) + 4, tmp); 8954310d6deSBernhard Schmidt } 8964310d6deSBernhard Schmidt #endif 8974310d6deSBernhard Schmidt 8985c95ab02SKevin Lo static int 8994310d6deSBernhard Schmidt rt2860_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 9004310d6deSBernhard Schmidt { 9014310d6deSBernhard Schmidt struct rt2860_vap *rvp = RT2860_VAP(vap); 9024310d6deSBernhard Schmidt struct ieee80211com *ic = vap->iv_ic; 9037a79cebfSGleb Smirnoff struct rt2860_softc *sc = ic->ic_softc; 9044310d6deSBernhard Schmidt uint32_t tmp; 9054310d6deSBernhard Schmidt int error; 9064310d6deSBernhard Schmidt 9074310d6deSBernhard Schmidt if (vap->iv_state == IEEE80211_S_RUN) { 9084310d6deSBernhard Schmidt /* turn link LED off */ 9094310d6deSBernhard Schmidt rt2860_set_leds(sc, RT2860_LED_RADIO); 9104310d6deSBernhard Schmidt } 9114310d6deSBernhard Schmidt 9124310d6deSBernhard Schmidt if (nstate == IEEE80211_S_INIT && vap->iv_state == IEEE80211_S_RUN) { 9134310d6deSBernhard Schmidt /* abort TSF synchronization */ 9144310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_BCN_TIME_CFG); 9154310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_BCN_TIME_CFG, 9164310d6deSBernhard Schmidt tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 9174310d6deSBernhard Schmidt RT2860_TBTT_TIMER_EN)); 9184310d6deSBernhard Schmidt } 9194310d6deSBernhard Schmidt 9204310d6deSBernhard Schmidt rt2860_set_gp_timer(sc, 0); 9214310d6deSBernhard Schmidt 9224310d6deSBernhard Schmidt error = rvp->ral_newstate(vap, nstate, arg); 9234310d6deSBernhard Schmidt if (error != 0) 9244310d6deSBernhard Schmidt return (error); 9254310d6deSBernhard Schmidt 9264310d6deSBernhard Schmidt if (nstate == IEEE80211_S_RUN) { 9274310d6deSBernhard Schmidt struct ieee80211_node *ni = vap->iv_bss; 9284310d6deSBernhard Schmidt 9294310d6deSBernhard Schmidt if (ic->ic_opmode != IEEE80211_M_MONITOR) { 9304310d6deSBernhard Schmidt rt2860_enable_mrr(sc); 9314310d6deSBernhard Schmidt rt2860_set_txpreamble(sc); 9324310d6deSBernhard Schmidt rt2860_set_basicrates(sc, &ni->ni_rates); 9334310d6deSBernhard Schmidt rt2860_set_bssid(sc, ni->ni_bssid); 9344310d6deSBernhard Schmidt } 9354310d6deSBernhard Schmidt 9364310d6deSBernhard Schmidt if (vap->iv_opmode == IEEE80211_M_HOSTAP || 9374310d6deSBernhard Schmidt vap->iv_opmode == IEEE80211_M_IBSS || 9384310d6deSBernhard Schmidt vap->iv_opmode == IEEE80211_M_MBSS) { 9394310d6deSBernhard Schmidt error = rt2860_setup_beacon(sc, vap); 9404310d6deSBernhard Schmidt if (error != 0) 9414310d6deSBernhard Schmidt return error; 9424310d6deSBernhard Schmidt } 9434310d6deSBernhard Schmidt 9444310d6deSBernhard Schmidt if (ic->ic_opmode != IEEE80211_M_MONITOR) { 9454310d6deSBernhard Schmidt rt2860_enable_tsf_sync(sc); 9464310d6deSBernhard Schmidt rt2860_set_gp_timer(sc, 500); 9474310d6deSBernhard Schmidt } 9484310d6deSBernhard Schmidt 9494310d6deSBernhard Schmidt /* turn link LED on */ 9504310d6deSBernhard Schmidt rt2860_set_leds(sc, RT2860_LED_RADIO | 9514310d6deSBernhard Schmidt (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan) ? 9524310d6deSBernhard Schmidt RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ)); 9534310d6deSBernhard Schmidt } 9544310d6deSBernhard Schmidt return error; 9554310d6deSBernhard Schmidt } 9564310d6deSBernhard Schmidt 9574310d6deSBernhard Schmidt /* Read 16-bit from eFUSE ROM (>=RT3071 only.) */ 9584310d6deSBernhard Schmidt static uint16_t 9594310d6deSBernhard Schmidt rt3090_efuse_read_2(struct rt2860_softc *sc, uint16_t addr) 9604310d6deSBernhard Schmidt { 9614310d6deSBernhard Schmidt uint32_t tmp; 9624310d6deSBernhard Schmidt uint16_t reg; 9634310d6deSBernhard Schmidt int ntries; 9644310d6deSBernhard Schmidt 9654310d6deSBernhard Schmidt addr *= 2; 9664310d6deSBernhard Schmidt /*- 9674310d6deSBernhard Schmidt * Read one 16-byte block into registers EFUSE_DATA[0-3]: 9684310d6deSBernhard Schmidt * DATA0: F E D C 9694310d6deSBernhard Schmidt * DATA1: B A 9 8 9704310d6deSBernhard Schmidt * DATA2: 7 6 5 4 9714310d6deSBernhard Schmidt * DATA3: 3 2 1 0 9724310d6deSBernhard Schmidt */ 9734310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT3070_EFUSE_CTRL); 9744310d6deSBernhard Schmidt tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK); 9754310d6deSBernhard Schmidt tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK; 9764310d6deSBernhard Schmidt RAL_WRITE(sc, RT3070_EFUSE_CTRL, tmp); 9774310d6deSBernhard Schmidt for (ntries = 0; ntries < 500; ntries++) { 9784310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT3070_EFUSE_CTRL); 9794310d6deSBernhard Schmidt if (!(tmp & RT3070_EFSROM_KICK)) 9804310d6deSBernhard Schmidt break; 9814310d6deSBernhard Schmidt DELAY(2); 9824310d6deSBernhard Schmidt } 9834310d6deSBernhard Schmidt if (ntries == 500) 9844310d6deSBernhard Schmidt return 0xffff; 9854310d6deSBernhard Schmidt 9864310d6deSBernhard Schmidt if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK) 9874310d6deSBernhard Schmidt return 0xffff; /* address not found */ 9884310d6deSBernhard Schmidt 9894310d6deSBernhard Schmidt /* determine to which 32-bit register our 16-bit word belongs */ 9904310d6deSBernhard Schmidt reg = RT3070_EFUSE_DATA3 - (addr & 0xc); 9914310d6deSBernhard Schmidt tmp = RAL_READ(sc, reg); 9924310d6deSBernhard Schmidt 9934310d6deSBernhard Schmidt return (addr & 2) ? tmp >> 16 : tmp & 0xffff; 9944310d6deSBernhard Schmidt } 9954310d6deSBernhard Schmidt 9964310d6deSBernhard Schmidt /* 9974310d6deSBernhard Schmidt * Read 16 bits at address 'addr' from the serial EEPROM (either 93C46, 9984310d6deSBernhard Schmidt * 93C66 or 93C86). 9994310d6deSBernhard Schmidt */ 10004310d6deSBernhard Schmidt static uint16_t 10014310d6deSBernhard Schmidt rt2860_eeprom_read_2(struct rt2860_softc *sc, uint16_t addr) 10024310d6deSBernhard Schmidt { 10034310d6deSBernhard Schmidt uint32_t tmp; 10044310d6deSBernhard Schmidt uint16_t val; 10054310d6deSBernhard Schmidt int n; 10064310d6deSBernhard Schmidt 10074310d6deSBernhard Schmidt /* clock C once before the first command */ 10084310d6deSBernhard Schmidt RT2860_EEPROM_CTL(sc, 0); 10094310d6deSBernhard Schmidt 10104310d6deSBernhard Schmidt RT2860_EEPROM_CTL(sc, RT2860_S); 10114310d6deSBernhard Schmidt RT2860_EEPROM_CTL(sc, RT2860_S | RT2860_C); 10124310d6deSBernhard Schmidt RT2860_EEPROM_CTL(sc, RT2860_S); 10134310d6deSBernhard Schmidt 10144310d6deSBernhard Schmidt /* write start bit (1) */ 10154310d6deSBernhard Schmidt RT2860_EEPROM_CTL(sc, RT2860_S | RT2860_D); 10164310d6deSBernhard Schmidt RT2860_EEPROM_CTL(sc, RT2860_S | RT2860_D | RT2860_C); 10174310d6deSBernhard Schmidt 10184310d6deSBernhard Schmidt /* write READ opcode (10) */ 10194310d6deSBernhard Schmidt RT2860_EEPROM_CTL(sc, RT2860_S | RT2860_D); 10204310d6deSBernhard Schmidt RT2860_EEPROM_CTL(sc, RT2860_S | RT2860_D | RT2860_C); 10214310d6deSBernhard Schmidt RT2860_EEPROM_CTL(sc, RT2860_S); 10224310d6deSBernhard Schmidt RT2860_EEPROM_CTL(sc, RT2860_S | RT2860_C); 10234310d6deSBernhard Schmidt 10244310d6deSBernhard Schmidt /* write address (A5-A0 or A7-A0) */ 10254310d6deSBernhard Schmidt n = ((RAL_READ(sc, RT2860_PCI_EECTRL) & 0x30) == 0) ? 5 : 7; 10264310d6deSBernhard Schmidt for (; n >= 0; n--) { 10274310d6deSBernhard Schmidt RT2860_EEPROM_CTL(sc, RT2860_S | 10284310d6deSBernhard Schmidt (((addr >> n) & 1) << RT2860_SHIFT_D)); 10294310d6deSBernhard Schmidt RT2860_EEPROM_CTL(sc, RT2860_S | 10304310d6deSBernhard Schmidt (((addr >> n) & 1) << RT2860_SHIFT_D) | RT2860_C); 10314310d6deSBernhard Schmidt } 10324310d6deSBernhard Schmidt 10334310d6deSBernhard Schmidt RT2860_EEPROM_CTL(sc, RT2860_S); 10344310d6deSBernhard Schmidt 10354310d6deSBernhard Schmidt /* read data Q15-Q0 */ 10364310d6deSBernhard Schmidt val = 0; 10374310d6deSBernhard Schmidt for (n = 15; n >= 0; n--) { 10384310d6deSBernhard Schmidt RT2860_EEPROM_CTL(sc, RT2860_S | RT2860_C); 10394310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_PCI_EECTRL); 10404310d6deSBernhard Schmidt val |= ((tmp & RT2860_Q) >> RT2860_SHIFT_Q) << n; 10414310d6deSBernhard Schmidt RT2860_EEPROM_CTL(sc, RT2860_S); 10424310d6deSBernhard Schmidt } 10434310d6deSBernhard Schmidt 10444310d6deSBernhard Schmidt RT2860_EEPROM_CTL(sc, 0); 10454310d6deSBernhard Schmidt 10464310d6deSBernhard Schmidt /* clear Chip Select and clock C */ 10474310d6deSBernhard Schmidt RT2860_EEPROM_CTL(sc, RT2860_S); 10484310d6deSBernhard Schmidt RT2860_EEPROM_CTL(sc, 0); 10494310d6deSBernhard Schmidt RT2860_EEPROM_CTL(sc, RT2860_C); 10504310d6deSBernhard Schmidt 10514310d6deSBernhard Schmidt return val; 10524310d6deSBernhard Schmidt } 10534310d6deSBernhard Schmidt 10544310d6deSBernhard Schmidt static __inline uint16_t 10554310d6deSBernhard Schmidt rt2860_srom_read(struct rt2860_softc *sc, uint8_t addr) 10564310d6deSBernhard Schmidt { 10574310d6deSBernhard Schmidt /* either eFUSE ROM or EEPROM */ 10584310d6deSBernhard Schmidt return sc->sc_srom_read(sc, addr); 10594310d6deSBernhard Schmidt } 10604310d6deSBernhard Schmidt 10614310d6deSBernhard Schmidt static void 10624310d6deSBernhard Schmidt rt2860_intr_coherent(struct rt2860_softc *sc) 10634310d6deSBernhard Schmidt { 10644310d6deSBernhard Schmidt uint32_t tmp; 10654310d6deSBernhard Schmidt 10664310d6deSBernhard Schmidt /* DMA finds data coherent event when checking the DDONE bit */ 10674310d6deSBernhard Schmidt 10684310d6deSBernhard Schmidt DPRINTF(("Tx/Rx Coherent interrupt\n")); 10694310d6deSBernhard Schmidt 10704310d6deSBernhard Schmidt /* restart DMA engine */ 10714310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_WPDMA_GLO_CFG); 10724310d6deSBernhard Schmidt tmp &= ~(RT2860_TX_WB_DDONE | RT2860_RX_DMA_EN | RT2860_TX_DMA_EN); 10734310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_WPDMA_GLO_CFG, tmp); 10744310d6deSBernhard Schmidt 10754310d6deSBernhard Schmidt (void)rt2860_txrx_enable(sc); 10764310d6deSBernhard Schmidt } 10774310d6deSBernhard Schmidt 10784310d6deSBernhard Schmidt static void 10794310d6deSBernhard Schmidt rt2860_drain_stats_fifo(struct rt2860_softc *sc) 10804310d6deSBernhard Schmidt { 1081f6930becSAndriy Voskoboinyk struct ieee80211_ratectl_tx_status *txs = &sc->sc_txs; 10824310d6deSBernhard Schmidt struct ieee80211_node *ni; 10834310d6deSBernhard Schmidt uint32_t stat; 10844310d6deSBernhard Schmidt uint8_t wcid, mcs, pid; 10854310d6deSBernhard Schmidt 10864310d6deSBernhard Schmidt /* drain Tx status FIFO (maxsize = 16) */ 1087f6930becSAndriy Voskoboinyk txs->flags = IEEE80211_RATECTL_STATUS_LONG_RETRY; 10884310d6deSBernhard Schmidt while ((stat = RAL_READ(sc, RT2860_TX_STAT_FIFO)) & RT2860_TXQ_VLD) { 10894310d6deSBernhard Schmidt DPRINTFN(4, ("tx stat 0x%08x\n", stat)); 10904310d6deSBernhard Schmidt 10914310d6deSBernhard Schmidt wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff; 109282bac68cSKyle Evans if (wcid > RT2860_WCID_MAX) 109382bac68cSKyle Evans continue; 10944310d6deSBernhard Schmidt ni = sc->wcid2ni[wcid]; 10954310d6deSBernhard Schmidt 10964310d6deSBernhard Schmidt /* if no ACK was requested, no feedback is available */ 109782bac68cSKyle Evans if (!(stat & RT2860_TXQ_ACKREQ) || ni == NULL) 10984310d6deSBernhard Schmidt continue; 10994310d6deSBernhard Schmidt 11004310d6deSBernhard Schmidt /* update per-STA AMRR stats */ 11014310d6deSBernhard Schmidt if (stat & RT2860_TXQ_OK) { 11024310d6deSBernhard Schmidt /* 11034310d6deSBernhard Schmidt * Check if there were retries, ie if the Tx success 11044310d6deSBernhard Schmidt * rate is different from the requested rate. Note 11054310d6deSBernhard Schmidt * that it works only because we do not allow rate 11064310d6deSBernhard Schmidt * fallback from OFDM to CCK. 11074310d6deSBernhard Schmidt */ 11084310d6deSBernhard Schmidt mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f; 11094310d6deSBernhard Schmidt pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf; 11104310d6deSBernhard Schmidt if (mcs + 1 != pid) 1111f6930becSAndriy Voskoboinyk txs->long_retries = 1; 11124310d6deSBernhard Schmidt else 1113f6930becSAndriy Voskoboinyk txs->long_retries = 0; 1114f6930becSAndriy Voskoboinyk txs->status = IEEE80211_RATECTL_TX_SUCCESS; 1115f6930becSAndriy Voskoboinyk ieee80211_ratectl_tx_complete(ni, txs); 11164310d6deSBernhard Schmidt } else { 1117f6930becSAndriy Voskoboinyk txs->status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED; 1118f6930becSAndriy Voskoboinyk txs->long_retries = 1; /* XXX */ 1119f6930becSAndriy Voskoboinyk ieee80211_ratectl_tx_complete(ni, txs); 11207a79cebfSGleb Smirnoff if_inc_counter(ni->ni_vap->iv_ifp, 11217a79cebfSGleb Smirnoff IFCOUNTER_OERRORS, 1); 11224310d6deSBernhard Schmidt } 11234310d6deSBernhard Schmidt } 11244310d6deSBernhard Schmidt } 11254310d6deSBernhard Schmidt 11264310d6deSBernhard Schmidt static void 11274310d6deSBernhard Schmidt rt2860_tx_intr(struct rt2860_softc *sc, int qid) 11284310d6deSBernhard Schmidt { 11294310d6deSBernhard Schmidt struct rt2860_tx_ring *ring = &sc->txq[qid]; 11304310d6deSBernhard Schmidt uint32_t hw; 11314310d6deSBernhard Schmidt 11324310d6deSBernhard Schmidt rt2860_drain_stats_fifo(sc); 11334310d6deSBernhard Schmidt 11344310d6deSBernhard Schmidt hw = RAL_READ(sc, RT2860_TX_DTX_IDX(qid)); 11354310d6deSBernhard Schmidt while (ring->next != hw) { 11364310d6deSBernhard Schmidt struct rt2860_tx_data *data = ring->data[ring->next]; 11374310d6deSBernhard Schmidt 11384310d6deSBernhard Schmidt if (data != NULL) { 11394310d6deSBernhard Schmidt bus_dmamap_sync(sc->txwi_dmat, data->map, 11404310d6deSBernhard Schmidt BUS_DMASYNC_POSTWRITE); 11414310d6deSBernhard Schmidt bus_dmamap_unload(sc->txwi_dmat, data->map); 11427a79cebfSGleb Smirnoff ieee80211_tx_complete(data->ni, data->m, 0); 1143ba2c1fbcSAdrian Chadd data->ni = NULL; 11447a79cebfSGleb Smirnoff data->m = NULL; 11454310d6deSBernhard Schmidt SLIST_INSERT_HEAD(&sc->data_pool, data, next); 11464310d6deSBernhard Schmidt ring->data[ring->next] = NULL; 11474310d6deSBernhard Schmidt } 11484310d6deSBernhard Schmidt ring->queued--; 11494310d6deSBernhard Schmidt ring->next = (ring->next + 1) % RT2860_TX_RING_COUNT; 11504310d6deSBernhard Schmidt } 11514310d6deSBernhard Schmidt 11524310d6deSBernhard Schmidt sc->sc_tx_timer = 0; 11534310d6deSBernhard Schmidt if (ring->queued < RT2860_TX_RING_COUNT) 11544310d6deSBernhard Schmidt sc->qfullmsk &= ~(1 << qid); 11557a79cebfSGleb Smirnoff rt2860_start(sc); 11564310d6deSBernhard Schmidt } 11574310d6deSBernhard Schmidt 11584310d6deSBernhard Schmidt /* 11594310d6deSBernhard Schmidt * Return the Rx chain with the highest RSSI for a given frame. 11604310d6deSBernhard Schmidt */ 11614310d6deSBernhard Schmidt static __inline uint8_t 11624310d6deSBernhard Schmidt rt2860_maxrssi_chain(struct rt2860_softc *sc, const struct rt2860_rxwi *rxwi) 11634310d6deSBernhard Schmidt { 11644310d6deSBernhard Schmidt uint8_t rxchain = 0; 11654310d6deSBernhard Schmidt 11664310d6deSBernhard Schmidt if (sc->nrxchains > 1) { 11674310d6deSBernhard Schmidt if (rxwi->rssi[1] > rxwi->rssi[rxchain]) 11684310d6deSBernhard Schmidt rxchain = 1; 11694310d6deSBernhard Schmidt if (sc->nrxchains > 2) 11704310d6deSBernhard Schmidt if (rxwi->rssi[2] > rxwi->rssi[rxchain]) 11714310d6deSBernhard Schmidt rxchain = 2; 11724310d6deSBernhard Schmidt } 11734310d6deSBernhard Schmidt return rxchain; 11744310d6deSBernhard Schmidt } 11754310d6deSBernhard Schmidt 11764310d6deSBernhard Schmidt static void 11774310d6deSBernhard Schmidt rt2860_rx_intr(struct rt2860_softc *sc) 11784310d6deSBernhard Schmidt { 11794310d6deSBernhard Schmidt struct rt2860_rx_radiotap_header *tap; 11807a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 11814310d6deSBernhard Schmidt struct ieee80211_frame *wh; 11824310d6deSBernhard Schmidt struct ieee80211_node *ni; 11834310d6deSBernhard Schmidt struct mbuf *m, *m1; 11844310d6deSBernhard Schmidt bus_addr_t physaddr; 11854310d6deSBernhard Schmidt uint32_t hw; 11864310d6deSBernhard Schmidt uint16_t phy; 11874310d6deSBernhard Schmidt uint8_t ant; 11884310d6deSBernhard Schmidt int8_t rssi, nf; 11894310d6deSBernhard Schmidt int error; 11904310d6deSBernhard Schmidt 11914310d6deSBernhard Schmidt hw = RAL_READ(sc, RT2860_FS_DRX_IDX) & 0xfff; 11924310d6deSBernhard Schmidt while (sc->rxq.cur != hw) { 11934310d6deSBernhard Schmidt struct rt2860_rx_data *data = &sc->rxq.data[sc->rxq.cur]; 11944310d6deSBernhard Schmidt struct rt2860_rxd *rxd = &sc->rxq.rxd[sc->rxq.cur]; 11954310d6deSBernhard Schmidt struct rt2860_rxwi *rxwi; 11964310d6deSBernhard Schmidt 11974310d6deSBernhard Schmidt bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 11984310d6deSBernhard Schmidt BUS_DMASYNC_POSTREAD); 11994310d6deSBernhard Schmidt 12004310d6deSBernhard Schmidt if (__predict_false(!(rxd->sdl0 & htole16(RT2860_RX_DDONE)))) { 12014310d6deSBernhard Schmidt DPRINTF(("RXD DDONE bit not set!\n")); 12024310d6deSBernhard Schmidt break; /* should not happen */ 12034310d6deSBernhard Schmidt } 12044310d6deSBernhard Schmidt 12054310d6deSBernhard Schmidt if (__predict_false(rxd->flags & 12064310d6deSBernhard Schmidt htole32(RT2860_RX_CRCERR | RT2860_RX_ICVERR))) { 12077a79cebfSGleb Smirnoff counter_u64_add(ic->ic_ierrors, 1); 12084310d6deSBernhard Schmidt goto skip; 12094310d6deSBernhard Schmidt } 12104310d6deSBernhard Schmidt 12114310d6deSBernhard Schmidt #ifdef HW_CRYPTO 12124310d6deSBernhard Schmidt if (__predict_false(rxd->flags & htole32(RT2860_RX_MICERR))) { 12134310d6deSBernhard Schmidt /* report MIC failures to net80211 for TKIP */ 12144310d6deSBernhard Schmidt ic->ic_stats.is_rx_locmicfail++; 12154310d6deSBernhard Schmidt ieee80211_michael_mic_failure(ic, 0/* XXX */); 12167a79cebfSGleb Smirnoff counter_u64_add(ic->ic_ierrors, 1); 12174310d6deSBernhard Schmidt goto skip; 12184310d6deSBernhard Schmidt } 12194310d6deSBernhard Schmidt #endif 12204310d6deSBernhard Schmidt 1221c6499eccSGleb Smirnoff m1 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 12224310d6deSBernhard Schmidt if (__predict_false(m1 == NULL)) { 12237a79cebfSGleb Smirnoff counter_u64_add(ic->ic_ierrors, 1); 12244310d6deSBernhard Schmidt goto skip; 12254310d6deSBernhard Schmidt } 12264310d6deSBernhard Schmidt 12274310d6deSBernhard Schmidt bus_dmamap_sync(sc->rxq.data_dmat, data->map, 12284310d6deSBernhard Schmidt BUS_DMASYNC_POSTREAD); 12294310d6deSBernhard Schmidt bus_dmamap_unload(sc->rxq.data_dmat, data->map); 12304310d6deSBernhard Schmidt 12314310d6deSBernhard Schmidt error = bus_dmamap_load(sc->rxq.data_dmat, data->map, 12324310d6deSBernhard Schmidt mtod(m1, void *), MCLBYTES, rt2860_dma_map_addr, 12334310d6deSBernhard Schmidt &physaddr, 0); 12344310d6deSBernhard Schmidt if (__predict_false(error != 0)) { 12354310d6deSBernhard Schmidt m_freem(m1); 12364310d6deSBernhard Schmidt 12374310d6deSBernhard Schmidt /* try to reload the old mbuf */ 12384310d6deSBernhard Schmidt error = bus_dmamap_load(sc->rxq.data_dmat, data->map, 12394310d6deSBernhard Schmidt mtod(data->m, void *), MCLBYTES, 12404310d6deSBernhard Schmidt rt2860_dma_map_addr, &physaddr, 0); 12414310d6deSBernhard Schmidt if (__predict_false(error != 0)) { 12424310d6deSBernhard Schmidt panic("%s: could not load old rx mbuf", 12434310d6deSBernhard Schmidt device_get_name(sc->sc_dev)); 12444310d6deSBernhard Schmidt } 12454310d6deSBernhard Schmidt /* physical address may have changed */ 12464310d6deSBernhard Schmidt rxd->sdp0 = htole32(physaddr); 12477a79cebfSGleb Smirnoff counter_u64_add(ic->ic_ierrors, 1); 12484310d6deSBernhard Schmidt goto skip; 12494310d6deSBernhard Schmidt } 12504310d6deSBernhard Schmidt 12514310d6deSBernhard Schmidt /* 12524310d6deSBernhard Schmidt * New mbuf successfully loaded, update Rx ring and continue 12534310d6deSBernhard Schmidt * processing. 12544310d6deSBernhard Schmidt */ 12554310d6deSBernhard Schmidt m = data->m; 12564310d6deSBernhard Schmidt data->m = m1; 12574310d6deSBernhard Schmidt rxd->sdp0 = htole32(physaddr); 12584310d6deSBernhard Schmidt 12594310d6deSBernhard Schmidt rxwi = mtod(m, struct rt2860_rxwi *); 12604310d6deSBernhard Schmidt 12614310d6deSBernhard Schmidt /* finalize mbuf */ 12624310d6deSBernhard Schmidt m->m_data = (caddr_t)(rxwi + 1); 12634310d6deSBernhard Schmidt m->m_pkthdr.len = m->m_len = le16toh(rxwi->len) & 0xfff; 12644310d6deSBernhard Schmidt 12654310d6deSBernhard Schmidt wh = mtod(m, struct ieee80211_frame *); 12664310d6deSBernhard Schmidt #ifdef HW_CRYPTO 12675945b5f5SKevin Lo if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { 12684310d6deSBernhard Schmidt /* frame is decrypted by hardware */ 12695945b5f5SKevin Lo wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; 12704310d6deSBernhard Schmidt } 12714310d6deSBernhard Schmidt #endif 12724310d6deSBernhard Schmidt 12734310d6deSBernhard Schmidt /* HW may insert 2 padding bytes after 802.11 header */ 12744310d6deSBernhard Schmidt if (rxd->flags & htole32(RT2860_RX_L2PAD)) { 12754310d6deSBernhard Schmidt u_int hdrlen = ieee80211_hdrsize(wh); 12764310d6deSBernhard Schmidt ovbcopy(wh, (caddr_t)wh + 2, hdrlen); 12774310d6deSBernhard Schmidt m->m_data += 2; 12784310d6deSBernhard Schmidt wh = mtod(m, struct ieee80211_frame *); 12794310d6deSBernhard Schmidt } 12804310d6deSBernhard Schmidt 12814310d6deSBernhard Schmidt ant = rt2860_maxrssi_chain(sc, rxwi); 12824310d6deSBernhard Schmidt rssi = rt2860_rssi2dbm(sc, rxwi->rssi[ant], ant); 12834310d6deSBernhard Schmidt nf = RT2860_NOISE_FLOOR; 12844310d6deSBernhard Schmidt 12854310d6deSBernhard Schmidt if (ieee80211_radiotap_active(ic)) { 12864310d6deSBernhard Schmidt tap = &sc->sc_rxtap; 12874310d6deSBernhard Schmidt tap->wr_flags = 0; 12884310d6deSBernhard Schmidt tap->wr_antenna = ant; 12894310d6deSBernhard Schmidt tap->wr_antsignal = nf + rssi; 12904310d6deSBernhard Schmidt tap->wr_antnoise = nf; 12914310d6deSBernhard Schmidt /* in case it can't be found below */ 12924310d6deSBernhard Schmidt tap->wr_rate = 2; 12934310d6deSBernhard Schmidt phy = le16toh(rxwi->phy); 12944310d6deSBernhard Schmidt switch (phy & RT2860_PHY_MODE) { 12954310d6deSBernhard Schmidt case RT2860_PHY_CCK: 12964310d6deSBernhard Schmidt switch ((phy & RT2860_PHY_MCS) & ~RT2860_PHY_SHPRE) { 12974310d6deSBernhard Schmidt case 0: tap->wr_rate = 2; break; 12984310d6deSBernhard Schmidt case 1: tap->wr_rate = 4; break; 12994310d6deSBernhard Schmidt case 2: tap->wr_rate = 11; break; 13004310d6deSBernhard Schmidt case 3: tap->wr_rate = 22; break; 13014310d6deSBernhard Schmidt } 13024310d6deSBernhard Schmidt if (phy & RT2860_PHY_SHPRE) 13034310d6deSBernhard Schmidt tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 13044310d6deSBernhard Schmidt break; 13054310d6deSBernhard Schmidt case RT2860_PHY_OFDM: 13064310d6deSBernhard Schmidt switch (phy & RT2860_PHY_MCS) { 13074310d6deSBernhard Schmidt case 0: tap->wr_rate = 12; break; 13084310d6deSBernhard Schmidt case 1: tap->wr_rate = 18; break; 13094310d6deSBernhard Schmidt case 2: tap->wr_rate = 24; break; 13104310d6deSBernhard Schmidt case 3: tap->wr_rate = 36; break; 13114310d6deSBernhard Schmidt case 4: tap->wr_rate = 48; break; 13124310d6deSBernhard Schmidt case 5: tap->wr_rate = 72; break; 13134310d6deSBernhard Schmidt case 6: tap->wr_rate = 96; break; 13144310d6deSBernhard Schmidt case 7: tap->wr_rate = 108; break; 13154310d6deSBernhard Schmidt } 13164310d6deSBernhard Schmidt break; 13174310d6deSBernhard Schmidt } 13184310d6deSBernhard Schmidt } 13194310d6deSBernhard Schmidt 13204310d6deSBernhard Schmidt RAL_UNLOCK(sc); 13214310d6deSBernhard Schmidt wh = mtod(m, struct ieee80211_frame *); 13224310d6deSBernhard Schmidt 13234310d6deSBernhard Schmidt /* send the frame to the 802.11 layer */ 13244310d6deSBernhard Schmidt ni = ieee80211_find_rxnode(ic, 13254310d6deSBernhard Schmidt (struct ieee80211_frame_min *)wh); 13264310d6deSBernhard Schmidt if (ni != NULL) { 13274310d6deSBernhard Schmidt (void)ieee80211_input(ni, m, rssi - nf, nf); 13284310d6deSBernhard Schmidt ieee80211_free_node(ni); 13294310d6deSBernhard Schmidt } else 13304310d6deSBernhard Schmidt (void)ieee80211_input_all(ic, m, rssi - nf, nf); 13314310d6deSBernhard Schmidt 13324310d6deSBernhard Schmidt RAL_LOCK(sc); 13334310d6deSBernhard Schmidt 13344310d6deSBernhard Schmidt skip: rxd->sdl0 &= ~htole16(RT2860_RX_DDONE); 13354310d6deSBernhard Schmidt 13364310d6deSBernhard Schmidt bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map, 13374310d6deSBernhard Schmidt BUS_DMASYNC_PREWRITE); 13384310d6deSBernhard Schmidt 13394310d6deSBernhard Schmidt sc->rxq.cur = (sc->rxq.cur + 1) % RT2860_RX_RING_COUNT; 13404310d6deSBernhard Schmidt } 13414310d6deSBernhard Schmidt 13424310d6deSBernhard Schmidt /* tell HW what we have processed */ 13434310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_RX_CALC_IDX, 13444310d6deSBernhard Schmidt (sc->rxq.cur - 1) % RT2860_RX_RING_COUNT); 13454310d6deSBernhard Schmidt } 13464310d6deSBernhard Schmidt 13474310d6deSBernhard Schmidt static void 13484310d6deSBernhard Schmidt rt2860_tbtt_intr(struct rt2860_softc *sc) 13494310d6deSBernhard Schmidt { 13504310d6deSBernhard Schmidt #if 0 13514310d6deSBernhard Schmidt struct ieee80211com *ic = &sc->sc_ic; 13524310d6deSBernhard Schmidt 13534310d6deSBernhard Schmidt #ifndef IEEE80211_STA_ONLY 13544310d6deSBernhard Schmidt if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 13554310d6deSBernhard Schmidt /* one less beacon until next DTIM */ 13564310d6deSBernhard Schmidt if (ic->ic_dtim_count == 0) 13574310d6deSBernhard Schmidt ic->ic_dtim_count = ic->ic_dtim_period - 1; 13584310d6deSBernhard Schmidt else 13594310d6deSBernhard Schmidt ic->ic_dtim_count--; 13604310d6deSBernhard Schmidt 13614310d6deSBernhard Schmidt /* update dynamic parts of beacon */ 13624310d6deSBernhard Schmidt rt2860_setup_beacon(sc); 13634310d6deSBernhard Schmidt 13644310d6deSBernhard Schmidt /* flush buffered multicast frames */ 13654310d6deSBernhard Schmidt if (ic->ic_dtim_count == 0) 13664310d6deSBernhard Schmidt ieee80211_notify_dtim(ic); 13674310d6deSBernhard Schmidt } 13684310d6deSBernhard Schmidt #endif 13694310d6deSBernhard Schmidt /* check if protection mode has changed */ 13704310d6deSBernhard Schmidt if ((sc->sc_ic_flags ^ ic->ic_flags) & IEEE80211_F_USEPROT) { 13717a79cebfSGleb Smirnoff rt2860_updateprot(sc); 13724310d6deSBernhard Schmidt sc->sc_ic_flags = ic->ic_flags; 13734310d6deSBernhard Schmidt } 13744310d6deSBernhard Schmidt #endif 13754310d6deSBernhard Schmidt } 13764310d6deSBernhard Schmidt 13774310d6deSBernhard Schmidt static void 13784310d6deSBernhard Schmidt rt2860_gp_intr(struct rt2860_softc *sc) 13794310d6deSBernhard Schmidt { 13807a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 13814310d6deSBernhard Schmidt struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 13824310d6deSBernhard Schmidt 13834310d6deSBernhard Schmidt DPRINTFN(2, ("GP timeout state=%d\n", vap->iv_state)); 13844310d6deSBernhard Schmidt 13854310d6deSBernhard Schmidt if (vap->iv_state == IEEE80211_S_RUN) 13864310d6deSBernhard Schmidt rt2860_updatestats(sc); 13874310d6deSBernhard Schmidt } 13884310d6deSBernhard Schmidt 1389e3cf3d44SKevin Lo void 13904310d6deSBernhard Schmidt rt2860_intr(void *arg) 13914310d6deSBernhard Schmidt { 13924310d6deSBernhard Schmidt struct rt2860_softc *sc = arg; 13934310d6deSBernhard Schmidt uint32_t r; 13944310d6deSBernhard Schmidt 13954310d6deSBernhard Schmidt RAL_LOCK(sc); 13964310d6deSBernhard Schmidt 13974310d6deSBernhard Schmidt r = RAL_READ(sc, RT2860_INT_STATUS); 13984310d6deSBernhard Schmidt if (__predict_false(r == 0xffffffff)) { 13994310d6deSBernhard Schmidt RAL_UNLOCK(sc); 14004310d6deSBernhard Schmidt return; /* device likely went away */ 14014310d6deSBernhard Schmidt } 14024310d6deSBernhard Schmidt if (r == 0) { 14034310d6deSBernhard Schmidt RAL_UNLOCK(sc); 14044310d6deSBernhard Schmidt return; /* not for us */ 14054310d6deSBernhard Schmidt } 14064310d6deSBernhard Schmidt 14074310d6deSBernhard Schmidt /* acknowledge interrupts */ 14084310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_INT_STATUS, r); 14094310d6deSBernhard Schmidt 14104310d6deSBernhard Schmidt if (r & RT2860_TX_RX_COHERENT) 14114310d6deSBernhard Schmidt rt2860_intr_coherent(sc); 14124310d6deSBernhard Schmidt 14134310d6deSBernhard Schmidt if (r & RT2860_MAC_INT_2) /* TX status */ 14144310d6deSBernhard Schmidt rt2860_drain_stats_fifo(sc); 14154310d6deSBernhard Schmidt 14164310d6deSBernhard Schmidt if (r & RT2860_TX_DONE_INT5) 14174310d6deSBernhard Schmidt rt2860_tx_intr(sc, 5); 14184310d6deSBernhard Schmidt 14194310d6deSBernhard Schmidt if (r & RT2860_RX_DONE_INT) 14204310d6deSBernhard Schmidt rt2860_rx_intr(sc); 14214310d6deSBernhard Schmidt 14224310d6deSBernhard Schmidt if (r & RT2860_TX_DONE_INT4) 14234310d6deSBernhard Schmidt rt2860_tx_intr(sc, 4); 14244310d6deSBernhard Schmidt 14254310d6deSBernhard Schmidt if (r & RT2860_TX_DONE_INT3) 14264310d6deSBernhard Schmidt rt2860_tx_intr(sc, 3); 14274310d6deSBernhard Schmidt 14284310d6deSBernhard Schmidt if (r & RT2860_TX_DONE_INT2) 14294310d6deSBernhard Schmidt rt2860_tx_intr(sc, 2); 14304310d6deSBernhard Schmidt 14314310d6deSBernhard Schmidt if (r & RT2860_TX_DONE_INT1) 14324310d6deSBernhard Schmidt rt2860_tx_intr(sc, 1); 14334310d6deSBernhard Schmidt 14344310d6deSBernhard Schmidt if (r & RT2860_TX_DONE_INT0) 14354310d6deSBernhard Schmidt rt2860_tx_intr(sc, 0); 14364310d6deSBernhard Schmidt 14374310d6deSBernhard Schmidt if (r & RT2860_MAC_INT_0) /* TBTT */ 14384310d6deSBernhard Schmidt rt2860_tbtt_intr(sc); 14394310d6deSBernhard Schmidt 14404310d6deSBernhard Schmidt if (r & RT2860_MAC_INT_3) /* Auto wakeup */ 14414310d6deSBernhard Schmidt /* TBD wakeup */; 14424310d6deSBernhard Schmidt 14434310d6deSBernhard Schmidt if (r & RT2860_MAC_INT_4) /* GP timer */ 14444310d6deSBernhard Schmidt rt2860_gp_intr(sc); 14454310d6deSBernhard Schmidt 14464310d6deSBernhard Schmidt RAL_UNLOCK(sc); 14474310d6deSBernhard Schmidt } 14484310d6deSBernhard Schmidt 14494310d6deSBernhard Schmidt static int 14504310d6deSBernhard Schmidt rt2860_tx(struct rt2860_softc *sc, struct mbuf *m, struct ieee80211_node *ni) 14514310d6deSBernhard Schmidt { 14527a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 14534310d6deSBernhard Schmidt struct ieee80211vap *vap = ni->ni_vap; 14544310d6deSBernhard Schmidt struct rt2860_tx_ring *ring; 14554310d6deSBernhard Schmidt struct rt2860_tx_data *data; 14564310d6deSBernhard Schmidt struct rt2860_txd *txd; 14574310d6deSBernhard Schmidt struct rt2860_txwi *txwi; 14584310d6deSBernhard Schmidt struct ieee80211_frame *wh; 1459f6313575SAndriy Voskoboinyk const struct ieee80211_txparam *tp = ni->ni_txparms; 14604310d6deSBernhard Schmidt struct ieee80211_key *k; 14614310d6deSBernhard Schmidt struct mbuf *m1; 14624310d6deSBernhard Schmidt bus_dma_segment_t segs[RT2860_MAX_SCATTER]; 14634310d6deSBernhard Schmidt bus_dma_segment_t *seg; 14644310d6deSBernhard Schmidt u_int hdrlen; 14654310d6deSBernhard Schmidt uint16_t qos, dur; 14664472999aSMateusz Guzik uint8_t type, qsel, mcs, pid, qid; 14674310d6deSBernhard Schmidt int i, nsegs, ntxds, pad, rate, ridx, error; 14684310d6deSBernhard Schmidt 14694310d6deSBernhard Schmidt /* the data pool contains at least one element, pick the first */ 14704310d6deSBernhard Schmidt data = SLIST_FIRST(&sc->data_pool); 14714310d6deSBernhard Schmidt 14724310d6deSBernhard Schmidt wh = mtod(m, struct ieee80211_frame *); 14734310d6deSBernhard Schmidt 14745945b5f5SKevin Lo if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { 14754310d6deSBernhard Schmidt k = ieee80211_crypto_encap(ni, m); 14764310d6deSBernhard Schmidt if (k == NULL) { 14774310d6deSBernhard Schmidt m_freem(m); 14784310d6deSBernhard Schmidt return ENOBUFS; 14794310d6deSBernhard Schmidt } 14804310d6deSBernhard Schmidt 14814310d6deSBernhard Schmidt /* packet header may have moved, reset our local pointer */ 14824310d6deSBernhard Schmidt wh = mtod(m, struct ieee80211_frame *); 14834310d6deSBernhard Schmidt } 14844310d6deSBernhard Schmidt 14854310d6deSBernhard Schmidt hdrlen = ieee80211_anyhdrsize(wh); 14864310d6deSBernhard Schmidt type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 14874310d6deSBernhard Schmidt 1488f6313575SAndriy Voskoboinyk if (m->m_flags & M_EAPOL) { 14894310d6deSBernhard Schmidt rate = tp->mgmtrate; 1490f6313575SAndriy Voskoboinyk } else if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1491f6313575SAndriy Voskoboinyk rate = tp->mcastrate; 14924310d6deSBernhard Schmidt } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { 14934310d6deSBernhard Schmidt rate = tp->ucastrate; 14944310d6deSBernhard Schmidt } else { 14954310d6deSBernhard Schmidt (void) ieee80211_ratectl_rate(ni, NULL, 0); 14964310d6deSBernhard Schmidt rate = ni->ni_txrate; 14974310d6deSBernhard Schmidt } 14984310d6deSBernhard Schmidt rate &= IEEE80211_RATE_VAL; 14994310d6deSBernhard Schmidt 15004310d6deSBernhard Schmidt qid = M_WME_GETAC(m); 15014310d6deSBernhard Schmidt if (IEEE80211_QOS_HAS_SEQ(wh)) { 15024310d6deSBernhard Schmidt qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; 15034310d6deSBernhard Schmidt } else { 15044310d6deSBernhard Schmidt qos = 0; 15054310d6deSBernhard Schmidt } 15064310d6deSBernhard Schmidt ring = &sc->txq[qid]; 1507f8bf74f2SAdrian Chadd ridx = ieee80211_legacy_rate_lookup(ic->ic_rt, rate); 15084310d6deSBernhard Schmidt 15094310d6deSBernhard Schmidt /* get MCS code from rate index */ 15104310d6deSBernhard Schmidt mcs = rt2860_rates[ridx].mcs; 15114310d6deSBernhard Schmidt 15124310d6deSBernhard Schmidt /* setup TX Wireless Information */ 15134310d6deSBernhard Schmidt txwi = data->txwi; 15144310d6deSBernhard Schmidt txwi->flags = 0; 15154310d6deSBernhard Schmidt /* let HW generate seq numbers for non-QoS frames */ 15164310d6deSBernhard Schmidt txwi->xflags = qos ? 0 : RT2860_TX_NSEQ; 15174310d6deSBernhard Schmidt if (type == IEEE80211_FC0_TYPE_DATA) 15184310d6deSBernhard Schmidt txwi->wcid = IEEE80211_AID(ni->ni_associd); 15194310d6deSBernhard Schmidt else 15204310d6deSBernhard Schmidt txwi->wcid = 0xff; 15214310d6deSBernhard Schmidt txwi->len = htole16(m->m_pkthdr.len); 15224310d6deSBernhard Schmidt if (rt2860_rates[ridx].phy == IEEE80211_T_DS) { 15234310d6deSBernhard Schmidt txwi->phy = htole16(RT2860_PHY_CCK); 15244310d6deSBernhard Schmidt if (ridx != RT2860_RIDX_CCK1 && 15254310d6deSBernhard Schmidt (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 15264310d6deSBernhard Schmidt mcs |= RT2860_PHY_SHPRE; 15274310d6deSBernhard Schmidt } else 15284310d6deSBernhard Schmidt txwi->phy = htole16(RT2860_PHY_OFDM); 15294310d6deSBernhard Schmidt txwi->phy |= htole16(mcs); 15304310d6deSBernhard Schmidt 15314310d6deSBernhard Schmidt /* 15324310d6deSBernhard Schmidt * We store the MCS code into the driver-private PacketID field. 15334310d6deSBernhard Schmidt * The PacketID is latched into TX_STAT_FIFO when Tx completes so 15344310d6deSBernhard Schmidt * that we know at which initial rate the frame was transmitted. 15354310d6deSBernhard Schmidt * We add 1 to the MCS code because setting the PacketID field to 15364310d6deSBernhard Schmidt * 0 means that we don't want feedback in TX_STAT_FIFO. 15374310d6deSBernhard Schmidt */ 15384310d6deSBernhard Schmidt pid = (mcs + 1) & 0xf; 15394310d6deSBernhard Schmidt txwi->len |= htole16(pid << RT2860_TX_PID_SHIFT); 15404310d6deSBernhard Schmidt 15414310d6deSBernhard Schmidt /* check if RTS/CTS or CTS-to-self protection is required */ 15424310d6deSBernhard Schmidt if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && 15434310d6deSBernhard Schmidt (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold || 15444310d6deSBernhard Schmidt ((ic->ic_flags & IEEE80211_F_USEPROT) && 15454310d6deSBernhard Schmidt rt2860_rates[ridx].phy == IEEE80211_T_OFDM))) 15464310d6deSBernhard Schmidt txwi->txop = RT2860_TX_TXOP_HT; 15474310d6deSBernhard Schmidt else 15484310d6deSBernhard Schmidt txwi->txop = RT2860_TX_TXOP_BACKOFF; 15494310d6deSBernhard Schmidt 15504310d6deSBernhard Schmidt if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && 15514310d6deSBernhard Schmidt (!qos || (qos & IEEE80211_QOS_ACKPOLICY) != 15524310d6deSBernhard Schmidt IEEE80211_QOS_ACKPOLICY_NOACK)) { 15534310d6deSBernhard Schmidt txwi->xflags |= RT2860_TX_ACK; 15544310d6deSBernhard Schmidt 15554310d6deSBernhard Schmidt if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 15564310d6deSBernhard Schmidt dur = rt2860_rates[ridx].sp_ack_dur; 15574310d6deSBernhard Schmidt else 15584310d6deSBernhard Schmidt dur = rt2860_rates[ridx].lp_ack_dur; 15594310d6deSBernhard Schmidt *(uint16_t *)wh->i_dur = htole16(dur); 15604310d6deSBernhard Schmidt } 15614310d6deSBernhard Schmidt /* ask MAC to insert timestamp into probe responses */ 1562*c249cc38SAdrian Chadd if (IEEE80211_IS_MGMT_PROBE_RESP(wh)) 15634310d6deSBernhard Schmidt /* NOTE: beacons do not pass through tx_data() */ 15644310d6deSBernhard Schmidt txwi->flags |= RT2860_TX_TS; 15654310d6deSBernhard Schmidt 15664310d6deSBernhard Schmidt if (ieee80211_radiotap_active_vap(vap)) { 15674310d6deSBernhard Schmidt struct rt2860_tx_radiotap_header *tap = &sc->sc_txtap; 15684310d6deSBernhard Schmidt 15694310d6deSBernhard Schmidt tap->wt_flags = 0; 15704310d6deSBernhard Schmidt tap->wt_rate = rate; 15714310d6deSBernhard Schmidt if (mcs & RT2860_PHY_SHPRE) 15724310d6deSBernhard Schmidt tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 15734310d6deSBernhard Schmidt 15744310d6deSBernhard Schmidt ieee80211_radiotap_tx(vap, m); 15754310d6deSBernhard Schmidt } 15764310d6deSBernhard Schmidt 15774310d6deSBernhard Schmidt pad = (hdrlen + 3) & ~3; 15784310d6deSBernhard Schmidt 15794310d6deSBernhard Schmidt /* copy and trim 802.11 header */ 15804310d6deSBernhard Schmidt memcpy(txwi + 1, wh, hdrlen); 15814310d6deSBernhard Schmidt m_adj(m, hdrlen); 15824310d6deSBernhard Schmidt 15834310d6deSBernhard Schmidt error = bus_dmamap_load_mbuf_sg(sc->txwi_dmat, data->map, m, segs, 15844310d6deSBernhard Schmidt &nsegs, 0); 15854310d6deSBernhard Schmidt if (__predict_false(error != 0 && error != EFBIG)) { 15864310d6deSBernhard Schmidt device_printf(sc->sc_dev, "can't map mbuf (error %d)\n", 15874310d6deSBernhard Schmidt error); 15884310d6deSBernhard Schmidt m_freem(m); 15894310d6deSBernhard Schmidt return error; 15904310d6deSBernhard Schmidt } 15914310d6deSBernhard Schmidt if (__predict_true(error == 0)) { 15924310d6deSBernhard Schmidt /* determine how many TXDs are required */ 15934310d6deSBernhard Schmidt ntxds = 1 + (nsegs / 2); 15944310d6deSBernhard Schmidt 15954310d6deSBernhard Schmidt if (ring->queued + ntxds >= RT2860_TX_RING_COUNT) { 15964310d6deSBernhard Schmidt /* not enough free TXDs, force mbuf defrag */ 15974310d6deSBernhard Schmidt bus_dmamap_unload(sc->txwi_dmat, data->map); 15984310d6deSBernhard Schmidt error = EFBIG; 15994310d6deSBernhard Schmidt } 16004310d6deSBernhard Schmidt } 16014310d6deSBernhard Schmidt if (__predict_false(error != 0)) { 1602c6499eccSGleb Smirnoff m1 = m_defrag(m, M_NOWAIT); 16034310d6deSBernhard Schmidt if (m1 == NULL) { 16044310d6deSBernhard Schmidt device_printf(sc->sc_dev, 16054310d6deSBernhard Schmidt "could not defragment mbuf\n"); 16064310d6deSBernhard Schmidt m_freem(m); 16074310d6deSBernhard Schmidt return ENOBUFS; 16084310d6deSBernhard Schmidt } 16094310d6deSBernhard Schmidt m = m1; 16104310d6deSBernhard Schmidt 16114310d6deSBernhard Schmidt error = bus_dmamap_load_mbuf_sg(sc->txwi_dmat, data->map, m, 16124310d6deSBernhard Schmidt segs, &nsegs, 0); 16134310d6deSBernhard Schmidt if (__predict_false(error != 0)) { 16144310d6deSBernhard Schmidt device_printf(sc->sc_dev, "can't map mbuf (error %d)\n", 16154310d6deSBernhard Schmidt error); 16164310d6deSBernhard Schmidt m_freem(m); 16174310d6deSBernhard Schmidt return error; 16184310d6deSBernhard Schmidt } 16194310d6deSBernhard Schmidt 16204310d6deSBernhard Schmidt /* determine how many TXDs are now required */ 16214310d6deSBernhard Schmidt ntxds = 1 + (nsegs / 2); 16224310d6deSBernhard Schmidt 16234310d6deSBernhard Schmidt if (ring->queued + ntxds >= RT2860_TX_RING_COUNT) { 16244310d6deSBernhard Schmidt /* this is a hopeless case, drop the mbuf! */ 16254310d6deSBernhard Schmidt bus_dmamap_unload(sc->txwi_dmat, data->map); 16264310d6deSBernhard Schmidt m_freem(m); 16274310d6deSBernhard Schmidt return ENOBUFS; 16284310d6deSBernhard Schmidt } 16294310d6deSBernhard Schmidt } 16304310d6deSBernhard Schmidt 16314310d6deSBernhard Schmidt qsel = (qid < WME_NUM_AC) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_MGMT; 16324310d6deSBernhard Schmidt 16334310d6deSBernhard Schmidt /* first segment is TXWI + 802.11 header */ 16344310d6deSBernhard Schmidt txd = &ring->txd[ring->cur]; 16354310d6deSBernhard Schmidt txd->sdp0 = htole32(data->paddr); 16364310d6deSBernhard Schmidt txd->sdl0 = htole16(sizeof (struct rt2860_txwi) + pad); 16374310d6deSBernhard Schmidt txd->flags = qsel; 16384310d6deSBernhard Schmidt 16394310d6deSBernhard Schmidt /* setup payload segments */ 16404310d6deSBernhard Schmidt seg = &segs[0]; 16414310d6deSBernhard Schmidt for (i = nsegs; i >= 2; i -= 2) { 16424310d6deSBernhard Schmidt txd->sdp1 = htole32(seg->ds_addr); 16434310d6deSBernhard Schmidt txd->sdl1 = htole16(seg->ds_len); 16444310d6deSBernhard Schmidt seg++; 16454310d6deSBernhard Schmidt ring->cur = (ring->cur + 1) % RT2860_TX_RING_COUNT; 16464310d6deSBernhard Schmidt /* grab a new Tx descriptor */ 16474310d6deSBernhard Schmidt txd = &ring->txd[ring->cur]; 16484310d6deSBernhard Schmidt txd->sdp0 = htole32(seg->ds_addr); 16494310d6deSBernhard Schmidt txd->sdl0 = htole16(seg->ds_len); 16504310d6deSBernhard Schmidt txd->flags = qsel; 16514310d6deSBernhard Schmidt seg++; 16524310d6deSBernhard Schmidt } 16534310d6deSBernhard Schmidt /* finalize last segment */ 16544310d6deSBernhard Schmidt if (i > 0) { 16554310d6deSBernhard Schmidt txd->sdp1 = htole32(seg->ds_addr); 16564310d6deSBernhard Schmidt txd->sdl1 = htole16(seg->ds_len | RT2860_TX_LS1); 16574310d6deSBernhard Schmidt } else { 16584310d6deSBernhard Schmidt txd->sdl0 |= htole16(RT2860_TX_LS0); 16594310d6deSBernhard Schmidt txd->sdl1 = 0; 16604310d6deSBernhard Schmidt } 16614310d6deSBernhard Schmidt 16624310d6deSBernhard Schmidt /* remove from the free pool and link it into the SW Tx slot */ 16634310d6deSBernhard Schmidt SLIST_REMOVE_HEAD(&sc->data_pool, next); 16644310d6deSBernhard Schmidt data->m = m; 16654310d6deSBernhard Schmidt data->ni = ni; 16664310d6deSBernhard Schmidt ring->data[ring->cur] = data; 16674310d6deSBernhard Schmidt 16684310d6deSBernhard Schmidt bus_dmamap_sync(sc->txwi_dmat, sc->txwi_map, BUS_DMASYNC_PREWRITE); 16694310d6deSBernhard Schmidt bus_dmamap_sync(sc->txwi_dmat, data->map, BUS_DMASYNC_PREWRITE); 16704310d6deSBernhard Schmidt bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 16714310d6deSBernhard Schmidt 16724310d6deSBernhard Schmidt DPRINTFN(4, ("sending frame qid=%d wcid=%d nsegs=%d ridx=%d\n", 16734310d6deSBernhard Schmidt qid, txwi->wcid, nsegs, ridx)); 16744310d6deSBernhard Schmidt 16754310d6deSBernhard Schmidt ring->cur = (ring->cur + 1) % RT2860_TX_RING_COUNT; 16764310d6deSBernhard Schmidt ring->queued += ntxds; 16774310d6deSBernhard Schmidt if (ring->queued >= RT2860_TX_RING_COUNT) 16784310d6deSBernhard Schmidt sc->qfullmsk |= 1 << qid; 16794310d6deSBernhard Schmidt 16804310d6deSBernhard Schmidt /* kick Tx */ 16814310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_TX_CTX_IDX(qid), ring->cur); 16824310d6deSBernhard Schmidt 16834310d6deSBernhard Schmidt return 0; 16844310d6deSBernhard Schmidt } 16854310d6deSBernhard Schmidt 16864310d6deSBernhard Schmidt static int 16874310d6deSBernhard Schmidt rt2860_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 16884310d6deSBernhard Schmidt const struct ieee80211_bpf_params *params) 16894310d6deSBernhard Schmidt { 16904310d6deSBernhard Schmidt struct ieee80211com *ic = ni->ni_ic; 16917a79cebfSGleb Smirnoff struct rt2860_softc *sc = ic->ic_softc; 16924310d6deSBernhard Schmidt int error; 16934310d6deSBernhard Schmidt 16944310d6deSBernhard Schmidt RAL_LOCK(sc); 16954310d6deSBernhard Schmidt 16964310d6deSBernhard Schmidt /* prevent management frames from being sent if we're not ready */ 16971c1cd920SKevin Lo if (!(sc->sc_flags & RT2860_RUNNING)) { 16984310d6deSBernhard Schmidt RAL_UNLOCK(sc); 16994310d6deSBernhard Schmidt m_freem(m); 17004310d6deSBernhard Schmidt return ENETDOWN; 17014310d6deSBernhard Schmidt } 17024310d6deSBernhard Schmidt if (params == NULL) { 17034310d6deSBernhard Schmidt /* 17044310d6deSBernhard Schmidt * Legacy path; interpret frame contents to decide 17054310d6deSBernhard Schmidt * precisely how to send the frame. 17064310d6deSBernhard Schmidt */ 17074310d6deSBernhard Schmidt error = rt2860_tx(sc, m, ni); 17084310d6deSBernhard Schmidt } else { 17094310d6deSBernhard Schmidt /* 17104310d6deSBernhard Schmidt * Caller supplied explicit parameters to use in 17114310d6deSBernhard Schmidt * sending the frame. 17124310d6deSBernhard Schmidt */ 17134310d6deSBernhard Schmidt error = rt2860_tx_raw(sc, m, ni, params); 17144310d6deSBernhard Schmidt } 17154310d6deSBernhard Schmidt sc->sc_tx_timer = 5; 17164310d6deSBernhard Schmidt RAL_UNLOCK(sc); 17174310d6deSBernhard Schmidt return error; 17184310d6deSBernhard Schmidt } 17194310d6deSBernhard Schmidt 17204310d6deSBernhard Schmidt static int 17214310d6deSBernhard Schmidt rt2860_tx_raw(struct rt2860_softc *sc, struct mbuf *m, 17224310d6deSBernhard Schmidt struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) 17234310d6deSBernhard Schmidt { 17247a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 17254310d6deSBernhard Schmidt struct ieee80211vap *vap = ni->ni_vap; 17264310d6deSBernhard Schmidt struct rt2860_tx_ring *ring; 17274310d6deSBernhard Schmidt struct rt2860_tx_data *data; 17284310d6deSBernhard Schmidt struct rt2860_txd *txd; 17294310d6deSBernhard Schmidt struct rt2860_txwi *txwi; 17304310d6deSBernhard Schmidt struct ieee80211_frame *wh; 17314310d6deSBernhard Schmidt struct mbuf *m1; 17324310d6deSBernhard Schmidt bus_dma_segment_t segs[RT2860_MAX_SCATTER]; 17334310d6deSBernhard Schmidt bus_dma_segment_t *seg; 17344310d6deSBernhard Schmidt u_int hdrlen; 17354310d6deSBernhard Schmidt uint16_t dur; 17364472999aSMateusz Guzik uint8_t qsel, mcs, pid, qid; 17374310d6deSBernhard Schmidt int i, nsegs, ntxds, pad, rate, ridx, error; 17384310d6deSBernhard Schmidt 17394310d6deSBernhard Schmidt /* the data pool contains at least one element, pick the first */ 17404310d6deSBernhard Schmidt data = SLIST_FIRST(&sc->data_pool); 17414310d6deSBernhard Schmidt 17424310d6deSBernhard Schmidt wh = mtod(m, struct ieee80211_frame *); 17434310d6deSBernhard Schmidt hdrlen = ieee80211_hdrsize(wh); 17444310d6deSBernhard Schmidt 17454310d6deSBernhard Schmidt /* Choose a TX rate index. */ 17464310d6deSBernhard Schmidt rate = params->ibp_rate0; 1747f8bf74f2SAdrian Chadd ridx = ieee80211_legacy_rate_lookup(ic->ic_rt, 1748f8bf74f2SAdrian Chadd rate & IEEE80211_RATE_VAL); 17494310d6deSBernhard Schmidt if (ridx == (uint8_t)-1) { 17504310d6deSBernhard Schmidt /* XXX fall back to mcast/mgmt rate? */ 17514310d6deSBernhard Schmidt m_freem(m); 17524310d6deSBernhard Schmidt return EINVAL; 17534310d6deSBernhard Schmidt } 17544310d6deSBernhard Schmidt 17554310d6deSBernhard Schmidt qid = params->ibp_pri & 3; 17564310d6deSBernhard Schmidt ring = &sc->txq[qid]; 17574310d6deSBernhard Schmidt 17584310d6deSBernhard Schmidt /* get MCS code from rate index */ 17594310d6deSBernhard Schmidt mcs = rt2860_rates[ridx].mcs; 17604310d6deSBernhard Schmidt 17614310d6deSBernhard Schmidt /* setup TX Wireless Information */ 17624310d6deSBernhard Schmidt txwi = data->txwi; 17634310d6deSBernhard Schmidt txwi->flags = 0; 17644310d6deSBernhard Schmidt /* let HW generate seq numbers for non-QoS frames */ 17654310d6deSBernhard Schmidt txwi->xflags = params->ibp_pri & 3 ? 0 : RT2860_TX_NSEQ; 17664310d6deSBernhard Schmidt txwi->wcid = 0xff; 17674310d6deSBernhard Schmidt txwi->len = htole16(m->m_pkthdr.len); 17684310d6deSBernhard Schmidt if (rt2860_rates[ridx].phy == IEEE80211_T_DS) { 17694310d6deSBernhard Schmidt txwi->phy = htole16(RT2860_PHY_CCK); 17704310d6deSBernhard Schmidt if (ridx != RT2860_RIDX_CCK1 && 17714310d6deSBernhard Schmidt (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 17724310d6deSBernhard Schmidt mcs |= RT2860_PHY_SHPRE; 17734310d6deSBernhard Schmidt } else 17744310d6deSBernhard Schmidt txwi->phy = htole16(RT2860_PHY_OFDM); 17754310d6deSBernhard Schmidt txwi->phy |= htole16(mcs); 17764310d6deSBernhard Schmidt 17774310d6deSBernhard Schmidt /* 17784310d6deSBernhard Schmidt * We store the MCS code into the driver-private PacketID field. 17794310d6deSBernhard Schmidt * The PacketID is latched into TX_STAT_FIFO when Tx completes so 17804310d6deSBernhard Schmidt * that we know at which initial rate the frame was transmitted. 17814310d6deSBernhard Schmidt * We add 1 to the MCS code because setting the PacketID field to 17824310d6deSBernhard Schmidt * 0 means that we don't want feedback in TX_STAT_FIFO. 17834310d6deSBernhard Schmidt */ 17844310d6deSBernhard Schmidt pid = (mcs + 1) & 0xf; 17854310d6deSBernhard Schmidt txwi->len |= htole16(pid << RT2860_TX_PID_SHIFT); 17864310d6deSBernhard Schmidt 17874310d6deSBernhard Schmidt /* check if RTS/CTS or CTS-to-self protection is required */ 17884310d6deSBernhard Schmidt if (params->ibp_flags & IEEE80211_BPF_RTS || 17894310d6deSBernhard Schmidt params->ibp_flags & IEEE80211_BPF_CTS) 17904310d6deSBernhard Schmidt txwi->txop = RT2860_TX_TXOP_HT; 17914310d6deSBernhard Schmidt else 17924310d6deSBernhard Schmidt txwi->txop = RT2860_TX_TXOP_BACKOFF; 17934310d6deSBernhard Schmidt if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) { 17944310d6deSBernhard Schmidt txwi->xflags |= RT2860_TX_ACK; 17954310d6deSBernhard Schmidt 17964310d6deSBernhard Schmidt if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 17974310d6deSBernhard Schmidt dur = rt2860_rates[ridx].sp_ack_dur; 17984310d6deSBernhard Schmidt else 17994310d6deSBernhard Schmidt dur = rt2860_rates[ridx].lp_ack_dur; 18004310d6deSBernhard Schmidt *(uint16_t *)wh->i_dur = htole16(dur); 18014310d6deSBernhard Schmidt } 18024310d6deSBernhard Schmidt /* ask MAC to insert timestamp into probe responses */ 1803*c249cc38SAdrian Chadd if (IEEE80211_IS_MGMT_PROBE_RESP(wh)) 18044310d6deSBernhard Schmidt /* NOTE: beacons do not pass through tx_data() */ 18054310d6deSBernhard Schmidt txwi->flags |= RT2860_TX_TS; 18064310d6deSBernhard Schmidt 18074310d6deSBernhard Schmidt if (ieee80211_radiotap_active_vap(vap)) { 18084310d6deSBernhard Schmidt struct rt2860_tx_radiotap_header *tap = &sc->sc_txtap; 18094310d6deSBernhard Schmidt 18104310d6deSBernhard Schmidt tap->wt_flags = 0; 18114310d6deSBernhard Schmidt tap->wt_rate = rate; 18124310d6deSBernhard Schmidt if (mcs & RT2860_PHY_SHPRE) 18134310d6deSBernhard Schmidt tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 18144310d6deSBernhard Schmidt 18154310d6deSBernhard Schmidt ieee80211_radiotap_tx(vap, m); 18164310d6deSBernhard Schmidt } 18174310d6deSBernhard Schmidt 18184310d6deSBernhard Schmidt pad = (hdrlen + 3) & ~3; 18194310d6deSBernhard Schmidt 18204310d6deSBernhard Schmidt /* copy and trim 802.11 header */ 18214310d6deSBernhard Schmidt memcpy(txwi + 1, wh, hdrlen); 18224310d6deSBernhard Schmidt m_adj(m, hdrlen); 18234310d6deSBernhard Schmidt 18244310d6deSBernhard Schmidt error = bus_dmamap_load_mbuf_sg(sc->txwi_dmat, data->map, m, segs, 18254310d6deSBernhard Schmidt &nsegs, 0); 18264310d6deSBernhard Schmidt if (__predict_false(error != 0 && error != EFBIG)) { 18274310d6deSBernhard Schmidt device_printf(sc->sc_dev, "can't map mbuf (error %d)\n", 18284310d6deSBernhard Schmidt error); 18294310d6deSBernhard Schmidt m_freem(m); 18304310d6deSBernhard Schmidt return error; 18314310d6deSBernhard Schmidt } 18324310d6deSBernhard Schmidt if (__predict_true(error == 0)) { 18334310d6deSBernhard Schmidt /* determine how many TXDs are required */ 18344310d6deSBernhard Schmidt ntxds = 1 + (nsegs / 2); 18354310d6deSBernhard Schmidt 18364310d6deSBernhard Schmidt if (ring->queued + ntxds >= RT2860_TX_RING_COUNT) { 18374310d6deSBernhard Schmidt /* not enough free TXDs, force mbuf defrag */ 18384310d6deSBernhard Schmidt bus_dmamap_unload(sc->txwi_dmat, data->map); 18394310d6deSBernhard Schmidt error = EFBIG; 18404310d6deSBernhard Schmidt } 18414310d6deSBernhard Schmidt } 18424310d6deSBernhard Schmidt if (__predict_false(error != 0)) { 1843c6499eccSGleb Smirnoff m1 = m_defrag(m, M_NOWAIT); 18444310d6deSBernhard Schmidt if (m1 == NULL) { 18454310d6deSBernhard Schmidt device_printf(sc->sc_dev, 18464310d6deSBernhard Schmidt "could not defragment mbuf\n"); 18474310d6deSBernhard Schmidt m_freem(m); 18484310d6deSBernhard Schmidt return ENOBUFS; 18494310d6deSBernhard Schmidt } 18504310d6deSBernhard Schmidt m = m1; 18514310d6deSBernhard Schmidt 18524310d6deSBernhard Schmidt error = bus_dmamap_load_mbuf_sg(sc->txwi_dmat, data->map, m, 18534310d6deSBernhard Schmidt segs, &nsegs, 0); 18544310d6deSBernhard Schmidt if (__predict_false(error != 0)) { 18554310d6deSBernhard Schmidt device_printf(sc->sc_dev, "can't map mbuf (error %d)\n", 18564310d6deSBernhard Schmidt error); 18574310d6deSBernhard Schmidt m_freem(m); 18584310d6deSBernhard Schmidt return error; 18594310d6deSBernhard Schmidt } 18604310d6deSBernhard Schmidt 18614310d6deSBernhard Schmidt /* determine how many TXDs are now required */ 18624310d6deSBernhard Schmidt ntxds = 1 + (nsegs / 2); 18634310d6deSBernhard Schmidt 18644310d6deSBernhard Schmidt if (ring->queued + ntxds >= RT2860_TX_RING_COUNT) { 18654310d6deSBernhard Schmidt /* this is a hopeless case, drop the mbuf! */ 18664310d6deSBernhard Schmidt bus_dmamap_unload(sc->txwi_dmat, data->map); 18674310d6deSBernhard Schmidt m_freem(m); 18684310d6deSBernhard Schmidt return ENOBUFS; 18694310d6deSBernhard Schmidt } 18704310d6deSBernhard Schmidt } 18714310d6deSBernhard Schmidt 18724310d6deSBernhard Schmidt qsel = (qid < WME_NUM_AC) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_MGMT; 18734310d6deSBernhard Schmidt 18744310d6deSBernhard Schmidt /* first segment is TXWI + 802.11 header */ 18754310d6deSBernhard Schmidt txd = &ring->txd[ring->cur]; 18764310d6deSBernhard Schmidt txd->sdp0 = htole32(data->paddr); 18774310d6deSBernhard Schmidt txd->sdl0 = htole16(sizeof (struct rt2860_txwi) + pad); 18784310d6deSBernhard Schmidt txd->flags = qsel; 18794310d6deSBernhard Schmidt 18804310d6deSBernhard Schmidt /* setup payload segments */ 18814310d6deSBernhard Schmidt seg = &segs[0]; 18824310d6deSBernhard Schmidt for (i = nsegs; i >= 2; i -= 2) { 18834310d6deSBernhard Schmidt txd->sdp1 = htole32(seg->ds_addr); 18844310d6deSBernhard Schmidt txd->sdl1 = htole16(seg->ds_len); 18854310d6deSBernhard Schmidt seg++; 18864310d6deSBernhard Schmidt ring->cur = (ring->cur + 1) % RT2860_TX_RING_COUNT; 18874310d6deSBernhard Schmidt /* grab a new Tx descriptor */ 18884310d6deSBernhard Schmidt txd = &ring->txd[ring->cur]; 18894310d6deSBernhard Schmidt txd->sdp0 = htole32(seg->ds_addr); 18904310d6deSBernhard Schmidt txd->sdl0 = htole16(seg->ds_len); 18914310d6deSBernhard Schmidt txd->flags = qsel; 18924310d6deSBernhard Schmidt seg++; 18934310d6deSBernhard Schmidt } 18944310d6deSBernhard Schmidt /* finalize last segment */ 18954310d6deSBernhard Schmidt if (i > 0) { 18964310d6deSBernhard Schmidt txd->sdp1 = htole32(seg->ds_addr); 18974310d6deSBernhard Schmidt txd->sdl1 = htole16(seg->ds_len | RT2860_TX_LS1); 18984310d6deSBernhard Schmidt } else { 18994310d6deSBernhard Schmidt txd->sdl0 |= htole16(RT2860_TX_LS0); 19004310d6deSBernhard Schmidt txd->sdl1 = 0; 19014310d6deSBernhard Schmidt } 19024310d6deSBernhard Schmidt 19034310d6deSBernhard Schmidt /* remove from the free pool and link it into the SW Tx slot */ 19044310d6deSBernhard Schmidt SLIST_REMOVE_HEAD(&sc->data_pool, next); 19054310d6deSBernhard Schmidt data->m = m; 19064310d6deSBernhard Schmidt data->ni = ni; 19074310d6deSBernhard Schmidt ring->data[ring->cur] = data; 19084310d6deSBernhard Schmidt 19094310d6deSBernhard Schmidt bus_dmamap_sync(sc->txwi_dmat, sc->txwi_map, BUS_DMASYNC_PREWRITE); 19104310d6deSBernhard Schmidt bus_dmamap_sync(sc->txwi_dmat, data->map, BUS_DMASYNC_PREWRITE); 19114310d6deSBernhard Schmidt bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE); 19124310d6deSBernhard Schmidt 19134310d6deSBernhard Schmidt DPRINTFN(4, ("sending frame qid=%d wcid=%d nsegs=%d ridx=%d\n", 19144310d6deSBernhard Schmidt qid, txwi->wcid, nsegs, ridx)); 19154310d6deSBernhard Schmidt 19164310d6deSBernhard Schmidt ring->cur = (ring->cur + 1) % RT2860_TX_RING_COUNT; 19174310d6deSBernhard Schmidt ring->queued += ntxds; 19184310d6deSBernhard Schmidt if (ring->queued >= RT2860_TX_RING_COUNT) 19194310d6deSBernhard Schmidt sc->qfullmsk |= 1 << qid; 19204310d6deSBernhard Schmidt 19214310d6deSBernhard Schmidt /* kick Tx */ 19224310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_TX_CTX_IDX(qid), ring->cur); 19234310d6deSBernhard Schmidt 19244310d6deSBernhard Schmidt return 0; 19254310d6deSBernhard Schmidt } 19264310d6deSBernhard Schmidt 19277a79cebfSGleb Smirnoff static int 19287a79cebfSGleb Smirnoff rt2860_transmit(struct ieee80211com *ic, struct mbuf *m) 19294310d6deSBernhard Schmidt { 19307a79cebfSGleb Smirnoff struct rt2860_softc *sc = ic->ic_softc; 19317a79cebfSGleb Smirnoff int error; 19324310d6deSBernhard Schmidt 19334310d6deSBernhard Schmidt RAL_LOCK(sc); 19341c1cd920SKevin Lo if ((sc->sc_flags & RT2860_RUNNING) == 0) { 19354310d6deSBernhard Schmidt RAL_UNLOCK(sc); 19367a79cebfSGleb Smirnoff return (ENXIO); 19377a79cebfSGleb Smirnoff } 19387a79cebfSGleb Smirnoff error = mbufq_enqueue(&sc->sc_snd, m); 19397a79cebfSGleb Smirnoff if (error) { 19407a79cebfSGleb Smirnoff RAL_UNLOCK(sc); 19417a79cebfSGleb Smirnoff return (error); 19427a79cebfSGleb Smirnoff } 19437a79cebfSGleb Smirnoff rt2860_start(sc); 19447a79cebfSGleb Smirnoff RAL_UNLOCK(sc); 19457a79cebfSGleb Smirnoff 19467a79cebfSGleb Smirnoff return (0); 19474310d6deSBernhard Schmidt } 19484310d6deSBernhard Schmidt 19494310d6deSBernhard Schmidt static void 19507a79cebfSGleb Smirnoff rt2860_start(struct rt2860_softc *sc) 19514310d6deSBernhard Schmidt { 19524310d6deSBernhard Schmidt struct ieee80211_node *ni; 19534310d6deSBernhard Schmidt struct mbuf *m; 19544310d6deSBernhard Schmidt 19554310d6deSBernhard Schmidt RAL_LOCK_ASSERT(sc); 19564310d6deSBernhard Schmidt 19571c1cd920SKevin Lo if ((sc->sc_flags & RT2860_RUNNING) == 0) 19584310d6deSBernhard Schmidt return; 19594310d6deSBernhard Schmidt 19607a79cebfSGleb Smirnoff while (!SLIST_EMPTY(&sc->data_pool) && sc->qfullmsk == 0 && 19617a79cebfSGleb Smirnoff (m = mbufq_dequeue(&sc->sc_snd)) != NULL) { 19624310d6deSBernhard Schmidt ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 19634310d6deSBernhard Schmidt if (rt2860_tx(sc, m, ni) != 0) { 19647a79cebfSGleb Smirnoff if_inc_counter(ni->ni_vap->iv_ifp, 19657a79cebfSGleb Smirnoff IFCOUNTER_OERRORS, 1); 19664310d6deSBernhard Schmidt ieee80211_free_node(ni); 19674310d6deSBernhard Schmidt continue; 19684310d6deSBernhard Schmidt } 19694310d6deSBernhard Schmidt sc->sc_tx_timer = 5; 19704310d6deSBernhard Schmidt } 19714310d6deSBernhard Schmidt } 19724310d6deSBernhard Schmidt 19734310d6deSBernhard Schmidt static void 19744310d6deSBernhard Schmidt rt2860_watchdog(void *arg) 19754310d6deSBernhard Schmidt { 19764310d6deSBernhard Schmidt struct rt2860_softc *sc = arg; 19774310d6deSBernhard Schmidt 19784310d6deSBernhard Schmidt RAL_LOCK_ASSERT(sc); 19794310d6deSBernhard Schmidt 19801c1cd920SKevin Lo KASSERT(sc->sc_flags & RT2860_RUNNING, ("not running")); 19814310d6deSBernhard Schmidt 19824310d6deSBernhard Schmidt if (sc->sc_invalid) /* card ejected */ 19834310d6deSBernhard Schmidt return; 19844310d6deSBernhard Schmidt 19854310d6deSBernhard Schmidt if (sc->sc_tx_timer > 0 && --sc->sc_tx_timer == 0) { 19867a79cebfSGleb Smirnoff device_printf(sc->sc_dev, "device timeout\n"); 19874310d6deSBernhard Schmidt rt2860_stop_locked(sc); 19884310d6deSBernhard Schmidt rt2860_init_locked(sc); 19897a79cebfSGleb Smirnoff counter_u64_add(sc->sc_ic.ic_oerrors, 1); 19904310d6deSBernhard Schmidt return; 19914310d6deSBernhard Schmidt } 19924310d6deSBernhard Schmidt callout_reset(&sc->watchdog_ch, hz, rt2860_watchdog, sc); 19934310d6deSBernhard Schmidt } 19944310d6deSBernhard Schmidt 19957a79cebfSGleb Smirnoff static void 19967a79cebfSGleb Smirnoff rt2860_parent(struct ieee80211com *ic) 19974310d6deSBernhard Schmidt { 19987a79cebfSGleb Smirnoff struct rt2860_softc *sc = ic->ic_softc; 19997a79cebfSGleb Smirnoff int startall = 0; 20004310d6deSBernhard Schmidt 20014310d6deSBernhard Schmidt RAL_LOCK(sc); 20027a79cebfSGleb Smirnoff if (ic->ic_nrunning> 0) { 20031c1cd920SKevin Lo if (!(sc->sc_flags & RT2860_RUNNING)) { 20044310d6deSBernhard Schmidt rt2860_init_locked(sc); 20054310d6deSBernhard Schmidt startall = 1; 20064310d6deSBernhard Schmidt } else 2007272f6adeSGleb Smirnoff rt2860_update_promisc(ic); 20081c1cd920SKevin Lo } else if (sc->sc_flags & RT2860_RUNNING) 20094310d6deSBernhard Schmidt rt2860_stop_locked(sc); 20104310d6deSBernhard Schmidt RAL_UNLOCK(sc); 20114310d6deSBernhard Schmidt if (startall) 20124310d6deSBernhard Schmidt ieee80211_start_all(ic); 20134310d6deSBernhard Schmidt } 20144310d6deSBernhard Schmidt 20154310d6deSBernhard Schmidt /* 20164310d6deSBernhard Schmidt * Reading and writing from/to the BBP is different from RT2560 and RT2661. 20174310d6deSBernhard Schmidt * We access the BBP through the 8051 microcontroller unit which means that 20184310d6deSBernhard Schmidt * the microcode must be loaded first. 20194310d6deSBernhard Schmidt */ 20204310d6deSBernhard Schmidt void 20214310d6deSBernhard Schmidt rt2860_mcu_bbp_write(struct rt2860_softc *sc, uint8_t reg, uint8_t val) 20224310d6deSBernhard Schmidt { 20234310d6deSBernhard Schmidt int ntries; 20244310d6deSBernhard Schmidt 20254310d6deSBernhard Schmidt for (ntries = 0; ntries < 100; ntries++) { 20264310d6deSBernhard Schmidt if (!(RAL_READ(sc, RT2860_H2M_BBPAGENT) & RT2860_BBP_CSR_KICK)) 20274310d6deSBernhard Schmidt break; 20284310d6deSBernhard Schmidt DELAY(1); 20294310d6deSBernhard Schmidt } 20304310d6deSBernhard Schmidt if (ntries == 100) { 20314310d6deSBernhard Schmidt device_printf(sc->sc_dev, 20324310d6deSBernhard Schmidt "could not write to BBP through MCU\n"); 20334310d6deSBernhard Schmidt return; 20344310d6deSBernhard Schmidt } 20354310d6deSBernhard Schmidt 20364310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_H2M_BBPAGENT, RT2860_BBP_RW_PARALLEL | 20374310d6deSBernhard Schmidt RT2860_BBP_CSR_KICK | reg << 8 | val); 20384310d6deSBernhard Schmidt RAL_BARRIER_WRITE(sc); 20394310d6deSBernhard Schmidt 20404310d6deSBernhard Schmidt rt2860_mcu_cmd(sc, RT2860_MCU_CMD_BBP, 0, 0); 20414310d6deSBernhard Schmidt DELAY(1000); 20424310d6deSBernhard Schmidt } 20434310d6deSBernhard Schmidt 20444310d6deSBernhard Schmidt uint8_t 20454310d6deSBernhard Schmidt rt2860_mcu_bbp_read(struct rt2860_softc *sc, uint8_t reg) 20464310d6deSBernhard Schmidt { 20474310d6deSBernhard Schmidt uint32_t val; 20484310d6deSBernhard Schmidt int ntries; 20494310d6deSBernhard Schmidt 20504310d6deSBernhard Schmidt for (ntries = 0; ntries < 100; ntries++) { 20514310d6deSBernhard Schmidt if (!(RAL_READ(sc, RT2860_H2M_BBPAGENT) & RT2860_BBP_CSR_KICK)) 20524310d6deSBernhard Schmidt break; 20534310d6deSBernhard Schmidt DELAY(1); 20544310d6deSBernhard Schmidt } 20554310d6deSBernhard Schmidt if (ntries == 100) { 20564310d6deSBernhard Schmidt device_printf(sc->sc_dev, 20574310d6deSBernhard Schmidt "could not read from BBP through MCU\n"); 20584310d6deSBernhard Schmidt return 0; 20594310d6deSBernhard Schmidt } 20604310d6deSBernhard Schmidt 20614310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_H2M_BBPAGENT, RT2860_BBP_RW_PARALLEL | 20624310d6deSBernhard Schmidt RT2860_BBP_CSR_KICK | RT2860_BBP_CSR_READ | reg << 8); 20634310d6deSBernhard Schmidt RAL_BARRIER_WRITE(sc); 20644310d6deSBernhard Schmidt 20654310d6deSBernhard Schmidt rt2860_mcu_cmd(sc, RT2860_MCU_CMD_BBP, 0, 0); 20664310d6deSBernhard Schmidt DELAY(1000); 20674310d6deSBernhard Schmidt 20684310d6deSBernhard Schmidt for (ntries = 0; ntries < 100; ntries++) { 20694310d6deSBernhard Schmidt val = RAL_READ(sc, RT2860_H2M_BBPAGENT); 20704310d6deSBernhard Schmidt if (!(val & RT2860_BBP_CSR_KICK)) 20714310d6deSBernhard Schmidt return val & 0xff; 20724310d6deSBernhard Schmidt DELAY(1); 20734310d6deSBernhard Schmidt } 20744310d6deSBernhard Schmidt device_printf(sc->sc_dev, "could not read from BBP through MCU\n"); 20754310d6deSBernhard Schmidt 20764310d6deSBernhard Schmidt return 0; 20774310d6deSBernhard Schmidt } 20784310d6deSBernhard Schmidt 20794310d6deSBernhard Schmidt /* 20804310d6deSBernhard Schmidt * Write to one of the 4 programmable 24-bit RF registers. 20814310d6deSBernhard Schmidt */ 20824310d6deSBernhard Schmidt static void 20834310d6deSBernhard Schmidt rt2860_rf_write(struct rt2860_softc *sc, uint8_t reg, uint32_t val) 20844310d6deSBernhard Schmidt { 20854310d6deSBernhard Schmidt uint32_t tmp; 20864310d6deSBernhard Schmidt int ntries; 20874310d6deSBernhard Schmidt 20884310d6deSBernhard Schmidt for (ntries = 0; ntries < 100; ntries++) { 20894310d6deSBernhard Schmidt if (!(RAL_READ(sc, RT2860_RF_CSR_CFG0) & RT2860_RF_REG_CTRL)) 20904310d6deSBernhard Schmidt break; 20914310d6deSBernhard Schmidt DELAY(1); 20924310d6deSBernhard Schmidt } 20934310d6deSBernhard Schmidt if (ntries == 100) { 20944310d6deSBernhard Schmidt device_printf(sc->sc_dev, "could not write to RF\n"); 20954310d6deSBernhard Schmidt return; 20964310d6deSBernhard Schmidt } 20974310d6deSBernhard Schmidt 20984310d6deSBernhard Schmidt /* RF registers are 24-bit on the RT2860 */ 20994310d6deSBernhard Schmidt tmp = RT2860_RF_REG_CTRL | 24 << RT2860_RF_REG_WIDTH_SHIFT | 21004310d6deSBernhard Schmidt (val & 0x3fffff) << 2 | (reg & 3); 21014310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_RF_CSR_CFG0, tmp); 21024310d6deSBernhard Schmidt } 21034310d6deSBernhard Schmidt 21044310d6deSBernhard Schmidt static uint8_t 21054310d6deSBernhard Schmidt rt3090_rf_read(struct rt2860_softc *sc, uint8_t reg) 21064310d6deSBernhard Schmidt { 21074310d6deSBernhard Schmidt uint32_t tmp; 21084310d6deSBernhard Schmidt int ntries; 21094310d6deSBernhard Schmidt 21104310d6deSBernhard Schmidt for (ntries = 0; ntries < 100; ntries++) { 21114310d6deSBernhard Schmidt if (!(RAL_READ(sc, RT3070_RF_CSR_CFG) & RT3070_RF_KICK)) 21124310d6deSBernhard Schmidt break; 21134310d6deSBernhard Schmidt DELAY(1); 21144310d6deSBernhard Schmidt } 21154310d6deSBernhard Schmidt if (ntries == 100) { 21164310d6deSBernhard Schmidt device_printf(sc->sc_dev, "could not read RF register\n"); 21174310d6deSBernhard Schmidt return 0xff; 21184310d6deSBernhard Schmidt } 21194310d6deSBernhard Schmidt tmp = RT3070_RF_KICK | reg << 8; 21204310d6deSBernhard Schmidt RAL_WRITE(sc, RT3070_RF_CSR_CFG, tmp); 21214310d6deSBernhard Schmidt 21224310d6deSBernhard Schmidt for (ntries = 0; ntries < 100; ntries++) { 21234310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT3070_RF_CSR_CFG); 21244310d6deSBernhard Schmidt if (!(tmp & RT3070_RF_KICK)) 21254310d6deSBernhard Schmidt break; 21264310d6deSBernhard Schmidt DELAY(1); 21274310d6deSBernhard Schmidt } 21284310d6deSBernhard Schmidt if (ntries == 100) { 21294310d6deSBernhard Schmidt device_printf(sc->sc_dev, "could not read RF register\n"); 21304310d6deSBernhard Schmidt return 0xff; 21314310d6deSBernhard Schmidt } 21324310d6deSBernhard Schmidt return tmp & 0xff; 21334310d6deSBernhard Schmidt } 21344310d6deSBernhard Schmidt 21354310d6deSBernhard Schmidt void 21364310d6deSBernhard Schmidt rt3090_rf_write(struct rt2860_softc *sc, uint8_t reg, uint8_t val) 21374310d6deSBernhard Schmidt { 21384310d6deSBernhard Schmidt uint32_t tmp; 21394310d6deSBernhard Schmidt int ntries; 21404310d6deSBernhard Schmidt 21414310d6deSBernhard Schmidt for (ntries = 0; ntries < 10; ntries++) { 21424310d6deSBernhard Schmidt if (!(RAL_READ(sc, RT3070_RF_CSR_CFG) & RT3070_RF_KICK)) 21434310d6deSBernhard Schmidt break; 21444310d6deSBernhard Schmidt DELAY(10); 21454310d6deSBernhard Schmidt } 21464310d6deSBernhard Schmidt if (ntries == 10) { 21474310d6deSBernhard Schmidt device_printf(sc->sc_dev, "could not write to RF\n"); 21484310d6deSBernhard Schmidt return; 21494310d6deSBernhard Schmidt } 21504310d6deSBernhard Schmidt 21514310d6deSBernhard Schmidt tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val; 21524310d6deSBernhard Schmidt RAL_WRITE(sc, RT3070_RF_CSR_CFG, tmp); 21534310d6deSBernhard Schmidt } 21544310d6deSBernhard Schmidt 21554310d6deSBernhard Schmidt /* 21564310d6deSBernhard Schmidt * Send a command to the 8051 microcontroller unit. 21574310d6deSBernhard Schmidt */ 21584310d6deSBernhard Schmidt int 21594310d6deSBernhard Schmidt rt2860_mcu_cmd(struct rt2860_softc *sc, uint8_t cmd, uint16_t arg, int wait) 21604310d6deSBernhard Schmidt { 21614310d6deSBernhard Schmidt int slot, ntries; 21624310d6deSBernhard Schmidt uint32_t tmp; 21634310d6deSBernhard Schmidt uint8_t cid; 21644310d6deSBernhard Schmidt 21654310d6deSBernhard Schmidt for (ntries = 0; ntries < 100; ntries++) { 21664310d6deSBernhard Schmidt if (!(RAL_READ(sc, RT2860_H2M_MAILBOX) & RT2860_H2M_BUSY)) 21674310d6deSBernhard Schmidt break; 21684310d6deSBernhard Schmidt DELAY(2); 21694310d6deSBernhard Schmidt } 21704310d6deSBernhard Schmidt if (ntries == 100) 21714310d6deSBernhard Schmidt return EIO; 21724310d6deSBernhard Schmidt 21734310d6deSBernhard Schmidt cid = wait ? cmd : RT2860_TOKEN_NO_INTR; 21744310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_H2M_MAILBOX, RT2860_H2M_BUSY | cid << 16 | arg); 21754310d6deSBernhard Schmidt RAL_BARRIER_WRITE(sc); 21764310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_HOST_CMD, cmd); 21774310d6deSBernhard Schmidt 21784310d6deSBernhard Schmidt if (!wait) 21794310d6deSBernhard Schmidt return 0; 21804310d6deSBernhard Schmidt /* wait for the command to complete */ 21814310d6deSBernhard Schmidt for (ntries = 0; ntries < 200; ntries++) { 21824310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_H2M_MAILBOX_CID); 21834310d6deSBernhard Schmidt /* find the command slot */ 21844310d6deSBernhard Schmidt for (slot = 0; slot < 4; slot++, tmp >>= 8) 21854310d6deSBernhard Schmidt if ((tmp & 0xff) == cid) 21864310d6deSBernhard Schmidt break; 21874310d6deSBernhard Schmidt if (slot < 4) 21884310d6deSBernhard Schmidt break; 21894310d6deSBernhard Schmidt DELAY(100); 21904310d6deSBernhard Schmidt } 21914310d6deSBernhard Schmidt if (ntries == 200) { 21924310d6deSBernhard Schmidt /* clear command and status */ 21934310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_H2M_MAILBOX_STATUS, 0xffffffff); 21944310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff); 21954310d6deSBernhard Schmidt return ETIMEDOUT; 21964310d6deSBernhard Schmidt } 21974310d6deSBernhard Schmidt /* get command status (1 means success) */ 21984310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_H2M_MAILBOX_STATUS); 21994310d6deSBernhard Schmidt tmp = (tmp >> (slot * 8)) & 0xff; 22004310d6deSBernhard Schmidt DPRINTF(("MCU command=0x%02x slot=%d status=0x%02x\n", 22014310d6deSBernhard Schmidt cmd, slot, tmp)); 22024310d6deSBernhard Schmidt /* clear command and status */ 22034310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_H2M_MAILBOX_STATUS, 0xffffffff); 22044310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff); 22054310d6deSBernhard Schmidt return (tmp == 1) ? 0 : EIO; 22064310d6deSBernhard Schmidt } 22074310d6deSBernhard Schmidt 22084310d6deSBernhard Schmidt static void 22094310d6deSBernhard Schmidt rt2860_enable_mrr(struct rt2860_softc *sc) 22104310d6deSBernhard Schmidt { 22114310d6deSBernhard Schmidt #define CCK(mcs) (mcs) 221226d9565dSPedro F. Giffuni #define OFDM(mcs) (1U << 3 | (mcs)) 22134310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_LG_FBK_CFG0, 22144310d6deSBernhard Schmidt OFDM(6) << 28 | /* 54->48 */ 22154310d6deSBernhard Schmidt OFDM(5) << 24 | /* 48->36 */ 22164310d6deSBernhard Schmidt OFDM(4) << 20 | /* 36->24 */ 22174310d6deSBernhard Schmidt OFDM(3) << 16 | /* 24->18 */ 22184310d6deSBernhard Schmidt OFDM(2) << 12 | /* 18->12 */ 22194310d6deSBernhard Schmidt OFDM(1) << 8 | /* 12-> 9 */ 22204310d6deSBernhard Schmidt OFDM(0) << 4 | /* 9-> 6 */ 22214310d6deSBernhard Schmidt OFDM(0)); /* 6-> 6 */ 22224310d6deSBernhard Schmidt 22234310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_LG_FBK_CFG1, 22244310d6deSBernhard Schmidt CCK(2) << 12 | /* 11->5.5 */ 22254310d6deSBernhard Schmidt CCK(1) << 8 | /* 5.5-> 2 */ 22264310d6deSBernhard Schmidt CCK(0) << 4 | /* 2-> 1 */ 22274310d6deSBernhard Schmidt CCK(0)); /* 1-> 1 */ 22284310d6deSBernhard Schmidt #undef OFDM 22294310d6deSBernhard Schmidt #undef CCK 22304310d6deSBernhard Schmidt } 22314310d6deSBernhard Schmidt 22324310d6deSBernhard Schmidt static void 22334310d6deSBernhard Schmidt rt2860_set_txpreamble(struct rt2860_softc *sc) 22344310d6deSBernhard Schmidt { 22357a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 22364310d6deSBernhard Schmidt uint32_t tmp; 22374310d6deSBernhard Schmidt 22384310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_AUTO_RSP_CFG); 22394310d6deSBernhard Schmidt tmp &= ~RT2860_CCK_SHORT_EN; 22404310d6deSBernhard Schmidt if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 22414310d6deSBernhard Schmidt tmp |= RT2860_CCK_SHORT_EN; 22424310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_AUTO_RSP_CFG, tmp); 22434310d6deSBernhard Schmidt } 22444310d6deSBernhard Schmidt 22454310d6deSBernhard Schmidt void 22464310d6deSBernhard Schmidt rt2860_set_basicrates(struct rt2860_softc *sc, 22474310d6deSBernhard Schmidt const struct ieee80211_rateset *rs) 22484310d6deSBernhard Schmidt { 22497a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 22504310d6deSBernhard Schmidt uint32_t mask = 0; 22514310d6deSBernhard Schmidt uint8_t rate; 22524310d6deSBernhard Schmidt int i; 22534310d6deSBernhard Schmidt 22544310d6deSBernhard Schmidt for (i = 0; i < rs->rs_nrates; i++) { 22554310d6deSBernhard Schmidt rate = rs->rs_rates[i]; 22564310d6deSBernhard Schmidt 22574310d6deSBernhard Schmidt if (!(rate & IEEE80211_RATE_BASIC)) 22584310d6deSBernhard Schmidt continue; 22594310d6deSBernhard Schmidt 2260d6166defSAdrian Chadd mask |= 1 << ieee80211_legacy_rate_lookup(ic->ic_rt, 2261d6166defSAdrian Chadd IEEE80211_RV(rate)); 22624310d6deSBernhard Schmidt } 22634310d6deSBernhard Schmidt 22644310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_LEGACY_BASIC_RATE, mask); 22654310d6deSBernhard Schmidt } 22664310d6deSBernhard Schmidt 22674310d6deSBernhard Schmidt static void 22684310d6deSBernhard Schmidt rt2860_scan_start(struct ieee80211com *ic) 22694310d6deSBernhard Schmidt { 22707a79cebfSGleb Smirnoff struct rt2860_softc *sc = ic->ic_softc; 22714310d6deSBernhard Schmidt uint32_t tmp; 22724310d6deSBernhard Schmidt 22734310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_BCN_TIME_CFG); 22744310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_BCN_TIME_CFG, 22754310d6deSBernhard Schmidt tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | 22764310d6deSBernhard Schmidt RT2860_TBTT_TIMER_EN)); 22774310d6deSBernhard Schmidt rt2860_set_gp_timer(sc, 0); 22784310d6deSBernhard Schmidt } 22794310d6deSBernhard Schmidt 22804310d6deSBernhard Schmidt static void 22814310d6deSBernhard Schmidt rt2860_scan_end(struct ieee80211com *ic) 22824310d6deSBernhard Schmidt { 22837a79cebfSGleb Smirnoff struct rt2860_softc *sc = ic->ic_softc; 22844310d6deSBernhard Schmidt struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 22854310d6deSBernhard Schmidt 22864310d6deSBernhard Schmidt if (vap->iv_state == IEEE80211_S_RUN) { 22874310d6deSBernhard Schmidt rt2860_enable_tsf_sync(sc); 22884310d6deSBernhard Schmidt rt2860_set_gp_timer(sc, 500); 22894310d6deSBernhard Schmidt } 22904310d6deSBernhard Schmidt } 22914310d6deSBernhard Schmidt 22924310d6deSBernhard Schmidt static void 22930a02496fSAndriy Voskoboinyk rt2860_getradiocaps(struct ieee80211com *ic, int maxchans, int *nchans, 22940a02496fSAndriy Voskoboinyk struct ieee80211_channel chans[]) 22950a02496fSAndriy Voskoboinyk { 22960a02496fSAndriy Voskoboinyk struct rt2860_softc *sc = ic->ic_softc; 22970a02496fSAndriy Voskoboinyk uint8_t bands[IEEE80211_MODE_BYTES]; 22980a02496fSAndriy Voskoboinyk 22990a02496fSAndriy Voskoboinyk memset(bands, 0, sizeof(bands)); 23000a02496fSAndriy Voskoboinyk setbit(bands, IEEE80211_MODE_11B); 23010a02496fSAndriy Voskoboinyk setbit(bands, IEEE80211_MODE_11G); 2302b84b3638SAndriy Voskoboinyk ieee80211_add_channels_default_2ghz(chans, maxchans, nchans, bands, 0); 23030a02496fSAndriy Voskoboinyk 23040a02496fSAndriy Voskoboinyk if (sc->rf_rev == RT2860_RF_2750 || sc->rf_rev == RT2860_RF_2850) { 23050a02496fSAndriy Voskoboinyk setbit(bands, IEEE80211_MODE_11A); 23060a02496fSAndriy Voskoboinyk ieee80211_add_channel_list_5ghz(chans, maxchans, nchans, 23070a02496fSAndriy Voskoboinyk rt2860_chan_5ghz, nitems(rt2860_chan_5ghz), bands, 0); 23080a02496fSAndriy Voskoboinyk } 23090a02496fSAndriy Voskoboinyk } 23100a02496fSAndriy Voskoboinyk 23110a02496fSAndriy Voskoboinyk static void 23124310d6deSBernhard Schmidt rt2860_set_channel(struct ieee80211com *ic) 23134310d6deSBernhard Schmidt { 23147a79cebfSGleb Smirnoff struct rt2860_softc *sc = ic->ic_softc; 23154310d6deSBernhard Schmidt 23164310d6deSBernhard Schmidt RAL_LOCK(sc); 23174310d6deSBernhard Schmidt rt2860_switch_chan(sc, ic->ic_curchan); 23184310d6deSBernhard Schmidt RAL_UNLOCK(sc); 23194310d6deSBernhard Schmidt } 23204310d6deSBernhard Schmidt 23214310d6deSBernhard Schmidt static void 23224310d6deSBernhard Schmidt rt2860_select_chan_group(struct rt2860_softc *sc, int group) 23234310d6deSBernhard Schmidt { 23244310d6deSBernhard Schmidt uint32_t tmp; 23254310d6deSBernhard Schmidt uint8_t agc; 23264310d6deSBernhard Schmidt 23274310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 62, 0x37 - sc->lna[group]); 23284310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 63, 0x37 - sc->lna[group]); 23294310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 64, 0x37 - sc->lna[group]); 23304310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 86, 0x00); 23314310d6deSBernhard Schmidt 23324310d6deSBernhard Schmidt if (group == 0) { 23334310d6deSBernhard Schmidt if (sc->ext_2ghz_lna) { 23344310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 82, 0x62); 23354310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 75, 0x46); 23364310d6deSBernhard Schmidt } else { 23374310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 82, 0x84); 23384310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 75, 0x50); 23394310d6deSBernhard Schmidt } 23404310d6deSBernhard Schmidt } else { 23414310d6deSBernhard Schmidt if (sc->ext_5ghz_lna) { 23424310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 82, 0xf2); 23434310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 75, 0x46); 23444310d6deSBernhard Schmidt } else { 23454310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 82, 0xf2); 23464310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 75, 0x50); 23474310d6deSBernhard Schmidt } 23484310d6deSBernhard Schmidt } 23494310d6deSBernhard Schmidt 23504310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_TX_BAND_CFG); 23514310d6deSBernhard Schmidt tmp &= ~(RT2860_5G_BAND_SEL_N | RT2860_5G_BAND_SEL_P); 23524310d6deSBernhard Schmidt tmp |= (group == 0) ? RT2860_5G_BAND_SEL_N : RT2860_5G_BAND_SEL_P; 23534310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_TX_BAND_CFG, tmp); 23544310d6deSBernhard Schmidt 23554310d6deSBernhard Schmidt /* enable appropriate Power Amplifiers and Low Noise Amplifiers */ 23564310d6deSBernhard Schmidt tmp = RT2860_RFTR_EN | RT2860_TRSW_EN | RT2860_LNA_PE0_EN; 23574310d6deSBernhard Schmidt if (sc->nrxchains > 1) 23584310d6deSBernhard Schmidt tmp |= RT2860_LNA_PE1_EN; 23594310d6deSBernhard Schmidt if (sc->mac_ver == 0x3593 && sc->nrxchains > 2) 23604310d6deSBernhard Schmidt tmp |= RT3593_LNA_PE2_EN; 23614310d6deSBernhard Schmidt if (group == 0) { /* 2GHz */ 23624310d6deSBernhard Schmidt tmp |= RT2860_PA_PE_G0_EN; 23634310d6deSBernhard Schmidt if (sc->ntxchains > 1) 23644310d6deSBernhard Schmidt tmp |= RT2860_PA_PE_G1_EN; 23654310d6deSBernhard Schmidt if (sc->mac_ver == 0x3593 && sc->ntxchains > 2) 23664310d6deSBernhard Schmidt tmp |= RT3593_PA_PE_G2_EN; 23674310d6deSBernhard Schmidt } else { /* 5GHz */ 23684310d6deSBernhard Schmidt tmp |= RT2860_PA_PE_A0_EN; 23694310d6deSBernhard Schmidt if (sc->ntxchains > 1) 23704310d6deSBernhard Schmidt tmp |= RT2860_PA_PE_A1_EN; 23714310d6deSBernhard Schmidt if (sc->mac_ver == 0x3593 && sc->ntxchains > 2) 23724310d6deSBernhard Schmidt tmp |= RT3593_PA_PE_A2_EN; 23734310d6deSBernhard Schmidt } 23744310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_TX_PIN_CFG, tmp); 23754310d6deSBernhard Schmidt 23764310d6deSBernhard Schmidt if (sc->mac_ver == 0x3593) { 23774310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_GPIO_CTRL); 23784310d6deSBernhard Schmidt if (sc->sc_flags & RT2860_PCIE) { 23794310d6deSBernhard Schmidt tmp &= ~0x01010000; 23804310d6deSBernhard Schmidt if (group == 0) 23814310d6deSBernhard Schmidt tmp |= 0x00010000; 23824310d6deSBernhard Schmidt } else { 23834310d6deSBernhard Schmidt tmp &= ~0x00008080; 23844310d6deSBernhard Schmidt if (group == 0) 23854310d6deSBernhard Schmidt tmp |= 0x00000080; 23864310d6deSBernhard Schmidt } 23874310d6deSBernhard Schmidt tmp = (tmp & ~0x00001000) | 0x00000010; 23884310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_GPIO_CTRL, tmp); 23894310d6deSBernhard Schmidt } 23904310d6deSBernhard Schmidt 23914310d6deSBernhard Schmidt /* set initial AGC value */ 23924310d6deSBernhard Schmidt if (group == 0) { /* 2GHz band */ 23934310d6deSBernhard Schmidt if (sc->mac_ver >= 0x3071) 23944310d6deSBernhard Schmidt agc = 0x1c + sc->lna[0] * 2; 23954310d6deSBernhard Schmidt else 23964310d6deSBernhard Schmidt agc = 0x2e + sc->lna[0]; 23974310d6deSBernhard Schmidt } else { /* 5GHz band */ 23984310d6deSBernhard Schmidt agc = 0x32 + (sc->lna[group] * 5) / 3; 23994310d6deSBernhard Schmidt } 24004310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 66, agc); 24014310d6deSBernhard Schmidt 24024310d6deSBernhard Schmidt DELAY(1000); 24034310d6deSBernhard Schmidt } 24044310d6deSBernhard Schmidt 24054310d6deSBernhard Schmidt static void 24064310d6deSBernhard Schmidt rt2860_set_chan(struct rt2860_softc *sc, u_int chan) 24074310d6deSBernhard Schmidt { 24084310d6deSBernhard Schmidt const struct rfprog *rfprog = rt2860_rf2850; 24094310d6deSBernhard Schmidt uint32_t r2, r3, r4; 24104310d6deSBernhard Schmidt int8_t txpow1, txpow2; 24114310d6deSBernhard Schmidt u_int i; 24124310d6deSBernhard Schmidt 24134310d6deSBernhard Schmidt /* find the settings for this channel (we know it exists) */ 24144310d6deSBernhard Schmidt for (i = 0; rfprog[i].chan != chan; i++); 24154310d6deSBernhard Schmidt 24164310d6deSBernhard Schmidt r2 = rfprog[i].r2; 24174310d6deSBernhard Schmidt if (sc->ntxchains == 1) 24184310d6deSBernhard Schmidt r2 |= 1 << 12; /* 1T: disable Tx chain 2 */ 24194310d6deSBernhard Schmidt if (sc->nrxchains == 1) 24204310d6deSBernhard Schmidt r2 |= 1 << 15 | 1 << 4; /* 1R: disable Rx chains 2 & 3 */ 24214310d6deSBernhard Schmidt else if (sc->nrxchains == 2) 24224310d6deSBernhard Schmidt r2 |= 1 << 4; /* 2R: disable Rx chain 3 */ 24234310d6deSBernhard Schmidt 24244310d6deSBernhard Schmidt /* use Tx power values from EEPROM */ 24254310d6deSBernhard Schmidt txpow1 = sc->txpow1[i]; 24264310d6deSBernhard Schmidt txpow2 = sc->txpow2[i]; 24274310d6deSBernhard Schmidt if (chan > 14) { 24284310d6deSBernhard Schmidt if (txpow1 >= 0) 24294310d6deSBernhard Schmidt txpow1 = txpow1 << 1 | 1; 24304310d6deSBernhard Schmidt else 24314310d6deSBernhard Schmidt txpow1 = (7 + txpow1) << 1; 24324310d6deSBernhard Schmidt if (txpow2 >= 0) 24334310d6deSBernhard Schmidt txpow2 = txpow2 << 1 | 1; 24344310d6deSBernhard Schmidt else 24354310d6deSBernhard Schmidt txpow2 = (7 + txpow2) << 1; 24364310d6deSBernhard Schmidt } 24374310d6deSBernhard Schmidt r3 = rfprog[i].r3 | txpow1 << 7; 24384310d6deSBernhard Schmidt r4 = rfprog[i].r4 | sc->freq << 13 | txpow2 << 4; 24394310d6deSBernhard Schmidt 24404310d6deSBernhard Schmidt rt2860_rf_write(sc, RT2860_RF1, rfprog[i].r1); 24414310d6deSBernhard Schmidt rt2860_rf_write(sc, RT2860_RF2, r2); 24424310d6deSBernhard Schmidt rt2860_rf_write(sc, RT2860_RF3, r3); 24434310d6deSBernhard Schmidt rt2860_rf_write(sc, RT2860_RF4, r4); 24444310d6deSBernhard Schmidt 24454310d6deSBernhard Schmidt DELAY(200); 24464310d6deSBernhard Schmidt 24474310d6deSBernhard Schmidt rt2860_rf_write(sc, RT2860_RF1, rfprog[i].r1); 24484310d6deSBernhard Schmidt rt2860_rf_write(sc, RT2860_RF2, r2); 24494310d6deSBernhard Schmidt rt2860_rf_write(sc, RT2860_RF3, r3 | 1); 24504310d6deSBernhard Schmidt rt2860_rf_write(sc, RT2860_RF4, r4); 24514310d6deSBernhard Schmidt 24524310d6deSBernhard Schmidt DELAY(200); 24534310d6deSBernhard Schmidt 24544310d6deSBernhard Schmidt rt2860_rf_write(sc, RT2860_RF1, rfprog[i].r1); 24554310d6deSBernhard Schmidt rt2860_rf_write(sc, RT2860_RF2, r2); 24564310d6deSBernhard Schmidt rt2860_rf_write(sc, RT2860_RF3, r3); 24574310d6deSBernhard Schmidt rt2860_rf_write(sc, RT2860_RF4, r4); 24584310d6deSBernhard Schmidt } 24594310d6deSBernhard Schmidt 24604310d6deSBernhard Schmidt static void 24614310d6deSBernhard Schmidt rt3090_set_chan(struct rt2860_softc *sc, u_int chan) 24624310d6deSBernhard Schmidt { 24634310d6deSBernhard Schmidt int8_t txpow1, txpow2; 24644310d6deSBernhard Schmidt uint8_t rf; 24654310d6deSBernhard Schmidt int i; 24664310d6deSBernhard Schmidt 24674310d6deSBernhard Schmidt /* RT3090 is 2GHz only */ 24684310d6deSBernhard Schmidt KASSERT(chan >= 1 && chan <= 14, ("chan %d not support", chan)); 24694310d6deSBernhard Schmidt 24704310d6deSBernhard Schmidt /* find the settings for this channel (we know it exists) */ 24714310d6deSBernhard Schmidt for (i = 0; rt2860_rf2850[i].chan != chan; i++); 24724310d6deSBernhard Schmidt 24734310d6deSBernhard Schmidt /* use Tx power values from EEPROM */ 24744310d6deSBernhard Schmidt txpow1 = sc->txpow1[i]; 24754310d6deSBernhard Schmidt txpow2 = sc->txpow2[i]; 24764310d6deSBernhard Schmidt 24774310d6deSBernhard Schmidt rt3090_rf_write(sc, 2, rt3090_freqs[i].n); 24784310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 3); 24794310d6deSBernhard Schmidt rf = (rf & ~0x0f) | rt3090_freqs[i].k; 24804310d6deSBernhard Schmidt rt3090_rf_write(sc, 3, rf); 24814310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 6); 24824310d6deSBernhard Schmidt rf = (rf & ~0x03) | rt3090_freqs[i].r; 24834310d6deSBernhard Schmidt rt3090_rf_write(sc, 6, rf); 24844310d6deSBernhard Schmidt 24854310d6deSBernhard Schmidt /* set Tx0 power */ 24864310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 12); 24874310d6deSBernhard Schmidt rf = (rf & ~0x1f) | txpow1; 24884310d6deSBernhard Schmidt rt3090_rf_write(sc, 12, rf); 24894310d6deSBernhard Schmidt 24904310d6deSBernhard Schmidt /* set Tx1 power */ 24914310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 13); 24924310d6deSBernhard Schmidt rf = (rf & ~0x1f) | txpow2; 24934310d6deSBernhard Schmidt rt3090_rf_write(sc, 13, rf); 24944310d6deSBernhard Schmidt 24954310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 1); 24964310d6deSBernhard Schmidt rf &= ~0xfc; 24974310d6deSBernhard Schmidt if (sc->ntxchains == 1) 24984310d6deSBernhard Schmidt rf |= RT3070_TX1_PD | RT3070_TX2_PD; 24994310d6deSBernhard Schmidt else if (sc->ntxchains == 2) 25004310d6deSBernhard Schmidt rf |= RT3070_TX2_PD; 25014310d6deSBernhard Schmidt if (sc->nrxchains == 1) 25024310d6deSBernhard Schmidt rf |= RT3070_RX1_PD | RT3070_RX2_PD; 25034310d6deSBernhard Schmidt else if (sc->nrxchains == 2) 25044310d6deSBernhard Schmidt rf |= RT3070_RX2_PD; 25054310d6deSBernhard Schmidt rt3090_rf_write(sc, 1, rf); 25064310d6deSBernhard Schmidt 25074310d6deSBernhard Schmidt /* set RF offset */ 25084310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 23); 25094310d6deSBernhard Schmidt rf = (rf & ~0x7f) | sc->freq; 25104310d6deSBernhard Schmidt rt3090_rf_write(sc, 23, rf); 25114310d6deSBernhard Schmidt 25124310d6deSBernhard Schmidt /* program RF filter */ 25134310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 24); /* Tx */ 25144310d6deSBernhard Schmidt rf = (rf & ~0x3f) | sc->rf24_20mhz; 25154310d6deSBernhard Schmidt rt3090_rf_write(sc, 24, rf); 25164310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 31); /* Rx */ 25174310d6deSBernhard Schmidt rf = (rf & ~0x3f) | sc->rf24_20mhz; 25184310d6deSBernhard Schmidt rt3090_rf_write(sc, 31, rf); 25194310d6deSBernhard Schmidt 25204310d6deSBernhard Schmidt /* enable RF tuning */ 25214310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 7); 25224310d6deSBernhard Schmidt rt3090_rf_write(sc, 7, rf | RT3070_TUNE); 25234310d6deSBernhard Schmidt } 25244310d6deSBernhard Schmidt 25256fc44dabSKevin Lo static void 25266fc44dabSKevin Lo rt5390_set_chan(struct rt2860_softc *sc, u_int chan) 25276fc44dabSKevin Lo { 25286fc44dabSKevin Lo uint8_t h20mhz, rf, tmp; 25296fc44dabSKevin Lo int8_t txpow1, txpow2; 25306fc44dabSKevin Lo int i; 25316fc44dabSKevin Lo 25326fc44dabSKevin Lo /* RT5390 is 2GHz only */ 25336fc44dabSKevin Lo KASSERT(chan >= 1 && chan <= 14, ("chan %d not support", chan)); 25346fc44dabSKevin Lo 25356fc44dabSKevin Lo /* find the settings for this channel (we know it exists) */ 25366fc44dabSKevin Lo for (i = 0; rt2860_rf2850[i].chan != chan; i++); 25376fc44dabSKevin Lo 25386fc44dabSKevin Lo /* use Tx power values from EEPROM */ 25396fc44dabSKevin Lo txpow1 = sc->txpow1[i]; 25406fc44dabSKevin Lo txpow2 = sc->txpow2[i]; 25416fc44dabSKevin Lo 25426fc44dabSKevin Lo rt3090_rf_write(sc, 8, rt3090_freqs[i].n); 25436fc44dabSKevin Lo rt3090_rf_write(sc, 9, rt3090_freqs[i].k & 0x0f); 25446fc44dabSKevin Lo rf = rt3090_rf_read(sc, 11); 25456fc44dabSKevin Lo rf = (rf & ~0x03) | (rt3090_freqs[i].r & 0x03); 25466fc44dabSKevin Lo rt3090_rf_write(sc, 11, rf); 25476fc44dabSKevin Lo 25486fc44dabSKevin Lo rf = rt3090_rf_read(sc, 49); 25496fc44dabSKevin Lo rf = (rf & ~0x3f) | (txpow1 & 0x3f); 25506fc44dabSKevin Lo /* the valid range of the RF R49 is 0x00~0x27 */ 25516fc44dabSKevin Lo if ((rf & 0x3f) > 0x27) 25526fc44dabSKevin Lo rf = (rf & ~0x3f) | 0x27; 25536fc44dabSKevin Lo rt3090_rf_write(sc, 49, rf); 25546fc44dabSKevin Lo if (sc->mac_ver == 0x5392) { 25556fc44dabSKevin Lo rf = rt3090_rf_read(sc, 50); 25566fc44dabSKevin Lo rf = (rf & ~0x3f) | (txpow2 & 0x3f); 25576fc44dabSKevin Lo /* the valid range of the RF R50 is 0x00~0x27 */ 25586fc44dabSKevin Lo if ((rf & 0x3f) > 0x27) 25596fc44dabSKevin Lo rf = (rf & ~0x3f) | 0x27; 25606fc44dabSKevin Lo rt3090_rf_write(sc, 50, rf); 25616fc44dabSKevin Lo } 25626fc44dabSKevin Lo 25636fc44dabSKevin Lo rf = rt3090_rf_read(sc, 1); 25646fc44dabSKevin Lo rf |= RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD; 25656fc44dabSKevin Lo if (sc->mac_ver == 0x5392) 25666fc44dabSKevin Lo rf |= RT3070_RX1_PD | RT3070_TX1_PD; 25676fc44dabSKevin Lo rt3090_rf_write(sc, 1, rf); 25686fc44dabSKevin Lo 25696fc44dabSKevin Lo rf = rt3090_rf_read(sc, 2); 25706fc44dabSKevin Lo rt3090_rf_write(sc, 2, rf | RT3593_RESCAL); 25716fc44dabSKevin Lo DELAY(1000); 25726fc44dabSKevin Lo rt3090_rf_write(sc, 2, rf & ~RT3593_RESCAL); 25736fc44dabSKevin Lo 25746fc44dabSKevin Lo rf = rt3090_rf_read(sc, 17); 25756fc44dabSKevin Lo tmp = rf; 25766fc44dabSKevin Lo rf = (rf & ~0x7f) | (sc->freq & 0x7f); 25776fc44dabSKevin Lo rf = MIN(rf, 0x5f); 25786fc44dabSKevin Lo if (tmp != rf) 25796fc44dabSKevin Lo rt2860_mcu_cmd(sc, 0x74, (tmp << 8 ) | rf, 0); 25806fc44dabSKevin Lo 25816fc44dabSKevin Lo if (sc->mac_ver == 0x5390) { 25826fc44dabSKevin Lo if (chan <= 4) 25836fc44dabSKevin Lo rf = 0x73; 25846fc44dabSKevin Lo else if (chan >= 5 && chan <= 6) 25856fc44dabSKevin Lo rf = 0x63; 25866fc44dabSKevin Lo else if (chan >= 7 && chan <= 10) 25876fc44dabSKevin Lo rf = 0x53; 25886fc44dabSKevin Lo else 25896fc44dabSKevin Lo rf = 43; 25906fc44dabSKevin Lo rt3090_rf_write(sc, 55, rf); 25916fc44dabSKevin Lo 25926fc44dabSKevin Lo if (chan == 1) 25936fc44dabSKevin Lo rf = 0x0c; 25946fc44dabSKevin Lo else if (chan == 2) 25956fc44dabSKevin Lo rf = 0x0b; 25966fc44dabSKevin Lo else if (chan == 3) 25976fc44dabSKevin Lo rf = 0x0a; 25986fc44dabSKevin Lo else if (chan >= 4 && chan <= 6) 25996fc44dabSKevin Lo rf = 0x09; 26006fc44dabSKevin Lo else if (chan >= 7 && chan <= 12) 26016fc44dabSKevin Lo rf = 0x08; 26026fc44dabSKevin Lo else if (chan == 13) 26036fc44dabSKevin Lo rf = 0x07; 26046fc44dabSKevin Lo else 26056fc44dabSKevin Lo rf = 0x06; 26066fc44dabSKevin Lo rt3090_rf_write(sc, 59, rf); 26076fc44dabSKevin Lo } 26086fc44dabSKevin Lo 26096fc44dabSKevin Lo /* Tx/Rx h20M */ 26106fc44dabSKevin Lo h20mhz = (sc->rf24_20mhz & 0x20) >> 5; 26116fc44dabSKevin Lo rf = rt3090_rf_read(sc, 30); 26126fc44dabSKevin Lo rf = (rf & ~0x06) | (h20mhz << 1) | (h20mhz << 2); 26136fc44dabSKevin Lo rt3090_rf_write(sc, 30, rf); 26146fc44dabSKevin Lo 26156fc44dabSKevin Lo /* Rx BB filter VCM */ 26166fc44dabSKevin Lo rf = rt3090_rf_read(sc, 30); 26176fc44dabSKevin Lo rf = (rf & ~0x18) | 0x10; 26186fc44dabSKevin Lo rt3090_rf_write(sc, 30, rf); 26196fc44dabSKevin Lo 26206fc44dabSKevin Lo /* Initiate VCO calibration. */ 26216fc44dabSKevin Lo rf = rt3090_rf_read(sc, 3); 26226fc44dabSKevin Lo rf |= RT3593_VCOCAL; 26236fc44dabSKevin Lo rt3090_rf_write(sc, 3, rf); 26246fc44dabSKevin Lo } 26256fc44dabSKevin Lo 26264310d6deSBernhard Schmidt static int 26274310d6deSBernhard Schmidt rt3090_rf_init(struct rt2860_softc *sc) 26284310d6deSBernhard Schmidt { 26294310d6deSBernhard Schmidt uint32_t tmp; 26304310d6deSBernhard Schmidt uint8_t rf, bbp; 26314310d6deSBernhard Schmidt int i; 26324310d6deSBernhard Schmidt 26334310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 30); 26344310d6deSBernhard Schmidt /* toggle RF R30 bit 7 */ 26354310d6deSBernhard Schmidt rt3090_rf_write(sc, 30, rf | 0x80); 26364310d6deSBernhard Schmidt DELAY(1000); 26374310d6deSBernhard Schmidt rt3090_rf_write(sc, 30, rf & ~0x80); 26384310d6deSBernhard Schmidt 26394310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT3070_LDO_CFG0); 26404310d6deSBernhard Schmidt tmp &= ~0x1f000000; 26414310d6deSBernhard Schmidt if (sc->patch_dac && sc->mac_rev < 0x0211) 26424310d6deSBernhard Schmidt tmp |= 0x0d000000; /* 1.35V */ 26434310d6deSBernhard Schmidt else 26444310d6deSBernhard Schmidt tmp |= 0x01000000; /* 1.2V */ 26454310d6deSBernhard Schmidt RAL_WRITE(sc, RT3070_LDO_CFG0, tmp); 26464310d6deSBernhard Schmidt 26474310d6deSBernhard Schmidt /* patch LNA_PE_G1 */ 26484310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT3070_GPIO_SWITCH); 26494310d6deSBernhard Schmidt RAL_WRITE(sc, RT3070_GPIO_SWITCH, tmp & ~0x20); 26504310d6deSBernhard Schmidt 26514310d6deSBernhard Schmidt /* initialize RF registers to default value */ 26526fc44dabSKevin Lo for (i = 0; i < nitems(rt3090_def_rf); i++) { 26534310d6deSBernhard Schmidt rt3090_rf_write(sc, rt3090_def_rf[i].reg, 26544310d6deSBernhard Schmidt rt3090_def_rf[i].val); 26554310d6deSBernhard Schmidt } 26564310d6deSBernhard Schmidt 26574310d6deSBernhard Schmidt /* select 20MHz bandwidth */ 26584310d6deSBernhard Schmidt rt3090_rf_write(sc, 31, 0x14); 26594310d6deSBernhard Schmidt 26604310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 6); 26614310d6deSBernhard Schmidt rt3090_rf_write(sc, 6, rf | 0x40); 26624310d6deSBernhard Schmidt 26634310d6deSBernhard Schmidt if (sc->mac_ver != 0x3593) { 26644310d6deSBernhard Schmidt /* calibrate filter for 20MHz bandwidth */ 26654310d6deSBernhard Schmidt sc->rf24_20mhz = 0x1f; /* default value */ 26664310d6deSBernhard Schmidt rt3090_filter_calib(sc, 0x07, 0x16, &sc->rf24_20mhz); 26674310d6deSBernhard Schmidt 26684310d6deSBernhard Schmidt /* select 40MHz bandwidth */ 26694310d6deSBernhard Schmidt bbp = rt2860_mcu_bbp_read(sc, 4); 26704310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 4, (bbp & ~0x08) | 0x10); 26714310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 31); 26724310d6deSBernhard Schmidt rt3090_rf_write(sc, 31, rf | 0x20); 26734310d6deSBernhard Schmidt 26744310d6deSBernhard Schmidt /* calibrate filter for 40MHz bandwidth */ 26754310d6deSBernhard Schmidt sc->rf24_40mhz = 0x2f; /* default value */ 26764310d6deSBernhard Schmidt rt3090_filter_calib(sc, 0x27, 0x19, &sc->rf24_40mhz); 26774310d6deSBernhard Schmidt 26784310d6deSBernhard Schmidt /* go back to 20MHz bandwidth */ 26794310d6deSBernhard Schmidt bbp = rt2860_mcu_bbp_read(sc, 4); 26804310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 4, bbp & ~0x18); 26814310d6deSBernhard Schmidt } 26824310d6deSBernhard Schmidt if (sc->mac_rev < 0x0211) 26834310d6deSBernhard Schmidt rt3090_rf_write(sc, 27, 0x03); 26844310d6deSBernhard Schmidt 26854310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT3070_OPT_14); 26864310d6deSBernhard Schmidt RAL_WRITE(sc, RT3070_OPT_14, tmp | 1); 26874310d6deSBernhard Schmidt 26884310d6deSBernhard Schmidt if (sc->rf_rev == RT3070_RF_3020) 26894310d6deSBernhard Schmidt rt3090_set_rx_antenna(sc, 0); 26904310d6deSBernhard Schmidt 26914310d6deSBernhard Schmidt bbp = rt2860_mcu_bbp_read(sc, 138); 26924310d6deSBernhard Schmidt if (sc->mac_ver == 0x3593) { 26934310d6deSBernhard Schmidt if (sc->ntxchains == 1) 26944310d6deSBernhard Schmidt bbp |= 0x60; /* turn off DAC1 and DAC2 */ 26954310d6deSBernhard Schmidt else if (sc->ntxchains == 2) 26964310d6deSBernhard Schmidt bbp |= 0x40; /* turn off DAC2 */ 26974310d6deSBernhard Schmidt if (sc->nrxchains == 1) 26984310d6deSBernhard Schmidt bbp &= ~0x06; /* turn off ADC1 and ADC2 */ 26994310d6deSBernhard Schmidt else if (sc->nrxchains == 2) 27004310d6deSBernhard Schmidt bbp &= ~0x04; /* turn off ADC2 */ 27014310d6deSBernhard Schmidt } else { 27024310d6deSBernhard Schmidt if (sc->ntxchains == 1) 27034310d6deSBernhard Schmidt bbp |= 0x20; /* turn off DAC1 */ 27044310d6deSBernhard Schmidt if (sc->nrxchains == 1) 27054310d6deSBernhard Schmidt bbp &= ~0x02; /* turn off ADC1 */ 27064310d6deSBernhard Schmidt } 27074310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 138, bbp); 27084310d6deSBernhard Schmidt 27094310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 1); 27104310d6deSBernhard Schmidt rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD); 27114310d6deSBernhard Schmidt rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD; 27124310d6deSBernhard Schmidt rt3090_rf_write(sc, 1, rf); 27134310d6deSBernhard Schmidt 27144310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 15); 27154310d6deSBernhard Schmidt rt3090_rf_write(sc, 15, rf & ~RT3070_TX_LO2); 27164310d6deSBernhard Schmidt 27174310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 17); 27184310d6deSBernhard Schmidt rf &= ~RT3070_TX_LO1; 27194310d6deSBernhard Schmidt if (sc->mac_rev >= 0x0211 && !sc->ext_2ghz_lna) 27204310d6deSBernhard Schmidt rf |= 0x20; /* fix for long range Rx issue */ 27214310d6deSBernhard Schmidt if (sc->txmixgain_2ghz >= 2) 27224310d6deSBernhard Schmidt rf = (rf & ~0x7) | sc->txmixgain_2ghz; 27234310d6deSBernhard Schmidt rt3090_rf_write(sc, 17, rf); 27244310d6deSBernhard Schmidt 27254310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 20); 27264310d6deSBernhard Schmidt rt3090_rf_write(sc, 20, rf & ~RT3070_RX_LO1); 27274310d6deSBernhard Schmidt 27284310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 21); 27294310d6deSBernhard Schmidt rt3090_rf_write(sc, 21, rf & ~RT3070_RX_LO2); 27304310d6deSBernhard Schmidt 27316fc44dabSKevin Lo return (0); 27324310d6deSBernhard Schmidt } 27334310d6deSBernhard Schmidt 27346fc44dabSKevin Lo static void 27356fc44dabSKevin Lo rt5390_rf_init(struct rt2860_softc *sc) 27366fc44dabSKevin Lo { 27376fc44dabSKevin Lo uint8_t rf, bbp; 27386fc44dabSKevin Lo int i; 27396fc44dabSKevin Lo 27406fc44dabSKevin Lo rf = rt3090_rf_read(sc, 2); 27416fc44dabSKevin Lo /* Toggle RF R2 bit 7. */ 27426fc44dabSKevin Lo rt3090_rf_write(sc, 2, rf | RT3593_RESCAL); 27436fc44dabSKevin Lo DELAY(1000); 27446fc44dabSKevin Lo rt3090_rf_write(sc, 2, rf & ~RT3593_RESCAL); 27456fc44dabSKevin Lo 27466fc44dabSKevin Lo /* Initialize RF registers to default value. */ 27476fc44dabSKevin Lo if (sc->mac_ver == 0x5392) { 27486fc44dabSKevin Lo for (i = 0; i < nitems(rt5392_def_rf); i++) { 27496fc44dabSKevin Lo rt3090_rf_write(sc, rt5392_def_rf[i].reg, 27506fc44dabSKevin Lo rt5392_def_rf[i].val); 27516fc44dabSKevin Lo } 27526fc44dabSKevin Lo } else { 27536fc44dabSKevin Lo for (i = 0; i < nitems(rt5390_def_rf); i++) { 27546fc44dabSKevin Lo rt3090_rf_write(sc, rt5390_def_rf[i].reg, 27556fc44dabSKevin Lo rt5390_def_rf[i].val); 27566fc44dabSKevin Lo } 27576fc44dabSKevin Lo } 27586fc44dabSKevin Lo 27596fc44dabSKevin Lo sc->rf24_20mhz = 0x1f; 27606fc44dabSKevin Lo sc->rf24_40mhz = 0x2f; 27616fc44dabSKevin Lo 27626fc44dabSKevin Lo if (sc->mac_rev < 0x0211) 27636fc44dabSKevin Lo rt3090_rf_write(sc, 27, 0x03); 27646fc44dabSKevin Lo 27656fc44dabSKevin Lo /* Set led open drain enable. */ 27666fc44dabSKevin Lo RAL_WRITE(sc, RT3070_OPT_14, RAL_READ(sc, RT3070_OPT_14) | 1); 27676fc44dabSKevin Lo 27686fc44dabSKevin Lo RAL_WRITE(sc, RT2860_TX_SW_CFG1, 0); 27696fc44dabSKevin Lo RAL_WRITE(sc, RT2860_TX_SW_CFG2, 0); 27706fc44dabSKevin Lo 27716fc44dabSKevin Lo if (sc->mac_ver == 0x5390) 27726fc44dabSKevin Lo rt3090_set_rx_antenna(sc, 0); 27736fc44dabSKevin Lo 27746fc44dabSKevin Lo /* Patch RSSI inaccurate issue. */ 27756fc44dabSKevin Lo rt2860_mcu_bbp_write(sc, 79, 0x13); 27766fc44dabSKevin Lo rt2860_mcu_bbp_write(sc, 80, 0x05); 27776fc44dabSKevin Lo rt2860_mcu_bbp_write(sc, 81, 0x33); 27786fc44dabSKevin Lo 27796fc44dabSKevin Lo /* Enable DC filter. */ 27806fc44dabSKevin Lo if (sc->mac_rev >= 0x0211) 27816fc44dabSKevin Lo rt2860_mcu_bbp_write(sc, 103, 0xc0); 27826fc44dabSKevin Lo 27836fc44dabSKevin Lo bbp = rt2860_mcu_bbp_read(sc, 138); 27846fc44dabSKevin Lo if (sc->ntxchains == 1) 27856fc44dabSKevin Lo bbp |= 0x20; /* Turn off DAC1. */ 27866fc44dabSKevin Lo if (sc->nrxchains == 1) 27876fc44dabSKevin Lo bbp &= ~0x02; /* Turn off ADC1. */ 27886fc44dabSKevin Lo rt2860_mcu_bbp_write(sc, 138, bbp); 27896fc44dabSKevin Lo 27906fc44dabSKevin Lo /* Enable RX LO1 and LO2. */ 27916fc44dabSKevin Lo rt3090_rf_write(sc, 38, rt3090_rf_read(sc, 38) & ~RT5390_RX_LO1); 27926fc44dabSKevin Lo rt3090_rf_write(sc, 39, rt3090_rf_read(sc, 39) & ~RT5390_RX_LO2); 27936fc44dabSKevin Lo 27946fc44dabSKevin Lo /* Avoid data lost and CRC error. */ 27956fc44dabSKevin Lo rt2860_mcu_bbp_write(sc, 4, 27966fc44dabSKevin Lo rt2860_mcu_bbp_read(sc, 4) | RT5390_MAC_IF_CTRL); 27976fc44dabSKevin Lo 27986fc44dabSKevin Lo rf = rt3090_rf_read(sc, 30); 27996fc44dabSKevin Lo rf = (rf & ~0x18) | 0x10; 28006fc44dabSKevin Lo rt3090_rf_write(sc, 30, rf); 28016fc44dabSKevin Lo } 28026fc44dabSKevin Lo 28036fc44dabSKevin Lo static void 28044310d6deSBernhard Schmidt rt3090_rf_wakeup(struct rt2860_softc *sc) 28054310d6deSBernhard Schmidt { 28064310d6deSBernhard Schmidt uint32_t tmp; 28074310d6deSBernhard Schmidt uint8_t rf; 28084310d6deSBernhard Schmidt 28094310d6deSBernhard Schmidt if (sc->mac_ver == 0x3593) { 28104310d6deSBernhard Schmidt /* enable VCO */ 28114310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 1); 28124310d6deSBernhard Schmidt rt3090_rf_write(sc, 1, rf | RT3593_VCO); 28134310d6deSBernhard Schmidt 28144310d6deSBernhard Schmidt /* initiate VCO calibration */ 28154310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 3); 28164310d6deSBernhard Schmidt rt3090_rf_write(sc, 3, rf | RT3593_VCOCAL); 28174310d6deSBernhard Schmidt 28184310d6deSBernhard Schmidt /* enable VCO bias current control */ 28194310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 6); 28204310d6deSBernhard Schmidt rt3090_rf_write(sc, 6, rf | RT3593_VCO_IC); 28214310d6deSBernhard Schmidt 28224310d6deSBernhard Schmidt /* initiate res calibration */ 28234310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 2); 28244310d6deSBernhard Schmidt rt3090_rf_write(sc, 2, rf | RT3593_RESCAL); 28254310d6deSBernhard Schmidt 28264310d6deSBernhard Schmidt /* set reference current control to 0.33 mA */ 28274310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 22); 28284310d6deSBernhard Schmidt rf &= ~RT3593_CP_IC_MASK; 28294310d6deSBernhard Schmidt rf |= 1 << RT3593_CP_IC_SHIFT; 28304310d6deSBernhard Schmidt rt3090_rf_write(sc, 22, rf); 28314310d6deSBernhard Schmidt 28324310d6deSBernhard Schmidt /* enable RX CTB */ 28334310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 46); 28344310d6deSBernhard Schmidt rt3090_rf_write(sc, 46, rf | RT3593_RX_CTB); 28354310d6deSBernhard Schmidt 28364310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 20); 28374310d6deSBernhard Schmidt rf &= ~(RT3593_LDO_RF_VC_MASK | RT3593_LDO_PLL_VC_MASK); 28384310d6deSBernhard Schmidt rt3090_rf_write(sc, 20, rf); 28394310d6deSBernhard Schmidt } else { 28404310d6deSBernhard Schmidt /* enable RF block */ 28414310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 1); 28424310d6deSBernhard Schmidt rt3090_rf_write(sc, 1, rf | RT3070_RF_BLOCK); 28434310d6deSBernhard Schmidt 28444310d6deSBernhard Schmidt /* enable VCO bias current control */ 28454310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 7); 28464310d6deSBernhard Schmidt rt3090_rf_write(sc, 7, rf | 0x30); 28474310d6deSBernhard Schmidt 28484310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 9); 28494310d6deSBernhard Schmidt rt3090_rf_write(sc, 9, rf | 0x0e); 28504310d6deSBernhard Schmidt 28514310d6deSBernhard Schmidt /* enable RX CTB */ 28524310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 21); 28534310d6deSBernhard Schmidt rt3090_rf_write(sc, 21, rf | RT3070_RX_CTB); 28544310d6deSBernhard Schmidt 28554310d6deSBernhard Schmidt /* fix Tx to Rx IQ glitch by raising RF voltage */ 28564310d6deSBernhard Schmidt rf = rt3090_rf_read(sc, 27); 28574310d6deSBernhard Schmidt rf &= ~0x77; 28584310d6deSBernhard Schmidt if (sc->mac_rev < 0x0211) 28594310d6deSBernhard Schmidt rf |= 0x03; 28604310d6deSBernhard Schmidt rt3090_rf_write(sc, 27, rf); 28614310d6deSBernhard Schmidt } 28624310d6deSBernhard Schmidt if (sc->patch_dac && sc->mac_rev < 0x0211) { 28634310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT3070_LDO_CFG0); 28644310d6deSBernhard Schmidt tmp = (tmp & ~0x1f000000) | 0x0d000000; 28654310d6deSBernhard Schmidt RAL_WRITE(sc, RT3070_LDO_CFG0, tmp); 28664310d6deSBernhard Schmidt } 28674310d6deSBernhard Schmidt } 28684310d6deSBernhard Schmidt 28696fc44dabSKevin Lo static void 28706fc44dabSKevin Lo rt5390_rf_wakeup(struct rt2860_softc *sc) 28716fc44dabSKevin Lo { 28726fc44dabSKevin Lo uint32_t tmp; 28736fc44dabSKevin Lo uint8_t rf; 28746fc44dabSKevin Lo 28756fc44dabSKevin Lo rf = rt3090_rf_read(sc, 1); 28766fc44dabSKevin Lo rf |= RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | 28776fc44dabSKevin Lo RT3070_TX0_PD; 28786fc44dabSKevin Lo if (sc->mac_ver == 0x5392) 28796fc44dabSKevin Lo rf |= RT3070_RX1_PD | RT3070_TX1_PD; 28806fc44dabSKevin Lo rt3090_rf_write(sc, 1, rf); 28816fc44dabSKevin Lo 28826fc44dabSKevin Lo rf = rt3090_rf_read(sc, 6); 28836fc44dabSKevin Lo rf |= RT3593_VCO_IC | RT3593_VCOCAL; 28846fc44dabSKevin Lo if (sc->mac_ver == 0x5390) 28856fc44dabSKevin Lo rf &= ~RT3593_VCO_IC; 28866fc44dabSKevin Lo rt3090_rf_write(sc, 6, rf); 28876fc44dabSKevin Lo 28886fc44dabSKevin Lo rt3090_rf_write(sc, 2, rt3090_rf_read(sc, 2) | RT3593_RESCAL); 28896fc44dabSKevin Lo 28906fc44dabSKevin Lo rf = rt3090_rf_read(sc, 22); 28916fc44dabSKevin Lo rf = (rf & ~0xe0) | 0x20; 28926fc44dabSKevin Lo rt3090_rf_write(sc, 22, rf); 28936fc44dabSKevin Lo 28946fc44dabSKevin Lo rt3090_rf_write(sc, 42, rt3090_rf_read(sc, 42) | RT5390_RX_CTB); 28956fc44dabSKevin Lo rt3090_rf_write(sc, 20, rt3090_rf_read(sc, 20) & ~0x77); 28966fc44dabSKevin Lo rt3090_rf_write(sc, 3, rt3090_rf_read(sc, 3) | RT3593_VCOCAL); 28976fc44dabSKevin Lo 28986fc44dabSKevin Lo if (sc->patch_dac && sc->mac_rev < 0x0211) { 28996fc44dabSKevin Lo tmp = RAL_READ(sc, RT3070_LDO_CFG0); 29006fc44dabSKevin Lo tmp = (tmp & ~0x1f000000) | 0x0d000000; 29016fc44dabSKevin Lo RAL_WRITE(sc, RT3070_LDO_CFG0, tmp); 29026fc44dabSKevin Lo } 29036fc44dabSKevin Lo } 29046fc44dabSKevin Lo 29056fc44dabSKevin Lo static int 29064310d6deSBernhard Schmidt rt3090_filter_calib(struct rt2860_softc *sc, uint8_t init, uint8_t target, 29074310d6deSBernhard Schmidt uint8_t *val) 29084310d6deSBernhard Schmidt { 29094310d6deSBernhard Schmidt uint8_t rf22, rf24; 29104310d6deSBernhard Schmidt uint8_t bbp55_pb, bbp55_sb, delta; 29114310d6deSBernhard Schmidt int ntries; 29124310d6deSBernhard Schmidt 29134310d6deSBernhard Schmidt /* program filter */ 29144310d6deSBernhard Schmidt rf24 = rt3090_rf_read(sc, 24); 29154310d6deSBernhard Schmidt rf24 = (rf24 & 0xc0) | init; /* initial filter value */ 29164310d6deSBernhard Schmidt rt3090_rf_write(sc, 24, rf24); 29174310d6deSBernhard Schmidt 29184310d6deSBernhard Schmidt /* enable baseband loopback mode */ 29194310d6deSBernhard Schmidt rf22 = rt3090_rf_read(sc, 22); 29204310d6deSBernhard Schmidt rt3090_rf_write(sc, 22, rf22 | RT3070_BB_LOOPBACK); 29214310d6deSBernhard Schmidt 29224310d6deSBernhard Schmidt /* set power and frequency of passband test tone */ 29234310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 24, 0x00); 29244310d6deSBernhard Schmidt for (ntries = 0; ntries < 100; ntries++) { 29254310d6deSBernhard Schmidt /* transmit test tone */ 29264310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 25, 0x90); 29274310d6deSBernhard Schmidt DELAY(1000); 29284310d6deSBernhard Schmidt /* read received power */ 29294310d6deSBernhard Schmidt bbp55_pb = rt2860_mcu_bbp_read(sc, 55); 29304310d6deSBernhard Schmidt if (bbp55_pb != 0) 29314310d6deSBernhard Schmidt break; 29324310d6deSBernhard Schmidt } 29334310d6deSBernhard Schmidt if (ntries == 100) 29346fc44dabSKevin Lo return (ETIMEDOUT); 29354310d6deSBernhard Schmidt 29364310d6deSBernhard Schmidt /* set power and frequency of stopband test tone */ 29374310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 24, 0x06); 29384310d6deSBernhard Schmidt for (ntries = 0; ntries < 100; ntries++) { 29394310d6deSBernhard Schmidt /* transmit test tone */ 29404310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 25, 0x90); 29414310d6deSBernhard Schmidt DELAY(1000); 29424310d6deSBernhard Schmidt /* read received power */ 29434310d6deSBernhard Schmidt bbp55_sb = rt2860_mcu_bbp_read(sc, 55); 29444310d6deSBernhard Schmidt 29454310d6deSBernhard Schmidt delta = bbp55_pb - bbp55_sb; 29464310d6deSBernhard Schmidt if (delta > target) 29474310d6deSBernhard Schmidt break; 29484310d6deSBernhard Schmidt 29494310d6deSBernhard Schmidt /* reprogram filter */ 29504310d6deSBernhard Schmidt rf24++; 29514310d6deSBernhard Schmidt rt3090_rf_write(sc, 24, rf24); 29524310d6deSBernhard Schmidt } 29534310d6deSBernhard Schmidt if (ntries < 100) { 29544310d6deSBernhard Schmidt if (rf24 != init) 29554310d6deSBernhard Schmidt rf24--; /* backtrack */ 29564310d6deSBernhard Schmidt *val = rf24; 29574310d6deSBernhard Schmidt rt3090_rf_write(sc, 24, rf24); 29584310d6deSBernhard Schmidt } 29594310d6deSBernhard Schmidt 29604310d6deSBernhard Schmidt /* restore initial state */ 29614310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 24, 0x00); 29624310d6deSBernhard Schmidt 29634310d6deSBernhard Schmidt /* disable baseband loopback mode */ 29644310d6deSBernhard Schmidt rf22 = rt3090_rf_read(sc, 22); 29654310d6deSBernhard Schmidt rt3090_rf_write(sc, 22, rf22 & ~RT3070_BB_LOOPBACK); 29664310d6deSBernhard Schmidt 29676fc44dabSKevin Lo return (0); 29684310d6deSBernhard Schmidt } 29694310d6deSBernhard Schmidt 29704310d6deSBernhard Schmidt static void 29714310d6deSBernhard Schmidt rt3090_rf_setup(struct rt2860_softc *sc) 29724310d6deSBernhard Schmidt { 29734310d6deSBernhard Schmidt uint8_t bbp; 29744310d6deSBernhard Schmidt int i; 29754310d6deSBernhard Schmidt 29764310d6deSBernhard Schmidt if (sc->mac_rev >= 0x0211) { 29774310d6deSBernhard Schmidt /* enable DC filter */ 29784310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 103, 0xc0); 29794310d6deSBernhard Schmidt 29804310d6deSBernhard Schmidt /* improve power consumption */ 29814310d6deSBernhard Schmidt bbp = rt2860_mcu_bbp_read(sc, 31); 29824310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 31, bbp & ~0x03); 29834310d6deSBernhard Schmidt } 29844310d6deSBernhard Schmidt 29854310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_TX_SW_CFG1, 0); 29864310d6deSBernhard Schmidt if (sc->mac_rev < 0x0211) { 29874310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_TX_SW_CFG2, 29884310d6deSBernhard Schmidt sc->patch_dac ? 0x2c : 0x0f); 29894310d6deSBernhard Schmidt } else 29904310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_TX_SW_CFG2, 0); 29914310d6deSBernhard Schmidt 29924310d6deSBernhard Schmidt /* initialize RF registers from ROM */ 29936fc44dabSKevin Lo if (sc->mac_ver < 0x5390) { 29944310d6deSBernhard Schmidt for (i = 0; i < 10; i++) { 29954310d6deSBernhard Schmidt if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff) 29964310d6deSBernhard Schmidt continue; 29974310d6deSBernhard Schmidt rt3090_rf_write(sc, sc->rf[i].reg, sc->rf[i].val); 29984310d6deSBernhard Schmidt } 29994310d6deSBernhard Schmidt } 30006fc44dabSKevin Lo } 30014310d6deSBernhard Schmidt 30024310d6deSBernhard Schmidt static void 30034310d6deSBernhard Schmidt rt2860_set_leds(struct rt2860_softc *sc, uint16_t which) 30044310d6deSBernhard Schmidt { 30054310d6deSBernhard Schmidt rt2860_mcu_cmd(sc, RT2860_MCU_CMD_LEDS, 30064310d6deSBernhard Schmidt which | (sc->leds & 0x7f), 0); 30074310d6deSBernhard Schmidt } 30084310d6deSBernhard Schmidt 30094310d6deSBernhard Schmidt /* 30104310d6deSBernhard Schmidt * Hardware has a general-purpose programmable timer interrupt that can 30114310d6deSBernhard Schmidt * periodically raise MAC_INT_4. 30124310d6deSBernhard Schmidt */ 30134310d6deSBernhard Schmidt static void 30144310d6deSBernhard Schmidt rt2860_set_gp_timer(struct rt2860_softc *sc, int ms) 30154310d6deSBernhard Schmidt { 30164310d6deSBernhard Schmidt uint32_t tmp; 30174310d6deSBernhard Schmidt 30184310d6deSBernhard Schmidt /* disable GP timer before reprogramming it */ 30194310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_INT_TIMER_EN); 30204310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_INT_TIMER_EN, tmp & ~RT2860_GP_TIMER_EN); 30214310d6deSBernhard Schmidt 30224310d6deSBernhard Schmidt if (ms == 0) 30234310d6deSBernhard Schmidt return; 30244310d6deSBernhard Schmidt 30254310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_INT_TIMER_CFG); 30264310d6deSBernhard Schmidt ms *= 16; /* Unit: 64us */ 30274310d6deSBernhard Schmidt tmp = (tmp & 0xffff) | ms << RT2860_GP_TIMER_SHIFT; 30284310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_INT_TIMER_CFG, tmp); 30294310d6deSBernhard Schmidt 30304310d6deSBernhard Schmidt /* enable GP timer */ 30314310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_INT_TIMER_EN); 30324310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_INT_TIMER_EN, tmp | RT2860_GP_TIMER_EN); 30334310d6deSBernhard Schmidt } 30344310d6deSBernhard Schmidt 30354310d6deSBernhard Schmidt static void 30364310d6deSBernhard Schmidt rt2860_set_bssid(struct rt2860_softc *sc, const uint8_t *bssid) 30374310d6deSBernhard Schmidt { 30384310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_MAC_BSSID_DW0, 30394310d6deSBernhard Schmidt bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24); 30404310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_MAC_BSSID_DW1, 30414310d6deSBernhard Schmidt bssid[4] | bssid[5] << 8); 30424310d6deSBernhard Schmidt } 30434310d6deSBernhard Schmidt 30444310d6deSBernhard Schmidt static void 30454310d6deSBernhard Schmidt rt2860_set_macaddr(struct rt2860_softc *sc, const uint8_t *addr) 30464310d6deSBernhard Schmidt { 30474310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_MAC_ADDR_DW0, 30484310d6deSBernhard Schmidt addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24); 30494310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_MAC_ADDR_DW1, 30504310d6deSBernhard Schmidt addr[4] | addr[5] << 8 | 0xff << 16); 30514310d6deSBernhard Schmidt } 30524310d6deSBernhard Schmidt 30534310d6deSBernhard Schmidt static void 3054272f6adeSGleb Smirnoff rt2860_updateslot(struct ieee80211com *ic) 30554310d6deSBernhard Schmidt { 3056272f6adeSGleb Smirnoff struct rt2860_softc *sc = ic->ic_softc; 30574310d6deSBernhard Schmidt uint32_t tmp; 30584310d6deSBernhard Schmidt 30594310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_BKOFF_SLOT_CFG); 30604310d6deSBernhard Schmidt tmp &= ~0xff; 3061bdfff33fSAndriy Voskoboinyk tmp |= IEEE80211_GET_SLOTTIME(ic); 30624310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_BKOFF_SLOT_CFG, tmp); 30634310d6deSBernhard Schmidt } 30644310d6deSBernhard Schmidt 30654310d6deSBernhard Schmidt static void 30667a79cebfSGleb Smirnoff rt2860_updateprot(struct rt2860_softc *sc) 30674310d6deSBernhard Schmidt { 30687a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 30694310d6deSBernhard Schmidt uint32_t tmp; 30704310d6deSBernhard Schmidt 30714310d6deSBernhard Schmidt tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL; 30724310d6deSBernhard Schmidt /* setup protection frame rate (MCS code) */ 30734310d6deSBernhard Schmidt tmp |= IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 30744310d6deSBernhard Schmidt rt2860_rates[RT2860_RIDX_OFDM6].mcs : 30754310d6deSBernhard Schmidt rt2860_rates[RT2860_RIDX_CCK11].mcs; 30764310d6deSBernhard Schmidt 30774310d6deSBernhard Schmidt /* CCK frames don't require protection */ 30784310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_CCK_PROT_CFG, tmp); 30794310d6deSBernhard Schmidt 30804310d6deSBernhard Schmidt if (ic->ic_flags & IEEE80211_F_USEPROT) { 30814310d6deSBernhard Schmidt if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) 30824310d6deSBernhard Schmidt tmp |= RT2860_PROT_CTRL_RTS_CTS; 30834310d6deSBernhard Schmidt else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) 30844310d6deSBernhard Schmidt tmp |= RT2860_PROT_CTRL_CTS; 30854310d6deSBernhard Schmidt } 30864310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_OFDM_PROT_CFG, tmp); 30874310d6deSBernhard Schmidt } 30884310d6deSBernhard Schmidt 30894310d6deSBernhard Schmidt static void 3090272f6adeSGleb Smirnoff rt2860_update_promisc(struct ieee80211com *ic) 30914310d6deSBernhard Schmidt { 3092272f6adeSGleb Smirnoff struct rt2860_softc *sc = ic->ic_softc; 30934310d6deSBernhard Schmidt uint32_t tmp; 30944310d6deSBernhard Schmidt 30954310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_RX_FILTR_CFG); 30964310d6deSBernhard Schmidt tmp &= ~RT2860_DROP_NOT_MYBSS; 30977a79cebfSGleb Smirnoff if (ic->ic_promisc == 0) 30984310d6deSBernhard Schmidt tmp |= RT2860_DROP_NOT_MYBSS; 30994310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_RX_FILTR_CFG, tmp); 31004310d6deSBernhard Schmidt } 31014310d6deSBernhard Schmidt 31024310d6deSBernhard Schmidt static int 31034310d6deSBernhard Schmidt rt2860_updateedca(struct ieee80211com *ic) 31044310d6deSBernhard Schmidt { 31057a79cebfSGleb Smirnoff struct rt2860_softc *sc = ic->ic_softc; 31069fbe631aSAdrian Chadd struct chanAccParams chp; 31074310d6deSBernhard Schmidt const struct wmeParams *wmep; 31084310d6deSBernhard Schmidt int aci; 31094310d6deSBernhard Schmidt 31109fbe631aSAdrian Chadd ieee80211_wme_ic_getparams(ic, &chp); 31119fbe631aSAdrian Chadd 31129fbe631aSAdrian Chadd wmep = chp.cap_wmeParams; 31134310d6deSBernhard Schmidt 31144310d6deSBernhard Schmidt /* update MAC TX configuration registers */ 31154310d6deSBernhard Schmidt for (aci = 0; aci < WME_NUM_AC; aci++) { 31164310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_EDCA_AC_CFG(aci), 31174310d6deSBernhard Schmidt wmep[aci].wmep_logcwmax << 16 | 31184310d6deSBernhard Schmidt wmep[aci].wmep_logcwmin << 12 | 31194310d6deSBernhard Schmidt wmep[aci].wmep_aifsn << 8 | 31204310d6deSBernhard Schmidt wmep[aci].wmep_txopLimit); 31214310d6deSBernhard Schmidt } 31224310d6deSBernhard Schmidt 31234310d6deSBernhard Schmidt /* update SCH/DMA registers too */ 31244310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_WMM_AIFSN_CFG, 31254310d6deSBernhard Schmidt wmep[WME_AC_VO].wmep_aifsn << 12 | 31264310d6deSBernhard Schmidt wmep[WME_AC_VI].wmep_aifsn << 8 | 31274310d6deSBernhard Schmidt wmep[WME_AC_BK].wmep_aifsn << 4 | 31284310d6deSBernhard Schmidt wmep[WME_AC_BE].wmep_aifsn); 31294310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_WMM_CWMIN_CFG, 31304310d6deSBernhard Schmidt wmep[WME_AC_VO].wmep_logcwmin << 12 | 31314310d6deSBernhard Schmidt wmep[WME_AC_VI].wmep_logcwmin << 8 | 31324310d6deSBernhard Schmidt wmep[WME_AC_BK].wmep_logcwmin << 4 | 31334310d6deSBernhard Schmidt wmep[WME_AC_BE].wmep_logcwmin); 31344310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_WMM_CWMAX_CFG, 31354310d6deSBernhard Schmidt wmep[WME_AC_VO].wmep_logcwmax << 12 | 31364310d6deSBernhard Schmidt wmep[WME_AC_VI].wmep_logcwmax << 8 | 31374310d6deSBernhard Schmidt wmep[WME_AC_BK].wmep_logcwmax << 4 | 31384310d6deSBernhard Schmidt wmep[WME_AC_BE].wmep_logcwmax); 31394310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_WMM_TXOP0_CFG, 31404310d6deSBernhard Schmidt wmep[WME_AC_BK].wmep_txopLimit << 16 | 31414310d6deSBernhard Schmidt wmep[WME_AC_BE].wmep_txopLimit); 31424310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_WMM_TXOP1_CFG, 31434310d6deSBernhard Schmidt wmep[WME_AC_VO].wmep_txopLimit << 16 | 31444310d6deSBernhard Schmidt wmep[WME_AC_VI].wmep_txopLimit); 31454310d6deSBernhard Schmidt 31464310d6deSBernhard Schmidt return 0; 31474310d6deSBernhard Schmidt } 31484310d6deSBernhard Schmidt 31494310d6deSBernhard Schmidt #ifdef HW_CRYPTO 31504310d6deSBernhard Schmidt static int 31514310d6deSBernhard Schmidt rt2860_set_key(struct ieee80211com *ic, struct ieee80211_node *ni, 31524310d6deSBernhard Schmidt struct ieee80211_key *k) 31534310d6deSBernhard Schmidt { 31544310d6deSBernhard Schmidt struct rt2860_softc *sc = ic->ic_softc; 31554310d6deSBernhard Schmidt bus_size_t base; 31564310d6deSBernhard Schmidt uint32_t attr; 31574310d6deSBernhard Schmidt uint8_t mode, wcid, iv[8]; 31584310d6deSBernhard Schmidt 31594310d6deSBernhard Schmidt /* defer setting of WEP keys until interface is brought up */ 31604310d6deSBernhard Schmidt if ((ic->ic_if.if_flags & (IFF_UP | IFF_RUNNING)) != 31614310d6deSBernhard Schmidt (IFF_UP | IFF_RUNNING)) 31624310d6deSBernhard Schmidt return 0; 31634310d6deSBernhard Schmidt 31644310d6deSBernhard Schmidt /* map net80211 cipher to RT2860 security mode */ 31654310d6deSBernhard Schmidt switch (k->k_cipher) { 31664310d6deSBernhard Schmidt case IEEE80211_CIPHER_WEP40: 31674310d6deSBernhard Schmidt mode = RT2860_MODE_WEP40; 31684310d6deSBernhard Schmidt break; 31694310d6deSBernhard Schmidt case IEEE80211_CIPHER_WEP104: 31704310d6deSBernhard Schmidt mode = RT2860_MODE_WEP104; 31714310d6deSBernhard Schmidt break; 31724310d6deSBernhard Schmidt case IEEE80211_CIPHER_TKIP: 31734310d6deSBernhard Schmidt mode = RT2860_MODE_TKIP; 31744310d6deSBernhard Schmidt break; 31754310d6deSBernhard Schmidt case IEEE80211_CIPHER_CCMP: 31764310d6deSBernhard Schmidt mode = RT2860_MODE_AES_CCMP; 31774310d6deSBernhard Schmidt break; 31784310d6deSBernhard Schmidt default: 31794310d6deSBernhard Schmidt return EINVAL; 31804310d6deSBernhard Schmidt } 31814310d6deSBernhard Schmidt 31824310d6deSBernhard Schmidt if (k->k_flags & IEEE80211_KEY_GROUP) { 31834310d6deSBernhard Schmidt wcid = 0; /* NB: update WCID0 for group keys */ 31844310d6deSBernhard Schmidt base = RT2860_SKEY(0, k->k_id); 31854310d6deSBernhard Schmidt } else { 31864310d6deSBernhard Schmidt wcid = ((struct rt2860_node *)ni)->wcid; 31874310d6deSBernhard Schmidt base = RT2860_PKEY(wcid); 31884310d6deSBernhard Schmidt } 31894310d6deSBernhard Schmidt 31904310d6deSBernhard Schmidt if (k->k_cipher == IEEE80211_CIPHER_TKIP) { 31914310d6deSBernhard Schmidt RAL_WRITE_REGION_1(sc, base, k->k_key, 16); 31924310d6deSBernhard Schmidt #ifndef IEEE80211_STA_ONLY 31934310d6deSBernhard Schmidt if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 31944310d6deSBernhard Schmidt RAL_WRITE_REGION_1(sc, base + 16, &k->k_key[16], 8); 31954310d6deSBernhard Schmidt RAL_WRITE_REGION_1(sc, base + 24, &k->k_key[24], 8); 31964310d6deSBernhard Schmidt } else 31974310d6deSBernhard Schmidt #endif 31984310d6deSBernhard Schmidt { 31994310d6deSBernhard Schmidt RAL_WRITE_REGION_1(sc, base + 16, &k->k_key[24], 8); 32004310d6deSBernhard Schmidt RAL_WRITE_REGION_1(sc, base + 24, &k->k_key[16], 8); 32014310d6deSBernhard Schmidt } 32024310d6deSBernhard Schmidt } else 32034310d6deSBernhard Schmidt RAL_WRITE_REGION_1(sc, base, k->k_key, k->k_len); 32044310d6deSBernhard Schmidt 32054310d6deSBernhard Schmidt if (!(k->k_flags & IEEE80211_KEY_GROUP) || 32064310d6deSBernhard Schmidt (k->k_flags & IEEE80211_KEY_TX)) { 32074310d6deSBernhard Schmidt /* set initial packet number in IV+EIV */ 32084310d6deSBernhard Schmidt if (k->k_cipher == IEEE80211_CIPHER_WEP40 || 32094310d6deSBernhard Schmidt k->k_cipher == IEEE80211_CIPHER_WEP104) { 32104310d6deSBernhard Schmidt uint32_t val = arc4random(); 32114310d6deSBernhard Schmidt /* skip weak IVs from Fluhrer/Mantin/Shamir */ 32124310d6deSBernhard Schmidt if (val >= 0x03ff00 && (val & 0xf8ff00) == 0x00ff00) 32134310d6deSBernhard Schmidt val += 0x000100; 32144310d6deSBernhard Schmidt iv[0] = val; 32154310d6deSBernhard Schmidt iv[1] = val >> 8; 32164310d6deSBernhard Schmidt iv[2] = val >> 16; 32174310d6deSBernhard Schmidt iv[3] = k->k_id << 6; 32184310d6deSBernhard Schmidt iv[4] = iv[5] = iv[6] = iv[7] = 0; 32194310d6deSBernhard Schmidt } else { 32204310d6deSBernhard Schmidt if (k->k_cipher == IEEE80211_CIPHER_TKIP) { 32214310d6deSBernhard Schmidt iv[0] = k->k_tsc >> 8; 32224310d6deSBernhard Schmidt iv[1] = (iv[0] | 0x20) & 0x7f; 32234310d6deSBernhard Schmidt iv[2] = k->k_tsc; 32244310d6deSBernhard Schmidt } else /* CCMP */ { 32254310d6deSBernhard Schmidt iv[0] = k->k_tsc; 32264310d6deSBernhard Schmidt iv[1] = k->k_tsc >> 8; 32274310d6deSBernhard Schmidt iv[2] = 0; 32284310d6deSBernhard Schmidt } 32294310d6deSBernhard Schmidt iv[3] = k->k_id << 6 | IEEE80211_WEP_EXTIV; 32304310d6deSBernhard Schmidt iv[4] = k->k_tsc >> 16; 32314310d6deSBernhard Schmidt iv[5] = k->k_tsc >> 24; 32324310d6deSBernhard Schmidt iv[6] = k->k_tsc >> 32; 32334310d6deSBernhard Schmidt iv[7] = k->k_tsc >> 40; 32344310d6deSBernhard Schmidt } 32354310d6deSBernhard Schmidt RAL_WRITE_REGION_1(sc, RT2860_IVEIV(wcid), iv, 8); 32364310d6deSBernhard Schmidt } 32374310d6deSBernhard Schmidt 32384310d6deSBernhard Schmidt if (k->k_flags & IEEE80211_KEY_GROUP) { 32394310d6deSBernhard Schmidt /* install group key */ 32404310d6deSBernhard Schmidt attr = RAL_READ(sc, RT2860_SKEY_MODE_0_7); 32414310d6deSBernhard Schmidt attr &= ~(0xf << (k->k_id * 4)); 32424310d6deSBernhard Schmidt attr |= mode << (k->k_id * 4); 32434310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_SKEY_MODE_0_7, attr); 32444310d6deSBernhard Schmidt } else { 32454310d6deSBernhard Schmidt /* install pairwise key */ 32464310d6deSBernhard Schmidt attr = RAL_READ(sc, RT2860_WCID_ATTR(wcid)); 32474310d6deSBernhard Schmidt attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN; 32484310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_WCID_ATTR(wcid), attr); 32494310d6deSBernhard Schmidt } 32504310d6deSBernhard Schmidt return 0; 32514310d6deSBernhard Schmidt } 32524310d6deSBernhard Schmidt 32534310d6deSBernhard Schmidt static void 32544310d6deSBernhard Schmidt rt2860_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni, 32554310d6deSBernhard Schmidt struct ieee80211_key *k) 32564310d6deSBernhard Schmidt { 32574310d6deSBernhard Schmidt struct rt2860_softc *sc = ic->ic_softc; 32584310d6deSBernhard Schmidt uint32_t attr; 32594310d6deSBernhard Schmidt uint8_t wcid; 32604310d6deSBernhard Schmidt 32614310d6deSBernhard Schmidt if (k->k_flags & IEEE80211_KEY_GROUP) { 32624310d6deSBernhard Schmidt /* remove group key */ 32634310d6deSBernhard Schmidt attr = RAL_READ(sc, RT2860_SKEY_MODE_0_7); 32644310d6deSBernhard Schmidt attr &= ~(0xf << (k->k_id * 4)); 32654310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_SKEY_MODE_0_7, attr); 32664310d6deSBernhard Schmidt 32674310d6deSBernhard Schmidt } else { 32684310d6deSBernhard Schmidt /* remove pairwise key */ 32694310d6deSBernhard Schmidt wcid = ((struct rt2860_node *)ni)->wcid; 32704310d6deSBernhard Schmidt attr = RAL_READ(sc, RT2860_WCID_ATTR(wcid)); 32714310d6deSBernhard Schmidt attr &= ~0xf; 32724310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_WCID_ATTR(wcid), attr); 32734310d6deSBernhard Schmidt } 32744310d6deSBernhard Schmidt } 32754310d6deSBernhard Schmidt #endif 32764310d6deSBernhard Schmidt 32774310d6deSBernhard Schmidt static int8_t 32784310d6deSBernhard Schmidt rt2860_rssi2dbm(struct rt2860_softc *sc, uint8_t rssi, uint8_t rxchain) 32794310d6deSBernhard Schmidt { 32807a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 32814310d6deSBernhard Schmidt struct ieee80211_channel *c = ic->ic_curchan; 32824310d6deSBernhard Schmidt int delta; 32834310d6deSBernhard Schmidt 32844310d6deSBernhard Schmidt if (IEEE80211_IS_CHAN_5GHZ(c)) { 32854310d6deSBernhard Schmidt u_int chan = ieee80211_chan2ieee(ic, c); 32864310d6deSBernhard Schmidt delta = sc->rssi_5ghz[rxchain]; 32874310d6deSBernhard Schmidt 32884310d6deSBernhard Schmidt /* determine channel group */ 32894310d6deSBernhard Schmidt if (chan <= 64) 32904310d6deSBernhard Schmidt delta -= sc->lna[1]; 32914310d6deSBernhard Schmidt else if (chan <= 128) 32924310d6deSBernhard Schmidt delta -= sc->lna[2]; 32934310d6deSBernhard Schmidt else 32944310d6deSBernhard Schmidt delta -= sc->lna[3]; 32954310d6deSBernhard Schmidt } else 32964310d6deSBernhard Schmidt delta = sc->rssi_2ghz[rxchain] - sc->lna[0]; 32974310d6deSBernhard Schmidt 32984310d6deSBernhard Schmidt return -12 - delta - rssi; 32994310d6deSBernhard Schmidt } 33004310d6deSBernhard Schmidt 33014310d6deSBernhard Schmidt /* 33024310d6deSBernhard Schmidt * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word. 33034310d6deSBernhard Schmidt * Used to adjust per-rate Tx power registers. 33044310d6deSBernhard Schmidt */ 33054310d6deSBernhard Schmidt static __inline uint32_t 33064310d6deSBernhard Schmidt b4inc(uint32_t b32, int8_t delta) 33074310d6deSBernhard Schmidt { 33084310d6deSBernhard Schmidt int8_t i, b4; 33094310d6deSBernhard Schmidt 33104310d6deSBernhard Schmidt for (i = 0; i < 8; i++) { 33114310d6deSBernhard Schmidt b4 = b32 & 0xf; 33124310d6deSBernhard Schmidt b4 += delta; 33134310d6deSBernhard Schmidt if (b4 < 0) 33144310d6deSBernhard Schmidt b4 = 0; 33154310d6deSBernhard Schmidt else if (b4 > 0xf) 33164310d6deSBernhard Schmidt b4 = 0xf; 331726d9565dSPedro F. Giffuni b32 = b32 >> 4 | (uint32_t)b4 << 28; 33184310d6deSBernhard Schmidt } 33194310d6deSBernhard Schmidt return b32; 33204310d6deSBernhard Schmidt } 33214310d6deSBernhard Schmidt 33224310d6deSBernhard Schmidt static const char * 3323b0f7be91SKevin Lo rt2860_get_rf(uint16_t rev) 33244310d6deSBernhard Schmidt { 33254310d6deSBernhard Schmidt switch (rev) { 33264310d6deSBernhard Schmidt case RT2860_RF_2820: return "RT2820"; 33274310d6deSBernhard Schmidt case RT2860_RF_2850: return "RT2850"; 33284310d6deSBernhard Schmidt case RT2860_RF_2720: return "RT2720"; 33294310d6deSBernhard Schmidt case RT2860_RF_2750: return "RT2750"; 33304310d6deSBernhard Schmidt case RT3070_RF_3020: return "RT3020"; 33314310d6deSBernhard Schmidt case RT3070_RF_2020: return "RT2020"; 33324310d6deSBernhard Schmidt case RT3070_RF_3021: return "RT3021"; 33334310d6deSBernhard Schmidt case RT3070_RF_3022: return "RT3022"; 33344310d6deSBernhard Schmidt case RT3070_RF_3052: return "RT3052"; 33354310d6deSBernhard Schmidt case RT3070_RF_3320: return "RT3320"; 33364310d6deSBernhard Schmidt case RT3070_RF_3053: return "RT3053"; 3337b0f7be91SKevin Lo case RT5390_RF_5360: return "RT5360"; 33386fc44dabSKevin Lo case RT5390_RF_5390: return "RT5390"; 33394310d6deSBernhard Schmidt default: return "unknown"; 33404310d6deSBernhard Schmidt } 33414310d6deSBernhard Schmidt } 33424310d6deSBernhard Schmidt 33434310d6deSBernhard Schmidt static int 33444310d6deSBernhard Schmidt rt2860_read_eeprom(struct rt2860_softc *sc, uint8_t macaddr[IEEE80211_ADDR_LEN]) 33454310d6deSBernhard Schmidt { 33464310d6deSBernhard Schmidt int8_t delta_2ghz, delta_5ghz; 33474310d6deSBernhard Schmidt uint32_t tmp; 33484310d6deSBernhard Schmidt uint16_t val; 33494310d6deSBernhard Schmidt int ridx, ant, i; 33504310d6deSBernhard Schmidt 33514310d6deSBernhard Schmidt /* check whether the ROM is eFUSE ROM or EEPROM */ 33524310d6deSBernhard Schmidt sc->sc_srom_read = rt2860_eeprom_read_2; 33534310d6deSBernhard Schmidt if (sc->mac_ver >= 0x3071) { 33544310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT3070_EFUSE_CTRL); 33554310d6deSBernhard Schmidt DPRINTF(("EFUSE_CTRL=0x%08x\n", tmp)); 33564310d6deSBernhard Schmidt if (tmp & RT3070_SEL_EFUSE) 33574310d6deSBernhard Schmidt sc->sc_srom_read = rt3090_efuse_read_2; 33584310d6deSBernhard Schmidt } 33594310d6deSBernhard Schmidt 3360b0f7be91SKevin Lo #ifdef RAL_DEBUG 33614310d6deSBernhard Schmidt /* read EEPROM version */ 33624310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_VERSION); 33634bae8310SKevin Lo DPRINTF(("EEPROM rev=%d, FAE=%d\n", val >> 8, val & 0xff)); 3364b0f7be91SKevin Lo #endif 33654310d6deSBernhard Schmidt 33664310d6deSBernhard Schmidt /* read MAC address */ 33674310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_MAC01); 33684310d6deSBernhard Schmidt macaddr[0] = val & 0xff; 33694310d6deSBernhard Schmidt macaddr[1] = val >> 8; 33704310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_MAC23); 33714310d6deSBernhard Schmidt macaddr[2] = val & 0xff; 33724310d6deSBernhard Schmidt macaddr[3] = val >> 8; 33734310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_MAC45); 33744310d6deSBernhard Schmidt macaddr[4] = val & 0xff; 33754310d6deSBernhard Schmidt macaddr[5] = val >> 8; 33764310d6deSBernhard Schmidt 3377b0f7be91SKevin Lo #ifdef RAL_DEBUG 33784310d6deSBernhard Schmidt /* read country code */ 33794310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_COUNTRY); 33804310d6deSBernhard Schmidt DPRINTF(("EEPROM region code=0x%04x\n", val)); 3381b0f7be91SKevin Lo #endif 33824310d6deSBernhard Schmidt 33834310d6deSBernhard Schmidt /* read vendor BBP settings */ 33844310d6deSBernhard Schmidt for (i = 0; i < 8; i++) { 33854310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_BBP_BASE + i); 33864310d6deSBernhard Schmidt sc->bbp[i].val = val & 0xff; 33874310d6deSBernhard Schmidt sc->bbp[i].reg = val >> 8; 33884310d6deSBernhard Schmidt DPRINTF(("BBP%d=0x%02x\n", sc->bbp[i].reg, sc->bbp[i].val)); 33894310d6deSBernhard Schmidt } 33904310d6deSBernhard Schmidt if (sc->mac_ver >= 0x3071) { 33914310d6deSBernhard Schmidt /* read vendor RF settings */ 33924310d6deSBernhard Schmidt for (i = 0; i < 10; i++) { 33934310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT3071_EEPROM_RF_BASE + i); 33944310d6deSBernhard Schmidt sc->rf[i].val = val & 0xff; 33954310d6deSBernhard Schmidt sc->rf[i].reg = val >> 8; 33964310d6deSBernhard Schmidt DPRINTF(("RF%d=0x%02x\n", sc->rf[i].reg, 33974310d6deSBernhard Schmidt sc->rf[i].val)); 33984310d6deSBernhard Schmidt } 33994310d6deSBernhard Schmidt } 34004310d6deSBernhard Schmidt 34014310d6deSBernhard Schmidt /* read RF frequency offset from EEPROM */ 34024310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_FREQ_LEDS); 34034310d6deSBernhard Schmidt sc->freq = ((val & 0xff) != 0xff) ? val & 0xff : 0; 34044310d6deSBernhard Schmidt DPRINTF(("EEPROM freq offset %d\n", sc->freq & 0xff)); 34054310d6deSBernhard Schmidt if ((val >> 8) != 0xff) { 34064310d6deSBernhard Schmidt /* read LEDs operating mode */ 34074310d6deSBernhard Schmidt sc->leds = val >> 8; 34084310d6deSBernhard Schmidt sc->led[0] = rt2860_srom_read(sc, RT2860_EEPROM_LED1); 34094310d6deSBernhard Schmidt sc->led[1] = rt2860_srom_read(sc, RT2860_EEPROM_LED2); 34104310d6deSBernhard Schmidt sc->led[2] = rt2860_srom_read(sc, RT2860_EEPROM_LED3); 34114310d6deSBernhard Schmidt } else { 34124310d6deSBernhard Schmidt /* broken EEPROM, use default settings */ 34134310d6deSBernhard Schmidt sc->leds = 0x01; 34144310d6deSBernhard Schmidt sc->led[0] = 0x5555; 34154310d6deSBernhard Schmidt sc->led[1] = 0x2221; 34164310d6deSBernhard Schmidt sc->led[2] = 0xa9f8; 34174310d6deSBernhard Schmidt } 34184310d6deSBernhard Schmidt DPRINTF(("EEPROM LED mode=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n", 34194310d6deSBernhard Schmidt sc->leds, sc->led[0], sc->led[1], sc->led[2])); 34204310d6deSBernhard Schmidt 34214310d6deSBernhard Schmidt /* read RF information */ 34224310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_ANTENNA); 3423b0f7be91SKevin Lo if (sc->mac_ver >= 0x5390) 3424b0f7be91SKevin Lo sc->rf_rev = rt2860_srom_read(sc, RT2860_EEPROM_CHIPID); 3425b0f7be91SKevin Lo else 34264310d6deSBernhard Schmidt sc->rf_rev = (val >> 8) & 0xf; 34274310d6deSBernhard Schmidt sc->ntxchains = (val >> 4) & 0xf; 34284310d6deSBernhard Schmidt sc->nrxchains = val & 0xf; 34294310d6deSBernhard Schmidt DPRINTF(("EEPROM RF rev=0x%02x chains=%dT%dR\n", 34304310d6deSBernhard Schmidt sc->rf_rev, sc->ntxchains, sc->nrxchains)); 34314310d6deSBernhard Schmidt 34324310d6deSBernhard Schmidt /* check if RF supports automatic Tx access gain control */ 34334310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_CONFIG); 34344310d6deSBernhard Schmidt DPRINTF(("EEPROM CFG 0x%04x\n", val)); 34354310d6deSBernhard Schmidt /* check if driver should patch the DAC issue */ 34364310d6deSBernhard Schmidt if ((val >> 8) != 0xff) 34374310d6deSBernhard Schmidt sc->patch_dac = (val >> 15) & 1; 34384310d6deSBernhard Schmidt if ((val & 0xff) != 0xff) { 34394310d6deSBernhard Schmidt sc->ext_5ghz_lna = (val >> 3) & 1; 34404310d6deSBernhard Schmidt sc->ext_2ghz_lna = (val >> 2) & 1; 34414310d6deSBernhard Schmidt /* check if RF supports automatic Tx access gain control */ 344274b8d63dSPedro F. Giffuni sc->calib_2ghz = sc->calib_5ghz = 0; /* XXX (val >> 1) & 1 */ 34434310d6deSBernhard Schmidt /* check if we have a hardware radio switch */ 34444310d6deSBernhard Schmidt sc->rfswitch = val & 1; 34454310d6deSBernhard Schmidt } 34464310d6deSBernhard Schmidt if (sc->sc_flags & RT2860_ADVANCED_PS) { 34474310d6deSBernhard Schmidt /* read PCIe power save level */ 34484310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_PCIE_PSLEVEL); 34494310d6deSBernhard Schmidt if ((val & 0xff) != 0xff) { 34504310d6deSBernhard Schmidt sc->pslevel = val & 0x3; 34514310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_REV); 34524310d6deSBernhard Schmidt if ((val & 0xff80) != 0x9280) 34534310d6deSBernhard Schmidt sc->pslevel = MIN(sc->pslevel, 1); 34544310d6deSBernhard Schmidt DPRINTF(("EEPROM PCIe PS Level=%d\n", sc->pslevel)); 34554310d6deSBernhard Schmidt } 34564310d6deSBernhard Schmidt } 34574310d6deSBernhard Schmidt 34584310d6deSBernhard Schmidt /* read power settings for 2GHz channels */ 34594310d6deSBernhard Schmidt for (i = 0; i < 14; i += 2) { 34604310d6deSBernhard Schmidt val = rt2860_srom_read(sc, 34614310d6deSBernhard Schmidt RT2860_EEPROM_PWR2GHZ_BASE1 + i / 2); 34624310d6deSBernhard Schmidt sc->txpow1[i + 0] = (int8_t)(val & 0xff); 34634310d6deSBernhard Schmidt sc->txpow1[i + 1] = (int8_t)(val >> 8); 34644310d6deSBernhard Schmidt 34656fc44dabSKevin Lo if (sc->mac_ver != 0x5390) { 34664310d6deSBernhard Schmidt val = rt2860_srom_read(sc, 34674310d6deSBernhard Schmidt RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2); 34684310d6deSBernhard Schmidt sc->txpow2[i + 0] = (int8_t)(val & 0xff); 34694310d6deSBernhard Schmidt sc->txpow2[i + 1] = (int8_t)(val >> 8); 34704310d6deSBernhard Schmidt } 34716fc44dabSKevin Lo } 34724310d6deSBernhard Schmidt /* fix broken Tx power entries */ 34734310d6deSBernhard Schmidt for (i = 0; i < 14; i++) { 34746fc44dabSKevin Lo if (sc->txpow1[i] < 0 || 34756fc44dabSKevin Lo sc->txpow1[i] > ((sc->mac_ver >= 0x5390) ? 39 : 31)) 34764310d6deSBernhard Schmidt sc->txpow1[i] = 5; 34776fc44dabSKevin Lo if (sc->mac_ver != 0x5390) { 34786fc44dabSKevin Lo if (sc->txpow2[i] < 0 || 34796fc44dabSKevin Lo sc->txpow2[i] > ((sc->mac_ver == 0x5392) ? 39 : 31)) 34804310d6deSBernhard Schmidt sc->txpow2[i] = 5; 34816fc44dabSKevin Lo } 34824310d6deSBernhard Schmidt DPRINTF(("chan %d: power1=%d, power2=%d\n", 34834310d6deSBernhard Schmidt rt2860_rf2850[i].chan, sc->txpow1[i], sc->txpow2[i])); 34844310d6deSBernhard Schmidt } 34854310d6deSBernhard Schmidt /* read power settings for 5GHz channels */ 34864310d6deSBernhard Schmidt for (i = 0; i < 40; i += 2) { 34874310d6deSBernhard Schmidt val = rt2860_srom_read(sc, 34884310d6deSBernhard Schmidt RT2860_EEPROM_PWR5GHZ_BASE1 + i / 2); 34894310d6deSBernhard Schmidt sc->txpow1[i + 14] = (int8_t)(val & 0xff); 34904310d6deSBernhard Schmidt sc->txpow1[i + 15] = (int8_t)(val >> 8); 34914310d6deSBernhard Schmidt 34924310d6deSBernhard Schmidt val = rt2860_srom_read(sc, 34934310d6deSBernhard Schmidt RT2860_EEPROM_PWR5GHZ_BASE2 + i / 2); 34944310d6deSBernhard Schmidt sc->txpow2[i + 14] = (int8_t)(val & 0xff); 34954310d6deSBernhard Schmidt sc->txpow2[i + 15] = (int8_t)(val >> 8); 34964310d6deSBernhard Schmidt } 34974310d6deSBernhard Schmidt /* fix broken Tx power entries */ 34984310d6deSBernhard Schmidt for (i = 0; i < 40; i++) { 34994310d6deSBernhard Schmidt if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15) 35004310d6deSBernhard Schmidt sc->txpow1[14 + i] = 5; 35014310d6deSBernhard Schmidt if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15) 35024310d6deSBernhard Schmidt sc->txpow2[14 + i] = 5; 35034310d6deSBernhard Schmidt DPRINTF(("chan %d: power1=%d, power2=%d\n", 35044310d6deSBernhard Schmidt rt2860_rf2850[14 + i].chan, sc->txpow1[14 + i], 35054310d6deSBernhard Schmidt sc->txpow2[14 + i])); 35064310d6deSBernhard Schmidt } 35074310d6deSBernhard Schmidt 35084310d6deSBernhard Schmidt /* read Tx power compensation for each Tx rate */ 35094310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_DELTAPWR); 35104310d6deSBernhard Schmidt delta_2ghz = delta_5ghz = 0; 35114310d6deSBernhard Schmidt if ((val & 0xff) != 0xff && (val & 0x80)) { 35124310d6deSBernhard Schmidt delta_2ghz = val & 0xf; 35134310d6deSBernhard Schmidt if (!(val & 0x40)) /* negative number */ 35144310d6deSBernhard Schmidt delta_2ghz = -delta_2ghz; 35154310d6deSBernhard Schmidt } 35164310d6deSBernhard Schmidt val >>= 8; 35174310d6deSBernhard Schmidt if ((val & 0xff) != 0xff && (val & 0x80)) { 35184310d6deSBernhard Schmidt delta_5ghz = val & 0xf; 35194310d6deSBernhard Schmidt if (!(val & 0x40)) /* negative number */ 35204310d6deSBernhard Schmidt delta_5ghz = -delta_5ghz; 35214310d6deSBernhard Schmidt } 35224310d6deSBernhard Schmidt DPRINTF(("power compensation=%d (2GHz), %d (5GHz)\n", 35234310d6deSBernhard Schmidt delta_2ghz, delta_5ghz)); 35244310d6deSBernhard Schmidt 35254310d6deSBernhard Schmidt for (ridx = 0; ridx < 5; ridx++) { 35264310d6deSBernhard Schmidt uint32_t reg; 35274310d6deSBernhard Schmidt 35284310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2); 35294310d6deSBernhard Schmidt reg = val; 35304310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2 + 1); 35314310d6deSBernhard Schmidt reg |= (uint32_t)val << 16; 35324310d6deSBernhard Schmidt 35334310d6deSBernhard Schmidt sc->txpow20mhz[ridx] = reg; 35344310d6deSBernhard Schmidt sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz); 35354310d6deSBernhard Schmidt sc->txpow40mhz_5ghz[ridx] = b4inc(reg, delta_5ghz); 35364310d6deSBernhard Schmidt 35374310d6deSBernhard Schmidt DPRINTF(("ridx %d: power 20MHz=0x%08x, 40MHz/2GHz=0x%08x, " 35384310d6deSBernhard Schmidt "40MHz/5GHz=0x%08x\n", ridx, sc->txpow20mhz[ridx], 35394310d6deSBernhard Schmidt sc->txpow40mhz_2ghz[ridx], sc->txpow40mhz_5ghz[ridx])); 35404310d6deSBernhard Schmidt } 35414310d6deSBernhard Schmidt 35424310d6deSBernhard Schmidt /* read factory-calibrated samples for temperature compensation */ 35434310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_TSSI1_2GHZ); 35444310d6deSBernhard Schmidt sc->tssi_2ghz[0] = val & 0xff; /* [-4] */ 35454310d6deSBernhard Schmidt sc->tssi_2ghz[1] = val >> 8; /* [-3] */ 35464310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_TSSI2_2GHZ); 35474310d6deSBernhard Schmidt sc->tssi_2ghz[2] = val & 0xff; /* [-2] */ 35484310d6deSBernhard Schmidt sc->tssi_2ghz[3] = val >> 8; /* [-1] */ 35494310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_TSSI3_2GHZ); 35504310d6deSBernhard Schmidt sc->tssi_2ghz[4] = val & 0xff; /* [+0] */ 35514310d6deSBernhard Schmidt sc->tssi_2ghz[5] = val >> 8; /* [+1] */ 35524310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_TSSI4_2GHZ); 35534310d6deSBernhard Schmidt sc->tssi_2ghz[6] = val & 0xff; /* [+2] */ 35544310d6deSBernhard Schmidt sc->tssi_2ghz[7] = val >> 8; /* [+3] */ 35554310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_TSSI5_2GHZ); 35564310d6deSBernhard Schmidt sc->tssi_2ghz[8] = val & 0xff; /* [+4] */ 35574310d6deSBernhard Schmidt sc->step_2ghz = val >> 8; 35584310d6deSBernhard Schmidt DPRINTF(("TSSI 2GHz: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x " 35594310d6deSBernhard Schmidt "0x%02x 0x%02x step=%d\n", sc->tssi_2ghz[0], sc->tssi_2ghz[1], 35604310d6deSBernhard Schmidt sc->tssi_2ghz[2], sc->tssi_2ghz[3], sc->tssi_2ghz[4], 35614310d6deSBernhard Schmidt sc->tssi_2ghz[5], sc->tssi_2ghz[6], sc->tssi_2ghz[7], 35624310d6deSBernhard Schmidt sc->tssi_2ghz[8], sc->step_2ghz)); 35634310d6deSBernhard Schmidt /* check that ref value is correct, otherwise disable calibration */ 35644310d6deSBernhard Schmidt if (sc->tssi_2ghz[4] == 0xff) 35654310d6deSBernhard Schmidt sc->calib_2ghz = 0; 35664310d6deSBernhard Schmidt 35674310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_TSSI1_5GHZ); 35684310d6deSBernhard Schmidt sc->tssi_5ghz[0] = val & 0xff; /* [-4] */ 35694310d6deSBernhard Schmidt sc->tssi_5ghz[1] = val >> 8; /* [-3] */ 35704310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_TSSI2_5GHZ); 35714310d6deSBernhard Schmidt sc->tssi_5ghz[2] = val & 0xff; /* [-2] */ 35724310d6deSBernhard Schmidt sc->tssi_5ghz[3] = val >> 8; /* [-1] */ 35734310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_TSSI3_5GHZ); 35744310d6deSBernhard Schmidt sc->tssi_5ghz[4] = val & 0xff; /* [+0] */ 35754310d6deSBernhard Schmidt sc->tssi_5ghz[5] = val >> 8; /* [+1] */ 35764310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_TSSI4_5GHZ); 35774310d6deSBernhard Schmidt sc->tssi_5ghz[6] = val & 0xff; /* [+2] */ 35784310d6deSBernhard Schmidt sc->tssi_5ghz[7] = val >> 8; /* [+3] */ 35794310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_TSSI5_5GHZ); 35804310d6deSBernhard Schmidt sc->tssi_5ghz[8] = val & 0xff; /* [+4] */ 35814310d6deSBernhard Schmidt sc->step_5ghz = val >> 8; 35824310d6deSBernhard Schmidt DPRINTF(("TSSI 5GHz: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x " 35834310d6deSBernhard Schmidt "0x%02x 0x%02x step=%d\n", sc->tssi_5ghz[0], sc->tssi_5ghz[1], 35844310d6deSBernhard Schmidt sc->tssi_5ghz[2], sc->tssi_5ghz[3], sc->tssi_5ghz[4], 35854310d6deSBernhard Schmidt sc->tssi_5ghz[5], sc->tssi_5ghz[6], sc->tssi_5ghz[7], 35864310d6deSBernhard Schmidt sc->tssi_5ghz[8], sc->step_5ghz)); 35874310d6deSBernhard Schmidt /* check that ref value is correct, otherwise disable calibration */ 35884310d6deSBernhard Schmidt if (sc->tssi_5ghz[4] == 0xff) 35894310d6deSBernhard Schmidt sc->calib_5ghz = 0; 35904310d6deSBernhard Schmidt 35914310d6deSBernhard Schmidt /* read RSSI offsets and LNA gains from EEPROM */ 35924310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_RSSI1_2GHZ); 35934310d6deSBernhard Schmidt sc->rssi_2ghz[0] = val & 0xff; /* Ant A */ 35944310d6deSBernhard Schmidt sc->rssi_2ghz[1] = val >> 8; /* Ant B */ 35954310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_RSSI2_2GHZ); 35964310d6deSBernhard Schmidt if (sc->mac_ver >= 0x3071) { 35974310d6deSBernhard Schmidt /* 35984310d6deSBernhard Schmidt * On RT3090 chips (limited to 2 Rx chains), this ROM 35994310d6deSBernhard Schmidt * field contains the Tx mixer gain for the 2GHz band. 36004310d6deSBernhard Schmidt */ 36014310d6deSBernhard Schmidt if ((val & 0xff) != 0xff) 36024310d6deSBernhard Schmidt sc->txmixgain_2ghz = val & 0x7; 36034310d6deSBernhard Schmidt DPRINTF(("tx mixer gain=%u (2GHz)\n", sc->txmixgain_2ghz)); 36044310d6deSBernhard Schmidt } else 36054310d6deSBernhard Schmidt sc->rssi_2ghz[2] = val & 0xff; /* Ant C */ 36064310d6deSBernhard Schmidt sc->lna[2] = val >> 8; /* channel group 2 */ 36074310d6deSBernhard Schmidt 36084310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_RSSI1_5GHZ); 36094310d6deSBernhard Schmidt sc->rssi_5ghz[0] = val & 0xff; /* Ant A */ 36104310d6deSBernhard Schmidt sc->rssi_5ghz[1] = val >> 8; /* Ant B */ 36114310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_RSSI2_5GHZ); 36124310d6deSBernhard Schmidt sc->rssi_5ghz[2] = val & 0xff; /* Ant C */ 36134310d6deSBernhard Schmidt sc->lna[3] = val >> 8; /* channel group 3 */ 36144310d6deSBernhard Schmidt 36154310d6deSBernhard Schmidt val = rt2860_srom_read(sc, RT2860_EEPROM_LNA); 36164310d6deSBernhard Schmidt if (sc->mac_ver >= 0x3071) 36174310d6deSBernhard Schmidt sc->lna[0] = RT3090_DEF_LNA; 36184310d6deSBernhard Schmidt else /* channel group 0 */ 36194310d6deSBernhard Schmidt sc->lna[0] = val & 0xff; 36204310d6deSBernhard Schmidt sc->lna[1] = val >> 8; /* channel group 1 */ 36214310d6deSBernhard Schmidt 36224310d6deSBernhard Schmidt /* fix broken 5GHz LNA entries */ 36234310d6deSBernhard Schmidt if (sc->lna[2] == 0 || sc->lna[2] == 0xff) { 36244310d6deSBernhard Schmidt DPRINTF(("invalid LNA for channel group %d\n", 2)); 36254310d6deSBernhard Schmidt sc->lna[2] = sc->lna[1]; 36264310d6deSBernhard Schmidt } 36274310d6deSBernhard Schmidt if (sc->lna[3] == 0 || sc->lna[3] == 0xff) { 36284310d6deSBernhard Schmidt DPRINTF(("invalid LNA for channel group %d\n", 3)); 36294310d6deSBernhard Schmidt sc->lna[3] = sc->lna[1]; 36304310d6deSBernhard Schmidt } 36314310d6deSBernhard Schmidt 36324310d6deSBernhard Schmidt /* fix broken RSSI offset entries */ 36334310d6deSBernhard Schmidt for (ant = 0; ant < 3; ant++) { 36344310d6deSBernhard Schmidt if (sc->rssi_2ghz[ant] < -10 || sc->rssi_2ghz[ant] > 10) { 36354310d6deSBernhard Schmidt DPRINTF(("invalid RSSI%d offset: %d (2GHz)\n", 36364310d6deSBernhard Schmidt ant + 1, sc->rssi_2ghz[ant])); 36374310d6deSBernhard Schmidt sc->rssi_2ghz[ant] = 0; 36384310d6deSBernhard Schmidt } 36394310d6deSBernhard Schmidt if (sc->rssi_5ghz[ant] < -10 || sc->rssi_5ghz[ant] > 10) { 36404310d6deSBernhard Schmidt DPRINTF(("invalid RSSI%d offset: %d (5GHz)\n", 36414310d6deSBernhard Schmidt ant + 1, sc->rssi_5ghz[ant])); 36424310d6deSBernhard Schmidt sc->rssi_5ghz[ant] = 0; 36434310d6deSBernhard Schmidt } 36444310d6deSBernhard Schmidt } 36454310d6deSBernhard Schmidt 36464310d6deSBernhard Schmidt return 0; 36474310d6deSBernhard Schmidt } 36484310d6deSBernhard Schmidt 36496fc44dabSKevin Lo static int 36504310d6deSBernhard Schmidt rt2860_bbp_init(struct rt2860_softc *sc) 36514310d6deSBernhard Schmidt { 36524310d6deSBernhard Schmidt int i, ntries; 36534310d6deSBernhard Schmidt 36544310d6deSBernhard Schmidt /* wait for BBP to wake up */ 36554310d6deSBernhard Schmidt for (ntries = 0; ntries < 20; ntries++) { 36564310d6deSBernhard Schmidt uint8_t bbp0 = rt2860_mcu_bbp_read(sc, 0); 36574310d6deSBernhard Schmidt if (bbp0 != 0 && bbp0 != 0xff) 36584310d6deSBernhard Schmidt break; 36594310d6deSBernhard Schmidt } 36604310d6deSBernhard Schmidt if (ntries == 20) { 36614310d6deSBernhard Schmidt device_printf(sc->sc_dev, 36624310d6deSBernhard Schmidt "timeout waiting for BBP to wake up\n"); 36636fc44dabSKevin Lo return (ETIMEDOUT); 36644310d6deSBernhard Schmidt } 36654310d6deSBernhard Schmidt 36664310d6deSBernhard Schmidt /* initialize BBP registers to default values */ 36676fc44dabSKevin Lo if (sc->mac_ver >= 0x5390) 36686fc44dabSKevin Lo rt5390_bbp_init(sc); 36696fc44dabSKevin Lo else { 36706fc44dabSKevin Lo for (i = 0; i < nitems(rt2860_def_bbp); i++) { 36714310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, rt2860_def_bbp[i].reg, 36724310d6deSBernhard Schmidt rt2860_def_bbp[i].val); 36734310d6deSBernhard Schmidt } 36746fc44dabSKevin Lo } 36754310d6deSBernhard Schmidt 36764310d6deSBernhard Schmidt /* fix BBP84 for RT2860E */ 36774310d6deSBernhard Schmidt if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0101) 36784310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 84, 0x19); 36794310d6deSBernhard Schmidt 36804310d6deSBernhard Schmidt if (sc->mac_ver >= 0x3071) { 36814310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 79, 0x13); 36824310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 80, 0x05); 36834310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 81, 0x33); 36844310d6deSBernhard Schmidt } else if (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) { 36854310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 69, 0x16); 36864310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 73, 0x12); 36874310d6deSBernhard Schmidt } 36884310d6deSBernhard Schmidt 36894310d6deSBernhard Schmidt return 0; 36906fc44dabSKevin Lo } 36916fc44dabSKevin Lo 36926fc44dabSKevin Lo static void 36936fc44dabSKevin Lo rt5390_bbp_init(struct rt2860_softc *sc) 36946fc44dabSKevin Lo { 36956fc44dabSKevin Lo uint8_t bbp; 36966fc44dabSKevin Lo int i; 36976fc44dabSKevin Lo 36986fc44dabSKevin Lo /* Apply maximum likelihood detection for 2 stream case. */ 36996fc44dabSKevin Lo if (sc->nrxchains > 1) { 37006fc44dabSKevin Lo bbp = rt2860_mcu_bbp_read(sc, 105); 37016fc44dabSKevin Lo rt2860_mcu_bbp_write(sc, 105, bbp | RT5390_MLD); 37026fc44dabSKevin Lo } 37036fc44dabSKevin Lo 37046fc44dabSKevin Lo /* Avoid data lost and CRC error. */ 37056fc44dabSKevin Lo bbp = rt2860_mcu_bbp_read(sc, 4); 37066fc44dabSKevin Lo rt2860_mcu_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL); 37076fc44dabSKevin Lo 37086fc44dabSKevin Lo for (i = 0; i < nitems(rt5390_def_bbp); i++) { 37096fc44dabSKevin Lo rt2860_mcu_bbp_write(sc, rt5390_def_bbp[i].reg, 37106fc44dabSKevin Lo rt5390_def_bbp[i].val); 37116fc44dabSKevin Lo } 37126fc44dabSKevin Lo 37136fc44dabSKevin Lo if (sc->mac_ver == 0x5392) { 37146fc44dabSKevin Lo rt2860_mcu_bbp_write(sc, 84, 0x9a); 37156fc44dabSKevin Lo rt2860_mcu_bbp_write(sc, 95, 0x9a); 37166fc44dabSKevin Lo rt2860_mcu_bbp_write(sc, 98, 0x12); 37176fc44dabSKevin Lo rt2860_mcu_bbp_write(sc, 106, 0x05); 37186fc44dabSKevin Lo rt2860_mcu_bbp_write(sc, 134, 0xd0); 37196fc44dabSKevin Lo rt2860_mcu_bbp_write(sc, 135, 0xf6); 37206fc44dabSKevin Lo } 37216fc44dabSKevin Lo 37226fc44dabSKevin Lo bbp = rt2860_mcu_bbp_read(sc, 152); 37236fc44dabSKevin Lo rt2860_mcu_bbp_write(sc, 152, bbp | 0x80); 37246fc44dabSKevin Lo 37256fc44dabSKevin Lo /* Disable hardware antenna diversity. */ 37266fc44dabSKevin Lo if (sc->mac_ver == 0x5390) 37276fc44dabSKevin Lo rt2860_mcu_bbp_write(sc, 154, 0); 37284310d6deSBernhard Schmidt } 37294310d6deSBernhard Schmidt 37304310d6deSBernhard Schmidt static int 37314310d6deSBernhard Schmidt rt2860_txrx_enable(struct rt2860_softc *sc) 37324310d6deSBernhard Schmidt { 37337a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 37344310d6deSBernhard Schmidt uint32_t tmp; 37354310d6deSBernhard Schmidt int ntries; 37364310d6deSBernhard Schmidt 37374310d6deSBernhard Schmidt /* enable Tx/Rx DMA engine */ 37384310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_TX_EN); 37394310d6deSBernhard Schmidt RAL_BARRIER_READ_WRITE(sc); 37404310d6deSBernhard Schmidt for (ntries = 0; ntries < 200; ntries++) { 37414310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_WPDMA_GLO_CFG); 37424310d6deSBernhard Schmidt if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 37434310d6deSBernhard Schmidt break; 37444310d6deSBernhard Schmidt DELAY(1000); 37454310d6deSBernhard Schmidt } 37464310d6deSBernhard Schmidt if (ntries == 200) { 37474310d6deSBernhard Schmidt device_printf(sc->sc_dev, "timeout waiting for DMA engine\n"); 37484310d6deSBernhard Schmidt return ETIMEDOUT; 37494310d6deSBernhard Schmidt } 37504310d6deSBernhard Schmidt 37514310d6deSBernhard Schmidt DELAY(50); 37524310d6deSBernhard Schmidt 37534310d6deSBernhard Schmidt tmp |= RT2860_RX_DMA_EN | RT2860_TX_DMA_EN | 37544310d6deSBernhard Schmidt RT2860_WPDMA_BT_SIZE64 << RT2860_WPDMA_BT_SIZE_SHIFT; 37554310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_WPDMA_GLO_CFG, tmp); 37564310d6deSBernhard Schmidt 37574310d6deSBernhard Schmidt /* set Rx filter */ 37584310d6deSBernhard Schmidt tmp = RT2860_DROP_CRC_ERR | RT2860_DROP_PHY_ERR; 37594310d6deSBernhard Schmidt if (ic->ic_opmode != IEEE80211_M_MONITOR) { 37604310d6deSBernhard Schmidt tmp |= RT2860_DROP_UC_NOME | RT2860_DROP_DUPL | 37614310d6deSBernhard Schmidt RT2860_DROP_CTS | RT2860_DROP_BA | RT2860_DROP_ACK | 37624310d6deSBernhard Schmidt RT2860_DROP_VER_ERR | RT2860_DROP_CTRL_RSV | 37634310d6deSBernhard Schmidt RT2860_DROP_CFACK | RT2860_DROP_CFEND; 37644310d6deSBernhard Schmidt if (ic->ic_opmode == IEEE80211_M_STA) 37654310d6deSBernhard Schmidt tmp |= RT2860_DROP_RTS | RT2860_DROP_PSPOLL; 37664310d6deSBernhard Schmidt } 37674310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_RX_FILTR_CFG, tmp); 37684310d6deSBernhard Schmidt 37694310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_MAC_SYS_CTRL, 37704310d6deSBernhard Schmidt RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 37714310d6deSBernhard Schmidt 37724310d6deSBernhard Schmidt return 0; 37734310d6deSBernhard Schmidt } 37744310d6deSBernhard Schmidt 37754310d6deSBernhard Schmidt static void 37764310d6deSBernhard Schmidt rt2860_init(void *arg) 37774310d6deSBernhard Schmidt { 37784310d6deSBernhard Schmidt struct rt2860_softc *sc = arg; 37797a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 37804310d6deSBernhard Schmidt 37814310d6deSBernhard Schmidt RAL_LOCK(sc); 37824310d6deSBernhard Schmidt rt2860_init_locked(sc); 37834310d6deSBernhard Schmidt RAL_UNLOCK(sc); 37844310d6deSBernhard Schmidt 37851c1cd920SKevin Lo if (sc->sc_flags & RT2860_RUNNING) 37864310d6deSBernhard Schmidt ieee80211_start_all(ic); 37874310d6deSBernhard Schmidt } 37884310d6deSBernhard Schmidt 37894310d6deSBernhard Schmidt static void 37904310d6deSBernhard Schmidt rt2860_init_locked(struct rt2860_softc *sc) 37914310d6deSBernhard Schmidt { 37927a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 37937a79cebfSGleb Smirnoff struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 37944310d6deSBernhard Schmidt uint32_t tmp; 37954310d6deSBernhard Schmidt uint8_t bbp1, bbp3; 37964310d6deSBernhard Schmidt int i, qid, ridx, ntries, error; 37974310d6deSBernhard Schmidt 37984310d6deSBernhard Schmidt RAL_LOCK_ASSERT(sc); 37994310d6deSBernhard Schmidt 38004310d6deSBernhard Schmidt if (sc->rfswitch) { 38014310d6deSBernhard Schmidt /* hardware has a radio switch on GPIO pin 2 */ 38024310d6deSBernhard Schmidt if (!(RAL_READ(sc, RT2860_GPIO_CTRL) & (1 << 2))) { 38034310d6deSBernhard Schmidt device_printf(sc->sc_dev, 38044310d6deSBernhard Schmidt "radio is disabled by hardware switch\n"); 38054310d6deSBernhard Schmidt #ifdef notyet 38064310d6deSBernhard Schmidt rt2860_stop_locked(sc); 38074310d6deSBernhard Schmidt return; 38084310d6deSBernhard Schmidt #endif 38094310d6deSBernhard Schmidt } 38104310d6deSBernhard Schmidt } 38114310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_PWR_PIN_CFG, RT2860_IO_RA_PE); 38124310d6deSBernhard Schmidt 38134310d6deSBernhard Schmidt /* disable DMA */ 38144310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_WPDMA_GLO_CFG); 38155c95ab02SKevin Lo tmp &= ~(RT2860_RX_DMA_BUSY | RT2860_RX_DMA_EN | RT2860_TX_DMA_BUSY | 38165c95ab02SKevin Lo RT2860_TX_DMA_EN); 38175c95ab02SKevin Lo tmp |= RT2860_TX_WB_DDONE; 38184310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_WPDMA_GLO_CFG, tmp); 38194310d6deSBernhard Schmidt 38205c95ab02SKevin Lo /* reset DMA indexes */ 38215c95ab02SKevin Lo RAL_WRITE(sc, RT2860_WPDMA_RST_IDX, RT2860_RST_DRX_IDX0 | 38225c95ab02SKevin Lo RT2860_RST_DTX_IDX5 | RT2860_RST_DTX_IDX4 | RT2860_RST_DTX_IDX3 | 38235c95ab02SKevin Lo RT2860_RST_DTX_IDX2 | RT2860_RST_DTX_IDX1 | RT2860_RST_DTX_IDX0); 38245c95ab02SKevin Lo 38254310d6deSBernhard Schmidt /* PBF hardware reset */ 38264310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_SYS_CTRL, 0xe1f); 38274310d6deSBernhard Schmidt RAL_BARRIER_WRITE(sc); 38284310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_SYS_CTRL, 0xe00); 38294310d6deSBernhard Schmidt 38304310d6deSBernhard Schmidt if ((error = rt2860_load_microcode(sc)) != 0) { 38314310d6deSBernhard Schmidt device_printf(sc->sc_dev, "could not load 8051 microcode\n"); 38324310d6deSBernhard Schmidt rt2860_stop_locked(sc); 38334310d6deSBernhard Schmidt return; 38344310d6deSBernhard Schmidt } 38354310d6deSBernhard Schmidt 38367a79cebfSGleb Smirnoff rt2860_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr); 38374310d6deSBernhard Schmidt 38384310d6deSBernhard Schmidt /* init Tx power for all Tx rates (from EEPROM) */ 38394310d6deSBernhard Schmidt for (ridx = 0; ridx < 5; ridx++) { 38404310d6deSBernhard Schmidt if (sc->txpow20mhz[ridx] == 0xffffffff) 38414310d6deSBernhard Schmidt continue; 38424310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]); 38434310d6deSBernhard Schmidt } 38444310d6deSBernhard Schmidt 38454310d6deSBernhard Schmidt for (ntries = 0; ntries < 100; ntries++) { 38464310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_WPDMA_GLO_CFG); 38474310d6deSBernhard Schmidt if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 38484310d6deSBernhard Schmidt break; 38494310d6deSBernhard Schmidt DELAY(1000); 38504310d6deSBernhard Schmidt } 38514310d6deSBernhard Schmidt if (ntries == 100) { 38524310d6deSBernhard Schmidt device_printf(sc->sc_dev, "timeout waiting for DMA engine\n"); 38534310d6deSBernhard Schmidt rt2860_stop_locked(sc); 38544310d6deSBernhard Schmidt return; 38554310d6deSBernhard Schmidt } 38565c95ab02SKevin Lo tmp &= ~(RT2860_RX_DMA_BUSY | RT2860_RX_DMA_EN | RT2860_TX_DMA_BUSY | 38575c95ab02SKevin Lo RT2860_TX_DMA_EN); 38585c95ab02SKevin Lo tmp |= RT2860_TX_WB_DDONE; 38594310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_WPDMA_GLO_CFG, tmp); 38604310d6deSBernhard Schmidt 38614310d6deSBernhard Schmidt /* reset Rx ring and all 6 Tx rings */ 38624310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_WPDMA_RST_IDX, 0x1003f); 38634310d6deSBernhard Schmidt 38644310d6deSBernhard Schmidt /* PBF hardware reset */ 38654310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_SYS_CTRL, 0xe1f); 38664310d6deSBernhard Schmidt RAL_BARRIER_WRITE(sc); 38674310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_SYS_CTRL, 0xe00); 38684310d6deSBernhard Schmidt 38694310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_PWR_PIN_CFG, RT2860_IO_RA_PE | RT2860_IO_RF_PE); 38704310d6deSBernhard Schmidt 38714310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST); 38724310d6deSBernhard Schmidt RAL_BARRIER_WRITE(sc); 38734310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_MAC_SYS_CTRL, 0); 38744310d6deSBernhard Schmidt 38756fc44dabSKevin Lo for (i = 0; i < nitems(rt2860_def_mac); i++) 38764310d6deSBernhard Schmidt RAL_WRITE(sc, rt2860_def_mac[i].reg, rt2860_def_mac[i].val); 38776fc44dabSKevin Lo if (sc->mac_ver >= 0x5390) 38786fc44dabSKevin Lo RAL_WRITE(sc, RT2860_TX_SW_CFG0, 0x00000404); 38796fc44dabSKevin Lo else if (sc->mac_ver >= 0x3071) { 38804310d6deSBernhard Schmidt /* set delay of PA_PE assertion to 1us (unit of 0.25us) */ 38814310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_TX_SW_CFG0, 38824310d6deSBernhard Schmidt 4 << RT2860_DLY_PAPE_EN_SHIFT); 38834310d6deSBernhard Schmidt } 38844310d6deSBernhard Schmidt 38854310d6deSBernhard Schmidt if (!(RAL_READ(sc, RT2860_PCI_CFG) & RT2860_PCI_CFG_PCI)) { 38864310d6deSBernhard Schmidt sc->sc_flags |= RT2860_PCIE; 38874310d6deSBernhard Schmidt /* PCIe has different clock cycle count than PCI */ 38884310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_US_CYC_CNT); 38894310d6deSBernhard Schmidt tmp = (tmp & ~0xff) | 0x7d; 38904310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_US_CYC_CNT, tmp); 38914310d6deSBernhard Schmidt } 38924310d6deSBernhard Schmidt 38934310d6deSBernhard Schmidt /* wait while MAC is busy */ 38944310d6deSBernhard Schmidt for (ntries = 0; ntries < 100; ntries++) { 38954310d6deSBernhard Schmidt if (!(RAL_READ(sc, RT2860_MAC_STATUS_REG) & 38964310d6deSBernhard Schmidt (RT2860_RX_STATUS_BUSY | RT2860_TX_STATUS_BUSY))) 38974310d6deSBernhard Schmidt break; 38984310d6deSBernhard Schmidt DELAY(1000); 38994310d6deSBernhard Schmidt } 39004310d6deSBernhard Schmidt if (ntries == 100) { 39014310d6deSBernhard Schmidt device_printf(sc->sc_dev, "timeout waiting for MAC\n"); 39024310d6deSBernhard Schmidt rt2860_stop_locked(sc); 39034310d6deSBernhard Schmidt return; 39044310d6deSBernhard Schmidt } 39054310d6deSBernhard Schmidt 39064310d6deSBernhard Schmidt /* clear Host to MCU mailbox */ 39074310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_H2M_BBPAGENT, 0); 39084310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_H2M_MAILBOX, 0); 39094310d6deSBernhard Schmidt 39104310d6deSBernhard Schmidt rt2860_mcu_cmd(sc, RT2860_MCU_CMD_RFRESET, 0, 0); 39114310d6deSBernhard Schmidt DELAY(1000); 39124310d6deSBernhard Schmidt 39134310d6deSBernhard Schmidt if ((error = rt2860_bbp_init(sc)) != 0) { 39144310d6deSBernhard Schmidt rt2860_stop_locked(sc); 39154310d6deSBernhard Schmidt return; 39164310d6deSBernhard Schmidt } 39174310d6deSBernhard Schmidt 39184310d6deSBernhard Schmidt /* clear RX WCID search table */ 39194310d6deSBernhard Schmidt RAL_SET_REGION_4(sc, RT2860_WCID_ENTRY(0), 0, 512); 39204310d6deSBernhard Schmidt /* clear pairwise key table */ 39214310d6deSBernhard Schmidt RAL_SET_REGION_4(sc, RT2860_PKEY(0), 0, 2048); 39224310d6deSBernhard Schmidt /* clear IV/EIV table */ 39234310d6deSBernhard Schmidt RAL_SET_REGION_4(sc, RT2860_IVEIV(0), 0, 512); 39244310d6deSBernhard Schmidt /* clear WCID attribute table */ 39254310d6deSBernhard Schmidt RAL_SET_REGION_4(sc, RT2860_WCID_ATTR(0), 0, 256); 39264310d6deSBernhard Schmidt /* clear shared key table */ 39274310d6deSBernhard Schmidt RAL_SET_REGION_4(sc, RT2860_SKEY(0, 0), 0, 8 * 32); 39284310d6deSBernhard Schmidt /* clear shared key mode */ 39294310d6deSBernhard Schmidt RAL_SET_REGION_4(sc, RT2860_SKEY_MODE_0_7, 0, 4); 39304310d6deSBernhard Schmidt 39314310d6deSBernhard Schmidt /* init Tx rings (4 EDCAs + HCCA + Mgt) */ 39324310d6deSBernhard Schmidt for (qid = 0; qid < 6; qid++) { 39334310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_TX_BASE_PTR(qid), sc->txq[qid].paddr); 39344310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_TX_MAX_CNT(qid), RT2860_TX_RING_COUNT); 39354310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_TX_CTX_IDX(qid), 0); 39364310d6deSBernhard Schmidt } 39374310d6deSBernhard Schmidt 39384310d6deSBernhard Schmidt /* init Rx ring */ 39394310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_RX_BASE_PTR, sc->rxq.paddr); 39404310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_RX_MAX_CNT, RT2860_RX_RING_COUNT); 39414310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_RX_CALC_IDX, RT2860_RX_RING_COUNT - 1); 39424310d6deSBernhard Schmidt 39434310d6deSBernhard Schmidt /* setup maximum buffer sizes */ 39444310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_MAX_LEN_CFG, 1 << 12 | 39454310d6deSBernhard Schmidt (MCLBYTES - sizeof (struct rt2860_rxwi) - 2)); 39464310d6deSBernhard Schmidt 39474310d6deSBernhard Schmidt for (ntries = 0; ntries < 100; ntries++) { 39484310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_WPDMA_GLO_CFG); 39494310d6deSBernhard Schmidt if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0) 39504310d6deSBernhard Schmidt break; 39514310d6deSBernhard Schmidt DELAY(1000); 39524310d6deSBernhard Schmidt } 39534310d6deSBernhard Schmidt if (ntries == 100) { 39544310d6deSBernhard Schmidt device_printf(sc->sc_dev, "timeout waiting for DMA engine\n"); 39554310d6deSBernhard Schmidt rt2860_stop_locked(sc); 39564310d6deSBernhard Schmidt return; 39574310d6deSBernhard Schmidt } 39585c95ab02SKevin Lo tmp &= ~(RT2860_RX_DMA_BUSY | RT2860_RX_DMA_EN | RT2860_TX_DMA_BUSY | 39595c95ab02SKevin Lo RT2860_TX_DMA_EN); 39605c95ab02SKevin Lo tmp |= RT2860_TX_WB_DDONE; 39614310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_WPDMA_GLO_CFG, tmp); 39624310d6deSBernhard Schmidt 39634310d6deSBernhard Schmidt /* disable interrupts mitigation */ 39644310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_DELAY_INT_CFG, 0); 39654310d6deSBernhard Schmidt 39664310d6deSBernhard Schmidt /* write vendor-specific BBP values (from EEPROM) */ 39674310d6deSBernhard Schmidt for (i = 0; i < 8; i++) { 39684310d6deSBernhard Schmidt if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff) 39694310d6deSBernhard Schmidt continue; 39704310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val); 39714310d6deSBernhard Schmidt } 39724310d6deSBernhard Schmidt 39734310d6deSBernhard Schmidt /* select Main antenna for 1T1R devices */ 39744310d6deSBernhard Schmidt if (sc->rf_rev == RT3070_RF_2020 || 39754310d6deSBernhard Schmidt sc->rf_rev == RT3070_RF_3020 || 39766fc44dabSKevin Lo sc->rf_rev == RT3070_RF_3320 || 39776fc44dabSKevin Lo sc->mac_ver == 0x5390) 39784310d6deSBernhard Schmidt rt3090_set_rx_antenna(sc, 0); 39794310d6deSBernhard Schmidt 39804310d6deSBernhard Schmidt /* send LEDs operating mode to microcontroller */ 39814310d6deSBernhard Schmidt rt2860_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0], 0); 39824310d6deSBernhard Schmidt rt2860_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1], 0); 39834310d6deSBernhard Schmidt rt2860_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2], 0); 39844310d6deSBernhard Schmidt 39856fc44dabSKevin Lo if (sc->mac_ver >= 0x5390) 39866fc44dabSKevin Lo rt5390_rf_init(sc); 39876fc44dabSKevin Lo else if (sc->mac_ver >= 0x3071) { 39886fc44dabSKevin Lo if ((error = rt3090_rf_init(sc)) != 0) { 39896fc44dabSKevin Lo rt2860_stop_locked(sc); 39906fc44dabSKevin Lo return; 39916fc44dabSKevin Lo } 39926fc44dabSKevin Lo } 39934310d6deSBernhard Schmidt 39944310d6deSBernhard Schmidt rt2860_mcu_cmd(sc, RT2860_MCU_CMD_SLEEP, 0x02ff, 1); 39954310d6deSBernhard Schmidt rt2860_mcu_cmd(sc, RT2860_MCU_CMD_WAKEUP, 0, 1); 39964310d6deSBernhard Schmidt 39976fc44dabSKevin Lo if (sc->mac_ver >= 0x5390) 39986fc44dabSKevin Lo rt5390_rf_wakeup(sc); 39996fc44dabSKevin Lo else if (sc->mac_ver >= 0x3071) 40004310d6deSBernhard Schmidt rt3090_rf_wakeup(sc); 40014310d6deSBernhard Schmidt 40024310d6deSBernhard Schmidt /* disable non-existing Rx chains */ 40034310d6deSBernhard Schmidt bbp3 = rt2860_mcu_bbp_read(sc, 3); 40044310d6deSBernhard Schmidt bbp3 &= ~(1 << 3 | 1 << 4); 40054310d6deSBernhard Schmidt if (sc->nrxchains == 2) 40064310d6deSBernhard Schmidt bbp3 |= 1 << 3; 40074310d6deSBernhard Schmidt else if (sc->nrxchains == 3) 40084310d6deSBernhard Schmidt bbp3 |= 1 << 4; 40094310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 3, bbp3); 40104310d6deSBernhard Schmidt 40114310d6deSBernhard Schmidt /* disable non-existing Tx chains */ 40124310d6deSBernhard Schmidt bbp1 = rt2860_mcu_bbp_read(sc, 1); 40134310d6deSBernhard Schmidt if (sc->ntxchains == 1) 40144310d6deSBernhard Schmidt bbp1 = (bbp1 & ~(1 << 3 | 1 << 4)); 40154310d6deSBernhard Schmidt else if (sc->mac_ver == 0x3593 && sc->ntxchains == 2) 40164310d6deSBernhard Schmidt bbp1 = (bbp1 & ~(1 << 4)) | 1 << 3; 40174310d6deSBernhard Schmidt else if (sc->mac_ver == 0x3593 && sc->ntxchains == 3) 40184310d6deSBernhard Schmidt bbp1 = (bbp1 & ~(1 << 3)) | 1 << 4; 40194310d6deSBernhard Schmidt rt2860_mcu_bbp_write(sc, 1, bbp1); 40204310d6deSBernhard Schmidt 40214310d6deSBernhard Schmidt if (sc->mac_ver >= 0x3071) 40224310d6deSBernhard Schmidt rt3090_rf_setup(sc); 40234310d6deSBernhard Schmidt 40244310d6deSBernhard Schmidt /* select default channel */ 40254310d6deSBernhard Schmidt rt2860_switch_chan(sc, ic->ic_curchan); 40264310d6deSBernhard Schmidt 40274310d6deSBernhard Schmidt /* reset RF from MCU */ 40284310d6deSBernhard Schmidt rt2860_mcu_cmd(sc, RT2860_MCU_CMD_RFRESET, 0, 0); 40294310d6deSBernhard Schmidt 40304310d6deSBernhard Schmidt /* set RTS threshold */ 40314310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_TX_RTS_CFG); 40324310d6deSBernhard Schmidt tmp &= ~0xffff00; 40334310d6deSBernhard Schmidt tmp |= IEEE80211_RTS_DEFAULT << 8; 40344310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_TX_RTS_CFG, tmp); 40354310d6deSBernhard Schmidt 40364310d6deSBernhard Schmidt /* setup initial protection mode */ 40377a79cebfSGleb Smirnoff rt2860_updateprot(sc); 40384310d6deSBernhard Schmidt 40394310d6deSBernhard Schmidt /* turn radio LED on */ 40404310d6deSBernhard Schmidt rt2860_set_leds(sc, RT2860_LED_RADIO); 40414310d6deSBernhard Schmidt 40424310d6deSBernhard Schmidt /* enable Tx/Rx DMA engine */ 40434310d6deSBernhard Schmidt if ((error = rt2860_txrx_enable(sc)) != 0) { 40444310d6deSBernhard Schmidt rt2860_stop_locked(sc); 40454310d6deSBernhard Schmidt return; 40464310d6deSBernhard Schmidt } 40474310d6deSBernhard Schmidt 40484310d6deSBernhard Schmidt /* clear pending interrupts */ 40494310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_INT_STATUS, 0xffffffff); 40504310d6deSBernhard Schmidt /* enable interrupts */ 40514310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_INT_MASK, 0x3fffc); 40524310d6deSBernhard Schmidt 40534310d6deSBernhard Schmidt if (sc->sc_flags & RT2860_ADVANCED_PS) 40544310d6deSBernhard Schmidt rt2860_mcu_cmd(sc, RT2860_MCU_CMD_PSLEVEL, sc->pslevel, 0); 40554310d6deSBernhard Schmidt 40561c1cd920SKevin Lo sc->sc_flags |= RT2860_RUNNING; 40574310d6deSBernhard Schmidt 40584310d6deSBernhard Schmidt callout_reset(&sc->watchdog_ch, hz, rt2860_watchdog, sc); 40594310d6deSBernhard Schmidt } 40604310d6deSBernhard Schmidt 40614310d6deSBernhard Schmidt static void 40624310d6deSBernhard Schmidt rt2860_stop(void *arg) 40634310d6deSBernhard Schmidt { 40644310d6deSBernhard Schmidt struct rt2860_softc *sc = arg; 40654310d6deSBernhard Schmidt 40664310d6deSBernhard Schmidt RAL_LOCK(sc); 40674310d6deSBernhard Schmidt rt2860_stop_locked(sc); 40684310d6deSBernhard Schmidt RAL_UNLOCK(sc); 40694310d6deSBernhard Schmidt } 40704310d6deSBernhard Schmidt 40714310d6deSBernhard Schmidt static void 40724310d6deSBernhard Schmidt rt2860_stop_locked(struct rt2860_softc *sc) 40734310d6deSBernhard Schmidt { 40744310d6deSBernhard Schmidt uint32_t tmp; 40754310d6deSBernhard Schmidt int qid; 40764310d6deSBernhard Schmidt 40771c1cd920SKevin Lo if (sc->sc_flags & RT2860_RUNNING) 40784310d6deSBernhard Schmidt rt2860_set_leds(sc, 0); /* turn all LEDs off */ 40794310d6deSBernhard Schmidt 40804310d6deSBernhard Schmidt callout_stop(&sc->watchdog_ch); 40814310d6deSBernhard Schmidt sc->sc_tx_timer = 0; 40821c1cd920SKevin Lo sc->sc_flags &= ~RT2860_RUNNING; 40834310d6deSBernhard Schmidt 40844310d6deSBernhard Schmidt /* disable interrupts */ 40854310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_INT_MASK, 0); 40864310d6deSBernhard Schmidt 40874310d6deSBernhard Schmidt /* disable GP timer */ 40884310d6deSBernhard Schmidt rt2860_set_gp_timer(sc, 0); 40894310d6deSBernhard Schmidt 40904310d6deSBernhard Schmidt /* disable Rx */ 40914310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_MAC_SYS_CTRL); 40924310d6deSBernhard Schmidt tmp &= ~(RT2860_MAC_RX_EN | RT2860_MAC_TX_EN); 40934310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_MAC_SYS_CTRL, tmp); 40944310d6deSBernhard Schmidt 40954310d6deSBernhard Schmidt /* reset adapter */ 40964310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST); 40974310d6deSBernhard Schmidt RAL_BARRIER_WRITE(sc); 40984310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_MAC_SYS_CTRL, 0); 40994310d6deSBernhard Schmidt 41004310d6deSBernhard Schmidt /* reset Tx and Rx rings (and reclaim TXWIs) */ 41014310d6deSBernhard Schmidt sc->qfullmsk = 0; 41024310d6deSBernhard Schmidt for (qid = 0; qid < 6; qid++) 41034310d6deSBernhard Schmidt rt2860_reset_tx_ring(sc, &sc->txq[qid]); 41044310d6deSBernhard Schmidt rt2860_reset_rx_ring(sc, &sc->rxq); 41054310d6deSBernhard Schmidt } 41064310d6deSBernhard Schmidt 41074310d6deSBernhard Schmidt int 41084310d6deSBernhard Schmidt rt2860_load_microcode(struct rt2860_softc *sc) 41094310d6deSBernhard Schmidt { 41104310d6deSBernhard Schmidt const struct firmware *fp; 41114310d6deSBernhard Schmidt int ntries, error; 41124310d6deSBernhard Schmidt 41134310d6deSBernhard Schmidt RAL_LOCK_ASSERT(sc); 41144310d6deSBernhard Schmidt 41154310d6deSBernhard Schmidt RAL_UNLOCK(sc); 41164310d6deSBernhard Schmidt fp = firmware_get("rt2860fw"); 41174310d6deSBernhard Schmidt RAL_LOCK(sc); 41184310d6deSBernhard Schmidt if (fp == NULL) { 41194310d6deSBernhard Schmidt device_printf(sc->sc_dev, 41204310d6deSBernhard Schmidt "unable to receive rt2860fw firmware image\n"); 41214310d6deSBernhard Schmidt return EINVAL; 41224310d6deSBernhard Schmidt } 41234310d6deSBernhard Schmidt 41244310d6deSBernhard Schmidt /* set "host program ram write selection" bit */ 41254310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_SYS_CTRL, RT2860_HST_PM_SEL); 41264310d6deSBernhard Schmidt /* write microcode image */ 41274310d6deSBernhard Schmidt RAL_WRITE_REGION_1(sc, RT2860_FW_BASE, fp->data, fp->datasize); 41284310d6deSBernhard Schmidt /* kick microcontroller unit */ 41294310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_SYS_CTRL, 0); 41304310d6deSBernhard Schmidt RAL_BARRIER_WRITE(sc); 41314310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_SYS_CTRL, RT2860_MCU_RESET); 41324310d6deSBernhard Schmidt 41334310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_H2M_BBPAGENT, 0); 41344310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_H2M_MAILBOX, 0); 41354310d6deSBernhard Schmidt 41364310d6deSBernhard Schmidt /* wait until microcontroller is ready */ 41374310d6deSBernhard Schmidt RAL_BARRIER_READ_WRITE(sc); 41384310d6deSBernhard Schmidt for (ntries = 0; ntries < 1000; ntries++) { 41394310d6deSBernhard Schmidt if (RAL_READ(sc, RT2860_SYS_CTRL) & RT2860_MCU_READY) 41404310d6deSBernhard Schmidt break; 41414310d6deSBernhard Schmidt DELAY(1000); 41424310d6deSBernhard Schmidt } 41434310d6deSBernhard Schmidt if (ntries == 1000) { 41444310d6deSBernhard Schmidt device_printf(sc->sc_dev, 41454310d6deSBernhard Schmidt "timeout waiting for MCU to initialize\n"); 41464310d6deSBernhard Schmidt error = ETIMEDOUT; 41474310d6deSBernhard Schmidt } else 41484310d6deSBernhard Schmidt error = 0; 41494310d6deSBernhard Schmidt 41504310d6deSBernhard Schmidt firmware_put(fp, FIRMWARE_UNLOAD); 41514310d6deSBernhard Schmidt return error; 41524310d6deSBernhard Schmidt } 41534310d6deSBernhard Schmidt 41544310d6deSBernhard Schmidt /* 41554310d6deSBernhard Schmidt * This function is called periodically to adjust Tx power based on 41564310d6deSBernhard Schmidt * temperature variation. 41574310d6deSBernhard Schmidt */ 41584310d6deSBernhard Schmidt #ifdef NOT_YET 41594310d6deSBernhard Schmidt static void 41604310d6deSBernhard Schmidt rt2860_calib(struct rt2860_softc *sc) 41614310d6deSBernhard Schmidt { 41624310d6deSBernhard Schmidt struct ieee80211com *ic = &sc->sc_ic; 41634310d6deSBernhard Schmidt const uint8_t *tssi; 41644310d6deSBernhard Schmidt uint8_t step, bbp49; 41654310d6deSBernhard Schmidt int8_t ridx, d; 41664310d6deSBernhard Schmidt 41674310d6deSBernhard Schmidt /* read current temperature */ 41684310d6deSBernhard Schmidt bbp49 = rt2860_mcu_bbp_read(sc, 49); 41694310d6deSBernhard Schmidt 41704310d6deSBernhard Schmidt if (IEEE80211_IS_CHAN_2GHZ(ic->ic_bss->ni_chan)) { 41714310d6deSBernhard Schmidt tssi = &sc->tssi_2ghz[4]; 41724310d6deSBernhard Schmidt step = sc->step_2ghz; 41734310d6deSBernhard Schmidt } else { 41744310d6deSBernhard Schmidt tssi = &sc->tssi_5ghz[4]; 41754310d6deSBernhard Schmidt step = sc->step_5ghz; 41764310d6deSBernhard Schmidt } 41774310d6deSBernhard Schmidt 41784310d6deSBernhard Schmidt if (bbp49 < tssi[0]) { /* lower than reference */ 41794310d6deSBernhard Schmidt /* use higher Tx power than default */ 41804310d6deSBernhard Schmidt for (d = 0; d > -4 && bbp49 <= tssi[d - 1]; d--); 41814310d6deSBernhard Schmidt } else if (bbp49 > tssi[0]) { /* greater than reference */ 41824310d6deSBernhard Schmidt /* use lower Tx power than default */ 41834310d6deSBernhard Schmidt for (d = 0; d < +4 && bbp49 >= tssi[d + 1]; d++); 41844310d6deSBernhard Schmidt } else { 41854310d6deSBernhard Schmidt /* use default Tx power */ 41864310d6deSBernhard Schmidt d = 0; 41874310d6deSBernhard Schmidt } 41884310d6deSBernhard Schmidt d *= step; 41894310d6deSBernhard Schmidt 41904310d6deSBernhard Schmidt DPRINTF(("BBP49=0x%02x, adjusting Tx power by %d\n", bbp49, d)); 41914310d6deSBernhard Schmidt 41924310d6deSBernhard Schmidt /* write adjusted Tx power values for each Tx rate */ 41934310d6deSBernhard Schmidt for (ridx = 0; ridx < 5; ridx++) { 41944310d6deSBernhard Schmidt if (sc->txpow20mhz[ridx] == 0xffffffff) 41954310d6deSBernhard Schmidt continue; 41964310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_TX_PWR_CFG(ridx), 41974310d6deSBernhard Schmidt b4inc(sc->txpow20mhz[ridx], d)); 41984310d6deSBernhard Schmidt } 41994310d6deSBernhard Schmidt } 42004310d6deSBernhard Schmidt #endif 42014310d6deSBernhard Schmidt 42024310d6deSBernhard Schmidt static void 42034310d6deSBernhard Schmidt rt3090_set_rx_antenna(struct rt2860_softc *sc, int aux) 42044310d6deSBernhard Schmidt { 42054310d6deSBernhard Schmidt uint32_t tmp; 42064310d6deSBernhard Schmidt 42074310d6deSBernhard Schmidt if (aux) { 42086fc44dabSKevin Lo if (sc->mac_ver == 0x5390) { 42096fc44dabSKevin Lo rt2860_mcu_bbp_write(sc, 152, 42106fc44dabSKevin Lo rt2860_mcu_bbp_read(sc, 152) & ~0x80); 42116fc44dabSKevin Lo } else { 42124310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_PCI_EECTRL); 42134310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_PCI_EECTRL, tmp & ~RT2860_C); 42144310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_GPIO_CTRL); 42154310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_GPIO_CTRL, (tmp & ~0x0808) | 0x08); 42166fc44dabSKevin Lo } 42176fc44dabSKevin Lo } else { 42186fc44dabSKevin Lo if (sc->mac_ver == 0x5390) { 42196fc44dabSKevin Lo rt2860_mcu_bbp_write(sc, 152, 42206fc44dabSKevin Lo rt2860_mcu_bbp_read(sc, 152) | 0x80); 42214310d6deSBernhard Schmidt } else { 42224310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_PCI_EECTRL); 42234310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_PCI_EECTRL, tmp | RT2860_C); 42244310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_GPIO_CTRL); 42254310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_GPIO_CTRL, tmp & ~0x0808); 42264310d6deSBernhard Schmidt } 42274310d6deSBernhard Schmidt } 42286fc44dabSKevin Lo } 42294310d6deSBernhard Schmidt 42304310d6deSBernhard Schmidt static void 42314310d6deSBernhard Schmidt rt2860_switch_chan(struct rt2860_softc *sc, struct ieee80211_channel *c) 42324310d6deSBernhard Schmidt { 42337a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 42344310d6deSBernhard Schmidt u_int chan, group; 42354310d6deSBernhard Schmidt 42364310d6deSBernhard Schmidt chan = ieee80211_chan2ieee(ic, c); 42374310d6deSBernhard Schmidt if (chan == 0 || chan == IEEE80211_CHAN_ANY) 42384310d6deSBernhard Schmidt return; 42394310d6deSBernhard Schmidt 42406fc44dabSKevin Lo if (sc->mac_ver >= 0x5390) 42416fc44dabSKevin Lo rt5390_set_chan(sc, chan); 42426fc44dabSKevin Lo else if (sc->mac_ver >= 0x3071) 42434310d6deSBernhard Schmidt rt3090_set_chan(sc, chan); 42444310d6deSBernhard Schmidt else 42454310d6deSBernhard Schmidt rt2860_set_chan(sc, chan); 42464310d6deSBernhard Schmidt 42474310d6deSBernhard Schmidt /* determine channel group */ 42484310d6deSBernhard Schmidt if (chan <= 14) 42494310d6deSBernhard Schmidt group = 0; 42504310d6deSBernhard Schmidt else if (chan <= 64) 42514310d6deSBernhard Schmidt group = 1; 42524310d6deSBernhard Schmidt else if (chan <= 128) 42534310d6deSBernhard Schmidt group = 2; 42544310d6deSBernhard Schmidt else 42554310d6deSBernhard Schmidt group = 3; 42564310d6deSBernhard Schmidt 42574310d6deSBernhard Schmidt /* XXX necessary only when group has changed! */ 42586fc44dabSKevin Lo if (sc->mac_ver < 0x5390) 42594310d6deSBernhard Schmidt rt2860_select_chan_group(sc, group); 42604310d6deSBernhard Schmidt 42614310d6deSBernhard Schmidt DELAY(1000); 42624310d6deSBernhard Schmidt } 42634310d6deSBernhard Schmidt 42644310d6deSBernhard Schmidt static int 42654310d6deSBernhard Schmidt rt2860_setup_beacon(struct rt2860_softc *sc, struct ieee80211vap *vap) 42664310d6deSBernhard Schmidt { 42674310d6deSBernhard Schmidt struct ieee80211com *ic = vap->iv_ic; 42684310d6deSBernhard Schmidt struct rt2860_txwi txwi; 42694310d6deSBernhard Schmidt struct mbuf *m; 42704310d6deSBernhard Schmidt int ridx; 42714310d6deSBernhard Schmidt 4272210ab3c2SAdrian Chadd if ((m = ieee80211_beacon_alloc(vap->iv_bss)) == NULL) 42734310d6deSBernhard Schmidt return ENOBUFS; 42744310d6deSBernhard Schmidt 42754310d6deSBernhard Schmidt memset(&txwi, 0, sizeof txwi); 42764310d6deSBernhard Schmidt txwi.wcid = 0xff; 42774310d6deSBernhard Schmidt txwi.len = htole16(m->m_pkthdr.len); 42784310d6deSBernhard Schmidt /* send beacons at the lowest available rate */ 42794310d6deSBernhard Schmidt ridx = IEEE80211_IS_CHAN_5GHZ(ic->ic_bsschan) ? 42804310d6deSBernhard Schmidt RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1; 42814310d6deSBernhard Schmidt txwi.phy = htole16(rt2860_rates[ridx].mcs); 42824310d6deSBernhard Schmidt if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM) 42834310d6deSBernhard Schmidt txwi.phy |= htole16(RT2860_PHY_OFDM); 42844310d6deSBernhard Schmidt txwi.txop = RT2860_TX_TXOP_HT; 42854310d6deSBernhard Schmidt txwi.flags = RT2860_TX_TS; 42864310d6deSBernhard Schmidt txwi.xflags = RT2860_TX_NSEQ; 42874310d6deSBernhard Schmidt 42884310d6deSBernhard Schmidt RAL_WRITE_REGION_1(sc, RT2860_BCN_BASE(0), 42894310d6deSBernhard Schmidt (uint8_t *)&txwi, sizeof txwi); 42904310d6deSBernhard Schmidt RAL_WRITE_REGION_1(sc, RT2860_BCN_BASE(0) + sizeof txwi, 42914310d6deSBernhard Schmidt mtod(m, uint8_t *), m->m_pkthdr.len); 42924310d6deSBernhard Schmidt 42934310d6deSBernhard Schmidt m_freem(m); 42944310d6deSBernhard Schmidt 42954310d6deSBernhard Schmidt return 0; 42964310d6deSBernhard Schmidt } 42974310d6deSBernhard Schmidt 42984310d6deSBernhard Schmidt static void 42994310d6deSBernhard Schmidt rt2860_enable_tsf_sync(struct rt2860_softc *sc) 43004310d6deSBernhard Schmidt { 43017a79cebfSGleb Smirnoff struct ieee80211com *ic = &sc->sc_ic; 43024310d6deSBernhard Schmidt struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 43034310d6deSBernhard Schmidt uint32_t tmp; 43044310d6deSBernhard Schmidt 43054310d6deSBernhard Schmidt tmp = RAL_READ(sc, RT2860_BCN_TIME_CFG); 43064310d6deSBernhard Schmidt 43074310d6deSBernhard Schmidt tmp &= ~0x1fffff; 43084310d6deSBernhard Schmidt tmp |= vap->iv_bss->ni_intval * 16; 43094310d6deSBernhard Schmidt tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN; 43104310d6deSBernhard Schmidt if (vap->iv_opmode == IEEE80211_M_STA) { 43114310d6deSBernhard Schmidt /* 43124310d6deSBernhard Schmidt * Local TSF is always updated with remote TSF on beacon 43134310d6deSBernhard Schmidt * reception. 43144310d6deSBernhard Schmidt */ 43154310d6deSBernhard Schmidt tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT; 43164310d6deSBernhard Schmidt } 43174310d6deSBernhard Schmidt else if (vap->iv_opmode == IEEE80211_M_IBSS || 43184310d6deSBernhard Schmidt vap->iv_opmode == IEEE80211_M_MBSS) { 43194310d6deSBernhard Schmidt tmp |= RT2860_BCN_TX_EN; 43204310d6deSBernhard Schmidt /* 43214310d6deSBernhard Schmidt * Local TSF is updated with remote TSF on beacon reception 43224310d6deSBernhard Schmidt * only if the remote TSF is greater than local TSF. 43234310d6deSBernhard Schmidt */ 43244310d6deSBernhard Schmidt tmp |= 2 << RT2860_TSF_SYNC_MODE_SHIFT; 43254310d6deSBernhard Schmidt } else if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 43264310d6deSBernhard Schmidt tmp |= RT2860_BCN_TX_EN; 43274310d6deSBernhard Schmidt /* SYNC with nobody */ 43284310d6deSBernhard Schmidt tmp |= 3 << RT2860_TSF_SYNC_MODE_SHIFT; 43294310d6deSBernhard Schmidt } 43304310d6deSBernhard Schmidt 43314310d6deSBernhard Schmidt RAL_WRITE(sc, RT2860_BCN_TIME_CFG, tmp); 43324310d6deSBernhard Schmidt } 4333