xref: /freebsd/sys/dev/ral/rt2860.c (revision c249cc3822dc002288700ee206cf28c0c6031449)
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
rt2860_attach(device_t dev,int id)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
rt2860_detach(void * xsc)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
rt2860_shutdown(void * xsc)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
rt2860_suspend(void * xsc)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
rt2860_resume(void * xsc)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 *
rt2860_vap_create(struct ieee80211com * ic,const char name[IFNAMSIZ],int unit,enum ieee80211_opmode opmode,int flags,const uint8_t bssid[IEEE80211_ADDR_LEN],const uint8_t mac[IEEE80211_ADDR_LEN])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
rt2860_vap_delete(struct ieee80211vap * vap)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
rt2860_dma_map_addr(void * arg,bus_dma_segment_t * segs,int nseg,int error)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
rt2860_alloc_tx_ring(struct rt2860_softc * sc,struct rt2860_tx_ring * ring)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
rt2860_reset_tx_ring(struct rt2860_softc * sc,struct rt2860_tx_ring * ring)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
rt2860_free_tx_ring(struct rt2860_softc * sc,struct rt2860_tx_ring * ring)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
rt2860_alloc_tx_pool(struct rt2860_softc * sc)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
rt2860_free_tx_pool(struct rt2860_softc * sc)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
rt2860_alloc_rx_ring(struct rt2860_softc * sc,struct rt2860_rx_ring * ring)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
rt2860_reset_rx_ring(struct rt2860_softc * sc,struct rt2860_rx_ring * ring)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
rt2860_free_rx_ring(struct rt2860_softc * sc,struct rt2860_rx_ring * ring)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
rt2860_updatestats(struct rt2860_softc * sc)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
rt2860_newassoc(struct ieee80211_node * ni,int isnew)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
rt2860_node_free(struct ieee80211_node * ni)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
rt2860_ampdu_rx_start(struct ieee80211com * ic,struct ieee80211_node * ni,uint8_t tid)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
rt2860_ampdu_rx_stop(struct ieee80211com * ic,struct ieee80211_node * ni,uint8_t tid)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
rt2860_newstate(struct ieee80211vap * vap,enum ieee80211_state nstate,int arg)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
rt3090_efuse_read_2(struct rt2860_softc * sc,uint16_t addr)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
rt2860_eeprom_read_2(struct rt2860_softc * sc,uint16_t addr)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
rt2860_srom_read(struct rt2860_softc * sc,uint8_t addr)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
rt2860_intr_coherent(struct rt2860_softc * sc)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
rt2860_drain_stats_fifo(struct rt2860_softc * sc)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
rt2860_tx_intr(struct rt2860_softc * sc,int qid)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
rt2860_maxrssi_chain(struct rt2860_softc * sc,const struct rt2860_rxwi * rxwi)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
rt2860_rx_intr(struct rt2860_softc * sc)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
rt2860_tbtt_intr(struct rt2860_softc * sc)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
rt2860_gp_intr(struct rt2860_softc * sc)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
rt2860_intr(void * arg)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
rt2860_tx(struct rt2860_softc * sc,struct mbuf * m,struct ieee80211_node * ni)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
rt2860_raw_xmit(struct ieee80211_node * ni,struct mbuf * m,const struct ieee80211_bpf_params * params)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
rt2860_tx_raw(struct rt2860_softc * sc,struct mbuf * m,struct ieee80211_node * ni,const struct ieee80211_bpf_params * params)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
rt2860_transmit(struct ieee80211com * ic,struct mbuf * m)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
rt2860_start(struct rt2860_softc * sc)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
rt2860_watchdog(void * arg)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
rt2860_parent(struct ieee80211com * ic)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
rt2860_mcu_bbp_write(struct rt2860_softc * sc,uint8_t reg,uint8_t val)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
rt2860_mcu_bbp_read(struct rt2860_softc * sc,uint8_t reg)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
rt2860_rf_write(struct rt2860_softc * sc,uint8_t reg,uint32_t val)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
rt3090_rf_read(struct rt2860_softc * sc,uint8_t reg)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
rt3090_rf_write(struct rt2860_softc * sc,uint8_t reg,uint8_t val)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
rt2860_mcu_cmd(struct rt2860_softc * sc,uint8_t cmd,uint16_t arg,int wait)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
rt2860_enable_mrr(struct rt2860_softc * sc)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
rt2860_set_txpreamble(struct rt2860_softc * sc)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
rt2860_set_basicrates(struct rt2860_softc * sc,const struct ieee80211_rateset * rs)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
rt2860_scan_start(struct ieee80211com * ic)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
rt2860_scan_end(struct ieee80211com * ic)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
rt2860_getradiocaps(struct ieee80211com * ic,int maxchans,int * nchans,struct ieee80211_channel chans[])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
rt2860_set_channel(struct ieee80211com * ic)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
rt2860_select_chan_group(struct rt2860_softc * sc,int group)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
rt2860_set_chan(struct rt2860_softc * sc,u_int chan)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
rt3090_set_chan(struct rt2860_softc * sc,u_int chan)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
rt5390_set_chan(struct rt2860_softc * sc,u_int chan)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
rt3090_rf_init(struct rt2860_softc * sc)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
rt5390_rf_init(struct rt2860_softc * sc)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
rt3090_rf_wakeup(struct rt2860_softc * sc)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
rt5390_rf_wakeup(struct rt2860_softc * sc)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
rt3090_filter_calib(struct rt2860_softc * sc,uint8_t init,uint8_t target,uint8_t * val)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
rt3090_rf_setup(struct rt2860_softc * sc)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
rt2860_set_leds(struct rt2860_softc * sc,uint16_t which)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
rt2860_set_gp_timer(struct rt2860_softc * sc,int ms)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
rt2860_set_bssid(struct rt2860_softc * sc,const uint8_t * bssid)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
rt2860_set_macaddr(struct rt2860_softc * sc,const uint8_t * addr)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
rt2860_updateslot(struct ieee80211com * ic)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
rt2860_updateprot(struct rt2860_softc * sc)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
rt2860_update_promisc(struct ieee80211com * ic)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
rt2860_updateedca(struct ieee80211com * ic)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
rt2860_set_key(struct ieee80211com * ic,struct ieee80211_node * ni,struct ieee80211_key * k)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
rt2860_delete_key(struct ieee80211com * ic,struct ieee80211_node * ni,struct ieee80211_key * k)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
rt2860_rssi2dbm(struct rt2860_softc * sc,uint8_t rssi,uint8_t rxchain)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
b4inc(uint32_t b32,int8_t delta)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 *
rt2860_get_rf(uint16_t rev)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
rt2860_read_eeprom(struct rt2860_softc * sc,uint8_t macaddr[IEEE80211_ADDR_LEN])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
rt2860_bbp_init(struct rt2860_softc * sc)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
rt5390_bbp_init(struct rt2860_softc * sc)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
rt2860_txrx_enable(struct rt2860_softc * sc)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
rt2860_init(void * arg)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
rt2860_init_locked(struct rt2860_softc * sc)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
rt2860_stop(void * arg)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
rt2860_stop_locked(struct rt2860_softc * sc)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
rt2860_load_microcode(struct rt2860_softc * sc)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
rt2860_calib(struct rt2860_softc * sc)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
rt3090_set_rx_antenna(struct rt2860_softc * sc,int aux)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
rt2860_switch_chan(struct rt2860_softc * sc,struct ieee80211_channel * c)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
rt2860_setup_beacon(struct rt2860_softc * sc,struct ieee80211vap * vap)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
rt2860_enable_tsf_sync(struct rt2860_softc * sc)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