rt2560.c revision 171086
1156321Sdamien/*	$FreeBSD: head/sys/dev/ral/rt2560.c 171086 2007-06-29 02:43:13Z kevlo $	*/
2156321Sdamien
3156321Sdamien/*-
4156321Sdamien * Copyright (c) 2005, 2006
5156321Sdamien *	Damien Bergamini <damien.bergamini@free.fr>
6156321Sdamien *
7156321Sdamien * Permission to use, copy, modify, and distribute this software for any
8156321Sdamien * purpose with or without fee is hereby granted, provided that the above
9156321Sdamien * copyright notice and this permission notice appear in all copies.
10156321Sdamien *
11156321Sdamien * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12156321Sdamien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13156321Sdamien * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14156321Sdamien * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15156321Sdamien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16156321Sdamien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17156321Sdamien * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18156321Sdamien */
19156321Sdamien
20156321Sdamien#include <sys/cdefs.h>
21156321Sdamien__FBSDID("$FreeBSD: head/sys/dev/ral/rt2560.c 171086 2007-06-29 02:43:13Z kevlo $");
22156321Sdamien
23156321Sdamien/*-
24156321Sdamien * Ralink Technology RT2560 chipset driver
25156321Sdamien * http://www.ralinktech.com/
26156321Sdamien */
27156321Sdamien
28156321Sdamien#include <sys/param.h>
29156321Sdamien#include <sys/sysctl.h>
30156321Sdamien#include <sys/sockio.h>
31156321Sdamien#include <sys/mbuf.h>
32156321Sdamien#include <sys/kernel.h>
33156321Sdamien#include <sys/socket.h>
34156321Sdamien#include <sys/systm.h>
35156321Sdamien#include <sys/malloc.h>
36164982Skevlo#include <sys/lock.h>
37164982Skevlo#include <sys/mutex.h>
38156321Sdamien#include <sys/module.h>
39156321Sdamien#include <sys/bus.h>
40156321Sdamien#include <sys/endian.h>
41156321Sdamien
42156321Sdamien#include <machine/bus.h>
43156321Sdamien#include <machine/resource.h>
44156321Sdamien#include <sys/rman.h>
45156321Sdamien
46156321Sdamien#include <net/bpf.h>
47156321Sdamien#include <net/if.h>
48156321Sdamien#include <net/if_arp.h>
49156321Sdamien#include <net/ethernet.h>
50156321Sdamien#include <net/if_dl.h>
51156321Sdamien#include <net/if_media.h>
52156321Sdamien#include <net/if_types.h>
53156321Sdamien
54156321Sdamien#include <net80211/ieee80211_var.h>
55156321Sdamien#include <net80211/ieee80211_radiotap.h>
56170530Ssam#include <net80211/ieee80211_regdomain.h>
57156321Sdamien
58156321Sdamien#include <netinet/in.h>
59156321Sdamien#include <netinet/in_systm.h>
60156321Sdamien#include <netinet/in_var.h>
61156321Sdamien#include <netinet/ip.h>
62156321Sdamien#include <netinet/if_ether.h>
63156321Sdamien
64156327Ssilby#include <dev/ral/if_ralrate.h>
65156327Ssilby#include <dev/ral/rt2560reg.h>
66156327Ssilby#include <dev/ral/rt2560var.h>
67156321Sdamien
68170530Ssam#define RT2560_RSSI(sc, rssi)					\
69170530Ssam	((rssi) > (RT2560_NOISE_FLOOR + (sc)->rssi_corr) ?	\
70170530Ssam	 ((rssi) - RT2560_NOISE_FLOOR - (sc)->rssi_corr) : 0)
71170530Ssam
72156321Sdamien#ifdef RAL_DEBUG
73156321Sdamien#define DPRINTF(x)	do { if (ral_debug > 0) printf x; } while (0)
74156321Sdamien#define DPRINTFN(n, x)	do { if (ral_debug >= (n)) printf x; } while (0)
75156321Sdamienextern int ral_debug;
76156321Sdamien#else
77156321Sdamien#define DPRINTF(x)
78156321Sdamien#define DPRINTFN(n, x)
79156321Sdamien#endif
80156321Sdamien
81156321Sdamienstatic void		rt2560_dma_map_addr(void *, bus_dma_segment_t *, int,
82156321Sdamien			    int);
83156321Sdamienstatic int		rt2560_alloc_tx_ring(struct rt2560_softc *,
84156321Sdamien			    struct rt2560_tx_ring *, int);
85156321Sdamienstatic void		rt2560_reset_tx_ring(struct rt2560_softc *,
86156321Sdamien			    struct rt2560_tx_ring *);
87156321Sdamienstatic void		rt2560_free_tx_ring(struct rt2560_softc *,
88156321Sdamien			    struct rt2560_tx_ring *);
89156321Sdamienstatic int		rt2560_alloc_rx_ring(struct rt2560_softc *,
90156321Sdamien			    struct rt2560_rx_ring *, int);
91156321Sdamienstatic void		rt2560_reset_rx_ring(struct rt2560_softc *,
92156321Sdamien			    struct rt2560_rx_ring *);
93156321Sdamienstatic void		rt2560_free_rx_ring(struct rt2560_softc *,
94156321Sdamien			    struct rt2560_rx_ring *);
95156321Sdamienstatic struct		ieee80211_node *rt2560_node_alloc(
96156321Sdamien			    struct ieee80211_node_table *);
97156321Sdamienstatic int		rt2560_media_change(struct ifnet *);
98156321Sdamienstatic void		rt2560_iter_func(void *, struct ieee80211_node *);
99156321Sdamienstatic void		rt2560_update_rssadapt(void *);
100156321Sdamienstatic int		rt2560_newstate(struct ieee80211com *,
101156321Sdamien			    enum ieee80211_state, int);
102156321Sdamienstatic uint16_t		rt2560_eeprom_read(struct rt2560_softc *, uint8_t);
103156321Sdamienstatic void		rt2560_encryption_intr(struct rt2560_softc *);
104156321Sdamienstatic void		rt2560_tx_intr(struct rt2560_softc *);
105156321Sdamienstatic void		rt2560_prio_intr(struct rt2560_softc *);
106156321Sdamienstatic void		rt2560_decryption_intr(struct rt2560_softc *);
107156321Sdamienstatic void		rt2560_rx_intr(struct rt2560_softc *);
108156321Sdamienstatic void		rt2560_beacon_expire(struct rt2560_softc *);
109156321Sdamienstatic void		rt2560_wakeup_expire(struct rt2560_softc *);
110156321Sdamienstatic uint8_t		rt2560_rxrate(struct rt2560_rx_desc *);
111156321Sdamienstatic int		rt2560_ack_rate(struct ieee80211com *, int);
112170530Ssamstatic void		rt2560_scan_start(struct ieee80211com *);
113170530Ssamstatic void		rt2560_scan_end(struct ieee80211com *);
114170530Ssamstatic void		rt2560_set_channel(struct ieee80211com *);
115156321Sdamienstatic uint16_t		rt2560_txtime(int, int, uint32_t);
116156321Sdamienstatic uint8_t		rt2560_plcp_signal(int);
117156321Sdamienstatic void		rt2560_setup_tx_desc(struct rt2560_softc *,
118156321Sdamien			    struct rt2560_tx_desc *, uint32_t, int, int, int,
119156321Sdamien			    bus_addr_t);
120156321Sdamienstatic int		rt2560_tx_bcn(struct rt2560_softc *, struct mbuf *,
121156321Sdamien			    struct ieee80211_node *);
122156321Sdamienstatic int		rt2560_tx_mgt(struct rt2560_softc *, struct mbuf *,
123156321Sdamien			    struct ieee80211_node *);
124156321Sdamienstatic struct		mbuf *rt2560_get_rts(struct rt2560_softc *,
125156321Sdamien			    struct ieee80211_frame *, uint16_t);
126156321Sdamienstatic int		rt2560_tx_data(struct rt2560_softc *, struct mbuf *,
127156321Sdamien			    struct ieee80211_node *);
128156321Sdamienstatic void		rt2560_start(struct ifnet *);
129165352Sbmsstatic void		rt2560_watchdog(void *);
130156321Sdamienstatic int		rt2560_reset(struct ifnet *);
131156321Sdamienstatic int		rt2560_ioctl(struct ifnet *, u_long, caddr_t);
132156321Sdamienstatic void		rt2560_bbp_write(struct rt2560_softc *, uint8_t,
133156321Sdamien			    uint8_t);
134156321Sdamienstatic uint8_t		rt2560_bbp_read(struct rt2560_softc *, uint8_t);
135156321Sdamienstatic void		rt2560_rf_write(struct rt2560_softc *, uint8_t,
136156321Sdamien			    uint32_t);
137156321Sdamienstatic void		rt2560_set_chan(struct rt2560_softc *,
138156321Sdamien			    struct ieee80211_channel *);
139156321Sdamien#if 0
140156321Sdamienstatic void		rt2560_disable_rf_tune(struct rt2560_softc *);
141156321Sdamien#endif
142156321Sdamienstatic void		rt2560_enable_tsf_sync(struct rt2560_softc *);
143156321Sdamienstatic void		rt2560_update_plcp(struct rt2560_softc *);
144156321Sdamienstatic void		rt2560_update_slot(struct ifnet *);
145156321Sdamienstatic void		rt2560_set_basicrates(struct rt2560_softc *);
146156321Sdamienstatic void		rt2560_update_led(struct rt2560_softc *, int, int);
147170530Ssamstatic void		rt2560_set_bssid(struct rt2560_softc *, const uint8_t *);
148156321Sdamienstatic void		rt2560_set_macaddr(struct rt2560_softc *, uint8_t *);
149156321Sdamienstatic void		rt2560_get_macaddr(struct rt2560_softc *, uint8_t *);
150156321Sdamienstatic void		rt2560_update_promisc(struct rt2560_softc *);
151156321Sdamienstatic const char	*rt2560_get_rf(int);
152156321Sdamienstatic void		rt2560_read_eeprom(struct rt2560_softc *);
153156321Sdamienstatic int		rt2560_bbp_init(struct rt2560_softc *);
154156321Sdamienstatic void		rt2560_set_txantenna(struct rt2560_softc *, int);
155156321Sdamienstatic void		rt2560_set_rxantenna(struct rt2560_softc *, int);
156156321Sdamienstatic void		rt2560_init(void *);
157160691Ssamstatic int		rt2560_raw_xmit(struct ieee80211_node *, struct mbuf *,
158160691Ssam				const struct ieee80211_bpf_params *);
159156321Sdamien
160156321Sdamienstatic const struct {
161156321Sdamien	uint32_t	reg;
162156321Sdamien	uint32_t	val;
163156321Sdamien} rt2560_def_mac[] = {
164156321Sdamien	RT2560_DEF_MAC
165156321Sdamien};
166156321Sdamien
167156321Sdamienstatic const struct {
168156321Sdamien	uint8_t	reg;
169156321Sdamien	uint8_t	val;
170156321Sdamien} rt2560_def_bbp[] = {
171156321Sdamien	RT2560_DEF_BBP
172156321Sdamien};
173156321Sdamien
174156321Sdamienstatic const uint32_t rt2560_rf2522_r2[]    = RT2560_RF2522_R2;
175156321Sdamienstatic const uint32_t rt2560_rf2523_r2[]    = RT2560_RF2523_R2;
176156321Sdamienstatic const uint32_t rt2560_rf2524_r2[]    = RT2560_RF2524_R2;
177156321Sdamienstatic const uint32_t rt2560_rf2525_r2[]    = RT2560_RF2525_R2;
178156321Sdamienstatic const uint32_t rt2560_rf2525_hi_r2[] = RT2560_RF2525_HI_R2;
179156321Sdamienstatic const uint32_t rt2560_rf2525e_r2[]   = RT2560_RF2525E_R2;
180156321Sdamienstatic const uint32_t rt2560_rf2526_r2[]    = RT2560_RF2526_R2;
181156321Sdamienstatic const uint32_t rt2560_rf2526_hi_r2[] = RT2560_RF2526_HI_R2;
182156321Sdamien
183156321Sdamienstatic const struct {
184156321Sdamien	uint8_t		chan;
185156321Sdamien	uint32_t	r1, r2, r4;
186156321Sdamien} rt2560_rf5222[] = {
187156321Sdamien	RT2560_RF5222
188156321Sdamien};
189156321Sdamien
190156321Sdamienint
191156321Sdamienrt2560_attach(device_t dev, int id)
192156321Sdamien{
193156321Sdamien	struct rt2560_softc *sc = device_get_softc(dev);
194156321Sdamien	struct ieee80211com *ic = &sc->sc_ic;
195156321Sdamien	struct ifnet *ifp;
196170530Ssam	int error, bands;
197156321Sdamien
198156321Sdamien	sc->sc_dev = dev;
199156321Sdamien
200156321Sdamien	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
201156321Sdamien	    MTX_DEF | MTX_RECURSE);
202156321Sdamien
203165352Sbms	callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0);
204156321Sdamien	callout_init(&sc->rssadapt_ch, CALLOUT_MPSAFE);
205156321Sdamien
206156321Sdamien	/* retrieve RT2560 rev. no */
207156321Sdamien	sc->asic_rev = RAL_READ(sc, RT2560_CSR0);
208156321Sdamien
209156321Sdamien	/* retrieve MAC address */
210156321Sdamien	rt2560_get_macaddr(sc, ic->ic_myaddr);
211156321Sdamien
212156321Sdamien	/* retrieve RF rev. no and various other things from EEPROM */
213156321Sdamien	rt2560_read_eeprom(sc);
214156321Sdamien
215156321Sdamien	device_printf(dev, "MAC/BBP RT2560 (rev 0x%02x), RF %s\n",
216156321Sdamien	    sc->asic_rev, rt2560_get_rf(sc->rf_rev));
217156321Sdamien
218156321Sdamien	/*
219156321Sdamien	 * Allocate Tx and Rx rings.
220156321Sdamien	 */
221156321Sdamien	error = rt2560_alloc_tx_ring(sc, &sc->txq, RT2560_TX_RING_COUNT);
222156321Sdamien	if (error != 0) {
223156321Sdamien		device_printf(sc->sc_dev, "could not allocate Tx ring\n");
224156321Sdamien		goto fail1;
225156321Sdamien	}
226156321Sdamien
227156321Sdamien	error = rt2560_alloc_tx_ring(sc, &sc->atimq, RT2560_ATIM_RING_COUNT);
228156321Sdamien	if (error != 0) {
229156321Sdamien		device_printf(sc->sc_dev, "could not allocate ATIM ring\n");
230156321Sdamien		goto fail2;
231156321Sdamien	}
232156321Sdamien
233156321Sdamien	error = rt2560_alloc_tx_ring(sc, &sc->prioq, RT2560_PRIO_RING_COUNT);
234156321Sdamien	if (error != 0) {
235156321Sdamien		device_printf(sc->sc_dev, "could not allocate Prio ring\n");
236156321Sdamien		goto fail3;
237156321Sdamien	}
238156321Sdamien
239156321Sdamien	error = rt2560_alloc_tx_ring(sc, &sc->bcnq, RT2560_BEACON_RING_COUNT);
240156321Sdamien	if (error != 0) {
241156321Sdamien		device_printf(sc->sc_dev, "could not allocate Beacon ring\n");
242156321Sdamien		goto fail4;
243156321Sdamien	}
244156321Sdamien
245156321Sdamien	error = rt2560_alloc_rx_ring(sc, &sc->rxq, RT2560_RX_RING_COUNT);
246156321Sdamien	if (error != 0) {
247156321Sdamien		device_printf(sc->sc_dev, "could not allocate Rx ring\n");
248156321Sdamien		goto fail5;
249156321Sdamien	}
250156321Sdamien
251156321Sdamien	ifp = sc->sc_ifp = if_alloc(IFT_ETHER);
252156321Sdamien	if (ifp == NULL) {
253156321Sdamien		device_printf(sc->sc_dev, "can not if_alloc()\n");
254156321Sdamien		goto fail6;
255156321Sdamien	}
256156321Sdamien
257156321Sdamien	ifp->if_softc = sc;
258156321Sdamien	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
259156321Sdamien	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
260156321Sdamien	ifp->if_init = rt2560_init;
261156321Sdamien	ifp->if_ioctl = rt2560_ioctl;
262156321Sdamien	ifp->if_start = rt2560_start;
263156321Sdamien	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
264156321Sdamien	ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
265156321Sdamien	IFQ_SET_READY(&ifp->if_snd);
266156321Sdamien
267156321Sdamien	ic->ic_ifp = ifp;
268156321Sdamien	ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
269156321Sdamien	ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
270156321Sdamien	ic->ic_state = IEEE80211_S_INIT;
271156321Sdamien
272156321Sdamien	/* set device capabilities */
273156321Sdamien	ic->ic_caps =
274156321Sdamien	    IEEE80211_C_IBSS |		/* IBSS mode supported */
275156321Sdamien	    IEEE80211_C_MONITOR |	/* monitor mode supported */
276156321Sdamien	    IEEE80211_C_HOSTAP |	/* HostAp mode supported */
277156321Sdamien	    IEEE80211_C_TXPMGT |	/* tx power management */
278156321Sdamien	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
279156321Sdamien	    IEEE80211_C_SHSLOT |	/* short slot time supported */
280170530Ssam	    IEEE80211_C_BGSCAN |	/* bg scanning support */
281156321Sdamien	    IEEE80211_C_WPA;		/* 802.11i */
282156321Sdamien
283170530Ssam	bands = 0;
284170530Ssam	setbit(&bands, IEEE80211_MODE_11B);
285170530Ssam	setbit(&bands, IEEE80211_MODE_11G);
286170530Ssam	if (sc->rf_rev == RT2560_RF_5222)
287170530Ssam		setbit(&bands, IEEE80211_MODE_11A);
288170530Ssam	ieee80211_init_channels(ic, 0, CTRY_DEFAULT, bands, 0, 1);
289156321Sdamien
290156321Sdamien	ieee80211_ifattach(ic);
291170530Ssam	ic->ic_scan_start = rt2560_scan_start;
292170530Ssam	ic->ic_scan_end = rt2560_scan_end;
293170530Ssam	ic->ic_set_channel = rt2560_set_channel;
294156321Sdamien	ic->ic_node_alloc = rt2560_node_alloc;
295156321Sdamien	ic->ic_updateslot = rt2560_update_slot;
296156321Sdamien	ic->ic_reset = rt2560_reset;
297156321Sdamien	/* enable s/w bmiss handling in sta mode */
298156321Sdamien	ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;
299156321Sdamien
300156321Sdamien	/* override state transition machine */
301156321Sdamien	sc->sc_newstate = ic->ic_newstate;
302156321Sdamien	ic->ic_newstate = rt2560_newstate;
303160691Ssam	ic->ic_raw_xmit = rt2560_raw_xmit;
304156321Sdamien	ieee80211_media_init(ic, rt2560_media_change, ieee80211_media_status);
305156321Sdamien
306156321Sdamien	bpfattach2(ifp, DLT_IEEE802_11_RADIO,
307171086Skevlo	    sizeof (struct ieee80211_frame) + sizeof (sc->sc_txtap),
308171086Skevlo	    &sc->sc_drvbpf);
309156321Sdamien
310171086Skevlo	sc->sc_rxtap_len = sizeof sc->sc_rxtap;
311156321Sdamien	sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
312156321Sdamien	sc->sc_rxtap.wr_ihdr.it_present = htole32(RT2560_RX_RADIOTAP_PRESENT);
313156321Sdamien
314171086Skevlo	sc->sc_txtap_len = sizeof sc->sc_txtap;
315156321Sdamien	sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
316156321Sdamien	sc->sc_txtap.wt_ihdr.it_present = htole32(RT2560_TX_RADIOTAP_PRESENT);
317156321Sdamien
318156321Sdamien	/*
319156321Sdamien	 * Add a few sysctl knobs.
320156321Sdamien	 */
321156321Sdamien	sc->dwelltime = 200;
322156321Sdamien
323156321Sdamien	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
324156321Sdamien	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
325156321Sdamien	    "txantenna", CTLFLAG_RW, &sc->tx_ant, 0, "tx antenna (0=auto)");
326156321Sdamien
327156321Sdamien	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
328156321Sdamien	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
329156321Sdamien	    "rxantenna", CTLFLAG_RW, &sc->rx_ant, 0, "rx antenna (0=auto)");
330156321Sdamien
331156321Sdamien	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
332156321Sdamien	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "dwell",
333156321Sdamien	    CTLFLAG_RW, &sc->dwelltime, 0,
334156321Sdamien	    "channel dwell time (ms) for AP/station scanning");
335156321Sdamien
336156321Sdamien	if (bootverbose)
337156321Sdamien		ieee80211_announce(ic);
338156321Sdamien
339156321Sdamien	return 0;
340156321Sdamien
341156321Sdamienfail6:	rt2560_free_rx_ring(sc, &sc->rxq);
342156321Sdamienfail5:	rt2560_free_tx_ring(sc, &sc->bcnq);
343156321Sdamienfail4:	rt2560_free_tx_ring(sc, &sc->prioq);
344156321Sdamienfail3:	rt2560_free_tx_ring(sc, &sc->atimq);
345156321Sdamienfail2:	rt2560_free_tx_ring(sc, &sc->txq);
346156321Sdamienfail1:	mtx_destroy(&sc->sc_mtx);
347156321Sdamien
348156321Sdamien	return ENXIO;
349156321Sdamien}
350156321Sdamien
351156321Sdamienint
352156321Sdamienrt2560_detach(void *xsc)
353156321Sdamien{
354156321Sdamien	struct rt2560_softc *sc = xsc;
355156321Sdamien	struct ieee80211com *ic = &sc->sc_ic;
356156321Sdamien	struct ifnet *ifp = ic->ic_ifp;
357170530Ssam
358156321Sdamien	rt2560_stop(sc);
359165352Sbms	callout_stop(&sc->watchdog_ch);
360156321Sdamien	callout_stop(&sc->rssadapt_ch);
361156321Sdamien
362156321Sdamien	bpfdetach(ifp);
363156321Sdamien	ieee80211_ifdetach(ic);
364156321Sdamien
365156321Sdamien	rt2560_free_tx_ring(sc, &sc->txq);
366156321Sdamien	rt2560_free_tx_ring(sc, &sc->atimq);
367156321Sdamien	rt2560_free_tx_ring(sc, &sc->prioq);
368156321Sdamien	rt2560_free_tx_ring(sc, &sc->bcnq);
369156321Sdamien	rt2560_free_rx_ring(sc, &sc->rxq);
370156321Sdamien
371156321Sdamien	if_free(ifp);
372156321Sdamien
373156321Sdamien	mtx_destroy(&sc->sc_mtx);
374156321Sdamien
375156321Sdamien	return 0;
376156321Sdamien}
377156321Sdamien
378156321Sdamienvoid
379156321Sdamienrt2560_resume(void *xsc)
380156321Sdamien{
381156321Sdamien	struct rt2560_softc *sc = xsc;
382156321Sdamien	struct ifnet *ifp = sc->sc_ic.ic_ifp;
383156321Sdamien
384156321Sdamien	if (ifp->if_flags & IFF_UP) {
385156321Sdamien		ifp->if_init(ifp->if_softc);
386156321Sdamien		if (ifp->if_drv_flags & IFF_DRV_RUNNING)
387156321Sdamien			ifp->if_start(ifp);
388156321Sdamien	}
389156321Sdamien}
390156321Sdamien
391156321Sdamienstatic void
392156321Sdamienrt2560_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
393156321Sdamien{
394156321Sdamien	if (error != 0)
395156321Sdamien		return;
396156321Sdamien
397156321Sdamien	KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
398156321Sdamien
399156321Sdamien	*(bus_addr_t *)arg = segs[0].ds_addr;
400156321Sdamien}
401156321Sdamien
402156321Sdamienstatic int
403156321Sdamienrt2560_alloc_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring,
404156321Sdamien    int count)
405156321Sdamien{
406156321Sdamien	int i, error;
407156321Sdamien
408156321Sdamien	ring->count = count;
409156321Sdamien	ring->queued = 0;
410156321Sdamien	ring->cur = ring->next = 0;
411156321Sdamien	ring->cur_encrypt = ring->next_encrypt = 0;
412156321Sdamien
413156321Sdamien	error = bus_dma_tag_create(NULL, 4, 0, BUS_SPACE_MAXADDR_32BIT,
414156321Sdamien	    BUS_SPACE_MAXADDR, NULL, NULL, count * RT2560_TX_DESC_SIZE, 1,
415156321Sdamien	    count * RT2560_TX_DESC_SIZE, 0, NULL, NULL, &ring->desc_dmat);
416156321Sdamien	if (error != 0) {
417156321Sdamien		device_printf(sc->sc_dev, "could not create desc DMA tag\n");
418156321Sdamien		goto fail;
419156321Sdamien	}
420156321Sdamien
421156321Sdamien	error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc,
422156321Sdamien	    BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map);
423156321Sdamien	if (error != 0) {
424156321Sdamien		device_printf(sc->sc_dev, "could not allocate DMA memory\n");
425156321Sdamien		goto fail;
426156321Sdamien	}
427156321Sdamien
428156321Sdamien	error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc,
429156321Sdamien	    count * RT2560_TX_DESC_SIZE, rt2560_dma_map_addr, &ring->physaddr,
430156321Sdamien	    0);
431156321Sdamien	if (error != 0) {
432156321Sdamien		device_printf(sc->sc_dev, "could not load desc DMA map\n");
433156321Sdamien		goto fail;
434156321Sdamien	}
435156321Sdamien
436156321Sdamien	ring->data = malloc(count * sizeof (struct rt2560_tx_data), M_DEVBUF,
437156321Sdamien	    M_NOWAIT | M_ZERO);
438156321Sdamien	if (ring->data == NULL) {
439156321Sdamien		device_printf(sc->sc_dev, "could not allocate soft data\n");
440156321Sdamien		error = ENOMEM;
441156321Sdamien		goto fail;
442156321Sdamien	}
443156321Sdamien
444156321Sdamien	error = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
445156321Sdamien	    BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, RT2560_MAX_SCATTER,
446156321Sdamien	    MCLBYTES, 0, NULL, NULL, &ring->data_dmat);
447156321Sdamien	if (error != 0) {
448156321Sdamien		device_printf(sc->sc_dev, "could not create data DMA tag\n");
449156321Sdamien		goto fail;
450156321Sdamien	}
451156321Sdamien
452156321Sdamien	for (i = 0; i < count; i++) {
453156321Sdamien		error = bus_dmamap_create(ring->data_dmat, 0,
454156321Sdamien		    &ring->data[i].map);
455156321Sdamien		if (error != 0) {
456156321Sdamien			device_printf(sc->sc_dev, "could not create DMA map\n");
457156321Sdamien			goto fail;
458156321Sdamien		}
459156321Sdamien	}
460156321Sdamien
461156321Sdamien	return 0;
462156321Sdamien
463156321Sdamienfail:	rt2560_free_tx_ring(sc, ring);
464156321Sdamien	return error;
465156321Sdamien}
466156321Sdamien
467156321Sdamienstatic void
468156321Sdamienrt2560_reset_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring)
469156321Sdamien{
470156321Sdamien	struct rt2560_tx_desc *desc;
471156321Sdamien	struct rt2560_tx_data *data;
472156321Sdamien	int i;
473156321Sdamien
474156321Sdamien	for (i = 0; i < ring->count; i++) {
475156321Sdamien		desc = &ring->desc[i];
476156321Sdamien		data = &ring->data[i];
477156321Sdamien
478156321Sdamien		if (data->m != NULL) {
479156321Sdamien			bus_dmamap_sync(ring->data_dmat, data->map,
480156321Sdamien			    BUS_DMASYNC_POSTWRITE);
481156321Sdamien			bus_dmamap_unload(ring->data_dmat, data->map);
482156321Sdamien			m_freem(data->m);
483156321Sdamien			data->m = NULL;
484156321Sdamien		}
485156321Sdamien
486156321Sdamien		if (data->ni != NULL) {
487156321Sdamien			ieee80211_free_node(data->ni);
488156321Sdamien			data->ni = NULL;
489156321Sdamien		}
490156321Sdamien
491156321Sdamien		desc->flags = 0;
492156321Sdamien	}
493156321Sdamien
494156321Sdamien	bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE);
495156321Sdamien
496156321Sdamien	ring->queued = 0;
497156321Sdamien	ring->cur = ring->next = 0;
498156321Sdamien	ring->cur_encrypt = ring->next_encrypt = 0;
499156321Sdamien}
500156321Sdamien
501156321Sdamienstatic void
502156321Sdamienrt2560_free_tx_ring(struct rt2560_softc *sc, struct rt2560_tx_ring *ring)
503156321Sdamien{
504156321Sdamien	struct rt2560_tx_data *data;
505156321Sdamien	int i;
506156321Sdamien
507156321Sdamien	if (ring->desc != NULL) {
508156321Sdamien		bus_dmamap_sync(ring->desc_dmat, ring->desc_map,
509156321Sdamien		    BUS_DMASYNC_POSTWRITE);
510156321Sdamien		bus_dmamap_unload(ring->desc_dmat, ring->desc_map);
511156321Sdamien		bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map);
512156321Sdamien	}
513156321Sdamien
514156321Sdamien	if (ring->desc_dmat != NULL)
515156321Sdamien		bus_dma_tag_destroy(ring->desc_dmat);
516156321Sdamien
517156321Sdamien	if (ring->data != NULL) {
518156321Sdamien		for (i = 0; i < ring->count; i++) {
519156321Sdamien			data = &ring->data[i];
520156321Sdamien
521156321Sdamien			if (data->m != NULL) {
522156321Sdamien				bus_dmamap_sync(ring->data_dmat, data->map,
523156321Sdamien				    BUS_DMASYNC_POSTWRITE);
524156321Sdamien				bus_dmamap_unload(ring->data_dmat, data->map);
525156321Sdamien				m_freem(data->m);
526156321Sdamien			}
527156321Sdamien
528156321Sdamien			if (data->ni != NULL)
529156321Sdamien				ieee80211_free_node(data->ni);
530156321Sdamien
531156321Sdamien			if (data->map != NULL)
532156321Sdamien				bus_dmamap_destroy(ring->data_dmat, data->map);
533156321Sdamien		}
534156321Sdamien
535156321Sdamien		free(ring->data, M_DEVBUF);
536156321Sdamien	}
537156321Sdamien
538156321Sdamien	if (ring->data_dmat != NULL)
539156321Sdamien		bus_dma_tag_destroy(ring->data_dmat);
540156321Sdamien}
541156321Sdamien
542156321Sdamienstatic int
543156321Sdamienrt2560_alloc_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring,
544156321Sdamien    int count)
545156321Sdamien{
546156321Sdamien	struct rt2560_rx_desc *desc;
547156321Sdamien	struct rt2560_rx_data *data;
548156321Sdamien	bus_addr_t physaddr;
549156321Sdamien	int i, error;
550156321Sdamien
551156321Sdamien	ring->count = count;
552156321Sdamien	ring->cur = ring->next = 0;
553156321Sdamien	ring->cur_decrypt = 0;
554156321Sdamien
555156321Sdamien	error = bus_dma_tag_create(NULL, 4, 0, BUS_SPACE_MAXADDR_32BIT,
556156321Sdamien	    BUS_SPACE_MAXADDR, NULL, NULL, count * RT2560_RX_DESC_SIZE, 1,
557156321Sdamien	    count * RT2560_RX_DESC_SIZE, 0, NULL, NULL, &ring->desc_dmat);
558156321Sdamien	if (error != 0) {
559156321Sdamien		device_printf(sc->sc_dev, "could not create desc DMA tag\n");
560156321Sdamien		goto fail;
561156321Sdamien	}
562156321Sdamien
563156321Sdamien	error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc,
564156321Sdamien	    BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map);
565156321Sdamien	if (error != 0) {
566156321Sdamien		device_printf(sc->sc_dev, "could not allocate DMA memory\n");
567156321Sdamien		goto fail;
568156321Sdamien	}
569156321Sdamien
570156321Sdamien	error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc,
571156321Sdamien	    count * RT2560_RX_DESC_SIZE, rt2560_dma_map_addr, &ring->physaddr,
572156321Sdamien	    0);
573156321Sdamien	if (error != 0) {
574156321Sdamien		device_printf(sc->sc_dev, "could not load desc DMA map\n");
575156321Sdamien		goto fail;
576156321Sdamien	}
577156321Sdamien
578156321Sdamien	ring->data = malloc(count * sizeof (struct rt2560_rx_data), M_DEVBUF,
579156321Sdamien	    M_NOWAIT | M_ZERO);
580156321Sdamien	if (ring->data == NULL) {
581156321Sdamien		device_printf(sc->sc_dev, "could not allocate soft data\n");
582156321Sdamien		error = ENOMEM;
583156321Sdamien		goto fail;
584156321Sdamien	}
585156321Sdamien
586156321Sdamien	/*
587156321Sdamien	 * Pre-allocate Rx buffers and populate Rx ring.
588156321Sdamien	 */
589156321Sdamien	error = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
590156321Sdamien	    BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1, MCLBYTES, 0, NULL,
591156321Sdamien	    NULL, &ring->data_dmat);
592156321Sdamien	if (error != 0) {
593156321Sdamien		device_printf(sc->sc_dev, "could not create data DMA tag\n");
594156321Sdamien		goto fail;
595156321Sdamien	}
596156321Sdamien
597156321Sdamien	for (i = 0; i < count; i++) {
598156321Sdamien		desc = &sc->rxq.desc[i];
599156321Sdamien		data = &sc->rxq.data[i];
600156321Sdamien
601156321Sdamien		error = bus_dmamap_create(ring->data_dmat, 0, &data->map);
602156321Sdamien		if (error != 0) {
603156321Sdamien			device_printf(sc->sc_dev, "could not create DMA map\n");
604156321Sdamien			goto fail;
605156321Sdamien		}
606156321Sdamien
607156321Sdamien		data->m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
608156321Sdamien		if (data->m == NULL) {
609156321Sdamien			device_printf(sc->sc_dev,
610156321Sdamien			    "could not allocate rx mbuf\n");
611156321Sdamien			error = ENOMEM;
612156321Sdamien			goto fail;
613156321Sdamien		}
614156321Sdamien
615156321Sdamien		error = bus_dmamap_load(ring->data_dmat, data->map,
616156321Sdamien		    mtod(data->m, void *), MCLBYTES, rt2560_dma_map_addr,
617156321Sdamien		    &physaddr, 0);
618156321Sdamien		if (error != 0) {
619156321Sdamien			device_printf(sc->sc_dev,
620156321Sdamien			    "could not load rx buf DMA map");
621156321Sdamien			goto fail;
622156321Sdamien		}
623156321Sdamien
624156321Sdamien		desc->flags = htole32(RT2560_RX_BUSY);
625156321Sdamien		desc->physaddr = htole32(physaddr);
626156321Sdamien	}
627156321Sdamien
628156321Sdamien	bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE);
629156321Sdamien
630156321Sdamien	return 0;
631156321Sdamien
632156321Sdamienfail:	rt2560_free_rx_ring(sc, ring);
633156321Sdamien	return error;
634156321Sdamien}
635156321Sdamien
636156321Sdamienstatic void
637156321Sdamienrt2560_reset_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring)
638156321Sdamien{
639156321Sdamien	int i;
640156321Sdamien
641156321Sdamien	for (i = 0; i < ring->count; i++) {
642156321Sdamien		ring->desc[i].flags = htole32(RT2560_RX_BUSY);
643156321Sdamien		ring->data[i].drop = 0;
644156321Sdamien	}
645156321Sdamien
646156321Sdamien	bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_PREWRITE);
647156321Sdamien
648156321Sdamien	ring->cur = ring->next = 0;
649156321Sdamien	ring->cur_decrypt = 0;
650156321Sdamien}
651156321Sdamien
652156321Sdamienstatic void
653156321Sdamienrt2560_free_rx_ring(struct rt2560_softc *sc, struct rt2560_rx_ring *ring)
654156321Sdamien{
655156321Sdamien	struct rt2560_rx_data *data;
656156321Sdamien	int i;
657156321Sdamien
658156321Sdamien	if (ring->desc != NULL) {
659156321Sdamien		bus_dmamap_sync(ring->desc_dmat, ring->desc_map,
660156321Sdamien		    BUS_DMASYNC_POSTWRITE);
661156321Sdamien		bus_dmamap_unload(ring->desc_dmat, ring->desc_map);
662156321Sdamien		bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map);
663156321Sdamien	}
664156321Sdamien
665156321Sdamien	if (ring->desc_dmat != NULL)
666156321Sdamien		bus_dma_tag_destroy(ring->desc_dmat);
667156321Sdamien
668156321Sdamien	if (ring->data != NULL) {
669156321Sdamien		for (i = 0; i < ring->count; i++) {
670156321Sdamien			data = &ring->data[i];
671156321Sdamien
672156321Sdamien			if (data->m != NULL) {
673156321Sdamien				bus_dmamap_sync(ring->data_dmat, data->map,
674156321Sdamien				    BUS_DMASYNC_POSTREAD);
675156321Sdamien				bus_dmamap_unload(ring->data_dmat, data->map);
676156321Sdamien				m_freem(data->m);
677156321Sdamien			}
678156321Sdamien
679156321Sdamien			if (data->map != NULL)
680156321Sdamien				bus_dmamap_destroy(ring->data_dmat, data->map);
681156321Sdamien		}
682156321Sdamien
683156321Sdamien		free(ring->data, M_DEVBUF);
684156321Sdamien	}
685156321Sdamien
686156321Sdamien	if (ring->data_dmat != NULL)
687156321Sdamien		bus_dma_tag_destroy(ring->data_dmat);
688156321Sdamien}
689156321Sdamien
690156321Sdamienstatic struct ieee80211_node *
691156321Sdamienrt2560_node_alloc(struct ieee80211_node_table *nt)
692156321Sdamien{
693156321Sdamien	struct rt2560_node *rn;
694156321Sdamien
695156321Sdamien	rn = malloc(sizeof (struct rt2560_node), M_80211_NODE,
696156321Sdamien	    M_NOWAIT | M_ZERO);
697156321Sdamien
698156321Sdamien	return (rn != NULL) ? &rn->ni : NULL;
699156321Sdamien}
700156321Sdamien
701156321Sdamienstatic int
702156321Sdamienrt2560_media_change(struct ifnet *ifp)
703156321Sdamien{
704156321Sdamien	struct rt2560_softc *sc = ifp->if_softc;
705156321Sdamien	int error;
706156321Sdamien
707156321Sdamien	error = ieee80211_media_change(ifp);
708156321Sdamien
709170530Ssam	if (error == ENETRESET) {
710170530Ssam		if ((ifp->if_flags & IFF_UP) &&
711170530Ssam		    (ifp->if_drv_flags & IFF_DRV_RUNNING))
712170530Ssam		        rt2560_init(sc);
713170530Ssam	}
714170530Ssam	return error;
715156321Sdamien}
716156321Sdamien
717156321Sdamien/*
718156321Sdamien * This function is called for each node present in the node station table.
719156321Sdamien */
720156321Sdamienstatic void
721156321Sdamienrt2560_iter_func(void *arg, struct ieee80211_node *ni)
722156321Sdamien{
723156321Sdamien	struct rt2560_node *rn = (struct rt2560_node *)ni;
724156321Sdamien
725156321Sdamien	ral_rssadapt_updatestats(&rn->rssadapt);
726156321Sdamien}
727156321Sdamien
728156321Sdamien/*
729156321Sdamien * This function is called periodically (every 100ms) in RUN state to update
730156321Sdamien * the rate adaptation statistics.
731156321Sdamien */
732156321Sdamienstatic void
733156321Sdamienrt2560_update_rssadapt(void *arg)
734156321Sdamien{
735156321Sdamien	struct rt2560_softc *sc = arg;
736156321Sdamien	struct ieee80211com *ic = &sc->sc_ic;
737156321Sdamien
738156321Sdamien	RAL_LOCK(sc);
739156321Sdamien
740156321Sdamien	ieee80211_iterate_nodes(&ic->ic_sta, rt2560_iter_func, arg);
741156321Sdamien	callout_reset(&sc->rssadapt_ch, hz / 10, rt2560_update_rssadapt, sc);
742156321Sdamien
743156321Sdamien	RAL_UNLOCK(sc);
744156321Sdamien}
745156321Sdamien
746156321Sdamienstatic int
747156321Sdamienrt2560_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
748156321Sdamien{
749156321Sdamien	struct rt2560_softc *sc = ic->ic_ifp->if_softc;
750156321Sdamien	enum ieee80211_state ostate;
751156321Sdamien	struct ieee80211_node *ni;
752156321Sdamien	struct mbuf *m;
753156321Sdamien	int error = 0;
754156321Sdamien
755156321Sdamien	ostate = ic->ic_state;
756156321Sdamien
757156321Sdamien	switch (nstate) {
758156321Sdamien	case IEEE80211_S_INIT:
759156321Sdamien		callout_stop(&sc->rssadapt_ch);
760156321Sdamien
761156321Sdamien		if (ostate == IEEE80211_S_RUN) {
762156321Sdamien			/* abort TSF synchronization */
763156321Sdamien			RAL_WRITE(sc, RT2560_CSR14, 0);
764156321Sdamien
765156321Sdamien			/* turn association led off */
766156321Sdamien			rt2560_update_led(sc, 0, 0);
767156321Sdamien		}
768156321Sdamien		break;
769156321Sdamien	case IEEE80211_S_RUN:
770156321Sdamien		ni = ic->ic_bss;
771156321Sdamien
772156321Sdamien		if (ic->ic_opmode != IEEE80211_M_MONITOR) {
773156321Sdamien			rt2560_update_plcp(sc);
774156321Sdamien			rt2560_set_basicrates(sc);
775156321Sdamien			rt2560_set_bssid(sc, ni->ni_bssid);
776156321Sdamien		}
777156321Sdamien
778156321Sdamien		if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
779156321Sdamien		    ic->ic_opmode == IEEE80211_M_IBSS) {
780156321Sdamien			m = ieee80211_beacon_alloc(ic, ni, &sc->sc_bo);
781156321Sdamien			if (m == NULL) {
782156321Sdamien				device_printf(sc->sc_dev,
783156321Sdamien				    "could not allocate beacon\n");
784156321Sdamien				error = ENOBUFS;
785156321Sdamien				break;
786156321Sdamien			}
787156321Sdamien
788156321Sdamien			ieee80211_ref_node(ni);
789156321Sdamien			error = rt2560_tx_bcn(sc, m, ni);
790156321Sdamien			if (error != 0)
791156321Sdamien				break;
792156321Sdamien		}
793156321Sdamien
794156321Sdamien		/* turn assocation led on */
795156321Sdamien		rt2560_update_led(sc, 1, 0);
796156321Sdamien
797156321Sdamien		if (ic->ic_opmode != IEEE80211_M_MONITOR) {
798156321Sdamien			callout_reset(&sc->rssadapt_ch, hz / 10,
799156321Sdamien			    rt2560_update_rssadapt, sc);
800156321Sdamien
801156321Sdamien			rt2560_enable_tsf_sync(sc);
802156321Sdamien		}
803156321Sdamien		break;
804170530Ssam	case IEEE80211_S_SCAN:
805170530Ssam	case IEEE80211_S_AUTH:
806170530Ssam	case IEEE80211_S_ASSOC:
807170530Ssam		break;
808156321Sdamien	}
809156321Sdamien
810156321Sdamien	return (error != 0) ? error : sc->sc_newstate(ic, nstate, arg);
811156321Sdamien}
812156321Sdamien
813156321Sdamien/*
814156321Sdamien * Read 16 bits at address 'addr' from the serial EEPROM (either 93C46 or
815156321Sdamien * 93C66).
816156321Sdamien */
817156321Sdamienstatic uint16_t
818156321Sdamienrt2560_eeprom_read(struct rt2560_softc *sc, uint8_t addr)
819156321Sdamien{
820156321Sdamien	uint32_t tmp;
821156321Sdamien	uint16_t val;
822156321Sdamien	int n;
823156321Sdamien
824156321Sdamien	/* clock C once before the first command */
825156321Sdamien	RT2560_EEPROM_CTL(sc, 0);
826156321Sdamien
827156321Sdamien	RT2560_EEPROM_CTL(sc, RT2560_S);
828156321Sdamien	RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C);
829156321Sdamien	RT2560_EEPROM_CTL(sc, RT2560_S);
830156321Sdamien
831156321Sdamien	/* write start bit (1) */
832156321Sdamien	RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D);
833156321Sdamien	RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D | RT2560_C);
834156321Sdamien
835156321Sdamien	/* write READ opcode (10) */
836156321Sdamien	RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D);
837156321Sdamien	RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_D | RT2560_C);
838156321Sdamien	RT2560_EEPROM_CTL(sc, RT2560_S);
839156321Sdamien	RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C);
840156321Sdamien
841156321Sdamien	/* write address (A5-A0 or A7-A0) */
842156321Sdamien	n = (RAL_READ(sc, RT2560_CSR21) & RT2560_93C46) ? 5 : 7;
843156321Sdamien	for (; n >= 0; n--) {
844156321Sdamien		RT2560_EEPROM_CTL(sc, RT2560_S |
845156321Sdamien		    (((addr >> n) & 1) << RT2560_SHIFT_D));
846156321Sdamien		RT2560_EEPROM_CTL(sc, RT2560_S |
847156321Sdamien		    (((addr >> n) & 1) << RT2560_SHIFT_D) | RT2560_C);
848156321Sdamien	}
849156321Sdamien
850156321Sdamien	RT2560_EEPROM_CTL(sc, RT2560_S);
851156321Sdamien
852156321Sdamien	/* read data Q15-Q0 */
853156321Sdamien	val = 0;
854156321Sdamien	for (n = 15; n >= 0; n--) {
855156321Sdamien		RT2560_EEPROM_CTL(sc, RT2560_S | RT2560_C);
856156321Sdamien		tmp = RAL_READ(sc, RT2560_CSR21);
857156321Sdamien		val |= ((tmp & RT2560_Q) >> RT2560_SHIFT_Q) << n;
858156321Sdamien		RT2560_EEPROM_CTL(sc, RT2560_S);
859156321Sdamien	}
860156321Sdamien
861156321Sdamien	RT2560_EEPROM_CTL(sc, 0);
862156321Sdamien
863156321Sdamien	/* clear Chip Select and clock C */
864156321Sdamien	RT2560_EEPROM_CTL(sc, RT2560_S);
865156321Sdamien	RT2560_EEPROM_CTL(sc, 0);
866156321Sdamien	RT2560_EEPROM_CTL(sc, RT2560_C);
867156321Sdamien
868156321Sdamien	return val;
869156321Sdamien}
870156321Sdamien
871156321Sdamien/*
872156321Sdamien * Some frames were processed by the hardware cipher engine and are ready for
873156321Sdamien * transmission.
874156321Sdamien */
875156321Sdamienstatic void
876156321Sdamienrt2560_encryption_intr(struct rt2560_softc *sc)
877156321Sdamien{
878156321Sdamien	struct rt2560_tx_desc *desc;
879156321Sdamien	int hw;
880156321Sdamien
881156321Sdamien	/* retrieve last descriptor index processed by cipher engine */
882156321Sdamien	hw = RAL_READ(sc, RT2560_SECCSR1) - sc->txq.physaddr;
883156321Sdamien	hw /= RT2560_TX_DESC_SIZE;
884156321Sdamien
885156321Sdamien	bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map,
886156321Sdamien	    BUS_DMASYNC_POSTREAD);
887156321Sdamien
888156321Sdamien	for (; sc->txq.next_encrypt != hw;) {
889156321Sdamien		desc = &sc->txq.desc[sc->txq.next_encrypt];
890156321Sdamien
891156321Sdamien		if ((le32toh(desc->flags) & RT2560_TX_BUSY) ||
892156321Sdamien		    (le32toh(desc->flags) & RT2560_TX_CIPHER_BUSY))
893156321Sdamien			break;
894156321Sdamien
895156321Sdamien		/* for TKIP, swap eiv field to fix a bug in ASIC */
896156321Sdamien		if ((le32toh(desc->flags) & RT2560_TX_CIPHER_MASK) ==
897156321Sdamien		    RT2560_TX_CIPHER_TKIP)
898156321Sdamien			desc->eiv = bswap32(desc->eiv);
899156321Sdamien
900156321Sdamien		/* mark the frame ready for transmission */
901156321Sdamien		desc->flags |= htole32(RT2560_TX_BUSY | RT2560_TX_VALID);
902156321Sdamien
903156321Sdamien		DPRINTFN(15, ("encryption done idx=%u\n",
904156321Sdamien		    sc->txq.next_encrypt));
905156321Sdamien
906156321Sdamien		sc->txq.next_encrypt =
907156321Sdamien		    (sc->txq.next_encrypt + 1) % RT2560_TX_RING_COUNT;
908156321Sdamien	}
909156321Sdamien
910156321Sdamien	bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map,
911156321Sdamien	    BUS_DMASYNC_PREWRITE);
912156321Sdamien
913156321Sdamien	/* kick Tx */
914156321Sdamien	RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_TX);
915156321Sdamien}
916156321Sdamien
917156321Sdamienstatic void
918156321Sdamienrt2560_tx_intr(struct rt2560_softc *sc)
919156321Sdamien{
920156321Sdamien	struct ieee80211com *ic = &sc->sc_ic;
921156321Sdamien	struct ifnet *ifp = ic->ic_ifp;
922156321Sdamien	struct rt2560_tx_desc *desc;
923156321Sdamien	struct rt2560_tx_data *data;
924156321Sdamien	struct rt2560_node *rn;
925156321Sdamien
926156321Sdamien	bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map,
927156321Sdamien	    BUS_DMASYNC_POSTREAD);
928156321Sdamien
929156321Sdamien	for (;;) {
930156321Sdamien		desc = &sc->txq.desc[sc->txq.next];
931156321Sdamien		data = &sc->txq.data[sc->txq.next];
932156321Sdamien
933156321Sdamien		if ((le32toh(desc->flags) & RT2560_TX_BUSY) ||
934156321Sdamien		    (le32toh(desc->flags) & RT2560_TX_CIPHER_BUSY) ||
935156321Sdamien		    !(le32toh(desc->flags) & RT2560_TX_VALID))
936156321Sdamien			break;
937156321Sdamien
938156321Sdamien		rn = (struct rt2560_node *)data->ni;
939156321Sdamien
940156321Sdamien		switch (le32toh(desc->flags) & RT2560_TX_RESULT_MASK) {
941156321Sdamien		case RT2560_TX_SUCCESS:
942156321Sdamien			DPRINTFN(10, ("data frame sent successfully\n"));
943156321Sdamien			if (data->id.id_node != NULL) {
944156321Sdamien				ral_rssadapt_raise_rate(ic, &rn->rssadapt,
945156321Sdamien				    &data->id);
946156321Sdamien			}
947156321Sdamien			ifp->if_opackets++;
948156321Sdamien			break;
949156321Sdamien
950156321Sdamien		case RT2560_TX_SUCCESS_RETRY:
951156321Sdamien			DPRINTFN(9, ("data frame sent after %u retries\n",
952156321Sdamien			    (le32toh(desc->flags) >> 5) & 0x7));
953156321Sdamien			ifp->if_opackets++;
954156321Sdamien			break;
955156321Sdamien
956156321Sdamien		case RT2560_TX_FAIL_RETRY:
957156321Sdamien			DPRINTFN(9, ("sending data frame failed (too much "
958156321Sdamien			    "retries)\n"));
959156321Sdamien			if (data->id.id_node != NULL) {
960156321Sdamien				ral_rssadapt_lower_rate(ic, data->ni,
961156321Sdamien				    &rn->rssadapt, &data->id);
962156321Sdamien			}
963156321Sdamien			ifp->if_oerrors++;
964156321Sdamien			break;
965156321Sdamien
966156321Sdamien		case RT2560_TX_FAIL_INVALID:
967156321Sdamien		case RT2560_TX_FAIL_OTHER:
968156321Sdamien		default:
969156321Sdamien			device_printf(sc->sc_dev, "sending data frame failed "
970156321Sdamien			    "0x%08x\n", le32toh(desc->flags));
971156321Sdamien			ifp->if_oerrors++;
972156321Sdamien		}
973156321Sdamien
974156321Sdamien		bus_dmamap_sync(sc->txq.data_dmat, data->map,
975156321Sdamien		    BUS_DMASYNC_POSTWRITE);
976156321Sdamien		bus_dmamap_unload(sc->txq.data_dmat, data->map);
977156321Sdamien		m_freem(data->m);
978156321Sdamien		data->m = NULL;
979156321Sdamien		ieee80211_free_node(data->ni);
980156321Sdamien		data->ni = NULL;
981156321Sdamien
982156321Sdamien		/* descriptor is no longer valid */
983156321Sdamien		desc->flags &= ~htole32(RT2560_TX_VALID);
984156321Sdamien
985156321Sdamien		DPRINTFN(15, ("tx done idx=%u\n", sc->txq.next));
986156321Sdamien
987156321Sdamien		sc->txq.queued--;
988156321Sdamien		sc->txq.next = (sc->txq.next + 1) % RT2560_TX_RING_COUNT;
989156321Sdamien	}
990156321Sdamien
991156321Sdamien	bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map,
992156321Sdamien	    BUS_DMASYNC_PREWRITE);
993156321Sdamien
994156321Sdamien	sc->sc_tx_timer = 0;
995156321Sdamien	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
996156321Sdamien	rt2560_start(ifp);
997156321Sdamien}
998156321Sdamien
999156321Sdamienstatic void
1000156321Sdamienrt2560_prio_intr(struct rt2560_softc *sc)
1001156321Sdamien{
1002156321Sdamien	struct ieee80211com *ic = &sc->sc_ic;
1003156321Sdamien	struct ifnet *ifp = ic->ic_ifp;
1004156321Sdamien	struct rt2560_tx_desc *desc;
1005156321Sdamien	struct rt2560_tx_data *data;
1006170530Ssam	struct ieee80211_node *ni;
1007170530Ssam	struct mbuf *m;
1008170530Ssam	int flags;
1009156321Sdamien
1010156321Sdamien	bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map,
1011156321Sdamien	    BUS_DMASYNC_POSTREAD);
1012156321Sdamien
1013156321Sdamien	for (;;) {
1014156321Sdamien		desc = &sc->prioq.desc[sc->prioq.next];
1015156321Sdamien		data = &sc->prioq.data[sc->prioq.next];
1016156321Sdamien
1017170530Ssam		flags = le32toh(desc->flags);
1018170530Ssam		if ((flags & RT2560_TX_BUSY) || (flags & RT2560_TX_VALID) == 0)
1019156321Sdamien			break;
1020156321Sdamien
1021170530Ssam		switch (flags & RT2560_TX_RESULT_MASK) {
1022156321Sdamien		case RT2560_TX_SUCCESS:
1023156321Sdamien			DPRINTFN(10, ("mgt frame sent successfully\n"));
1024156321Sdamien			break;
1025156321Sdamien
1026156321Sdamien		case RT2560_TX_SUCCESS_RETRY:
1027156321Sdamien			DPRINTFN(9, ("mgt frame sent after %u retries\n",
1028170530Ssam			    (flags >> 5) & 0x7));
1029156321Sdamien			break;
1030156321Sdamien
1031156321Sdamien		case RT2560_TX_FAIL_RETRY:
1032156321Sdamien			DPRINTFN(9, ("sending mgt frame failed (too much "
1033156321Sdamien			    "retries)\n"));
1034156321Sdamien			break;
1035156321Sdamien
1036156321Sdamien		case RT2560_TX_FAIL_INVALID:
1037156321Sdamien		case RT2560_TX_FAIL_OTHER:
1038156321Sdamien		default:
1039156321Sdamien			device_printf(sc->sc_dev, "sending mgt frame failed "
1040170530Ssam			    "0x%08x\n", flags);
1041170530Ssam			break;
1042156321Sdamien		}
1043156321Sdamien
1044156321Sdamien		bus_dmamap_sync(sc->prioq.data_dmat, data->map,
1045156321Sdamien		    BUS_DMASYNC_POSTWRITE);
1046156321Sdamien		bus_dmamap_unload(sc->prioq.data_dmat, data->map);
1047170530Ssam
1048170530Ssam		m = data->m;
1049156321Sdamien		data->m = NULL;
1050170530Ssam		ni = data->ni;
1051156321Sdamien		data->ni = NULL;
1052156321Sdamien
1053156321Sdamien		/* descriptor is no longer valid */
1054156321Sdamien		desc->flags &= ~htole32(RT2560_TX_VALID);
1055156321Sdamien
1056156321Sdamien		DPRINTFN(15, ("prio done idx=%u\n", sc->prioq.next));
1057156321Sdamien
1058156321Sdamien		sc->prioq.queued--;
1059156321Sdamien		sc->prioq.next = (sc->prioq.next + 1) % RT2560_PRIO_RING_COUNT;
1060170530Ssam
1061170530Ssam		if (m->m_flags & M_TXCB)
1062170530Ssam			ieee80211_process_callback(ni, m,
1063170530Ssam				(flags & RT2560_TX_RESULT_MASK) &~
1064170530Ssam				(RT2560_TX_SUCCESS | RT2560_TX_SUCCESS_RETRY));
1065170530Ssam		m_freem(m);
1066170530Ssam		ieee80211_free_node(ni);
1067156321Sdamien	}
1068156321Sdamien
1069156321Sdamien	bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map,
1070156321Sdamien	    BUS_DMASYNC_PREWRITE);
1071156321Sdamien
1072156321Sdamien	sc->sc_tx_timer = 0;
1073156321Sdamien	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1074156321Sdamien	rt2560_start(ifp);
1075156321Sdamien}
1076156321Sdamien
1077156321Sdamien/*
1078156321Sdamien * Some frames were processed by the hardware cipher engine and are ready for
1079156321Sdamien * transmission to the IEEE802.11 layer.
1080156321Sdamien */
1081156321Sdamienstatic void
1082156321Sdamienrt2560_decryption_intr(struct rt2560_softc *sc)
1083156321Sdamien{
1084156321Sdamien	struct ieee80211com *ic = &sc->sc_ic;
1085156321Sdamien	struct ifnet *ifp = ic->ic_ifp;
1086156321Sdamien	struct rt2560_rx_desc *desc;
1087156321Sdamien	struct rt2560_rx_data *data;
1088156321Sdamien	bus_addr_t physaddr;
1089156321Sdamien	struct ieee80211_frame *wh;
1090156321Sdamien	struct ieee80211_node *ni;
1091156321Sdamien	struct rt2560_node *rn;
1092156321Sdamien	struct mbuf *mnew, *m;
1093156321Sdamien	int hw, error;
1094156321Sdamien
1095156321Sdamien	/* retrieve last decriptor index processed by cipher engine */
1096156321Sdamien	hw = RAL_READ(sc, RT2560_SECCSR0) - sc->rxq.physaddr;
1097156321Sdamien	hw /= RT2560_RX_DESC_SIZE;
1098156321Sdamien
1099156321Sdamien	bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map,
1100156321Sdamien	    BUS_DMASYNC_POSTREAD);
1101156321Sdamien
1102156321Sdamien	for (; sc->rxq.cur_decrypt != hw;) {
1103156321Sdamien		desc = &sc->rxq.desc[sc->rxq.cur_decrypt];
1104156321Sdamien		data = &sc->rxq.data[sc->rxq.cur_decrypt];
1105156321Sdamien
1106156321Sdamien		if ((le32toh(desc->flags) & RT2560_RX_BUSY) ||
1107156321Sdamien		    (le32toh(desc->flags) & RT2560_RX_CIPHER_BUSY))
1108156321Sdamien			break;
1109156321Sdamien
1110156321Sdamien		if (data->drop) {
1111156321Sdamien			ifp->if_ierrors++;
1112156321Sdamien			goto skip;
1113156321Sdamien		}
1114156321Sdamien
1115156321Sdamien		if ((le32toh(desc->flags) & RT2560_RX_CIPHER_MASK) != 0 &&
1116156321Sdamien		    (le32toh(desc->flags) & RT2560_RX_ICV_ERROR)) {
1117156321Sdamien			ifp->if_ierrors++;
1118156321Sdamien			goto skip;
1119156321Sdamien		}
1120156321Sdamien
1121156321Sdamien		/*
1122156321Sdamien		 * Try to allocate a new mbuf for this ring element and load it
1123156321Sdamien		 * before processing the current mbuf. If the ring element
1124156321Sdamien		 * cannot be loaded, drop the received packet and reuse the old
1125156321Sdamien		 * mbuf. In the unlikely case that the old mbuf can't be
1126156321Sdamien		 * reloaded either, explicitly panic.
1127156321Sdamien		 */
1128156321Sdamien		mnew = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
1129156321Sdamien		if (mnew == NULL) {
1130156321Sdamien			ifp->if_ierrors++;
1131156321Sdamien			goto skip;
1132156321Sdamien		}
1133156321Sdamien
1134156321Sdamien		bus_dmamap_sync(sc->rxq.data_dmat, data->map,
1135156321Sdamien		    BUS_DMASYNC_POSTREAD);
1136156321Sdamien		bus_dmamap_unload(sc->rxq.data_dmat, data->map);
1137156321Sdamien
1138156321Sdamien		error = bus_dmamap_load(sc->rxq.data_dmat, data->map,
1139156321Sdamien		    mtod(mnew, void *), MCLBYTES, rt2560_dma_map_addr,
1140156321Sdamien		    &physaddr, 0);
1141156321Sdamien		if (error != 0) {
1142156321Sdamien			m_freem(mnew);
1143156321Sdamien
1144156321Sdamien			/* try to reload the old mbuf */
1145156321Sdamien			error = bus_dmamap_load(sc->rxq.data_dmat, data->map,
1146156321Sdamien			    mtod(data->m, void *), MCLBYTES,
1147156321Sdamien			    rt2560_dma_map_addr, &physaddr, 0);
1148156321Sdamien			if (error != 0) {
1149156321Sdamien				/* very unlikely that it will fail... */
1150156321Sdamien				panic("%s: could not load old rx mbuf",
1151156321Sdamien				    device_get_name(sc->sc_dev));
1152156321Sdamien			}
1153156321Sdamien			ifp->if_ierrors++;
1154156321Sdamien			goto skip;
1155156321Sdamien		}
1156156321Sdamien
1157156321Sdamien		/*
1158156321Sdamien	 	 * New mbuf successfully loaded, update Rx ring and continue
1159156321Sdamien		 * processing.
1160156321Sdamien		 */
1161156321Sdamien		m = data->m;
1162156321Sdamien		data->m = mnew;
1163156321Sdamien		desc->physaddr = htole32(physaddr);
1164156321Sdamien
1165156321Sdamien		/* finalize mbuf */
1166156321Sdamien		m->m_pkthdr.rcvif = ifp;
1167156321Sdamien		m->m_pkthdr.len = m->m_len =
1168156321Sdamien		    (le32toh(desc->flags) >> 16) & 0xfff;
1169156321Sdamien
1170159180Scsjp		if (bpf_peers_present(sc->sc_drvbpf)) {
1171156321Sdamien			struct rt2560_rx_radiotap_header *tap = &sc->sc_rxtap;
1172156321Sdamien			uint32_t tsf_lo, tsf_hi;
1173156321Sdamien
1174156321Sdamien			/* get timestamp (low and high 32 bits) */
1175156321Sdamien			tsf_hi = RAL_READ(sc, RT2560_CSR17);
1176156321Sdamien			tsf_lo = RAL_READ(sc, RT2560_CSR16);
1177156321Sdamien
1178156321Sdamien			tap->wr_tsf =
1179156321Sdamien			    htole64(((uint64_t)tsf_hi << 32) | tsf_lo);
1180156321Sdamien			tap->wr_flags = 0;
1181156321Sdamien			tap->wr_rate = rt2560_rxrate(desc);
1182156321Sdamien			tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
1183156321Sdamien			tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
1184156321Sdamien			tap->wr_antenna = sc->rx_ant;
1185170530Ssam			tap->wr_antsignal = RT2560_RSSI(sc, desc->rssi);
1186156321Sdamien
1187156321Sdamien			bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m);
1188156321Sdamien		}
1189156321Sdamien
1190170530Ssam		sc->sc_flags |= RAL_INPUT_RUNNING;
1191170530Ssam		RAL_UNLOCK(sc);
1192156321Sdamien		wh = mtod(m, struct ieee80211_frame *);
1193156321Sdamien		ni = ieee80211_find_rxnode(ic,
1194156321Sdamien		    (struct ieee80211_frame_min *)wh);
1195156321Sdamien
1196156321Sdamien		/* send the frame to the 802.11 layer */
1197170530Ssam		ieee80211_input(ic, m, ni, RT2560_RSSI(sc, desc->rssi),
1198170530Ssam				RT2560_NOISE_FLOOR, 0);
1199156321Sdamien
1200156321Sdamien		/* give rssi to the rate adatation algorithm */
1201156321Sdamien		rn = (struct rt2560_node *)ni;
1202170530Ssam		ral_rssadapt_input(ic, ni, &rn->rssadapt,
1203170530Ssam				   RT2560_RSSI(sc, desc->rssi));
1204156321Sdamien
1205156321Sdamien		/* node is no longer needed */
1206156321Sdamien		ieee80211_free_node(ni);
1207156321Sdamien
1208170530Ssam		RAL_LOCK(sc);
1209170530Ssam		sc->sc_flags &= ~RAL_INPUT_RUNNING;
1210156321Sdamienskip:		desc->flags = htole32(RT2560_RX_BUSY);
1211156321Sdamien
1212156321Sdamien		DPRINTFN(15, ("decryption done idx=%u\n", sc->rxq.cur_decrypt));
1213156321Sdamien
1214156321Sdamien		sc->rxq.cur_decrypt =
1215156321Sdamien		    (sc->rxq.cur_decrypt + 1) % RT2560_RX_RING_COUNT;
1216156321Sdamien	}
1217156321Sdamien
1218156321Sdamien	bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map,
1219156321Sdamien	    BUS_DMASYNC_PREWRITE);
1220156321Sdamien}
1221156321Sdamien
1222156321Sdamien/*
1223156321Sdamien * Some frames were received. Pass them to the hardware cipher engine before
1224156321Sdamien * sending them to the 802.11 layer.
1225156321Sdamien */
1226156321Sdamienstatic void
1227156321Sdamienrt2560_rx_intr(struct rt2560_softc *sc)
1228156321Sdamien{
1229156321Sdamien	struct rt2560_rx_desc *desc;
1230156321Sdamien	struct rt2560_rx_data *data;
1231156321Sdamien
1232156321Sdamien	bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map,
1233156321Sdamien	    BUS_DMASYNC_POSTREAD);
1234156321Sdamien
1235156321Sdamien	for (;;) {
1236156321Sdamien		desc = &sc->rxq.desc[sc->rxq.cur];
1237156321Sdamien		data = &sc->rxq.data[sc->rxq.cur];
1238156321Sdamien
1239156321Sdamien		if ((le32toh(desc->flags) & RT2560_RX_BUSY) ||
1240156321Sdamien		    (le32toh(desc->flags) & RT2560_RX_CIPHER_BUSY))
1241156321Sdamien			break;
1242156321Sdamien
1243156321Sdamien		data->drop = 0;
1244156321Sdamien
1245156321Sdamien		if ((le32toh(desc->flags) & RT2560_RX_PHY_ERROR) ||
1246156321Sdamien		    (le32toh(desc->flags) & RT2560_RX_CRC_ERROR)) {
1247156321Sdamien			/*
1248156321Sdamien			 * This should not happen since we did not request
1249156321Sdamien			 * to receive those frames when we filled RXCSR0.
1250156321Sdamien			 */
1251156321Sdamien			DPRINTFN(5, ("PHY or CRC error flags 0x%08x\n",
1252156321Sdamien			    le32toh(desc->flags)));
1253156321Sdamien			data->drop = 1;
1254156321Sdamien		}
1255156321Sdamien
1256156321Sdamien		if (((le32toh(desc->flags) >> 16) & 0xfff) > MCLBYTES) {
1257156321Sdamien			DPRINTFN(5, ("bad length\n"));
1258156321Sdamien			data->drop = 1;
1259156321Sdamien		}
1260156321Sdamien
1261156321Sdamien		/* mark the frame for decryption */
1262156321Sdamien		desc->flags |= htole32(RT2560_RX_CIPHER_BUSY);
1263156321Sdamien
1264156321Sdamien		DPRINTFN(15, ("rx done idx=%u\n", sc->rxq.cur));
1265156321Sdamien
1266156321Sdamien		sc->rxq.cur = (sc->rxq.cur + 1) % RT2560_RX_RING_COUNT;
1267156321Sdamien	}
1268156321Sdamien
1269156321Sdamien	bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map,
1270156321Sdamien	    BUS_DMASYNC_PREWRITE);
1271156321Sdamien
1272156321Sdamien	/* kick decrypt */
1273156321Sdamien	RAL_WRITE(sc, RT2560_SECCSR0, RT2560_KICK_DECRYPT);
1274156321Sdamien}
1275156321Sdamien
1276156321Sdamien/*
1277156321Sdamien * This function is called periodically in IBSS mode when a new beacon must be
1278156321Sdamien * sent out.
1279156321Sdamien */
1280156321Sdamienstatic void
1281156321Sdamienrt2560_beacon_expire(struct rt2560_softc *sc)
1282156321Sdamien{
1283156321Sdamien	struct ieee80211com *ic = &sc->sc_ic;
1284156321Sdamien	struct rt2560_tx_data *data;
1285156321Sdamien
1286156321Sdamien	if (ic->ic_opmode != IEEE80211_M_IBSS &&
1287156321Sdamien	    ic->ic_opmode != IEEE80211_M_HOSTAP)
1288170530Ssam		return;
1289156321Sdamien
1290156321Sdamien	data = &sc->bcnq.data[sc->bcnq.next];
1291170530Ssam	/*
1292170530Ssam	 * Don't send beacon if bsschan isn't set
1293170530Ssam	 */
1294170530Ssam	if (data->ni == NULL)
1295170530Ssam	        return;
1296156321Sdamien
1297156321Sdamien	bus_dmamap_sync(sc->bcnq.data_dmat, data->map, BUS_DMASYNC_POSTWRITE);
1298156321Sdamien	bus_dmamap_unload(sc->bcnq.data_dmat, data->map);
1299156321Sdamien
1300156321Sdamien	ieee80211_beacon_update(ic, data->ni, &sc->sc_bo, data->m, 1);
1301156321Sdamien
1302159180Scsjp	if (bpf_peers_present(ic->ic_rawbpf))
1303156321Sdamien		bpf_mtap(ic->ic_rawbpf, data->m);
1304156321Sdamien
1305156321Sdamien	rt2560_tx_bcn(sc, data->m, data->ni);
1306156321Sdamien
1307156321Sdamien	DPRINTFN(15, ("beacon expired\n"));
1308156321Sdamien
1309156321Sdamien	sc->bcnq.next = (sc->bcnq.next + 1) % RT2560_BEACON_RING_COUNT;
1310156321Sdamien}
1311156321Sdamien
1312156321Sdamien/* ARGSUSED */
1313156321Sdamienstatic void
1314156321Sdamienrt2560_wakeup_expire(struct rt2560_softc *sc)
1315156321Sdamien{
1316156321Sdamien	DPRINTFN(2, ("wakeup expired\n"));
1317156321Sdamien}
1318156321Sdamien
1319156321Sdamienvoid
1320156321Sdamienrt2560_intr(void *arg)
1321156321Sdamien{
1322156321Sdamien	struct rt2560_softc *sc = arg;
1323156975Sdamien	struct ifnet *ifp = sc->sc_ifp;
1324156321Sdamien	uint32_t r;
1325156321Sdamien
1326156321Sdamien	RAL_LOCK(sc);
1327156321Sdamien
1328156321Sdamien	/* disable interrupts */
1329156321Sdamien	RAL_WRITE(sc, RT2560_CSR8, 0xffffffff);
1330156321Sdamien
1331156975Sdamien	/* don't re-enable interrupts if we're shutting down */
1332156975Sdamien	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1333156975Sdamien		RAL_UNLOCK(sc);
1334156975Sdamien		return;
1335156975Sdamien	}
1336156975Sdamien
1337156321Sdamien	r = RAL_READ(sc, RT2560_CSR7);
1338156321Sdamien	RAL_WRITE(sc, RT2560_CSR7, r);
1339156321Sdamien
1340156321Sdamien	if (r & RT2560_BEACON_EXPIRE)
1341156321Sdamien		rt2560_beacon_expire(sc);
1342156321Sdamien
1343156321Sdamien	if (r & RT2560_WAKEUP_EXPIRE)
1344156321Sdamien		rt2560_wakeup_expire(sc);
1345156321Sdamien
1346156321Sdamien	if (r & RT2560_ENCRYPTION_DONE)
1347156321Sdamien		rt2560_encryption_intr(sc);
1348156321Sdamien
1349156321Sdamien	if (r & RT2560_TX_DONE)
1350156321Sdamien		rt2560_tx_intr(sc);
1351156321Sdamien
1352156321Sdamien	if (r & RT2560_PRIO_DONE)
1353156321Sdamien		rt2560_prio_intr(sc);
1354156321Sdamien
1355156321Sdamien	if (r & RT2560_DECRYPTION_DONE)
1356156321Sdamien		rt2560_decryption_intr(sc);
1357156321Sdamien
1358156321Sdamien	if (r & RT2560_RX_DONE)
1359156321Sdamien		rt2560_rx_intr(sc);
1360156321Sdamien
1361156321Sdamien	/* re-enable interrupts */
1362156321Sdamien	RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK);
1363156321Sdamien
1364156321Sdamien	RAL_UNLOCK(sc);
1365156321Sdamien}
1366156321Sdamien
1367156321Sdamien/* quickly determine if a given rate is CCK or OFDM */
1368156321Sdamien#define RAL_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22)
1369156321Sdamien
1370156321Sdamien#define RAL_ACK_SIZE	14	/* 10 + 4(FCS) */
1371156321Sdamien#define RAL_CTS_SIZE	14	/* 10 + 4(FCS) */
1372156321Sdamien
1373156321Sdamien#define RAL_SIFS		10	/* us */
1374156321Sdamien
1375156321Sdamien#define RT2560_TXRX_TURNAROUND	10	/* us */
1376156321Sdamien
1377156321Sdamien/*
1378156321Sdamien * This function is only used by the Rx radiotap code.
1379156321Sdamien */
1380156321Sdamienstatic uint8_t
1381156321Sdamienrt2560_rxrate(struct rt2560_rx_desc *desc)
1382156321Sdamien{
1383156321Sdamien	if (le32toh(desc->flags) & RT2560_RX_OFDM) {
1384156321Sdamien		/* reverse function of rt2560_plcp_signal */
1385156321Sdamien		switch (desc->rate) {
1386156321Sdamien		case 0xb:	return 12;
1387156321Sdamien		case 0xf:	return 18;
1388156321Sdamien		case 0xa:	return 24;
1389156321Sdamien		case 0xe:	return 36;
1390156321Sdamien		case 0x9:	return 48;
1391156321Sdamien		case 0xd:	return 72;
1392156321Sdamien		case 0x8:	return 96;
1393156321Sdamien		case 0xc:	return 108;
1394156321Sdamien		}
1395156321Sdamien	} else {
1396156321Sdamien		if (desc->rate == 10)
1397156321Sdamien			return 2;
1398156321Sdamien		if (desc->rate == 20)
1399156321Sdamien			return 4;
1400156321Sdamien		if (desc->rate == 55)
1401156321Sdamien			return 11;
1402156321Sdamien		if (desc->rate == 110)
1403156321Sdamien			return 22;
1404156321Sdamien	}
1405156321Sdamien	return 2;	/* should not get there */
1406156321Sdamien}
1407156321Sdamien
1408156321Sdamien/*
1409156321Sdamien * Return the expected ack rate for a frame transmitted at rate `rate'.
1410156321Sdamien * XXX: this should depend on the destination node basic rate set.
1411156321Sdamien */
1412156321Sdamienstatic int
1413156321Sdamienrt2560_ack_rate(struct ieee80211com *ic, int rate)
1414156321Sdamien{
1415156321Sdamien	switch (rate) {
1416156321Sdamien	/* CCK rates */
1417156321Sdamien	case 2:
1418156321Sdamien		return 2;
1419156321Sdamien	case 4:
1420156321Sdamien	case 11:
1421156321Sdamien	case 22:
1422156321Sdamien		return (ic->ic_curmode == IEEE80211_MODE_11B) ? 4 : rate;
1423156321Sdamien
1424156321Sdamien	/* OFDM rates */
1425156321Sdamien	case 12:
1426156321Sdamien	case 18:
1427156321Sdamien		return 12;
1428156321Sdamien	case 24:
1429156321Sdamien	case 36:
1430156321Sdamien		return 24;
1431156321Sdamien	case 48:
1432156321Sdamien	case 72:
1433156321Sdamien	case 96:
1434156321Sdamien	case 108:
1435156321Sdamien		return 48;
1436156321Sdamien	}
1437156321Sdamien
1438156321Sdamien	/* default to 1Mbps */
1439156321Sdamien	return 2;
1440156321Sdamien}
1441156321Sdamien
1442156321Sdamien/*
1443156321Sdamien * Compute the duration (in us) needed to transmit `len' bytes at rate `rate'.
1444156321Sdamien * The function automatically determines the operating mode depending on the
1445156321Sdamien * given rate. `flags' indicates whether short preamble is in use or not.
1446156321Sdamien */
1447156321Sdamienstatic uint16_t
1448156321Sdamienrt2560_txtime(int len, int rate, uint32_t flags)
1449156321Sdamien{
1450156321Sdamien	uint16_t txtime;
1451156321Sdamien
1452156321Sdamien	if (RAL_RATE_IS_OFDM(rate)) {
1453156321Sdamien		/* IEEE Std 802.11a-1999, pp. 37 */
1454156321Sdamien		txtime = (8 + 4 * len + 3 + rate - 1) / rate;
1455156321Sdamien		txtime = 16 + 4 + 4 * txtime + 6;
1456156321Sdamien	} else {
1457156321Sdamien		/* IEEE Std 802.11b-1999, pp. 28 */
1458156321Sdamien		txtime = (16 * len + rate - 1) / rate;
1459156321Sdamien		if (rate != 2 && (flags & IEEE80211_F_SHPREAMBLE))
1460156321Sdamien			txtime +=  72 + 24;
1461156321Sdamien		else
1462156321Sdamien			txtime += 144 + 48;
1463156321Sdamien	}
1464156321Sdamien
1465156321Sdamien	return txtime;
1466156321Sdamien}
1467156321Sdamien
1468156321Sdamienstatic uint8_t
1469156321Sdamienrt2560_plcp_signal(int rate)
1470156321Sdamien{
1471156321Sdamien	switch (rate) {
1472156321Sdamien	/* CCK rates (returned values are device-dependent) */
1473156321Sdamien	case 2:		return 0x0;
1474156321Sdamien	case 4:		return 0x1;
1475156321Sdamien	case 11:	return 0x2;
1476156321Sdamien	case 22:	return 0x3;
1477156321Sdamien
1478156321Sdamien	/* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
1479156321Sdamien	case 12:	return 0xb;
1480156321Sdamien	case 18:	return 0xf;
1481156321Sdamien	case 24:	return 0xa;
1482156321Sdamien	case 36:	return 0xe;
1483156321Sdamien	case 48:	return 0x9;
1484156321Sdamien	case 72:	return 0xd;
1485156321Sdamien	case 96:	return 0x8;
1486156321Sdamien	case 108:	return 0xc;
1487156321Sdamien
1488156321Sdamien	/* unsupported rates (should not get there) */
1489156321Sdamien	default:	return 0xff;
1490156321Sdamien	}
1491156321Sdamien}
1492156321Sdamien
1493156321Sdamienstatic void
1494156321Sdamienrt2560_setup_tx_desc(struct rt2560_softc *sc, struct rt2560_tx_desc *desc,
1495156321Sdamien    uint32_t flags, int len, int rate, int encrypt, bus_addr_t physaddr)
1496156321Sdamien{
1497156321Sdamien	struct ieee80211com *ic = &sc->sc_ic;
1498156321Sdamien	uint16_t plcp_length;
1499156321Sdamien	int remainder;
1500156321Sdamien
1501156321Sdamien	desc->flags = htole32(flags);
1502156321Sdamien	desc->flags |= htole32(len << 16);
1503156321Sdamien	desc->flags |= encrypt ? htole32(RT2560_TX_CIPHER_BUSY) :
1504156321Sdamien	    htole32(RT2560_TX_BUSY | RT2560_TX_VALID);
1505156321Sdamien
1506156321Sdamien	desc->physaddr = htole32(physaddr);
1507156321Sdamien	desc->wme = htole16(
1508156321Sdamien	    RT2560_AIFSN(2) |
1509156321Sdamien	    RT2560_LOGCWMIN(3) |
1510156321Sdamien	    RT2560_LOGCWMAX(8));
1511156321Sdamien
1512156321Sdamien	/* setup PLCP fields */
1513156321Sdamien	desc->plcp_signal  = rt2560_plcp_signal(rate);
1514156321Sdamien	desc->plcp_service = 4;
1515156321Sdamien
1516156321Sdamien	len += IEEE80211_CRC_LEN;
1517156321Sdamien	if (RAL_RATE_IS_OFDM(rate)) {
1518156321Sdamien		desc->flags |= htole32(RT2560_TX_OFDM);
1519156321Sdamien
1520156321Sdamien		plcp_length = len & 0xfff;
1521156321Sdamien		desc->plcp_length_hi = plcp_length >> 6;
1522156321Sdamien		desc->plcp_length_lo = plcp_length & 0x3f;
1523156321Sdamien	} else {
1524156321Sdamien		plcp_length = (16 * len + rate - 1) / rate;
1525156321Sdamien		if (rate == 22) {
1526156321Sdamien			remainder = (16 * len) % 22;
1527156321Sdamien			if (remainder != 0 && remainder < 7)
1528156321Sdamien				desc->plcp_service |= RT2560_PLCP_LENGEXT;
1529156321Sdamien		}
1530156321Sdamien		desc->plcp_length_hi = plcp_length >> 8;
1531156321Sdamien		desc->plcp_length_lo = plcp_length & 0xff;
1532156321Sdamien
1533156321Sdamien		if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
1534156321Sdamien			desc->plcp_signal |= 0x08;
1535156321Sdamien	}
1536156321Sdamien}
1537156321Sdamien
1538156321Sdamienstatic int
1539156321Sdamienrt2560_tx_bcn(struct rt2560_softc *sc, struct mbuf *m0,
1540156321Sdamien    struct ieee80211_node *ni)
1541156321Sdamien{
1542156321Sdamien	struct ieee80211com *ic = &sc->sc_ic;
1543156321Sdamien	struct rt2560_tx_desc *desc;
1544156321Sdamien	struct rt2560_tx_data *data;
1545156321Sdamien	bus_dma_segment_t segs[RT2560_MAX_SCATTER];
1546156321Sdamien	int nsegs, rate, error;
1547156321Sdamien
1548156321Sdamien	desc = &sc->bcnq.desc[sc->bcnq.cur];
1549156321Sdamien	data = &sc->bcnq.data[sc->bcnq.cur];
1550156321Sdamien
1551156321Sdamien	rate = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? 12 : 2;
1552156321Sdamien
1553156321Sdamien	error = bus_dmamap_load_mbuf_sg(sc->bcnq.data_dmat, data->map, m0,
1554156321Sdamien	    segs, &nsegs, BUS_DMA_NOWAIT);
1555156321Sdamien	if (error != 0) {
1556156321Sdamien		device_printf(sc->sc_dev, "could not map mbuf (error %d)\n",
1557156321Sdamien		    error);
1558156321Sdamien		m_freem(m0);
1559156321Sdamien		return error;
1560156321Sdamien	}
1561156321Sdamien
1562159180Scsjp	if (bpf_peers_present(sc->sc_drvbpf)) {
1563156321Sdamien		struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap;
1564156321Sdamien
1565156321Sdamien		tap->wt_flags = 0;
1566156321Sdamien		tap->wt_rate = rate;
1567156321Sdamien		tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
1568156321Sdamien		tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
1569156321Sdamien		tap->wt_antenna = sc->tx_ant;
1570156321Sdamien
1571156321Sdamien		bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0);
1572156321Sdamien	}
1573156321Sdamien
1574156321Sdamien	data->m = m0;
1575156321Sdamien	data->ni = ni;
1576156321Sdamien
1577156321Sdamien	rt2560_setup_tx_desc(sc, desc, RT2560_TX_IFS_NEWBACKOFF |
1578156321Sdamien	    RT2560_TX_TIMESTAMP, m0->m_pkthdr.len, rate, 0, segs->ds_addr);
1579156321Sdamien
1580156321Sdamien	DPRINTFN(10, ("sending beacon frame len=%u idx=%u rate=%u\n",
1581156321Sdamien	    m0->m_pkthdr.len, sc->bcnq.cur, rate));
1582156321Sdamien
1583156321Sdamien	bus_dmamap_sync(sc->bcnq.data_dmat, data->map, BUS_DMASYNC_PREWRITE);
1584156321Sdamien	bus_dmamap_sync(sc->bcnq.desc_dmat, sc->bcnq.desc_map,
1585156321Sdamien	    BUS_DMASYNC_PREWRITE);
1586156321Sdamien
1587156321Sdamien	sc->bcnq.cur = (sc->bcnq.cur + 1) % RT2560_BEACON_RING_COUNT;
1588156321Sdamien
1589156321Sdamien	return 0;
1590156321Sdamien}
1591156321Sdamien
1592156321Sdamienstatic int
1593156321Sdamienrt2560_tx_mgt(struct rt2560_softc *sc, struct mbuf *m0,
1594156321Sdamien    struct ieee80211_node *ni)
1595156321Sdamien{
1596156321Sdamien	struct ieee80211com *ic = &sc->sc_ic;
1597156321Sdamien	struct rt2560_tx_desc *desc;
1598156321Sdamien	struct rt2560_tx_data *data;
1599156321Sdamien	struct ieee80211_frame *wh;
1600156321Sdamien	bus_dma_segment_t segs[RT2560_MAX_SCATTER];
1601156321Sdamien	uint16_t dur;
1602156321Sdamien	uint32_t flags = 0;
1603156321Sdamien	int nsegs, rate, error;
1604156321Sdamien
1605156321Sdamien	desc = &sc->prioq.desc[sc->prioq.cur];
1606156321Sdamien	data = &sc->prioq.data[sc->prioq.cur];
1607156321Sdamien
1608156321Sdamien	rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 2;
1609156321Sdamien
1610156321Sdamien	error = bus_dmamap_load_mbuf_sg(sc->prioq.data_dmat, data->map, m0,
1611156321Sdamien	    segs, &nsegs, 0);
1612156321Sdamien	if (error != 0) {
1613156321Sdamien		device_printf(sc->sc_dev, "could not map mbuf (error %d)\n",
1614156321Sdamien		    error);
1615156321Sdamien		m_freem(m0);
1616156321Sdamien		return error;
1617156321Sdamien	}
1618156321Sdamien
1619159180Scsjp	if (bpf_peers_present(sc->sc_drvbpf)) {
1620156321Sdamien		struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap;
1621156321Sdamien
1622156321Sdamien		tap->wt_flags = 0;
1623156321Sdamien		tap->wt_rate = rate;
1624156321Sdamien		tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
1625156321Sdamien		tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
1626156321Sdamien		tap->wt_antenna = sc->tx_ant;
1627156321Sdamien
1628156321Sdamien		bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0);
1629156321Sdamien	}
1630156321Sdamien
1631156321Sdamien	data->m = m0;
1632156321Sdamien	data->ni = ni;
1633156321Sdamien
1634156321Sdamien	wh = mtod(m0, struct ieee80211_frame *);
1635156321Sdamien
1636156321Sdamien	if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
1637156321Sdamien		flags |= RT2560_TX_ACK;
1638156321Sdamien
1639156321Sdamien		dur = rt2560_txtime(RAL_ACK_SIZE, rate, ic->ic_flags) +
1640156321Sdamien		      RAL_SIFS;
1641156321Sdamien		*(uint16_t *)wh->i_dur = htole16(dur);
1642156321Sdamien
1643156321Sdamien		/* tell hardware to add timestamp for probe responses */
1644156321Sdamien		if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
1645156321Sdamien		    IEEE80211_FC0_TYPE_MGT &&
1646156321Sdamien		    (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
1647156321Sdamien		    IEEE80211_FC0_SUBTYPE_PROBE_RESP)
1648156321Sdamien			flags |= RT2560_TX_TIMESTAMP;
1649156321Sdamien	}
1650156321Sdamien
1651156321Sdamien	rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate, 0,
1652156321Sdamien	    segs->ds_addr);
1653156321Sdamien
1654156321Sdamien	bus_dmamap_sync(sc->prioq.data_dmat, data->map, BUS_DMASYNC_PREWRITE);
1655156321Sdamien	bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map,
1656156321Sdamien	    BUS_DMASYNC_PREWRITE);
1657156321Sdamien
1658156321Sdamien	DPRINTFN(10, ("sending mgt frame len=%u idx=%u rate=%u\n",
1659156321Sdamien	    m0->m_pkthdr.len, sc->prioq.cur, rate));
1660156321Sdamien
1661156321Sdamien	/* kick prio */
1662156321Sdamien	sc->prioq.queued++;
1663156321Sdamien	sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT;
1664156321Sdamien	RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO);
1665156321Sdamien
1666156321Sdamien	return 0;
1667156321Sdamien}
1668156321Sdamien
1669160691Ssamstatic int
1670160691Ssamrt2560_tx_raw(struct rt2560_softc *sc, struct mbuf *m0,
1671160691Ssam    struct ieee80211_node *ni, const struct ieee80211_bpf_params *params)
1672160691Ssam{
1673160691Ssam	struct ieee80211com *ic = &sc->sc_ic;
1674160691Ssam	struct rt2560_tx_desc *desc;
1675160691Ssam	struct rt2560_tx_data *data;
1676160691Ssam	bus_dma_segment_t segs[RT2560_MAX_SCATTER];
1677160691Ssam	uint32_t flags;
1678160691Ssam	int nsegs, rate, error;
1679160691Ssam
1680160691Ssam	desc = &sc->prioq.desc[sc->prioq.cur];
1681160691Ssam	data = &sc->prioq.data[sc->prioq.cur];
1682160691Ssam
1683160691Ssam	rate = params->ibp_rate0 & IEEE80211_RATE_VAL;
1684160691Ssam	/* XXX validate */
1685168860Ssephe	if (rate == 0) {
1686168860Ssephe		m_freem(m0);
1687160691Ssam		return EINVAL;
1688168860Ssephe	}
1689160691Ssam
1690160691Ssam	error = bus_dmamap_load_mbuf_sg(sc->prioq.data_dmat, data->map, m0,
1691160691Ssam	    segs, &nsegs, 0);
1692160691Ssam	if (error != 0) {
1693160691Ssam		device_printf(sc->sc_dev, "could not map mbuf (error %d)\n",
1694160691Ssam		    error);
1695160691Ssam		m_freem(m0);
1696160691Ssam		return error;
1697160691Ssam	}
1698160691Ssam
1699160691Ssam	if (bpf_peers_present(sc->sc_drvbpf)) {
1700160691Ssam		struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap;
1701160691Ssam
1702160691Ssam		tap->wt_flags = 0;
1703160691Ssam		tap->wt_rate = rate;
1704160691Ssam		tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
1705160691Ssam		tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
1706160691Ssam		tap->wt_antenna = sc->tx_ant;
1707160691Ssam
1708160691Ssam		bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0);
1709160691Ssam	}
1710160691Ssam
1711160691Ssam	data->m = m0;
1712160691Ssam	data->ni = ni;
1713160691Ssam
1714160691Ssam	flags = 0;
1715160691Ssam	if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0)
1716160691Ssam		flags |= RT2560_TX_ACK;
1717160691Ssam
1718160691Ssam	/* XXX need to setup descriptor ourself */
1719160691Ssam	rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len,
1720160691Ssam	    rate, (params->ibp_flags & IEEE80211_BPF_CRYPTO) != 0,
1721160691Ssam	    segs->ds_addr);
1722160691Ssam
1723160691Ssam	bus_dmamap_sync(sc->prioq.data_dmat, data->map, BUS_DMASYNC_PREWRITE);
1724160691Ssam	bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map,
1725160691Ssam	    BUS_DMASYNC_PREWRITE);
1726160691Ssam
1727160691Ssam	DPRINTFN(10, ("sending raw frame len=%u idx=%u rate=%u\n",
1728160691Ssam	    m0->m_pkthdr.len, sc->prioq.cur, rate));
1729160691Ssam
1730160691Ssam	/* kick prio */
1731160691Ssam	sc->prioq.queued++;
1732160691Ssam	sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT;
1733160691Ssam	RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO);
1734160691Ssam
1735160691Ssam	return 0;
1736160691Ssam}
1737160691Ssam
1738156321Sdamien/*
1739156321Sdamien * Build a RTS control frame.
1740156321Sdamien */
1741156321Sdamienstatic struct mbuf *
1742156321Sdamienrt2560_get_rts(struct rt2560_softc *sc, struct ieee80211_frame *wh,
1743156321Sdamien    uint16_t dur)
1744156321Sdamien{
1745156321Sdamien	struct ieee80211_frame_rts *rts;
1746156321Sdamien	struct mbuf *m;
1747156321Sdamien
1748156321Sdamien	MGETHDR(m, M_DONTWAIT, MT_DATA);
1749156321Sdamien	if (m == NULL) {
1750156321Sdamien		sc->sc_ic.ic_stats.is_tx_nobuf++;
1751156321Sdamien		device_printf(sc->sc_dev, "could not allocate RTS frame\n");
1752156321Sdamien		return NULL;
1753156321Sdamien	}
1754156321Sdamien
1755156321Sdamien	rts = mtod(m, struct ieee80211_frame_rts *);
1756156321Sdamien
1757156321Sdamien	rts->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_CTL |
1758156321Sdamien	    IEEE80211_FC0_SUBTYPE_RTS;
1759156321Sdamien	rts->i_fc[1] = IEEE80211_FC1_DIR_NODS;
1760156321Sdamien	*(uint16_t *)rts->i_dur = htole16(dur);
1761156321Sdamien	IEEE80211_ADDR_COPY(rts->i_ra, wh->i_addr1);
1762156321Sdamien	IEEE80211_ADDR_COPY(rts->i_ta, wh->i_addr2);
1763156321Sdamien
1764156321Sdamien	m->m_pkthdr.len = m->m_len = sizeof (struct ieee80211_frame_rts);
1765156321Sdamien
1766156321Sdamien	return m;
1767156321Sdamien}
1768156321Sdamien
1769156321Sdamienstatic int
1770156321Sdamienrt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0,
1771156321Sdamien    struct ieee80211_node *ni)
1772156321Sdamien{
1773156321Sdamien	struct ieee80211com *ic = &sc->sc_ic;
1774156321Sdamien	struct rt2560_tx_desc *desc;
1775156321Sdamien	struct rt2560_tx_data *data;
1776156321Sdamien	struct rt2560_node *rn;
1777156321Sdamien	struct ieee80211_frame *wh;
1778156321Sdamien	struct ieee80211_key *k;
1779156321Sdamien	struct mbuf *mnew;
1780156321Sdamien	bus_dma_segment_t segs[RT2560_MAX_SCATTER];
1781156321Sdamien	uint16_t dur;
1782156321Sdamien	uint32_t flags = 0;
1783156321Sdamien	int nsegs, rate, error;
1784156321Sdamien
1785156321Sdamien	wh = mtod(m0, struct ieee80211_frame *);
1786156321Sdamien
1787156321Sdamien	if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
1788170530Ssam		rate = ic->ic_fixed_rate;
1789156321Sdamien	} else {
1790170530Ssam		struct ieee80211_rateset *rs;
1791170530Ssam
1792156321Sdamien		rs = &ni->ni_rates;
1793156321Sdamien		rn = (struct rt2560_node *)ni;
1794156321Sdamien		ni->ni_txrate = ral_rssadapt_choose(&rn->rssadapt, rs, wh,
1795156321Sdamien		    m0->m_pkthdr.len, NULL, 0);
1796156321Sdamien		rate = rs->rs_rates[ni->ni_txrate];
1797156321Sdamien	}
1798156321Sdamien	rate &= IEEE80211_RATE_VAL;
1799156321Sdamien
1800156321Sdamien	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
1801156321Sdamien		k = ieee80211_crypto_encap(ic, ni, m0);
1802156321Sdamien		if (k == NULL) {
1803156321Sdamien			m_freem(m0);
1804156321Sdamien			return ENOBUFS;
1805156321Sdamien		}
1806156321Sdamien
1807156321Sdamien		/* packet header may have moved, reset our local pointer */
1808156321Sdamien		wh = mtod(m0, struct ieee80211_frame *);
1809156321Sdamien	}
1810156321Sdamien
1811156321Sdamien	/*
1812156321Sdamien	 * IEEE Std 802.11-1999, pp 82: "A STA shall use an RTS/CTS exchange
1813156321Sdamien	 * for directed frames only when the length of the MPDU is greater
1814156321Sdamien	 * than the length threshold indicated by [...]" ic_rtsthreshold.
1815156321Sdamien	 */
1816156321Sdamien	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
1817156321Sdamien	    m0->m_pkthdr.len > ic->ic_rtsthreshold) {
1818156321Sdamien		struct mbuf *m;
1819156321Sdamien		uint16_t dur;
1820156321Sdamien		int rtsrate, ackrate;
1821156321Sdamien
1822156321Sdamien		rtsrate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 2;
1823156321Sdamien		ackrate = rt2560_ack_rate(ic, rate);
1824156321Sdamien
1825156321Sdamien		dur = rt2560_txtime(m0->m_pkthdr.len + 4, rate, ic->ic_flags) +
1826156321Sdamien		      rt2560_txtime(RAL_CTS_SIZE, rtsrate, ic->ic_flags) +
1827156321Sdamien		      rt2560_txtime(RAL_ACK_SIZE, ackrate, ic->ic_flags) +
1828156321Sdamien		      3 * RAL_SIFS;
1829156321Sdamien
1830156321Sdamien		m = rt2560_get_rts(sc, wh, dur);
1831156321Sdamien
1832156321Sdamien		desc = &sc->txq.desc[sc->txq.cur_encrypt];
1833156321Sdamien		data = &sc->txq.data[sc->txq.cur_encrypt];
1834156321Sdamien
1835156321Sdamien		error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map,
1836156321Sdamien		    m, segs, &nsegs, 0);
1837156321Sdamien		if (error != 0) {
1838156321Sdamien			device_printf(sc->sc_dev,
1839156321Sdamien			    "could not map mbuf (error %d)\n", error);
1840156321Sdamien			m_freem(m);
1841156321Sdamien			m_freem(m0);
1842156321Sdamien			return error;
1843156321Sdamien		}
1844156321Sdamien
1845156321Sdamien		/* avoid multiple free() of the same node for each fragment */
1846156321Sdamien		ieee80211_ref_node(ni);
1847156321Sdamien
1848156321Sdamien		data->m = m;
1849156321Sdamien		data->ni = ni;
1850156321Sdamien
1851156321Sdamien		/* RTS frames are not taken into account for rssadapt */
1852156321Sdamien		data->id.id_node = NULL;
1853156321Sdamien
1854156321Sdamien		rt2560_setup_tx_desc(sc, desc, RT2560_TX_ACK |
1855156321Sdamien		    RT2560_TX_MORE_FRAG, m->m_pkthdr.len, rtsrate, 1,
1856156321Sdamien		    segs->ds_addr);
1857156321Sdamien
1858156321Sdamien		bus_dmamap_sync(sc->txq.data_dmat, data->map,
1859156321Sdamien		    BUS_DMASYNC_PREWRITE);
1860156321Sdamien
1861156321Sdamien		sc->txq.queued++;
1862156321Sdamien		sc->txq.cur_encrypt =
1863156321Sdamien		    (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT;
1864156321Sdamien
1865156321Sdamien		/*
1866156321Sdamien		 * IEEE Std 802.11-1999: when an RTS/CTS exchange is used, the
1867156321Sdamien		 * asynchronous data frame shall be transmitted after the CTS
1868156321Sdamien		 * frame and a SIFS period.
1869156321Sdamien		 */
1870156321Sdamien		flags |= RT2560_TX_LONG_RETRY | RT2560_TX_IFS_SIFS;
1871156321Sdamien	}
1872156321Sdamien
1873156321Sdamien	data = &sc->txq.data[sc->txq.cur_encrypt];
1874156321Sdamien	desc = &sc->txq.desc[sc->txq.cur_encrypt];
1875156321Sdamien
1876156321Sdamien	error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, m0,
1877156321Sdamien	    segs, &nsegs, 0);
1878156321Sdamien	if (error != 0 && error != EFBIG) {
1879156321Sdamien		device_printf(sc->sc_dev, "could not map mbuf (error %d)\n",
1880156321Sdamien		    error);
1881156321Sdamien		m_freem(m0);
1882156321Sdamien		return error;
1883156321Sdamien	}
1884156321Sdamien	if (error != 0) {
1885156321Sdamien		mnew = m_defrag(m0, M_DONTWAIT);
1886156321Sdamien		if (mnew == NULL) {
1887156321Sdamien			device_printf(sc->sc_dev,
1888156321Sdamien			    "could not defragment mbuf\n");
1889156321Sdamien			m_freem(m0);
1890156321Sdamien			return ENOBUFS;
1891156321Sdamien		}
1892156321Sdamien		m0 = mnew;
1893156321Sdamien
1894156321Sdamien		error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map,
1895156321Sdamien		    m0, segs, &nsegs, 0);
1896156321Sdamien		if (error != 0) {
1897156321Sdamien			device_printf(sc->sc_dev,
1898156321Sdamien			    "could not map mbuf (error %d)\n", error);
1899156321Sdamien			m_freem(m0);
1900156321Sdamien			return error;
1901156321Sdamien		}
1902156321Sdamien
1903156321Sdamien		/* packet header may have moved, reset our local pointer */
1904156321Sdamien		wh = mtod(m0, struct ieee80211_frame *);
1905156321Sdamien	}
1906156321Sdamien
1907159180Scsjp	if (bpf_peers_present(sc->sc_drvbpf)) {
1908156321Sdamien		struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap;
1909156321Sdamien
1910156321Sdamien		tap->wt_flags = 0;
1911156321Sdamien		tap->wt_rate = rate;
1912156321Sdamien		tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
1913156321Sdamien		tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
1914156321Sdamien		tap->wt_antenna = sc->tx_ant;
1915156321Sdamien
1916156321Sdamien		bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0);
1917156321Sdamien	}
1918156321Sdamien
1919156321Sdamien	data->m = m0;
1920156321Sdamien	data->ni = ni;
1921156321Sdamien
1922156321Sdamien	/* remember link conditions for rate adaptation algorithm */
1923156321Sdamien	if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) {
1924156321Sdamien		data->id.id_len = m0->m_pkthdr.len;
1925156321Sdamien		data->id.id_rateidx = ni->ni_txrate;
1926156321Sdamien		data->id.id_node = ni;
1927156321Sdamien		data->id.id_rssi = ni->ni_rssi;
1928156321Sdamien	} else
1929156321Sdamien		data->id.id_node = NULL;
1930156321Sdamien
1931156321Sdamien	if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
1932156321Sdamien		flags |= RT2560_TX_ACK;
1933156321Sdamien
1934156321Sdamien		dur = rt2560_txtime(RAL_ACK_SIZE, rt2560_ack_rate(ic, rate),
1935156321Sdamien		    ic->ic_flags) + RAL_SIFS;
1936156321Sdamien		*(uint16_t *)wh->i_dur = htole16(dur);
1937156321Sdamien	}
1938156321Sdamien
1939156321Sdamien	rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate, 1,
1940156321Sdamien	    segs->ds_addr);
1941156321Sdamien
1942156321Sdamien	bus_dmamap_sync(sc->txq.data_dmat, data->map, BUS_DMASYNC_PREWRITE);
1943156321Sdamien	bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map,
1944156321Sdamien	    BUS_DMASYNC_PREWRITE);
1945156321Sdamien
1946156321Sdamien	DPRINTFN(10, ("sending data frame len=%u idx=%u rate=%u\n",
1947156321Sdamien	    m0->m_pkthdr.len, sc->txq.cur_encrypt, rate));
1948156321Sdamien
1949156321Sdamien	/* kick encrypt */
1950156321Sdamien	sc->txq.queued++;
1951156321Sdamien	sc->txq.cur_encrypt = (sc->txq.cur_encrypt + 1) % RT2560_TX_RING_COUNT;
1952156321Sdamien	RAL_WRITE(sc, RT2560_SECCSR1, RT2560_KICK_ENCRYPT);
1953156321Sdamien
1954156321Sdamien	return 0;
1955156321Sdamien}
1956156321Sdamien
1957156321Sdamienstatic void
1958156321Sdamienrt2560_start(struct ifnet *ifp)
1959156321Sdamien{
1960156321Sdamien	struct rt2560_softc *sc = ifp->if_softc;
1961156321Sdamien	struct ieee80211com *ic = &sc->sc_ic;
1962156321Sdamien	struct mbuf *m0;
1963156321Sdamien	struct ether_header *eh;
1964156321Sdamien	struct ieee80211_node *ni;
1965156321Sdamien
1966156321Sdamien	RAL_LOCK(sc);
1967156321Sdamien
1968156975Sdamien	/* prevent management frames from being sent if we're not ready */
1969156975Sdamien	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1970156975Sdamien		RAL_UNLOCK(sc);
1971156975Sdamien		return;
1972156975Sdamien	}
1973156975Sdamien
1974156321Sdamien	for (;;) {
1975156321Sdamien		IF_POLL(&ic->ic_mgtq, m0);
1976156321Sdamien		if (m0 != NULL) {
1977156321Sdamien			if (sc->prioq.queued >= RT2560_PRIO_RING_COUNT) {
1978156321Sdamien				ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1979156321Sdamien				break;
1980156321Sdamien			}
1981156321Sdamien			IF_DEQUEUE(&ic->ic_mgtq, m0);
1982156321Sdamien
1983156321Sdamien			ni = (struct ieee80211_node *)m0->m_pkthdr.rcvif;
1984156321Sdamien			m0->m_pkthdr.rcvif = NULL;
1985156321Sdamien
1986159180Scsjp			if (bpf_peers_present(ic->ic_rawbpf))
1987156321Sdamien				bpf_mtap(ic->ic_rawbpf, m0);
1988156321Sdamien
1989170530Ssam			if (rt2560_tx_mgt(sc, m0, ni) != 0) {
1990170530Ssam				ieee80211_free_node(ni);
1991156321Sdamien				break;
1992170530Ssam			}
1993156321Sdamien		} else {
1994156321Sdamien			if (ic->ic_state != IEEE80211_S_RUN)
1995156321Sdamien				break;
1996156321Sdamien			IFQ_DRV_DEQUEUE(&ifp->if_snd, m0);
1997156321Sdamien			if (m0 == NULL)
1998156321Sdamien				break;
1999156321Sdamien			if (sc->txq.queued >= RT2560_TX_RING_COUNT - 1) {
2000156321Sdamien				IFQ_DRV_PREPEND(&ifp->if_snd, m0);
2001156321Sdamien				ifp->if_drv_flags |= IFF_DRV_OACTIVE;
2002156321Sdamien				break;
2003156321Sdamien			}
2004156321Sdamien
2005156321Sdamien			if (m0->m_len < sizeof (struct ether_header) &&
2006156321Sdamien			    !(m0 = m_pullup(m0, sizeof (struct ether_header))))
2007156321Sdamien				continue;
2008156321Sdamien
2009156321Sdamien			eh = mtod(m0, struct ether_header *);
2010156321Sdamien			ni = ieee80211_find_txnode(ic, eh->ether_dhost);
2011156321Sdamien			if (ni == NULL) {
2012156321Sdamien				m_freem(m0);
2013156321Sdamien				continue;
2014156321Sdamien			}
2015170530Ssam			if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
2016170530Ssam			    (m0->m_flags & M_PWR_SAV) == 0) {
2017170530Ssam				/*
2018170530Ssam				 * Station in power save mode; pass the frame
2019170530Ssam				 * to the 802.11 layer and continue.  We'll get
2020170530Ssam				 * the frame back when the time is right.
2021170530Ssam				 */
2022170530Ssam				ieee80211_pwrsave(ni, m0);
2023170530Ssam				/*
2024170530Ssam				 * If we're in power save mode 'cuz of a bg
2025170530Ssam				 * scan cancel it so the traffic can flow.
2026170530Ssam				 * The packet we just queued will automatically
2027170530Ssam				 * get sent when we drop out of power save.
2028170530Ssam				 * XXX locking
2029170530Ssam				 */
2030170530Ssam				if (ic->ic_flags & IEEE80211_F_SCAN)
2031170530Ssam					ieee80211_cancel_scan(ic);
2032170530Ssam				ieee80211_free_node(ni);
2033170530Ssam				continue;
2034170530Ssam
2035170530Ssam			}
2036170530Ssam
2037156321Sdamien			BPF_MTAP(ifp, m0);
2038156321Sdamien
2039156321Sdamien			m0 = ieee80211_encap(ic, m0, ni);
2040156321Sdamien			if (m0 == NULL) {
2041156321Sdamien				ieee80211_free_node(ni);
2042156321Sdamien				continue;
2043156321Sdamien			}
2044170530Ssam
2045159180Scsjp			if (bpf_peers_present(ic->ic_rawbpf))
2046156321Sdamien				bpf_mtap(ic->ic_rawbpf, m0);
2047156321Sdamien
2048156321Sdamien			if (rt2560_tx_data(sc, m0, ni) != 0) {
2049156321Sdamien				ieee80211_free_node(ni);
2050156321Sdamien				ifp->if_oerrors++;
2051156321Sdamien				break;
2052156321Sdamien			}
2053156321Sdamien		}
2054156321Sdamien
2055156321Sdamien		sc->sc_tx_timer = 5;
2056165352Sbms		callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc);
2057156321Sdamien	}
2058156321Sdamien
2059156321Sdamien	RAL_UNLOCK(sc);
2060156321Sdamien}
2061156321Sdamien
2062156321Sdamienstatic void
2063165352Sbmsrt2560_watchdog(void *arg)
2064156321Sdamien{
2065167470Ssam	struct rt2560_softc *sc = arg;
2066156321Sdamien
2067156321Sdamien	if (sc->sc_tx_timer > 0) {
2068156321Sdamien		if (--sc->sc_tx_timer == 0) {
2069156321Sdamien			device_printf(sc->sc_dev, "device timeout\n");
2070156321Sdamien			rt2560_init(sc);
2071165352Sbms			sc->sc_ifp->if_oerrors++;
2072156321Sdamien			return;
2073156321Sdamien		}
2074165352Sbms		callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc);
2075156321Sdamien	}
2076156321Sdamien}
2077156321Sdamien
2078156321Sdamien/*
2079156321Sdamien * This function allows for fast channel switching in monitor mode (used by
2080156321Sdamien * net-mgmt/kismet). In IBSS mode, we must explicitly reset the interface to
2081156321Sdamien * generate a new beacon frame.
2082156321Sdamien */
2083156321Sdamienstatic int
2084156321Sdamienrt2560_reset(struct ifnet *ifp)
2085156321Sdamien{
2086156321Sdamien	struct rt2560_softc *sc = ifp->if_softc;
2087156321Sdamien	struct ieee80211com *ic = &sc->sc_ic;
2088156321Sdamien
2089156321Sdamien	if (ic->ic_opmode != IEEE80211_M_MONITOR)
2090156321Sdamien		return ENETRESET;
2091156321Sdamien
2092156321Sdamien	rt2560_set_chan(sc, ic->ic_curchan);
2093156321Sdamien
2094156321Sdamien	return 0;
2095156321Sdamien}
2096156321Sdamien
2097156321Sdamienstatic int
2098156321Sdamienrt2560_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
2099156321Sdamien{
2100156321Sdamien	struct rt2560_softc *sc = ifp->if_softc;
2101156321Sdamien	struct ieee80211com *ic = &sc->sc_ic;
2102156321Sdamien	int error = 0;
2103156321Sdamien
2104156321Sdamien
2105170530Ssam
2106156321Sdamien	switch (cmd) {
2107156321Sdamien	case SIOCSIFFLAGS:
2108156321Sdamien		if (ifp->if_flags & IFF_UP) {
2109170530Ssam			RAL_LOCK(sc);
2110156321Sdamien			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
2111156321Sdamien				rt2560_update_promisc(sc);
2112156321Sdamien			else
2113156321Sdamien				rt2560_init(sc);
2114170530Ssam			RAL_UNLOCK(sc);
2115156321Sdamien		} else {
2116156321Sdamien			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
2117156321Sdamien				rt2560_stop(sc);
2118156321Sdamien		}
2119170530Ssam
2120156321Sdamien		break;
2121156321Sdamien
2122156321Sdamien	default:
2123156321Sdamien		error = ieee80211_ioctl(ic, cmd, data);
2124156321Sdamien	}
2125156321Sdamien
2126156321Sdamien	if (error == ENETRESET) {
2127156321Sdamien		if ((ifp->if_flags & IFF_UP) &&
2128156321Sdamien		    (ifp->if_drv_flags & IFF_DRV_RUNNING) &&
2129156321Sdamien		    (ic->ic_roaming != IEEE80211_ROAMING_MANUAL))
2130156321Sdamien			rt2560_init(sc);
2131156321Sdamien		error = 0;
2132156321Sdamien	}
2133156321Sdamien
2134156321Sdamien
2135156321Sdamien	return error;
2136156321Sdamien}
2137156321Sdamien
2138156321Sdamienstatic void
2139156321Sdamienrt2560_bbp_write(struct rt2560_softc *sc, uint8_t reg, uint8_t val)
2140156321Sdamien{
2141156321Sdamien	uint32_t tmp;
2142156321Sdamien	int ntries;
2143156321Sdamien
2144156321Sdamien	for (ntries = 0; ntries < 100; ntries++) {
2145156321Sdamien		if (!(RAL_READ(sc, RT2560_BBPCSR) & RT2560_BBP_BUSY))
2146156321Sdamien			break;
2147156321Sdamien		DELAY(1);
2148156321Sdamien	}
2149156321Sdamien	if (ntries == 100) {
2150156321Sdamien		device_printf(sc->sc_dev, "could not write to BBP\n");
2151156321Sdamien		return;
2152156321Sdamien	}
2153156321Sdamien
2154156321Sdamien	tmp = RT2560_BBP_WRITE | RT2560_BBP_BUSY | reg << 8 | val;
2155156321Sdamien	RAL_WRITE(sc, RT2560_BBPCSR, tmp);
2156156321Sdamien
2157156321Sdamien	DPRINTFN(15, ("BBP R%u <- 0x%02x\n", reg, val));
2158156321Sdamien}
2159156321Sdamien
2160156321Sdamienstatic uint8_t
2161156321Sdamienrt2560_bbp_read(struct rt2560_softc *sc, uint8_t reg)
2162156321Sdamien{
2163156321Sdamien	uint32_t val;
2164156321Sdamien	int ntries;
2165156321Sdamien
2166156321Sdamien	val = RT2560_BBP_BUSY | reg << 8;
2167156321Sdamien	RAL_WRITE(sc, RT2560_BBPCSR, val);
2168156321Sdamien
2169156321Sdamien	for (ntries = 0; ntries < 100; ntries++) {
2170156321Sdamien		val = RAL_READ(sc, RT2560_BBPCSR);
2171156321Sdamien		if (!(val & RT2560_BBP_BUSY))
2172156321Sdamien			return val & 0xff;
2173156321Sdamien		DELAY(1);
2174156321Sdamien	}
2175156321Sdamien
2176156321Sdamien	device_printf(sc->sc_dev, "could not read from BBP\n");
2177156321Sdamien	return 0;
2178156321Sdamien}
2179156321Sdamien
2180156321Sdamienstatic void
2181156321Sdamienrt2560_rf_write(struct rt2560_softc *sc, uint8_t reg, uint32_t val)
2182156321Sdamien{
2183156321Sdamien	uint32_t tmp;
2184156321Sdamien	int ntries;
2185156321Sdamien
2186156321Sdamien	for (ntries = 0; ntries < 100; ntries++) {
2187156321Sdamien		if (!(RAL_READ(sc, RT2560_RFCSR) & RT2560_RF_BUSY))
2188156321Sdamien			break;
2189156321Sdamien		DELAY(1);
2190156321Sdamien	}
2191156321Sdamien	if (ntries == 100) {
2192156321Sdamien		device_printf(sc->sc_dev, "could not write to RF\n");
2193156321Sdamien		return;
2194156321Sdamien	}
2195156321Sdamien
2196156321Sdamien	tmp = RT2560_RF_BUSY | RT2560_RF_20BIT | (val & 0xfffff) << 2 |
2197156321Sdamien	    (reg & 0x3);
2198156321Sdamien	RAL_WRITE(sc, RT2560_RFCSR, tmp);
2199156321Sdamien
2200156321Sdamien	/* remember last written value in sc */
2201156321Sdamien	sc->rf_regs[reg] = val;
2202156321Sdamien
2203156321Sdamien	DPRINTFN(15, ("RF R[%u] <- 0x%05x\n", reg & 0x3, val & 0xfffff));
2204156321Sdamien}
2205156321Sdamien
2206156321Sdamienstatic void
2207156321Sdamienrt2560_set_chan(struct rt2560_softc *sc, struct ieee80211_channel *c)
2208156321Sdamien{
2209156321Sdamien	struct ieee80211com *ic = &sc->sc_ic;
2210156321Sdamien	uint8_t power, tmp;
2211156321Sdamien	u_int i, chan;
2212156321Sdamien
2213156321Sdamien	chan = ieee80211_chan2ieee(ic, c);
2214156321Sdamien	if (chan == 0 || chan == IEEE80211_CHAN_ANY)
2215156321Sdamien		return;
2216156321Sdamien
2217156321Sdamien	if (IEEE80211_IS_CHAN_2GHZ(c))
2218156321Sdamien		power = min(sc->txpow[chan - 1], 31);
2219156321Sdamien	else
2220156321Sdamien		power = 31;
2221156321Sdamien
2222156321Sdamien	/* adjust txpower using ifconfig settings */
2223156321Sdamien	power -= (100 - ic->ic_txpowlimit) / 8;
2224156321Sdamien
2225156321Sdamien	DPRINTFN(2, ("setting channel to %u, txpower to %u\n", chan, power));
2226156321Sdamien
2227156321Sdamien	switch (sc->rf_rev) {
2228156321Sdamien	case RT2560_RF_2522:
2229156321Sdamien		rt2560_rf_write(sc, RAL_RF1, 0x00814);
2230156321Sdamien		rt2560_rf_write(sc, RAL_RF2, rt2560_rf2522_r2[chan - 1]);
2231156321Sdamien		rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040);
2232156321Sdamien		break;
2233156321Sdamien
2234156321Sdamien	case RT2560_RF_2523:
2235156321Sdamien		rt2560_rf_write(sc, RAL_RF1, 0x08804);
2236156321Sdamien		rt2560_rf_write(sc, RAL_RF2, rt2560_rf2523_r2[chan - 1]);
2237156321Sdamien		rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x38044);
2238156321Sdamien		rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286);
2239156321Sdamien		break;
2240156321Sdamien
2241156321Sdamien	case RT2560_RF_2524:
2242156321Sdamien		rt2560_rf_write(sc, RAL_RF1, 0x0c808);
2243156321Sdamien		rt2560_rf_write(sc, RAL_RF2, rt2560_rf2524_r2[chan - 1]);
2244156321Sdamien		rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040);
2245156321Sdamien		rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286);
2246156321Sdamien		break;
2247156321Sdamien
2248156321Sdamien	case RT2560_RF_2525:
2249156321Sdamien		rt2560_rf_write(sc, RAL_RF1, 0x08808);
2250156321Sdamien		rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525_hi_r2[chan - 1]);
2251156321Sdamien		rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044);
2252156321Sdamien		rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286);
2253156321Sdamien
2254156321Sdamien		rt2560_rf_write(sc, RAL_RF1, 0x08808);
2255156321Sdamien		rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525_r2[chan - 1]);
2256156321Sdamien		rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044);
2257156321Sdamien		rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286);
2258156321Sdamien		break;
2259156321Sdamien
2260156321Sdamien	case RT2560_RF_2525E:
2261156321Sdamien		rt2560_rf_write(sc, RAL_RF1, 0x08808);
2262156321Sdamien		rt2560_rf_write(sc, RAL_RF2, rt2560_rf2525e_r2[chan - 1]);
2263156321Sdamien		rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044);
2264156321Sdamien		rt2560_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00286 : 0x00282);
2265156321Sdamien		break;
2266156321Sdamien
2267156321Sdamien	case RT2560_RF_2526:
2268156321Sdamien		rt2560_rf_write(sc, RAL_RF2, rt2560_rf2526_hi_r2[chan - 1]);
2269156321Sdamien		rt2560_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381);
2270156321Sdamien		rt2560_rf_write(sc, RAL_RF1, 0x08804);
2271156321Sdamien
2272156321Sdamien		rt2560_rf_write(sc, RAL_RF2, rt2560_rf2526_r2[chan - 1]);
2273156321Sdamien		rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x18044);
2274156321Sdamien		rt2560_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381);
2275156321Sdamien		break;
2276156321Sdamien
2277156321Sdamien	/* dual-band RF */
2278156321Sdamien	case RT2560_RF_5222:
2279156321Sdamien		for (i = 0; rt2560_rf5222[i].chan != chan; i++);
2280156321Sdamien
2281156321Sdamien		rt2560_rf_write(sc, RAL_RF1, rt2560_rf5222[i].r1);
2282156321Sdamien		rt2560_rf_write(sc, RAL_RF2, rt2560_rf5222[i].r2);
2283156321Sdamien		rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040);
2284156321Sdamien		rt2560_rf_write(sc, RAL_RF4, rt2560_rf5222[i].r4);
2285156321Sdamien		break;
2286170530Ssam	default:
2287170530Ssam 	        printf("unknown ral rev=%d\n", sc->rf_rev);
2288156321Sdamien	}
2289156321Sdamien
2290156321Sdamien	if (ic->ic_state != IEEE80211_S_SCAN) {
2291156321Sdamien		/* set Japan filter bit for channel 14 */
2292156321Sdamien		tmp = rt2560_bbp_read(sc, 70);
2293156321Sdamien
2294156321Sdamien		tmp &= ~RT2560_JAPAN_FILTER;
2295156321Sdamien		if (chan == 14)
2296156321Sdamien			tmp |= RT2560_JAPAN_FILTER;
2297156321Sdamien
2298156321Sdamien		rt2560_bbp_write(sc, 70, tmp);
2299156321Sdamien
2300156321Sdamien		/* clear CRC errors */
2301156321Sdamien		RAL_READ(sc, RT2560_CNT0);
2302156321Sdamien	}
2303156321Sdamien}
2304156321Sdamien
2305170530Ssamstatic void
2306170530Ssamrt2560_set_channel(struct ieee80211com *ic)
2307170530Ssam{
2308170530Ssam	struct ifnet *ifp = ic->ic_ifp;
2309170530Ssam	struct rt2560_softc *sc = ifp->if_softc;
2310170530Ssam
2311170530Ssam	RAL_LOCK(sc);
2312170530Ssam	rt2560_set_chan(sc, ic->ic_curchan);
2313170530Ssam	RAL_UNLOCK(sc);
2314170530Ssam
2315170530Ssam}
2316170530Ssam
2317156321Sdamien#if 0
2318156321Sdamien/*
2319156321Sdamien * Disable RF auto-tuning.
2320156321Sdamien */
2321156321Sdamienstatic void
2322156321Sdamienrt2560_disable_rf_tune(struct rt2560_softc *sc)
2323156321Sdamien{
2324156321Sdamien	uint32_t tmp;
2325156321Sdamien
2326156321Sdamien	if (sc->rf_rev != RT2560_RF_2523) {
2327156321Sdamien		tmp = sc->rf_regs[RAL_RF1] & ~RAL_RF1_AUTOTUNE;
2328156321Sdamien		rt2560_rf_write(sc, RAL_RF1, tmp);
2329156321Sdamien	}
2330156321Sdamien
2331156321Sdamien	tmp = sc->rf_regs[RAL_RF3] & ~RAL_RF3_AUTOTUNE;
2332156321Sdamien	rt2560_rf_write(sc, RAL_RF3, tmp);
2333156321Sdamien
2334156321Sdamien	DPRINTFN(2, ("disabling RF autotune\n"));
2335156321Sdamien}
2336156321Sdamien#endif
2337156321Sdamien
2338156321Sdamien/*
2339156321Sdamien * Refer to IEEE Std 802.11-1999 pp. 123 for more information on TSF
2340156321Sdamien * synchronization.
2341156321Sdamien */
2342156321Sdamienstatic void
2343156321Sdamienrt2560_enable_tsf_sync(struct rt2560_softc *sc)
2344156321Sdamien{
2345156321Sdamien	struct ieee80211com *ic = &sc->sc_ic;
2346156321Sdamien	uint16_t logcwmin, preload;
2347156321Sdamien	uint32_t tmp;
2348156321Sdamien
2349156321Sdamien	/* first, disable TSF synchronization */
2350156321Sdamien	RAL_WRITE(sc, RT2560_CSR14, 0);
2351156321Sdamien
2352156321Sdamien	tmp = 16 * ic->ic_bss->ni_intval;
2353156321Sdamien	RAL_WRITE(sc, RT2560_CSR12, tmp);
2354156321Sdamien
2355156321Sdamien	RAL_WRITE(sc, RT2560_CSR13, 0);
2356156321Sdamien
2357156321Sdamien	logcwmin = 5;
2358156321Sdamien	preload = (ic->ic_opmode == IEEE80211_M_STA) ? 384 : 1024;
2359156321Sdamien	tmp = logcwmin << 16 | preload;
2360156321Sdamien	RAL_WRITE(sc, RT2560_BCNOCSR, tmp);
2361156321Sdamien
2362156321Sdamien	/* finally, enable TSF synchronization */
2363156321Sdamien	tmp = RT2560_ENABLE_TSF | RT2560_ENABLE_TBCN;
2364156321Sdamien	if (ic->ic_opmode == IEEE80211_M_STA)
2365156321Sdamien		tmp |= RT2560_ENABLE_TSF_SYNC(1);
2366156321Sdamien	else
2367156321Sdamien		tmp |= RT2560_ENABLE_TSF_SYNC(2) |
2368156321Sdamien		       RT2560_ENABLE_BEACON_GENERATOR;
2369156321Sdamien	RAL_WRITE(sc, RT2560_CSR14, tmp);
2370156321Sdamien
2371156321Sdamien	DPRINTF(("enabling TSF synchronization\n"));
2372156321Sdamien}
2373156321Sdamien
2374156321Sdamienstatic void
2375156321Sdamienrt2560_update_plcp(struct rt2560_softc *sc)
2376156321Sdamien{
2377156321Sdamien	struct ieee80211com *ic = &sc->sc_ic;
2378156321Sdamien
2379156321Sdamien	/* no short preamble for 1Mbps */
2380156321Sdamien	RAL_WRITE(sc, RT2560_PLCP1MCSR, 0x00700400);
2381156321Sdamien
2382156321Sdamien	if (!(ic->ic_flags & IEEE80211_F_SHPREAMBLE)) {
2383156321Sdamien		/* values taken from the reference driver */
2384156321Sdamien		RAL_WRITE(sc, RT2560_PLCP2MCSR,   0x00380401);
2385156321Sdamien		RAL_WRITE(sc, RT2560_PLCP5p5MCSR, 0x00150402);
2386156321Sdamien		RAL_WRITE(sc, RT2560_PLCP11MCSR,  0x000b8403);
2387156321Sdamien	} else {
2388156321Sdamien		/* same values as above or'ed 0x8 */
2389156321Sdamien		RAL_WRITE(sc, RT2560_PLCP2MCSR,   0x00380409);
2390156321Sdamien		RAL_WRITE(sc, RT2560_PLCP5p5MCSR, 0x0015040a);
2391156321Sdamien		RAL_WRITE(sc, RT2560_PLCP11MCSR,  0x000b840b);
2392156321Sdamien	}
2393156321Sdamien
2394156321Sdamien	DPRINTF(("updating PLCP for %s preamble\n",
2395156321Sdamien	    (ic->ic_flags & IEEE80211_F_SHPREAMBLE) ? "short" : "long"));
2396156321Sdamien}
2397156321Sdamien
2398156321Sdamien/*
2399156321Sdamien * This function can be called by ieee80211_set_shortslottime(). Refer to
2400156321Sdamien * IEEE Std 802.11-1999 pp. 85 to know how these values are computed.
2401156321Sdamien */
2402156321Sdamienstatic void
2403156321Sdamienrt2560_update_slot(struct ifnet *ifp)
2404156321Sdamien{
2405156321Sdamien	struct rt2560_softc *sc = ifp->if_softc;
2406156321Sdamien	struct ieee80211com *ic = &sc->sc_ic;
2407156321Sdamien	uint8_t slottime;
2408156321Sdamien	uint16_t tx_sifs, tx_pifs, tx_difs, eifs;
2409156321Sdamien	uint32_t tmp;
2410156321Sdamien
2411156321Sdamien	slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20;
2412156321Sdamien
2413156321Sdamien	/* update the MAC slot boundaries */
2414156321Sdamien	tx_sifs = RAL_SIFS - RT2560_TXRX_TURNAROUND;
2415156321Sdamien	tx_pifs = tx_sifs + slottime;
2416156321Sdamien	tx_difs = tx_sifs + 2 * slottime;
2417156321Sdamien	eifs = (ic->ic_curmode == IEEE80211_MODE_11B) ? 364 : 60;
2418156321Sdamien
2419156321Sdamien	tmp = RAL_READ(sc, RT2560_CSR11);
2420156321Sdamien	tmp = (tmp & ~0x1f00) | slottime << 8;
2421156321Sdamien	RAL_WRITE(sc, RT2560_CSR11, tmp);
2422156321Sdamien
2423156321Sdamien	tmp = tx_pifs << 16 | tx_sifs;
2424156321Sdamien	RAL_WRITE(sc, RT2560_CSR18, tmp);
2425156321Sdamien
2426156321Sdamien	tmp = eifs << 16 | tx_difs;
2427156321Sdamien	RAL_WRITE(sc, RT2560_CSR19, tmp);
2428156321Sdamien
2429156321Sdamien	DPRINTF(("setting slottime to %uus\n", slottime));
2430156321Sdamien}
2431156321Sdamien
2432156321Sdamienstatic void
2433156321Sdamienrt2560_set_basicrates(struct rt2560_softc *sc)
2434156321Sdamien{
2435156321Sdamien	struct ieee80211com *ic = &sc->sc_ic;
2436156321Sdamien
2437156321Sdamien	/* update basic rate set */
2438156321Sdamien	if (ic->ic_curmode == IEEE80211_MODE_11B) {
2439156321Sdamien		/* 11b basic rates: 1, 2Mbps */
2440156321Sdamien		RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x3);
2441156321Sdamien	} else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) {
2442156321Sdamien		/* 11a basic rates: 6, 12, 24Mbps */
2443156321Sdamien		RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x150);
2444156321Sdamien	} else {
2445156321Sdamien		/* 11g basic rates: 1, 2, 5.5, 11, 6, 12, 24Mbps */
2446156321Sdamien		RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x15f);
2447156321Sdamien	}
2448156321Sdamien}
2449156321Sdamien
2450156321Sdamienstatic void
2451156321Sdamienrt2560_update_led(struct rt2560_softc *sc, int led1, int led2)
2452156321Sdamien{
2453156321Sdamien	uint32_t tmp;
2454156321Sdamien
2455156321Sdamien	/* set ON period to 70ms and OFF period to 30ms */
2456156321Sdamien	tmp = led1 << 16 | led2 << 17 | 70 << 8 | 30;
2457156321Sdamien	RAL_WRITE(sc, RT2560_LEDCSR, tmp);
2458156321Sdamien}
2459156321Sdamien
2460156321Sdamienstatic void
2461170530Ssamrt2560_set_bssid(struct rt2560_softc *sc, const uint8_t *bssid)
2462156321Sdamien{
2463156321Sdamien	uint32_t tmp;
2464156321Sdamien
2465156321Sdamien	tmp = bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24;
2466156321Sdamien	RAL_WRITE(sc, RT2560_CSR5, tmp);
2467156321Sdamien
2468156321Sdamien	tmp = bssid[4] | bssid[5] << 8;
2469156321Sdamien	RAL_WRITE(sc, RT2560_CSR6, tmp);
2470156321Sdamien
2471156321Sdamien	DPRINTF(("setting BSSID to %6D\n", bssid, ":"));
2472156321Sdamien}
2473156321Sdamien
2474156321Sdamienstatic void
2475156321Sdamienrt2560_set_macaddr(struct rt2560_softc *sc, uint8_t *addr)
2476156321Sdamien{
2477156321Sdamien	uint32_t tmp;
2478156321Sdamien
2479156321Sdamien	tmp = addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24;
2480156321Sdamien	RAL_WRITE(sc, RT2560_CSR3, tmp);
2481156321Sdamien
2482156321Sdamien	tmp = addr[4] | addr[5] << 8;
2483156321Sdamien	RAL_WRITE(sc, RT2560_CSR4, tmp);
2484156321Sdamien
2485156321Sdamien	DPRINTF(("setting MAC address to %6D\n", addr, ":"));
2486156321Sdamien}
2487156321Sdamien
2488156321Sdamienstatic void
2489156321Sdamienrt2560_get_macaddr(struct rt2560_softc *sc, uint8_t *addr)
2490156321Sdamien{
2491156321Sdamien	uint32_t tmp;
2492156321Sdamien
2493156321Sdamien	tmp = RAL_READ(sc, RT2560_CSR3);
2494156321Sdamien	addr[0] = tmp & 0xff;
2495156321Sdamien	addr[1] = (tmp >>  8) & 0xff;
2496156321Sdamien	addr[2] = (tmp >> 16) & 0xff;
2497156321Sdamien	addr[3] = (tmp >> 24);
2498156321Sdamien
2499156321Sdamien	tmp = RAL_READ(sc, RT2560_CSR4);
2500156321Sdamien	addr[4] = tmp & 0xff;
2501156321Sdamien	addr[5] = (tmp >> 8) & 0xff;
2502156321Sdamien}
2503156321Sdamien
2504156321Sdamienstatic void
2505156321Sdamienrt2560_update_promisc(struct rt2560_softc *sc)
2506156321Sdamien{
2507156321Sdamien	struct ifnet *ifp = sc->sc_ic.ic_ifp;
2508156321Sdamien	uint32_t tmp;
2509156321Sdamien
2510156321Sdamien	tmp = RAL_READ(sc, RT2560_RXCSR0);
2511156321Sdamien
2512156321Sdamien	tmp &= ~RT2560_DROP_NOT_TO_ME;
2513156321Sdamien	if (!(ifp->if_flags & IFF_PROMISC))
2514156321Sdamien		tmp |= RT2560_DROP_NOT_TO_ME;
2515156321Sdamien
2516156321Sdamien	RAL_WRITE(sc, RT2560_RXCSR0, tmp);
2517156321Sdamien
2518156321Sdamien	DPRINTF(("%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ?
2519156321Sdamien	    "entering" : "leaving"));
2520156321Sdamien}
2521156321Sdamien
2522156321Sdamienstatic const char *
2523156321Sdamienrt2560_get_rf(int rev)
2524156321Sdamien{
2525156321Sdamien	switch (rev) {
2526156321Sdamien	case RT2560_RF_2522:	return "RT2522";
2527156321Sdamien	case RT2560_RF_2523:	return "RT2523";
2528156321Sdamien	case RT2560_RF_2524:	return "RT2524";
2529156321Sdamien	case RT2560_RF_2525:	return "RT2525";
2530156321Sdamien	case RT2560_RF_2525E:	return "RT2525e";
2531156321Sdamien	case RT2560_RF_2526:	return "RT2526";
2532156321Sdamien	case RT2560_RF_5222:	return "RT5222";
2533156321Sdamien	default:		return "unknown";
2534156321Sdamien	}
2535156321Sdamien}
2536156321Sdamien
2537156321Sdamienstatic void
2538156321Sdamienrt2560_read_eeprom(struct rt2560_softc *sc)
2539156321Sdamien{
2540156321Sdamien	uint16_t val;
2541156321Sdamien	int i;
2542156321Sdamien
2543156321Sdamien	val = rt2560_eeprom_read(sc, RT2560_EEPROM_CONFIG0);
2544156321Sdamien	sc->rf_rev =   (val >> 11) & 0x7;
2545156321Sdamien	sc->hw_radio = (val >> 10) & 0x1;
2546156321Sdamien	sc->led_mode = (val >> 6)  & 0x7;
2547156321Sdamien	sc->rx_ant =   (val >> 4)  & 0x3;
2548156321Sdamien	sc->tx_ant =   (val >> 2)  & 0x3;
2549156321Sdamien	sc->nb_ant =   val & 0x3;
2550156321Sdamien
2551156321Sdamien	/* read default values for BBP registers */
2552156321Sdamien	for (i = 0; i < 16; i++) {
2553156321Sdamien		val = rt2560_eeprom_read(sc, RT2560_EEPROM_BBP_BASE + i);
2554156321Sdamien		sc->bbp_prom[i].reg = val >> 8;
2555156321Sdamien		sc->bbp_prom[i].val = val & 0xff;
2556156321Sdamien	}
2557156321Sdamien
2558156321Sdamien	/* read Tx power for all b/g channels */
2559156321Sdamien	for (i = 0; i < 14 / 2; i++) {
2560156321Sdamien		val = rt2560_eeprom_read(sc, RT2560_EEPROM_TXPOWER + i);
2561156321Sdamien		sc->txpow[i * 2] = val >> 8;
2562156321Sdamien		sc->txpow[i * 2 + 1] = val & 0xff;
2563156321Sdamien	}
2564170530Ssam
2565170530Ssam	val = rt2560_eeprom_read(sc, RT2560_EEPROM_CALIBRATE);
2566170530Ssam	if ((val & 0xff) == 0xff)
2567170530Ssam		sc->rssi_corr = RT2560_DEFAULT_RSSI_CORR;
2568170530Ssam	else
2569170530Ssam		sc->rssi_corr = val & 0xff;
2570170530Ssam	DPRINTF(("rssi correction %d, calibrate 0x%02x\n",
2571170530Ssam		 sc->rssi_corr, val));
2572156321Sdamien}
2573156321Sdamien
2574170530Ssam
2575170530Ssamstatic void
2576170530Ssamrt2560_scan_start(struct ieee80211com *ic)
2577170530Ssam{
2578170530Ssam	struct ifnet *ifp = ic->ic_ifp;
2579170530Ssam	struct rt2560_softc *sc = ifp->if_softc;
2580170530Ssam
2581170530Ssam	/* abort TSF synchronization */
2582170530Ssam	RAL_WRITE(sc, RT2560_CSR14, 0);
2583170530Ssam	rt2560_set_bssid(sc, ifp->if_broadcastaddr);
2584170530Ssam}
2585170530Ssam
2586170530Ssamstatic void
2587170530Ssamrt2560_scan_end(struct ieee80211com *ic)
2588170530Ssam{
2589170530Ssam	struct ifnet *ifp = ic->ic_ifp;
2590170530Ssam	struct rt2560_softc *sc = ifp->if_softc;
2591170530Ssam
2592170530Ssam	rt2560_enable_tsf_sync(sc);
2593170530Ssam	/* XXX keep local copy */
2594170530Ssam	rt2560_set_bssid(sc, ic->ic_bss->ni_bssid);
2595170530Ssam}
2596170530Ssam
2597156321Sdamienstatic int
2598156321Sdamienrt2560_bbp_init(struct rt2560_softc *sc)
2599156321Sdamien{
2600156321Sdamien#define N(a)	(sizeof (a) / sizeof ((a)[0]))
2601156321Sdamien	int i, ntries;
2602156321Sdamien
2603156321Sdamien	/* wait for BBP to be ready */
2604156321Sdamien	for (ntries = 0; ntries < 100; ntries++) {
2605156321Sdamien		if (rt2560_bbp_read(sc, RT2560_BBP_VERSION) != 0)
2606156321Sdamien			break;
2607156321Sdamien		DELAY(1);
2608156321Sdamien	}
2609156321Sdamien	if (ntries == 100) {
2610156321Sdamien		device_printf(sc->sc_dev, "timeout waiting for BBP\n");
2611156321Sdamien		return EIO;
2612156321Sdamien	}
2613156321Sdamien
2614156321Sdamien	/* initialize BBP registers to default values */
2615156321Sdamien	for (i = 0; i < N(rt2560_def_bbp); i++) {
2616156321Sdamien		rt2560_bbp_write(sc, rt2560_def_bbp[i].reg,
2617156321Sdamien		    rt2560_def_bbp[i].val);
2618156321Sdamien	}
2619156321Sdamien#if 0
2620156321Sdamien	/* initialize BBP registers to values stored in EEPROM */
2621156321Sdamien	for (i = 0; i < 16; i++) {
2622156321Sdamien		if (sc->bbp_prom[i].reg == 0xff)
2623156321Sdamien			continue;
2624156321Sdamien		rt2560_bbp_write(sc, sc->bbp_prom[i].reg, sc->bbp_prom[i].val);
2625156321Sdamien	}
2626156321Sdamien#endif
2627156321Sdamien
2628156321Sdamien	return 0;
2629156321Sdamien#undef N
2630156321Sdamien}
2631156321Sdamien
2632156321Sdamienstatic void
2633156321Sdamienrt2560_set_txantenna(struct rt2560_softc *sc, int antenna)
2634156321Sdamien{
2635156321Sdamien	uint32_t tmp;
2636156321Sdamien	uint8_t tx;
2637156321Sdamien
2638156321Sdamien	tx = rt2560_bbp_read(sc, RT2560_BBP_TX) & ~RT2560_BBP_ANTMASK;
2639156321Sdamien	if (antenna == 1)
2640156321Sdamien		tx |= RT2560_BBP_ANTA;
2641156321Sdamien	else if (antenna == 2)
2642156321Sdamien		tx |= RT2560_BBP_ANTB;
2643156321Sdamien	else
2644156321Sdamien		tx |= RT2560_BBP_DIVERSITY;
2645156321Sdamien
2646156321Sdamien	/* need to force I/Q flip for RF 2525e, 2526 and 5222 */
2647156321Sdamien	if (sc->rf_rev == RT2560_RF_2525E || sc->rf_rev == RT2560_RF_2526 ||
2648156321Sdamien	    sc->rf_rev == RT2560_RF_5222)
2649156321Sdamien		tx |= RT2560_BBP_FLIPIQ;
2650156321Sdamien
2651156321Sdamien	rt2560_bbp_write(sc, RT2560_BBP_TX, tx);
2652156321Sdamien
2653156321Sdamien	/* update values for CCK and OFDM in BBPCSR1 */
2654156321Sdamien	tmp = RAL_READ(sc, RT2560_BBPCSR1) & ~0x00070007;
2655156321Sdamien	tmp |= (tx & 0x7) << 16 | (tx & 0x7);
2656156321Sdamien	RAL_WRITE(sc, RT2560_BBPCSR1, tmp);
2657156321Sdamien}
2658156321Sdamien
2659156321Sdamienstatic void
2660156321Sdamienrt2560_set_rxantenna(struct rt2560_softc *sc, int antenna)
2661156321Sdamien{
2662156321Sdamien	uint8_t rx;
2663156321Sdamien
2664156321Sdamien	rx = rt2560_bbp_read(sc, RT2560_BBP_RX) & ~RT2560_BBP_ANTMASK;
2665156321Sdamien	if (antenna == 1)
2666156321Sdamien		rx |= RT2560_BBP_ANTA;
2667156321Sdamien	else if (antenna == 2)
2668156321Sdamien		rx |= RT2560_BBP_ANTB;
2669156321Sdamien	else
2670156321Sdamien		rx |= RT2560_BBP_DIVERSITY;
2671156321Sdamien
2672156321Sdamien	/* need to force no I/Q flip for RF 2525e and 2526 */
2673156321Sdamien	if (sc->rf_rev == RT2560_RF_2525E || sc->rf_rev == RT2560_RF_2526)
2674156321Sdamien		rx &= ~RT2560_BBP_FLIPIQ;
2675156321Sdamien
2676156321Sdamien	rt2560_bbp_write(sc, RT2560_BBP_RX, rx);
2677156321Sdamien}
2678156321Sdamien
2679156321Sdamienstatic void
2680156321Sdamienrt2560_init(void *priv)
2681156321Sdamien{
2682156321Sdamien#define N(a)	(sizeof (a) / sizeof ((a)[0]))
2683156321Sdamien	struct rt2560_softc *sc = priv;
2684156321Sdamien	struct ieee80211com *ic = &sc->sc_ic;
2685156321Sdamien	struct ifnet *ifp = ic->ic_ifp;
2686156321Sdamien	uint32_t tmp;
2687156321Sdamien	int i;
2688156321Sdamien
2689156975Sdamien
2690170530Ssam
2691156321Sdamien	rt2560_stop(sc);
2692156321Sdamien
2693170530Ssam	RAL_LOCK(sc);
2694156321Sdamien	/* setup tx rings */
2695156321Sdamien	tmp = RT2560_PRIO_RING_COUNT << 24 |
2696156321Sdamien	      RT2560_ATIM_RING_COUNT << 16 |
2697156321Sdamien	      RT2560_TX_RING_COUNT   <<  8 |
2698156321Sdamien	      RT2560_TX_DESC_SIZE;
2699156321Sdamien
2700156321Sdamien	/* rings must be initialized in this exact order */
2701156321Sdamien	RAL_WRITE(sc, RT2560_TXCSR2, tmp);
2702156321Sdamien	RAL_WRITE(sc, RT2560_TXCSR3, sc->txq.physaddr);
2703156321Sdamien	RAL_WRITE(sc, RT2560_TXCSR5, sc->prioq.physaddr);
2704156321Sdamien	RAL_WRITE(sc, RT2560_TXCSR4, sc->atimq.physaddr);
2705156321Sdamien	RAL_WRITE(sc, RT2560_TXCSR6, sc->bcnq.physaddr);
2706156321Sdamien
2707156321Sdamien	/* setup rx ring */
2708156321Sdamien	tmp = RT2560_RX_RING_COUNT << 8 | RT2560_RX_DESC_SIZE;
2709156321Sdamien
2710156321Sdamien	RAL_WRITE(sc, RT2560_RXCSR1, tmp);
2711156321Sdamien	RAL_WRITE(sc, RT2560_RXCSR2, sc->rxq.physaddr);
2712156321Sdamien
2713156321Sdamien	/* initialize MAC registers to default values */
2714156321Sdamien	for (i = 0; i < N(rt2560_def_mac); i++)
2715156321Sdamien		RAL_WRITE(sc, rt2560_def_mac[i].reg, rt2560_def_mac[i].val);
2716156321Sdamien
2717156321Sdamien	IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp));
2718156321Sdamien	rt2560_set_macaddr(sc, ic->ic_myaddr);
2719156321Sdamien
2720156321Sdamien	/* set basic rate set (will be updated later) */
2721156321Sdamien	RAL_WRITE(sc, RT2560_ARSP_PLCP_1, 0x153);
2722156321Sdamien
2723156321Sdamien	rt2560_set_txantenna(sc, sc->tx_ant);
2724156321Sdamien	rt2560_set_rxantenna(sc, sc->rx_ant);
2725156321Sdamien	rt2560_update_slot(ifp);
2726156321Sdamien	rt2560_update_plcp(sc);
2727156321Sdamien	rt2560_update_led(sc, 0, 0);
2728156321Sdamien
2729156321Sdamien	RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC);
2730156321Sdamien	RAL_WRITE(sc, RT2560_CSR1, RT2560_HOST_READY);
2731156321Sdamien
2732156321Sdamien	if (rt2560_bbp_init(sc) != 0) {
2733156321Sdamien		rt2560_stop(sc);
2734156975Sdamien		RAL_UNLOCK(sc);
2735156321Sdamien		return;
2736156321Sdamien	}
2737156321Sdamien
2738156321Sdamien	/* set default BSS channel */
2739156321Sdamien	rt2560_set_chan(sc, ic->ic_curchan);
2740156321Sdamien
2741156321Sdamien	/* kick Rx */
2742156321Sdamien	tmp = RT2560_DROP_PHY_ERROR | RT2560_DROP_CRC_ERROR;
2743156321Sdamien	if (ic->ic_opmode != IEEE80211_M_MONITOR) {
2744156321Sdamien		tmp |= RT2560_DROP_CTL | RT2560_DROP_VERSION_ERROR;
2745156321Sdamien		if (ic->ic_opmode != IEEE80211_M_HOSTAP)
2746156321Sdamien			tmp |= RT2560_DROP_TODS;
2747156321Sdamien		if (!(ifp->if_flags & IFF_PROMISC))
2748156321Sdamien			tmp |= RT2560_DROP_NOT_TO_ME;
2749156321Sdamien	}
2750156321Sdamien	RAL_WRITE(sc, RT2560_RXCSR0, tmp);
2751156321Sdamien
2752156321Sdamien	/* clear old FCS and Rx FIFO errors */
2753156321Sdamien	RAL_READ(sc, RT2560_CNT0);
2754156321Sdamien	RAL_READ(sc, RT2560_CNT4);
2755156321Sdamien
2756156321Sdamien	/* clear any pending interrupts */
2757156321Sdamien	RAL_WRITE(sc, RT2560_CSR7, 0xffffffff);
2758156321Sdamien
2759156321Sdamien	/* enable interrupts */
2760156321Sdamien	RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK);
2761156321Sdamien
2762156321Sdamien	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
2763156321Sdamien	ifp->if_drv_flags |= IFF_DRV_RUNNING;
2764156321Sdamien
2765156321Sdamien	if (ic->ic_opmode != IEEE80211_M_MONITOR) {
2766156321Sdamien		if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL)
2767156321Sdamien			ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2768156321Sdamien	} else
2769156321Sdamien		ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
2770156975Sdamien
2771156975Sdamien	RAL_UNLOCK(sc);
2772156321Sdamien#undef N
2773156321Sdamien}
2774156321Sdamien
2775156321Sdamienvoid
2776170530Ssamrt2560_stop(void *arg)
2777156321Sdamien{
2778170530Ssam	struct rt2560_softc *sc = arg;
2779156321Sdamien	struct ieee80211com *ic = &sc->sc_ic;
2780156321Sdamien	struct ifnet *ifp = ic->ic_ifp;
2781170530Ssam	volatile int *flags = &sc->sc_flags;
2782156321Sdamien
2783170530Ssam	while (*flags & RAL_INPUT_RUNNING) {
2784170530Ssam		tsleep(sc, 0, "ralrunning", hz/10);
2785170530Ssam	}
2786156321Sdamien
2787170530Ssam	RAL_LOCK(sc);
2788170530Ssam	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2789170530Ssam		ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
2790170530Ssam		sc->sc_tx_timer = 0;
2791170530Ssam		ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
2792156975Sdamien
2793170530Ssam		/* abort Tx */
2794170530Ssam		RAL_WRITE(sc, RT2560_TXCSR0, RT2560_ABORT_TX);
2795170530Ssam
2796170530Ssam		/* disable Rx */
2797170530Ssam		RAL_WRITE(sc, RT2560_RXCSR0, RT2560_DISABLE_RX);
2798156321Sdamien
2799170530Ssam		/* reset ASIC (imply reset BBP) */
2800170530Ssam		RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC);
2801170530Ssam		RAL_WRITE(sc, RT2560_CSR1, 0);
2802156321Sdamien
2803170530Ssam		/* disable interrupts */
2804170530Ssam		RAL_WRITE(sc, RT2560_CSR8, 0xffffffff);
2805170530Ssam
2806170530Ssam		/* reset Tx and Rx rings */
2807170530Ssam		rt2560_reset_tx_ring(sc, &sc->txq);
2808170530Ssam		rt2560_reset_tx_ring(sc, &sc->atimq);
2809170530Ssam		rt2560_reset_tx_ring(sc, &sc->prioq);
2810170530Ssam		rt2560_reset_tx_ring(sc, &sc->bcnq);
2811170530Ssam		rt2560_reset_rx_ring(sc, &sc->rxq);
2812170530Ssam	}
2813170530Ssam	RAL_UNLOCK(sc);
2814156321Sdamien}
2815160691Ssam
2816160691Ssamstatic int
2817160691Ssamrt2560_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
2818160691Ssam	const struct ieee80211_bpf_params *params)
2819160691Ssam{
2820160691Ssam	struct ieee80211com *ic = ni->ni_ic;
2821160691Ssam	struct ifnet *ifp = ic->ic_ifp;
2822160691Ssam	struct rt2560_softc *sc = ifp->if_softc;
2823160691Ssam
2824160691Ssam	RAL_LOCK(sc);
2825160691Ssam
2826160691Ssam	/* prevent management frames from being sent if we're not ready */
2827160691Ssam	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
2828160691Ssam		RAL_UNLOCK(sc);
2829168860Ssephe		m_freem(m);
2830168860Ssephe		ieee80211_free_node(ni);
2831160691Ssam		return ENETDOWN;
2832160691Ssam	}
2833160691Ssam	if (sc->prioq.queued >= RT2560_PRIO_RING_COUNT) {
2834160691Ssam		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
2835160691Ssam		RAL_UNLOCK(sc);
2836168860Ssephe		m_freem(m);
2837168860Ssephe		ieee80211_free_node(ni);
2838160691Ssam		return ENOBUFS;		/* XXX */
2839160691Ssam	}
2840160691Ssam
2841160691Ssam	if (bpf_peers_present(ic->ic_rawbpf))
2842160691Ssam		bpf_mtap(ic->ic_rawbpf, m);
2843160691Ssam
2844160691Ssam	ifp->if_opackets++;
2845160691Ssam
2846160691Ssam	if (params == NULL) {
2847160691Ssam		/*
2848160691Ssam		 * Legacy path; interpret frame contents to decide
2849160691Ssam		 * precisely how to send the frame.
2850160691Ssam		 */
2851160691Ssam		if (rt2560_tx_mgt(sc, m, ni) != 0)
2852160691Ssam			goto bad;
2853160691Ssam	} else {
2854160691Ssam		/*
2855160691Ssam		 * Caller supplied explicit parameters to use in
2856160691Ssam		 * sending the frame.
2857160691Ssam		 */
2858160691Ssam		if (rt2560_tx_raw(sc, m, ni, params))
2859160691Ssam			goto bad;
2860160691Ssam	}
2861160691Ssam	sc->sc_tx_timer = 5;
2862165352Sbms	callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc);
2863160691Ssam
2864160691Ssam	RAL_UNLOCK(sc);
2865160691Ssam
2866160691Ssam	return 0;
2867160691Ssambad:
2868160691Ssam	ifp->if_oerrors++;
2869160905Ssam	ieee80211_free_node(ni);
2870160691Ssam	RAL_UNLOCK(sc);
2871160691Ssam	return EIO;		/* XXX */
2872160691Ssam}
2873170530Ssam
2874