if_run.c revision 245047
1178676Ssam/*-
2198429Srpaulo * Copyright (c) 2008,2010 Damien Bergamini <damien.bergamini@free.fr>
3178676Ssam * ported to FreeBSD by Akinori Furukoshi <moonlightakkiy@yahoo.ca>
4178676Ssam * USB Consulting, Hans Petter Selasky <hselasky@freebsd.org>
5178676Ssam *
6178676Ssam * Permission to use, copy, modify, and distribute this software for any
7178676Ssam * purpose with or without fee is hereby granted, provided that the above
8178676Ssam * copyright notice and this permission notice appear in all copies.
9178676Ssam *
10178676Ssam * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11178676Ssam * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12178676Ssam * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13178676Ssam * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14178676Ssam * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15178676Ssam * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16178676Ssam * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17178676Ssam */
18178676Ssam
19178676Ssam#include <sys/cdefs.h>
20178676Ssam__FBSDID("$FreeBSD: head/sys/dev/usb/wlan/if_run.c 245047 2013-01-04 20:44:17Z hselasky $");
21178676Ssam
22201209Srpaulo/*-
23201209Srpaulo * Ralink Technology RT2700U/RT2800U/RT3000U chipset driver.
24178676Ssam * http://www.ralinktech.com/
25178676Ssam */
26178676Ssam
27178676Ssam#include <sys/param.h>
28178676Ssam#include <sys/sockio.h>
29178676Ssam#include <sys/sysctl.h>
30178676Ssam#include <sys/lock.h>
31178676Ssam#include <sys/mutex.h>
32178676Ssam#include <sys/mbuf.h>
33178676Ssam#include <sys/kernel.h>
34178676Ssam#include <sys/socket.h>
35178676Ssam#include <sys/systm.h>
36178676Ssam#include <sys/malloc.h>
37178676Ssam#include <sys/module.h>
38178676Ssam#include <sys/bus.h>
39178676Ssam#include <sys/endian.h>
40178676Ssam#include <sys/linker.h>
41178676Ssam#include <sys/firmware.h>
42178676Ssam#include <sys/kdb.h>
43178676Ssam
44178676Ssam#include <machine/bus.h>
45178676Ssam#include <machine/resource.h>
46178676Ssam#include <sys/rman.h>
47178676Ssam
48178676Ssam#include <net/bpf.h>
49178676Ssam#include <net/if.h>
50178676Ssam#include <net/if_arp.h>
51178676Ssam#include <net/ethernet.h>
52178676Ssam#include <net/if_dl.h>
53178676Ssam#include <net/if_media.h>
54178676Ssam#include <net/if_types.h>
55178676Ssam
56178676Ssam#include <netinet/in.h>
57178676Ssam#include <netinet/in_systm.h>
58178676Ssam#include <netinet/in_var.h>
59178676Ssam#include <netinet/if_ether.h>
60178676Ssam#include <netinet/ip.h>
61178676Ssam
62178676Ssam#include <net80211/ieee80211_var.h>
63178676Ssam#include <net80211/ieee80211_regdomain.h>
64178676Ssam#include <net80211/ieee80211_radiotap.h>
65178676Ssam#include <net80211/ieee80211_ratectl.h>
66178676Ssam
67178676Ssam#include <dev/usb/usb.h>
68178676Ssam#include <dev/usb/usbdi.h>
69178676Ssam#include "usbdevs.h"
70206358Srpaulo
71178676Ssam#define USB_DEBUG_VAR run_debug
72178676Ssam#include <dev/usb/usb_debug.h>
73178676Ssam
74178676Ssam#include <dev/usb/wlan/if_runreg.h>
75220723Sbschmidt#include <dev/usb/wlan/if_runvar.h>
76220723Sbschmidt
77220723Sbschmidt#define	N(_a) ((int)(sizeof((_a)) / sizeof((_a)[0])))
78220723Sbschmidt
79220723Sbschmidt#ifdef	USB_DEBUG
80220723Sbschmidt#define RUN_DEBUG
81220895Sbschmidt#endif
82220895Sbschmidt
83220895Sbschmidt#ifdef	RUN_DEBUG
84220895Sbschmidtint run_debug = 0;
85220895Sbschmidtstatic SYSCTL_NODE(_hw_usb, OID_AUTO, run, CTLFLAG_RW, 0, "USB run");
86220895SbschmidtSYSCTL_INT(_hw_usb_run, OID_AUTO, debug, CTLFLAG_RW, &run_debug, 0,
87220895Sbschmidt    "run debug level");
88220895Sbschmidt#endif
89220895Sbschmidt
90220895Sbschmidt#define IEEE80211_HAS_ADDR4(wh) \
91220895Sbschmidt	(((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
92220895Sbschmidt
93220895Sbschmidt/*
94220895Sbschmidt * Because of LOR in run_key_delete(), use atomic instead.
95221634Sbschmidt * '& RUN_CMDQ_MASQ' is to loop cmdq[].
96220895Sbschmidt */
97220895Sbschmidt#define RUN_CMDQ_GET(c)	(atomic_fetchadd_32((c), 1) & RUN_CMDQ_MASQ)
98221634Sbschmidt
99220895Sbschmidtstatic const STRUCT_USB_HOST_ID run_devs[] = {
100220895Sbschmidt#define RUN_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) }
101220895Sbschmidt    RUN_DEV(ABOCOM,		RT2770),
102220895Sbschmidt    RUN_DEV(ABOCOM,		RT2870),
103220895Sbschmidt    RUN_DEV(ABOCOM,		RT3070),
104220895Sbschmidt    RUN_DEV(ABOCOM,		RT3071),
105220895Sbschmidt    RUN_DEV(ABOCOM,		RT3072),
106220895Sbschmidt    RUN_DEV(ABOCOM2,		RT2870_1),
107220895Sbschmidt    RUN_DEV(ACCTON,		RT2770),
108220723Sbschmidt    RUN_DEV(ACCTON,		RT2870_1),
109220723Sbschmidt    RUN_DEV(ACCTON,		RT2870_2),
110220723Sbschmidt    RUN_DEV(ACCTON,		RT2870_3),
111178676Ssam    RUN_DEV(ACCTON,		RT2870_4),
112178676Ssam    RUN_DEV(ACCTON,		RT2870_5),
113220728Sbschmidt    RUN_DEV(ACCTON,		RT3070),
114220728Sbschmidt    RUN_DEV(ACCTON,		RT3070_1),
115206477Sbschmidt    RUN_DEV(ACCTON,		RT3070_2),
116220723Sbschmidt    RUN_DEV(ACCTON,		RT3070_3),
117178676Ssam    RUN_DEV(ACCTON,		RT3070_4),
118178676Ssam    RUN_DEV(ACCTON,		RT3070_5),
119178676Ssam    RUN_DEV(AIRTIES,		RT3070),
120178676Ssam    RUN_DEV(ALLWIN,		RT2070),
121178676Ssam    RUN_DEV(ALLWIN,		RT2770),
122206474Sbschmidt    RUN_DEV(ALLWIN,		RT2870),
123220723Sbschmidt    RUN_DEV(ALLWIN,		RT3070),
124220723Sbschmidt    RUN_DEV(ALLWIN,		RT3071),
125220723Sbschmidt    RUN_DEV(ALLWIN,		RT3072),
126206477Sbschmidt    RUN_DEV(ALLWIN,		RT3572),
127206477Sbschmidt    RUN_DEV(AMIGO,		RT2870_1),
128206477Sbschmidt    RUN_DEV(AMIGO,		RT2870_2),
129206477Sbschmidt    RUN_DEV(AMIT,		CGWLUSB2GNR),
130206474Sbschmidt    RUN_DEV(AMIT,		RT2870_1),
131178676Ssam    RUN_DEV(AMIT2,		RT2870),
132220691Sbschmidt    RUN_DEV(ASUS,		RT2870_1),
133178676Ssam    RUN_DEV(ASUS,		RT2870_2),
134206477Sbschmidt    RUN_DEV(ASUS,		RT2870_3),
135206477Sbschmidt    RUN_DEV(ASUS,		RT2870_4),
136206477Sbschmidt    RUN_DEV(ASUS,		RT2870_5),
137206477Sbschmidt    RUN_DEV(ASUS,		USBN13),
138206477Sbschmidt    RUN_DEV(ASUS,		RT3070_1),
139206477Sbschmidt    RUN_DEV(ASUS,		USB_N53),
140206477Sbschmidt    RUN_DEV(ASUS2,		USBN11),
141206477Sbschmidt    RUN_DEV(AZUREWAVE,		RT2870_1),
142206477Sbschmidt    RUN_DEV(AZUREWAVE,		RT2870_2),
143206477Sbschmidt    RUN_DEV(AZUREWAVE,		RT3070_1),
144206477Sbschmidt    RUN_DEV(AZUREWAVE,		RT3070_2),
145206477Sbschmidt    RUN_DEV(AZUREWAVE,		RT3070_3),
146178676Ssam    RUN_DEV(BELKIN,		F5D8053V3),
147206477Sbschmidt    RUN_DEV(BELKIN,		F5D8055),
148206477Sbschmidt    RUN_DEV(BELKIN,		F5D8055V2),
149206477Sbschmidt    RUN_DEV(BELKIN,		F6D4050V1),
150206477Sbschmidt    RUN_DEV(BELKIN,		RT2870_1),
151198429Srpaulo    RUN_DEV(BELKIN,		RT2870_2),
152206477Sbschmidt    RUN_DEV(CISCOLINKSYS,	AE1000),
153206477Sbschmidt    RUN_DEV(CISCOLINKSYS2,	RT3070),
154206477Sbschmidt    RUN_DEV(CISCOLINKSYS3,	RT3070),
155206474Sbschmidt    RUN_DEV(CONCEPTRONIC2,	RT2870_1),
156206474Sbschmidt    RUN_DEV(CONCEPTRONIC2,	RT2870_2),
157206474Sbschmidt    RUN_DEV(CONCEPTRONIC2,	RT2870_3),
158220726Sbschmidt    RUN_DEV(CONCEPTRONIC2,	RT2870_4),
159220723Sbschmidt    RUN_DEV(CONCEPTRONIC2,	RT2870_5),
160220723Sbschmidt    RUN_DEV(CONCEPTRONIC2,	RT2870_6),
161220723Sbschmidt    RUN_DEV(CONCEPTRONIC2,	RT2870_7),
162220723Sbschmidt    RUN_DEV(CONCEPTRONIC2,	RT2870_8),
163220726Sbschmidt    RUN_DEV(CONCEPTRONIC2,	RT3070_1),
164206477Sbschmidt    RUN_DEV(CONCEPTRONIC2,	RT3070_2),
165206477Sbschmidt    RUN_DEV(CONCEPTRONIC2,	VIGORN61),
166198429Srpaulo    RUN_DEV(COREGA,		CGWLUSB300GNM),
167220715Sbschmidt    RUN_DEV(COREGA,		RT2870_1),
168206477Sbschmidt    RUN_DEV(COREGA,		RT2870_2),
169206477Sbschmidt    RUN_DEV(COREGA,		RT2870_3),
170220667Sbschmidt    RUN_DEV(COREGA,		RT3070),
171206477Sbschmidt    RUN_DEV(CYBERTAN,		RT2870),
172198429Srpaulo    RUN_DEV(DLINK,		RT2870),
173206477Sbschmidt    RUN_DEV(DLINK,		RT3072),
174178676Ssam    RUN_DEV(DLINK2,		DWA130),
175206477Sbschmidt    RUN_DEV(DLINK2,		RT2870_1),
176201209Srpaulo    RUN_DEV(DLINK2,		RT2870_2),
177220674Sbschmidt    RUN_DEV(DLINK2,		RT3070_1),
178220674Sbschmidt    RUN_DEV(DLINK2,		RT3070_2),
179206477Sbschmidt    RUN_DEV(DLINK2,		RT3070_3),
180198429Srpaulo    RUN_DEV(DLINK2,		RT3070_4),
181206477Sbschmidt    RUN_DEV(DLINK2,		RT3070_5),
182198429Srpaulo    RUN_DEV(DLINK2,		RT3072),
183206477Sbschmidt    RUN_DEV(DLINK2,		RT3072_1),
184198429Srpaulo    RUN_DEV(EDIMAX,		EW7717),
185206477Sbschmidt    RUN_DEV(EDIMAX,		EW7718),
186198429Srpaulo    RUN_DEV(EDIMAX,		RT2870_1),
187221651Sbschmidt    RUN_DEV(ENCORE,		RT3070_1),
188206477Sbschmidt    RUN_DEV(ENCORE,		RT3070_2),
189206477Sbschmidt    RUN_DEV(ENCORE,		RT3070_3),
190206477Sbschmidt    RUN_DEV(GIGABYTE,		GNWB31N),
191206477Sbschmidt    RUN_DEV(GIGABYTE,		GNWB32L),
192206477Sbschmidt    RUN_DEV(GIGABYTE,		RT2870_1),
193206477Sbschmidt    RUN_DEV(GIGASET,		RT3070_1),
194206477Sbschmidt    RUN_DEV(GIGASET,		RT3070_2),
195198429Srpaulo    RUN_DEV(GUILLEMOT,		HWNU300),
196206477Sbschmidt    RUN_DEV(HAWKING,		HWUN2),
197198429Srpaulo    RUN_DEV(HAWKING,		RT2870_1),
198206475Sbschmidt    RUN_DEV(HAWKING,		RT2870_2),
199206477Sbschmidt    RUN_DEV(HAWKING,		RT3070),
200206475Sbschmidt    RUN_DEV(IODATA,		RT3072_1),
201206477Sbschmidt    RUN_DEV(IODATA,		RT3072_2),
202220720Sbschmidt    RUN_DEV(IODATA,		RT3072_3),
203220720Sbschmidt    RUN_DEV(IODATA,		RT3072_4),
204220720Sbschmidt    RUN_DEV(LINKSYS4,		RT3070),
205220720Sbschmidt    RUN_DEV(LINKSYS4,		WUSB100),
206198429Srpaulo    RUN_DEV(LINKSYS4,		WUSB54GCV3),
207198429Srpaulo    RUN_DEV(LINKSYS4,		WUSB600N),
208206477Sbschmidt    RUN_DEV(LINKSYS4,		WUSB600NV2),
209206477Sbschmidt    RUN_DEV(LOGITEC,		RT2870_1),
210220667Sbschmidt    RUN_DEV(LOGITEC,		RT2870_2),
211206477Sbschmidt    RUN_DEV(LOGITEC,		RT2870_3),
212206477Sbschmidt    RUN_DEV(LOGITEC,		LANW300NU2),
213206477Sbschmidt    RUN_DEV(LOGITEC,		LANW150NU2),
214198429Srpaulo    RUN_DEV(MELCO,		RT2870_1),
215206477Sbschmidt    RUN_DEV(MELCO,		RT2870_2),
216198429Srpaulo    RUN_DEV(MELCO,		WLIUCAG300N),
217220715Sbschmidt    RUN_DEV(MELCO,		WLIUCG300N),
218220715Sbschmidt    RUN_DEV(MELCO,		WLIUCG301N),
219206477Sbschmidt    RUN_DEV(MELCO,		WLIUCGN),
220220721Sbschmidt    RUN_DEV(MELCO,		WLIUCGNM),
221201209Srpaulo    RUN_DEV(MELCO,		WLIUCGNM2),
222206477Sbschmidt    RUN_DEV(MOTOROLA4,		RT2770),
223206477Sbschmidt    RUN_DEV(MOTOROLA4,		RT3070),
224206477Sbschmidt    RUN_DEV(MSI,		RT3070_1),
225206477Sbschmidt    RUN_DEV(MSI,		RT3070_2),
226206477Sbschmidt    RUN_DEV(MSI,		RT3070_3),
227201882Skeramida    RUN_DEV(MSI,		RT3070_4),
228206477Sbschmidt    RUN_DEV(MSI,		RT3070_5),
229201882Skeramida    RUN_DEV(MSI,		RT3070_6),
230206477Sbschmidt    RUN_DEV(MSI,		RT3070_7),
231206477Sbschmidt    RUN_DEV(MSI,		RT3070_8),
232206477Sbschmidt    RUN_DEV(MSI,		RT3070_9),
233206477Sbschmidt    RUN_DEV(MSI,		RT3070_10),
234206477Sbschmidt    RUN_DEV(MSI,		RT3070_11),
235206477Sbschmidt    RUN_DEV(OVISLINK,		RT3072),
236206477Sbschmidt    RUN_DEV(PARA,		RT3070),
237178676Ssam    RUN_DEV(PEGATRON,		RT2870),
238206477Sbschmidt    RUN_DEV(PEGATRON,		RT3070),
239206477Sbschmidt    RUN_DEV(PEGATRON,		RT3070_2),
240206477Sbschmidt    RUN_DEV(PEGATRON,		RT3070_3),
241206477Sbschmidt    RUN_DEV(PHILIPS,		RT2870),
242206477Sbschmidt    RUN_DEV(PLANEX2,		GWUS300MINIS),
243178676Ssam    RUN_DEV(PLANEX2,		GWUSMICRON),
244206477Sbschmidt    RUN_DEV(PLANEX2,		RT2870),
245206477Sbschmidt    RUN_DEV(PLANEX2,		RT3070),
246220662Sbschmidt    RUN_DEV(QCOM,		RT2870),
247220891Sbschmidt    RUN_DEV(QUANTA,		RT3070),
248206477Sbschmidt    RUN_DEV(RALINK,		RT2070),
249220634Sbschmidt    RUN_DEV(RALINK,		RT2770),
250206477Sbschmidt    RUN_DEV(RALINK,		RT2870),
251206477Sbschmidt    RUN_DEV(RALINK,		RT3070),
252206477Sbschmidt    RUN_DEV(RALINK,		RT3071),
253221650Sbschmidt    RUN_DEV(RALINK,		RT3072),
254221650Sbschmidt    RUN_DEV(RALINK,		RT3370),
255221650Sbschmidt    RUN_DEV(RALINK,		RT3572),
256221650Sbschmidt    RUN_DEV(RALINK,		RT8070),
257221651Sbschmidt    RUN_DEV(SAMSUNG,		WIS09ABGN),
258221651Sbschmidt    RUN_DEV(SAMSUNG2,		RT2870_1),
259221651Sbschmidt    RUN_DEV(SENAO,		RT2870_1),
260221651Sbschmidt    RUN_DEV(SENAO,		RT2870_2),
261206474Sbschmidt    RUN_DEV(SENAO,		RT2870_3),
262206474Sbschmidt    RUN_DEV(SENAO,		RT2870_4),
263221651Sbschmidt    RUN_DEV(SENAO,		RT3070),
264221651Sbschmidt    RUN_DEV(SENAO,		RT3071),
265206474Sbschmidt    RUN_DEV(SENAO,		RT3072_1),
266221651Sbschmidt    RUN_DEV(SENAO,		RT3072_2),
267221651Sbschmidt    RUN_DEV(SENAO,		RT3072_3),
268220726Sbschmidt    RUN_DEV(SENAO,		RT3072_4),
269206474Sbschmidt    RUN_DEV(SENAO,		RT3072_5),
270221651Sbschmidt    RUN_DEV(SITECOMEU,		RT2770),
271221651Sbschmidt    RUN_DEV(SITECOMEU,		RT2870_1),
272220726Sbschmidt    RUN_DEV(SITECOMEU,		RT2870_2),
273220674Sbschmidt    RUN_DEV(SITECOMEU,		RT2870_3),
274220674Sbschmidt    RUN_DEV(SITECOMEU,		RT2870_4),
275206477Sbschmidt    RUN_DEV(SITECOMEU,		RT3070),
276220677Sbschmidt    RUN_DEV(SITECOMEU,		RT3070_2),
277220676Sbschmidt    RUN_DEV(SITECOMEU,		RT3070_3),
278206477Sbschmidt    RUN_DEV(SITECOMEU,		RT3070_4),
279206477Sbschmidt    RUN_DEV(SITECOMEU,		RT3071),
280206477Sbschmidt    RUN_DEV(SITECOMEU,		RT3072_1),
281198429Srpaulo    RUN_DEV(SITECOMEU,		RT3072_2),
282206477Sbschmidt    RUN_DEV(SITECOMEU,		RT3072_3),
283206477Sbschmidt    RUN_DEV(SITECOMEU,		RT3072_4),
284198429Srpaulo    RUN_DEV(SITECOMEU,		RT3072_5),
285206477Sbschmidt    RUN_DEV(SITECOMEU,		RT3072_6),
286210111Sbschmidt    RUN_DEV(SITECOMEU,		WL608),
287210111Sbschmidt    RUN_DEV(SPARKLAN,		RT2870_1),
288210111Sbschmidt    RUN_DEV(SPARKLAN,		RT3070),
289210111Sbschmidt    RUN_DEV(SWEEX2,		LW153),
290206477Sbschmidt    RUN_DEV(SWEEX2,		LW303),
291206477Sbschmidt    RUN_DEV(SWEEX2,		LW313),
292206477Sbschmidt    RUN_DEV(TOSHIBA,		RT3070),
293206477Sbschmidt    RUN_DEV(UMEDIA,		RT2870_1),
294206477Sbschmidt    RUN_DEV(ZCOM,		RT2870_1),
295206477Sbschmidt    RUN_DEV(ZCOM,		RT2870_2),
296206477Sbschmidt    RUN_DEV(ZINWELL,		RT2870_1),
297206477Sbschmidt    RUN_DEV(ZINWELL,		RT2870_2),
298206477Sbschmidt    RUN_DEV(ZINWELL,		RT3070),
299206477Sbschmidt    RUN_DEV(ZINWELL,		RT3072_1),
300220723Sbschmidt    RUN_DEV(ZINWELL,		RT3072_2),
301220723Sbschmidt    RUN_DEV(ZYXEL,		RT2870_1),
302206477Sbschmidt    RUN_DEV(ZYXEL,		RT2870_2),
303206477Sbschmidt#undef RUN_DEV
304206477Sbschmidt};
305206477Sbschmidt
306220726Sbschmidtstatic device_probe_t	run_match;
307220726Sbschmidtstatic device_attach_t	run_attach;
308220726Sbschmidtstatic device_detach_t	run_detach;
309220726Sbschmidt
310220726Sbschmidtstatic usb_callback_t	run_bulk_rx_callback;
311198429Srpaulostatic usb_callback_t	run_bulk_tx_callback0;
312178676Ssamstatic usb_callback_t	run_bulk_tx_callback1;
313178676Ssamstatic usb_callback_t	run_bulk_tx_callback2;
314178676Ssamstatic usb_callback_t	run_bulk_tx_callback3;
315178676Ssamstatic usb_callback_t	run_bulk_tx_callback4;
316178676Ssamstatic usb_callback_t	run_bulk_tx_callback5;
317178676Ssam
318178676Ssamstatic void	run_bulk_tx_callbackN(struct usb_xfer *xfer,
319178676Ssam		    usb_error_t error, unsigned int index);
320178676Ssamstatic struct ieee80211vap *run_vap_create(struct ieee80211com *,
321178676Ssam		    const char [IFNAMSIZ], int, enum ieee80211_opmode, int,
322178676Ssam		    const uint8_t [IEEE80211_ADDR_LEN],
323178676Ssam		    const uint8_t [IEEE80211_ADDR_LEN]);
324178676Ssamstatic void	run_vap_delete(struct ieee80211vap *);
325178676Ssamstatic void	run_cmdq_cb(void *, int);
326178676Ssamstatic void	run_setup_tx_list(struct run_softc *,
327178676Ssam		    struct run_endpoint_queue *);
328178676Ssamstatic void	run_unsetup_tx_list(struct run_softc *,
329178676Ssam		    struct run_endpoint_queue *);
330178676Ssamstatic int	run_load_microcode(struct run_softc *);
331178676Ssamstatic int	run_reset(struct run_softc *);
332178676Ssamstatic usb_error_t run_do_request(struct run_softc *,
333178676Ssam		    struct usb_device_request *, void *);
334178676Ssamstatic int	run_read(struct run_softc *, uint16_t, uint32_t *);
335178676Ssamstatic int	run_read_region_1(struct run_softc *, uint16_t, uint8_t *, int);
336178676Ssamstatic int	run_write_2(struct run_softc *, uint16_t, uint16_t);
337178676Ssamstatic int	run_write(struct run_softc *, uint16_t, uint32_t);
338220723Sbschmidtstatic int	run_write_region_1(struct run_softc *, uint16_t,
339220723Sbschmidt		    const uint8_t *, int);
340220723Sbschmidtstatic int	run_set_region_4(struct run_softc *, uint16_t, uint32_t, int);
341220723Sbschmidtstatic int	run_efuse_read_2(struct run_softc *, uint16_t, uint16_t *);
342220723Sbschmidtstatic int	run_eeprom_read_2(struct run_softc *, uint16_t, uint16_t *);
343220723Sbschmidtstatic int	run_rt2870_rf_write(struct run_softc *, uint8_t, uint32_t);
344220723Sbschmidtstatic int	run_rt3070_rf_read(struct run_softc *, uint8_t, uint8_t *);
345220723Sbschmidtstatic int	run_rt3070_rf_write(struct run_softc *, uint8_t, uint8_t);
346220723Sbschmidtstatic int	run_bbp_read(struct run_softc *, uint8_t, uint8_t *);
347220723Sbschmidtstatic int	run_bbp_write(struct run_softc *, uint8_t, uint8_t);
348220723Sbschmidtstatic int	run_mcu_cmd(struct run_softc *, uint8_t, uint16_t);
349220723Sbschmidtstatic const char *run_get_rf(int);
350220723Sbschmidtstatic int	run_read_eeprom(struct run_softc *);
351220723Sbschmidtstatic struct ieee80211_node *run_node_alloc(struct ieee80211vap *,
352220723Sbschmidt			    const uint8_t mac[IEEE80211_ADDR_LEN]);
353220723Sbschmidtstatic int	run_media_change(struct ifnet *);
354220723Sbschmidtstatic int	run_newstate(struct ieee80211vap *, enum ieee80211_state, int);
355220723Sbschmidtstatic int	run_wme_update(struct ieee80211com *);
356220723Sbschmidtstatic void	run_wme_update_cb(void *);
357220723Sbschmidtstatic void	run_key_update_begin(struct ieee80211vap *);
358220723Sbschmidtstatic void	run_key_update_end(struct ieee80211vap *);
359220723Sbschmidtstatic void	run_key_set_cb(void *);
360220723Sbschmidtstatic int	run_key_set(struct ieee80211vap *, struct ieee80211_key *,
361220723Sbschmidt			    const uint8_t mac[IEEE80211_ADDR_LEN]);
362220723Sbschmidtstatic void	run_key_delete_cb(void *);
363220723Sbschmidtstatic int	run_key_delete(struct ieee80211vap *, struct ieee80211_key *);
364220723Sbschmidtstatic void	run_ratectl_to(void *);
365220723Sbschmidtstatic void	run_ratectl_cb(void *, int);
366220723Sbschmidtstatic void	run_drain_fifo(void *);
367220723Sbschmidtstatic void	run_iter_func(void *, struct ieee80211_node *);
368220723Sbschmidtstatic void	run_newassoc_cb(void *);
369220723Sbschmidtstatic void	run_newassoc(struct ieee80211_node *, int);
370220723Sbschmidtstatic void	run_rx_frame(struct run_softc *, struct mbuf *, uint32_t);
371220723Sbschmidtstatic void	run_tx_free(struct run_endpoint_queue *pq,
372220723Sbschmidt		    struct run_tx_data *, int);
373220723Sbschmidtstatic void	run_set_tx_desc(struct run_softc *, struct run_tx_data *);
374220723Sbschmidtstatic int	run_tx(struct run_softc *, struct mbuf *,
375220723Sbschmidt		    struct ieee80211_node *);
376220723Sbschmidtstatic int	run_tx_mgt(struct run_softc *, struct mbuf *,
377220723Sbschmidt		    struct ieee80211_node *);
378220723Sbschmidtstatic int	run_sendprot(struct run_softc *, const struct mbuf *,
379220723Sbschmidt		    struct ieee80211_node *, int, int);
380178676Ssamstatic int	run_tx_param(struct run_softc *, struct mbuf *,
381178676Ssam		    struct ieee80211_node *,
382178676Ssam		    const struct ieee80211_bpf_params *);
383178676Ssamstatic int	run_raw_xmit(struct ieee80211_node *, struct mbuf *,
384220723Sbschmidt		    const struct ieee80211_bpf_params *);
385220723Sbschmidtstatic void	run_start(struct ifnet *);
386220723Sbschmidtstatic int	run_ioctl(struct ifnet *, u_long, caddr_t);
387220723Sbschmidtstatic void	run_set_agc(struct run_softc *, uint8_t);
388220723Sbschmidtstatic void	run_select_chan_group(struct run_softc *, int);
389220723Sbschmidtstatic void	run_set_rx_antenna(struct run_softc *, int);
390220723Sbschmidtstatic void	run_rt2870_set_chan(struct run_softc *, u_int);
391220723Sbschmidtstatic void	run_rt3070_set_chan(struct run_softc *, u_int);
392220723Sbschmidtstatic void	run_rt3572_set_chan(struct run_softc *, u_int);
393178676Ssamstatic int	run_set_chan(struct run_softc *, struct ieee80211_channel *);
394178676Ssamstatic void	run_set_channel(struct ieee80211com *);
395220723Sbschmidtstatic void	run_scan_start(struct ieee80211com *);
396220723Sbschmidtstatic void	run_scan_end(struct ieee80211com *);
397220723Sbschmidtstatic void	run_update_beacon(struct ieee80211vap *, int);
398220726Sbschmidtstatic void	run_update_beacon_cb(void *);
399178676Ssamstatic void	run_updateprot(struct ieee80211com *);
400220723Sbschmidtstatic void	run_updateprot_cb(void *);
401178676Ssamstatic void	run_usb_timeout_cb(void *);
402220723Sbschmidtstatic void	run_reset_livelock(struct run_softc *);
403220726Sbschmidtstatic void	run_enable_tsf_sync(struct run_softc *);
404220723Sbschmidtstatic void	run_enable_mrr(struct run_softc *);
405220723Sbschmidtstatic void	run_set_txpreamble(struct run_softc *);
406220723Sbschmidtstatic void	run_set_basicrates(struct run_softc *);
407220723Sbschmidtstatic void	run_set_leds(struct run_softc *, uint16_t);
408178676Ssamstatic void	run_set_bssid(struct run_softc *, const uint8_t *);
409178676Ssamstatic void	run_set_macaddr(struct run_softc *, const uint8_t *);
410178676Ssamstatic void	run_updateslot(struct ifnet *);
411198429Srpaulostatic void	run_updateslot_cb(void *);
412178676Ssamstatic void	run_update_mcast(struct ifnet *);
413198429Srpaulostatic int8_t	run_rssi2dbm(struct run_softc *, uint8_t, uint8_t);
414198429Srpaulostatic void	run_update_promisc_locked(struct ifnet *);
415198429Srpaulostatic void	run_update_promisc(struct ifnet *);
416198429Srpaulostatic int	run_bbp_init(struct run_softc *);
417198429Srpaulostatic int	run_rt3070_rf_init(struct run_softc *);
418198429Srpaulostatic int	run_rt3070_filter_calib(struct run_softc *, uint8_t, uint8_t,
419198429Srpaulo		    uint8_t *);
420198429Srpaulostatic void	run_rt3070_rf_setup(struct run_softc *);
421178676Ssamstatic int	run_txrx_enable(struct run_softc *);
422178676Ssamstatic void	run_init(void *);
423178676Ssamstatic void	run_init_locked(struct run_softc *);
424178676Ssamstatic void	run_stop(void *);
425178676Ssamstatic void	run_delay(struct run_softc *, unsigned int);
426178676Ssam
427178676Ssamstatic const struct {
428178676Ssam	uint16_t	reg;
429220721Sbschmidt	uint32_t	val;
430184233Smav} rt2870_def_mac[] = {
431190526Ssam	RT2870_DEF_MAC
432178676Ssam};
433178676Ssam
434178676Ssamstatic const struct {
435198429Srpaulo	uint8_t	reg;
436198429Srpaulo	uint8_t	val;
437198429Srpaulo} rt2860_def_bbp[] = {
438198429Srpaulo	RT2860_DEF_BBP
439219902Sjhb};
440198429Srpaulo
441198429Srpaulostatic const struct rfprog {
442198429Srpaulo	uint8_t		chan;
443178676Ssam	uint32_t	r1, r2, r3, r4;
444178676Ssam} rt2860_rf2850[] = {
445198429Srpaulo	RT2860_RF2850
446178676Ssam};
447178676Ssam
448198429Srpaulostruct {
449220721Sbschmidt	uint8_t	n, r, k;
450220721Sbschmidt} rt3070_freqs[] = {
451198429Srpaulo	RT3070_RF3052
452198429Srpaulo};
453220721Sbschmidt
454220721Sbschmidtstatic const struct {
455198429Srpaulo	uint8_t	reg;
456198429Srpaulo	uint8_t	val;
457198429Srpaulo} rt3070_def_rf[] = {
458178676Ssam	RT3070_DEF_RF
459178676Ssam},rt3572_def_rf[] = {
460198429Srpaulo	RT3572_DEF_RF
461178676Ssam};
462198429Srpaulo
463220726Sbschmidtstatic const struct usb_config run_config[RUN_N_XFER] = {
464220724Sbschmidt    [RUN_BULK_TX_BE] = {
465198429Srpaulo	.type = UE_BULK,
466178676Ssam	.endpoint = UE_ADDR_ANY,
467178676Ssam	.ep_index = 0,
468178676Ssam	.direction = UE_DIR_OUT,
469178676Ssam	.bufsize = RUN_MAX_TXSZ,
470220726Sbschmidt	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
471178676Ssam	.callback = run_bulk_tx_callback0,
472184233Smav	.timeout = 5000,	/* ms */
473184233Smav    },
474184233Smav    [RUN_BULK_TX_BK] = {
475220725Sbschmidt	.type = UE_BULK,
476178676Ssam	.endpoint = UE_ADDR_ANY,
477198429Srpaulo	.direction = UE_DIR_OUT,
478178676Ssam	.ep_index = 1,
479220724Sbschmidt	.bufsize = RUN_MAX_TXSZ,
480178676Ssam	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
481198429Srpaulo	.callback = run_bulk_tx_callback1,
482178676Ssam	.timeout = 5000,	/* ms */
483178676Ssam    },
484178676Ssam    [RUN_BULK_TX_VI] = {
485178676Ssam	.type = UE_BULK,
486220728Sbschmidt	.endpoint = UE_ADDR_ANY,
487220728Sbschmidt	.direction = UE_DIR_OUT,
488220728Sbschmidt	.ep_index = 2,
489220728Sbschmidt	.bufsize = RUN_MAX_TXSZ,
490220728Sbschmidt	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
491220728Sbschmidt	.callback = run_bulk_tx_callback2,
492220728Sbschmidt	.timeout = 5000,	/* ms */
493220728Sbschmidt    },
494220728Sbschmidt    [RUN_BULK_TX_VO] = {
495198429Srpaulo	.type = UE_BULK,
496198429Srpaulo	.endpoint = UE_ADDR_ANY,
497198429Srpaulo	.direction = UE_DIR_OUT,
498220726Sbschmidt	.ep_index = 3,
499198429Srpaulo	.bufsize = RUN_MAX_TXSZ,
500178676Ssam	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
501178676Ssam	.callback = run_bulk_tx_callback3,
502178676Ssam	.timeout = 5000,	/* ms */
503198429Srpaulo    },
504220726Sbschmidt    [RUN_BULK_TX_HCCA] = {
505178676Ssam	.type = UE_BULK,
506198429Srpaulo	.endpoint = UE_ADDR_ANY,
507198429Srpaulo	.direction = UE_DIR_OUT,
508178676Ssam	.ep_index = 4,
509178676Ssam	.bufsize = RUN_MAX_TXSZ,
510178676Ssam	.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
511198429Srpaulo	.callback = run_bulk_tx_callback4,
512220726Sbschmidt	.timeout = 5000,	/* ms */
513178676Ssam    },
514220724Sbschmidt    [RUN_BULK_TX_PRIO] = {
515178676Ssam	.type = UE_BULK,
516178676Ssam	.endpoint = UE_ADDR_ANY,
517178676Ssam	.direction = UE_DIR_OUT,
518201209Srpaulo	.ep_index = 5,
519201209Srpaulo	.bufsize = RUN_MAX_TXSZ,
520201209Srpaulo	.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
521220724Sbschmidt	.callback = run_bulk_tx_callback5,
522220724Sbschmidt	.timeout = 5000,	/* ms */
523201209Srpaulo    },
524201209Srpaulo    [RUN_BULK_RX] = {
525201209Srpaulo	.type = UE_BULK,
526198429Srpaulo	.endpoint = UE_ADDR_ANY,
527220726Sbschmidt	.direction = UE_DIR_IN,
528178676Ssam	.bufsize = RUN_MAX_RXSZ,
529220726Sbschmidt	.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
530178676Ssam	.callback = run_bulk_rx_callback,
531178676Ssam    }
532178676Ssam};
533220725Sbschmidt
534220728Sbschmidtstatic int
535220726Sbschmidtrun_match(device_t self)
536178676Ssam{
537220724Sbschmidt	struct usb_attach_arg *uaa = device_get_ivars(self);
538220724Sbschmidt
539178676Ssam	if (uaa->usb_mode != USB_MODE_HOST)
540178676Ssam		return (ENXIO);
541178676Ssam	if (uaa->info.bConfigIndex != 0)
542178676Ssam		return (ENXIO);
543198429Srpaulo	if (uaa->info.bIfaceIndex != RT2860_IFACE_INDEX)
544220726Sbschmidt		return (ENXIO);
545220724Sbschmidt
546220724Sbschmidt	return (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa));
547178676Ssam}
548178676Ssam
549178676Ssamstatic int
550198429Srpaulorun_attach(device_t self)
551198429Srpaulo{
552198429Srpaulo	struct run_softc *sc = device_get_softc(self);
553178676Ssam	struct usb_attach_arg *uaa = device_get_ivars(self);
554178676Ssam	struct ieee80211com *ic;
555178676Ssam	struct ifnet *ifp;
556178676Ssam	uint32_t ver;
557178676Ssam	int i, ntries, error;
558220726Sbschmidt	uint8_t iface_index, bands;
559178676Ssam
560198429Srpaulo	device_set_usb_desc(self);
561178676Ssam	sc->sc_udev = uaa->device;
562178676Ssam	sc->sc_dev = self;
563178676Ssam
564198429Srpaulo	mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev),
565178676Ssam	    MTX_NETWORK_LOCK, MTX_DEF);
566178957Ssam
567178957Ssam	iface_index = RT2860_IFACE_INDEX;
568178676Ssam
569178676Ssam	error = usbd_transfer_setup(uaa->device, &iface_index,
570178676Ssam	    sc->sc_xfer, run_config, RUN_N_XFER, sc, &sc->sc_mtx);
571178676Ssam	if (error) {
572178676Ssam		device_printf(self, "could not allocate USB transfers, "
573178676Ssam		    "err=%s\n", usbd_errstr(error));
574178676Ssam		goto detach;
575178676Ssam	}
576178676Ssam
577221640Sbschmidt	RUN_LOCK(sc);
578221640Sbschmidt
579221640Sbschmidt	/* wait for the chip to settle */
580221642Sbschmidt	for (ntries = 0; ntries < 100; ntries++) {
581221642Sbschmidt		if (run_read(sc, RT2860_ASIC_VER_ID, &ver) != 0) {
582221642Sbschmidt			RUN_UNLOCK(sc);
583221642Sbschmidt			goto detach;
584221642Sbschmidt		}
585221642Sbschmidt		if (ver != 0 && ver != 0xffffffff)
586221642Sbschmidt			break;
587221642Sbschmidt		run_delay(sc, 10);
588221642Sbschmidt	}
589221642Sbschmidt	if (ntries == 100) {
590221642Sbschmidt		device_printf(sc->sc_dev,
591221642Sbschmidt		    "timeout waiting for NIC to initialize\n");
592221642Sbschmidt		RUN_UNLOCK(sc);
593221642Sbschmidt		goto detach;
594221642Sbschmidt	}
595221642Sbschmidt	sc->mac_ver = ver >> 16;
596221642Sbschmidt	sc->mac_rev = ver & 0xffff;
597221642Sbschmidt
598221642Sbschmidt	/* retrieve RF rev. no and various other things from EEPROM */
599221642Sbschmidt	run_read_eeprom(sc);
600221642Sbschmidt
601221642Sbschmidt	device_printf(sc->sc_dev,
602221657Sbschmidt	    "MAC/BBP RT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), address %s\n",
603221657Sbschmidt	    sc->mac_ver, sc->mac_rev, run_get_rf(sc->rf_rev),
604221657Sbschmidt	    sc->ntxchains, sc->nrxchains, ether_sprintf(sc->sc_bssid));
605221657Sbschmidt
606221657Sbschmidt	RUN_UNLOCK(sc);
607221657Sbschmidt
608221657Sbschmidt	ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
609221657Sbschmidt	if (ifp == NULL) {
610221657Sbschmidt		device_printf(sc->sc_dev, "can not if_alloc()\n");
611221657Sbschmidt		goto detach;
612201209Srpaulo	}
613221657Sbschmidt	ic = ifp->if_l2com;
614221657Sbschmidt
615221657Sbschmidt	ifp->if_softc = sc;
616178678Ssam	if_initname(ifp, "run", device_get_unit(sc->sc_dev));
617201209Srpaulo	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
618221657Sbschmidt	ifp->if_init = run_init;
619221657Sbschmidt	ifp->if_ioctl = run_ioctl;
620221657Sbschmidt	ifp->if_start = run_start;
621221657Sbschmidt	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
622221657Sbschmidt	ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
623201209Srpaulo	IFQ_SET_READY(&ifp->if_snd);
624221657Sbschmidt
625221657Sbschmidt	ic->ic_ifp = ifp;
626201209Srpaulo	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
627178676Ssam	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
628178676Ssam
629178676Ssam	/* set device capabilities */
630178676Ssam	ic->ic_caps =
631178676Ssam	    IEEE80211_C_STA |		/* station mode supported */
632178676Ssam	    IEEE80211_C_MONITOR |	/* monitor mode supported */
633207554Ssobomax	    IEEE80211_C_IBSS |
634207554Ssobomax	    IEEE80211_C_HOSTAP |
635178676Ssam	    IEEE80211_C_WDS |		/* 4-address traffic works */
636178676Ssam	    IEEE80211_C_MBSS |
637190526Ssam	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
638178676Ssam	    IEEE80211_C_SHSLOT |	/* short slot time supported */
639178676Ssam	    IEEE80211_C_WME |		/* WME */
640178676Ssam	    IEEE80211_C_WPA;		/* WPA1|WPA2(RSN) */
641178676Ssam
642221650Sbschmidt	ic->ic_cryptocaps =
643220723Sbschmidt	    IEEE80211_CRYPTO_WEP |
644221650Sbschmidt	    IEEE80211_CRYPTO_AES_CCM |
645220723Sbschmidt	    IEEE80211_CRYPTO_TKIPMIC |
646221651Sbschmidt	    IEEE80211_CRYPTO_TKIP;
647221651Sbschmidt
648221651Sbschmidt	ic->ic_flags |= IEEE80211_F_DATAPAD;
649221651Sbschmidt	ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;
650221651Sbschmidt
651221651Sbschmidt	bands = 0;
652220715Sbschmidt	setbit(&bands, IEEE80211_MODE_11B);
653220721Sbschmidt	setbit(&bands, IEEE80211_MODE_11G);
654201209Srpaulo	ieee80211_init_channels(ic, NULL, &bands);
655198429Srpaulo
656198429Srpaulo	/*
657198429Srpaulo	 * Do this by own because h/w supports
658198429Srpaulo	 * more channels than ieee80211_init_channels()
659198429Srpaulo	 */
660201209Srpaulo	if (sc->rf_rev == RT2860_RF_2750 ||
661178676Ssam	    sc->rf_rev == RT2860_RF_2850 ||
662198429Srpaulo	    sc->rf_rev == RT3070_RF_3052) {
663220667Sbschmidt		/* set supported .11a rates */
664220667Sbschmidt		for (i = 14; i < N(rt2860_rf2850); i++) {
665220667Sbschmidt			uint8_t chan = rt2860_rf2850[i].chan;
666220726Sbschmidt			ic->ic_channels[ic->ic_nchans].ic_freq =
667220726Sbschmidt			    ieee80211_ieee2mhz(chan, IEEE80211_CHAN_A);
668220726Sbschmidt			ic->ic_channels[ic->ic_nchans].ic_ieee = chan;
669220667Sbschmidt			ic->ic_channels[ic->ic_nchans].ic_flags = IEEE80211_CHAN_A;
670178676Ssam			ic->ic_channels[ic->ic_nchans].ic_extieee = 0;
671178676Ssam			ic->ic_nchans++;
672198429Srpaulo		}
673198429Srpaulo	}
674198429Srpaulo
675198429Srpaulo	ieee80211_ifattach(ic, sc->sc_bssid);
676178676Ssam
677198429Srpaulo	ic->ic_scan_start = run_scan_start;
678220724Sbschmidt	ic->ic_scan_end = run_scan_end;
679198429Srpaulo	ic->ic_set_channel = run_set_channel;
680198429Srpaulo	ic->ic_node_alloc = run_node_alloc;
681198429Srpaulo	ic->ic_newassoc = run_newassoc;
682178676Ssam	ic->ic_updateslot = run_updateslot;
683220724Sbschmidt	ic->ic_update_mcast = run_update_mcast;
684220724Sbschmidt	ic->ic_wme.wme_update = run_wme_update;
685178676Ssam	ic->ic_raw_xmit = run_raw_xmit;
686178676Ssam	ic->ic_update_promisc = run_update_promisc;
687220635Sbschmidt
688178676Ssam	ic->ic_vap_create = run_vap_create;
689178676Ssam	ic->ic_vap_delete = run_vap_delete;
690178676Ssam
691220728Sbschmidt	ieee80211_radiotap_attach(ic,
692220728Sbschmidt	    &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap),
693178676Ssam		RUN_TX_RADIOTAP_PRESENT,
694220728Sbschmidt	    &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap),
695198429Srpaulo		RUN_RX_RADIOTAP_PRESENT);
696220728Sbschmidt
697220728Sbschmidt	TASK_INIT(&sc->cmdq_task, 0, run_cmdq_cb, sc);
698220728Sbschmidt	TASK_INIT(&sc->ratectl_task, 0, run_ratectl_cb, sc);
699220728Sbschmidt	callout_init((struct callout *)&sc->ratectl_ch, 1);
700220728Sbschmidt
701220728Sbschmidt	if (bootverbose)
702220728Sbschmidt		ieee80211_announce(ic);
703220728Sbschmidt
704220728Sbschmidt	return (0);
705220728Sbschmidt
706220728Sbschmidtdetach:
707220728Sbschmidt	run_detach(self);
708220728Sbschmidt	return (ENXIO);
709220728Sbschmidt}
710220728Sbschmidt
711221651Sbschmidtstatic int
712220728Sbschmidtrun_detach(device_t self)
713220728Sbschmidt{
714220728Sbschmidt	struct run_softc *sc = device_get_softc(self);
715220728Sbschmidt	struct ifnet *ifp = sc->sc_ifp;
716220728Sbschmidt	struct ieee80211com *ic;
717220728Sbschmidt	int i;
718220728Sbschmidt
719220728Sbschmidt	/* stop all USB transfers */
720220728Sbschmidt	usbd_transfer_unsetup(sc->sc_xfer, RUN_N_XFER);
721220728Sbschmidt
722220728Sbschmidt	RUN_LOCK(sc);
723220728Sbschmidt
724220728Sbschmidt	sc->ratectl_run = RUN_RATECTL_OFF;
725220728Sbschmidt	sc->cmdq_run = sc->cmdq_key_set = RUN_CMDQ_ABORT;
726220728Sbschmidt
727220728Sbschmidt	/* free TX list, if any */
728220728Sbschmidt	for (i = 0; i != RUN_EP_QUEUES; i++)
729220728Sbschmidt		run_unsetup_tx_list(sc, &sc->sc_epq[i]);
730220728Sbschmidt	RUN_UNLOCK(sc);
731220728Sbschmidt
732220728Sbschmidt	if (ifp) {
733220728Sbschmidt		ic = ifp->if_l2com;
734220728Sbschmidt		/* drain tasks */
735220728Sbschmidt		usb_callout_drain(&sc->ratectl_ch);
736220728Sbschmidt		ieee80211_draintask(ic, &sc->cmdq_task);
737220728Sbschmidt		ieee80211_draintask(ic, &sc->ratectl_task);
738220728Sbschmidt		ieee80211_ifdetach(ic);
739220728Sbschmidt		if_free(ifp);
740220728Sbschmidt	}
741220728Sbschmidt
742220728Sbschmidt	mtx_destroy(&sc->sc_mtx);
743220728Sbschmidt
744220728Sbschmidt	return (0);
745220728Sbschmidt}
746220728Sbschmidt
747220728Sbschmidtstatic struct ieee80211vap *
748220728Sbschmidtrun_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
749221651Sbschmidt    enum ieee80211_opmode opmode, int flags,
750220728Sbschmidt    const uint8_t bssid[IEEE80211_ADDR_LEN],
751220728Sbschmidt    const uint8_t mac[IEEE80211_ADDR_LEN])
752220728Sbschmidt{
753220728Sbschmidt	struct ifnet *ifp = ic->ic_ifp;
754220728Sbschmidt	struct run_softc *sc = ifp->if_softc;
755220728Sbschmidt	struct run_vap *rvp;
756220728Sbschmidt	struct ieee80211vap *vap;
757220728Sbschmidt	int i;
758220866Sbschmidt
759220866Sbschmidt	if (sc->rvp_cnt >= RUN_VAP_MAX) {
760220728Sbschmidt		if_printf(ifp, "number of VAPs maxed out\n");
761198429Srpaulo		return (NULL);
762198429Srpaulo	}
763201209Srpaulo
764198439Srpaulo	switch (opmode) {
765220727Sbschmidt	case IEEE80211_M_STA:
766201209Srpaulo		/* enable s/w bmiss handling for sta mode */
767201209Srpaulo		flags |= IEEE80211_CLONE_NOBEACONS;
768198429Srpaulo		/* fall though */
769198429Srpaulo	case IEEE80211_M_IBSS:
770201209Srpaulo	case IEEE80211_M_MONITOR:
771198439Srpaulo	case IEEE80211_M_HOSTAP:
772198429Srpaulo	case IEEE80211_M_MBSS:
773198429Srpaulo		/* other than WDS vaps, only one at a time */
774198429Srpaulo		if (!TAILQ_EMPTY(&ic->ic_vaps))
775201209Srpaulo			return (NULL);
776198439Srpaulo		break;
777198429Srpaulo	case IEEE80211_M_WDS:
778198429Srpaulo		TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next){
779206444Sbschmidt			if(vap->iv_opmode != IEEE80211_M_HOSTAP)
780198439Srpaulo				continue;
781198429Srpaulo			/* WDS vap's always share the local mac address. */
782198429Srpaulo			flags &= ~IEEE80211_CLONE_BSSID;
783201209Srpaulo			break;
784198439Srpaulo		}
785220728Sbschmidt		if (vap == NULL) {
786201209Srpaulo			if_printf(ifp, "wds only supported in ap mode\n");
787220727Sbschmidt			return (NULL);
788201209Srpaulo		}
789201209Srpaulo		break;
790201209Srpaulo	default:
791198429Srpaulo		if_printf(ifp, "unknown opmode %d\n", opmode);
792198429Srpaulo		return (NULL);
793201209Srpaulo	}
794210109Sbschmidt
795220867Sbschmidt	rvp = (struct run_vap *) malloc(sizeof(struct run_vap),
796220867Sbschmidt	    M_80211_VAP, M_NOWAIT | M_ZERO);
797220867Sbschmidt	if (rvp == NULL)
798198429Srpaulo		return (NULL);
799210109Sbschmidt	vap = &rvp->vap;
800210109Sbschmidt	ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac);
801220894Sbschmidt
802220894Sbschmidt	vap->iv_key_update_begin = run_key_update_begin;
803220891Sbschmidt	vap->iv_key_update_end = run_key_update_end;
804220894Sbschmidt	vap->iv_update_beacon = run_update_beacon;
805220894Sbschmidt	vap->iv_max_aid = RT2870_WCID_MAX;
806210109Sbschmidt	/*
807198429Srpaulo	 * To delete the right key from h/w, we need wcid.
808198429Srpaulo	 * Luckily, there is unused space in ieee80211_key{}, wk_pad,
809198429Srpaulo	 * and matching wcid will be written into there. So, cast
810220728Sbschmidt	 * some spells to remove 'const' from ieee80211_key{}
811198429Srpaulo	 */
812220728Sbschmidt	vap->iv_key_delete = (void *)run_key_delete;
813178676Ssam	vap->iv_key_set = (void *)run_key_set;
814178676Ssam
815178676Ssam	/* override state transition machine */
816198429Srpaulo	rvp->newstate = vap->iv_newstate;
817178676Ssam	vap->iv_newstate = run_newstate;
818206477Sbschmidt
819198429Srpaulo	ieee80211_ratectl_init(vap);
820178676Ssam	ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */);
821178676Ssam
822178676Ssam	/* complete setup */
823178676Ssam	ieee80211_vap_attach(vap, run_media_change, ieee80211_media_status);
824198429Srpaulo
825198429Srpaulo	/* make sure id is always unique */
826198429Srpaulo	for (i = 0; i < RUN_VAP_MAX; i++) {
827198429Srpaulo		if((sc->rvp_bmap & 1 << i) == 0){
828198429Srpaulo			sc->rvp_bmap |= 1 << i;
829178676Ssam			rvp->rvp_id = i;
830178676Ssam			break;
831220723Sbschmidt		}
832220723Sbschmidt	}
833220723Sbschmidt	if (sc->rvp_cnt++ == 0)
834220723Sbschmidt		ic->ic_opmode = opmode;
835220723Sbschmidt
836220723Sbschmidt	if (opmode == IEEE80211_M_HOSTAP)
837220723Sbschmidt		sc->cmdq_run = RUN_CMDQ_GO;
838220723Sbschmidt
839220723Sbschmidt	DPRINTF("rvp_id=%d bmap=%x rvp_cnt=%d\n",
840220723Sbschmidt	    rvp->rvp_id, sc->rvp_bmap, sc->rvp_cnt);
841220723Sbschmidt
842220723Sbschmidt	return (vap);
843220723Sbschmidt}
844178676Ssam
845178676Ssamstatic void
846220726Sbschmidtrun_vap_delete(struct ieee80211vap *vap)
847220726Sbschmidt{
848220726Sbschmidt	struct run_vap *rvp = RUN_VAP(vap);
849178676Ssam	struct ifnet *ifp;
850178676Ssam	struct ieee80211com *ic;
851178676Ssam	struct run_softc *sc;
852178676Ssam	uint8_t rvp_id;
853178676Ssam
854178676Ssam	if (vap == NULL)
855178676Ssam		return;
856178676Ssam
857178676Ssam	ic = vap->iv_ic;
858178676Ssam	ifp = ic->ic_ifp;
859178676Ssam
860178676Ssam	sc = ifp->if_softc;
861178676Ssam
862198429Srpaulo	RUN_LOCK(sc);
863178676Ssam
864178676Ssam	m_freem(rvp->beacon_mbuf);
865178676Ssam	rvp->beacon_mbuf = NULL;
866206358Srpaulo
867198429Srpaulo	rvp_id = rvp->rvp_id;
868206476Sbschmidt	sc->ratectl_run &= ~(1 << rvp_id);
869178676Ssam	sc->rvp_bmap &= ~(1 << rvp_id);
870178676Ssam	run_set_region_4(sc, RT2860_SKEY(rvp_id, 0), 0, 128);
871178676Ssam	run_set_region_4(sc, RT2860_BCN_BASE(rvp_id), 0, 512);
872178676Ssam	--sc->rvp_cnt;
873178676Ssam
874178676Ssam	DPRINTF("vap=%p rvp_id=%d bmap=%x rvp_cnt=%d\n",
875178676Ssam	    vap, rvp_id, sc->rvp_bmap, sc->rvp_cnt);
876178676Ssam
877178676Ssam	RUN_UNLOCK(sc);
878206358Srpaulo
879178676Ssam	ieee80211_ratectl_deinit(vap);
880178676Ssam	ieee80211_vap_detach(vap);
881178676Ssam	free(rvp, M_80211_VAP);
882178676Ssam}
883206477Sbschmidt
884220635Sbschmidt/*
885178676Ssam * There are numbers of functions need to be called in context thread.
886178676Ssam * Rather than creating taskqueue event for each of those functions,
887198429Srpaulo * here is all-for-one taskqueue callback function. This function
888198429Srpaulo * gurantees deferred functions are executed in the same order they
889220721Sbschmidt * were enqueued.
890178676Ssam * '& RUN_CMDQ_MASQ' is to loop cmdq[].
891198429Srpaulo */
892198429Srpaulostatic void
893198429Srpaulorun_cmdq_cb(void *arg, int pending)
894198429Srpaulo{
895198429Srpaulo	struct run_softc *sc = arg;
896198429Srpaulo	uint8_t i;
897198429Srpaulo
898198429Srpaulo	/* call cmdq[].func locked */
899220667Sbschmidt	RUN_LOCK(sc);
900220667Sbschmidt	for (i = sc->cmdq_exec; sc->cmdq[i].func && pending;
901198429Srpaulo	    i = sc->cmdq_exec, pending--) {
902198429Srpaulo		DPRINTFN(6, "cmdq_exec=%d pending=%d\n", i, pending);
903198429Srpaulo		if (sc->cmdq_run == RUN_CMDQ_GO) {
904220725Sbschmidt			/*
905220723Sbschmidt			 * If arg0 is NULL, callback func needs more
906220723Sbschmidt			 * than one arg. So, pass ptr to cmdq struct.
907220723Sbschmidt			 */
908220723Sbschmidt			if (sc->cmdq[i].arg0)
909220723Sbschmidt				sc->cmdq[i].func(sc->cmdq[i].arg0);
910220723Sbschmidt			else
911220723Sbschmidt				sc->cmdq[i].func(&sc->cmdq[i]);
912201209Srpaulo		}
913198429Srpaulo		sc->cmdq[i].arg0 = NULL;
914220728Sbschmidt		sc->cmdq[i].func = NULL;
915220728Sbschmidt		sc->cmdq_exec++;
916198429Srpaulo		sc->cmdq_exec &= RUN_CMDQ_MASQ;
917198429Srpaulo	}
918201209Srpaulo	RUN_UNLOCK(sc);
919201209Srpaulo}
920198429Srpaulo
921198429Srpaulostatic void
922198429Srpaulorun_setup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
923198429Srpaulo{
924198429Srpaulo	struct run_tx_data *data;
925198429Srpaulo
926198429Srpaulo	memset(pq, 0, sizeof(*pq));
927198429Srpaulo
928198429Srpaulo	STAILQ_INIT(&pq->tx_qh);
929178676Ssam	STAILQ_INIT(&pq->tx_fh);
930178676Ssam
931178676Ssam	for (data = &pq->tx_data[0];
932178676Ssam	    data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) {
933220723Sbschmidt		data->sc = sc;
934220723Sbschmidt		STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
935220723Sbschmidt	}
936220723Sbschmidt	pq->tx_nfree = RUN_TX_RING_COUNT;
937220723Sbschmidt}
938220723Sbschmidt
939220723Sbschmidtstatic void
940220723Sbschmidtrun_unsetup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
941220723Sbschmidt{
942220723Sbschmidt	struct run_tx_data *data;
943220723Sbschmidt
944220723Sbschmidt	/* make sure any subsequent use of the queues will fail */
945220723Sbschmidt	pq->tx_nfree = 0;
946220723Sbschmidt	STAILQ_INIT(&pq->tx_fh);
947220723Sbschmidt	STAILQ_INIT(&pq->tx_qh);
948220723Sbschmidt
949220723Sbschmidt	/* free up all node references and mbufs */
950220723Sbschmidt	for (data = &pq->tx_data[0];
951220723Sbschmidt	    data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) {
952220723Sbschmidt		if (data->m != NULL) {
953220723Sbschmidt			m_freem(data->m);
954220723Sbschmidt			data->m = NULL;
955220723Sbschmidt		}
956220723Sbschmidt		if (data->ni != NULL) {
957220723Sbschmidt			ieee80211_free_node(data->ni);
958220723Sbschmidt			data->ni = NULL;
959220723Sbschmidt		}
960220723Sbschmidt	}
961220723Sbschmidt}
962220723Sbschmidt
963220723Sbschmidtstatic int
964220723Sbschmidtrun_load_microcode(struct run_softc *sc)
965220723Sbschmidt{
966220723Sbschmidt	usb_device_request_t req;
967220723Sbschmidt	const struct firmware *fw;
968220723Sbschmidt	const u_char *base;
969220723Sbschmidt	uint32_t tmp;
970220723Sbschmidt	int ntries, error;
971220723Sbschmidt	const uint64_t *temp;
972220723Sbschmidt	uint64_t bytes;
973220723Sbschmidt
974220723Sbschmidt	RUN_UNLOCK(sc);
975220723Sbschmidt	fw = firmware_get("runfw");
976220723Sbschmidt	RUN_LOCK(sc);
977198429Srpaulo	if (fw == NULL) {
978178676Ssam		device_printf(sc->sc_dev,
979198429Srpaulo		    "failed loadfirmware of file %s\n", "runfw");
980178676Ssam		return ENOENT;
981198429Srpaulo	}
982198429Srpaulo
983178676Ssam	if (fw->datasize != 8192) {
984198429Srpaulo		device_printf(sc->sc_dev,
985198429Srpaulo		    "invalid firmware size (should be 8KB)\n");
986198429Srpaulo		error = EINVAL;
987220726Sbschmidt		goto fail;
988198429Srpaulo	}
989198429Srpaulo
990198429Srpaulo	/*
991198429Srpaulo	 * RT3071/RT3072 use a different firmware
992198429Srpaulo	 * run-rt2870 (8KB) contains both,
993198429Srpaulo	 * first half (4KB) is for rt2870,
994198429Srpaulo	 * last half is for rt3071.
995198429Srpaulo	 */
996198429Srpaulo	base = fw->data;
997198429Srpaulo	if ((sc->mac_ver) != 0x2860 &&
998198429Srpaulo	    (sc->mac_ver) != 0x2872 &&
999198429Srpaulo	    (sc->mac_ver) != 0x3070) {
1000198429Srpaulo		base += 4096;
1001198429Srpaulo	}
1002198429Srpaulo
1003198429Srpaulo	/* cheap sanity check */
1004198429Srpaulo	temp = fw->data;
1005201209Srpaulo	bytes = *temp;
1006198429Srpaulo	if (bytes != be64toh(0xffffff0210280210)) {
1007198429Srpaulo		device_printf(sc->sc_dev, "firmware checksum failed\n");
1008198429Srpaulo		error = EINVAL;
1009198429Srpaulo		goto fail;
1010198429Srpaulo	}
1011198429Srpaulo
1012198429Srpaulo	run_read(sc, RT2860_ASIC_VER_ID, &tmp);
1013201209Srpaulo	/* write microcode image */
1014198429Srpaulo	run_write_region_1(sc, RT2870_FW_BASE, base, 4096);
1015198429Srpaulo	run_write(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff);
1016198429Srpaulo	run_write(sc, RT2860_H2M_MAILBOX_STATUS, 0xffffffff);
1017198429Srpaulo
1018198429Srpaulo	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1019198429Srpaulo	req.bRequest = RT2870_RESET;
1020198429Srpaulo	USETW(req.wValue, 8);
1021198429Srpaulo	USETW(req.wIndex, 0);
1022198429Srpaulo	USETW(req.wLength, 0);
1023198429Srpaulo	if ((error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL))
1024198429Srpaulo	    != 0) {
1025198429Srpaulo		device_printf(sc->sc_dev, "firmware reset failed\n");
1026198429Srpaulo		goto fail;
1027198429Srpaulo	}
1028198429Srpaulo
1029198429Srpaulo	run_delay(sc, 10);
1030198429Srpaulo
1031198429Srpaulo	run_write(sc, RT2860_H2M_MAILBOX, 0);
1032198429Srpaulo	if ((error = run_mcu_cmd(sc, RT2860_MCU_CMD_RFRESET, 0)) != 0)
1033198429Srpaulo		goto fail;
1034198429Srpaulo
1035198429Srpaulo	/* wait until microcontroller is ready */
1036198429Srpaulo	for (ntries = 0; ntries < 1000; ntries++) {
1037198429Srpaulo		if ((error = run_read(sc, RT2860_SYS_CTRL, &tmp)) != 0) {
1038198429Srpaulo			goto fail;
1039198429Srpaulo		}
1040198429Srpaulo		if (tmp & RT2860_MCU_READY)
1041201209Srpaulo			break;
1042198429Srpaulo		run_delay(sc, 10);
1043198429Srpaulo	}
1044198429Srpaulo	if (ntries == 1000) {
1045198429Srpaulo		device_printf(sc->sc_dev,
1046198429Srpaulo		    "timeout waiting for MCU to initialize\n");
1047198429Srpaulo		error = ETIMEDOUT;
1048198429Srpaulo		goto fail;
1049201209Srpaulo	}
1050198429Srpaulo	device_printf(sc->sc_dev, "firmware %s ver. %u.%u loaded\n",
1051198429Srpaulo	    (base == fw->data) ? "RT2870" : "RT3071",
1052198429Srpaulo	    *(base + 4092), *(base + 4093));
1053198429Srpaulo
1054198429Srpaulofail:
1055198429Srpaulo	firmware_put(fw, FIRMWARE_UNLOAD);
1056198429Srpaulo	return (error);
1057198429Srpaulo}
1058198429Srpaulo
1059198429Srpauloint
1060198429Srpaulorun_reset(struct run_softc *sc)
1061198429Srpaulo{
1062198429Srpaulo	usb_device_request_t req;
1063198429Srpaulo
1064198429Srpaulo	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1065198429Srpaulo	req.bRequest = RT2870_RESET;
1066198429Srpaulo	USETW(req.wValue, 1);
1067198429Srpaulo	USETW(req.wIndex, 0);
1068198429Srpaulo	USETW(req.wLength, 0);
1069198429Srpaulo	return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL));
1070198429Srpaulo}
1071198429Srpaulo
1072198429Srpaulostatic usb_error_t
1073198429Srpaulorun_do_request(struct run_softc *sc,
1074198429Srpaulo    struct usb_device_request *req, void *data)
1075198429Srpaulo{
1076198429Srpaulo	usb_error_t err;
1077198429Srpaulo	int ntries = 10;
1078198429Srpaulo
1079198429Srpaulo	RUN_LOCK_ASSERT(sc, MA_OWNED);
1080198429Srpaulo
1081198429Srpaulo	while (ntries--) {
1082206477Sbschmidt		err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx,
1083198429Srpaulo		    req, data, 0, NULL, 250 /* ms */);
1084198429Srpaulo		if (err == 0)
1085198429Srpaulo			break;
1086198429Srpaulo		DPRINTFN(1, "Control request failed, %s (retrying)\n",
1087198429Srpaulo		    usbd_errstr(err));
1088198429Srpaulo		run_delay(sc, 10);
1089198429Srpaulo	}
1090198429Srpaulo	return (err);
1091198429Srpaulo}
1092198429Srpaulo
1093198429Srpaulostatic int
1094198429Srpaulorun_read(struct run_softc *sc, uint16_t reg, uint32_t *val)
1095198429Srpaulo{
1096198429Srpaulo	uint32_t tmp;
1097198429Srpaulo	int error;
1098198429Srpaulo
1099198429Srpaulo	error = run_read_region_1(sc, reg, (uint8_t *)&tmp, sizeof tmp);
1100198429Srpaulo	if (error == 0)
1101198429Srpaulo		*val = le32toh(tmp);
1102198429Srpaulo	else
1103198429Srpaulo		*val = 0xffffffff;
1104198429Srpaulo	return (error);
1105198429Srpaulo}
1106198429Srpaulo
1107198429Srpaulostatic int
1108198429Srpaulorun_read_region_1(struct run_softc *sc, uint16_t reg, uint8_t *buf, int len)
1109198429Srpaulo{
1110198429Srpaulo	usb_device_request_t req;
1111198429Srpaulo
1112198429Srpaulo	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1113206477Sbschmidt	req.bRequest = RT2870_READ_REGION_1;
1114198429Srpaulo	USETW(req.wValue, 0);
1115198429Srpaulo	USETW(req.wIndex, reg);
1116203934Sbschmidt	USETW(req.wLength, len);
1117201209Srpaulo
1118198429Srpaulo	return (run_do_request(sc, &req, buf));
1119201209Srpaulo}
1120220726Sbschmidt
1121198429Srpaulostatic int
1122198429Srpaulorun_write_2(struct run_softc *sc, uint16_t reg, uint16_t val)
1123220726Sbschmidt{
1124198429Srpaulo	usb_device_request_t req;
1125198429Srpaulo
1126198429Srpaulo	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1127198429Srpaulo	req.bRequest = RT2870_WRITE_2;
1128198429Srpaulo	USETW(req.wValue, val);
1129198429Srpaulo	USETW(req.wIndex, reg);
1130201209Srpaulo	USETW(req.wLength, 0);
1131201209Srpaulo
1132201209Srpaulo	return (run_do_request(sc, &req, NULL));
1133201209Srpaulo}
1134201209Srpaulo
1135198429Srpaulostatic int
1136198429Srpaulorun_write(struct run_softc *sc, uint16_t reg, uint32_t val)
1137198429Srpaulo{
1138198429Srpaulo	int error;
1139198429Srpaulo
1140201209Srpaulo	if ((error = run_write_2(sc, reg, val & 0xffff)) == 0)
1141203934Sbschmidt		error = run_write_2(sc, reg + 2, val >> 16);
1142203934Sbschmidt	return (error);
1143201209Srpaulo}
1144201209Srpaulo
1145201209Srpaulostatic int
1146201209Srpaulorun_write_region_1(struct run_softc *sc, uint16_t reg, const uint8_t *buf,
1147203934Sbschmidt    int len)
1148201209Srpaulo{
1149201209Srpaulo#if 1
1150201209Srpaulo	int i, error = 0;
1151201209Srpaulo	/*
1152201209Srpaulo	 * NB: the WRITE_REGION_1 command is not stable on RT2860.
1153201209Srpaulo	 * We thus issue multiple WRITE_2 commands instead.
1154203934Sbschmidt	 */
1155201209Srpaulo	KASSERT((len & 1) == 0, ("run_write_region_1: Data too long.\n"));
1156201209Srpaulo	for (i = 0; i < len && error == 0; i += 2)
1157203934Sbschmidt		error = run_write_2(sc, reg + i, buf[i] | buf[i + 1] << 8);
1158201209Srpaulo	return (error);
1159201209Srpaulo#else
1160203934Sbschmidt	usb_device_request_t req;
1161201209Srpaulo
1162178676Ssam	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1163178676Ssam	req.bRequest = RT2870_WRITE_REGION_1;
1164178676Ssam	USETW(req.wValue, 0);
1165206477Sbschmidt	USETW(req.wIndex, reg);
1166198429Srpaulo	USETW(req.wLength, len);
1167198429Srpaulo	return (run_do_request(sc, &req, buf));
1168220723Sbschmidt#endif
1169198429Srpaulo}
1170198429Srpaulo
1171198429Srpaulostatic int
1172201209Srpaulorun_set_region_4(struct run_softc *sc, uint16_t reg, uint32_t val, int len)
1173198429Srpaulo{
1174198429Srpaulo	int i, error = 0;
1175201209Srpaulo
1176198429Srpaulo	KASSERT((len & 3) == 0, ("run_set_region_4: Invalid data length.\n"));
1177198429Srpaulo	for (i = 0; i < len && error == 0; i += 4)
1178198429Srpaulo		error = run_write(sc, reg + i, val);
1179198429Srpaulo	return (error);
1180198429Srpaulo}
1181201209Srpaulo
1182198429Srpaulo/* Read 16-bit from eFUSE ROM (RT3070 only.) */
1183198429Srpaulostatic int
1184198429Srpaulorun_efuse_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
1185198429Srpaulo{
1186198429Srpaulo	uint32_t tmp;
1187198429Srpaulo	uint16_t reg;
1188198429Srpaulo	int error, ntries;
1189198429Srpaulo
1190198429Srpaulo	if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
1191198429Srpaulo		return (error);
1192198429Srpaulo
1193198429Srpaulo	addr *= 2;
1194198429Srpaulo	/*-
1195198429Srpaulo	 * Read one 16-byte block into registers EFUSE_DATA[0-3]:
1196198429Srpaulo	 * DATA0: F E D C
1197198429Srpaulo	 * DATA1: B A 9 8
1198198429Srpaulo	 * DATA2: 7 6 5 4
1199198429Srpaulo	 * DATA3: 3 2 1 0
1200198429Srpaulo	 */
1201198429Srpaulo	tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK);
1202198429Srpaulo	tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK;
1203198429Srpaulo	run_write(sc, RT3070_EFUSE_CTRL, tmp);
1204198429Srpaulo	for (ntries = 0; ntries < 100; ntries++) {
1205198429Srpaulo		if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
1206198429Srpaulo			return (error);
1207178676Ssam		if (!(tmp & RT3070_EFSROM_KICK))
1208178676Ssam			break;
1209178676Ssam		run_delay(sc, 2);
1210198429Srpaulo	}
1211198429Srpaulo	if (ntries == 100)
1212198429Srpaulo		return (ETIMEDOUT);
1213198429Srpaulo
1214178676Ssam	if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK) {
1215178676Ssam		*val = 0xffff;	/* address not found */
1216198429Srpaulo		return (0);
1217178676Ssam	}
1218220691Sbschmidt	/* determine to which 32-bit register our 16-bit word belongs */
1219178676Ssam	reg = RT3070_EFUSE_DATA3 - (addr & 0xc);
1220198429Srpaulo	if ((error = run_read(sc, reg, &tmp)) != 0)
1221178676Ssam		return (error);
1222220723Sbschmidt
1223178676Ssam	*val = (addr & 2) ? tmp >> 16 : tmp & 0xffff;
1224178676Ssam	return (0);
1225198429Srpaulo}
1226178676Ssam
1227220691Sbschmidtstatic int
1228220711Sbschmidtrun_eeprom_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
1229178676Ssam{
1230220711Sbschmidt	usb_device_request_t req;
1231178676Ssam	uint16_t tmp;
1232220691Sbschmidt	int error;
1233220711Sbschmidt
1234178676Ssam	addr *= 2;
1235220711Sbschmidt	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1236220691Sbschmidt	req.bRequest = RT2870_EEPROM_READ;
1237220691Sbschmidt	USETW(req.wValue, 0);
1238220711Sbschmidt	USETW(req.wIndex, addr);
1239178676Ssam	USETW(req.wLength, sizeof tmp);
1240178676Ssam
1241220704Sbschmidt	error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, &tmp);
1242220704Sbschmidt	if (error == 0)
1243178676Ssam		*val = le16toh(tmp);
1244178676Ssam	else
1245220726Sbschmidt		*val = 0xffff;
1246178676Ssam	return (error);
1247220726Sbschmidt}
1248220726Sbschmidt
1249178676Ssamstatic __inline int
1250178676Ssamrun_srom_read(struct run_softc *sc, uint16_t addr, uint16_t *val)
1251178676Ssam{
1252206477Sbschmidt	/* either eFUSE ROM or EEPROM */
1253178676Ssam	return sc->sc_srom_read(sc, addr, val);
1254178676Ssam}
1255220701Sbschmidt
1256220701Sbschmidtstatic int
1257220701Sbschmidtrun_rt2870_rf_write(struct run_softc *sc, uint8_t reg, uint32_t val)
1258220701Sbschmidt{
1259220701Sbschmidt	uint32_t tmp;
1260178676Ssam	int error, ntries;
1261220701Sbschmidt
1262178676Ssam	for (ntries = 0; ntries < 10; ntries++) {
1263220701Sbschmidt		if ((error = run_read(sc, RT2860_RF_CSR_CFG0, &tmp)) != 0)
1264220701Sbschmidt			return (error);
1265220701Sbschmidt		if (!(tmp & RT2860_RF_REG_CTRL))
1266220701Sbschmidt			break;
1267178676Ssam	}
1268220701Sbschmidt	if (ntries == 10)
1269178676Ssam		return (ETIMEDOUT);
1270178676Ssam
1271178676Ssam	/* RF registers are 24-bit on the RT2860 */
1272206477Sbschmidt	tmp = RT2860_RF_REG_CTRL | 24 << RT2860_RF_REG_WIDTH_SHIFT |
1273198429Srpaulo	    (val & 0x3fffff) << 2 | (reg & 3);
1274178676Ssam	return (run_write(sc, RT2860_RF_CSR_CFG0, tmp));
1275198429Srpaulo}
1276220691Sbschmidt
1277220728Sbschmidtstatic int
1278178676Ssamrun_rt3070_rf_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
1279178676Ssam{
1280206477Sbschmidt	uint32_t tmp;
1281198429Srpaulo	int error, ntries;
1282178676Ssam
1283198429Srpaulo	for (ntries = 0; ntries < 100; ntries++) {
1284178676Ssam		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1285178676Ssam			return (error);
1286206477Sbschmidt		if (!(tmp & RT3070_RF_KICK))
1287178676Ssam			break;
1288178676Ssam	}
1289198429Srpaulo	if (ntries == 100)
1290220691Sbschmidt		return (ETIMEDOUT);
1291178676Ssam
1292178676Ssam	tmp = RT3070_RF_KICK | reg << 8;
1293206477Sbschmidt	if ((error = run_write(sc, RT3070_RF_CSR_CFG, tmp)) != 0)
1294178676Ssam		return (error);
1295178676Ssam
1296178676Ssam	for (ntries = 0; ntries < 100; ntries++) {
1297178676Ssam		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1298178676Ssam			return (error);
1299206477Sbschmidt		if (!(tmp & RT3070_RF_KICK))
1300201209Srpaulo			break;
1301201209Srpaulo	}
1302201209Srpaulo	if (ntries == 100)
1303220691Sbschmidt		return (ETIMEDOUT);
1304220691Sbschmidt
1305201209Srpaulo	*val = tmp & 0xff;
1306201209Srpaulo	return (0);
1307206477Sbschmidt}
1308201209Srpaulo
1309201209Srpaulostatic int
1310201209Srpaulorun_rt3070_rf_write(struct run_softc *sc, uint8_t reg, uint8_t val)
1311201209Srpaulo{
1312201209Srpaulo	uint32_t tmp;
1313206477Sbschmidt	int error, ntries;
1314178676Ssam
1315178676Ssam	for (ntries = 0; ntries < 10; ntries++) {
1316198429Srpaulo		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1317220728Sbschmidt			return (error);
1318178676Ssam		if (!(tmp & RT3070_RF_KICK))
1319178676Ssam			break;
1320206477Sbschmidt	}
1321178676Ssam	if (ntries == 10)
1322178676Ssam		return (ETIMEDOUT);
1323178676Ssam
1324178676Ssam	tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val;
1325178676Ssam	return (run_write(sc, RT3070_RF_CSR_CFG, tmp));
1326206477Sbschmidt}
1327178676Ssam
1328178676Ssamstatic int
1329198429Srpaulorun_bbp_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
1330178676Ssam{
1331178676Ssam	uint32_t tmp;
1332178676Ssam	int ntries, error;
1333178676Ssam
1334198429Srpaulo	for (ntries = 0; ntries < 10; ntries++) {
1335198429Srpaulo		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1336220691Sbschmidt			return (error);
1337220691Sbschmidt		if (!(tmp & RT2860_BBP_CSR_KICK))
1338178676Ssam			break;
1339178676Ssam	}
1340220711Sbschmidt	if (ntries == 10)
1341178676Ssam		return (ETIMEDOUT);
1342178676Ssam
1343178676Ssam	tmp = RT2860_BBP_CSR_READ | RT2860_BBP_CSR_KICK | reg << 8;
1344178676Ssam	if ((error = run_write(sc, RT2860_BBP_CSR_CFG, tmp)) != 0)
1345220702Sbschmidt		return (error);
1346220702Sbschmidt
1347220702Sbschmidt	for (ntries = 0; ntries < 10; ntries++) {
1348198429Srpaulo		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1349198429Srpaulo			return (error);
1350220711Sbschmidt		if (!(tmp & RT2860_BBP_CSR_KICK))
1351178676Ssam			break;
1352198429Srpaulo	}
1353198429Srpaulo	if (ntries == 10)
1354178676Ssam		return (ETIMEDOUT);
1355220702Sbschmidt
1356220702Sbschmidt	*val = tmp & 0xff;
1357220702Sbschmidt	return (0);
1358220702Sbschmidt}
1359220702Sbschmidt
1360198429Srpaulostatic int
1361198429Srpaulorun_bbp_write(struct run_softc *sc, uint8_t reg, uint8_t val)
1362220711Sbschmidt{
1363198429Srpaulo	uint32_t tmp;
1364198429Srpaulo	int ntries, error;
1365198429Srpaulo
1366198429Srpaulo	for (ntries = 0; ntries < 10; ntries++) {
1367178676Ssam		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1368198429Srpaulo			return (error);
1369178676Ssam		if (!(tmp & RT2860_BBP_CSR_KICK))
1370178676Ssam			break;
1371178676Ssam	}
1372178676Ssam	if (ntries == 10)
1373178676Ssam		return (ETIMEDOUT);
1374201209Srpaulo
1375178676Ssam	tmp = RT2860_BBP_CSR_KICK | reg << 8 | val;
1376178676Ssam	return (run_write(sc, RT2860_BBP_CSR_CFG, tmp));
1377220711Sbschmidt}
1378178676Ssam
1379178676Ssam/*
1380178676Ssam * Send a command to the 8051 microcontroller unit.
1381198429Srpaulo */
1382220692Sbschmidtstatic int
1383220692Sbschmidtrun_mcu_cmd(struct run_softc *sc, uint8_t cmd, uint16_t arg)
1384198439Srpaulo{
1385178676Ssam	uint32_t tmp;
1386220711Sbschmidt	int error, ntries;
1387220710Sbschmidt
1388178676Ssam	for (ntries = 0; ntries < 100; ntries++) {
1389178676Ssam		if ((error = run_read(sc, RT2860_H2M_MAILBOX, &tmp)) != 0)
1390198429Srpaulo			return error;
1391201209Srpaulo		if (!(tmp & RT2860_H2M_BUSY))
1392220692Sbschmidt			break;
1393220692Sbschmidt	}
1394178676Ssam	if (ntries == 100)
1395178676Ssam		return ETIMEDOUT;
1396220711Sbschmidt
1397220711Sbschmidt	tmp = RT2860_H2M_BUSY | RT2860_TOKEN_NO_INTR << 16 | arg;
1398178676Ssam	if ((error = run_write(sc, RT2860_H2M_MAILBOX, tmp)) == 0)
1399178676Ssam		error = run_write(sc, RT2860_HOST_CMD, cmd);
1400178676Ssam	return (error);
1401198429Srpaulo}
1402178676Ssam
1403178676Ssam/*
1404220726Sbschmidt * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word.
1405178676Ssam * Used to adjust per-rate Tx power registers.
1406178676Ssam */
1407220726Sbschmidtstatic __inline uint32_t
1408178676Ssamb4inc(uint32_t b32, int8_t delta)
1409220726Sbschmidt{
1410220726Sbschmidt	int8_t i, b4;
1411178676Ssam
1412178676Ssam	for (i = 0; i < 8; i++) {
1413178676Ssam		b4 = b32 & 0xf;
1414206477Sbschmidt		b4 += delta;
1415178676Ssam		if (b4 < 0)
1416178676Ssam			b4 = 0;
1417178676Ssam		else if (b4 > 0xf)
1418178676Ssam			b4 = 0xf;
1419198429Srpaulo		b32 = b32 >> 4 | b4 << 28;
1420198429Srpaulo	}
1421198429Srpaulo	return (b32);
1422198429Srpaulo}
1423198429Srpaulo
1424198429Srpaulostatic const char *
1425198429Srpaulorun_get_rf(int rev)
1426198429Srpaulo{
1427198429Srpaulo	switch (rev) {
1428198429Srpaulo	case RT2860_RF_2820:	return "RT2820";
1429178676Ssam	case RT2860_RF_2850:	return "RT2850";
1430198429Srpaulo	case RT2860_RF_2720:	return "RT2720";
1431178676Ssam	case RT2860_RF_2750:	return "RT2750";
1432178676Ssam	case RT3070_RF_3020:	return "RT3020";
1433206477Sbschmidt	case RT3070_RF_2020:	return "RT2020";
1434178676Ssam	case RT3070_RF_3021:	return "RT3021";
1435178676Ssam	case RT3070_RF_3022:	return "RT3022";
1436178676Ssam	case RT3070_RF_3052:	return "RT3052";
1437178676Ssam	}
1438178676Ssam	return ("unknown");
1439198429Srpaulo}
1440178676Ssam
1441198429Srpauloint
1442198429Srpaulorun_read_eeprom(struct run_softc *sc)
1443198429Srpaulo{
1444198429Srpaulo	int8_t delta_2ghz, delta_5ghz;
1445201209Srpaulo	uint32_t tmp;
1446198439Srpaulo	uint16_t val;
1447201209Srpaulo	int ridx, ant, i;
1448198429Srpaulo
1449220710Sbschmidt	/* check whether the ROM is eFUSE ROM or EEPROM */
1450198429Srpaulo	sc->sc_srom_read = run_eeprom_read_2;
1451201209Srpaulo	if (sc->mac_ver >= 0x3070) {
1452201209Srpaulo		run_read(sc, RT3070_EFUSE_CTRL, &tmp);
1453198429Srpaulo		DPRINTF("EFUSE_CTRL=0x%08x\n", tmp);
1454220701Sbschmidt		if (tmp & RT3070_SEL_EFUSE)
1455220701Sbschmidt			sc->sc_srom_read = run_efuse_read_2;
1456220701Sbschmidt	}
1457220701Sbschmidt
1458178676Ssam	/* read ROM version */
1459178676Ssam	run_srom_read(sc, RT2860_EEPROM_VERSION, &val);
1460206477Sbschmidt	DPRINTF("EEPROM rev=%d, FAE=%d\n", val & 0xff, val >> 8);
1461178676Ssam
1462178676Ssam	/* read MAC address */
1463220723Sbschmidt	run_srom_read(sc, RT2860_EEPROM_MAC01, &val);
1464178676Ssam	sc->sc_bssid[0] = val & 0xff;
1465178676Ssam	sc->sc_bssid[1] = val >> 8;
1466178676Ssam	run_srom_read(sc, RT2860_EEPROM_MAC23, &val);
1467178676Ssam	sc->sc_bssid[2] = val & 0xff;
1468178676Ssam	sc->sc_bssid[3] = val >> 8;
1469178676Ssam	run_srom_read(sc, RT2860_EEPROM_MAC45, &val);
1470178676Ssam	sc->sc_bssid[4] = val & 0xff;
1471220725Sbschmidt	sc->sc_bssid[5] = val >> 8;
1472220726Sbschmidt
1473220691Sbschmidt	/* read vender BBP settings */
1474220691Sbschmidt	for (i = 0; i < 10; i++) {
1475178676Ssam		run_srom_read(sc, RT2860_EEPROM_BBP_BASE + i, &val);
1476178676Ssam		sc->bbp[i].val = val & 0xff;
1477198429Srpaulo		sc->bbp[i].reg = val >> 8;
1478178676Ssam		DPRINTF("BBP%d=0x%02x\n", sc->bbp[i].reg, sc->bbp[i].val);
1479178676Ssam	}
1480178676Ssam	if (sc->mac_ver >= 0x3071) {
1481198429Srpaulo		/* read vendor RF settings */
1482220726Sbschmidt		for (i = 0; i < 10; i++) {
1483220691Sbschmidt			run_srom_read(sc, RT3071_EEPROM_RF_BASE + i, &val);
1484220691Sbschmidt			sc->rf[i].val = val & 0xff;
1485178676Ssam			sc->rf[i].reg = val >> 8;
1486178676Ssam			DPRINTF("RF%d=0x%02x\n", sc->rf[i].reg,
1487198429Srpaulo			    sc->rf[i].val);
1488178676Ssam		}
1489178676Ssam	}
1490178676Ssam
1491178676Ssam	/* read RF frequency offset from EEPROM */
1492198429Srpaulo	run_srom_read(sc, RT2860_EEPROM_FREQ_LEDS, &val);
1493220726Sbschmidt	sc->freq = ((val & 0xff) != 0xff) ? val & 0xff : 0;
1494220726Sbschmidt	DPRINTF("EEPROM freq offset %d\n", sc->freq & 0xff);
1495220726Sbschmidt
1496198429Srpaulo	if (val >> 8 != 0xff) {
1497198429Srpaulo		/* read LEDs operating mode */
1498220711Sbschmidt		sc->leds = val >> 8;
1499178676Ssam		run_srom_read(sc, RT2860_EEPROM_LED1, &sc->led[0]);
1500198429Srpaulo		run_srom_read(sc, RT2860_EEPROM_LED2, &sc->led[1]);
1501198429Srpaulo		run_srom_read(sc, RT2860_EEPROM_LED3, &sc->led[2]);
1502178676Ssam	} else {
1503198429Srpaulo		/* broken EEPROM, use default settings */
1504178676Ssam		sc->leds = 0x01;
1505178676Ssam		sc->led[0] = 0x5555;
1506178676Ssam		sc->led[1] = 0x2221;
1507198429Srpaulo		sc->led[2] = 0x5627;	/* differs from RT2860 */
1508198429Srpaulo	}
1509198429Srpaulo	DPRINTF("EEPROM LED mode=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n",
1510198429Srpaulo	    sc->leds, sc->led[0], sc->led[1], sc->led[2]);
1511201209Srpaulo
1512178676Ssam	/* read RF information */
1513178676Ssam	run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
1514220711Sbschmidt	if (val == 0xffff) {
1515178676Ssam		DPRINTF("invalid EEPROM antenna info, using default\n");
1516178676Ssam		if (sc->mac_ver == 0x3572) {
1517178676Ssam			/* default to RF3052 2T2R */
1518178676Ssam			sc->rf_rev = RT3070_RF_3052;
1519178676Ssam			sc->ntxchains = 2;
1520220726Sbschmidt			sc->nrxchains = 2;
1521220726Sbschmidt		} else if (sc->mac_ver >= 0x3070) {
1522178676Ssam			/* default to RF3020 1T1R */
1523178676Ssam			sc->rf_rev = RT3070_RF_3020;
1524178676Ssam			sc->ntxchains = 1;
1525206477Sbschmidt			sc->nrxchains = 1;
1526178676Ssam		} else {
1527178676Ssam			/* default to RF2820 1T2R */
1528198429Srpaulo			sc->rf_rev = RT2860_RF_2820;
1529178676Ssam			sc->ntxchains = 1;
1530178676Ssam			sc->nrxchains = 2;
1531178676Ssam		}
1532178676Ssam	} else {
1533178676Ssam		sc->rf_rev = (val >> 8) & 0xf;
1534220704Sbschmidt		sc->ntxchains = (val >> 4) & 0xf;
1535220704Sbschmidt		sc->nrxchains = val & 0xf;
1536201209Srpaulo	}
1537178676Ssam	DPRINTF("EEPROM RF rev=0x%02x chains=%dT%dR\n",
1538178676Ssam	    sc->rf_rev, sc->ntxchains, sc->nrxchains);
1539178676Ssam
1540178676Ssam	/* check if RF supports automatic Tx access gain control */
1541198429Srpaulo	run_srom_read(sc, RT2860_EEPROM_CONFIG, &val);
1542198429Srpaulo	DPRINTF("EEPROM CFG 0x%04x\n", val);
1543198439Srpaulo	/* check if driver should patch the DAC issue */
1544198439Srpaulo	if ((val >> 8) != 0xff)
1545198429Srpaulo		sc->patch_dac = (val >> 15) & 1;
1546178676Ssam	if ((val & 0xff) != 0xff) {
1547178676Ssam		sc->ext_5ghz_lna = (val >> 3) & 1;
1548178676Ssam		sc->ext_2ghz_lna = (val >> 2) & 1;
1549178676Ssam		/* check if RF supports automatic Tx access gain control */
1550206477Sbschmidt		sc->calib_2ghz = sc->calib_5ghz = (val >> 1) & 1;
1551178676Ssam		/* check if we have a hardware radio switch */
1552178676Ssam		sc->rfswitch = val & 1;
1553178676Ssam	}
1554178676Ssam
1555178676Ssam	/* read power settings for 2GHz channels */
1556178676Ssam	for (i = 0; i < 14; i += 2) {
1557178676Ssam		run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE1 + i / 2, &val);
1558201209Srpaulo		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
1559201209Srpaulo		sc->txpow1[i + 1] = (int8_t)(val >> 8);
1560178676Ssam
1561201209Srpaulo		run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2, &val);
1562201209Srpaulo		sc->txpow2[i + 0] = (int8_t)(val & 0xff);
1563201209Srpaulo		sc->txpow2[i + 1] = (int8_t)(val >> 8);
1564201209Srpaulo	}
1565201209Srpaulo	/* fix broken Tx power entries */
1566178676Ssam	for (i = 0; i < 14; i++) {
1567201209Srpaulo		if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31)
1568201209Srpaulo			sc->txpow1[i] = 5;
1569178676Ssam		if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31)
1570220701Sbschmidt			sc->txpow2[i] = 5;
1571220701Sbschmidt		DPRINTF("chan %d: power1=%d, power2=%d\n",
1572220701Sbschmidt		    rt2860_rf2850[i].chan, sc->txpow1[i], sc->txpow2[i]);
1573220701Sbschmidt	}
1574178676Ssam	/* read power settings for 5GHz channels */
1575178676Ssam	for (i = 0; i < 40; i += 2) {
1576206477Sbschmidt		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
1577201209Srpaulo		sc->txpow1[i + 14] = (int8_t)(val & 0xff);
1578201209Srpaulo		sc->txpow1[i + 15] = (int8_t)(val >> 8);
1579201209Srpaulo
1580201209Srpaulo		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
1581201209Srpaulo		sc->txpow2[i + 14] = (int8_t)(val & 0xff);
1582201209Srpaulo		sc->txpow2[i + 15] = (int8_t)(val >> 8);
1583201209Srpaulo	}
1584201209Srpaulo	/* fix broken Tx power entries */
1585201209Srpaulo	for (i = 0; i < 40; i++) {
1586220725Sbschmidt		if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15)
1587201209Srpaulo			sc->txpow1[14 + i] = 5;
1588201209Srpaulo		if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15)
1589201209Srpaulo			sc->txpow2[14 + i] = 5;
1590201209Srpaulo		DPRINTF("chan %d: power1=%d, power2=%d\n",
1591201209Srpaulo		    rt2860_rf2850[14 + i].chan, sc->txpow1[14 + i],
1592201209Srpaulo		    sc->txpow2[14 + i]);
1593201209Srpaulo	}
1594201209Srpaulo
1595201209Srpaulo	/* read Tx power compensation for each Tx rate */
1596201209Srpaulo	run_srom_read(sc, RT2860_EEPROM_DELTAPWR, &val);
1597201209Srpaulo	delta_2ghz = delta_5ghz = 0;
1598201209Srpaulo	if ((val & 0xff) != 0xff && (val & 0x80)) {
1599201209Srpaulo		delta_2ghz = val & 0xf;
1600201209Srpaulo		if (!(val & 0x40))	/* negative number */
1601206477Sbschmidt			delta_2ghz = -delta_2ghz;
1602198429Srpaulo	}
1603178676Ssam	val >>= 8;
1604220728Sbschmidt	if ((val & 0xff) != 0xff && (val & 0x80)) {
1605220723Sbschmidt		delta_5ghz = val & 0xf;
1606198429Srpaulo		if (!(val & 0x40))	/* negative number */
1607178676Ssam			delta_5ghz = -delta_5ghz;
1608198429Srpaulo	}
1609198429Srpaulo	DPRINTF("power compensation=%d (2GHz), %d (5GHz)\n",
1610198429Srpaulo	    delta_2ghz, delta_5ghz);
1611198429Srpaulo
1612198429Srpaulo	for (ridx = 0; ridx < 5; ridx++) {
1613198429Srpaulo		uint32_t reg;
1614178676Ssam
1615201209Srpaulo		run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2, &val);
1616220726Sbschmidt		reg = val;
1617201209Srpaulo		run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2 + 1, &val);
1618220726Sbschmidt		reg |= (uint32_t)val << 16;
1619220726Sbschmidt
1620201209Srpaulo		sc->txpow20mhz[ridx] = reg;
1621201209Srpaulo		sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz);
1622201209Srpaulo		sc->txpow40mhz_5ghz[ridx] = b4inc(reg, delta_5ghz);
1623198429Srpaulo
1624198429Srpaulo		DPRINTF("ridx %d: power 20MHz=0x%08x, 40MHz/2GHz=0x%08x, "
1625198429Srpaulo		    "40MHz/5GHz=0x%08x\n", ridx, sc->txpow20mhz[ridx],
1626198429Srpaulo		    sc->txpow40mhz_2ghz[ridx], sc->txpow40mhz_5ghz[ridx]);
1627220726Sbschmidt	}
1628220726Sbschmidt
1629198429Srpaulo	/* read RSSI offsets and LNA gains from EEPROM */
1630198429Srpaulo	run_srom_read(sc, RT2860_EEPROM_RSSI1_2GHZ, &val);
1631198429Srpaulo	sc->rssi_2ghz[0] = val & 0xff;	/* Ant A */
1632201209Srpaulo	sc->rssi_2ghz[1] = val >> 8;	/* Ant B */
1633220726Sbschmidt	run_srom_read(sc, RT2860_EEPROM_RSSI2_2GHZ, &val);
1634201209Srpaulo	if (sc->mac_ver >= 0x3070) {
1635201209Srpaulo		/*
1636201209Srpaulo		 * On RT3070 chips (limited to 2 Rx chains), this ROM
1637201209Srpaulo		 * field contains the Tx mixer gain for the 2GHz band.
1638201209Srpaulo		 */
1639198429Srpaulo		if ((val & 0xff) != 0xff)
1640178676Ssam			sc->txmixgain_2ghz = val & 0x7;
1641220729Sbschmidt		DPRINTF("tx mixer gain=%u (2GHz)\n", sc->txmixgain_2ghz);
1642220729Sbschmidt	} else
1643220729Sbschmidt		sc->rssi_2ghz[2] = val & 0xff;	/* Ant C */
1644220729Sbschmidt	sc->lna[2] = val >> 8;		/* channel group 2 */
1645220729Sbschmidt
1646220729Sbschmidt	run_srom_read(sc, RT2860_EEPROM_RSSI1_5GHZ, &val);
1647198429Srpaulo	sc->rssi_5ghz[0] = val & 0xff;	/* Ant A */
1648198429Srpaulo	sc->rssi_5ghz[1] = val >> 8;	/* Ant B */
1649198429Srpaulo	run_srom_read(sc, RT2860_EEPROM_RSSI2_5GHZ, &val);
1650220727Sbschmidt	if (sc->mac_ver == 0x3572) {
1651220727Sbschmidt		/*
1652220727Sbschmidt		 * On RT3572 chips (limited to 2 Rx chains), this ROM
1653220727Sbschmidt		 * field contains the Tx mixer gain for the 5GHz band.
1654220727Sbschmidt		 */
1655178676Ssam		if ((val & 0xff) != 0xff)
1656198429Srpaulo			sc->txmixgain_5ghz = val & 0x7;
1657198429Srpaulo		DPRINTF("tx mixer gain=%u (5GHz)\n", sc->txmixgain_5ghz);
1658178676Ssam	} else
1659198429Srpaulo		sc->rssi_5ghz[2] = val & 0xff;	/* Ant C */
1660220728Sbschmidt	sc->lna[3] = val >> 8;		/* channel group 3 */
1661178676Ssam
1662201209Srpaulo	run_srom_read(sc, RT2860_EEPROM_LNA, &val);
1663201209Srpaulo	sc->lna[0] = val & 0xff;	/* channel group 0 */
1664198429Srpaulo	sc->lna[1] = val >> 8;		/* channel group 1 */
1665198429Srpaulo
1666178676Ssam	/* fix broken 5GHz LNA entries */
1667178676Ssam	if (sc->lna[2] == 0 || sc->lna[2] == 0xff) {
1668206477Sbschmidt		DPRINTF("invalid LNA for channel group %d\n", 2);
1669198429Srpaulo		sc->lna[2] = sc->lna[1];
1670178676Ssam	}
1671201209Srpaulo	if (sc->lna[3] == 0 || sc->lna[3] == 0xff) {
1672220723Sbschmidt		DPRINTF("invalid LNA for channel group %d\n", 3);
1673198429Srpaulo		sc->lna[3] = sc->lna[1];
1674178676Ssam	}
1675220725Sbschmidt
1676198429Srpaulo	/* fix broken RSSI offset entries */
1677178676Ssam	for (ant = 0; ant < 3; ant++) {
1678220725Sbschmidt		if (sc->rssi_2ghz[ant] < -10 || sc->rssi_2ghz[ant] > 10) {
1679221636Sbschmidt			DPRINTF("invalid RSSI%d offset: %d (2GHz)\n",
1680201209Srpaulo			    ant + 1, sc->rssi_2ghz[ant]);
1681201209Srpaulo			sc->rssi_2ghz[ant] = 0;
1682201209Srpaulo		}
1683198429Srpaulo		if (sc->rssi_5ghz[ant] < -10 || sc->rssi_5ghz[ant] > 10) {
1684198429Srpaulo			DPRINTF("invalid RSSI%d offset: %d (5GHz)\n",
1685198429Srpaulo			    ant + 1, sc->rssi_5ghz[ant]);
1686198429Srpaulo			sc->rssi_5ghz[ant] = 0;
1687198429Srpaulo		}
1688198429Srpaulo	}
1689198429Srpaulo	return (0);
1690198429Srpaulo}
1691198429Srpaulo
1692198429Srpaulostatic struct ieee80211_node *
1693198429Srpaulorun_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
1694198429Srpaulo{
1695198429Srpaulo	return malloc(sizeof (struct run_node), M_DEVBUF, M_NOWAIT | M_ZERO);
1696198429Srpaulo}
1697198429Srpaulo
1698198429Srpaulostatic int
1699198429Srpaulorun_media_change(struct ifnet *ifp)
1700198429Srpaulo{
1701198429Srpaulo	struct ieee80211vap *vap = ifp->if_softc;
1702198429Srpaulo	struct ieee80211com *ic = vap->iv_ic;
1703198429Srpaulo	const struct ieee80211_txparam *tp;
1704198429Srpaulo	struct run_softc *sc = ic->ic_ifp->if_softc;
1705198429Srpaulo	uint8_t rate, ridx;
1706198429Srpaulo	int error;
1707198429Srpaulo
1708201209Srpaulo	RUN_LOCK(sc);
1709198429Srpaulo
1710198429Srpaulo	error = ieee80211_media_change(ifp);
1711178676Ssam	if (error != ENETRESET) {
1712198429Srpaulo		RUN_UNLOCK(sc);
1713178676Ssam		return (error);
1714178676Ssam	}
1715198429Srpaulo
1716206477Sbschmidt	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
1717198429Srpaulo	if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
1718178676Ssam		struct ieee80211_node *ni;
1719198429Srpaulo		struct run_node	*rn;
1720198429Srpaulo
1721198429Srpaulo		rate = ic->ic_sup_rates[ic->ic_curmode].
1722178676Ssam		    rs_rates[tp->ucastrate] & IEEE80211_RATE_VAL;
1723198429Srpaulo		for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
1724198429Srpaulo			if (rt2860_rates[ridx].rate == rate)
1725198429Srpaulo				break;
1726198429Srpaulo		ni = ieee80211_ref_node(vap->iv_bss);
1727198429Srpaulo		rn = (struct run_node *)ni;
1728198429Srpaulo		rn->fix_ridx = ridx;
1729198429Srpaulo		DPRINTF("rate=%d, fix_ridx=%d\n", rate, rn->fix_ridx);
1730198429Srpaulo		ieee80211_free_node(ni);
1731198429Srpaulo	}
1732198429Srpaulo
1733198429Srpaulo#if 0
1734198429Srpaulo	if ((ifp->if_flags & IFF_UP) &&
1735198429Srpaulo	    (ifp->if_drv_flags &  IFF_DRV_RUNNING)){
1736198429Srpaulo		run_init_locked(sc);
1737198429Srpaulo	}
1738198429Srpaulo#endif
1739198429Srpaulo
1740198429Srpaulo	RUN_UNLOCK(sc);
1741198429Srpaulo
1742198429Srpaulo	return (0);
1743198429Srpaulo}
1744198429Srpaulo
1745198429Srpaulostatic int
1746198429Srpaulorun_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
1747178676Ssam{
1748198429Srpaulo	const struct ieee80211_txparam *tp;
1749178676Ssam	struct ieee80211com *ic = vap->iv_ic;
1750206477Sbschmidt	struct run_softc *sc = ic->ic_ifp->if_softc;
1751198429Srpaulo	struct run_vap *rvp = RUN_VAP(vap);
1752178676Ssam	enum ieee80211_state ostate;
1753206444Sbschmidt	uint32_t sta[3];
1754220674Sbschmidt	uint32_t tmp;
1755220723Sbschmidt	uint8_t ratectl;
1756220723Sbschmidt	uint8_t restart_ratectl = 0;
1757198429Srpaulo	uint8_t bid = 1 << rvp->rvp_id;
1758178676Ssam
1759220725Sbschmidt	ostate = vap->iv_state;
1760198429Srpaulo	DPRINTF("%s -> %s\n",
1761198429Srpaulo		ieee80211_state_name[ostate],
1762198429Srpaulo		ieee80211_state_name[nstate]);
1763198429Srpaulo
1764178676Ssam	IEEE80211_UNLOCK(ic);
1765220725Sbschmidt	RUN_LOCK(sc);
1766221636Sbschmidt
1767221635Sbschmidt	ratectl = sc->ratectl_run; /* remember current state */
1768221635Sbschmidt	sc->ratectl_run = RUN_RATECTL_OFF;
1769221635Sbschmidt	usb_callout_stop(&sc->ratectl_ch);
1770221635Sbschmidt
1771201209Srpaulo	if (ostate == IEEE80211_S_RUN) {
1772198429Srpaulo		/* turn link LED off */
1773178676Ssam		run_set_leds(sc, RT2860_LED_RADIO);
1774201209Srpaulo	}
1775201209Srpaulo
1776201209Srpaulo	switch (nstate) {
1777201209Srpaulo	case IEEE80211_S_INIT:
1778198429Srpaulo		restart_ratectl = 1;
1779198429Srpaulo
1780206444Sbschmidt		if (ostate != IEEE80211_S_RUN)
1781206444Sbschmidt			break;
1782220726Sbschmidt
1783220726Sbschmidt		ratectl &= ~bid;
1784210108Sbschmidt		sc->runbmap &= ~bid;
1785206444Sbschmidt
1786198429Srpaulo		/* abort TSF synchronization if there is no vap running */
1787201209Srpaulo		if (--sc->running == 0) {
1788198429Srpaulo			run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
1789220674Sbschmidt			run_write(sc, RT2860_BCN_TIME_CFG,
1790198429Srpaulo			    tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
1791198429Srpaulo			    RT2860_TBTT_TIMER_EN));
1792220674Sbschmidt		}
1793201209Srpaulo		break;
1794220674Sbschmidt
1795220674Sbschmidt	case IEEE80211_S_RUN:
1796220674Sbschmidt		if (!(sc->runbmap & bid)) {
1797220674Sbschmidt			if(sc->running++)
1798220674Sbschmidt				restart_ratectl = 1;
1799220674Sbschmidt			sc->runbmap |= bid;
1800220674Sbschmidt		}
1801178676Ssam
1802178676Ssam		m_freem(rvp->beacon_mbuf);
1803178676Ssam		rvp->beacon_mbuf = NULL;
1804201209Srpaulo
1805201209Srpaulo		switch (vap->iv_opmode) {
1806201209Srpaulo		case IEEE80211_M_HOSTAP:
1807201209Srpaulo		case IEEE80211_M_MBSS:
1808201209Srpaulo			sc->ap_running |= bid;
1809201209Srpaulo			ic->ic_opmode = vap->iv_opmode;
1810201209Srpaulo			run_update_beacon_cb(vap);
1811201209Srpaulo			break;
1812201209Srpaulo		case IEEE80211_M_IBSS:
1813201209Srpaulo			sc->adhoc_running |= bid;
1814201209Srpaulo			if (!sc->ap_running)
1815201209Srpaulo				ic->ic_opmode = vap->iv_opmode;
1816201209Srpaulo			run_update_beacon_cb(vap);
1817201209Srpaulo			break;
1818201209Srpaulo		case IEEE80211_M_STA:
1819201209Srpaulo			sc->sta_running |= bid;
1820201209Srpaulo			if (!sc->ap_running && !sc->adhoc_running)
1821201209Srpaulo				ic->ic_opmode = vap->iv_opmode;
1822201209Srpaulo
1823201209Srpaulo			/* read statistic counters (clear on read) */
1824201209Srpaulo			run_read_region_1(sc, RT2860_TX_STA_CNT0,
1825201209Srpaulo			    (uint8_t *)sta, sizeof sta);
1826198429Srpaulo
1827201209Srpaulo			break;
1828178676Ssam		default:
1829198429Srpaulo			ic->ic_opmode = vap->iv_opmode;
1830198429Srpaulo			break;
1831201209Srpaulo		}
1832201209Srpaulo
1833198429Srpaulo		if (vap->iv_opmode != IEEE80211_M_MONITOR) {
1834220687Sbschmidt			struct ieee80211_node *ni;
1835220687Sbschmidt
1836178676Ssam			if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) {
1837198429Srpaulo				RUN_UNLOCK(sc);
1838198429Srpaulo				IEEE80211_LOCK(ic);
1839198429Srpaulo				return (-1);
1840198429Srpaulo			}
1841198429Srpaulo			run_updateslot(ic->ic_ifp);
1842198429Srpaulo			run_enable_mrr(sc);
1843198429Srpaulo			run_set_txpreamble(sc);
1844198429Srpaulo			run_set_basicrates(sc);
1845198429Srpaulo			ni = ieee80211_ref_node(vap->iv_bss);
1846201209Srpaulo			IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid);
1847178676Ssam			run_set_bssid(sc, ni->ni_bssid);
1848198429Srpaulo			ieee80211_free_node(ni);
1849198429Srpaulo			run_enable_tsf_sync(sc);
1850198429Srpaulo
1851198429Srpaulo			/* enable automatic rate adaptation */
1852206445Sbschmidt			tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
1853201209Srpaulo			if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
1854220726Sbschmidt				ratectl |= bid;
1855198429Srpaulo		}
1856198429Srpaulo
1857198429Srpaulo		/* turn link LED on */
1858198429Srpaulo		run_set_leds(sc, RT2860_LED_RADIO |
1859198429Srpaulo		    (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ?
1860198429Srpaulo		     RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ));
1861220726Sbschmidt
1862198429Srpaulo		break;
1863178676Ssam	default:
1864220723Sbschmidt		DPRINTFN(6, "undefined case\n");
1865220723Sbschmidt		break;
1866220723Sbschmidt	}
1867220723Sbschmidt
1868220723Sbschmidt	/* restart amrr for running VAPs */
1869220726Sbschmidt	if ((sc->ratectl_run = ratectl) && restart_ratectl)
1870220726Sbschmidt		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
1871220723Sbschmidt
1872221636Sbschmidt	RUN_UNLOCK(sc);
1873221636Sbschmidt	IEEE80211_LOCK(ic);
1874221636Sbschmidt
1875221636Sbschmidt	return(rvp->newstate(vap, nstate, arg));
1876221636Sbschmidt}
1877221636Sbschmidt
1878178676Ssam/* ARGSUSED */
1879178676Ssamstatic void
1880178676Ssamrun_wme_update_cb(void *arg)
1881198429Srpaulo{
1882201209Srpaulo	struct ieee80211com *ic = arg;
1883178676Ssam	struct run_softc *sc = ic->ic_ifp->if_softc;
1884198429Srpaulo	struct ieee80211_wme_state *wmesp = &ic->ic_wme;
1885198429Srpaulo	int aci, error = 0;
1886201209Srpaulo
1887201209Srpaulo	RUN_LOCK_ASSERT(sc, MA_OWNED);
1888198429Srpaulo
1889221636Sbschmidt	/* update MAC TX configuration registers */
1890221636Sbschmidt	for (aci = 0; aci < WME_NUM_AC; aci++) {
1891178676Ssam		error = run_write(sc, RT2860_EDCA_AC_CFG(aci),
1892221636Sbschmidt		    wmesp->wme_params[aci].wmep_logcwmax << 16 |
1893221636Sbschmidt		    wmesp->wme_params[aci].wmep_logcwmin << 12 |
1894221636Sbschmidt		    wmesp->wme_params[aci].wmep_aifsn  <<  8 |
1895198429Srpaulo		    wmesp->wme_params[aci].wmep_txopLimit);
1896221636Sbschmidt		if (error) goto err;
1897198429Srpaulo	}
1898198429Srpaulo
1899198429Srpaulo	/* update SCH/DMA registers too */
1900198429Srpaulo	error = run_write(sc, RT2860_WMM_AIFSN_CFG,
1901198429Srpaulo	    wmesp->wme_params[WME_AC_VO].wmep_aifsn  << 12 |
1902198429Srpaulo	    wmesp->wme_params[WME_AC_VI].wmep_aifsn  <<  8 |
1903221636Sbschmidt	    wmesp->wme_params[WME_AC_BK].wmep_aifsn  <<  4 |
1904221636Sbschmidt	    wmesp->wme_params[WME_AC_BE].wmep_aifsn);
1905221636Sbschmidt	if (error) goto err;
1906198429Srpaulo	error = run_write(sc, RT2860_WMM_CWMIN_CFG,
1907198429Srpaulo	    wmesp->wme_params[WME_AC_VO].wmep_logcwmin << 12 |
1908198429Srpaulo	    wmesp->wme_params[WME_AC_VI].wmep_logcwmin <<  8 |
1909198429Srpaulo	    wmesp->wme_params[WME_AC_BK].wmep_logcwmin <<  4 |
1910221636Sbschmidt	    wmesp->wme_params[WME_AC_BE].wmep_logcwmin);
1911221636Sbschmidt	if (error) goto err;
1912198429Srpaulo	error = run_write(sc, RT2860_WMM_CWMAX_CFG,
1913198429Srpaulo	    wmesp->wme_params[WME_AC_VO].wmep_logcwmax << 12 |
1914221636Sbschmidt	    wmesp->wme_params[WME_AC_VI].wmep_logcwmax <<  8 |
1915198429Srpaulo	    wmesp->wme_params[WME_AC_BK].wmep_logcwmax <<  4 |
1916198429Srpaulo	    wmesp->wme_params[WME_AC_BE].wmep_logcwmax);
1917198429Srpaulo	if (error) goto err;
1918221636Sbschmidt	error = run_write(sc, RT2860_WMM_TXOP0_CFG,
1919198429Srpaulo	    wmesp->wme_params[WME_AC_BK].wmep_txopLimit << 16 |
1920198429Srpaulo	    wmesp->wme_params[WME_AC_BE].wmep_txopLimit);
1921221636Sbschmidt	if (error) goto err;
1922221636Sbschmidt	error = run_write(sc, RT2860_WMM_TXOP1_CFG,
1923198429Srpaulo	    wmesp->wme_params[WME_AC_VO].wmep_txopLimit << 16 |
1924198429Srpaulo	    wmesp->wme_params[WME_AC_VI].wmep_txopLimit);
1925178676Ssam
1926198429Srpauloerr:
1927198429Srpaulo	if (error)
1928221636Sbschmidt		DPRINTF("WME update failed\n");
1929178676Ssam
1930198429Srpaulo	return;
1931198429Srpaulo}
1932198429Srpaulo
1933198429Srpaulostatic int
1934221636Sbschmidtrun_wme_update(struct ieee80211com *ic)
1935198429Srpaulo{
1936198429Srpaulo	struct run_softc *sc = ic->ic_ifp->if_softc;
1937198429Srpaulo
1938198429Srpaulo	/* sometime called wothout lock */
1939221636Sbschmidt	if (mtx_owned(&ic->ic_comlock.mtx)) {
1940178676Ssam		uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
1941198429Srpaulo		DPRINTF("cmdq_store=%d\n", i);
1942178676Ssam		sc->cmdq[i].func = run_wme_update_cb;
1943198429Srpaulo		sc->cmdq[i].arg0 = ic;
1944201209Srpaulo		ieee80211_runtask(ic, &sc->cmdq_task);
1945198429Srpaulo		return (0);
1946198429Srpaulo	}
1947198429Srpaulo
1948178676Ssam	RUN_LOCK(sc);
1949201209Srpaulo	run_wme_update_cb(ic);
1950201209Srpaulo	RUN_UNLOCK(sc);
1951201209Srpaulo
1952198429Srpaulo	/* return whatever, upper layer desn't care anyway */
1953201209Srpaulo	return (0);
1954198429Srpaulo}
1955201209Srpaulo
1956198429Srpaulostatic void
1957178676Ssamrun_key_update_begin(struct ieee80211vap *vap)
1958178676Ssam{
1959220723Sbschmidt	/*
1960220723Sbschmidt	 * To avoid out-of-order events, both run_key_set() and
1961220723Sbschmidt	 * _delete() are deferred and handled by run_cmdq_cb().
1962221636Sbschmidt	 * So, there is nothing we need to do here.
1963220723Sbschmidt	 */
1964221636Sbschmidt}
1965221636Sbschmidt
1966221636Sbschmidtstatic void
1967221636Sbschmidtrun_key_update_end(struct ieee80211vap *vap)
1968221636Sbschmidt{
1969221636Sbschmidt	/* null */
1970221636Sbschmidt}
1971221636Sbschmidt
1972221636Sbschmidtstatic void
1973220723Sbschmidtrun_key_set_cb(void *arg)
1974221636Sbschmidt{
1975221636Sbschmidt	struct run_cmdq *cmdq = arg;
1976221636Sbschmidt	struct ieee80211vap *vap = cmdq->arg1;
1977221636Sbschmidt	struct ieee80211_key *k = cmdq->k;
1978221636Sbschmidt	struct ieee80211com *ic = vap->iv_ic;
1979221636Sbschmidt	struct run_softc *sc = ic->ic_ifp->if_softc;
1980221636Sbschmidt	struct ieee80211_node *ni;
1981220723Sbschmidt	uint32_t attr;
1982220723Sbschmidt	uint16_t base, associd;
1983220723Sbschmidt	uint8_t mode, wcid, iv[8];
1984220723Sbschmidt
1985220723Sbschmidt	RUN_LOCK_ASSERT(sc, MA_OWNED);
1986220723Sbschmidt
1987220723Sbschmidt	if (vap->iv_opmode == IEEE80211_M_HOSTAP)
1988220723Sbschmidt		ni = ieee80211_find_vap_node(&ic->ic_sta, vap, cmdq->mac);
1989220723Sbschmidt	else
1990220723Sbschmidt		ni = vap->iv_bss;
1991220723Sbschmidt	associd = (ni != NULL) ? ni->ni_associd : 0;
1992220723Sbschmidt
1993220723Sbschmidt	/* map net80211 cipher to RT2860 security mode */
1994220723Sbschmidt	switch (k->wk_cipher->ic_cipher) {
1995220723Sbschmidt	case IEEE80211_CIPHER_WEP:
1996220723Sbschmidt		if(k->wk_keylen < 8)
1997220723Sbschmidt			mode = RT2860_MODE_WEP40;
1998220723Sbschmidt		else
1999220723Sbschmidt			mode = RT2860_MODE_WEP104;
2000220723Sbschmidt		break;
2001220723Sbschmidt	case IEEE80211_CIPHER_TKIP:
2002220723Sbschmidt		mode = RT2860_MODE_TKIP;
2003220723Sbschmidt		break;
2004220723Sbschmidt	case IEEE80211_CIPHER_AES_CCM:
2005220723Sbschmidt		mode = RT2860_MODE_AES_CCMP;
2006220723Sbschmidt		break;
2007220723Sbschmidt	default:
2008220723Sbschmidt		DPRINTF("undefined case\n");
2009220723Sbschmidt		return;
2010220723Sbschmidt	}
2011220723Sbschmidt
2012201209Srpaulo	DPRINTFN(1, "associd=%x, keyix=%d, mode=%x, type=%s, tx=%s, rx=%s\n",
2013201209Srpaulo	    associd, k->wk_keyix, mode,
2014206477Sbschmidt	    (k->wk_flags & IEEE80211_KEY_GROUP) ? "group" : "pairwise",
2015201209Srpaulo	    (k->wk_flags & IEEE80211_KEY_XMIT) ? "on" : "off",
2016201209Srpaulo	    (k->wk_flags & IEEE80211_KEY_RECV) ? "on" : "off");
2017201209Srpaulo
2018221637Sbschmidt	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2019221637Sbschmidt		wcid = 0;	/* NB: update WCID0 for group keys */
2020221637Sbschmidt		base = RT2860_SKEY(RUN_VAP(vap)->rvp_id, k->wk_keyix);
2021201209Srpaulo	} else {
2022201209Srpaulo		wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
2023221637Sbschmidt		    1 : RUN_AID2WCID(associd);
2024221637Sbschmidt		base = RT2860_PKEY(wcid);
2025201209Srpaulo	}
2026201209Srpaulo
2027201209Srpaulo	if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) {
2028201209Srpaulo		if(run_write_region_1(sc, base, k->wk_key, 16))
2029201209Srpaulo			return;
2030201209Srpaulo		if(run_write_region_1(sc, base + 16, &k->wk_key[16], 8))	/* wk_txmic */
2031201209Srpaulo			return;
2032221637Sbschmidt		if(run_write_region_1(sc, base + 24, &k->wk_key[24], 8))	/* wk_rxmic */
2033221637Sbschmidt			return;
2034201209Srpaulo	} else {
2035201209Srpaulo		/* roundup len to 16-bit: XXX fix write_region_1() instead */
2036201209Srpaulo		if(run_write_region_1(sc, base, k->wk_key, (k->wk_keylen + 1) & ~1))
2037201209Srpaulo			return;
2038201209Srpaulo	}
2039201209Srpaulo
2040201209Srpaulo	if (!(k->wk_flags & IEEE80211_KEY_GROUP) ||
2041201209Srpaulo	    (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))) {
2042201209Srpaulo		/* set initial packet number in IV+EIV */
2043201209Srpaulo		if (k->wk_cipher == IEEE80211_CIPHER_WEP) {
2044201209Srpaulo			memset(iv, 0, sizeof iv);
2045201209Srpaulo			iv[3] = vap->iv_def_txkey << 6;
2046201209Srpaulo		} else {
2047201209Srpaulo			if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) {
2048221637Sbschmidt				iv[0] = k->wk_keytsc >> 8;
2049221637Sbschmidt				iv[1] = (iv[0] | 0x20) & 0x7f;
2050221637Sbschmidt				iv[2] = k->wk_keytsc;
2051221637Sbschmidt			} else /* CCMP */ {
2052221637Sbschmidt				iv[0] = k->wk_keytsc;
2053221637Sbschmidt				iv[1] = k->wk_keytsc >> 8;
2054221637Sbschmidt				iv[2] = 0;
2055221637Sbschmidt			}
2056221637Sbschmidt			iv[3] = k->wk_keyix << 6 | IEEE80211_WEP_EXTIV;
2057221637Sbschmidt			iv[4] = k->wk_keytsc >> 16;
2058221637Sbschmidt			iv[5] = k->wk_keytsc >> 24;
2059221637Sbschmidt			iv[6] = k->wk_keytsc >> 32;
2060221637Sbschmidt			iv[7] = k->wk_keytsc >> 40;
2061221637Sbschmidt		}
2062221637Sbschmidt		if (run_write_region_1(sc, RT2860_IVEIV(wcid), iv, 8))
2063221637Sbschmidt			return;
2064221637Sbschmidt	}
2065221637Sbschmidt
2066221637Sbschmidt	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2067221637Sbschmidt		/* install group key */
2068221637Sbschmidt		if (run_read(sc, RT2860_SKEY_MODE_0_7, &attr))
2069221637Sbschmidt			return;
2070221637Sbschmidt		attr &= ~(0xf << (k->wk_keyix * 4));
2071221637Sbschmidt		attr |= mode << (k->wk_keyix * 4);
2072221637Sbschmidt		if (run_write(sc, RT2860_SKEY_MODE_0_7, attr))
2073221637Sbschmidt			return;
2074221637Sbschmidt	} else {
2075201209Srpaulo		/* install pairwise key */
2076201209Srpaulo		if (run_read(sc, RT2860_WCID_ATTR(wcid), &attr))
2077201209Srpaulo			return;
2078206477Sbschmidt		attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN;
2079198429Srpaulo		if (run_write(sc, RT2860_WCID_ATTR(wcid), attr))
2080178676Ssam			return;
2081198429Srpaulo	}
2082198429Srpaulo
2083178676Ssam	/* TODO create a pass-thru key entry? */
2084221648Sbschmidt
2085221648Sbschmidt	/* need wcid to delete the right key later */
2086221648Sbschmidt	k->wk_pad = wcid;
2087221648Sbschmidt}
2088221648Sbschmidt
2089221648Sbschmidt/*
2090221648Sbschmidt * Don't have to be deferred, but in order to keep order of
2091221648Sbschmidt * execution, i.e. with run_key_delete(), defer this and let
2092221648Sbschmidt * run_cmdq_cb() maintain the order.
2093221648Sbschmidt *
2094221648Sbschmidt * return 0 on error
2095221648Sbschmidt */
2096221648Sbschmidtstatic int
2097221648Sbschmidtrun_key_set(struct ieee80211vap *vap, struct ieee80211_key *k,
2098221648Sbschmidt		const uint8_t mac[IEEE80211_ADDR_LEN])
2099221648Sbschmidt{
2100221648Sbschmidt	struct ieee80211com *ic = vap->iv_ic;
2101221648Sbschmidt	struct run_softc *sc = ic->ic_ifp->if_softc;
2102221648Sbschmidt	uint32_t i;
2103221648Sbschmidt
2104220715Sbschmidt	i = RUN_CMDQ_GET(&sc->cmdq_store);
2105220715Sbschmidt	DPRINTF("cmdq_store=%d\n", i);
2106220715Sbschmidt	sc->cmdq[i].func = run_key_set_cb;
2107221648Sbschmidt	sc->cmdq[i].arg0 = NULL;
2108221648Sbschmidt	sc->cmdq[i].arg1 = vap;
2109220715Sbschmidt	sc->cmdq[i].k = k;
2110221649Sbschmidt	IEEE80211_ADDR_COPY(sc->cmdq[i].mac, mac);
2111221648Sbschmidt	ieee80211_runtask(ic, &sc->cmdq_task);
2112220715Sbschmidt
2113221648Sbschmidt	/*
2114221649Sbschmidt	 * To make sure key will be set when hostapd
2115221649Sbschmidt	 * calls iv_key_set() before if_init().
2116221648Sbschmidt	 */
2117221649Sbschmidt	if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
2118221649Sbschmidt		RUN_LOCK(sc);
2119221649Sbschmidt		sc->cmdq_key_set = RUN_CMDQ_GO;
2120221649Sbschmidt		RUN_UNLOCK(sc);
2121221649Sbschmidt	}
2122221649Sbschmidt
2123221649Sbschmidt	return (1);
2124221649Sbschmidt}
2125221649Sbschmidt
2126221649Sbschmidt/*
2127221649Sbschmidt * If wlan is destroyed without being brought down i.e. without
2128221649Sbschmidt * wlan down or wpa_cli terminate, this function is called after
2129221649Sbschmidt * vap is gone. Don't refer it.
2130221649Sbschmidt */
2131221649Sbschmidtstatic void
2132221649Sbschmidtrun_key_delete_cb(void *arg)
2133221649Sbschmidt{
2134221649Sbschmidt	struct run_cmdq *cmdq = arg;
2135221649Sbschmidt	struct run_softc *sc = cmdq->arg1;
2136221649Sbschmidt	struct ieee80211_key *k = &cmdq->key;
2137221649Sbschmidt	uint32_t attr;
2138221649Sbschmidt	uint8_t wcid;
2139221649Sbschmidt
2140221649Sbschmidt	RUN_LOCK_ASSERT(sc, MA_OWNED);
2141221649Sbschmidt
2142221648Sbschmidt	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2143221649Sbschmidt		/* remove group key */
2144221649Sbschmidt		DPRINTF("removing group key\n");
2145221649Sbschmidt		run_read(sc, RT2860_SKEY_MODE_0_7, &attr);
2146221649Sbschmidt		attr &= ~(0xf << (k->wk_keyix * 4));
2147221649Sbschmidt		run_write(sc, RT2860_SKEY_MODE_0_7, attr);
2148221649Sbschmidt	} else {
2149221649Sbschmidt		/* remove pairwise key */
2150221649Sbschmidt		DPRINTF("removing key for wcid %x\n", k->wk_pad);
2151220715Sbschmidt		/* matching wcid was written to wk_pad in run_key_set() */
2152220715Sbschmidt		wcid = k->wk_pad;
2153220715Sbschmidt		run_read(sc, RT2860_WCID_ATTR(wcid), &attr);
2154206477Sbschmidt		attr &= ~0xf;
2155198429Srpaulo		run_write(sc, RT2860_WCID_ATTR(wcid), attr);
2156178676Ssam		run_set_region_4(sc, RT2860_WCID_ENTRY(wcid), 0, 8);
2157220726Sbschmidt	}
2158220726Sbschmidt
2159220726Sbschmidt	k->wk_pad = 0;
2160198429Srpaulo}
2161198429Srpaulo
2162198429Srpaulo/*
2163178676Ssam * return 0 on error
2164206477Sbschmidt */
2165198429Srpaulostatic int
2166198429Srpaulorun_key_delete(struct ieee80211vap *vap, struct ieee80211_key *k)
2167198429Srpaulo{
2168198429Srpaulo	struct ieee80211com *ic = vap->iv_ic;
2169198429Srpaulo	struct run_softc *sc = ic->ic_ifp->if_softc;
2170220688Sbschmidt	struct ieee80211_key *k0;
2171178676Ssam	uint32_t i;
2172198429Srpaulo
2173220726Sbschmidt	/*
2174178676Ssam	 * When called back, key might be gone. So, make a copy
2175198429Srpaulo	 * of some values need to delete keys before deferring.
2176198429Srpaulo	 * But, because of LOR with node lock, cannot use lock here.
2177220667Sbschmidt	 * So, use atomic instead.
2178178676Ssam	 */
2179210114Sbschmidt	i = RUN_CMDQ_GET(&sc->cmdq_store);
2180210114Sbschmidt	DPRINTF("cmdq_store=%d\n", i);
2181210114Sbschmidt	sc->cmdq[i].func = run_key_delete_cb;
2182210114Sbschmidt	sc->cmdq[i].arg0 = NULL;
2183210114Sbschmidt	sc->cmdq[i].arg1 = sc;
2184210114Sbschmidt	k0 = &sc->cmdq[i].key;
2185210114Sbschmidt	k0->wk_flags = k->wk_flags;
2186210114Sbschmidt	k0->wk_keyix = k->wk_keyix;
2187210114Sbschmidt	/* matching wcid was written to wk_pad in run_key_set() */
2188210114Sbschmidt	k0->wk_pad = k->wk_pad;
2189210114Sbschmidt	ieee80211_runtask(ic, &sc->cmdq_task);
2190210114Sbschmidt	return (1);	/* return fake success */
2191210114Sbschmidt
2192198439Srpaulo}
2193198439Srpaulo
2194220667Sbschmidtstatic void
2195220667Sbschmidtrun_ratectl_to(void *arg)
2196220688Sbschmidt{
2197220688Sbschmidt	struct run_softc *sc = arg;
2198220688Sbschmidt
2199220688Sbschmidt	/* do it in a process context, so it can go sleep */
2200210114Sbschmidt	ieee80211_runtask(sc->sc_ifp->if_l2com, &sc->ratectl_task);
2201210114Sbschmidt	/* next timeout will be rescheduled in the callback task */
2202210114Sbschmidt}
2203198429Srpaulo
2204210114Sbschmidt/* ARGSUSED */
2205210114Sbschmidtstatic void
2206220667Sbschmidtrun_ratectl_cb(void *arg, int pending)
2207220667Sbschmidt{
2208210114Sbschmidt	struct run_softc *sc = arg;
2209210114Sbschmidt	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
2210210114Sbschmidt	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
2211210114Sbschmidt
2212198429Srpaulo	if (vap == NULL)
2213198429Srpaulo		return;
2214198429Srpaulo
2215198429Srpaulo	if (sc->rvp_cnt <= 1 && vap->iv_opmode == IEEE80211_M_STA)
2216220688Sbschmidt		run_iter_func(sc, vap->iv_bss);
2217220688Sbschmidt	else {
2218220688Sbschmidt		/*
2219220688Sbschmidt		 * run_reset_livelock() doesn't do anything with AMRR,
2220210114Sbschmidt		 * but Ralink wants us to call it every 1 sec. So, we
2221210114Sbschmidt		 * piggyback here rather than creating another callout.
2222220667Sbschmidt		 * Livelock may occur only in HOSTAP or IBSS mode
2223220667Sbschmidt		 * (when h/w is sending beacons).
2224220667Sbschmidt		 */
2225220667Sbschmidt		RUN_LOCK(sc);
2226210114Sbschmidt		run_reset_livelock(sc);
2227210114Sbschmidt		/* just in case, there are some stats to drain */
2228178676Ssam		run_drain_fifo(sc);
2229198429Srpaulo		RUN_UNLOCK(sc);
2230198429Srpaulo		ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, sc);
2231220688Sbschmidt	}
2232220688Sbschmidt
2233198429Srpaulo	if(sc->ratectl_run != RUN_RATECTL_OFF)
2234178676Ssam		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2235178676Ssam}
2236220667Sbschmidt
2237220667Sbschmidtstatic void
2238220667Sbschmidtrun_drain_fifo(void *arg)
2239220667Sbschmidt{
2240220667Sbschmidt	struct run_softc *sc = arg;
2241220667Sbschmidt	struct ifnet *ifp = sc->sc_ifp;
2242220667Sbschmidt	uint32_t stat;
2243220667Sbschmidt	uint16_t (*wstat)[3];
2244220667Sbschmidt	uint8_t wcid, mcs, pid;
2245220667Sbschmidt	int8_t retry;
2246220667Sbschmidt
2247220667Sbschmidt	RUN_LOCK_ASSERT(sc, MA_OWNED);
2248220667Sbschmidt
2249220667Sbschmidt	for (;;) {
2250220667Sbschmidt		/* drain Tx status FIFO (maxsize = 16) */
2251220667Sbschmidt		run_read(sc, RT2860_TX_STAT_FIFO, &stat);
2252220667Sbschmidt		DPRINTFN(4, "tx stat 0x%08x\n", stat);
2253220667Sbschmidt		if (!(stat & RT2860_TXQ_VLD))
2254220667Sbschmidt			break;
2255220667Sbschmidt
2256220667Sbschmidt		wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff;
2257198429Srpaulo
2258198429Srpaulo		/* if no ACK was requested, no feedback is available */
2259198429Srpaulo		if (!(stat & RT2860_TXQ_ACKREQ) || wcid > RT2870_WCID_MAX ||
2260198429Srpaulo		    wcid == 0)
2261206477Sbschmidt			continue;
2262198429Srpaulo
2263198429Srpaulo		/*
2264178676Ssam		 * Even though each stat is Tx-complete-status like format,
2265198429Srpaulo		 * the device can poll stats. Because there is no guarantee
2266198429Srpaulo		 * that the referring node is still around when read the stats.
2267198429Srpaulo		 * So that, if we use ieee80211_ratectl_tx_update(), we will
2268202986Srpaulo		 * have hard time not to refer already freed node.
2269198429Srpaulo		 *
2270198429Srpaulo		 * To eliminate such page faults, we poll stats in softc.
2271198429Srpaulo		 * Then, update the rates later with ieee80211_ratectl_tx_update().
2272198429Srpaulo		 */
2273178676Ssam		wstat = &(sc->wcid_stats[wcid]);
2274178676Ssam		(*wstat)[RUN_TXCNT]++;
2275198429Srpaulo		if (stat & RT2860_TXQ_OK)
2276198429Srpaulo			(*wstat)[RUN_SUCCESS]++;
2277198429Srpaulo		else
2278198429Srpaulo			ifp->if_oerrors++;
2279206477Sbschmidt		/*
2280198429Srpaulo		 * Check if there were retries, ie if the Tx success rate is
2281178676Ssam		 * different from the requested rate. Note that it works only
2282178676Ssam		 * because we do not allow rate fallback from OFDM to CCK.
2283220728Sbschmidt		 */
2284178676Ssam		mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f;
2285178676Ssam		pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf;
2286178676Ssam		if ((retry = pid -1 - mcs) > 0) {
2287178676Ssam			(*wstat)[RUN_TXCNT] += retry;
2288178676Ssam			(*wstat)[RUN_RETRY] += retry;
2289198429Srpaulo		}
2290178676Ssam	}
2291178676Ssam	DPRINTFN(3, "count=%d\n", sc->fifo_cnt);
2292178676Ssam
2293198429Srpaulo	sc->fifo_cnt = 0;
2294198429Srpaulo}
2295178676Ssam
2296198429Srpaulostatic void
2297198429Srpaulorun_iter_func(void *arg, struct ieee80211_node *ni)
2298178676Ssam{
2299178676Ssam	struct run_softc *sc = arg;
2300201209Srpaulo	struct ieee80211vap *vap = ni->ni_vap;
2301178676Ssam	struct ieee80211com *ic = ni->ni_ic;
2302178676Ssam	struct ifnet *ifp = ic->ic_ifp;
2303178676Ssam	struct run_node *rn = (void *)ni;
2304178676Ssam	union run_stats sta[2];
2305178676Ssam	uint16_t (*wstat)[3];
2306178676Ssam	int txcnt, success, retrycnt, error;
2307201209Srpaulo
2308198439Srpaulo	RUN_LOCK(sc);
2309178676Ssam
2310178676Ssam	if (sc->rvp_cnt <= 1 && (vap->iv_opmode == IEEE80211_M_IBSS ||
2311220724Sbschmidt	    vap->iv_opmode == IEEE80211_M_STA)) {
2312220724Sbschmidt		/* read statistic counters (clear on read) and update AMRR state */
2313178676Ssam		error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta,
2314178676Ssam		    sizeof sta);
2315198429Srpaulo		if (error != 0)
2316198429Srpaulo			goto fail;
2317198429Srpaulo
2318198429Srpaulo		/* count failed TX as errors */
2319178676Ssam		ifp->if_oerrors += le16toh(sta[0].error.fail);
2320178676Ssam
2321178676Ssam		retrycnt = le16toh(sta[1].tx.retry);
2322178676Ssam		success = le16toh(sta[1].tx.success);
2323178676Ssam		txcnt = retrycnt + success + le16toh(sta[0].error.fail);
2324198429Srpaulo
2325198429Srpaulo		DPRINTFN(3, "retrycnt=%d success=%d failcnt=%d\n",
2326198429Srpaulo			retrycnt, success, le16toh(sta[0].error.fail));
2327198429Srpaulo	} else {
2328220724Sbschmidt		wstat = &(sc->wcid_stats[RUN_AID2WCID(ni->ni_associd)]);
2329198429Srpaulo
2330178676Ssam		if (wstat == &(sc->wcid_stats[0]) ||
2331178676Ssam		    wstat > &(sc->wcid_stats[RT2870_WCID_MAX]))
2332178676Ssam			goto fail;
2333198429Srpaulo
2334198429Srpaulo		txcnt = (*wstat)[RUN_TXCNT];
2335178676Ssam		success = (*wstat)[RUN_SUCCESS];
2336178676Ssam		retrycnt = (*wstat)[RUN_RETRY];
2337178676Ssam		DPRINTFN(3, "retrycnt=%d txcnt=%d success=%d\n",
2338178676Ssam		    retrycnt, txcnt, success);
2339178676Ssam
2340178676Ssam		memset(wstat, 0, sizeof(*wstat));
2341220692Sbschmidt	}
2342198429Srpaulo
2343178676Ssam	ieee80211_ratectl_tx_update(vap, ni, &txcnt, &success, &retrycnt);
2344178676Ssam	rn->amrr_ridx = ieee80211_ratectl_rate(ni, NULL, 0);
2345178676Ssam
2346178676Ssamfail:
2347178676Ssam	RUN_UNLOCK(sc);
2348201209Srpaulo
2349201209Srpaulo	DPRINTFN(3, "ridx=%d\n", rn->amrr_ridx);
2350220692Sbschmidt}
2351220692Sbschmidt
2352178676Ssamstatic void
2353178676Ssamrun_newassoc_cb(void *arg)
2354178676Ssam{
2355198429Srpaulo	struct run_cmdq *cmdq = arg;
2356220693Sbschmidt	struct ieee80211_node *ni = cmdq->arg1;
2357220693Sbschmidt	struct run_softc *sc = ni->ni_vap->iv_ic->ic_ifp->if_softc;
2358220693Sbschmidt	uint8_t wcid = cmdq->wcid;
2359220693Sbschmidt
2360220693Sbschmidt	RUN_LOCK_ASSERT(sc, MA_OWNED);
2361220693Sbschmidt
2362220693Sbschmidt	run_write_region_1(sc, RT2860_WCID_ENTRY(wcid),
2363220693Sbschmidt	    ni->ni_macaddr, IEEE80211_ADDR_LEN);
2364220693Sbschmidt
2365220693Sbschmidt	memset(&(sc->wcid_stats[wcid]), 0, sizeof(sc->wcid_stats[wcid]));
2366220693Sbschmidt}
2367220693Sbschmidt
2368178676Ssamstatic void
2369178676Ssamrun_newassoc(struct ieee80211_node *ni, int isnew)
2370178676Ssam{
2371178676Ssam	struct run_node *rn = (void *)ni;
2372178676Ssam	struct ieee80211_rateset *rs = &ni->ni_rates;
2373198429Srpaulo	struct ieee80211vap *vap = ni->ni_vap;
2374198429Srpaulo	struct ieee80211com *ic = vap->iv_ic;
2375198429Srpaulo	struct run_softc *sc = ic->ic_ifp->if_softc;
2376201209Srpaulo	uint8_t rate;
2377201209Srpaulo	uint8_t ridx;
2378198429Srpaulo	uint8_t wcid;
2379198429Srpaulo	int i, j;
2380178676Ssam
2381178676Ssam	wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
2382178676Ssam	    1 : RUN_AID2WCID(ni->ni_associd);
2383178676Ssam
2384198429Srpaulo	if (wcid > RT2870_WCID_MAX) {
2385178676Ssam		device_printf(sc->sc_dev, "wcid=%d out of range\n", wcid);
2386178676Ssam		return;
2387178676Ssam	}
2388178676Ssam
2389178676Ssam	/* only interested in true associations */
2390220728Sbschmidt	if (isnew && ni->ni_associd != 0) {
2391220689Sbschmidt
2392192468Ssam		/*
2393178676Ssam		 * This function could is called though timeout function.
2394178676Ssam		 * Need to defer.
2395178676Ssam		 */
2396201209Srpaulo		uint32_t cnt = RUN_CMDQ_GET(&sc->cmdq_store);
2397192468Ssam		DPRINTF("cmdq_store=%d\n", cnt);
2398220723Sbschmidt		sc->cmdq[cnt].func = run_newassoc_cb;
2399220723Sbschmidt		sc->cmdq[cnt].arg0 = NULL;
2400220723Sbschmidt		sc->cmdq[cnt].arg1 = ni;
2401201209Srpaulo		sc->cmdq[cnt].wcid = wcid;
2402201209Srpaulo		ieee80211_runtask(ic, &sc->cmdq_task);
2403201209Srpaulo	}
2404201209Srpaulo
2405201209Srpaulo	DPRINTF("new assoc isnew=%d associd=%x addr=%s\n",
2406201209Srpaulo	    isnew, ni->ni_associd, ether_sprintf(ni->ni_macaddr));
2407201209Srpaulo
2408201209Srpaulo	for (i = 0; i < rs->rs_nrates; i++) {
2409201209Srpaulo		rate = rs->rs_rates[i] & IEEE80211_RATE_VAL;
2410201209Srpaulo		/* convert 802.11 rate to hardware rate index */
2411201209Srpaulo		for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2412201209Srpaulo			if (rt2860_rates[ridx].rate == rate)
2413201209Srpaulo				break;
2414201209Srpaulo		rn->ridx[i] = ridx;
2415201209Srpaulo		/* determine rate of control response frames */
2416201209Srpaulo		for (j = i; j >= 0; j--) {
2417201209Srpaulo			if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) &&
2418201209Srpaulo			    rt2860_rates[rn->ridx[i]].phy ==
2419178676Ssam			    rt2860_rates[rn->ridx[j]].phy)
2420178676Ssam				break;
2421178676Ssam		}
2422178676Ssam		if (j >= 0) {
2423198429Srpaulo			rn->ctl_ridx[i] = rn->ridx[j];
2424178676Ssam		} else {
2425221650Sbschmidt			/* no basic rate found, use mandatory one */
2426221650Sbschmidt			rn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx;
2427220726Sbschmidt		}
2428198429Srpaulo		DPRINTF("rate=0x%02x ridx=%d ctl_ridx=%d\n",
2429178676Ssam		    rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]);
2430178676Ssam	}
2431220726Sbschmidt	rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate;
2432178676Ssam	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2433178676Ssam		if (rt2860_rates[ridx].rate == rate)
2434178676Ssam			break;
2435178676Ssam	rn->mgt_ridx = ridx;
2436201209Srpaulo	DPRINTF("rate=%d, mgmt_ridx=%d\n", rate, rn->mgt_ridx);
2437206477Sbschmidt
2438201209Srpaulo	usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2439201209Srpaulo}
2440201209Srpaulo
2441221651Sbschmidt/*
2442221651Sbschmidt * Return the Rx chain with the highest RSSI for a given frame.
2443221651Sbschmidt */
2444201209Srpaulostatic __inline uint8_t
2445201209Srpaulorun_maxrssi_chain(struct run_softc *sc, const struct rt2860_rxwi *rxwi)
2446221651Sbschmidt{
2447221651Sbschmidt	uint8_t rxchain = 0;
2448221651Sbschmidt
2449221651Sbschmidt	if (sc->nrxchains > 1) {
2450201209Srpaulo		if (rxwi->rssi[1] > rxwi->rssi[rxchain])
2451220704Sbschmidt			rxchain = 1;
2452220704Sbschmidt		if (sc->nrxchains > 2)
2453221651Sbschmidt			if (rxwi->rssi[2] > rxwi->rssi[rxchain])
2454221651Sbschmidt				rxchain = 2;
2455221651Sbschmidt	}
2456221651Sbschmidt	return (rxchain);
2457221651Sbschmidt}
2458221651Sbschmidt
2459221651Sbschmidtstatic void
2460221651Sbschmidtrun_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen)
2461221651Sbschmidt{
2462221651Sbschmidt	struct ifnet *ifp = sc->sc_ifp;
2463221651Sbschmidt	struct ieee80211com *ic = ifp->if_l2com;
2464221651Sbschmidt	struct ieee80211_frame *wh;
2465221651Sbschmidt	struct ieee80211_node *ni;
2466221651Sbschmidt	struct rt2870_rxd *rxd;
2467221651Sbschmidt	struct rt2860_rxwi *rxwi;
2468221651Sbschmidt	uint32_t flags;
2469221651Sbschmidt	uint16_t len, phy;
2470221651Sbschmidt	uint8_t ant, rssi;
2471221651Sbschmidt	int8_t nf;
2472221651Sbschmidt
2473221651Sbschmidt	rxwi = mtod(m, struct rt2860_rxwi *);
2474221651Sbschmidt	len = le16toh(rxwi->len) & 0xfff;
2475221651Sbschmidt	if (__predict_false(len > dmalen)) {
2476221651Sbschmidt		m_freem(m);
2477221651Sbschmidt		ifp->if_ierrors++;
2478221651Sbschmidt		DPRINTF("bad RXWI length %u > %u\n", len, dmalen);
2479221651Sbschmidt		return;
2480221651Sbschmidt	}
2481221651Sbschmidt	/* Rx descriptor is located at the end */
2482201209Srpaulo	rxd = (struct rt2870_rxd *)(mtod(m, caddr_t) + dmalen);
2483201209Srpaulo	flags = le32toh(rxd->flags);
2484198429Srpaulo
2485220674Sbschmidt	if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) {
2486220674Sbschmidt		m_freem(m);
2487220674Sbschmidt		ifp->if_ierrors++;
2488220674Sbschmidt		DPRINTF("%s error.\n", (flags & RT2860_RX_CRCERR)?"CRC":"ICV");
2489220674Sbschmidt		return;
2490220674Sbschmidt	}
2491220674Sbschmidt
2492220674Sbschmidt	m->m_data += sizeof(struct rt2860_rxwi);
2493220674Sbschmidt	m->m_pkthdr.len = m->m_len -= sizeof(struct rt2860_rxwi);
2494220674Sbschmidt
2495220674Sbschmidt	wh = mtod(m, struct ieee80211_frame *);
2496220674Sbschmidt
2497220674Sbschmidt	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
2498220674Sbschmidt		wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
2499220674Sbschmidt		m->m_flags |= M_WEP;
2500220674Sbschmidt	}
2501220674Sbschmidt
2502220674Sbschmidt	if (flags & RT2860_RX_L2PAD) {
2503220674Sbschmidt		DPRINTFN(8, "received RT2860_RX_L2PAD frame\n");
2504220867Sbschmidt		len += 2;
2505220867Sbschmidt	}
2506220867Sbschmidt
2507220674Sbschmidt	ni = ieee80211_find_rxnode(ic,
2508220674Sbschmidt	    mtod(m, struct ieee80211_frame_min *));
2509220674Sbschmidt
2510220674Sbschmidt	if (__predict_false(flags & RT2860_RX_MICERR)) {
2511220674Sbschmidt		/* report MIC failures to net80211 for TKIP */
2512220674Sbschmidt		if (ni != NULL)
2513220674Sbschmidt			ieee80211_notify_michael_failure(ni->ni_vap, wh, rxwi->keyidx);
2514220674Sbschmidt		m_freem(m);
2515220674Sbschmidt		ifp->if_ierrors++;
2516220674Sbschmidt		DPRINTF("MIC error. Someone is lying.\n");
2517220674Sbschmidt		return;
2518220674Sbschmidt	}
2519220674Sbschmidt
2520220674Sbschmidt	ant = run_maxrssi_chain(sc, rxwi);
2521220674Sbschmidt	rssi = rxwi->rssi[ant];
2522220674Sbschmidt	nf = run_rssi2dbm(sc, rssi, ant);
2523220674Sbschmidt
2524220674Sbschmidt	m->m_pkthdr.rcvif = ifp;
2525220674Sbschmidt	m->m_pkthdr.len = m->m_len = len;
2526220674Sbschmidt
2527220674Sbschmidt	if (ni != NULL) {
2528220674Sbschmidt		(void)ieee80211_input(ni, m, rssi, nf);
2529220674Sbschmidt		ieee80211_free_node(ni);
2530220674Sbschmidt	} else {
2531220674Sbschmidt		(void)ieee80211_input_all(ic, m, rssi, nf);
2532220674Sbschmidt	}
2533220674Sbschmidt
2534220674Sbschmidt	if (__predict_false(ieee80211_radiotap_active(ic))) {
2535220674Sbschmidt		struct run_rx_radiotap_header *tap = &sc->sc_rxtap;
2536220674Sbschmidt
2537220674Sbschmidt		tap->wr_flags = 0;
2538220674Sbschmidt		tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
2539220674Sbschmidt		tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
2540220674Sbschmidt		tap->wr_antsignal = rssi;
2541220674Sbschmidt		tap->wr_antenna = ant;
2542220674Sbschmidt		tap->wr_dbm_antsignal = run_rssi2dbm(sc, rssi, ant);
2543220674Sbschmidt		tap->wr_rate = 2;	/* in case it can't be found below */
2544198429Srpaulo		phy = le16toh(rxwi->phy);
2545198429Srpaulo		switch (phy & RT2860_PHY_MODE) {
2546198429Srpaulo		case RT2860_PHY_CCK:
2547206477Sbschmidt			switch ((phy & RT2860_PHY_MCS) & ~RT2860_PHY_SHPRE) {
2548198429Srpaulo			case 0:	tap->wr_rate =   2; break;
2549198429Srpaulo			case 1:	tap->wr_rate =   4; break;
2550198429Srpaulo			case 2:	tap->wr_rate =  11; break;
2551220728Sbschmidt			case 3:	tap->wr_rate =  22; break;
2552178676Ssam			}
2553178676Ssam			if (phy & RT2860_PHY_SHPRE)
2554178676Ssam				tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
2555178676Ssam			break;
2556178676Ssam		case RT2860_PHY_OFDM:
2557198429Srpaulo			switch (phy & RT2860_PHY_MCS) {
2558178676Ssam			case 0:	tap->wr_rate =  12; break;
2559220725Sbschmidt			case 1:	tap->wr_rate =  18; break;
2560178676Ssam			case 2:	tap->wr_rate =  24; break;
2561178676Ssam			case 3:	tap->wr_rate =  36; break;
2562178676Ssam			case 4:	tap->wr_rate =  48; break;
2563178676Ssam			case 5:	tap->wr_rate =  72; break;
2564202986Srpaulo			case 6:	tap->wr_rate =  96; break;
2565220724Sbschmidt			case 7:	tap->wr_rate = 108; break;
2566220724Sbschmidt			}
2567220724Sbschmidt			break;
2568220667Sbschmidt		}
2569178676Ssam	}
2570198429Srpaulo}
2571178676Ssam
2572198429Srpaulostatic void
2573178676Ssamrun_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error)
2574220728Sbschmidt{
2575178676Ssam	struct run_softc *sc = usbd_xfer_softc(xfer);
2576178676Ssam	struct ifnet *ifp = sc->sc_ifp;
2577178676Ssam	struct mbuf *m = NULL;
2578220725Sbschmidt	struct mbuf *m0;
2579198429Srpaulo	uint32_t dmalen;
2580198429Srpaulo	int xferlen;
2581178676Ssam
2582178676Ssam	usbd_xfer_status(xfer, &xferlen, NULL, NULL, NULL);
2583178676Ssam
2584198429Srpaulo	switch (USB_GET_STATE(xfer)) {
2585178676Ssam	case USB_ST_TRANSFERRED:
2586178676Ssam
2587178676Ssam		DPRINTFN(15, "rx done, actlen=%d\n", xferlen);
2588178676Ssam
2589198429Srpaulo		if (xferlen < (int)(sizeof(uint32_t) +
2590198429Srpaulo		    sizeof(struct rt2860_rxwi) + sizeof(struct rt2870_rxd))) {
2591178676Ssam			DPRINTF("xfer too short %d\n", xferlen);
2592178676Ssam			goto tr_setup;
2593178676Ssam		}
2594178676Ssam
2595178676Ssam		m = sc->rx_m;
2596178676Ssam		sc->rx_m = NULL;
2597198429Srpaulo
2598178676Ssam		/* FALLTHROUGH */
2599178676Ssam	case USB_ST_SETUP:
2600178676Ssamtr_setup:
2601178676Ssam		if (sc->rx_m == NULL) {
2602198429Srpaulo			sc->rx_m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR,
2603198429Srpaulo			    MJUMPAGESIZE /* xfer can be bigger than MCLBYTES */);
2604198429Srpaulo		}
2605198429Srpaulo		if (sc->rx_m == NULL) {
2606206477Sbschmidt			DPRINTF("could not allocate mbuf - idle with stall\n");
2607198429Srpaulo			ifp->if_ierrors++;
2608198429Srpaulo			usbd_xfer_set_stall(xfer);
2609178676Ssam			usbd_xfer_set_frames(xfer, 0);
2610198429Srpaulo		} else {
2611221651Sbschmidt			/*
2612221651Sbschmidt			 * Directly loading a mbuf cluster into DMA to
2613198429Srpaulo			 * save some data copying. This works because
2614221651Sbschmidt			 * there is only one cluster.
2615221651Sbschmidt			 */
2616221651Sbschmidt			usbd_xfer_set_frame_data(xfer, 0,
2617198429Srpaulo			    mtod(sc->rx_m, caddr_t), RUN_MAX_RXSZ);
2618198429Srpaulo			usbd_xfer_set_frames(xfer, 1);
2619201209Srpaulo		}
2620201209Srpaulo		usbd_transfer_submit(xfer);
2621198429Srpaulo		break;
2622201209Srpaulo
2623207001Sbschmidt	default:	/* Error */
2624221651Sbschmidt		if (error != USB_ERR_CANCELLED) {
2625221651Sbschmidt			/* try to clear stall first */
2626221651Sbschmidt			usbd_xfer_set_stall(xfer);
2627221651Sbschmidt
2628221651Sbschmidt			if (error == USB_ERR_TIMEOUT)
2629221651Sbschmidt				device_printf(sc->sc_dev, "device timeout\n");
2630221651Sbschmidt
2631198429Srpaulo			ifp->if_ierrors++;
2632198429Srpaulo
2633206477Sbschmidt			goto tr_setup;
2634198429Srpaulo		}
2635198429Srpaulo		if (sc->rx_m != NULL) {
2636198429Srpaulo			m_freem(sc->rx_m);
2637198429Srpaulo			sc->rx_m = NULL;
2638221651Sbschmidt		}
2639221651Sbschmidt		break;
2640198429Srpaulo	}
2641221651Sbschmidt
2642221651Sbschmidt	if (m == NULL)
2643221651Sbschmidt		return;
2644198429Srpaulo
2645198429Srpaulo	/* inputting all the frames must be last */
2646201209Srpaulo
2647201209Srpaulo	RUN_UNLOCK(sc);
2648198429Srpaulo
2649198429Srpaulo	m->m_pkthdr.len = m->m_len = xferlen;
2650201209Srpaulo
2651198429Srpaulo	/* HW can aggregate multiple 802.11 frames in a single USB xfer */
2652198429Srpaulo	for(;;) {
2653201209Srpaulo		dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff;
2654202986Srpaulo
2655207001Sbschmidt		if ((dmalen >= (uint32_t)-8) || (dmalen == 0) ||
2656221651Sbschmidt		    ((dmalen & 3) != 0)) {
2657221651Sbschmidt			DPRINTF("bad DMA length %u\n", dmalen);
2658221651Sbschmidt			break;
2659221651Sbschmidt		}
2660221651Sbschmidt		if ((dmalen + 8) > (uint32_t)xferlen) {
2661221651Sbschmidt			DPRINTF("bad DMA length %u > %d\n",
2662221651Sbschmidt			dmalen + 8, xferlen);
2663198429Srpaulo			break;
2664198429Srpaulo		}
2665198429Srpaulo
2666198429Srpaulo		/* If it is the last one or a single frame, we won't copy. */
2667198429Srpaulo		if ((xferlen -= dmalen + 8) <= 8) {
2668206477Sbschmidt			/* trim 32-bit DMA-len header */
2669201209Srpaulo			m->m_data += 4;
2670198429Srpaulo			m->m_pkthdr.len = m->m_len -= 4;
2671198429Srpaulo			run_rx_frame(sc, m, dmalen);
2672178676Ssam			break;
2673178676Ssam		}
2674178676Ssam
2675178676Ssam		/* copy aggregated frames to another mbuf */
2676178676Ssam		m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
2677206358Srpaulo		if (__predict_false(m0 == NULL)) {
2678178676Ssam			DPRINTF("could not allocate mbuf\n");
2679178676Ssam			ifp->if_ierrors++;
2680178676Ssam			break;
2681198429Srpaulo		}
2682201209Srpaulo		m_copydata(m, 4 /* skip 32-bit DMA-len header */,
2683201209Srpaulo		    dmalen + sizeof(struct rt2870_rxd), mtod(m0, caddr_t));
2684178676Ssam		m0->m_pkthdr.len = m0->m_len =
2685178676Ssam		    dmalen + sizeof(struct rt2870_rxd);
2686206358Srpaulo		run_rx_frame(sc, m0, dmalen);
2687178676Ssam
2688178676Ssam		/* update data ptr */
2689178676Ssam		m->m_data += dmalen + 8;
2690178676Ssam		m->m_pkthdr.len = m->m_len -= dmalen + 8;
2691178676Ssam	}
2692178676Ssam
2693178676Ssam	RUN_LOCK(sc);
2694178676Ssam}
2695178676Ssam
2696178676Ssamstatic void
2697178676Ssamrun_tx_free(struct run_endpoint_queue *pq,
2698178676Ssam    struct run_tx_data *data, int txerr)
2699178676Ssam{
2700178676Ssam	if (data->m != NULL) {
2701178676Ssam		if (data->m->m_flags & M_TXCB)
2702178676Ssam			ieee80211_process_callback(data->ni, data->m,
2703178676Ssam			    txerr ? ETIMEDOUT : 0);
2704178676Ssam		m_freem(data->m);
2705178676Ssam		data->m = NULL;
2706178676Ssam
2707178676Ssam		if (data->ni == NULL) {
2708178676Ssam			DPRINTF("no node\n");
2709178676Ssam		} else {
2710201209Srpaulo			ieee80211_free_node(data->ni);
2711201209Srpaulo			data->ni = NULL;
2712201209Srpaulo		}
2713201209Srpaulo	}
2714220719Sbschmidt
2715201209Srpaulo	STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
2716206358Srpaulo	pq->tx_nfree++;
2717206358Srpaulo}
2718201209Srpaulo
2719220719Sbschmidtstatic void
2720206358Srpaulorun_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, unsigned int index)
2721206358Srpaulo{
2722201209Srpaulo	struct run_softc *sc = usbd_xfer_softc(xfer);
2723178676Ssam	struct ifnet *ifp = sc->sc_ifp;
2724178676Ssam	struct ieee80211com *ic = ifp->if_l2com;
2725178676Ssam	struct run_tx_data *data;
2726178676Ssam	struct ieee80211vap *vap = NULL;
2727198429Srpaulo	struct usb_page_cache *pc;
2728198429Srpaulo	struct run_endpoint_queue *pq = &sc->sc_epq[index];
2729198429Srpaulo	struct mbuf *m;
2730198429Srpaulo	usb_frlength_t size;
2731198429Srpaulo	int actlen;
2732198429Srpaulo	int sumlen;
2733198429Srpaulo
2734198429Srpaulo	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
2735178676Ssam
2736178676Ssam	switch (USB_GET_STATE(xfer)) {
2737198429Srpaulo	case USB_ST_TRANSFERRED:
2738198429Srpaulo		DPRINTFN(11, "transfer complete: %d "
2739198429Srpaulo		    "bytes @ index %d\n", actlen, index);
2740198429Srpaulo
2741206477Sbschmidt		data = usbd_xfer_get_priv(xfer);
2742198429Srpaulo
2743178676Ssam		run_tx_free(pq, data, 0);
2744178676Ssam		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
2745178676Ssam
2746178676Ssam		usbd_xfer_set_priv(xfer, NULL);
2747178676Ssam
2748198429Srpaulo		ifp->if_opackets++;
2749178676Ssam
2750178676Ssam		/* FALLTHROUGH */
2751178676Ssam	case USB_ST_SETUP:
2752198429Srpaulotr_setup:
2753178676Ssam		data = STAILQ_FIRST(&pq->tx_qh);
2754220704Sbschmidt		if (data == NULL)
2755220704Sbschmidt			break;
2756201209Srpaulo
2757178676Ssam		STAILQ_REMOVE_HEAD(&pq->tx_qh, next);
2758178676Ssam
2759178676Ssam		m = data->m;
2760198439Srpaulo		if ((m->m_pkthdr.len +
2761178676Ssam		    sizeof(data->desc) + 3 + 8) > RUN_MAX_TXSZ) {
2762178676Ssam			DPRINTF("data overflow, %u bytes\n",
2763221651Sbschmidt			    m->m_pkthdr.len);
2764221651Sbschmidt
2765221651Sbschmidt			ifp->if_oerrors++;
2766221651Sbschmidt
2767221651Sbschmidt			run_tx_free(pq, data, 1);
2768221651Sbschmidt
2769221651Sbschmidt			goto tr_setup;
2770221651Sbschmidt		}
2771221651Sbschmidt
2772221651Sbschmidt		pc = usbd_xfer_get_frame(xfer, 0);
2773221651Sbschmidt		size = sizeof(data->desc);
2774221651Sbschmidt		usbd_copy_in(pc, 0, &data->desc, size);
2775221651Sbschmidt		usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len);
2776221651Sbschmidt		size += m->m_pkthdr.len;
2777221651Sbschmidt		/*
2778221651Sbschmidt		 * Align end on a 4-byte boundary, pad 8 bytes (CRC +
2779221651Sbschmidt		 * 4-byte padding), and be sure to zero those trailing
2780221651Sbschmidt		 * bytes:
2781221651Sbschmidt		 */
2782221651Sbschmidt		usbd_frame_zero(pc, size, ((-size) & 3) + 8);
2783221651Sbschmidt		size += ((-size) & 3) + 8;
2784221651Sbschmidt
2785221651Sbschmidt		vap = data->ni->ni_vap;
2786221651Sbschmidt		if (ieee80211_radiotap_active_vap(vap)) {
2787221651Sbschmidt			struct run_tx_radiotap_header *tap = &sc->sc_txtap;
2788221651Sbschmidt			struct rt2860_txwi *txwi =
2789221651Sbschmidt			    (struct rt2860_txwi *)(&data->desc + sizeof(struct rt2870_txd));
2790221651Sbschmidt
2791221651Sbschmidt			tap->wt_flags = 0;
2792221651Sbschmidt			tap->wt_rate = rt2860_rates[data->ridx].rate;
2793221651Sbschmidt			tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
2794221651Sbschmidt			tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
2795221651Sbschmidt			tap->wt_hwqueue = index;
2796221651Sbschmidt			if (le16toh(txwi->phy) & RT2860_PHY_SHPRE)
2797221651Sbschmidt				tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
2798221651Sbschmidt
2799221651Sbschmidt			ieee80211_radiotap_tx(vap, m);
2800221651Sbschmidt		}
2801221651Sbschmidt
2802221651Sbschmidt		DPRINTFN(11, "sending frame len=%u/%u  @ index %d\n",
2803221651Sbschmidt		    m->m_pkthdr.len, size, index);
2804221651Sbschmidt
2805221651Sbschmidt		usbd_xfer_set_frame_len(xfer, 0, size);
2806221651Sbschmidt		usbd_xfer_set_priv(xfer, data);
2807221651Sbschmidt
2808221651Sbschmidt		usbd_transfer_submit(xfer);
2809221651Sbschmidt
2810221651Sbschmidt		RUN_UNLOCK(sc);
2811221651Sbschmidt		run_start(ifp);
2812221651Sbschmidt		RUN_LOCK(sc);
2813221651Sbschmidt
2814221651Sbschmidt		break;
2815221651Sbschmidt
2816221651Sbschmidt	default:
2817221651Sbschmidt		DPRINTF("USB transfer error, %s\n",
2818221651Sbschmidt		    usbd_errstr(error));
2819221651Sbschmidt
2820221651Sbschmidt		data = usbd_xfer_get_priv(xfer);
2821221651Sbschmidt
2822221651Sbschmidt		ifp->if_oerrors++;
2823221651Sbschmidt
2824221651Sbschmidt		if (data != NULL) {
2825221651Sbschmidt			if(data->ni != NULL)
2826221651Sbschmidt				vap = data->ni->ni_vap;
2827221651Sbschmidt			run_tx_free(pq, data, error);
2828221651Sbschmidt			usbd_xfer_set_priv(xfer, NULL);
2829221651Sbschmidt		}
2830221651Sbschmidt		if (vap == NULL)
2831221651Sbschmidt			vap = TAILQ_FIRST(&ic->ic_vaps);
2832221651Sbschmidt
2833221651Sbschmidt		if (error != USB_ERR_CANCELLED) {
2834221651Sbschmidt			if (error == USB_ERR_TIMEOUT) {
2835221651Sbschmidt				device_printf(sc->sc_dev, "device timeout\n");
2836221651Sbschmidt				uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
2837221651Sbschmidt				DPRINTF("cmdq_store=%d\n", i);
2838221651Sbschmidt				sc->cmdq[i].func = run_usb_timeout_cb;
2839221651Sbschmidt				sc->cmdq[i].arg0 = vap;
2840221651Sbschmidt				ieee80211_runtask(ic, &sc->cmdq_task);
2841221651Sbschmidt			}
2842221651Sbschmidt
2843221651Sbschmidt			/*
2844221651Sbschmidt			 * Try to clear stall first, also if other
2845221651Sbschmidt			 * errors occur, hence clearing stall
2846221651Sbschmidt			 * introduces a 50 ms delay:
2847221651Sbschmidt			 */
2848221651Sbschmidt			usbd_xfer_set_stall(xfer);
2849221651Sbschmidt			goto tr_setup;
2850221651Sbschmidt		}
2851221651Sbschmidt		break;
2852221651Sbschmidt	}
2853198429Srpaulo}
2854198429Srpaulo
2855198429Srpaulostatic void
2856206477Sbschmidtrun_bulk_tx_callback0(struct usb_xfer *xfer, usb_error_t error)
2857178676Ssam{
2858178676Ssam	run_bulk_tx_callbackN(xfer, error, 0);
2859220728Sbschmidt}
2860178676Ssam
2861178676Ssamstatic void
2862178676Ssamrun_bulk_tx_callback1(struct usb_xfer *xfer, usb_error_t error)
2863178676Ssam{
2864178676Ssam	run_bulk_tx_callbackN(xfer, error, 1);
2865198429Srpaulo}
2866198429Srpaulo
2867198429Srpaulostatic void
2868198429Srpaulorun_bulk_tx_callback2(struct usb_xfer *xfer, usb_error_t error)
2869178676Ssam{
2870178676Ssam	run_bulk_tx_callbackN(xfer, error, 2);
2871198429Srpaulo}
2872178676Ssam
2873201209Srpaulostatic void
2874201209Srpaulorun_bulk_tx_callback3(struct usb_xfer *xfer, usb_error_t error)
2875198429Srpaulo{
2876198429Srpaulo	run_bulk_tx_callbackN(xfer, error, 3);
2877178676Ssam}
2878178676Ssam
2879198439Srpaulostatic void
2880178676Ssamrun_bulk_tx_callback4(struct usb_xfer *xfer, usb_error_t error)
2881178676Ssam{
2882178676Ssam	run_bulk_tx_callbackN(xfer, error, 4);
2883198429Srpaulo}
2884198429Srpaulo
2885178676Ssamstatic void
2886178676Ssamrun_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error)
2887198429Srpaulo{
2888198429Srpaulo	run_bulk_tx_callbackN(xfer, error, 5);
2889178676Ssam}
2890178676Ssam
2891198429Srpaulostatic void
2892198429Srpaulorun_set_tx_desc(struct run_softc *sc, struct run_tx_data *data)
2893198429Srpaulo{
2894198429Srpaulo	struct mbuf *m = data->m;
2895178676Ssam	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
2896178676Ssam	struct ieee80211vap *vap = data->ni->ni_vap;
2897201209Srpaulo	struct ieee80211_frame *wh;
2898201209Srpaulo	struct rt2870_txd *txd;
2899201209Srpaulo	struct rt2860_txwi *txwi;
2900201209Srpaulo	uint16_t xferlen;
2901201209Srpaulo	uint16_t mcs;
2902178676Ssam	uint8_t ridx = data->ridx;
2903198429Srpaulo	uint8_t pad;
2904220728Sbschmidt
2905178676Ssam	/* get MCS code from rate index */
2906178676Ssam	mcs = rt2860_rates[ridx].mcs;
2907178676Ssam
2908178676Ssam	xferlen = sizeof(*txwi) + m->m_pkthdr.len;
2909198429Srpaulo
2910178676Ssam	/* roundup to 32-bit alignment */
2911178676Ssam	xferlen = (xferlen + 3) & ~3;
2912198429Srpaulo
2913198429Srpaulo	txd = (struct rt2870_txd *)&data->desc;
2914178676Ssam	txd->len = htole16(xferlen);
2915178676Ssam
2916202986Srpaulo	wh = mtod(m, struct ieee80211_frame *);
2917178676Ssam
2918201209Srpaulo	/*
2919201209Srpaulo	 * Ether both are true or both are false, the header
2920202986Srpaulo	 * are nicely aligned to 32-bit. So, no L2 padding.
2921201209Srpaulo	 */
2922178676Ssam	if(IEEE80211_HAS_ADDR4(wh) == IEEE80211_QOS_HAS_SEQ(wh))
2923178676Ssam		pad = 0;
2924178676Ssam	else
2925178676Ssam		pad = 2;
2926178676Ssam
2927178676Ssam	/* setup TX Wireless Information */
2928178676Ssam	txwi = (struct rt2860_txwi *)(txd + 1);
2929220660Sbschmidt	txwi->len = htole16(m->m_pkthdr.len - pad);
2930220660Sbschmidt	if (rt2860_rates[ridx].phy == IEEE80211_T_DS) {
2931220660Sbschmidt		txwi->phy = htole16(RT2860_PHY_CCK);
2932220660Sbschmidt		if (ridx != RT2860_RIDX_CCK1 &&
2933220660Sbschmidt		    (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
2934220660Sbschmidt			mcs |= RT2860_PHY_SHPRE;
2935220660Sbschmidt	} else
2936220660Sbschmidt		txwi->phy = htole16(RT2860_PHY_OFDM);
2937220660Sbschmidt	txwi->phy |= htole16(mcs);
2938201209Srpaulo
2939178676Ssam	/* check if RTS/CTS or CTS-to-self protection is required */
2940178676Ssam	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
2941198429Srpaulo	    (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold ||
2942198429Srpaulo	     ((ic->ic_flags & IEEE80211_F_USEPROT) &&
2943178676Ssam	      rt2860_rates[ridx].phy == IEEE80211_T_OFDM)))
2944178676Ssam		txwi->txop |= RT2860_TX_TXOP_HT;
2945178676Ssam	else
2946198429Srpaulo		txwi->txop |= RT2860_TX_TXOP_BACKOFF;
2947201209Srpaulo
2948201209Srpaulo	if (vap->iv_opmode != IEEE80211_M_STA && !IEEE80211_QOS_HAS_SEQ(wh))
2949178676Ssam		txwi->xflags |= RT2860_TX_NSEQ;
2950178676Ssam}
2951178676Ssam
2952178676Ssam/* This function must be called locked */
2953178676Ssamstatic int
2954178676Ssamrun_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
2955178676Ssam{
2956198429Srpaulo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
2957178676Ssam	struct ieee80211vap *vap = ni->ni_vap;
2958178676Ssam	struct ieee80211_frame *wh;
2959178676Ssam	struct ieee80211_channel *chan;
2960201209Srpaulo	const struct ieee80211_txparam *tp;
2961178676Ssam	struct run_node *rn = (void *)ni;
2962178676Ssam	struct run_tx_data *data;
2963198429Srpaulo	struct rt2870_txd *txd;
2964198429Srpaulo	struct rt2860_txwi *txwi;
2965178676Ssam	uint16_t qos;
2966178676Ssam	uint16_t dur;
2967198429Srpaulo	uint16_t qid;
2968198429Srpaulo	uint8_t type;
2969178676Ssam	uint8_t tid;
2970178676Ssam	uint8_t ridx;
2971178676Ssam	uint8_t ctl_ridx;
2972178676Ssam	uint8_t qflags;
2973178676Ssam	uint8_t xflags = 0;
2974178676Ssam	int hasqos;
2975178676Ssam
2976201209Srpaulo	RUN_LOCK_ASSERT(sc, MA_OWNED);
2977201209Srpaulo
2978178676Ssam	wh = mtod(m, struct ieee80211_frame *);
2979178676Ssam
2980178676Ssam	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
2981178676Ssam
2982198429Srpaulo	/*
2983198429Srpaulo	 * There are 7 bulk endpoints: 1 for RX
2984178676Ssam	 * and 6 for TX (4 EDCAs + HCCA + Prio).
2985178676Ssam	 * Update 03-14-2009:  some devices like the Planex GW-US300MiniS
2986178676Ssam	 * seem to have only 4 TX bulk endpoints (Fukaumi Naoki).
2987201209Srpaulo	 */
2988201209Srpaulo	if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) {
2989178676Ssam		uint8_t *frm;
2990178676Ssam
2991178676Ssam		if(IEEE80211_HAS_ADDR4(wh))
2992178676Ssam			frm = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos;
2993178676Ssam		else
2994198429Srpaulo			frm =((struct ieee80211_qosframe *)wh)->i_qos;
2995198429Srpaulo
2996178676Ssam		qos = le16toh(*(const uint16_t *)frm);
2997178676Ssam		tid = qos & IEEE80211_QOS_TID;
2998178676Ssam		qid = TID_TO_WME_AC(tid);
2999201209Srpaulo	} else {
3000201209Srpaulo		qos = 0;
3001178676Ssam		tid = 0;
3002178676Ssam		qid = WME_AC_BE;
3003178676Ssam	}
3004178676Ssam	qflags = (qid < 4) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA;
3005201209Srpaulo
3006191746Sthompsa	DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n",
3007201209Srpaulo	    qos, qid, tid, qflags);
3008178676Ssam
3009178676Ssam	chan = (ni->ni_chan != IEEE80211_CHAN_ANYC)?ni->ni_chan:ic->ic_curchan;
3010198429Srpaulo	tp = &vap->iv_txparms[ieee80211_chan2mode(chan)];
3011220674Sbschmidt
3012198429Srpaulo	/* pickup a rate index */
3013198429Srpaulo	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
3014198429Srpaulo	    type != IEEE80211_FC0_TYPE_DATA) {
3015201209Srpaulo		ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
3016198429Srpaulo		    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
3017198429Srpaulo		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
3018178676Ssam	} else {
3019198429Srpaulo		if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
3020178676Ssam			ridx = rn->fix_ridx;
3021178676Ssam		else
3022178676Ssam			ridx = rn->amrr_ridx;
3023198429Srpaulo		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
3024178676Ssam	}
3025198429Srpaulo
3026178676Ssam	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
3027178676Ssam	    (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) !=
3028198429Srpaulo	     IEEE80211_QOS_ACKPOLICY_NOACK)) {
3029198429Srpaulo		xflags |= RT2860_TX_ACK;
3030198429Srpaulo		if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
3031198429Srpaulo			dur = rt2860_rates[ctl_ridx].sp_ack_dur;
3032206477Sbschmidt		else
3033198429Srpaulo			dur = rt2860_rates[ctl_ridx].lp_ack_dur;
3034198429Srpaulo		*(uint16_t *)wh->i_dur = htole16(dur);
3035198429Srpaulo	}
3036198429Srpaulo
3037198429Srpaulo	/* reserve slots for mgmt packets, just in case */
3038198429Srpaulo	if (sc->sc_epq[qid].tx_nfree < 3) {
3039198429Srpaulo		DPRINTFN(10, "tx ring %d is full\n", qid);
3040198429Srpaulo		return (-1);
3041198429Srpaulo	}
3042220728Sbschmidt
3043198429Srpaulo	data = STAILQ_FIRST(&sc->sc_epq[qid].tx_fh);
3044198429Srpaulo	STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next);
3045198429Srpaulo	sc->sc_epq[qid].tx_nfree--;
3046198429Srpaulo
3047198429Srpaulo	txd = (struct rt2870_txd *)&data->desc;
3048206477Sbschmidt	txd->flags = qflags;
3049191746Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3050191746Sthompsa	txwi->xflags = xflags;
3051191746Sthompsa	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3052191746Sthompsa		txwi->wcid = 0;
3053198429Srpaulo	} else {
3054191746Sthompsa		txwi->wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
3055191746Sthompsa		    1 : RUN_AID2WCID(ni->ni_associd);
3056191746Sthompsa	}
3057191746Sthompsa	/* clear leftover garbage bits */
3058198429Srpaulo	txwi->flags = 0;
3059198429Srpaulo	txwi->txop = 0;
3060191746Sthompsa
3061191746Sthompsa	data->m = m;
3062191746Sthompsa	data->ni = ni;
3063191746Sthompsa	data->ridx = ridx;
3064191746Sthompsa
3065198429Srpaulo	run_set_tx_desc(sc, data);
3066198429Srpaulo
3067198429Srpaulo	/*
3068198429Srpaulo	 * The chip keeps track of 2 kind of Tx stats,
3069198429Srpaulo	 *  * TX_STAT_FIFO, for per WCID stats, and
3070206477Sbschmidt	 *  * TX_STA_CNT0 for all-TX-in-one stats.
3071201209Srpaulo	 *
3072191746Sthompsa	 * To use FIFO stats, we need to store MCS into the driver-private
3073198429Srpaulo 	 * PacketID field. So that, we can tell whose stats when we read them.
3074198429Srpaulo 	 * We add 1 to the MCS because setting the PacketID field to 0 means
3075191746Sthompsa 	 * that we don't want feedback in TX_STAT_FIFO.
3076191746Sthompsa 	 * And, that's what we want for STA mode, since TX_STA_CNT0 does the job.
3077191746Sthompsa 	 *
3078201209Srpaulo 	 * FIFO stats doesn't count Tx with WCID 0xff, so we do this in run_tx().
3079201209Srpaulo 	 */
3080201209Srpaulo	if (sc->rvp_cnt > 1 || vap->iv_opmode == IEEE80211_M_HOSTAP ||
3081198429Srpaulo	    vap->iv_opmode == IEEE80211_M_MBSS) {
3082198429Srpaulo		uint16_t pid = (rt2860_rates[ridx].mcs + 1) & 0xf;
3083198429Srpaulo		txwi->len |= htole16(pid << RT2860_TX_PID_SHIFT);
3084220728Sbschmidt
3085220726Sbschmidt		/*
3086220726Sbschmidt		 * Unlike PCI based devices, we don't get any interrupt from
3087198429Srpaulo		 * USB devices, so we simulate FIFO-is-full interrupt here.
3088198429Srpaulo		 * Ralink recomends to drain FIFO stats every 100 ms, but 16 slots
3089198429Srpaulo		 * quickly get fulled. To prevent overflow, increment a counter on
3090220726Sbschmidt		 * every FIFO stat request, so we know how many slots are left.
3091198429Srpaulo		 * We do this only in HOSTAP or multiple vap mode since FIFO stats
3092198429Srpaulo		 * are used only in those modes.
3093198429Srpaulo		 * We just drain stats. AMRR gets updated every 1 sec by
3094198429Srpaulo		 * run_ratectl_cb() via callout.
3095198429Srpaulo		 * Call it early. Otherwise overflow.
3096198429Srpaulo		 */
3097198429Srpaulo		if (sc->fifo_cnt++ == 10) {
3098198429Srpaulo			/*
3099220726Sbschmidt			 * With multiple vaps or if_bridge, if_start() is called
3100198429Srpaulo			 * with a non-sleepable lock, tcpinp. So, need to defer.
3101198429Srpaulo			 */
3102198429Srpaulo			uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
3103198429Srpaulo			DPRINTFN(6, "cmdq_store=%d\n", i);
3104198429Srpaulo			sc->cmdq[i].func = run_drain_fifo;
3105198429Srpaulo			sc->cmdq[i].arg0 = sc;
3106198429Srpaulo			ieee80211_runtask(ic, &sc->cmdq_task);
3107198429Srpaulo		}
3108198429Srpaulo	}
3109198429Srpaulo
3110198429Srpaulo        STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next);
3111198429Srpaulo
3112198429Srpaulo	usbd_transfer_start(sc->sc_xfer[qid]);
3113198429Srpaulo
3114198429Srpaulo	DPRINTFN(8, "sending data frame len=%d rate=%d qid=%d\n", m->m_pkthdr.len +
3115198429Srpaulo	    (int)(sizeof (struct rt2870_txd) + sizeof (struct rt2860_rxwi)),
3116198429Srpaulo	    rt2860_rates[ridx].rate, qid);
3117198429Srpaulo
3118198429Srpaulo	return (0);
3119220728Sbschmidt}
3120198429Srpaulo
3121198429Srpaulostatic int
3122198429Srpaulorun_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
3123198429Srpaulo{
3124198429Srpaulo	struct ifnet *ifp = sc->sc_ifp;
3125191746Sthompsa	struct ieee80211com *ic = ifp->if_l2com;
3126191746Sthompsa	struct run_node *rn = (void *)ni;
3127206477Sbschmidt	struct run_tx_data *data;
3128178676Ssam	struct ieee80211_frame *wh;
3129178676Ssam	struct rt2870_txd *txd;
3130178676Ssam	struct rt2860_txwi *txwi;
3131198429Srpaulo	uint16_t dur;
3132201209Srpaulo	uint8_t ridx = rn->mgt_ridx;
3133178676Ssam	uint8_t type;
3134178676Ssam	uint8_t xflags = 0;
3135178676Ssam	uint8_t wflags = 0;
3136198429Srpaulo
3137201209Srpaulo	RUN_LOCK_ASSERT(sc, MA_OWNED);
3138178676Ssam
3139201209Srpaulo	wh = mtod(m, struct ieee80211_frame *);
3140201209Srpaulo
3141201209Srpaulo	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3142201209Srpaulo
3143201209Srpaulo	/* tell hardware to add timestamp for probe responses */
3144201209Srpaulo	if ((wh->i_fc[0] &
3145201209Srpaulo	    (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==
3146201209Srpaulo	    (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP))
3147201209Srpaulo		wflags |= RT2860_TX_TS;
3148206444Sbschmidt	else if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3149206444Sbschmidt		xflags |= RT2860_TX_ACK;
3150206444Sbschmidt
3151206444Sbschmidt		dur = ieee80211_ack_duration(ic->ic_rt, rt2860_rates[ridx].rate,
3152201209Srpaulo		    ic->ic_flags & IEEE80211_F_SHPREAMBLE);
3153201209Srpaulo		*(uint16_t *)wh->i_dur = htole16(dur);
3154201209Srpaulo	}
3155201209Srpaulo
3156201209Srpaulo	if (sc->sc_epq[0].tx_nfree == 0) {
3157201209Srpaulo		/* let caller free mbuf */
3158201209Srpaulo		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
3159201209Srpaulo		return (EIO);
3160178676Ssam	}
3161198429Srpaulo	data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3162198429Srpaulo	STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3163201209Srpaulo	sc->sc_epq[0].tx_nfree--;
3164198429Srpaulo
3165178676Ssam	txd = (struct rt2870_txd *)&data->desc;
3166198429Srpaulo	txd->flags = RT2860_TX_QSEL_EDCA;
3167198429Srpaulo	txwi = (struct rt2860_txwi *)(txd + 1);
3168201209Srpaulo	txwi->wcid = 0xff;
3169201209Srpaulo	txwi->flags = wflags;
3170178676Ssam	txwi->xflags = xflags;
3171198429Srpaulo	txwi->txop = 0;	/* clear leftover garbage bits */
3172191746Sthompsa
3173201209Srpaulo	data->m = m;
3174198429Srpaulo	data->ni = ni;
3175198429Srpaulo	data->ridx = ridx;
3176198429Srpaulo
3177198429Srpaulo	run_set_tx_desc(sc, data);
3178198429Srpaulo
3179198429Srpaulo	DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m->m_pkthdr.len +
3180220724Sbschmidt	    (int)(sizeof (struct rt2870_txd) + sizeof (struct rt2860_rxwi)),
3181220724Sbschmidt	    rt2860_rates[ridx].rate);
3182220725Sbschmidt
3183201209Srpaulo	STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3184201209Srpaulo
3185201209Srpaulo	usbd_transfer_start(sc->sc_xfer[0]);
3186178676Ssam
3187178676Ssam	return (0);
3188201209Srpaulo}
3189201209Srpaulo
3190201209Srpaulostatic int
3191201209Srpaulorun_sendprot(struct run_softc *sc,
3192201209Srpaulo    const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate)
3193201209Srpaulo{
3194201209Srpaulo	struct ieee80211com *ic = ni->ni_ic;
3195201209Srpaulo	struct ieee80211_frame *wh;
3196201209Srpaulo	struct run_tx_data *data;
3197201209Srpaulo	struct rt2870_txd *txd;
3198201209Srpaulo	struct rt2860_txwi *txwi;
3199201209Srpaulo	struct mbuf *mprot;
3200201209Srpaulo	int ridx;
3201201209Srpaulo	int protrate;
3202201209Srpaulo	int ackrate;
3203178676Ssam	int pktlen;
3204201209Srpaulo	int isshort;
3205201209Srpaulo	uint16_t dur;
3206201209Srpaulo	uint8_t type;
3207198429Srpaulo	uint8_t wflags = 0;
3208201209Srpaulo	uint8_t xflags = 0;
3209198429Srpaulo
3210198429Srpaulo	RUN_LOCK_ASSERT(sc, MA_OWNED);
3211198429Srpaulo
3212198429Srpaulo	KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY,
3213198429Srpaulo	    ("protection %d", prot));
3214198429Srpaulo
3215198429Srpaulo	wh = mtod(m, struct ieee80211_frame *);
3216201209Srpaulo	pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN;
3217198429Srpaulo	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3218201209Srpaulo
3219201209Srpaulo	protrate = ieee80211_ctl_rate(ic->ic_rt, rate);
3220198429Srpaulo	ackrate = ieee80211_ack_rate(ic->ic_rt, rate);
3221178676Ssam
3222178676Ssam	isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
3223178676Ssam	dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort)
3224198429Srpaulo	    + ieee80211_ack_duration(ic->ic_rt, rate, isshort);
3225198429Srpaulo	wflags = RT2860_TX_FRAG;
3226220725Sbschmidt
3227198429Srpaulo	/* check that there are free slots before allocating the mbuf */
3228206477Sbschmidt	if (sc->sc_epq[0].tx_nfree == 0) {
3229198429Srpaulo		/* let caller free mbuf */
3230198429Srpaulo		sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE;
3231178676Ssam		return (ENOBUFS);
3232198429Srpaulo	}
3233178676Ssam
3234198429Srpaulo	if (prot == IEEE80211_PROT_RTSCTS) {
3235198439Srpaulo		/* NB: CTS is the same size as an ACK */
3236198439Srpaulo		dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort);
3237201209Srpaulo		xflags |= RT2860_TX_ACK;
3238198429Srpaulo		mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur);
3239198439Srpaulo	} else {
3240198439Srpaulo		mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur);
3241198439Srpaulo	}
3242198429Srpaulo	if (mprot == NULL) {
3243198429Srpaulo		sc->sc_ifp->if_oerrors++;
3244206477Sbschmidt		DPRINTF("could not allocate mbuf\n");
3245198429Srpaulo		return (ENOBUFS);
3246198429Srpaulo	}
3247198429Srpaulo
3248198429Srpaulo        data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3249198429Srpaulo        STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3250198429Srpaulo        sc->sc_epq[0].tx_nfree--;
3251198439Srpaulo
3252198439Srpaulo	txd = (struct rt2870_txd *)&data->desc;
3253198439Srpaulo	txd->flags = RT2860_TX_QSEL_EDCA;
3254198429Srpaulo	txwi = (struct rt2860_txwi *)(txd + 1);
3255198439Srpaulo	txwi->wcid = 0xff;
3256198439Srpaulo	txwi->flags = wflags;
3257198439Srpaulo	txwi->xflags = xflags;
3258198429Srpaulo	txwi->txop = 0;	/* clear leftover garbage bits */
3259198429Srpaulo
3260206475Sbschmidt	data->m = mprot;
3261206477Sbschmidt	data->ni = ieee80211_ref_node(ni);
3262198429Srpaulo
3263198429Srpaulo	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
3264198429Srpaulo		if (rt2860_rates[ridx].rate == protrate)
3265198429Srpaulo			break;
3266198429Srpaulo	data->ridx = ridx;
3267198439Srpaulo
3268198439Srpaulo	run_set_tx_desc(sc, data);
3269198439Srpaulo
3270198429Srpaulo        DPRINTFN(1, "sending prot len=%u rate=%u\n",
3271198439Srpaulo            m->m_pkthdr.len, rate);
3272206443Sbschmidt
3273198439Srpaulo        STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3274198429Srpaulo
3275206475Sbschmidt	usbd_transfer_start(sc->sc_xfer[0]);
3276198429Srpaulo
3277206477Sbschmidt	return (0);
3278220720Sbschmidt}
3279178676Ssam
3280221651Sbschmidtstatic int
3281198429Srpaulorun_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni,
3282178676Ssam    const struct ieee80211_bpf_params *params)
3283178676Ssam{
3284198429Srpaulo	struct ieee80211com *ic = ni->ni_ic;
3285220720Sbschmidt	struct ieee80211_frame *wh;
3286178676Ssam	struct run_tx_data *data;
3287178676Ssam	struct rt2870_txd *txd;
3288178676Ssam	struct rt2860_txwi *txwi;
3289178676Ssam	uint8_t type;
3290178676Ssam	uint8_t ridx;
3291198429Srpaulo	uint8_t rate;
3292220700Sbschmidt	uint8_t opflags = 0;
3293178676Ssam	uint8_t xflags = 0;
3294220720Sbschmidt	int error;
3295178676Ssam
3296220723Sbschmidt	RUN_LOCK_ASSERT(sc, MA_OWNED);
3297220723Sbschmidt
3298220720Sbschmidt	KASSERT(params != NULL, ("no raw xmit params"));
3299178676Ssam
3300178676Ssam	wh = mtod(m, struct ieee80211_frame *);
3301178676Ssam	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3302198429Srpaulo
3303198429Srpaulo	rate = params->ibp_rate0;
3304178676Ssam	if (!ieee80211_isratevalid(ic->ic_rt, rate)) {
3305178676Ssam		/* let caller free mbuf */
3306220720Sbschmidt		return (EINVAL);
3307220720Sbschmidt	}
3308220720Sbschmidt
3309220720Sbschmidt	if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0)
3310220720Sbschmidt		xflags |= RT2860_TX_ACK;
3311220720Sbschmidt	if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) {
3312220720Sbschmidt		error = run_sendprot(sc, m, ni,
3313220720Sbschmidt		    params->ibp_flags & IEEE80211_BPF_RTS ?
3314220720Sbschmidt			IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY,
3315220720Sbschmidt		    rate);
3316221651Sbschmidt		if (error) {
3317221651Sbschmidt			/* let caller free mbuf */
3318221651Sbschmidt			return error;
3319221651Sbschmidt		}
3320221651Sbschmidt		opflags |= /*XXX RT2573_TX_LONG_RETRY |*/ RT2860_TX_TXOP_SIFS;
3321221651Sbschmidt	}
3322221651Sbschmidt
3323221651Sbschmidt	if (sc->sc_epq[0].tx_nfree == 0) {
3324221651Sbschmidt		/* let caller free mbuf */
3325221651Sbschmidt		sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE;
3326198429Srpaulo		DPRINTF("sending raw frame, but tx ring is full\n");
3327198429Srpaulo		return (EIO);
3328198429Srpaulo	}
3329198429Srpaulo        data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3330201209Srpaulo        STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3331178676Ssam        sc->sc_epq[0].tx_nfree--;
3332178676Ssam
3333198429Srpaulo	txd = (struct rt2870_txd *)&data->desc;
3334178676Ssam	txd->flags = RT2860_TX_QSEL_EDCA;
3335178676Ssam	txwi = (struct rt2860_txwi *)(txd + 1);
3336178676Ssam	txwi->wcid = 0xff;
3337178676Ssam	txwi->xflags = xflags;
3338206358Srpaulo	txwi->txop = opflags;
3339206358Srpaulo	txwi->flags = 0;	/* clear leftover garbage bits */
3340178676Ssam
3341178676Ssam        data->m = m;
3342221648Sbschmidt        data->ni = ni;
3343178676Ssam	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
3344198429Srpaulo		if (rt2860_rates[ridx].rate == rate)
3345178676Ssam			break;
3346220725Sbschmidt	data->ridx = ridx;
3347198429Srpaulo
3348178676Ssam        run_set_tx_desc(sc, data);
3349198429Srpaulo
3350178676Ssam        DPRINTFN(10, "sending raw frame len=%u rate=%u\n",
3351178676Ssam            m->m_pkthdr.len, rate);
3352220725Sbschmidt
3353198429Srpaulo        STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3354198429Srpaulo
3355198429Srpaulo	usbd_transfer_start(sc->sc_xfer[0]);
3356178676Ssam
3357192468Ssam        return (0);
3358178676Ssam}
3359178676Ssam
3360178676Ssamstatic int
3361221648Sbschmidtrun_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
3362178676Ssam    const struct ieee80211_bpf_params *params)
3363178676Ssam{
3364178676Ssam	struct ifnet *ifp = ni->ni_ic->ic_ifp;
3365198429Srpaulo	struct run_softc *sc = ifp->if_softc;
3366178676Ssam	int error = 0;
3367178676Ssam
3368198429Srpaulo	RUN_LOCK(sc);
3369198429Srpaulo
3370198429Srpaulo	/* prevent management frames from being sent if we're not ready */
3371198429Srpaulo	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
3372198429Srpaulo		error =  ENETDOWN;
3373198429Srpaulo		goto done;
3374198429Srpaulo	}
3375198429Srpaulo
3376198429Srpaulo	if (params == NULL) {
3377198429Srpaulo		/* tx mgt packet */
3378198429Srpaulo		if ((error = run_tx_mgt(sc, m, ni)) != 0) {
3379198429Srpaulo			ifp->if_oerrors++;
3380220720Sbschmidt			DPRINTF("mgt tx failed\n");
3381220720Sbschmidt			goto done;
3382220720Sbschmidt		}
3383220720Sbschmidt	} else {
3384220720Sbschmidt		/* tx raw packet with param */
3385220720Sbschmidt		if ((error = run_tx_param(sc, m, ni, params)) != 0) {
3386198429Srpaulo			ifp->if_oerrors++;
3387198429Srpaulo			DPRINTF("tx with param failed\n");
3388198429Srpaulo			goto done;
3389198429Srpaulo		}
3390178676Ssam	}
3391198429Srpaulo
3392198429Srpaulo	ifp->if_opackets++;
3393178676Ssam
3394198429Srpaulodone:
3395198429Srpaulo	RUN_UNLOCK(sc);
3396198429Srpaulo
3397198429Srpaulo	if (error != 0) {
3398198429Srpaulo		if(m != NULL)
3399178676Ssam			m_freem(m);
3400201209Srpaulo		ieee80211_free_node(ni);
3401178676Ssam	}
3402198429Srpaulo
3403178676Ssam	return (error);
3404198429Srpaulo}
3405178676Ssam
3406198429Srpaulostatic void
3407198429Srpaulorun_start(struct ifnet *ifp)
3408198429Srpaulo{
3409198429Srpaulo	struct run_softc *sc = ifp->if_softc;
3410198429Srpaulo	struct ieee80211_node *ni;
3411198429Srpaulo	struct mbuf *m;
3412198429Srpaulo
3413198429Srpaulo	RUN_LOCK(sc);
3414201209Srpaulo
3415178676Ssam	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
3416198429Srpaulo		RUN_UNLOCK(sc);
3417198429Srpaulo		return;
3418220728Sbschmidt	}
3419198429Srpaulo
3420198429Srpaulo	for (;;) {
3421198429Srpaulo		/* send data frames */
3422178676Ssam		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
3423178676Ssam		if (m == NULL)
3424178676Ssam			break;
3425198429Srpaulo
3426178676Ssam		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
3427178676Ssam		if (run_tx(sc, m, ni) != 0) {
3428178676Ssam			IFQ_DRV_PREPEND(&ifp->if_snd, m);
3429178676Ssam			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
3430198429Srpaulo			break;
3431178676Ssam		}
3432198429Srpaulo	}
3433178676Ssam
3434198429Srpaulo	RUN_UNLOCK(sc);
3435178676Ssam}
3436178676Ssam
3437201209Srpaulostatic int
3438178676Ssamrun_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
3439178676Ssam{
3440178676Ssam	struct run_softc *sc = ifp->if_softc;
3441178676Ssam	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
3442178676Ssam	struct ifreq *ifr = (struct ifreq *) data;
3443198429Srpaulo	int startall = 0;
3444220720Sbschmidt	int error = 0;
3445201209Srpaulo
3446201209Srpaulo	switch (cmd) {
3447178676Ssam	case SIOCSIFFLAGS:
3448221648Sbschmidt		RUN_LOCK(sc);
3449220728Sbschmidt		if (ifp->if_flags & IFF_UP) {
3450201209Srpaulo			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)){
3451201209Srpaulo				startall = 1;
3452198429Srpaulo				run_init_locked(sc);
3453201209Srpaulo			} else
3454221648Sbschmidt				run_update_promisc_locked(ifp);
3455201209Srpaulo		} else {
3456220715Sbschmidt			if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
3457201209Srpaulo			    (ic->ic_nrunning == 0 || sc->rvp_cnt <= 1)) {
3458201209Srpaulo					run_stop(sc);
3459198429Srpaulo			}
3460201209Srpaulo		}
3461201209Srpaulo		RUN_UNLOCK(sc);
3462178676Ssam		if (startall)
3463198429Srpaulo			ieee80211_start_all(ic);
3464178676Ssam		break;
3465178676Ssam	case SIOCGIFMEDIA:
3466198429Srpaulo		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
3467198429Srpaulo		break;
3468198429Srpaulo	case SIOCGIFADDR:
3469198429Srpaulo		error = ether_ioctl(ifp, cmd, data);
3470198429Srpaulo		break;
3471220700Sbschmidt	default:
3472220700Sbschmidt		error = EINVAL;
3473220700Sbschmidt		break;
3474220700Sbschmidt	}
3475220700Sbschmidt
3476220700Sbschmidt	return (error);
3477220700Sbschmidt}
3478220700Sbschmidt
3479178676Ssamstatic void
3480220700Sbschmidtrun_set_agc(struct run_softc *sc, uint8_t agc)
3481220700Sbschmidt{
3482220700Sbschmidt	uint8_t bbp;
3483220700Sbschmidt
3484220700Sbschmidt	if (sc->mac_ver == 0x3572) {
3485220700Sbschmidt		run_bbp_read(sc, 27, &bbp);
3486220700Sbschmidt		bbp &= ~(0x3 << 5);
3487220700Sbschmidt		run_bbp_write(sc, 27, bbp | 0 << 5);	/* select Rx0 */
3488220700Sbschmidt		run_bbp_write(sc, 66, agc);
3489220700Sbschmidt		run_bbp_write(sc, 27, bbp | 1 << 5);	/* select Rx1 */
3490220700Sbschmidt		run_bbp_write(sc, 66, agc);
3491220700Sbschmidt	} else
3492178676Ssam		run_bbp_write(sc, 66, agc);
3493178676Ssam}
3494220700Sbschmidt
3495198429Srpaulostatic void
3496178676Ssamrun_select_chan_group(struct run_softc *sc, int group)
3497178676Ssam{
3498178676Ssam	uint32_t tmp;
3499178676Ssam	uint8_t agc;
3500198429Srpaulo
3501178676Ssam	run_bbp_write(sc, 62, 0x37 - sc->lna[group]);
3502178676Ssam	run_bbp_write(sc, 63, 0x37 - sc->lna[group]);
3503178676Ssam	run_bbp_write(sc, 64, 0x37 - sc->lna[group]);
3504198429Srpaulo	run_bbp_write(sc, 86, 0x00);
3505178676Ssam
3506198429Srpaulo	if (group == 0) {
3507220700Sbschmidt		if (sc->ext_2ghz_lna) {
3508220700Sbschmidt			run_bbp_write(sc, 82, 0x62);
3509220700Sbschmidt			run_bbp_write(sc, 75, 0x46);
3510198429Srpaulo		} else {
3511201209Srpaulo			run_bbp_write(sc, 82, 0x84);
3512201209Srpaulo			run_bbp_write(sc, 75, 0x50);
3513198429Srpaulo		}
3514198429Srpaulo	} else {
3515220700Sbschmidt		if (sc->mac_ver == 0x3572)
3516178676Ssam			run_bbp_write(sc, 82, 0x94);
3517220700Sbschmidt		else
3518220700Sbschmidt			run_bbp_write(sc, 82, 0xf2);
3519220700Sbschmidt		if (sc->ext_5ghz_lna)
3520220700Sbschmidt			run_bbp_write(sc, 75, 0x46);
3521178676Ssam		else
3522178676Ssam			run_bbp_write(sc, 75, 0x50);
3523201209Srpaulo	}
3524201209Srpaulo
3525198429Srpaulo	run_read(sc, RT2860_TX_BAND_CFG, &tmp);
3526198429Srpaulo	tmp &= ~(RT2860_5G_BAND_SEL_N | RT2860_5G_BAND_SEL_P);
3527198429Srpaulo	tmp |= (group == 0) ? RT2860_5G_BAND_SEL_N : RT2860_5G_BAND_SEL_P;
3528178676Ssam	run_write(sc, RT2860_TX_BAND_CFG, tmp);
3529198429Srpaulo
3530220728Sbschmidt	/* enable appropriate Power Amplifiers and Low Noise Amplifiers */
3531178676Ssam	tmp = RT2860_RFTR_EN | RT2860_TRSW_EN | RT2860_LNA_PE0_EN;
3532198429Srpaulo	if (sc->nrxchains > 1)
3533178676Ssam		tmp |= RT2860_LNA_PE1_EN;
3534198429Srpaulo	if (group == 0) {	/* 2GHz */
3535178676Ssam		tmp |= RT2860_PA_PE_G0_EN;
3536198429Srpaulo		if (sc->ntxchains > 1)
3537198429Srpaulo			tmp |= RT2860_PA_PE_G1_EN;
3538198429Srpaulo	} else {		/* 5GHz */
3539178676Ssam		tmp |= RT2860_PA_PE_A0_EN;
3540178676Ssam		if (sc->ntxchains > 1)
3541178676Ssam			tmp |= RT2860_PA_PE_A1_EN;
3542178676Ssam	}
3543178676Ssam	if (sc->mac_ver == 0x3572) {
3544201209Srpaulo		run_rt3070_rf_write(sc, 8, 0x00);
3545220720Sbschmidt		run_write(sc, RT2860_TX_PIN_CFG, tmp);
3546178676Ssam		run_rt3070_rf_write(sc, 8, 0x80);
3547221651Sbschmidt	} else
3548178676Ssam		run_write(sc, RT2860_TX_PIN_CFG, tmp);
3549198429Srpaulo
3550198429Srpaulo	/* set initial AGC value */
3551198429Srpaulo	if (group == 0) {	/* 2GHz band */
3552198429Srpaulo		if (sc->mac_ver >= 0x3070)
3553198429Srpaulo			agc = 0x1c + sc->lna[0] * 2;
3554220720Sbschmidt		else
3555178676Ssam			agc = 0x2e + sc->lna[0];
3556178676Ssam	} else {		/* 5GHz band */
3557220700Sbschmidt		if (sc->mac_ver == 0x3572)
3558220700Sbschmidt			agc = 0x22 + (sc->lna[group] * 5) / 3;
3559198429Srpaulo		else
3560198429Srpaulo			agc = 0x32 + (sc->lna[group] * 5) / 3;
3561220720Sbschmidt	}
3562201209Srpaulo	run_set_agc(sc, agc);
3563178676Ssam}
3564198429Srpaulo
3565178676Ssamstatic void
3566201209Srpaulorun_rt2870_set_chan(struct run_softc *sc, uint32_t chan)
3567198429Srpaulo{
3568198429Srpaulo	const struct rfprog *rfprog = rt2860_rf2850;
3569198429Srpaulo	uint32_t r2, r3, r4;
3570220720Sbschmidt	int8_t txpow1, txpow2;
3571220720Sbschmidt	int i;
3572220720Sbschmidt
3573178676Ssam	/* find the settings for this channel (we know it exists) */
3574178676Ssam	for (i = 0; rfprog[i].chan != chan; i++);
3575178676Ssam
3576198429Srpaulo	r2 = rfprog[i].r2;
3577198429Srpaulo	if (sc->ntxchains == 1)
3578221648Sbschmidt		r2 |= 1 << 12;		/* 1T: disable Tx chain 2 */
3579221648Sbschmidt	if (sc->nrxchains == 1)
3580198429Srpaulo		r2 |= 1 << 15 | 1 << 4;	/* 1R: disable Rx chains 2 & 3 */
3581201209Srpaulo	else if (sc->nrxchains == 2)
3582198429Srpaulo		r2 |= 1 << 4;		/* 2R: disable Rx chain 3 */
3583198429Srpaulo
3584198429Srpaulo	/* use Tx power values from EEPROM */
3585201209Srpaulo	txpow1 = sc->txpow1[i];
3586198429Srpaulo	txpow2 = sc->txpow2[i];
3587201209Srpaulo	if (chan > 14) {
3588198429Srpaulo		if (txpow1 >= 0)
3589198429Srpaulo			txpow1 = txpow1 << 1 | 1;
3590198429Srpaulo		else
3591198429Srpaulo			txpow1 = (7 + txpow1) << 1;
3592198429Srpaulo		if (txpow2 >= 0)
3593198429Srpaulo			txpow2 = txpow2 << 1 | 1;
3594198429Srpaulo		else
3595201209Srpaulo			txpow2 = (7 + txpow2) << 1;
3596198429Srpaulo	}
3597198429Srpaulo	r3 = rfprog[i].r3 | txpow1 << 7;
3598198429Srpaulo	r4 = rfprog[i].r4 | sc->freq << 13 | txpow2 << 4;
3599198429Srpaulo
3600198429Srpaulo	run_rt2870_rf_write(sc, RT2860_RF1, rfprog[i].r1);
3601198429Srpaulo	run_rt2870_rf_write(sc, RT2860_RF2, r2);
3602198429Srpaulo	run_rt2870_rf_write(sc, RT2860_RF3, r3);
3603198429Srpaulo	run_rt2870_rf_write(sc, RT2860_RF4, r4);
3604198429Srpaulo
3605198429Srpaulo	run_delay(sc, 10);
3606198429Srpaulo
3607198429Srpaulo	run_rt2870_rf_write(sc, RT2860_RF1, rfprog[i].r1);
3608198429Srpaulo	run_rt2870_rf_write(sc, RT2860_RF2, r2);
3609198429Srpaulo	run_rt2870_rf_write(sc, RT2860_RF3, r3 | 1);
3610198429Srpaulo	run_rt2870_rf_write(sc, RT2860_RF4, r4);
3611198429Srpaulo
3612198429Srpaulo	run_delay(sc, 10);
3613198429Srpaulo
3614198429Srpaulo	run_rt2870_rf_write(sc, RT2860_RF1, rfprog[i].r1);
3615198429Srpaulo	run_rt2870_rf_write(sc, RT2860_RF2, r2);
3616198429Srpaulo	run_rt2870_rf_write(sc, RT2860_RF3, r3);
3617198429Srpaulo	run_rt2870_rf_write(sc, RT2860_RF4, r4);
3618198429Srpaulo}
3619198429Srpaulo
3620220725Sbschmidtstatic void
3621198429Srpaulorun_rt3070_set_chan(struct run_softc *sc, uint32_t chan)
3622198429Srpaulo{
3623198429Srpaulo	int8_t txpow1, txpow2;
3624198429Srpaulo	uint8_t rf;
3625198429Srpaulo	int i;
3626198429Srpaulo
3627198429Srpaulo	/* RT3070 is 2GHz only */
3628198429Srpaulo	KASSERT(chan >= 1 && chan <= 14, ("wrong channel selected\n"));
3629198429Srpaulo
3630198429Srpaulo	/* find the settings for this channel (we know it exists) */
3631198429Srpaulo	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
3632198429Srpaulo
3633201209Srpaulo	/* use Tx power values from EEPROM */
3634198429Srpaulo	txpow1 = sc->txpow1[i];
3635198429Srpaulo	txpow2 = sc->txpow2[i];
3636198429Srpaulo
3637198429Srpaulo	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
3638198429Srpaulo	run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k);
3639198429Srpaulo	run_rt3070_rf_read(sc, 6, &rf);
3640198429Srpaulo	rf = (rf & ~0x03) | rt3070_freqs[i].r;
3641198429Srpaulo	run_rt3070_rf_write(sc, 6, rf);
3642198429Srpaulo
3643198429Srpaulo	/* set Tx0 power */
3644198429Srpaulo	run_rt3070_rf_read(sc, 12, &rf);
3645201209Srpaulo	rf = (rf & ~0x1f) | txpow1;
3646198429Srpaulo	run_rt3070_rf_write(sc, 12, rf);
3647198429Srpaulo
3648198429Srpaulo	/* set Tx1 power */
3649198429Srpaulo	run_rt3070_rf_read(sc, 13, &rf);
3650220728Sbschmidt	rf = (rf & ~0x1f) | txpow2;
3651198429Srpaulo	run_rt3070_rf_write(sc, 13, rf);
3652198429Srpaulo
3653198429Srpaulo	run_rt3070_rf_read(sc, 1, &rf);
3654221648Sbschmidt	rf &= ~0xfc;
3655221648Sbschmidt	if (sc->ntxchains == 1)
3656221648Sbschmidt		rf |= 1 << 7 | 1 << 5;	/* 1T: disable Tx chains 2 & 3 */
3657221648Sbschmidt	else if (sc->ntxchains == 2)
3658201209Srpaulo		rf |= 1 << 7;		/* 2T: disable Tx chain 3 */
3659201209Srpaulo	if (sc->nrxchains == 1)
3660201209Srpaulo		rf |= 1 << 6 | 1 << 4;	/* 1R: disable Rx chains 2 & 3 */
3661221648Sbschmidt	else if (sc->nrxchains == 2)
3662198429Srpaulo		rf |= 1 << 6;		/* 2R: disable Rx chain 3 */
3663220694Sbschmidt	run_rt3070_rf_write(sc, 1, rf);
3664220694Sbschmidt
3665198429Srpaulo	/* set RF offset */
3666198429Srpaulo	run_rt3070_rf_read(sc, 23, &rf);
3667198429Srpaulo	rf = (rf & ~0x7f) | sc->freq;
3668198429Srpaulo	run_rt3070_rf_write(sc, 23, rf);
3669198429Srpaulo
3670201209Srpaulo	/* program RF filter */
3671198429Srpaulo	run_rt3070_rf_read(sc, 24, &rf);	/* Tx */
3672198429Srpaulo	rf = (rf & ~0x3f) | sc->rf24_20mhz;
3673198429Srpaulo	run_rt3070_rf_write(sc, 24, rf);
3674220700Sbschmidt	run_rt3070_rf_read(sc, 31, &rf);	/* Rx */
3675220700Sbschmidt	rf = (rf & ~0x3f) | sc->rf24_20mhz;
3676220700Sbschmidt	run_rt3070_rf_write(sc, 31, rf);
3677220700Sbschmidt
3678220700Sbschmidt	/* enable RF tuning */
3679220700Sbschmidt	run_rt3070_rf_read(sc, 7, &rf);
3680220700Sbschmidt	run_rt3070_rf_write(sc, 7, rf | 0x01);
3681220700Sbschmidt}
3682178676Ssam
3683220700Sbschmidtstatic void
3684220700Sbschmidtrun_rt3572_set_chan(struct run_softc *sc, u_int chan)
3685220700Sbschmidt{
3686220700Sbschmidt	int8_t txpow1, txpow2;
3687220700Sbschmidt	uint32_t tmp;
3688220700Sbschmidt	uint8_t rf;
3689220700Sbschmidt	int i;
3690220700Sbschmidt
3691220700Sbschmidt	/* find the settings for this channel (we know it exists) */
3692220700Sbschmidt	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
3693220700Sbschmidt
3694220700Sbschmidt	/* use Tx power values from EEPROM */
3695178676Ssam	txpow1 = sc->txpow1[i];
3696178676Ssam	txpow2 = sc->txpow2[i];
3697220700Sbschmidt
3698201209Srpaulo	if (chan <= 14) {
3699178676Ssam		run_bbp_write(sc, 25, sc->bbp25);
3700178676Ssam		run_bbp_write(sc, 26, sc->bbp26);
3701178676Ssam	} else {
3702178676Ssam		/* enable IQ phase correction */
3703201209Srpaulo		run_bbp_write(sc, 25, 0x09);
3704178676Ssam		run_bbp_write(sc, 26, 0xff);
3705178676Ssam	}
3706178676Ssam
3707201209Srpaulo	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
3708178676Ssam	run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k);
3709198429Srpaulo	run_rt3070_rf_read(sc, 6, &rf);
3710220700Sbschmidt	rf  = (rf & ~0x0f) | rt3070_freqs[i].r;
3711220700Sbschmidt	rf |= (chan <= 14) ? 0x08 : 0x04;
3712220700Sbschmidt	run_rt3070_rf_write(sc, 6, rf);
3713198429Srpaulo
3714201209Srpaulo	/* set PLL mode */
3715201209Srpaulo	run_rt3070_rf_read(sc, 5, &rf);
3716198429Srpaulo	rf &= ~(0x08 | 0x04);
3717198429Srpaulo	rf |= (chan <= 14) ? 0x04 : 0x08;
3718220700Sbschmidt	run_rt3070_rf_write(sc, 5, rf);
3719178676Ssam
3720220700Sbschmidt	/* set Tx power for chain 0 */
3721220700Sbschmidt	if (chan <= 14)
3722220700Sbschmidt		rf = 0x60 | txpow1;
3723220700Sbschmidt	else
3724178676Ssam		rf = 0xe0 | (txpow1 & 0xc) << 1 | (txpow1 & 0x3);
3725178676Ssam	run_rt3070_rf_write(sc, 12, rf);
3726201209Srpaulo
3727201209Srpaulo	/* set Tx power for chain 1 */
3728201209Srpaulo	if (chan <= 14)
3729201209Srpaulo		rf = 0x60 | txpow2;
3730201209Srpaulo	else
3731201209Srpaulo		rf = 0xe0 | (txpow2 & 0xc) << 1 | (txpow2 & 0x3);
3732198429Srpaulo	run_rt3070_rf_write(sc, 13, rf);
3733220728Sbschmidt
3734178676Ssam	/* set Tx/Rx streams */
3735198429Srpaulo	run_rt3070_rf_read(sc, 1, &rf);
3736178676Ssam	rf &= ~0xfc;
3737198429Srpaulo	if (sc->ntxchains == 1)
3738178676Ssam		rf |= 1 << 7 | 1 << 5;  /* 1T: disable Tx chains 2 & 3 */
3739198429Srpaulo	else if (sc->ntxchains == 2)
3740198429Srpaulo		rf |= 1 << 7;           /* 2T: disable Tx chain 3 */
3741198429Srpaulo	if (sc->nrxchains == 1)
3742178676Ssam		rf |= 1 << 6 | 1 << 4;  /* 1R: disable Rx chains 2 & 3 */
3743178676Ssam	else if (sc->nrxchains == 2)
3744178676Ssam		rf |= 1 << 6;           /* 2R: disable Rx chain 3 */
3745178676Ssam	run_rt3070_rf_write(sc, 1, rf);
3746178676Ssam
3747178676Ssam	/* set RF offset */
3748220720Sbschmidt	run_rt3070_rf_read(sc, 23, &rf);
3749178676Ssam	rf = (rf & ~0x7f) | sc->freq;
3750178676Ssam	run_rt3070_rf_write(sc, 23, rf);
3751178676Ssam
3752178676Ssam	/* program RF filter */
3753198429Srpaulo	rf = sc->rf24_20mhz;
3754178676Ssam	run_rt3070_rf_write(sc, 24, rf);	/* Tx */
3755178676Ssam	run_rt3070_rf_write(sc, 31, rf);	/* Rx */
3756178676Ssam
3757178676Ssam	/* enable RF tuning */
3758178676Ssam	run_rt3070_rf_read(sc, 7, &rf);
3759178676Ssam	rf = (chan <= 14) ? 0xd8 : ((rf & ~0xc8) | 0x14);
3760178676Ssam	run_rt3070_rf_write(sc, 7, rf);
3761178676Ssam
3762178676Ssam	/* TSSI */
3763178676Ssam	rf = (chan <= 14) ? 0xc3 : 0xc0;
3764178676Ssam	run_rt3070_rf_write(sc, 9, rf);
3765178676Ssam
3766178676Ssam	/* set loop filter 1 */
3767220720Sbschmidt	run_rt3070_rf_write(sc, 10, 0xf1);
3768178676Ssam	/* set loop filter 2 */
3769178676Ssam	run_rt3070_rf_write(sc, 11, (chan <= 14) ? 0xb9 : 0x00);
3770178676Ssam
3771178676Ssam	/* set tx_mx2_ic */
3772178676Ssam	run_rt3070_rf_write(sc, 15, (chan <= 14) ? 0x53 : 0x43);
3773220720Sbschmidt	/* set tx_mx1_ic */
3774178676Ssam	if (chan <= 14)
3775178676Ssam		rf = 0x48 | sc->txmixgain_2ghz;
3776178676Ssam	else
3777178676Ssam		rf = 0x78 | sc->txmixgain_5ghz;
3778178676Ssam	run_rt3070_rf_write(sc, 16, rf);
3779178676Ssam
3780220667Sbschmidt	/* set tx_lo1 */
3781220667Sbschmidt	run_rt3070_rf_write(sc, 17, 0x23);
3782178676Ssam	/* set tx_lo2 */
3783178676Ssam	if (chan <= 14)
3784178676Ssam		rf = 0x93;
3785178676Ssam	else if (chan <= 64)
3786206477Sbschmidt		rf = 0xb7;
3787198429Srpaulo	else if (chan <= 128)
3788198429Srpaulo		rf = 0x74;
3789198429Srpaulo	else
3790198429Srpaulo		rf = 0x72;
3791198429Srpaulo	run_rt3070_rf_write(sc, 19, rf);
3792198429Srpaulo
3793198429Srpaulo	/* set rx_lo1 */
3794198429Srpaulo	if (chan <= 14)
3795198429Srpaulo		rf = 0xb3;
3796206477Sbschmidt	else if (chan <= 64)
3797198429Srpaulo		rf = 0xf6;
3798198429Srpaulo	else if (chan <= 128)
3799198429Srpaulo		rf = 0xf4;
3800198429Srpaulo	else
3801198429Srpaulo		rf = 0xf3;
3802198429Srpaulo	run_rt3070_rf_write(sc, 20, rf);
3803198429Srpaulo
3804198429Srpaulo	/* set pfd_delay */
3805220720Sbschmidt	if (chan <= 14)
3806220720Sbschmidt		rf = 0x15;
3807220720Sbschmidt	else if (chan <= 64)
3808220720Sbschmidt		rf = 0x3d;
3809198429Srpaulo	else
3810198429Srpaulo		rf = 0x01;
3811198429Srpaulo	run_rt3070_rf_write(sc, 25, rf);
3812198429Srpaulo
3813198429Srpaulo	/* set rx_lo2 */
3814198429Srpaulo	run_rt3070_rf_write(sc, 26, (chan <= 14) ? 0x85 : 0x87);
3815198429Srpaulo	/* set ldo_rf_vc */
3816198429Srpaulo	run_rt3070_rf_write(sc, 27, (chan <= 14) ? 0x00 : 0x01);
3817198429Srpaulo	/* set drv_cc */
3818220720Sbschmidt	run_rt3070_rf_write(sc, 29, (chan <= 14) ? 0x9b : 0x9f);
3819220720Sbschmidt
3820198429Srpaulo	run_read(sc, RT2860_GPIO_CTRL, &tmp);
3821220720Sbschmidt	tmp &= ~0x8080;
3822198429Srpaulo	if (chan <= 14)
3823198429Srpaulo		tmp |= 0x80;
3824198429Srpaulo	run_write(sc, RT2860_GPIO_CTRL, tmp);
3825198429Srpaulo
3826198429Srpaulo	/* enable RF tuning */
3827178676Ssam	run_rt3070_rf_read(sc, 7, &rf);
3828220667Sbschmidt	run_rt3070_rf_write(sc, 7, rf | 0x01);
3829178676Ssam
3830220667Sbschmidt	run_delay(sc, 2);
3831220667Sbschmidt}
3832220667Sbschmidt
3833178676Ssamstatic void
3834220667Sbschmidtrun_set_rx_antenna(struct run_softc *sc, int aux)
3835220667Sbschmidt{
3836220667Sbschmidt	uint32_t tmp;
3837220667Sbschmidt
3838220668Sbschmidt	if (aux) {
3839220668Sbschmidt		run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 0);
3840220667Sbschmidt		run_read(sc, RT2860_GPIO_CTRL, &tmp);
3841220667Sbschmidt		run_write(sc, RT2860_GPIO_CTRL, (tmp & ~0x0808) | 0x08);
3842220667Sbschmidt	} else {
3843220667Sbschmidt		run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 1);
3844178676Ssam		run_read(sc, RT2860_GPIO_CTRL, &tmp);
3845220667Sbschmidt		run_write(sc, RT2860_GPIO_CTRL, tmp & ~0x0808);
3846178676Ssam	}
3847178676Ssam}
3848206477Sbschmidt
3849178676Ssamstatic int
3850178676Ssamrun_set_chan(struct run_softc *sc, struct ieee80211_channel *c)
3851178676Ssam{
3852178676Ssam	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
3853201209Srpaulo	uint32_t chan, group;
3854178676Ssam
3855201209Srpaulo	chan = ieee80211_chan2ieee(ic, c);
3856178676Ssam	if (chan == 0 || chan == IEEE80211_CHAN_ANY)
3857178676Ssam		return (EINVAL);
3858220723Sbschmidt
3859220723Sbschmidt	if (sc->mac_ver == 0x3572)
3860220723Sbschmidt		run_rt3572_set_chan(sc, chan);
3861178676Ssam	else if (sc->mac_ver >= 0x3070)
3862178704Sthompsa		run_rt3070_set_chan(sc, chan);
3863178676Ssam	else
3864178676Ssam		run_rt2870_set_chan(sc, chan);
3865178676Ssam
3866201209Srpaulo	/* determine channel group */
3867201209Srpaulo	if (chan <= 14)
3868201209Srpaulo		group = 0;
3869201209Srpaulo	else if (chan <= 64)
3870178676Ssam		group = 1;
3871178676Ssam	else if (chan <= 128)
3872178676Ssam		group = 2;
3873178676Ssam	else
3874178676Ssam		group = 3;
3875178704Sthompsa
3876178704Sthompsa	/* XXX necessary only when group has changed! */
3877178704Sthompsa	run_select_chan_group(sc, group);
3878201209Srpaulo
3879201209Srpaulo	run_delay(sc, 10);
3880178676Ssam
3881178676Ssam	return (0);
3882178676Ssam}
3883178676Ssam
3884178704Sthompsastatic void
3885178704Sthompsarun_set_channel(struct ieee80211com *ic)
3886178704Sthompsa{
3887178676Ssam	struct run_softc *sc = ic->ic_ifp->if_softc;
3888178676Ssam
3889178676Ssam	RUN_LOCK(sc);
3890178676Ssam	run_set_chan(sc, ic->ic_curchan);
3891178676Ssam	RUN_UNLOCK(sc);
3892178676Ssam
3893178676Ssam	return;
3894206477Sbschmidt}
3895178676Ssam
3896178676Ssamstatic void
3897221651Sbschmidtrun_scan_start(struct ieee80211com *ic)
3898178676Ssam{
3899178676Ssam	struct run_softc *sc = ic->ic_ifp->if_softc;
3900198429Srpaulo	uint32_t tmp;
3901178676Ssam
3902198439Srpaulo	RUN_LOCK(sc);
3903178676Ssam
3904198439Srpaulo	/* abort TSF synchronization */
3905178676Ssam	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
3906221650Sbschmidt	run_write(sc, RT2860_BCN_TIME_CFG,
3907221650Sbschmidt	    tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
3908178676Ssam	    RT2860_TBTT_TIMER_EN));
3909178676Ssam	run_set_bssid(sc, sc->sc_ifp->if_broadcastaddr);
3910198429Srpaulo
3911198429Srpaulo	RUN_UNLOCK(sc);
3912178676Ssam
3913198439Srpaulo	return;
3914198439Srpaulo}
3915198439Srpaulo
3916198439Srpaulostatic void
3917201209Srpaulorun_scan_end(struct ieee80211com *ic)
3918198439Srpaulo{
3919198439Srpaulo	struct run_softc *sc = ic->ic_ifp->if_softc;
3920198439Srpaulo
3921201209Srpaulo	RUN_LOCK(sc);
3922198439Srpaulo
3923198439Srpaulo	run_enable_tsf_sync(sc);
3924198439Srpaulo	/* XXX keep local copy */
3925198439Srpaulo	run_set_bssid(sc, sc->sc_bssid);
3926198439Srpaulo
3927198439Srpaulo	RUN_UNLOCK(sc);
3928198439Srpaulo
3929198439Srpaulo	return;
3930198439Srpaulo}
3931198439Srpaulo
3932198439Srpaulo/*
3933178676Ssam * Could be called from ieee80211_node_timeout()
3934178676Ssam * (non-sleepable thread)
3935178676Ssam */
3936178676Ssamstatic void
3937178676Ssamrun_update_beacon(struct ieee80211vap *vap, int item)
3938178676Ssam{
3939198429Srpaulo	struct ieee80211com *ic = vap->iv_ic;
3940198429Srpaulo	struct run_softc *sc = ic->ic_ifp->if_softc;
3941198429Srpaulo	struct run_vap *rvp = RUN_VAP(vap);
3942178676Ssam	int mcast = 0;
3943178676Ssam	uint32_t i;
3944178676Ssam
3945178676Ssam	KASSERT(vap != NULL, ("no beacon"));
3946178676Ssam
3947198439Srpaulo	switch (item) {
3948201209Srpaulo	case IEEE80211_BEACON_ERP:
3949198439Srpaulo		run_updateslot(ic->ic_ifp);
3950198439Srpaulo		break;
3951201209Srpaulo	case IEEE80211_BEACON_HTINFO:
3952198439Srpaulo		run_updateprot(ic);
3953198439Srpaulo		break;
3954198439Srpaulo	case IEEE80211_BEACON_TIM:
3955198439Srpaulo		mcast = 1;	/*TODO*/
3956198439Srpaulo		break;
3957198429Srpaulo	default:
3958220728Sbschmidt		break;
3959198429Srpaulo	}
3960198429Srpaulo
3961178676Ssam	setbit(rvp->bo.bo_flags, item);
3962198429Srpaulo	ieee80211_beacon_update(vap->iv_bss, &rvp->bo, rvp->beacon_mbuf, mcast);
3963178676Ssam
3964198439Srpaulo	i = RUN_CMDQ_GET(&sc->cmdq_store);
3965178676Ssam	DPRINTF("cmdq_store=%d\n", i);
3966178676Ssam	sc->cmdq[i].func = run_update_beacon_cb;
3967206477Sbschmidt	sc->cmdq[i].arg0 = vap;
3968198429Srpaulo	ieee80211_runtask(ic, &sc->cmdq_task);
3969198429Srpaulo
3970198429Srpaulo	return;
3971198429Srpaulo}
3972198429Srpaulo
3973198429Srpaulostatic void
3974198429Srpaulorun_update_beacon_cb(void *arg)
3975198429Srpaulo{
3976198429Srpaulo	struct ieee80211vap *vap = arg;
3977198429Srpaulo	struct run_vap *rvp = RUN_VAP(vap);
3978198429Srpaulo	struct ieee80211com *ic = vap->iv_ic;
3979198429Srpaulo	struct run_softc *sc = ic->ic_ifp->if_softc;
3980198429Srpaulo	struct rt2860_txwi txwi;
3981198429Srpaulo	struct mbuf *m;
3982198429Srpaulo	uint8_t ridx;
3983198429Srpaulo
3984198429Srpaulo	if (vap->iv_bss->ni_chan == IEEE80211_CHAN_ANYC)
3985198429Srpaulo		return;
3986206477Sbschmidt	if (ic->ic_bsschan == IEEE80211_CHAN_ANYC)
3987198429Srpaulo		return;
3988198429Srpaulo
3989198429Srpaulo	/*
3990198429Srpaulo	 * No need to call ieee80211_beacon_update(), run_update_beacon()
3991198429Srpaulo	 * is taking care of apropriate calls.
3992198429Srpaulo	 */
3993206477Sbschmidt	if (rvp->beacon_mbuf == NULL) {
3994220715Sbschmidt		rvp->beacon_mbuf = ieee80211_beacon_alloc(vap->iv_bss,
3995178676Ssam		    &rvp->bo);
3996220715Sbschmidt		if (rvp->beacon_mbuf == NULL)
3997220715Sbschmidt			return;
3998198429Srpaulo	}
3999220715Sbschmidt	m = rvp->beacon_mbuf;
4000221648Sbschmidt
4001178676Ssam	memset(&txwi, 0, sizeof txwi);
4002198429Srpaulo	txwi.wcid = 0xff;
4003201209Srpaulo	txwi.len = htole16(m->m_pkthdr.len);
4004178676Ssam	/* send beacons at the lowest available rate */
4005198429Srpaulo	ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
4006220715Sbschmidt	    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
4007198429Srpaulo	txwi.phy = htole16(rt2860_rates[ridx].mcs);
4008201209Srpaulo	if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM)
4009221651Sbschmidt	        txwi.phy |= htole16(RT2860_PHY_OFDM);
4010198429Srpaulo	txwi.txop = RT2860_TX_TXOP_HT;
4011198429Srpaulo	txwi.flags = RT2860_TX_TS;
4012198429Srpaulo	txwi.xflags = RT2860_TX_NSEQ;
4013220715Sbschmidt
4014221649Sbschmidt	run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id),
4015221649Sbschmidt	    (uint8_t *)&txwi, sizeof txwi);
4016221649Sbschmidt	run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id) + sizeof txwi,
4017221649Sbschmidt	    mtod(m, uint8_t *), (m->m_pkthdr.len + 1) & ~1);	/* roundup len */
4018178676Ssam
4019221649Sbschmidt	return;
4020221649Sbschmidt}
4021221649Sbschmidt
4022221649Sbschmidtstatic void
4023221648Sbschmidtrun_updateprot(struct ieee80211com *ic)
4024221648Sbschmidt{
4025221649Sbschmidt	struct run_softc *sc = ic->ic_ifp->if_softc;
4026221649Sbschmidt	uint32_t i;
4027221649Sbschmidt
4028221649Sbschmidt	i = RUN_CMDQ_GET(&sc->cmdq_store);
4029220715Sbschmidt	DPRINTF("cmdq_store=%d\n", i);
4030220715Sbschmidt	sc->cmdq[i].func = run_updateprot_cb;
4031220715Sbschmidt	sc->cmdq[i].arg0 = ic;
4032178676Ssam	ieee80211_runtask(ic, &sc->cmdq_task);
4033220715Sbschmidt}
4034178676Ssam
4035178676Ssamstatic void
4036178676Ssamrun_updateprot_cb(void *arg)
4037198429Srpaulo{
4038178676Ssam	struct ieee80211com *ic = arg;
4039206477Sbschmidt	struct run_softc *sc = ic->ic_ifp->if_softc;
4040201209Srpaulo	uint32_t tmp;
4041178676Ssam
4042220728Sbschmidt	tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL;
4043198429Srpaulo	/* setup protection frame rate (MCS code) */
4044220715Sbschmidt	tmp |= (ic->ic_curmode == IEEE80211_MODE_11A) ?
4045178676Ssam	    rt2860_rates[RT2860_RIDX_OFDM6].mcs :
4046220715Sbschmidt	    rt2860_rates[RT2860_RIDX_CCK11].mcs;
4047220715Sbschmidt
4048220715Sbschmidt	/* CCK frames don't require protection */
4049178676Ssam	run_write(sc, RT2860_CCK_PROT_CFG, tmp);
4050178676Ssam	if (ic->ic_flags & IEEE80211_F_USEPROT) {
4051198429Srpaulo		if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
4052220728Sbschmidt			tmp |= RT2860_PROT_CTRL_RTS_CTS;
4053198429Srpaulo		else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
4054220728Sbschmidt			tmp |= RT2860_PROT_CTRL_CTS;
4055198429Srpaulo	}
4056178676Ssam	run_write(sc, RT2860_OFDM_PROT_CFG, tmp);
4057220715Sbschmidt}
4058220715Sbschmidt
4059220715Sbschmidtstatic void
4060220715Sbschmidtrun_usb_timeout_cb(void *arg)
4061220728Sbschmidt{
4062220715Sbschmidt	struct ieee80211vap *vap = arg;
4063220715Sbschmidt	struct run_softc *sc = vap->iv_ic->ic_ifp->if_softc;
4064220715Sbschmidt
4065220715Sbschmidt	RUN_LOCK_ASSERT(sc, MA_OWNED);
4066220715Sbschmidt
4067220715Sbschmidt	if(vap->iv_state == IEEE80211_S_RUN &&
4068220715Sbschmidt	    vap->iv_opmode != IEEE80211_M_STA)
4069220715Sbschmidt		run_reset_livelock(sc);
4070221648Sbschmidt	else if (vap->iv_state == IEEE80211_S_SCAN) {
4071220715Sbschmidt		DPRINTF("timeout caused by scan\n");
4072221648Sbschmidt		/* cancel bgscan */
4073221648Sbschmidt		ieee80211_cancel_scan(vap);
4074220715Sbschmidt	} else
4075220715Sbschmidt		DPRINTF("timeout by unknown cause\n");
4076221648Sbschmidt}
4077220715Sbschmidt
4078220715Sbschmidtstatic void
4079178676Ssamrun_reset_livelock(struct run_softc *sc)
4080178676Ssam{
4081206477Sbschmidt	uint32_t tmp;
4082220721Sbschmidt
4083178676Ssam	RUN_LOCK_ASSERT(sc, MA_OWNED);
4084178676Ssam
4085178676Ssam	/*
4086178676Ssam	 * In IBSS or HostAP modes (when the hardware sends beacons), the MAC
4087220721Sbschmidt	 * can run into a livelock and start sending CTS-to-self frames like
4088178676Ssam	 * crazy if protection is enabled.  Reset MAC/BBP for a while
4089178676Ssam	 */
4090178676Ssam	run_read(sc, RT2860_DEBUG, &tmp);
4091220721Sbschmidt	DPRINTFN(3, "debug reg %08x\n", tmp);
4092220721Sbschmidt	if ((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))) {
4093220721Sbschmidt		DPRINTF("CTS-to-self livelock detected\n");
4094220721Sbschmidt		run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST);
4095220721Sbschmidt		run_delay(sc, 1);
4096220721Sbschmidt		run_write(sc, RT2860_MAC_SYS_CTRL,
4097220721Sbschmidt		    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
4098220721Sbschmidt	}
4099178676Ssam}
4100201209Srpaulo
4101178676Ssamstatic void
4102220725Sbschmidtrun_update_promisc_locked(struct ifnet *ifp)
4103178676Ssam{
4104201209Srpaulo	struct run_softc *sc = ifp->if_softc;
4105178676Ssam        uint32_t tmp;
4106178676Ssam
4107178676Ssam	run_read(sc, RT2860_RX_FILTR_CFG, &tmp);
4108178676Ssam
4109201209Srpaulo	tmp |= RT2860_DROP_UC_NOME;
4110201209Srpaulo        if (ifp->if_flags & IFF_PROMISC)
4111201209Srpaulo		tmp &= ~RT2860_DROP_UC_NOME;
4112201209Srpaulo
4113201209Srpaulo	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
4114201209Srpaulo
4115206477Sbschmidt        DPRINTF("%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ?
4116178676Ssam            "entering" : "leaving");
4117178676Ssam}
4118178676Ssam
4119178676Ssamstatic void
4120198429Srpaulorun_update_promisc(struct ifnet *ifp)
4121198429Srpaulo{
4122198429Srpaulo	struct run_softc *sc = ifp->if_softc;
4123178676Ssam
4124198429Srpaulo	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
4125178676Ssam		return;
4126178676Ssam
4127198429Srpaulo	RUN_LOCK(sc);
4128178676Ssam	run_update_promisc_locked(ifp);
4129178676Ssam	RUN_UNLOCK(sc);
4130178676Ssam}
4131201209Srpaulo
4132201209Srpaulostatic void
4133178676Ssamrun_enable_tsf_sync(struct run_softc *sc)
4134206477Sbschmidt{
4135178676Ssam	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
4136178676Ssam	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
4137178676Ssam	uint32_t tmp;
4138201209Srpaulo
4139178676Ssam	DPRINTF("rvp_id=%d ic_opmode=%d\n", RUN_VAP(vap)->rvp_id, ic->ic_opmode);
4140198429Srpaulo
4141178676Ssam	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
4142201209Srpaulo	tmp &= ~0x1fffff;
4143201209Srpaulo	tmp |= vap->iv_bss->ni_intval * 16;
4144201209Srpaulo	tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN;
4145201209Srpaulo
4146201209Srpaulo	if (ic->ic_opmode == IEEE80211_M_STA) {
4147201209Srpaulo		/*
4148178676Ssam		 * Local TSF is always updated with remote TSF on beacon
4149201209Srpaulo		 * reception.
4150220726Sbschmidt		 */
4151178676Ssam		tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT;
4152178676Ssam	} else if (ic->ic_opmode == IEEE80211_M_IBSS) {
4153178676Ssam	        tmp |= RT2860_BCN_TX_EN;
4154206477Sbschmidt	        /*
4155198429Srpaulo	         * Local TSF is updated with remote TSF on beacon reception
4156178676Ssam	         * only if the remote TSF is greater than local TSF.
4157198429Srpaulo	         */
4158178676Ssam	        tmp |= 2 << RT2860_TSF_SYNC_MODE_SHIFT;
4159178676Ssam	} else if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
4160198429Srpaulo		    ic->ic_opmode == IEEE80211_M_MBSS) {
4161198429Srpaulo	        tmp |= RT2860_BCN_TX_EN;
4162198429Srpaulo	        /* SYNC with nobody */
4163198429Srpaulo	        tmp |= 3 << RT2860_TSF_SYNC_MODE_SHIFT;
4164178676Ssam	} else {
4165198429Srpaulo		DPRINTF("Enabling TSF failed. undefined opmode\n");
4166220634Sbschmidt		return;
4167198429Srpaulo	}
4168198429Srpaulo
4169178676Ssam	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
4170198429Srpaulo}
4171198429Srpaulo
4172178676Ssamstatic void
4173198429Srpaulorun_enable_mrr(struct run_softc *sc)
4174178676Ssam{
4175178676Ssam#define CCK(mcs)	(mcs)
4176206477Sbschmidt#define OFDM(mcs)	(1 << 3 | (mcs))
4177198429Srpaulo	run_write(sc, RT2860_LG_FBK_CFG0,
4178178676Ssam	    OFDM(6) << 28 |	/* 54->48 */
4179201882Skeramida	    OFDM(5) << 24 |	/* 48->36 */
4180201882Skeramida	    OFDM(4) << 20 |	/* 36->24 */
4181201882Skeramida	    OFDM(3) << 16 |	/* 24->18 */
4182220725Sbschmidt	    OFDM(2) << 12 |	/* 18->12 */
4183178676Ssam	    OFDM(1) <<  8 |	/* 12-> 9 */
4184178676Ssam	    OFDM(0) <<  4 |	/*  9-> 6 */
4185198429Srpaulo	    OFDM(0));		/*  6-> 6 */
4186198429Srpaulo
4187198429Srpaulo	run_write(sc, RT2860_LG_FBK_CFG1,
4188201882Skeramida	    CCK(2) << 12 |	/* 11->5.5 */
4189178676Ssam	    CCK(1) <<  8 |	/* 5.5-> 2 */
4190178676Ssam	    CCK(0) <<  4 |	/*   2-> 1 */
4191178676Ssam	    CCK(0));		/*   1-> 1 */
4192178676Ssam#undef OFDM
4193198429Srpaulo#undef CCK
4194178676Ssam}
4195178676Ssam
4196178676Ssamstatic void
4197206477Sbschmidtrun_set_txpreamble(struct run_softc *sc)
4198201882Skeramida{
4199201882Skeramida	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
4200178676Ssam	uint32_t tmp;
4201198429Srpaulo
4202178676Ssam	run_read(sc, RT2860_AUTO_RSP_CFG, &tmp);
4203178676Ssam	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
4204198429Srpaulo		tmp |= RT2860_CCK_SHORT_EN;
4205178676Ssam	else
4206178676Ssam		tmp &= ~RT2860_CCK_SHORT_EN;
4207178676Ssam	run_write(sc, RT2860_AUTO_RSP_CFG, tmp);
4208178676Ssam}
4209178676Ssam
4210198429Srpaulostatic void
4211198429Srpaulorun_set_basicrates(struct run_softc *sc)
4212220723Sbschmidt{
4213178676Ssam	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
4214178676Ssam
4215198429Srpaulo	/* set basic rates mask */
4216178676Ssam	if (ic->ic_curmode == IEEE80211_MODE_11B)
4217220687Sbschmidt		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x003);
4218220687Sbschmidt	else if (ic->ic_curmode == IEEE80211_MODE_11A)
4219201209Srpaulo		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x150);
4220201209Srpaulo	else	/* 11g */
4221178676Ssam		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x15f);
4222178676Ssam}
4223178676Ssam
4224178676Ssamstatic void
4225178676Ssamrun_set_leds(struct run_softc *sc, uint16_t which)
4226178676Ssam{
4227178676Ssam	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LEDS,
4228198429Srpaulo	    which | (sc->leds & 0x7f));
4229198429Srpaulo}
4230178676Ssam
4231178676Ssamstatic void
4232198429Srpaulorun_set_bssid(struct run_softc *sc, const uint8_t *bssid)
4233198429Srpaulo{
4234178676Ssam	run_write(sc, RT2860_MAC_BSSID_DW0,
4235178676Ssam	    bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24);
4236198429Srpaulo	run_write(sc, RT2860_MAC_BSSID_DW1,
4237178676Ssam	    bssid[4] | bssid[5] << 8);
4238178676Ssam}
4239178676Ssam
4240178676Ssamstatic void
4241178676Ssamrun_set_macaddr(struct run_softc *sc, const uint8_t *addr)
4242178676Ssam{
4243178676Ssam	run_write(sc, RT2860_MAC_ADDR_DW0,
4244178676Ssam	    addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24);
4245178676Ssam	run_write(sc, RT2860_MAC_ADDR_DW1,
4246201209Srpaulo	    addr[4] | addr[5] << 8 | 0xff << 16);
4247178676Ssam}
4248178676Ssam
4249178676Ssamstatic void
4250178676Ssamrun_updateslot(struct ifnet *ifp)
4251178676Ssam{
4252178676Ssam	struct run_softc *sc = ifp->if_softc;
4253178676Ssam	struct ieee80211com *ic = ifp->if_l2com;
4254178676Ssam	uint32_t i;
4255178676Ssam
4256178676Ssam	i = RUN_CMDQ_GET(&sc->cmdq_store);
4257178676Ssam	DPRINTF("cmdq_store=%d\n", i);
4258178676Ssam	sc->cmdq[i].func = run_updateslot_cb;
4259178676Ssam	sc->cmdq[i].arg0 = ifp;
4260201209Srpaulo	ieee80211_runtask(ic, &sc->cmdq_task);
4261178676Ssam
4262178676Ssam	return;
4263178676Ssam}
4264178676Ssam
4265198429Srpaulo/* ARGSUSED */
4266198429Srpaulostatic void
4267178676Ssamrun_updateslot_cb(void *arg)
4268178676Ssam{
4269178676Ssam	struct ifnet *ifp = arg;
4270178676Ssam	struct run_softc *sc = ifp->if_softc;
4271198429Srpaulo	struct ieee80211com *ic = ifp->if_l2com;
4272178676Ssam	uint32_t tmp;
4273178676Ssam
4274178676Ssam	run_read(sc, RT2860_BKOFF_SLOT_CFG, &tmp);
4275178676Ssam	tmp &= ~0xff;
4276178676Ssam	tmp |= (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20;
4277178676Ssam	run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp);
4278178676Ssam}
4279178676Ssam
4280178676Ssamstatic void
4281178676Ssamrun_update_mcast(struct ifnet *ifp)
4282178676Ssam{
4283178676Ssam	/* h/w filter supports getting everything or nothing */
4284178676Ssam	ifp->if_flags |= IFF_ALLMULTI;
4285178676Ssam}
4286178676Ssam
4287178676Ssamstatic int8_t
4288198429Srpaulorun_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain)
4289178676Ssam{
4290178676Ssam	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
4291178676Ssam	struct ieee80211_channel *c = ic->ic_curchan;
4292178676Ssam	int delta;
4293178676Ssam
4294178676Ssam	if (IEEE80211_IS_CHAN_5GHZ(c)) {
4295201209Srpaulo		uint32_t chan = ieee80211_chan2ieee(ic, c);
4296198429Srpaulo		delta = sc->rssi_5ghz[rxchain];
4297198429Srpaulo
4298198429Srpaulo		/* determine channel group */
4299178676Ssam		if (chan <= 64)
4300198429Srpaulo			delta -= sc->lna[1];
4301178676Ssam		else if (chan <= 128)
4302198429Srpaulo			delta -= sc->lna[2];
4303198429Srpaulo		else
4304198429Srpaulo			delta -= sc->lna[3];
4305198429Srpaulo	} else
4306198429Srpaulo		delta = sc->rssi_2ghz[rxchain] - sc->lna[0];
4307198429Srpaulo
4308198429Srpaulo	return (-12 - delta - rssi);
4309198429Srpaulo}
4310198429Srpaulo
4311178676Ssamstatic int
4312201209Srpaulorun_bbp_init(struct run_softc *sc)
4313178676Ssam{
4314178676Ssam	int i, error, ntries;
4315178676Ssam	uint8_t bbp0;
4316178676Ssam
4317178676Ssam	/* wait for BBP to wake up */
4318178676Ssam	for (ntries = 0; ntries < 20; ntries++) {
4319178676Ssam		if ((error = run_bbp_read(sc, 0, &bbp0)) != 0)
4320178676Ssam			return error;
4321178676Ssam		if (bbp0 != 0 && bbp0 != 0xff)
4322178676Ssam			break;
4323178676Ssam	}
4324178676Ssam	if (ntries == 20)
4325198429Srpaulo		return (ETIMEDOUT);
4326178676Ssam
4327178676Ssam	/* initialize BBP registers to default values */
4328198429Srpaulo	for (i = 0; i < N(rt2860_def_bbp); i++) {
4329198429Srpaulo		run_bbp_write(sc, rt2860_def_bbp[i].reg,
4330178676Ssam		    rt2860_def_bbp[i].val);
4331178676Ssam	}
4332178676Ssam
4333178676Ssam	/* fix BBP84 for RT2860E */
4334178676Ssam	if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0101)
4335178676Ssam		run_bbp_write(sc, 84, 0x19);
4336178676Ssam
4337178676Ssam	if (sc->mac_ver >= 0x3070) {
4338178676Ssam		run_bbp_write(sc, 79, 0x13);
4339178676Ssam		run_bbp_write(sc, 80, 0x05);
4340178676Ssam		run_bbp_write(sc, 81, 0x33);
4341178676Ssam	} else if (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) {
4342178676Ssam		run_bbp_write(sc, 69, 0x16);
4343178676Ssam		run_bbp_write(sc, 73, 0x12);
4344178676Ssam	}
4345178676Ssam	return (0);
4346178676Ssam}
4347206477Sbschmidt
4348201882Skeramidastatic int
4349201882Skeramidarun_rt3070_rf_init(struct run_softc *sc)
4350198429Srpaulo{
4351198429Srpaulo	uint32_t tmp;
4352198429Srpaulo	uint8_t rf, target, bbp4;
4353198429Srpaulo	int i;
4354198429Srpaulo
4355198429Srpaulo	run_rt3070_rf_read(sc, 30, &rf);
4356198429Srpaulo	/* toggle RF R30 bit 7 */
4357198429Srpaulo	run_rt3070_rf_write(sc, 30, rf | 0x80);
4358198429Srpaulo	run_delay(sc, 10);
4359198429Srpaulo	run_rt3070_rf_write(sc, 30, rf & ~0x80);
4360198429Srpaulo
4361198429Srpaulo	/* initialize RF registers to default value */
4362198429Srpaulo	if (sc->mac_ver == 0x3572) {
4363198429Srpaulo		for (i = 0; i < N(rt3572_def_rf); i++) {
4364198429Srpaulo			run_rt3070_rf_write(sc, rt3572_def_rf[i].reg,
4365178676Ssam			    rt3572_def_rf[i].val);
4366198429Srpaulo		}
4367178676Ssam	} else {
4368206477Sbschmidt		for (i = 0; i < N(rt3070_def_rf); i++) {
4369198429Srpaulo			run_rt3070_rf_write(sc, rt3070_def_rf[i].reg,
4370178676Ssam			    rt3070_def_rf[i].val);
4371198429Srpaulo		}
4372198429Srpaulo	}
4373198429Srpaulo
4374178676Ssam	if (sc->mac_ver == 0x3070) {
4375201209Srpaulo		/* change voltage from 1.2V to 1.35V for RT3070 */
4376198429Srpaulo		run_read(sc, RT3070_LDO_CFG0, &tmp);
4377178676Ssam		tmp = (tmp & ~0x0f000000) | 0x0d000000;
4378178676Ssam		run_write(sc, RT3070_LDO_CFG0, tmp);
4379220689Sbschmidt
4380220689Sbschmidt	} else if (sc->mac_ver == 0x3071) {
4381220689Sbschmidt		run_rt3070_rf_read(sc, 6, &rf);
4382220689Sbschmidt		run_rt3070_rf_write(sc, 6, rf | 0x40);
4383220689Sbschmidt		run_rt3070_rf_write(sc, 31, 0x14);
4384220689Sbschmidt
4385198429Srpaulo		run_read(sc, RT3070_LDO_CFG0, &tmp);
4386220724Sbschmidt		tmp &= ~0x1f000000;
4387220724Sbschmidt		if (sc->mac_rev < 0x0211)
4388220724Sbschmidt			tmp |= 0x0d000000;	/* 1.3V */
4389178676Ssam		else
4390178676Ssam			tmp |= 0x01000000;	/* 1.2V */
4391178676Ssam		run_write(sc, RT3070_LDO_CFG0, tmp);
4392178676Ssam
4393206477Sbschmidt		/* patch LNA_PE_G1 */
4394198429Srpaulo		run_read(sc, RT3070_GPIO_SWITCH, &tmp);
4395198429Srpaulo		run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20);
4396198429Srpaulo
4397220723Sbschmidt	} else if (sc->mac_ver == 0x3572) {
4398198429Srpaulo		run_rt3070_rf_read(sc, 6, &rf);
4399198429Srpaulo		run_rt3070_rf_write(sc, 6, rf | 0x40);
4400198429Srpaulo
4401198429Srpaulo		/* increase voltage from 1.2V to 1.35V */
4402198429Srpaulo		run_read(sc, RT3070_LDO_CFG0, &tmp);
4403198429Srpaulo		tmp = (tmp & ~0x1f000000) | 0x0d000000;
4404198429Srpaulo		run_write(sc, RT3070_LDO_CFG0, tmp);
4405198429Srpaulo
4406220724Sbschmidt		if (sc->mac_rev < 0x0211 || !sc->patch_dac) {
4407220724Sbschmidt			run_delay(sc, 1);	/* wait for 1msec */
4408201822Strasz			/* decrease voltage back to 1.2V */
4409198429Srpaulo			tmp = (tmp & ~0x1f000000) | 0x01000000;
4410198429Srpaulo			run_write(sc, RT3070_LDO_CFG0, tmp);
4411198429Srpaulo		}
4412198429Srpaulo	}
4413178676Ssam
4414198429Srpaulo	/* select 20MHz bandwidth */
4415178676Ssam	run_rt3070_rf_read(sc, 31, &rf);
4416206477Sbschmidt	run_rt3070_rf_write(sc, 31, rf & ~0x20);
4417178676Ssam
4418178676Ssam	/* calibrate filter for 20MHz bandwidth */
4419178676Ssam	sc->rf24_20mhz = 0x1f;	/* default value */
4420178676Ssam	target = (sc->mac_ver < 0x3071) ? 0x16 : 0x13;
4421178676Ssam	run_rt3070_filter_calib(sc, 0x07, target, &sc->rf24_20mhz);
4422178676Ssam
4423198429Srpaulo	/* select 40MHz bandwidth */
4424198429Srpaulo	run_bbp_read(sc, 4, &bbp4);
4425198429Srpaulo	run_bbp_write(sc, 4, (bbp4 & ~0x08) | 0x10);
4426198429Srpaulo	run_rt3070_rf_read(sc, 31, &rf);
4427178676Ssam	run_rt3070_rf_write(sc, 31, rf | 0x20);
4428198429Srpaulo
4429178676Ssam	/* calibrate filter for 40MHz bandwidth */
4430178676Ssam	sc->rf24_40mhz = 0x2f;	/* default value */
4431178676Ssam	target = (sc->mac_ver < 0x3071) ? 0x19 : 0x15;
4432178676Ssam	run_rt3070_filter_calib(sc, 0x27, target, &sc->rf24_40mhz);
4433198429Srpaulo
4434178676Ssam	/* go back to 20MHz bandwidth */
4435206477Sbschmidt	run_bbp_read(sc, 4, &bbp4);
4436198429Srpaulo	run_bbp_write(sc, 4, bbp4 & ~0x18);
4437178676Ssam
4438178676Ssam	if (sc->mac_ver == 0x3572) {
4439178676Ssam		/* save default BBP registers 25 and 26 values */
4440178676Ssam		run_bbp_read(sc, 25, &sc->bbp25);
4441178676Ssam		run_bbp_read(sc, 26, &sc->bbp26);
4442178676Ssam	} else if (sc->mac_rev < 0x0211)
4443178676Ssam		run_rt3070_rf_write(sc, 27, 0x03);
4444178676Ssam
4445178676Ssam	run_read(sc, RT3070_OPT_14, &tmp);
4446220725Sbschmidt	run_write(sc, RT3070_OPT_14, tmp | 1);
4447178676Ssam
4448178676Ssam	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
4449198429Srpaulo		run_rt3070_rf_read(sc, 17, &rf);
4450220659Sbschmidt		rf &= ~RT3070_TX_LO1;
4451198429Srpaulo		if ((sc->mac_ver == 0x3070 ||
4452178676Ssam		     (sc->mac_ver == 0x3071 && sc->mac_rev >= 0x0211)) &&
4453178676Ssam		    !sc->ext_2ghz_lna)
4454178676Ssam			rf |= 0x20;	/* fix for long range Rx issue */
4455201209Srpaulo		if (sc->txmixgain_2ghz >= 1)
4456201209Srpaulo			rf = (rf & ~0x7) | sc->txmixgain_2ghz;
4457178676Ssam		run_rt3070_rf_write(sc, 17, rf);
4458178676Ssam	}
4459178676Ssam
4460206477Sbschmidt	if (sc->mac_rev == 0x3071) {
4461198429Srpaulo		run_rt3070_rf_read(sc, 1, &rf);
4462198429Srpaulo		rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD);
4463201209Srpaulo		rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD;
4464201209Srpaulo		run_rt3070_rf_write(sc, 1, rf);
4465198429Srpaulo
4466198429Srpaulo		run_rt3070_rf_read(sc, 15, &rf);
4467220725Sbschmidt		run_rt3070_rf_write(sc, 15, rf & ~RT3070_TX_LO2);
4468198429Srpaulo
4469201209Srpaulo		run_rt3070_rf_read(sc, 20, &rf);
4470201209Srpaulo		run_rt3070_rf_write(sc, 20, rf & ~RT3070_RX_LO1);
4471201209Srpaulo
4472201209Srpaulo		run_rt3070_rf_read(sc, 21, &rf);
4473201209Srpaulo		run_rt3070_rf_write(sc, 21, rf & ~RT3070_RX_LO2);
4474201209Srpaulo	}
4475198429Srpaulo
4476198429Srpaulo	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
4477178676Ssam		/* fix Tx to Rx IQ glitch by raising RF voltage */
4478178676Ssam		run_rt3070_rf_read(sc, 27, &rf);
4479178676Ssam		rf &= ~0x77;
4480206477Sbschmidt		if (sc->mac_rev < 0x0211)
4481178676Ssam			rf |= 0x03;
4482178676Ssam		run_rt3070_rf_write(sc, 27, rf);
4483220728Sbschmidt	}
4484178676Ssam	return (0);
4485198429Srpaulo}
4486178676Ssam
4487178676Ssamstatic int
4488198429Srpaulorun_rt3070_filter_calib(struct run_softc *sc, uint8_t init, uint8_t target,
4489178676Ssam    uint8_t *val)
4490178676Ssam{
4491178676Ssam	uint8_t rf22, rf24;
4492198429Srpaulo	uint8_t bbp55_pb, bbp55_sb, delta;
4493201209Srpaulo	int ntries;
4494201209Srpaulo
4495206444Sbschmidt	/* program filter */
4496201209Srpaulo	run_rt3070_rf_read(sc, 24, &rf24);
4497198429Srpaulo	rf24 = (rf24 & 0xc0) | init;	/* initial filter value */
4498201209Srpaulo	run_rt3070_rf_write(sc, 24, rf24);
4499201209Srpaulo
4500178676Ssam	/* enable baseband loopback mode */
4501198429Srpaulo	run_rt3070_rf_read(sc, 22, &rf22);
4502220726Sbschmidt	run_rt3070_rf_write(sc, 22, rf22 | 0x01);
4503178676Ssam
4504178676Ssam	/* set power and frequency of passband test tone */
4505198429Srpaulo	run_bbp_write(sc, 24, 0x00);
4506220728Sbschmidt	for (ntries = 0; ntries < 100; ntries++) {
4507198429Srpaulo		/* transmit test tone */
4508198429Srpaulo		run_bbp_write(sc, 25, 0x90);
4509198429Srpaulo		run_delay(sc, 10);
4510198429Srpaulo		/* read received power */
4511220724Sbschmidt		run_bbp_read(sc, 55, &bbp55_pb);
4512220724Sbschmidt		if (bbp55_pb != 0)
4513198429Srpaulo			break;
4514178676Ssam	}
4515178676Ssam	if (ntries == 100)
4516178676Ssam		return ETIMEDOUT;
4517178676Ssam
4518178676Ssam	/* set power and frequency of stopband test tone */
4519198429Srpaulo	run_bbp_write(sc, 24, 0x06);
4520178676Ssam	for (ntries = 0; ntries < 100; ntries++) {
4521206477Sbschmidt		/* transmit test tone */
4522198429Srpaulo		run_bbp_write(sc, 25, 0x90);
4523178676Ssam		run_delay(sc, 10);
4524178676Ssam		/* read received power */
4525220728Sbschmidt		run_bbp_read(sc, 55, &bbp55_sb);
4526178676Ssam
4527198429Srpaulo		delta = bbp55_pb - bbp55_sb;
4528198429Srpaulo		if (delta > target)
4529178676Ssam			break;
4530198429Srpaulo
4531178676Ssam		/* reprogram filter */
4532178676Ssam		rf24++;
4533178676Ssam		run_rt3070_rf_write(sc, 24, rf24);
4534178676Ssam	}
4535198429Srpaulo	if (ntries < 100) {
4536178676Ssam		if (rf24 != init)
4537178676Ssam			rf24--;	/* backtrack */
4538178676Ssam		*val = rf24;
4539198429Srpaulo		run_rt3070_rf_write(sc, 24, rf24);
4540198429Srpaulo	}
4541198429Srpaulo
4542178676Ssam	/* restore initial state */
4543198429Srpaulo	run_bbp_write(sc, 24, 0x00);
4544210110Sbschmidt
4545178676Ssam	/* disable baseband loopback mode */
4546210110Sbschmidt	run_rt3070_rf_read(sc, 22, &rf22);
4547210110Sbschmidt	run_rt3070_rf_write(sc, 22, rf22 & ~0x01);
4548210110Sbschmidt
4549210110Sbschmidt	return (0);
4550210110Sbschmidt}
4551210110Sbschmidt
4552198429Srpaulostatic void
4553201209Srpaulorun_rt3070_rf_setup(struct run_softc *sc)
4554201209Srpaulo{
4555178676Ssam	uint8_t bbp, rf;
4556220728Sbschmidt	int i;
4557198429Srpaulo
4558198429Srpaulo	if (sc->mac_ver == 0x3572) {
4559198429Srpaulo		/* enable DC filter */
4560198429Srpaulo		if (sc->mac_rev >= 0x0201)
4561201209Srpaulo			run_bbp_write(sc, 103, 0xc0);
4562220728Sbschmidt
4563198429Srpaulo		run_bbp_read(sc, 138, &bbp);
4564198429Srpaulo		if (sc->ntxchains == 1)
4565198429Srpaulo			bbp |= 0x20;	/* turn off DAC1 */
4566198429Srpaulo		if (sc->nrxchains == 1)
4567198429Srpaulo			bbp &= ~0x02;	/* turn off ADC1 */
4568198429Srpaulo		run_bbp_write(sc, 138, bbp);
4569198429Srpaulo
4570198429Srpaulo		if (sc->mac_rev >= 0x0211) {
4571198429Srpaulo			/* improve power consumption */
4572198429Srpaulo			run_bbp_read(sc, 31, &bbp);
4573206477Sbschmidt			run_bbp_write(sc, 31, bbp & ~0x03);
4574198429Srpaulo		}
4575198429Srpaulo
4576198429Srpaulo		run_rt3070_rf_read(sc, 16, &rf);
4577198429Srpaulo		rf = (rf & ~0x07) | sc->txmixgain_2ghz;
4578198429Srpaulo		run_rt3070_rf_write(sc, 16, rf);
4579198429Srpaulo
4580198429Srpaulo	} else if (sc->mac_ver == 0x3071) {
4581198429Srpaulo		/* enable DC filter */
4582198429Srpaulo		if (sc->mac_rev >= 0x0201)
4583198429Srpaulo			run_bbp_write(sc, 103, 0xc0);
4584198429Srpaulo
4585198429Srpaulo		run_bbp_read(sc, 138, &bbp);
4586206477Sbschmidt		if (sc->ntxchains == 1)
4587198429Srpaulo			bbp |= 0x20;	/* turn off DAC1 */
4588198429Srpaulo		if (sc->nrxchains == 1)
4589198429Srpaulo			bbp &= ~0x02;	/* turn off ADC1 */
4590198429Srpaulo		run_bbp_write(sc, 138, bbp);
4591198429Srpaulo
4592220866Sbschmidt		if (sc->mac_rev >= 0x0211) {
4593198429Srpaulo			/* improve power consumption */
4594198429Srpaulo			run_bbp_read(sc, 31, &bbp);
4595198429Srpaulo			run_bbp_write(sc, 31, bbp & ~0x03);
4596198429Srpaulo		}
4597198429Srpaulo
4598198429Srpaulo		run_write(sc, RT2860_TX_SW_CFG1, 0);
4599198429Srpaulo		if (sc->mac_rev < 0x0211) {
4600206477Sbschmidt			run_write(sc, RT2860_TX_SW_CFG2,
4601198429Srpaulo			    sc->patch_dac ? 0x2c : 0x0f);
4602198429Srpaulo		} else
4603198429Srpaulo			run_write(sc, RT2860_TX_SW_CFG2, 0);
4604198429Srpaulo
4605198429Srpaulo	} else if (sc->mac_ver == 0x3070) {
4606198429Srpaulo		if (sc->mac_rev >= 0x0201) {
4607198429Srpaulo			/* enable DC filter */
4608201209Srpaulo			run_bbp_write(sc, 103, 0xc0);
4609178676Ssam
4610201209Srpaulo			/* improve power consumption */
4611198429Srpaulo			run_bbp_read(sc, 31, &bbp);
4612178676Ssam			run_bbp_write(sc, 31, bbp & ~0x03);
4613178676Ssam		}
4614198429Srpaulo
4615198429Srpaulo		if (sc->mac_rev < 0x0211) {
4616178676Ssam			run_write(sc, RT2860_TX_SW_CFG1, 0);
4617201209Srpaulo			run_write(sc, RT2860_TX_SW_CFG2, 0x2c);
4618198429Srpaulo		} else
4619198429Srpaulo			run_write(sc, RT2860_TX_SW_CFG2, 0);
4620198429Srpaulo	}
4621198429Srpaulo
4622198429Srpaulo	/* initialize RF registers from ROM for >=RT3071*/
4623198429Srpaulo	if (sc->mac_ver >= 0x3071) {
4624198429Srpaulo		for (i = 0; i < 10; i++) {
4625178676Ssam			if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff)
4626178676Ssam				continue;
4627178676Ssam			run_rt3070_rf_write(sc, sc->rf[i].reg, sc->rf[i].val);
4628198429Srpaulo		}
4629201209Srpaulo	}
4630198429Srpaulo}
4631178676Ssam
4632178676Ssamstatic int
4633206477Sbschmidtrun_txrx_enable(struct run_softc *sc)
4634198429Srpaulo{
4635198429Srpaulo	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
4636198429Srpaulo	uint32_t tmp;
4637198429Srpaulo	int error, ntries;
4638220723Sbschmidt
4639198429Srpaulo	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_TX_EN);
4640206444Sbschmidt	for (ntries = 0; ntries < 200; ntries++) {
4641206444Sbschmidt		if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0)
4642198429Srpaulo			return error;
4643198429Srpaulo		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
4644220866Sbschmidt			break;
4645198429Srpaulo		run_delay(sc, 50);
4646198429Srpaulo	}
4647201209Srpaulo	if (ntries == 200)
4648201209Srpaulo		return ETIMEDOUT;
4649201209Srpaulo
4650201209Srpaulo	run_delay(sc, 50);
4651201209Srpaulo
4652201209Srpaulo	tmp |= RT2860_RX_DMA_EN | RT2860_TX_DMA_EN | RT2860_TX_WB_DDONE;
4653201209Srpaulo	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
4654206444Sbschmidt
4655198429Srpaulo	/* enable Rx bulk aggregation (set timeout and limit) */
4656198429Srpaulo	tmp = RT2860_USB_TX_EN | RT2860_USB_RX_EN | RT2860_USB_RX_AGG_EN |
4657198429Srpaulo	    RT2860_USB_RX_AGG_TO(128) | RT2860_USB_RX_AGG_LMT(2);
4658198429Srpaulo	run_write(sc, RT2860_USB_DMA_CFG, tmp);
4659198429Srpaulo
4660198429Srpaulo	/* set Rx filter */
4661198429Srpaulo	tmp = RT2860_DROP_CRC_ERR | RT2860_DROP_PHY_ERR;
4662198429Srpaulo	if (ic->ic_opmode != IEEE80211_M_MONITOR) {
4663201209Srpaulo		tmp |= RT2860_DROP_UC_NOME | RT2860_DROP_DUPL |
4664198429Srpaulo		    RT2860_DROP_CTS | RT2860_DROP_BA | RT2860_DROP_ACK |
4665198429Srpaulo		    RT2860_DROP_VER_ERR | RT2860_DROP_CTRL_RSV |
4666198429Srpaulo		    RT2860_DROP_CFACK | RT2860_DROP_CFEND;
4667178676Ssam		if (ic->ic_opmode == IEEE80211_M_STA)
4668198429Srpaulo			tmp |= RT2860_DROP_RTS | RT2860_DROP_PSPOLL;
4669178676Ssam	}
4670178676Ssam	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
4671206477Sbschmidt
4672178676Ssam	run_write(sc, RT2860_MAC_SYS_CTRL,
4673178676Ssam	    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
4674198429Srpaulo
4675178676Ssam	return (0);
4676178676Ssam}
4677178676Ssam
4678178676Ssamstatic void
4679178676Ssamrun_init_locked(struct run_softc *sc)
4680178676Ssam{
4681178676Ssam	struct ifnet *ifp = sc->sc_ifp;
4682198429Srpaulo	struct ieee80211com *ic = ifp->if_l2com;
4683178676Ssam	uint32_t tmp;
4684178676Ssam	uint8_t bbp1, bbp3;
4685178676Ssam	int i;
4686178676Ssam	int ridx;
4687178676Ssam	int ntries;
4688178676Ssam
4689178676Ssam	if (ic->ic_nrunning > 1)
4690178676Ssam		return;
4691201209Srpaulo
4692178676Ssam	run_stop(sc);
4693178676Ssam
4694178676Ssam	if (run_load_microcode(sc) != 0) {
4695198439Srpaulo		device_printf(sc->sc_dev, "could not load 8051 microcode\n");
4696198429Srpaulo		goto fail;
4697178676Ssam	}
4698198429Srpaulo
4699220726Sbschmidt	for (ntries = 0; ntries < 100; ntries++) {
4700178676Ssam		if (run_read(sc, RT2860_ASIC_VER_ID, &tmp) != 0)
4701178676Ssam			goto fail;
4702198429Srpaulo		if (tmp != 0 && tmp != 0xffffffff)
4703178676Ssam			break;
4704178676Ssam		run_delay(sc, 10);
4705220634Sbschmidt	}
4706178676Ssam	if (ntries == 100)
4707198429Srpaulo		goto fail;
4708178676Ssam
4709178676Ssam	for (i = 0; i != RUN_EP_QUEUES; i++)
4710178676Ssam		run_setup_tx_list(sc, &sc->sc_epq[i]);
4711178676Ssam
4712198429Srpaulo	run_set_macaddr(sc, IF_LLADDR(ifp));
4713178676Ssam
4714178676Ssam	for (ntries = 0; ntries < 100; ntries++) {
4715198429Srpaulo		if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
4716198429Srpaulo			goto fail;
4717198429Srpaulo		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
4718198429Srpaulo			break;
4719178676Ssam		run_delay(sc, 10);
4720178676Ssam	}
4721198429Srpaulo	if (ntries == 100) {
4722178676Ssam		device_printf(sc->sc_dev, "timeout waiting for DMA engine\n");
4723178676Ssam		goto fail;
4724198429Srpaulo	}
4725198429Srpaulo	tmp &= 0xff0;
4726198429Srpaulo	tmp |= RT2860_TX_WB_DDONE;
4727198429Srpaulo	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
4728178676Ssam
4729178676Ssam	/* turn off PME_OEN to solve high-current issue */
4730198429Srpaulo	run_read(sc, RT2860_SYS_CTRL, &tmp);
4731178676Ssam	run_write(sc, RT2860_SYS_CTRL, tmp & ~RT2860_PME_OEN);
4732178676Ssam
4733198429Srpaulo	run_write(sc, RT2860_MAC_SYS_CTRL,
4734198429Srpaulo	    RT2860_BBP_HRST | RT2860_MAC_SRST);
4735198429Srpaulo	run_write(sc, RT2860_USB_DMA_CFG, 0);
4736178676Ssam
4737178676Ssam	if (run_reset(sc) != 0) {
4738178676Ssam		device_printf(sc->sc_dev, "could not reset chipset\n");
4739198429Srpaulo		goto fail;
4740178676Ssam	}
4741178676Ssam
4742198429Srpaulo	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
4743178676Ssam
4744198429Srpaulo	/* init Tx power for all Tx rates (from EEPROM) */
4745178676Ssam	for (ridx = 0; ridx < 5; ridx++) {
4746178676Ssam		if (sc->txpow20mhz[ridx] == 0xffffffff)
4747198429Srpaulo			continue;
4748198429Srpaulo		run_write(sc, RT2860_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]);
4749198429Srpaulo	}
4750178676Ssam
4751178676Ssam	for (i = 0; i < N(rt2870_def_mac); i++)
4752178676Ssam		run_write(sc, rt2870_def_mac[i].reg, rt2870_def_mac[i].val);
4753198429Srpaulo	run_write(sc, RT2860_WMM_AIFSN_CFG, 0x00002273);
4754178676Ssam	run_write(sc, RT2860_WMM_CWMIN_CFG, 0x00002344);
4755178676Ssam	run_write(sc, RT2860_WMM_CWMAX_CFG, 0x000034aa);
4756198429Srpaulo
4757178676Ssam	if (sc->mac_ver >= 0x3070) {
4758178676Ssam		/* set delay of PA_PE assertion to 1us (unit of 0.25us) */
4759198429Srpaulo		run_write(sc, RT2860_TX_SW_CFG0,
4760178676Ssam		    4 << RT2860_DLY_PAPE_EN_SHIFT);
4761178676Ssam	}
4762220634Sbschmidt
4763178676Ssam	/* wait while MAC is busy */
4764198429Srpaulo	for (ntries = 0; ntries < 100; ntries++) {
4765178676Ssam		if (run_read(sc, RT2860_MAC_STATUS_REG, &tmp) != 0)
4766178676Ssam			goto fail;
4767178676Ssam		if (!(tmp & (RT2860_RX_STATUS_BUSY | RT2860_TX_STATUS_BUSY)))
4768178676Ssam			break;
4769198429Srpaulo		run_delay(sc, 10);
4770178676Ssam	}
4771178676Ssam	if (ntries == 100)
4772178676Ssam		goto fail;
4773178676Ssam
4774178676Ssam	/* clear Host to MCU mailbox */
4775198429Srpaulo	run_write(sc, RT2860_H2M_BBPAGENT, 0);
4776178676Ssam	run_write(sc, RT2860_H2M_MAILBOX, 0);
4777178676Ssam	run_delay(sc, 10);
4778198429Srpaulo
4779178676Ssam	if (run_bbp_init(sc) != 0) {
4780198429Srpaulo		device_printf(sc->sc_dev, "could not initialize BBP\n");
4781198429Srpaulo		goto fail;
4782178676Ssam	}
4783178676Ssam
4784198429Srpaulo	/* abort TSF synchronization */
4785178676Ssam	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
4786198429Srpaulo	tmp &= ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
4787178676Ssam	    RT2860_TBTT_TIMER_EN);
4788178676Ssam	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
4789198429Srpaulo
4790178676Ssam	/* clear RX WCID search table */
4791178676Ssam	run_set_region_4(sc, RT2860_WCID_ENTRY(0), 0, 512);
4792178676Ssam	/* clear WCID attribute table */
4793178676Ssam	run_set_region_4(sc, RT2860_WCID_ATTR(0), 0, 8 * 32);
4794178676Ssam
4795198429Srpaulo	/* hostapd sets a key before init. So, don't clear it. */
4796198429Srpaulo	if (sc->cmdq_key_set != RUN_CMDQ_GO) {
4797220726Sbschmidt		/* clear shared key table */
4798198429Srpaulo		run_set_region_4(sc, RT2860_SKEY(0, 0), 0, 8 * 32);
4799198429Srpaulo		/* clear shared key mode */
4800198429Srpaulo		run_set_region_4(sc, RT2860_SKEY_MODE_0_7, 0, 4);
4801178676Ssam	}
4802178676Ssam
4803198429Srpaulo	run_read(sc, RT2860_US_CYC_CNT, &tmp);
4804178676Ssam	tmp = (tmp & ~0xff) | 0x1e;
4805178676Ssam	run_write(sc, RT2860_US_CYC_CNT, tmp);
4806178676Ssam
4807178676Ssam	if (sc->mac_rev != 0x0101)
4808178676Ssam		run_write(sc, RT2860_TXOP_CTRL_CFG, 0x0000583f);
4809178676Ssam
4810198429Srpaulo	run_write(sc, RT2860_WMM_TXOP0_CFG, 0);
4811198429Srpaulo	run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96);
4812178676Ssam
4813178676Ssam	/* write vendor-specific BBP values (from EEPROM) */
4814178676Ssam	for (i = 0; i < 10; i++) {
4815178676Ssam		if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff)
4816178676Ssam			continue;
4817178676Ssam		run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val);
4818198429Srpaulo	}
4819198429Srpaulo
4820178676Ssam	/* select Main antenna for 1T1R devices */
4821178676Ssam	if (sc->rf_rev == RT3070_RF_3020)
4822206477Sbschmidt		run_set_rx_antenna(sc, 0);
4823178676Ssam
4824178676Ssam	/* send LEDs operating mode to microcontroller */
4825178676Ssam	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0]);
4826220729Sbschmidt	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1]);
4827220729Sbschmidt	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2]);
4828178676Ssam
4829178676Ssam	if (sc->mac_ver >= 0x3070)
4830220729Sbschmidt		run_rt3070_rf_init(sc);
4831178676Ssam
4832198429Srpaulo	/* disable non-existing Rx chains */
4833220726Sbschmidt	run_bbp_read(sc, 3, &bbp3);
4834220726Sbschmidt	bbp3 &= ~(1 << 3 | 1 << 4);
4835220726Sbschmidt	if (sc->nrxchains == 2)
4836220726Sbschmidt		bbp3 |= 1 << 3;
4837220726Sbschmidt	else if (sc->nrxchains == 3)
4838220726Sbschmidt		bbp3 |= 1 << 4;
4839198429Srpaulo	run_bbp_write(sc, 3, bbp3);
4840220726Sbschmidt
4841220726Sbschmidt	/* disable non-existing Tx chains */
4842220726Sbschmidt	run_bbp_read(sc, 1, &bbp1);
4843198429Srpaulo	if (sc->ntxchains == 1)
4844220726Sbschmidt		bbp1 &= ~(1 << 3 | 1 << 4);
4845220726Sbschmidt	run_bbp_write(sc, 1, bbp1);
4846178676Ssam
4847202986Srpaulo	if (sc->mac_ver >= 0x3070)
4848178676Ssam		run_rt3070_rf_setup(sc);
4849198429Srpaulo
4850198429Srpaulo	/* select default channel */
4851198429Srpaulo	run_set_chan(sc, ic->ic_curchan);
4852220729Sbschmidt
4853220729Sbschmidt	/* setup initial protection mode */
4854220729Sbschmidt	run_updateprot_cb(ic);
4855220729Sbschmidt
4856220729Sbschmidt	/* turn radio LED on */
4857220729Sbschmidt	run_set_leds(sc, RT2860_LED_RADIO);
4858220729Sbschmidt
4859220729Sbschmidt	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
4860220729Sbschmidt	ifp->if_drv_flags |= IFF_DRV_RUNNING;
4861220729Sbschmidt	sc->cmdq_run = RUN_CMDQ_GO;
4862220729Sbschmidt
4863220729Sbschmidt	for (i = 0; i != RUN_N_XFER; i++)
4864220729Sbschmidt		usbd_xfer_set_stall(sc->sc_xfer[i]);
4865220729Sbschmidt
4866220729Sbschmidt	usbd_transfer_start(sc->sc_xfer[RUN_BULK_RX]);
4867178676Ssam
4868178676Ssam	if (run_txrx_enable(sc) != 0)
4869198429Srpaulo		goto fail;
4870198429Srpaulo
4871198429Srpaulo	return;
4872198429Srpaulo
4873206477Sbschmidtfail:
4874198429Srpaulo	run_stop(sc);
4875198429Srpaulo}
4876220723Sbschmidt
4877198429Srpaulostatic void
4878198429Srpaulorun_init(void *arg)
4879220721Sbschmidt{
4880198429Srpaulo	struct run_softc *sc = arg;
4881198429Srpaulo	struct ifnet *ifp = sc->sc_ifp;
4882198429Srpaulo	struct ieee80211com *ic = ifp->if_l2com;
4883198429Srpaulo
4884198429Srpaulo	RUN_LOCK(sc);
4885198429Srpaulo	run_init_locked(sc);
4886198429Srpaulo	RUN_UNLOCK(sc);
4887198429Srpaulo
4888198429Srpaulo	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
4889198429Srpaulo		ieee80211_start_all(ic);
4890198429Srpaulo}
4891198429Srpaulo
4892198429Srpaulostatic void
4893198429Srpaulorun_stop(void *arg)
4894198429Srpaulo{
4895201209Srpaulo	struct run_softc *sc = (struct run_softc *)arg;
4896220721Sbschmidt	struct ifnet *ifp = sc->sc_ifp;
4897220721Sbschmidt	uint32_t tmp;
4898198429Srpaulo	int i;
4899198429Srpaulo	int ntries;
4900198429Srpaulo
4901198429Srpaulo	RUN_LOCK_ASSERT(sc, MA_OWNED);
4902198429Srpaulo
4903198429Srpaulo	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
4904198429Srpaulo		run_set_leds(sc, 0);	/* turn all LEDs off */
4905198429Srpaulo
4906198429Srpaulo	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
4907198429Srpaulo
4908198429Srpaulo	sc->ratectl_run = RUN_RATECTL_OFF;
4909198429Srpaulo	sc->cmdq_run = sc->cmdq_key_set;
4910198429Srpaulo
4911198429Srpaulo	RUN_UNLOCK(sc);
4912198429Srpaulo
4913198429Srpaulo	for(i = 0; i < RUN_N_XFER; i++)
4914198429Srpaulo		usbd_transfer_drain(sc->sc_xfer[i]);
4915198429Srpaulo
4916198429Srpaulo	RUN_LOCK(sc);
4917198429Srpaulo
4918198429Srpaulo	if (sc->rx_m != NULL) {
4919198429Srpaulo		m_free(sc->rx_m);
4920198429Srpaulo		sc->rx_m = NULL;
4921198429Srpaulo	}
4922198429Srpaulo
4923198429Srpaulo	/* disable Tx/Rx */
4924206477Sbschmidt	run_read(sc, RT2860_MAC_SYS_CTRL, &tmp);
4925220662Sbschmidt	tmp &= ~(RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
4926220662Sbschmidt	run_write(sc, RT2860_MAC_SYS_CTRL, tmp);
4927220662Sbschmidt
4928220662Sbschmidt	/* wait for pending Tx to complete */
4929220662Sbschmidt	for (ntries = 0; ntries < 100; ntries++) {
4930220662Sbschmidt		if (run_read(sc, RT2860_TXRXQ_PCNT, &tmp) != 0) {
4931220662Sbschmidt			DPRINTF("Cannot read Tx queue count\n");
4932220662Sbschmidt			break;
4933220662Sbschmidt		}
4934220662Sbschmidt		if ((tmp & RT2860_TX2Q_PCNT_MASK) == 0) {
4935220662Sbschmidt			DPRINTF("All Tx cleared\n");
4936220662Sbschmidt			break;
4937220662Sbschmidt		}
4938220662Sbschmidt		run_delay(sc, 10);
4939220891Sbschmidt	}
4940220891Sbschmidt	if (ntries >= 100)
4941220891Sbschmidt		DPRINTF("There are still pending Tx\n");
4942220891Sbschmidt	run_delay(sc, 10);
4943220891Sbschmidt	run_write(sc, RT2860_USB_DMA_CFG, 0);
4944220891Sbschmidt
4945220891Sbschmidt	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST);
4946220891Sbschmidt	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
4947220891Sbschmidt
4948220891Sbschmidt	for (i = 0; i != RUN_EP_QUEUES; i++)
4949220891Sbschmidt		run_unsetup_tx_list(sc, &sc->sc_epq[i]);
4950220891Sbschmidt
4951220891Sbschmidt	return;
4952220891Sbschmidt}
4953220891Sbschmidt
4954220891Sbschmidtstatic void
4955220891Sbschmidtrun_delay(struct run_softc *sc, unsigned int ms)
4956220891Sbschmidt{
4957220891Sbschmidt	usb_pause_mtx(mtx_owned(&sc->sc_mtx) ?
4958220891Sbschmidt	    &sc->sc_mtx : NULL, USB_MS_TO_TICKS(ms));
4959220891Sbschmidt}
4960220891Sbschmidt
4961220891Sbschmidtstatic device_method_t run_methods[] = {
4962220891Sbschmidt	/* Device interface */
4963220891Sbschmidt	DEVMETHOD(device_probe,		run_match),
4964220891Sbschmidt	DEVMETHOD(device_attach,	run_attach),
4965220891Sbschmidt	DEVMETHOD(device_detach,	run_detach),
4966220891Sbschmidt
4967220891Sbschmidt	{ 0, 0 }
4968220891Sbschmidt};
4969220891Sbschmidt
4970220891Sbschmidtstatic driver_t run_driver = {
4971220891Sbschmidt	.name = "run",
4972220891Sbschmidt	.methods = run_methods,
4973220891Sbschmidt	.size = sizeof(struct run_softc)
4974220891Sbschmidt};
4975220891Sbschmidt
4976220891Sbschmidtstatic devclass_t run_devclass;
4977220891Sbschmidt
4978220891SbschmidtDRIVER_MODULE(run, uhub, run_driver, run_devclass, NULL, 0);
4979220891SbschmidtMODULE_DEPEND(run, wlan, 1, 1, 1);
4980220891SbschmidtMODULE_DEPEND(run, usb, 1, 1, 1);
4981220891SbschmidtMODULE_DEPEND(run, firmware, 1, 1, 1);
4982220891SbschmidtMODULE_VERSION(run, 1);
4983220891Sbschmidt