1235233Sbschmidt/*-
2235233Sbschmidt * Copyright (c) 2007-2010 Damien Bergamini <damien.bergamini@free.fr>
3235233Sbschmidt * Copyright (c) 2012 Bernhard Schmidt <bschmidt@FreeBSD.org>
4235233Sbschmidt *
5235233Sbschmidt * Permission to use, copy, modify, and distribute this software for any
6235233Sbschmidt * purpose with or without fee is hereby granted, provided that the above
7235233Sbschmidt * copyright notice and this permission notice appear in all copies.
8235233Sbschmidt *
9235233Sbschmidt * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10235233Sbschmidt * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11235233Sbschmidt * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12235233Sbschmidt * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13235233Sbschmidt * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14235233Sbschmidt * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15235233Sbschmidt * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16235233Sbschmidt *
17235233Sbschmidt * $OpenBSD: rt2860.c,v 1.65 2010/10/23 14:24:54 damien Exp $
18235233Sbschmidt */
19235233Sbschmidt
20235233Sbschmidt#include <sys/cdefs.h>
21235233Sbschmidt__FBSDID("$FreeBSD: stable/11/sys/dev/ral/rt2860.c 306851 2016-10-08 16:39:21Z avos $");
22235233Sbschmidt
23235233Sbschmidt/*-
24278551Skevlo * Ralink Technology RT2860/RT3090/RT3390/RT3562/RT5390/RT5392 chipset driver
25235233Sbschmidt * http://www.ralinktech.com/
26235233Sbschmidt */
27235233Sbschmidt
28235233Sbschmidt#include <sys/param.h>
29235233Sbschmidt#include <sys/sysctl.h>
30235233Sbschmidt#include <sys/sockio.h>
31235233Sbschmidt#include <sys/mbuf.h>
32235233Sbschmidt#include <sys/kernel.h>
33235233Sbschmidt#include <sys/socket.h>
34235233Sbschmidt#include <sys/systm.h>
35235233Sbschmidt#include <sys/malloc.h>
36235233Sbschmidt#include <sys/lock.h>
37235233Sbschmidt#include <sys/mutex.h>
38235233Sbschmidt#include <sys/module.h>
39235233Sbschmidt#include <sys/bus.h>
40235233Sbschmidt#include <sys/endian.h>
41235233Sbschmidt#include <sys/firmware.h>
42235233Sbschmidt
43235233Sbschmidt#include <machine/bus.h>
44235233Sbschmidt#include <machine/resource.h>
45235233Sbschmidt#include <sys/rman.h>
46235233Sbschmidt
47235233Sbschmidt#include <net/bpf.h>
48235233Sbschmidt#include <net/if.h>
49257176Sglebius#include <net/if_var.h>
50235233Sbschmidt#include <net/if_arp.h>
51235233Sbschmidt#include <net/ethernet.h>
52235233Sbschmidt#include <net/if_dl.h>
53235233Sbschmidt#include <net/if_media.h>
54235233Sbschmidt#include <net/if_types.h>
55235233Sbschmidt
56235233Sbschmidt#include <net80211/ieee80211_var.h>
57235233Sbschmidt#include <net80211/ieee80211_radiotap.h>
58235233Sbschmidt#include <net80211/ieee80211_regdomain.h>
59235233Sbschmidt#include <net80211/ieee80211_ratectl.h>
60235233Sbschmidt
61235233Sbschmidt#include <netinet/in.h>
62235233Sbschmidt#include <netinet/in_systm.h>
63235233Sbschmidt#include <netinet/in_var.h>
64235233Sbschmidt#include <netinet/ip.h>
65235233Sbschmidt#include <netinet/if_ether.h>
66235233Sbschmidt
67235233Sbschmidt#include <dev/ral/rt2860reg.h>
68235233Sbschmidt#include <dev/ral/rt2860var.h>
69235233Sbschmidt
70235233Sbschmidt#define RAL_DEBUG
71235233Sbschmidt#ifdef RAL_DEBUG
72235233Sbschmidt#define DPRINTF(x)	do { if (sc->sc_debug > 0) printf x; } while (0)
73235233Sbschmidt#define DPRINTFN(n, x)	do { if (sc->sc_debug >= (n)) printf x; } while (0)
74235233Sbschmidt#else
75235233Sbschmidt#define DPRINTF(x)
76235233Sbschmidt#define DPRINTFN(n, x)
77235233Sbschmidt#endif
78235233Sbschmidt
79235233Sbschmidtstatic struct ieee80211vap *rt2860_vap_create(struct ieee80211com *,
80235233Sbschmidt			    const char [IFNAMSIZ], int, enum ieee80211_opmode,
81235233Sbschmidt			    int, const uint8_t [IEEE80211_ADDR_LEN],
82235233Sbschmidt			    const uint8_t [IEEE80211_ADDR_LEN]);
83235233Sbschmidtstatic void	rt2860_vap_delete(struct ieee80211vap *);
84235233Sbschmidtstatic void	rt2860_dma_map_addr(void *, bus_dma_segment_t *, int, int);
85235233Sbschmidtstatic int	rt2860_alloc_tx_ring(struct rt2860_softc *,
86235233Sbschmidt		    struct rt2860_tx_ring *);
87235233Sbschmidtstatic void	rt2860_reset_tx_ring(struct rt2860_softc *,
88235233Sbschmidt		    struct rt2860_tx_ring *);
89235233Sbschmidtstatic void	rt2860_free_tx_ring(struct rt2860_softc *,
90235233Sbschmidt		    struct rt2860_tx_ring *);
91235233Sbschmidtstatic int	rt2860_alloc_tx_pool(struct rt2860_softc *);
92235233Sbschmidtstatic void	rt2860_free_tx_pool(struct rt2860_softc *);
93235233Sbschmidtstatic int	rt2860_alloc_rx_ring(struct rt2860_softc *,
94235233Sbschmidt		    struct rt2860_rx_ring *);
95235233Sbschmidtstatic void	rt2860_reset_rx_ring(struct rt2860_softc *,
96235233Sbschmidt		    struct rt2860_rx_ring *);
97235233Sbschmidtstatic void	rt2860_free_rx_ring(struct rt2860_softc *,
98235233Sbschmidt		    struct rt2860_rx_ring *);
99235233Sbschmidtstatic void	rt2860_updatestats(struct rt2860_softc *);
100235233Sbschmidtstatic void	rt2860_newassoc(struct ieee80211_node *, int);
101235233Sbschmidtstatic void	rt2860_node_free(struct ieee80211_node *);
102235233Sbschmidt#ifdef IEEE80211_HT
103235233Sbschmidtstatic int	rt2860_ampdu_rx_start(struct ieee80211com *,
104235233Sbschmidt		    struct ieee80211_node *, uint8_t);
105235233Sbschmidtstatic void	rt2860_ampdu_rx_stop(struct ieee80211com *,
106235233Sbschmidt		    struct ieee80211_node *, uint8_t);
107235233Sbschmidt#endif
108235233Sbschmidtstatic int	rt2860_newstate(struct ieee80211vap *, enum ieee80211_state,
109235233Sbschmidt		    int);
110235233Sbschmidtstatic uint16_t	rt3090_efuse_read_2(struct rt2860_softc *, uint16_t);
111235233Sbschmidtstatic uint16_t	rt2860_eeprom_read_2(struct rt2860_softc *, uint16_t);
112235233Sbschmidtstatic void	rt2860_intr_coherent(struct rt2860_softc *);
113235233Sbschmidtstatic void	rt2860_drain_stats_fifo(struct rt2860_softc *);
114235233Sbschmidtstatic void	rt2860_tx_intr(struct rt2860_softc *, int);
115235233Sbschmidtstatic void	rt2860_rx_intr(struct rt2860_softc *);
116235233Sbschmidtstatic void	rt2860_tbtt_intr(struct rt2860_softc *);
117235233Sbschmidtstatic void	rt2860_gp_intr(struct rt2860_softc *);
118235233Sbschmidtstatic int	rt2860_tx(struct rt2860_softc *, struct mbuf *,
119235233Sbschmidt		    struct ieee80211_node *);
120235233Sbschmidtstatic int	rt2860_raw_xmit(struct ieee80211_node *, struct mbuf *,
121235233Sbschmidt		    const struct ieee80211_bpf_params *);
122235233Sbschmidtstatic int	rt2860_tx_raw(struct rt2860_softc *, struct mbuf *,
123235233Sbschmidt		    struct ieee80211_node *,
124235233Sbschmidt		    const struct ieee80211_bpf_params *params);
125287197Sglebiusstatic int	rt2860_transmit(struct ieee80211com *, struct mbuf *);
126287197Sglebiusstatic void	rt2860_start(struct rt2860_softc *);
127235233Sbschmidtstatic void	rt2860_watchdog(void *);
128287197Sglebiusstatic void	rt2860_parent(struct ieee80211com *);
129235233Sbschmidtstatic void	rt2860_mcu_bbp_write(struct rt2860_softc *, uint8_t, uint8_t);
130235233Sbschmidtstatic uint8_t	rt2860_mcu_bbp_read(struct rt2860_softc *, uint8_t);
131235233Sbschmidtstatic void	rt2860_rf_write(struct rt2860_softc *, uint8_t, uint32_t);
132235233Sbschmidtstatic uint8_t	rt3090_rf_read(struct rt2860_softc *, uint8_t);
133235233Sbschmidtstatic void	rt3090_rf_write(struct rt2860_softc *, uint8_t, uint8_t);
134235233Sbschmidtstatic int	rt2860_mcu_cmd(struct rt2860_softc *, uint8_t, uint16_t, int);
135235233Sbschmidtstatic void	rt2860_enable_mrr(struct rt2860_softc *);
136235233Sbschmidtstatic void	rt2860_set_txpreamble(struct rt2860_softc *);
137235233Sbschmidtstatic void	rt2860_set_basicrates(struct rt2860_softc *,
138235233Sbschmidt		    const struct ieee80211_rateset *);
139235233Sbschmidtstatic void	rt2860_scan_start(struct ieee80211com *);
140235233Sbschmidtstatic void	rt2860_scan_end(struct ieee80211com *);
141300752Savosstatic void	rt2860_getradiocaps(struct ieee80211com *, int, int *,
142300752Savos		    struct ieee80211_channel[]);
143235233Sbschmidtstatic void	rt2860_set_channel(struct ieee80211com *);
144235233Sbschmidtstatic void	rt2860_select_chan_group(struct rt2860_softc *, int);
145235233Sbschmidtstatic void	rt2860_set_chan(struct rt2860_softc *, u_int);
146235233Sbschmidtstatic void	rt3090_set_chan(struct rt2860_softc *, u_int);
147278551Skevlostatic void	rt5390_set_chan(struct rt2860_softc *, u_int);
148235233Sbschmidtstatic int	rt3090_rf_init(struct rt2860_softc *);
149278551Skevlostatic void	rt5390_rf_init(struct rt2860_softc *);
150235233Sbschmidtstatic void	rt3090_rf_wakeup(struct rt2860_softc *);
151278551Skevlostatic void	rt5390_rf_wakeup(struct rt2860_softc *);
152235233Sbschmidtstatic int	rt3090_filter_calib(struct rt2860_softc *, uint8_t, uint8_t,
153235233Sbschmidt		    uint8_t *);
154235233Sbschmidtstatic void	rt3090_rf_setup(struct rt2860_softc *);
155235233Sbschmidtstatic void	rt2860_set_leds(struct rt2860_softc *, uint16_t);
156235233Sbschmidtstatic void	rt2860_set_gp_timer(struct rt2860_softc *, int);
157235233Sbschmidtstatic void	rt2860_set_bssid(struct rt2860_softc *, const uint8_t *);
158235233Sbschmidtstatic void	rt2860_set_macaddr(struct rt2860_softc *, const uint8_t *);
159283540Sglebiusstatic void	rt2860_update_promisc(struct ieee80211com *);
160283540Sglebiusstatic void	rt2860_updateslot(struct ieee80211com *);
161287197Sglebiusstatic void	rt2860_updateprot(struct rt2860_softc *);
162235233Sbschmidtstatic int	rt2860_updateedca(struct ieee80211com *);
163235233Sbschmidt#ifdef HW_CRYPTO
164235233Sbschmidtstatic int	rt2860_set_key(struct ieee80211com *, struct ieee80211_node *,
165235233Sbschmidt		    struct ieee80211_key *);
166235233Sbschmidtstatic void	rt2860_delete_key(struct ieee80211com *,
167235233Sbschmidt		    struct ieee80211_node *, struct ieee80211_key *);
168235233Sbschmidt#endif
169235233Sbschmidtstatic int8_t	rt2860_rssi2dbm(struct rt2860_softc *, uint8_t, uint8_t);
170300006Skevlostatic const char *rt2860_get_rf(uint16_t);
171235233Sbschmidtstatic int	rt2860_read_eeprom(struct rt2860_softc *,
172235233Sbschmidt		    uint8_t macaddr[IEEE80211_ADDR_LEN]);
173235233Sbschmidtstatic int	rt2860_bbp_init(struct rt2860_softc *);
174278551Skevlostatic void	rt5390_bbp_init(struct rt2860_softc *);
175235233Sbschmidtstatic int	rt2860_txrx_enable(struct rt2860_softc *);
176235233Sbschmidtstatic void	rt2860_init(void *);
177235233Sbschmidtstatic void	rt2860_init_locked(struct rt2860_softc *);
178235233Sbschmidtstatic void	rt2860_stop(void *);
179235233Sbschmidtstatic void	rt2860_stop_locked(struct rt2860_softc *);
180235233Sbschmidtstatic int	rt2860_load_microcode(struct rt2860_softc *);
181235233Sbschmidt#ifdef NOT_YET
182235233Sbschmidtstatic void	rt2860_calib(struct rt2860_softc *);
183235233Sbschmidt#endif
184235233Sbschmidtstatic void	rt3090_set_rx_antenna(struct rt2860_softc *, int);
185235233Sbschmidtstatic void	rt2860_switch_chan(struct rt2860_softc *,
186235233Sbschmidt		    struct ieee80211_channel *);
187235233Sbschmidtstatic int	rt2860_setup_beacon(struct rt2860_softc *,
188235233Sbschmidt		    struct ieee80211vap *);
189235233Sbschmidtstatic void	rt2860_enable_tsf_sync(struct rt2860_softc *);
190235233Sbschmidt
191235233Sbschmidtstatic const struct {
192235233Sbschmidt	uint32_t	reg;
193235233Sbschmidt	uint32_t	val;
194235233Sbschmidt} rt2860_def_mac[] = {
195235233Sbschmidt	RT2860_DEF_MAC
196235233Sbschmidt};
197235233Sbschmidt
198235233Sbschmidtstatic const struct {
199235233Sbschmidt	uint8_t	reg;
200235233Sbschmidt	uint8_t	val;
201235233Sbschmidt} rt2860_def_bbp[] = {
202235233Sbschmidt	RT2860_DEF_BBP
203278551Skevlo}, rt5390_def_bbp[] = {
204278551Skevlo	RT5390_DEF_BBP
205235233Sbschmidt};
206235233Sbschmidt
207235233Sbschmidtstatic const struct rfprog {
208235233Sbschmidt	uint8_t		chan;
209235233Sbschmidt	uint32_t	r1, r2, r3, r4;
210235233Sbschmidt} rt2860_rf2850[] = {
211235233Sbschmidt	RT2860_RF2850
212235233Sbschmidt};
213235233Sbschmidt
214235233Sbschmidtstruct {
215235233Sbschmidt	uint8_t	n, r, k;
216235233Sbschmidt} rt3090_freqs[] = {
217235233Sbschmidt	RT3070_RF3052
218235233Sbschmidt};
219235233Sbschmidt
220235233Sbschmidtstatic const struct {
221235233Sbschmidt	uint8_t	reg;
222235233Sbschmidt	uint8_t	val;
223278551Skevlo} rt3090_def_rf[] = {
224235233Sbschmidt	RT3070_DEF_RF
225278551Skevlo}, rt5390_def_rf[] = {
226278551Skevlo	RT5390_DEF_RF
227278551Skevlo}, rt5392_def_rf[] = {
228278551Skevlo	RT5392_DEF_RF
229235233Sbschmidt};
230235233Sbschmidt
231300752Savosstatic const uint8_t rt2860_chan_2ghz[] =
232300752Savos	{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
233300752Savosstatic const uint8_t rt2860_chan_5ghz[] =
234300752Savos	{ 36, 38, 40, 44, 46, 48, 52, 54, 56, 60, 62, 64, 100, 102, 104,
235300752Savos	  108, 110, 112, 116, 118, 120, 124, 126, 128, 132, 134, 136, 140,
236300752Savos	  149, 151, 153, 157, 159, 161, 165, 167, 169, 171, 173 };
237300752Savos
238235233Sbschmidtint
239235233Sbschmidtrt2860_attach(device_t dev, int id)
240235233Sbschmidt{
241235233Sbschmidt	struct rt2860_softc *sc = device_get_softc(dev);
242287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
243235233Sbschmidt	uint32_t tmp;
244235233Sbschmidt	int error, ntries, qid;
245235233Sbschmidt
246235233Sbschmidt	sc->sc_dev = dev;
247235233Sbschmidt	sc->sc_debug = 0;
248235233Sbschmidt
249235233Sbschmidt	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
250235233Sbschmidt	    MTX_DEF | MTX_RECURSE);
251235233Sbschmidt
252235233Sbschmidt	callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0);
253287197Sglebius	mbufq_init(&sc->sc_snd, ifqmaxlen);
254235233Sbschmidt
255235233Sbschmidt	/* wait for NIC to initialize */
256235233Sbschmidt	for (ntries = 0; ntries < 100; ntries++) {
257235233Sbschmidt		tmp = RAL_READ(sc, RT2860_ASIC_VER_ID);
258235233Sbschmidt		if (tmp != 0 && tmp != 0xffffffff)
259235233Sbschmidt			break;
260235233Sbschmidt		DELAY(10);
261235233Sbschmidt	}
262235233Sbschmidt	if (ntries == 100) {
263235233Sbschmidt		device_printf(sc->sc_dev,
264235233Sbschmidt		    "timeout waiting for NIC to initialize\n");
265235233Sbschmidt		error = EIO;
266235233Sbschmidt		goto fail1;
267235233Sbschmidt	}
268235233Sbschmidt	sc->mac_ver = tmp >> 16;
269235233Sbschmidt	sc->mac_rev = tmp & 0xffff;
270235233Sbschmidt
271235233Sbschmidt	if (sc->mac_ver != 0x2860 &&
272235233Sbschmidt	    (id == 0x0681 || id == 0x0781 || id == 0x1059))
273235233Sbschmidt		sc->sc_flags |= RT2860_ADVANCED_PS;
274235233Sbschmidt
275235233Sbschmidt	/* retrieve RF rev. no and various other things from EEPROM */
276287197Sglebius	rt2860_read_eeprom(sc, ic->ic_macaddr);
277278551Skevlo	device_printf(sc->sc_dev, "MAC/BBP RT%X (rev 0x%04X), "
278278551Skevlo	    "RF %s (MIMO %dT%dR), address %6D\n",
279278551Skevlo	    sc->mac_ver, sc->mac_rev, rt2860_get_rf(sc->rf_rev),
280287197Sglebius	    sc->ntxchains, sc->nrxchains, ic->ic_macaddr, ":");
281235233Sbschmidt
282235233Sbschmidt	/*
283235233Sbschmidt	 * Allocate Tx (4 EDCAs + HCCA + Mgt) and Rx rings.
284235233Sbschmidt	 */
285235233Sbschmidt	for (qid = 0; qid < 6; qid++) {
286235233Sbschmidt		if ((error = rt2860_alloc_tx_ring(sc, &sc->txq[qid])) != 0) {
287235233Sbschmidt			device_printf(sc->sc_dev,
288235233Sbschmidt			    "could not allocate Tx ring %d\n", qid);
289235233Sbschmidt			goto fail2;
290235233Sbschmidt		}
291235233Sbschmidt	}
292235233Sbschmidt
293235233Sbschmidt	if ((error = rt2860_alloc_rx_ring(sc, &sc->rxq)) != 0) {
294235233Sbschmidt		device_printf(sc->sc_dev, "could not allocate Rx ring\n");
295235233Sbschmidt		goto fail2;
296235233Sbschmidt	}
297235233Sbschmidt
298235233Sbschmidt	if ((error = rt2860_alloc_tx_pool(sc)) != 0) {
299235233Sbschmidt		device_printf(sc->sc_dev, "could not allocate Tx pool\n");
300235233Sbschmidt		goto fail3;
301235233Sbschmidt	}
302235233Sbschmidt
303235233Sbschmidt	/* mgmt ring is broken on RT2860C, use EDCA AC VO ring instead */
304235233Sbschmidt	sc->mgtqid = (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) ?
305235233Sbschmidt	    WME_AC_VO : 5;
306235233Sbschmidt
307283537Sglebius	ic->ic_softc = sc;
308283527Sglebius	ic->ic_name = device_get_nameunit(dev);
309235233Sbschmidt	ic->ic_opmode = IEEE80211_M_STA;
310235233Sbschmidt	ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
311235233Sbschmidt
312235233Sbschmidt	/* set device capabilities */
313235233Sbschmidt	ic->ic_caps =
314235233Sbschmidt		  IEEE80211_C_STA		/* station mode */
315235233Sbschmidt		| IEEE80211_C_IBSS		/* ibss, nee adhoc, mode */
316235233Sbschmidt		| IEEE80211_C_HOSTAP		/* hostap mode */
317235233Sbschmidt		| IEEE80211_C_MONITOR		/* monitor mode */
318235233Sbschmidt		| IEEE80211_C_AHDEMO		/* adhoc demo mode */
319235233Sbschmidt		| IEEE80211_C_WDS		/* 4-address traffic works */
320235233Sbschmidt		| IEEE80211_C_MBSS		/* mesh point link mode */
321235233Sbschmidt		| IEEE80211_C_SHPREAMBLE	/* short preamble supported */
322235233Sbschmidt		| IEEE80211_C_SHSLOT		/* short slot time supported */
323235233Sbschmidt		| IEEE80211_C_WPA		/* capable of WPA1+WPA2 */
324235233Sbschmidt#if 0
325235233Sbschmidt		| IEEE80211_C_BGSCAN		/* capable of bg scanning */
326235233Sbschmidt#endif
327235233Sbschmidt		| IEEE80211_C_WME		/* 802.11e */
328235233Sbschmidt		;
329235233Sbschmidt
330300752Savos	rt2860_getradiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans,
331300752Savos	    ic->ic_channels);
332235233Sbschmidt
333287197Sglebius	ieee80211_ifattach(ic);
334235233Sbschmidt
335235233Sbschmidt	ic->ic_wme.wme_update = rt2860_updateedca;
336235233Sbschmidt	ic->ic_scan_start = rt2860_scan_start;
337235233Sbschmidt	ic->ic_scan_end = rt2860_scan_end;
338300752Savos	ic->ic_getradiocaps = rt2860_getradiocaps;
339235233Sbschmidt	ic->ic_set_channel = rt2860_set_channel;
340235233Sbschmidt	ic->ic_updateslot = rt2860_updateslot;
341235233Sbschmidt	ic->ic_update_promisc = rt2860_update_promisc;
342235233Sbschmidt	ic->ic_raw_xmit = rt2860_raw_xmit;
343235233Sbschmidt	sc->sc_node_free = ic->ic_node_free;
344235233Sbschmidt	ic->ic_node_free = rt2860_node_free;
345235233Sbschmidt	ic->ic_newassoc = rt2860_newassoc;
346287197Sglebius	ic->ic_transmit = rt2860_transmit;
347287197Sglebius	ic->ic_parent = rt2860_parent;
348235233Sbschmidt	ic->ic_vap_create = rt2860_vap_create;
349235233Sbschmidt	ic->ic_vap_delete = rt2860_vap_delete;
350235233Sbschmidt
351235233Sbschmidt	ieee80211_radiotap_attach(ic,
352235233Sbschmidt	    &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap),
353235233Sbschmidt		RT2860_TX_RADIOTAP_PRESENT,
354235233Sbschmidt	    &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap),
355235233Sbschmidt		RT2860_RX_RADIOTAP_PRESENT);
356235233Sbschmidt
357235233Sbschmidt#ifdef RAL_DEBUG
358235233Sbschmidt	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
359235233Sbschmidt	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
360235233Sbschmidt	    "debug", CTLFLAG_RW, &sc->sc_debug, 0, "debug msgs");
361235233Sbschmidt#endif
362235233Sbschmidt	if (bootverbose)
363235233Sbschmidt		ieee80211_announce(ic);
364235233Sbschmidt
365235233Sbschmidt	return 0;
366235233Sbschmidt
367235233Sbschmidtfail3:	rt2860_free_rx_ring(sc, &sc->rxq);
368235233Sbschmidtfail2:	while (--qid >= 0)
369235233Sbschmidt		rt2860_free_tx_ring(sc, &sc->txq[qid]);
370235233Sbschmidtfail1:	mtx_destroy(&sc->sc_mtx);
371235233Sbschmidt	return error;
372235233Sbschmidt}
373235233Sbschmidt
374235233Sbschmidtint
375235233Sbschmidtrt2860_detach(void *xsc)
376235233Sbschmidt{
377235233Sbschmidt	struct rt2860_softc *sc = xsc;
378287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
379235233Sbschmidt	int qid;
380235233Sbschmidt
381235233Sbschmidt	RAL_LOCK(sc);
382235233Sbschmidt	rt2860_stop_locked(sc);
383235233Sbschmidt	RAL_UNLOCK(sc);
384235233Sbschmidt
385235233Sbschmidt	ieee80211_ifdetach(ic);
386287197Sglebius	mbufq_drain(&sc->sc_snd);
387235233Sbschmidt	for (qid = 0; qid < 6; qid++)
388235233Sbschmidt		rt2860_free_tx_ring(sc, &sc->txq[qid]);
389235233Sbschmidt	rt2860_free_rx_ring(sc, &sc->rxq);
390235233Sbschmidt	rt2860_free_tx_pool(sc);
391235233Sbschmidt
392235233Sbschmidt	mtx_destroy(&sc->sc_mtx);
393235233Sbschmidt
394235233Sbschmidt	return 0;
395235233Sbschmidt}
396235233Sbschmidt
397235233Sbschmidtvoid
398235233Sbschmidtrt2860_shutdown(void *xsc)
399235233Sbschmidt{
400235233Sbschmidt	struct rt2860_softc *sc = xsc;
401235233Sbschmidt
402235233Sbschmidt	rt2860_stop(sc);
403235233Sbschmidt}
404235233Sbschmidt
405235233Sbschmidtvoid
406235233Sbschmidtrt2860_suspend(void *xsc)
407235233Sbschmidt{
408235233Sbschmidt	struct rt2860_softc *sc = xsc;
409235233Sbschmidt
410235233Sbschmidt	rt2860_stop(sc);
411235233Sbschmidt}
412235233Sbschmidt
413235233Sbschmidtvoid
414235233Sbschmidtrt2860_resume(void *xsc)
415235233Sbschmidt{
416235233Sbschmidt	struct rt2860_softc *sc = xsc;
417235233Sbschmidt
418287197Sglebius	if (sc->sc_ic.ic_nrunning > 0)
419235233Sbschmidt		rt2860_init(sc);
420235233Sbschmidt}
421235233Sbschmidt
422235233Sbschmidtstatic struct ieee80211vap *
423235233Sbschmidtrt2860_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
424235233Sbschmidt    enum ieee80211_opmode opmode, int flags,
425235233Sbschmidt    const uint8_t bssid[IEEE80211_ADDR_LEN],
426235233Sbschmidt    const uint8_t mac[IEEE80211_ADDR_LEN])
427235233Sbschmidt{
428287197Sglebius	struct rt2860_softc *sc = ic->ic_softc;
429235233Sbschmidt	struct rt2860_vap *rvp;
430235233Sbschmidt	struct ieee80211vap *vap;
431235233Sbschmidt
432235233Sbschmidt	switch (opmode) {
433235233Sbschmidt	case IEEE80211_M_STA:
434235233Sbschmidt	case IEEE80211_M_IBSS:
435235233Sbschmidt	case IEEE80211_M_AHDEMO:
436235233Sbschmidt	case IEEE80211_M_MONITOR:
437235233Sbschmidt	case IEEE80211_M_HOSTAP:
438235233Sbschmidt	case IEEE80211_M_MBSS:
439235233Sbschmidt		/* XXXRP: TBD */
440235233Sbschmidt		if (!TAILQ_EMPTY(&ic->ic_vaps)) {
441287197Sglebius			device_printf(sc->sc_dev, "only 1 vap supported\n");
442235233Sbschmidt			return NULL;
443235233Sbschmidt		}
444235233Sbschmidt		if (opmode == IEEE80211_M_STA)
445235233Sbschmidt			flags |= IEEE80211_CLONE_NOBEACONS;
446235233Sbschmidt		break;
447235233Sbschmidt	case IEEE80211_M_WDS:
448235233Sbschmidt		if (TAILQ_EMPTY(&ic->ic_vaps) ||
449235233Sbschmidt		    ic->ic_opmode != IEEE80211_M_HOSTAP) {
450287197Sglebius			device_printf(sc->sc_dev,
451287197Sglebius			    "wds only supported in ap mode\n");
452235233Sbschmidt			return NULL;
453235233Sbschmidt		}
454235233Sbschmidt		/*
455235233Sbschmidt		 * Silently remove any request for a unique
456235233Sbschmidt		 * bssid; WDS vap's always share the local
457235233Sbschmidt		 * mac address.
458235233Sbschmidt		 */
459235233Sbschmidt		flags &= ~IEEE80211_CLONE_BSSID;
460235233Sbschmidt		break;
461235233Sbschmidt	default:
462287197Sglebius		device_printf(sc->sc_dev, "unknown opmode %d\n", opmode);
463235233Sbschmidt		return NULL;
464235233Sbschmidt	}
465287197Sglebius	rvp = malloc(sizeof(struct rt2860_vap), M_80211_VAP, M_WAITOK | M_ZERO);
466235233Sbschmidt	vap = &rvp->ral_vap;
467287197Sglebius	ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid);
468235233Sbschmidt
469235233Sbschmidt	/* override state transition machine */
470235233Sbschmidt	rvp->ral_newstate = vap->iv_newstate;
471235233Sbschmidt	vap->iv_newstate = rt2860_newstate;
472235233Sbschmidt#if 0
473235233Sbschmidt	vap->iv_update_beacon = rt2860_beacon_update;
474235233Sbschmidt#endif
475235233Sbschmidt
476235233Sbschmidt	/* HW supports up to 255 STAs (0-254) in HostAP and IBSS modes */
477235233Sbschmidt	vap->iv_max_aid = min(IEEE80211_AID_MAX, RT2860_WCID_MAX);
478235233Sbschmidt
479235233Sbschmidt	ieee80211_ratectl_init(vap);
480235233Sbschmidt	/* complete setup */
481287197Sglebius	ieee80211_vap_attach(vap, ieee80211_media_change,
482287197Sglebius	    ieee80211_media_status, mac);
483235233Sbschmidt	if (TAILQ_FIRST(&ic->ic_vaps) == vap)
484235233Sbschmidt		ic->ic_opmode = opmode;
485235233Sbschmidt	return vap;
486235233Sbschmidt}
487235233Sbschmidt
488235233Sbschmidtstatic void
489235233Sbschmidtrt2860_vap_delete(struct ieee80211vap *vap)
490235233Sbschmidt{
491235233Sbschmidt	struct rt2860_vap *rvp = RT2860_VAP(vap);
492235233Sbschmidt
493235233Sbschmidt	ieee80211_ratectl_deinit(vap);
494235233Sbschmidt	ieee80211_vap_detach(vap);
495235233Sbschmidt	free(rvp, M_80211_VAP);
496235233Sbschmidt}
497235233Sbschmidt
498235233Sbschmidtstatic void
499235233Sbschmidtrt2860_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
500235233Sbschmidt{
501235233Sbschmidt	if (error != 0)
502235233Sbschmidt		return;
503235233Sbschmidt
504235233Sbschmidt	KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
505235233Sbschmidt
506235233Sbschmidt	*(bus_addr_t *)arg = segs[0].ds_addr;
507235233Sbschmidt}
508235233Sbschmidt
509235233Sbschmidt
510235233Sbschmidtstatic int
511235233Sbschmidtrt2860_alloc_tx_ring(struct rt2860_softc *sc, struct rt2860_tx_ring *ring)
512235233Sbschmidt{
513235233Sbschmidt	int size, error;
514235233Sbschmidt
515235233Sbschmidt	size = RT2860_TX_RING_COUNT * sizeof (struct rt2860_txd);
516235233Sbschmidt
517235233Sbschmidt	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 16, 0,
518235233Sbschmidt	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
519235233Sbschmidt	    size, 1, size, 0, NULL, NULL, &ring->desc_dmat);
520235233Sbschmidt	if (error != 0) {
521290133Skevlo		device_printf(sc->sc_dev, "could not create desc DMA tag\n");
522235233Sbschmidt		goto fail;
523235233Sbschmidt	}
524235233Sbschmidt
525235233Sbschmidt	error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->txd,
526235233Sbschmidt	    BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map);
527235233Sbschmidt	if (error != 0) {
528235233Sbschmidt		device_printf(sc->sc_dev, "could not allocate DMA memory\n");
529235233Sbschmidt		goto fail;
530235233Sbschmidt	}
531235233Sbschmidt
532235233Sbschmidt	error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->txd,
533235233Sbschmidt	    size, rt2860_dma_map_addr, &ring->paddr, 0);
534235233Sbschmidt	if (error != 0) {
535235233Sbschmidt		device_printf(sc->sc_dev, "could not load desc DMA map\n");
536235233Sbschmidt		goto fail;
537235233Sbschmidt	}
538235233Sbschmidt
539235233Sbschmidt	bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE);
540235233Sbschmidt
541235233Sbschmidt	return 0;
542235233Sbschmidt
543235233Sbschmidtfail:	rt2860_free_tx_ring(sc, ring);
544235233Sbschmidt	return error;
545235233Sbschmidt}
546235233Sbschmidt
547235233Sbschmidtvoid
548235233Sbschmidtrt2860_reset_tx_ring(struct rt2860_softc *sc, struct rt2860_tx_ring *ring)
549235233Sbschmidt{
550235233Sbschmidt	struct rt2860_tx_data *data;
551235233Sbschmidt	int i;
552235233Sbschmidt
553235233Sbschmidt	for (i = 0; i < RT2860_TX_RING_COUNT; i++) {
554235233Sbschmidt		if ((data = ring->data[i]) == NULL)
555235233Sbschmidt			continue;	/* nothing mapped in this slot */
556235233Sbschmidt
557235233Sbschmidt		if (data->m != NULL) {
558235233Sbschmidt			bus_dmamap_sync(sc->txwi_dmat, data->map,
559235233Sbschmidt			    BUS_DMASYNC_POSTWRITE);
560235233Sbschmidt			bus_dmamap_unload(sc->txwi_dmat, data->map);
561235233Sbschmidt			m_freem(data->m);
562235233Sbschmidt			data->m = NULL;
563235233Sbschmidt		}
564235233Sbschmidt		if (data->ni != NULL) {
565235233Sbschmidt			ieee80211_free_node(data->ni);
566235233Sbschmidt			data->ni = NULL;
567235233Sbschmidt		}
568235233Sbschmidt
569235233Sbschmidt		SLIST_INSERT_HEAD(&sc->data_pool, data, next);
570235233Sbschmidt		ring->data[i] = NULL;
571235233Sbschmidt	}
572235233Sbschmidt
573235233Sbschmidt	ring->queued = 0;
574235233Sbschmidt	ring->cur = ring->next = 0;
575235233Sbschmidt}
576235233Sbschmidt
577235233Sbschmidtvoid
578235233Sbschmidtrt2860_free_tx_ring(struct rt2860_softc *sc, struct rt2860_tx_ring *ring)
579235233Sbschmidt{
580235233Sbschmidt	struct rt2860_tx_data *data;
581235233Sbschmidt	int i;
582235233Sbschmidt
583235233Sbschmidt	if (ring->txd != NULL) {
584235233Sbschmidt		bus_dmamap_sync(ring->desc_dmat, ring->desc_map,
585235233Sbschmidt		    BUS_DMASYNC_POSTWRITE);
586235233Sbschmidt		bus_dmamap_unload(ring->desc_dmat, ring->desc_map);
587235233Sbschmidt		bus_dmamem_free(ring->desc_dmat, ring->txd, ring->desc_map);
588235233Sbschmidt	}
589235233Sbschmidt	if (ring->desc_dmat != NULL)
590235233Sbschmidt		bus_dma_tag_destroy(ring->desc_dmat);
591235233Sbschmidt
592235233Sbschmidt	for (i = 0; i < RT2860_TX_RING_COUNT; i++) {
593235233Sbschmidt		if ((data = ring->data[i]) == NULL)
594235233Sbschmidt			continue;	/* nothing mapped in this slot */
595235233Sbschmidt
596235233Sbschmidt		if (data->m != NULL) {
597235233Sbschmidt			bus_dmamap_sync(sc->txwi_dmat, data->map,
598235233Sbschmidt			    BUS_DMASYNC_POSTWRITE);
599235233Sbschmidt			bus_dmamap_unload(sc->txwi_dmat, data->map);
600235233Sbschmidt			m_freem(data->m);
601235233Sbschmidt		}
602235233Sbschmidt		if (data->ni != NULL)
603235233Sbschmidt			ieee80211_free_node(data->ni);
604235233Sbschmidt
605235233Sbschmidt		SLIST_INSERT_HEAD(&sc->data_pool, data, next);
606235233Sbschmidt	}
607235233Sbschmidt}
608235233Sbschmidt
609235233Sbschmidt/*
610235233Sbschmidt * Allocate a pool of TX Wireless Information blocks.
611235233Sbschmidt */
612235233Sbschmidtint
613235233Sbschmidtrt2860_alloc_tx_pool(struct rt2860_softc *sc)
614235233Sbschmidt{
615235233Sbschmidt	caddr_t vaddr;
616235233Sbschmidt	bus_addr_t paddr;
617235233Sbschmidt	int i, size, error;
618235233Sbschmidt
619235233Sbschmidt	size = RT2860_TX_POOL_COUNT * RT2860_TXWI_DMASZ;
620235233Sbschmidt
621235233Sbschmidt	/* init data_pool early in case of failure.. */
622235233Sbschmidt	SLIST_INIT(&sc->data_pool);
623235233Sbschmidt
624235233Sbschmidt	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0,
625235233Sbschmidt	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
626235233Sbschmidt	    size, 1, size, 0, NULL, NULL, &sc->txwi_dmat);
627235233Sbschmidt	if (error != 0) {
628235233Sbschmidt		device_printf(sc->sc_dev, "could not create txwi DMA tag\n");
629235233Sbschmidt		goto fail;
630235233Sbschmidt	}
631235233Sbschmidt
632235233Sbschmidt	error = bus_dmamem_alloc(sc->txwi_dmat, (void **)&sc->txwi_vaddr,
633235233Sbschmidt	    BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sc->txwi_map);
634235233Sbschmidt	if (error != 0) {
635235233Sbschmidt		device_printf(sc->sc_dev, "could not allocate DMA memory\n");
636235233Sbschmidt		goto fail;
637235233Sbschmidt	}
638235233Sbschmidt
639235233Sbschmidt	error = bus_dmamap_load(sc->txwi_dmat, sc->txwi_map,
640235233Sbschmidt	    sc->txwi_vaddr, size, rt2860_dma_map_addr, &paddr, 0);
641235233Sbschmidt	if (error != 0) {
642235233Sbschmidt		device_printf(sc->sc_dev, "could not load txwi DMA map\n");
643235233Sbschmidt		goto fail;
644235233Sbschmidt	}
645235233Sbschmidt
646235233Sbschmidt	bus_dmamap_sync(sc->txwi_dmat, sc->txwi_map, BUS_DMASYNC_PREWRITE);
647235233Sbschmidt
648235233Sbschmidt	vaddr = sc->txwi_vaddr;
649235233Sbschmidt	for (i = 0; i < RT2860_TX_POOL_COUNT; i++) {
650235233Sbschmidt		struct rt2860_tx_data *data = &sc->data[i];
651235233Sbschmidt
652235233Sbschmidt		error = bus_dmamap_create(sc->txwi_dmat, 0, &data->map);
653235233Sbschmidt		if (error != 0) {
654235233Sbschmidt			device_printf(sc->sc_dev, "could not create DMA map\n");
655235233Sbschmidt			goto fail;
656235233Sbschmidt		}
657235233Sbschmidt		data->txwi = (struct rt2860_txwi *)vaddr;
658235233Sbschmidt		data->paddr = paddr;
659235233Sbschmidt		vaddr += RT2860_TXWI_DMASZ;
660235233Sbschmidt		paddr += RT2860_TXWI_DMASZ;
661235233Sbschmidt
662235233Sbschmidt		SLIST_INSERT_HEAD(&sc->data_pool, data, next);
663235233Sbschmidt	}
664235233Sbschmidt
665235233Sbschmidt	return 0;
666235233Sbschmidt
667235233Sbschmidtfail:	rt2860_free_tx_pool(sc);
668235233Sbschmidt	return error;
669235233Sbschmidt}
670235233Sbschmidt
671235233Sbschmidtvoid
672235233Sbschmidtrt2860_free_tx_pool(struct rt2860_softc *sc)
673235233Sbschmidt{
674235233Sbschmidt	if (sc->txwi_vaddr != NULL) {
675235233Sbschmidt		bus_dmamap_sync(sc->txwi_dmat, sc->txwi_map,
676235233Sbschmidt		    BUS_DMASYNC_POSTWRITE);
677235233Sbschmidt		bus_dmamap_unload(sc->txwi_dmat, sc->txwi_map);
678235233Sbschmidt		bus_dmamem_free(sc->txwi_dmat, sc->txwi_vaddr, sc->txwi_map);
679235233Sbschmidt	}
680235233Sbschmidt	if (sc->txwi_dmat != NULL)
681235233Sbschmidt		bus_dma_tag_destroy(sc->txwi_dmat);
682235233Sbschmidt
683235233Sbschmidt	while (!SLIST_EMPTY(&sc->data_pool)) {
684235233Sbschmidt		struct rt2860_tx_data *data;
685235233Sbschmidt		data = SLIST_FIRST(&sc->data_pool);
686235233Sbschmidt		bus_dmamap_destroy(sc->txwi_dmat, data->map);
687235233Sbschmidt		SLIST_REMOVE_HEAD(&sc->data_pool, next);
688235233Sbschmidt	}
689235233Sbschmidt}
690235233Sbschmidt
691235233Sbschmidtint
692235233Sbschmidtrt2860_alloc_rx_ring(struct rt2860_softc *sc, struct rt2860_rx_ring *ring)
693235233Sbschmidt{
694235233Sbschmidt	bus_addr_t physaddr;
695235233Sbschmidt	int i, size, error;
696235233Sbschmidt
697235233Sbschmidt	size = RT2860_RX_RING_COUNT * sizeof (struct rt2860_rxd);
698235233Sbschmidt
699235233Sbschmidt	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 16, 0,
700235233Sbschmidt	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
701235233Sbschmidt	    size, 1, size, 0, NULL, NULL, &ring->desc_dmat);
702235233Sbschmidt	if (error != 0) {
703235233Sbschmidt		device_printf(sc->sc_dev, "could not create desc DMA tag\n");
704235233Sbschmidt		goto fail;
705235233Sbschmidt	}
706235233Sbschmidt
707235233Sbschmidt	error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->rxd,
708235233Sbschmidt	    BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map);
709235233Sbschmidt	if (error != 0) {
710235233Sbschmidt		device_printf(sc->sc_dev, "could not allocate DMA memory\n");
711235233Sbschmidt		goto fail;
712235233Sbschmidt	}
713235233Sbschmidt
714235233Sbschmidt	error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->rxd,
715235233Sbschmidt	    size, rt2860_dma_map_addr, &ring->paddr, 0);
716235233Sbschmidt	if (error != 0) {
717235233Sbschmidt		device_printf(sc->sc_dev, "could not load desc DMA map\n");
718235233Sbschmidt		goto fail;
719235233Sbschmidt	}
720235233Sbschmidt
721235233Sbschmidt	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0,
722235233Sbschmidt	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES,
723235233Sbschmidt	    1, MCLBYTES, 0, NULL, NULL, &ring->data_dmat);
724235233Sbschmidt	if (error != 0) {
725235233Sbschmidt		device_printf(sc->sc_dev, "could not create data DMA tag\n");
726235233Sbschmidt		goto fail;
727235233Sbschmidt	}
728235233Sbschmidt
729235233Sbschmidt	for (i = 0; i < RT2860_RX_RING_COUNT; i++) {
730235233Sbschmidt		struct rt2860_rx_data *data = &ring->data[i];
731235233Sbschmidt		struct rt2860_rxd *rxd = &ring->rxd[i];
732235233Sbschmidt
733235233Sbschmidt		error = bus_dmamap_create(ring->data_dmat, 0, &data->map);
734235233Sbschmidt		if (error != 0) {
735235233Sbschmidt			device_printf(sc->sc_dev, "could not create DMA map\n");
736235233Sbschmidt			goto fail;
737235233Sbschmidt		}
738235233Sbschmidt
739243857Sglebius		data->m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
740235233Sbschmidt		if (data->m == NULL) {
741235233Sbschmidt			device_printf(sc->sc_dev,
742235233Sbschmidt			    "could not allocate rx mbuf\n");
743235233Sbschmidt			error = ENOMEM;
744235233Sbschmidt			goto fail;
745235233Sbschmidt		}
746235233Sbschmidt
747235233Sbschmidt		error = bus_dmamap_load(ring->data_dmat, data->map,
748235233Sbschmidt		    mtod(data->m, void *), MCLBYTES, rt2860_dma_map_addr,
749235233Sbschmidt		    &physaddr, 0);
750235233Sbschmidt		if (error != 0) {
751235233Sbschmidt			device_printf(sc->sc_dev,
752235233Sbschmidt			    "could not load rx buf DMA map");
753235233Sbschmidt			goto fail;
754235233Sbschmidt		}
755235233Sbschmidt
756235233Sbschmidt		rxd->sdp0 = htole32(physaddr);
757235233Sbschmidt		rxd->sdl0 = htole16(MCLBYTES);
758235233Sbschmidt	}
759235233Sbschmidt
760235233Sbschmidt	bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE);
761235233Sbschmidt
762235233Sbschmidt	return 0;
763235233Sbschmidt
764235233Sbschmidtfail:	rt2860_free_rx_ring(sc, ring);
765235233Sbschmidt	return error;
766235233Sbschmidt}
767235233Sbschmidt
768235233Sbschmidtvoid
769235233Sbschmidtrt2860_reset_rx_ring(struct rt2860_softc *sc, struct rt2860_rx_ring *ring)
770235233Sbschmidt{
771235233Sbschmidt	int i;
772235233Sbschmidt
773235233Sbschmidt	for (i = 0; i < RT2860_RX_RING_COUNT; i++)
774235233Sbschmidt		ring->rxd[i].sdl0 &= ~htole16(RT2860_RX_DDONE);
775235233Sbschmidt
776235233Sbschmidt	bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE);
777235233Sbschmidt
778235233Sbschmidt	ring->cur = 0;
779235233Sbschmidt}
780235233Sbschmidt
781235233Sbschmidtvoid
782235233Sbschmidtrt2860_free_rx_ring(struct rt2860_softc *sc, struct rt2860_rx_ring *ring)
783235233Sbschmidt{
784235233Sbschmidt	int i;
785235233Sbschmidt
786235233Sbschmidt	if (ring->rxd != NULL) {
787235233Sbschmidt		bus_dmamap_sync(ring->desc_dmat, ring->desc_map,
788235233Sbschmidt		    BUS_DMASYNC_POSTWRITE);
789235233Sbschmidt		bus_dmamap_unload(ring->desc_dmat, ring->desc_map);
790235233Sbschmidt		bus_dmamem_free(ring->desc_dmat, ring->rxd, ring->desc_map);
791235233Sbschmidt	}
792235233Sbschmidt	if (ring->desc_dmat != NULL)
793235233Sbschmidt		bus_dma_tag_destroy(ring->desc_dmat);
794235233Sbschmidt
795235233Sbschmidt	for (i = 0; i < RT2860_RX_RING_COUNT; i++) {
796235233Sbschmidt		struct rt2860_rx_data *data = &ring->data[i];
797235233Sbschmidt
798235233Sbschmidt		if (data->m != NULL) {
799235233Sbschmidt			bus_dmamap_sync(ring->data_dmat, data->map,
800235233Sbschmidt			    BUS_DMASYNC_POSTREAD);
801235233Sbschmidt			bus_dmamap_unload(ring->data_dmat, data->map);
802235233Sbschmidt			m_freem(data->m);
803235233Sbschmidt		}
804235233Sbschmidt		if (data->map != NULL)
805235233Sbschmidt			bus_dmamap_destroy(ring->data_dmat, data->map);
806235233Sbschmidt	}
807235233Sbschmidt	if (ring->data_dmat != NULL)
808235233Sbschmidt		bus_dma_tag_destroy(ring->data_dmat);
809235233Sbschmidt}
810235233Sbschmidt
811235233Sbschmidtstatic void
812235233Sbschmidtrt2860_updatestats(struct rt2860_softc *sc)
813235233Sbschmidt{
814287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
815235233Sbschmidt
816235233Sbschmidt	/*
817235233Sbschmidt	 * In IBSS or HostAP modes (when the hardware sends beacons), the
818235233Sbschmidt	 * MAC can run into a livelock and start sending CTS-to-self frames
819235233Sbschmidt	 * like crazy if protection is enabled.  Fortunately, we can detect
820235233Sbschmidt	 * when such a situation occurs and reset the MAC.
821235233Sbschmidt	 */
822235233Sbschmidt	if (ic->ic_curmode != IEEE80211_M_STA) {
823235233Sbschmidt		/* check if we're in a livelock situation.. */
824235233Sbschmidt		uint32_t tmp = RAL_READ(sc, RT2860_DEBUG);
825235233Sbschmidt		if ((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))) {
826235233Sbschmidt			/* ..and reset MAC/BBP for a while.. */
827235233Sbschmidt			DPRINTF(("CTS-to-self livelock detected\n"));
828235233Sbschmidt			RAL_WRITE(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST);
829235233Sbschmidt			RAL_BARRIER_WRITE(sc);
830235233Sbschmidt			DELAY(1);
831235233Sbschmidt			RAL_WRITE(sc, RT2860_MAC_SYS_CTRL,
832235233Sbschmidt			    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
833235233Sbschmidt		}
834235233Sbschmidt	}
835235233Sbschmidt}
836235233Sbschmidt
837235233Sbschmidtstatic void
838235233Sbschmidtrt2860_newassoc(struct ieee80211_node *ni, int isnew)
839235233Sbschmidt{
840235233Sbschmidt	struct ieee80211com *ic = ni->ni_ic;
841287197Sglebius	struct rt2860_softc *sc = ic->ic_softc;
842235233Sbschmidt	uint8_t wcid;
843235233Sbschmidt
844235233Sbschmidt	wcid = IEEE80211_AID(ni->ni_associd);
845235233Sbschmidt	if (isnew && ni->ni_associd != 0) {
846235233Sbschmidt		sc->wcid2ni[wcid] = ni;
847235233Sbschmidt
848235233Sbschmidt		/* init WCID table entry */
849235233Sbschmidt		RAL_WRITE_REGION_1(sc, RT2860_WCID_ENTRY(wcid),
850235233Sbschmidt		    ni->ni_macaddr, IEEE80211_ADDR_LEN);
851235233Sbschmidt	}
852235233Sbschmidt	DPRINTF(("new assoc isnew=%d addr=%s WCID=%d\n",
853235233Sbschmidt	    isnew, ether_sprintf(ni->ni_macaddr), wcid));
854235233Sbschmidt}
855235233Sbschmidt
856235233Sbschmidtstatic void
857235233Sbschmidtrt2860_node_free(struct ieee80211_node *ni)
858235233Sbschmidt{
859235233Sbschmidt	struct ieee80211com *ic = ni->ni_ic;
860287197Sglebius	struct rt2860_softc *sc = ic->ic_softc;
861235233Sbschmidt	uint8_t wcid;
862235233Sbschmidt
863235233Sbschmidt	if (ni->ni_associd != 0) {
864235233Sbschmidt		wcid = IEEE80211_AID(ni->ni_associd);
865235233Sbschmidt
866235233Sbschmidt		/* clear Rx WCID search table entry */
867235233Sbschmidt		RAL_SET_REGION_4(sc, RT2860_WCID_ENTRY(wcid), 0, 2);
868235233Sbschmidt	}
869235233Sbschmidt	sc->sc_node_free(ni);
870235233Sbschmidt}
871235233Sbschmidt
872235233Sbschmidt#ifdef IEEE80211_HT
873235233Sbschmidtstatic int
874235233Sbschmidtrt2860_ampdu_rx_start(struct ieee80211com *ic, struct ieee80211_node *ni,
875235233Sbschmidt    uint8_t tid)
876235233Sbschmidt{
877235233Sbschmidt	struct rt2860_softc *sc = ic->ic_softc;
878235233Sbschmidt	uint8_t wcid = ((struct rt2860_node *)ni)->wcid;
879235233Sbschmidt	uint32_t tmp;
880235233Sbschmidt
881235233Sbschmidt	/* update BA session mask */
882235233Sbschmidt	tmp = RAL_READ(sc, RT2860_WCID_ENTRY(wcid) + 4);
883235233Sbschmidt	tmp |= (1 << tid) << 16;
884235233Sbschmidt	RAL_WRITE(sc, RT2860_WCID_ENTRY(wcid) + 4, tmp);
885235233Sbschmidt	return 0;
886235233Sbschmidt}
887235233Sbschmidt
888235233Sbschmidtstatic void
889235233Sbschmidtrt2860_ampdu_rx_stop(struct ieee80211com *ic, struct ieee80211_node *ni,
890235233Sbschmidt    uint8_t tid)
891235233Sbschmidt{
892235233Sbschmidt	struct rt2860_softc *sc = ic->ic_softc;
893235233Sbschmidt	uint8_t wcid = ((struct rt2860_node *)ni)->wcid;
894235233Sbschmidt	uint32_t tmp;
895235233Sbschmidt
896235233Sbschmidt	/* update BA session mask */
897235233Sbschmidt	tmp = RAL_READ(sc, RT2860_WCID_ENTRY(wcid) + 4);
898235233Sbschmidt	tmp &= ~((1 << tid) << 16);
899235233Sbschmidt	RAL_WRITE(sc, RT2860_WCID_ENTRY(wcid) + 4, tmp);
900235233Sbschmidt}
901235233Sbschmidt#endif
902235233Sbschmidt
903301575Skevlostatic int
904235233Sbschmidtrt2860_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
905235233Sbschmidt{
906235233Sbschmidt	struct rt2860_vap *rvp = RT2860_VAP(vap);
907235233Sbschmidt	struct ieee80211com *ic = vap->iv_ic;
908287197Sglebius	struct rt2860_softc *sc = ic->ic_softc;
909235233Sbschmidt	uint32_t tmp;
910235233Sbschmidt	int error;
911235233Sbschmidt
912235233Sbschmidt	if (vap->iv_state == IEEE80211_S_RUN) {
913235233Sbschmidt		/* turn link LED off */
914235233Sbschmidt		rt2860_set_leds(sc, RT2860_LED_RADIO);
915235233Sbschmidt	}
916235233