1203134Sthompsa/*-
2205042Sthompsa * Copyright (c) 2008,2010 Damien Bergamini <damien.bergamini@free.fr>
3205042Sthompsa * ported to FreeBSD by Akinori Furukoshi <moonlightakkiy@yahoo.ca>
4205042Sthompsa * USB Consulting, Hans Petter Selasky <hselasky@freebsd.org>
5261868Skevlo * Copyright (c) 2013-2014 Kevin Lo
6203134Sthompsa *
7203134Sthompsa * Permission to use, copy, modify, and distribute this software for any
8203134Sthompsa * purpose with or without fee is hereby granted, provided that the above
9203134Sthompsa * copyright notice and this permission notice appear in all copies.
10203134Sthompsa *
11203134Sthompsa * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12203134Sthompsa * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13203134Sthompsa * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14203134Sthompsa * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15203134Sthompsa * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16203134Sthompsa * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17203134Sthompsa * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18203134Sthompsa */
19203134Sthompsa
20203134Sthompsa#include <sys/cdefs.h>
21203134Sthompsa__FBSDID("$FreeBSD: releng/10.2/sys/dev/usb/wlan/if_run.c 281878 2015-04-23 01:52:07Z kevlo $");
22203134Sthompsa
23203134Sthompsa/*-
24259453Shselasky * Ralink Technology RT2700U/RT2800U/RT3000U/RT3900E chipset driver.
25203134Sthompsa * http://www.ralinktech.com/
26203134Sthompsa */
27203134Sthompsa
28203134Sthompsa#include <sys/param.h>
29203134Sthompsa#include <sys/sockio.h>
30203134Sthompsa#include <sys/sysctl.h>
31203134Sthompsa#include <sys/lock.h>
32203134Sthompsa#include <sys/mutex.h>
33203134Sthompsa#include <sys/mbuf.h>
34203134Sthompsa#include <sys/kernel.h>
35203134Sthompsa#include <sys/socket.h>
36203134Sthompsa#include <sys/systm.h>
37203134Sthompsa#include <sys/malloc.h>
38203134Sthompsa#include <sys/module.h>
39203134Sthompsa#include <sys/bus.h>
40203134Sthompsa#include <sys/endian.h>
41203134Sthompsa#include <sys/linker.h>
42203134Sthompsa#include <sys/firmware.h>
43203134Sthompsa#include <sys/kdb.h>
44203134Sthompsa
45203134Sthompsa#include <machine/bus.h>
46203134Sthompsa#include <machine/resource.h>
47203134Sthompsa#include <sys/rman.h>
48203134Sthompsa
49203134Sthompsa#include <net/bpf.h>
50203134Sthompsa#include <net/if.h>
51203134Sthompsa#include <net/if_arp.h>
52203134Sthompsa#include <net/ethernet.h>
53203134Sthompsa#include <net/if_dl.h>
54203134Sthompsa#include <net/if_media.h>
55203134Sthompsa#include <net/if_types.h>
56203134Sthompsa
57203134Sthompsa#include <netinet/in.h>
58203134Sthompsa#include <netinet/in_systm.h>
59203134Sthompsa#include <netinet/in_var.h>
60203134Sthompsa#include <netinet/if_ether.h>
61203134Sthompsa#include <netinet/ip.h>
62203134Sthompsa
63203134Sthompsa#include <net80211/ieee80211_var.h>
64203134Sthompsa#include <net80211/ieee80211_regdomain.h>
65203134Sthompsa#include <net80211/ieee80211_radiotap.h>
66206358Srpaulo#include <net80211/ieee80211_ratectl.h>
67203134Sthompsa
68203134Sthompsa#include <dev/usb/usb.h>
69203134Sthompsa#include <dev/usb/usbdi.h>
70203134Sthompsa#include "usbdevs.h"
71203134Sthompsa
72261868Skevlo#define	USB_DEBUG_VAR	run_debug
73203134Sthompsa#include <dev/usb/usb_debug.h>
74261868Skevlo#include <dev/usb/usb_msctest.h>
75203134Sthompsa
76220235Skevlo#include <dev/usb/wlan/if_runreg.h>
77220235Skevlo#include <dev/usb/wlan/if_runvar.h>
78203134Sthompsa
79207077Sthompsa#ifdef	USB_DEBUG
80261868Skevlo#define	RUN_DEBUG
81203134Sthompsa#endif
82203134Sthompsa
83203134Sthompsa#ifdef	RUN_DEBUG
84203134Sthompsaint run_debug = 0;
85227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, run, CTLFLAG_RW, 0, "USB run");
86203134SthompsaSYSCTL_INT(_hw_usb_run, OID_AUTO, debug, CTLFLAG_RW, &run_debug, 0,
87203134Sthompsa    "run debug level");
88203134Sthompsa#endif
89203134Sthompsa
90261868Skevlo#define	IEEE80211_HAS_ADDR4(wh)	\
91203134Sthompsa	(((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
92203134Sthompsa
93208019Sthompsa/*
94208019Sthompsa * Because of LOR in run_key_delete(), use atomic instead.
95208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[].
96208019Sthompsa */
97261868Skevlo#define	RUN_CMDQ_GET(c)	(atomic_fetchadd_32((c), 1) & RUN_CMDQ_MASQ)
98208019Sthompsa
99223486Shselaskystatic const STRUCT_USB_HOST_ID run_devs[] = {
100261868Skevlo#define	RUN_DEV(v,p)	{ USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) }
101261868Skevlo#define	RUN_DEV_EJECT(v,p)	\
102262604Skevlo	{ USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RUN_EJECT) }
103262604Skevlo#define	RUN_EJECT	1
104209918Sthompsa    RUN_DEV(ABOCOM,		RT2770),
105209918Sthompsa    RUN_DEV(ABOCOM,		RT2870),
106209918Sthompsa    RUN_DEV(ABOCOM,		RT3070),
107209918Sthompsa    RUN_DEV(ABOCOM,		RT3071),
108209918Sthompsa    RUN_DEV(ABOCOM,		RT3072),
109209918Sthompsa    RUN_DEV(ABOCOM2,		RT2870_1),
110209918Sthompsa    RUN_DEV(ACCTON,		RT2770),
111209918Sthompsa    RUN_DEV(ACCTON,		RT2870_1),
112209918Sthompsa    RUN_DEV(ACCTON,		RT2870_2),
113209918Sthompsa    RUN_DEV(ACCTON,		RT2870_3),
114209918Sthompsa    RUN_DEV(ACCTON,		RT2870_4),
115209918Sthompsa    RUN_DEV(ACCTON,		RT2870_5),
116209918Sthompsa    RUN_DEV(ACCTON,		RT3070),
117209918Sthompsa    RUN_DEV(ACCTON,		RT3070_1),
118209918Sthompsa    RUN_DEV(ACCTON,		RT3070_2),
119209918Sthompsa    RUN_DEV(ACCTON,		RT3070_3),
120209918Sthompsa    RUN_DEV(ACCTON,		RT3070_4),
121209918Sthompsa    RUN_DEV(ACCTON,		RT3070_5),
122209918Sthompsa    RUN_DEV(AIRTIES,		RT3070),
123209918Sthompsa    RUN_DEV(ALLWIN,		RT2070),
124209918Sthompsa    RUN_DEV(ALLWIN,		RT2770),
125209918Sthompsa    RUN_DEV(ALLWIN,		RT2870),
126209918Sthompsa    RUN_DEV(ALLWIN,		RT3070),
127209918Sthompsa    RUN_DEV(ALLWIN,		RT3071),
128209918Sthompsa    RUN_DEV(ALLWIN,		RT3072),
129209918Sthompsa    RUN_DEV(ALLWIN,		RT3572),
130209918Sthompsa    RUN_DEV(AMIGO,		RT2870_1),
131209918Sthompsa    RUN_DEV(AMIGO,		RT2870_2),
132209918Sthompsa    RUN_DEV(AMIT,		CGWLUSB2GNR),
133209918Sthompsa    RUN_DEV(AMIT,		RT2870_1),
134209918Sthompsa    RUN_DEV(AMIT2,		RT2870),
135209918Sthompsa    RUN_DEV(ASUS,		RT2870_1),
136209918Sthompsa    RUN_DEV(ASUS,		RT2870_2),
137209918Sthompsa    RUN_DEV(ASUS,		RT2870_3),
138209918Sthompsa    RUN_DEV(ASUS,		RT2870_4),
139209918Sthompsa    RUN_DEV(ASUS,		RT2870_5),
140209918Sthompsa    RUN_DEV(ASUS,		USBN13),
141209918Sthompsa    RUN_DEV(ASUS,		RT3070_1),
142261868Skevlo    RUN_DEV(ASUS,		USBN66),
143239358Shselasky    RUN_DEV(ASUS,		USB_N53),
144209918Sthompsa    RUN_DEV(ASUS2,		USBN11),
145209918Sthompsa    RUN_DEV(AZUREWAVE,		RT2870_1),
146209918Sthompsa    RUN_DEV(AZUREWAVE,		RT2870_2),
147209918Sthompsa    RUN_DEV(AZUREWAVE,		RT3070_1),
148209918Sthompsa    RUN_DEV(AZUREWAVE,		RT3070_2),
149209918Sthompsa    RUN_DEV(AZUREWAVE,		RT3070_3),
150261868Skevlo    RUN_DEV(BELKIN,		F9L1103),
151209918Sthompsa    RUN_DEV(BELKIN,		F5D8053V3),
152209918Sthompsa    RUN_DEV(BELKIN,		F5D8055),
153226534Shselasky    RUN_DEV(BELKIN,		F5D8055V2),
154209918Sthompsa    RUN_DEV(BELKIN,		F6D4050V1),
155257044Shselasky    RUN_DEV(BELKIN,		F6D4050V2),
156209918Sthompsa    RUN_DEV(BELKIN,		RT2870_1),
157209918Sthompsa    RUN_DEV(BELKIN,		RT2870_2),
158226534Shselasky    RUN_DEV(CISCOLINKSYS,	AE1000),
159209918Sthompsa    RUN_DEV(CISCOLINKSYS2,	RT3070),
160209918Sthompsa    RUN_DEV(CISCOLINKSYS3,	RT3070),
161209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_1),
162209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_2),
163209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_3),
164209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_4),
165209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_5),
166209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_6),
167209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_7),
168209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_8),
169209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT3070_1),
170209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT3070_2),
171209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	VIGORN61),
172209918Sthompsa    RUN_DEV(COREGA,		CGWLUSB300GNM),
173209918Sthompsa    RUN_DEV(COREGA,		RT2870_1),
174209918Sthompsa    RUN_DEV(COREGA,		RT2870_2),
175209918Sthompsa    RUN_DEV(COREGA,		RT2870_3),
176209918Sthompsa    RUN_DEV(COREGA,		RT3070),
177209918Sthompsa    RUN_DEV(CYBERTAN,		RT2870),
178209918Sthompsa    RUN_DEV(DLINK,		RT2870),
179209918Sthompsa    RUN_DEV(DLINK,		RT3072),
180255238Sbr    RUN_DEV(DLINK,		DWA127),
181259453Shselasky    RUN_DEV(DLINK,		DWA140B3),
182259453Shselasky    RUN_DEV(DLINK,		DWA160B2),
183267263Skevlo    RUN_DEV(DLINK,		DWA140D1),
184261868Skevlo    RUN_DEV(DLINK,		DWA162),
185209918Sthompsa    RUN_DEV(DLINK2,		DWA130),
186209918Sthompsa    RUN_DEV(DLINK2,		RT2870_1),
187209918Sthompsa    RUN_DEV(DLINK2,		RT2870_2),
188209918Sthompsa    RUN_DEV(DLINK2,		RT3070_1),
189209918Sthompsa    RUN_DEV(DLINK2,		RT3070_2),
190209918Sthompsa    RUN_DEV(DLINK2,		RT3070_3),
191209918Sthompsa    RUN_DEV(DLINK2,		RT3070_4),
192209918Sthompsa    RUN_DEV(DLINK2,		RT3070_5),
193209918Sthompsa    RUN_DEV(DLINK2,		RT3072),
194209918Sthompsa    RUN_DEV(DLINK2,		RT3072_1),
195209918Sthompsa    RUN_DEV(EDIMAX,		EW7717),
196209918Sthompsa    RUN_DEV(EDIMAX,		EW7718),
197261868Skevlo    RUN_DEV(EDIMAX,		EW7733UND),
198209918Sthompsa    RUN_DEV(EDIMAX,		RT2870_1),
199209918Sthompsa    RUN_DEV(ENCORE,		RT3070_1),
200209918Sthompsa    RUN_DEV(ENCORE,		RT3070_2),
201209918Sthompsa    RUN_DEV(ENCORE,		RT3070_3),
202209918Sthompsa    RUN_DEV(GIGABYTE,		GNWB31N),
203209918Sthompsa    RUN_DEV(GIGABYTE,		GNWB32L),
204209918Sthompsa    RUN_DEV(GIGABYTE,		RT2870_1),
205209918Sthompsa    RUN_DEV(GIGASET,		RT3070_1),
206209918Sthompsa    RUN_DEV(GIGASET,		RT3070_2),
207209918Sthompsa    RUN_DEV(GUILLEMOT,		HWNU300),
208209918Sthompsa    RUN_DEV(HAWKING,		HWUN2),
209209918Sthompsa    RUN_DEV(HAWKING,		RT2870_1),
210209918Sthompsa    RUN_DEV(HAWKING,		RT2870_2),
211209918Sthompsa    RUN_DEV(HAWKING,		RT3070),
212209918Sthompsa    RUN_DEV(IODATA,		RT3072_1),
213209918Sthompsa    RUN_DEV(IODATA,		RT3072_2),
214209918Sthompsa    RUN_DEV(IODATA,		RT3072_3),
215209918Sthompsa    RUN_DEV(IODATA,		RT3072_4),
216209918Sthompsa    RUN_DEV(LINKSYS4,		RT3070),
217209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB100),
218209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB54GCV3),
219209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB600N),
220209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB600NV2),
221209918Sthompsa    RUN_DEV(LOGITEC,		RT2870_1),
222209918Sthompsa    RUN_DEV(LOGITEC,		RT2870_2),
223209918Sthompsa    RUN_DEV(LOGITEC,		RT2870_3),
224230333Shselasky    RUN_DEV(LOGITEC,		LANW300NU2),
225238274Shrs    RUN_DEV(LOGITEC,		LANW150NU2),
226248458Shselasky    RUN_DEV(LOGITEC,		LANW300NU2S),
227281878Skevlo    RUN_DEV(MELCO,		WLIUCG300HP),
228209918Sthompsa    RUN_DEV(MELCO,		RT2870_2),
229209918Sthompsa    RUN_DEV(MELCO,		WLIUCAG300N),
230209918Sthompsa    RUN_DEV(MELCO,		WLIUCG300N),
231219257Sdaichi    RUN_DEV(MELCO,		WLIUCG301N),
232209918Sthompsa    RUN_DEV(MELCO,		WLIUCGN),
233227781Shselasky    RUN_DEV(MELCO,		WLIUCGNM),
234281878Skevlo    RUN_DEV(MELCO,		WLIUCG300HPV1),
235238274Shrs    RUN_DEV(MELCO,		WLIUCGNM2),
236209918Sthompsa    RUN_DEV(MOTOROLA4,		RT2770),
237209918Sthompsa    RUN_DEV(MOTOROLA4,		RT3070),
238209918Sthompsa    RUN_DEV(MSI,		RT3070_1),
239209918Sthompsa    RUN_DEV(MSI,		RT3070_2),
240209918Sthompsa    RUN_DEV(MSI,		RT3070_3),
241209918Sthompsa    RUN_DEV(MSI,		RT3070_4),
242209918Sthompsa    RUN_DEV(MSI,		RT3070_5),
243209918Sthompsa    RUN_DEV(MSI,		RT3070_6),
244209918Sthompsa    RUN_DEV(MSI,		RT3070_7),
245209918Sthompsa    RUN_DEV(MSI,		RT3070_8),
246209918Sthompsa    RUN_DEV(MSI,		RT3070_9),
247209918Sthompsa    RUN_DEV(MSI,		RT3070_10),
248209918Sthompsa    RUN_DEV(MSI,		RT3070_11),
249209918Sthompsa    RUN_DEV(OVISLINK,		RT3072),
250209918Sthompsa    RUN_DEV(PARA,		RT3070),
251209918Sthompsa    RUN_DEV(PEGATRON,		RT2870),
252209918Sthompsa    RUN_DEV(PEGATRON,		RT3070),
253209918Sthompsa    RUN_DEV(PEGATRON,		RT3070_2),
254209918Sthompsa    RUN_DEV(PEGATRON,		RT3070_3),
255209918Sthompsa    RUN_DEV(PHILIPS,		RT2870),
256209918Sthompsa    RUN_DEV(PLANEX2,		GWUS300MINIS),
257209918Sthompsa    RUN_DEV(PLANEX2,		GWUSMICRON),
258209918Sthompsa    RUN_DEV(PLANEX2,		RT2870),
259209918Sthompsa    RUN_DEV(PLANEX2,		RT3070),
260209918Sthompsa    RUN_DEV(QCOM,		RT2870),
261209918Sthompsa    RUN_DEV(QUANTA,		RT3070),
262209918Sthompsa    RUN_DEV(RALINK,		RT2070),
263209918Sthompsa    RUN_DEV(RALINK,		RT2770),
264209918Sthompsa    RUN_DEV(RALINK,		RT2870),
265209918Sthompsa    RUN_DEV(RALINK,		RT3070),
266209918Sthompsa    RUN_DEV(RALINK,		RT3071),
267209918Sthompsa    RUN_DEV(RALINK,		RT3072),
268209918Sthompsa    RUN_DEV(RALINK,		RT3370),
269209918Sthompsa    RUN_DEV(RALINK,		RT3572),
270261868Skevlo    RUN_DEV(RALINK,		RT3573),
271259453Shselasky    RUN_DEV(RALINK,		RT5370),
272259453Shselasky    RUN_DEV(RALINK,		RT5572),
273209918Sthompsa    RUN_DEV(RALINK,		RT8070),
274226534Shselasky    RUN_DEV(SAMSUNG,		WIS09ABGN),
275209918Sthompsa    RUN_DEV(SAMSUNG2,		RT2870_1),
276209918Sthompsa    RUN_DEV(SENAO,		RT2870_1),
277209918Sthompsa    RUN_DEV(SENAO,		RT2870_2),
278209918Sthompsa    RUN_DEV(SENAO,		RT2870_3),
279209918Sthompsa    RUN_DEV(SENAO,		RT2870_4),
280209918Sthompsa    RUN_DEV(SENAO,		RT3070),
281209918Sthompsa    RUN_DEV(SENAO,		RT3071),
282209918Sthompsa    RUN_DEV(SENAO,		RT3072_1),
283209918Sthompsa    RUN_DEV(SENAO,		RT3072_2),
284209918Sthompsa    RUN_DEV(SENAO,		RT3072_3),
285209918Sthompsa    RUN_DEV(SENAO,		RT3072_4),
286209918Sthompsa    RUN_DEV(SENAO,		RT3072_5),
287209918Sthompsa    RUN_DEV(SITECOMEU,		RT2770),
288209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_1),
289209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_2),
290209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_3),
291209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_4),
292209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070),
293209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070_2),
294209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070_3),
295209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070_4),
296209918Sthompsa    RUN_DEV(SITECOMEU,		RT3071),
297209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_1),
298209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_2),
299209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_3),
300209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_4),
301209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_5),
302209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_6),
303209918Sthompsa    RUN_DEV(SITECOMEU,		WL608),
304209918Sthompsa    RUN_DEV(SPARKLAN,		RT2870_1),
305209918Sthompsa    RUN_DEV(SPARKLAN,		RT3070),
306209918Sthompsa    RUN_DEV(SWEEX2,		LW153),
307209918Sthompsa    RUN_DEV(SWEEX2,		LW303),
308209918Sthompsa    RUN_DEV(SWEEX2,		LW313),
309209918Sthompsa    RUN_DEV(TOSHIBA,		RT3070),
310209918Sthompsa    RUN_DEV(UMEDIA,		RT2870_1),
311209918Sthompsa    RUN_DEV(ZCOM,		RT2870_1),
312209918Sthompsa    RUN_DEV(ZCOM,		RT2870_2),
313209918Sthompsa    RUN_DEV(ZINWELL,		RT2870_1),
314209918Sthompsa    RUN_DEV(ZINWELL,		RT2870_2),
315209918Sthompsa    RUN_DEV(ZINWELL,		RT3070),
316209918Sthompsa    RUN_DEV(ZINWELL,		RT3072_1),
317209918Sthompsa    RUN_DEV(ZINWELL,		RT3072_2),
318209918Sthompsa    RUN_DEV(ZYXEL,		RT2870_1),
319209918Sthompsa    RUN_DEV(ZYXEL,		RT2870_2),
320262604Skevlo    RUN_DEV_EJECT(ZYXEL,	NWD2705),
321261868Skevlo    RUN_DEV_EJECT(RALINK,	RT_STOR),
322261868Skevlo#undef RUN_DEV_EJECT
323209918Sthompsa#undef RUN_DEV
324203134Sthompsa};
325203134Sthompsa
326203134Sthompsastatic device_probe_t	run_match;
327203134Sthompsastatic device_attach_t	run_attach;
328203134Sthompsastatic device_detach_t	run_detach;
329203134Sthompsa
330203134Sthompsastatic usb_callback_t	run_bulk_rx_callback;
331203134Sthompsastatic usb_callback_t	run_bulk_tx_callback0;
332203134Sthompsastatic usb_callback_t	run_bulk_tx_callback1;
333203134Sthompsastatic usb_callback_t	run_bulk_tx_callback2;
334203134Sthompsastatic usb_callback_t	run_bulk_tx_callback3;
335203134Sthompsastatic usb_callback_t	run_bulk_tx_callback4;
336203134Sthompsastatic usb_callback_t	run_bulk_tx_callback5;
337203134Sthompsa
338261868Skevlostatic void	run_autoinst(void *, struct usb_device *,
339261868Skevlo		    struct usb_attach_arg *);
340261868Skevlostatic int	run_driver_loaded(struct module *, int, void *);
341203134Sthompsastatic void	run_bulk_tx_callbackN(struct usb_xfer *xfer,
342259453Shselasky		    usb_error_t error, u_int index);
343203134Sthompsastatic struct ieee80211vap *run_vap_create(struct ieee80211com *,
344228621Sbschmidt		    const char [IFNAMSIZ], int, enum ieee80211_opmode, int,
345228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN],
346228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN]);
347203134Sthompsastatic void	run_vap_delete(struct ieee80211vap *);
348208019Sthompsastatic void	run_cmdq_cb(void *, int);
349203134Sthompsastatic void	run_setup_tx_list(struct run_softc *,
350203134Sthompsa		    struct run_endpoint_queue *);
351203134Sthompsastatic void	run_unsetup_tx_list(struct run_softc *,
352203134Sthompsa		    struct run_endpoint_queue *);
353203134Sthompsastatic int	run_load_microcode(struct run_softc *);
354203134Sthompsastatic int	run_reset(struct run_softc *);
355203134Sthompsastatic usb_error_t run_do_request(struct run_softc *,
356203134Sthompsa		    struct usb_device_request *, void *);
357203134Sthompsastatic int	run_read(struct run_softc *, uint16_t, uint32_t *);
358203134Sthompsastatic int	run_read_region_1(struct run_softc *, uint16_t, uint8_t *, int);
359203134Sthompsastatic int	run_write_2(struct run_softc *, uint16_t, uint16_t);
360203134Sthompsastatic int	run_write(struct run_softc *, uint16_t, uint32_t);
361203134Sthompsastatic int	run_write_region_1(struct run_softc *, uint16_t,
362203134Sthompsa		    const uint8_t *, int);
363203134Sthompsastatic int	run_set_region_4(struct run_softc *, uint16_t, uint32_t, int);
364261868Skevlostatic int	run_efuse_read(struct run_softc *, uint16_t, uint16_t *, int);
365203134Sthompsastatic int	run_efuse_read_2(struct run_softc *, uint16_t, uint16_t *);
366203134Sthompsastatic int	run_eeprom_read_2(struct run_softc *, uint16_t, uint16_t *);
367259453Shselaskystatic int	run_rt2870_rf_write(struct run_softc *, uint32_t);
368203134Sthompsastatic int	run_rt3070_rf_read(struct run_softc *, uint8_t, uint8_t *);
369203134Sthompsastatic int	run_rt3070_rf_write(struct run_softc *, uint8_t, uint8_t);
370203134Sthompsastatic int	run_bbp_read(struct run_softc *, uint8_t, uint8_t *);
371203134Sthompsastatic int	run_bbp_write(struct run_softc *, uint8_t, uint8_t);
372203134Sthompsastatic int	run_mcu_cmd(struct run_softc *, uint8_t, uint16_t);
373259453Shselaskystatic const char *run_get_rf(uint16_t);
374261868Skevlostatic void	run_rt3593_get_txpower(struct run_softc *);
375261868Skevlostatic void	run_get_txpower(struct run_softc *);
376203134Sthompsastatic int	run_read_eeprom(struct run_softc *);
377203134Sthompsastatic struct ieee80211_node *run_node_alloc(struct ieee80211vap *,
378203134Sthompsa			    const uint8_t mac[IEEE80211_ADDR_LEN]);
379203134Sthompsastatic int	run_media_change(struct ifnet *);
380203134Sthompsastatic int	run_newstate(struct ieee80211vap *, enum ieee80211_state, int);
381203134Sthompsastatic int	run_wme_update(struct ieee80211com *);
382208019Sthompsastatic void	run_wme_update_cb(void *);
383203134Sthompsastatic void	run_key_update_begin(struct ieee80211vap *);
384203134Sthompsastatic void	run_key_update_end(struct ieee80211vap *);
385208019Sthompsastatic void	run_key_set_cb(void *);
386208019Sthompsastatic int	run_key_set(struct ieee80211vap *, struct ieee80211_key *,
387259453Shselasky		    const uint8_t mac[IEEE80211_ADDR_LEN]);
388208019Sthompsastatic void	run_key_delete_cb(void *);
389208019Sthompsastatic int	run_key_delete(struct ieee80211vap *, struct ieee80211_key *);
390206358Srpaulostatic void	run_ratectl_to(void *);
391206358Srpaulostatic void	run_ratectl_cb(void *, int);
392208019Sthompsastatic void	run_drain_fifo(void *);
393203134Sthompsastatic void	run_iter_func(void *, struct ieee80211_node *);
394208019Sthompsastatic void	run_newassoc_cb(void *);
395203134Sthompsastatic void	run_newassoc(struct ieee80211_node *, int);
396203134Sthompsastatic void	run_rx_frame(struct run_softc *, struct mbuf *, uint32_t);
397203134Sthompsastatic void	run_tx_free(struct run_endpoint_queue *pq,
398203134Sthompsa		    struct run_tx_data *, int);
399208019Sthompsastatic void	run_set_tx_desc(struct run_softc *, struct run_tx_data *);
400203134Sthompsastatic int	run_tx(struct run_softc *, struct mbuf *,
401203134Sthompsa		    struct ieee80211_node *);
402203134Sthompsastatic int	run_tx_mgt(struct run_softc *, struct mbuf *,
403203134Sthompsa		    struct ieee80211_node *);
404203134Sthompsastatic int	run_sendprot(struct run_softc *, const struct mbuf *,
405203134Sthompsa		    struct ieee80211_node *, int, int);
406203134Sthompsastatic int	run_tx_param(struct run_softc *, struct mbuf *,
407203134Sthompsa		    struct ieee80211_node *,
408203134Sthompsa		    const struct ieee80211_bpf_params *);
409203134Sthompsastatic int	run_raw_xmit(struct ieee80211_node *, struct mbuf *,
410203134Sthompsa		    const struct ieee80211_bpf_params *);
411203134Sthompsastatic void	run_start(struct ifnet *);
412203134Sthompsastatic int	run_ioctl(struct ifnet *, u_long, caddr_t);
413261868Skevlostatic void	run_iq_calib(struct run_softc *, u_int);
414205042Sthompsastatic void	run_set_agc(struct run_softc *, uint8_t);
415203134Sthompsastatic void	run_select_chan_group(struct run_softc *, int);
416203134Sthompsastatic void	run_set_rx_antenna(struct run_softc *, int);
417203134Sthompsastatic void	run_rt2870_set_chan(struct run_softc *, u_int);
418203134Sthompsastatic void	run_rt3070_set_chan(struct run_softc *, u_int);
419205042Sthompsastatic void	run_rt3572_set_chan(struct run_softc *, u_int);
420261868Skevlostatic void	run_rt3593_set_chan(struct run_softc *, u_int);
421259453Shselaskystatic void	run_rt5390_set_chan(struct run_softc *, u_int);
422259453Shselaskystatic void	run_rt5592_set_chan(struct run_softc *, u_int);
423203134Sthompsastatic int	run_set_chan(struct run_softc *, struct ieee80211_channel *);
424203134Sthompsastatic void	run_set_channel(struct ieee80211com *);
425203134Sthompsastatic void	run_scan_start(struct ieee80211com *);
426203134Sthompsastatic void	run_scan_end(struct ieee80211com *);
427203134Sthompsastatic void	run_update_beacon(struct ieee80211vap *, int);
428208019Sthompsastatic void	run_update_beacon_cb(void *);
429203134Sthompsastatic void	run_updateprot(struct ieee80211com *);
430218492Sbschmidtstatic void	run_updateprot_cb(void *);
431208019Sthompsastatic void	run_usb_timeout_cb(void *);
432203134Sthompsastatic void	run_reset_livelock(struct run_softc *);
433203134Sthompsastatic void	run_enable_tsf_sync(struct run_softc *);
434203134Sthompsastatic void	run_enable_mrr(struct run_softc *);
435203134Sthompsastatic void	run_set_txpreamble(struct run_softc *);
436203134Sthompsastatic void	run_set_basicrates(struct run_softc *);
437203134Sthompsastatic void	run_set_leds(struct run_softc *, uint16_t);
438203134Sthompsastatic void	run_set_bssid(struct run_softc *, const uint8_t *);
439203134Sthompsastatic void	run_set_macaddr(struct run_softc *, const uint8_t *);
440203134Sthompsastatic void	run_updateslot(struct ifnet *);
441218492Sbschmidtstatic void	run_updateslot_cb(void *);
442208019Sthompsastatic void	run_update_mcast(struct ifnet *);
443203134Sthompsastatic int8_t	run_rssi2dbm(struct run_softc *, uint8_t, uint8_t);
444203134Sthompsastatic void	run_update_promisc_locked(struct ifnet *);
445203134Sthompsastatic void	run_update_promisc(struct ifnet *);
446259453Shselaskystatic void	run_rt5390_bbp_init(struct run_softc *);
447203134Sthompsastatic int	run_bbp_init(struct run_softc *);
448203134Sthompsastatic int	run_rt3070_rf_init(struct run_softc *);
449261868Skevlostatic void	run_rt3593_rf_init(struct run_softc *);
450259453Shselaskystatic void	run_rt5390_rf_init(struct run_softc *);
451203134Sthompsastatic int	run_rt3070_filter_calib(struct run_softc *, uint8_t, uint8_t,
452203134Sthompsa		    uint8_t *);
453205042Sthompsastatic void	run_rt3070_rf_setup(struct run_softc *);
454261868Skevlostatic void	run_rt3593_rf_setup(struct run_softc *);
455261868Skevlostatic void	run_rt5390_rf_setup(struct run_softc *);
456203134Sthompsastatic int	run_txrx_enable(struct run_softc *);
457259453Shselaskystatic void	run_adjust_freq_offset(struct run_softc *);
458203134Sthompsastatic void	run_init(void *);
459203134Sthompsastatic void	run_init_locked(struct run_softc *);
460203134Sthompsastatic void	run_stop(void *);
461259453Shselaskystatic void	run_delay(struct run_softc *, u_int);
462203134Sthompsa
463261868Skevlostatic eventhandler_tag run_etag;
464261868Skevlo
465261868Skevlostatic const struct rt2860_rate {
466261868Skevlo	uint8_t		rate;
467261868Skevlo	uint8_t		mcs;
468261868Skevlo	enum		ieee80211_phytype phy;
469261868Skevlo	uint8_t		ctl_ridx;
470261868Skevlo	uint16_t	sp_ack_dur;
471261868Skevlo	uint16_t	lp_ack_dur;
472261868Skevlo} rt2860_rates[] = {
473261868Skevlo	{   2, 0, IEEE80211_T_DS,   0, 314, 314 },
474261868Skevlo	{   4, 1, IEEE80211_T_DS,   1, 258, 162 },
475261868Skevlo	{  11, 2, IEEE80211_T_DS,   2, 223, 127 },
476261868Skevlo	{  22, 3, IEEE80211_T_DS,   3, 213, 117 },
477261868Skevlo	{  12, 0, IEEE80211_T_OFDM, 4,  60,  60 },
478261868Skevlo	{  18, 1, IEEE80211_T_OFDM, 4,  52,  52 },
479261868Skevlo	{  24, 2, IEEE80211_T_OFDM, 6,  48,  48 },
480261868Skevlo	{  36, 3, IEEE80211_T_OFDM, 6,  44,  44 },
481261868Skevlo	{  48, 4, IEEE80211_T_OFDM, 8,  44,  44 },
482261868Skevlo	{  72, 5, IEEE80211_T_OFDM, 8,  40,  40 },
483261868Skevlo	{  96, 6, IEEE80211_T_OFDM, 8,  40,  40 },
484261868Skevlo	{ 108, 7, IEEE80211_T_OFDM, 8,  40,  40 }
485261868Skevlo};
486261868Skevlo
487203134Sthompsastatic const struct {
488208019Sthompsa	uint16_t	reg;
489203134Sthompsa	uint32_t	val;
490203134Sthompsa} rt2870_def_mac[] = {
491203134Sthompsa	RT2870_DEF_MAC
492203134Sthompsa};
493203134Sthompsa
494203134Sthompsastatic const struct {
495203134Sthompsa	uint8_t	reg;
496203134Sthompsa	uint8_t	val;
497203134Sthompsa} rt2860_def_bbp[] = {
498203134Sthompsa	RT2860_DEF_BBP
499259453Shselasky},rt5390_def_bbp[] = {
500259453Shselasky	RT5390_DEF_BBP
501259453Shselasky},rt5592_def_bbp[] = {
502259453Shselasky	RT5592_DEF_BBP
503203134Sthompsa};
504203134Sthompsa
505259453Shselasky/*
506259453Shselasky * Default values for BBP register R196 for RT5592.
507259453Shselasky */
508259453Shselaskystatic const uint8_t rt5592_bbp_r196[] = {
509259453Shselasky	0xe0, 0x1f, 0x38, 0x32, 0x08, 0x28, 0x19, 0x0a, 0xff, 0x00,
510259453Shselasky	0x16, 0x10, 0x10, 0x0b, 0x36, 0x2c, 0x26, 0x24, 0x42, 0x36,
511259453Shselasky	0x30, 0x2d, 0x4c, 0x46, 0x3d, 0x40, 0x3e, 0x42, 0x3d, 0x40,
512259453Shselasky	0x3c, 0x34, 0x2c, 0x2f, 0x3c, 0x35, 0x2e, 0x2a, 0x49, 0x41,
513259453Shselasky	0x36, 0x31, 0x30, 0x30, 0x0e, 0x0d, 0x28, 0x21, 0x1c, 0x16,
514259453Shselasky	0x50, 0x4a, 0x43, 0x40, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00,
515259453Shselasky	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
516259453Shselasky	0x00, 0x00, 0x7d, 0x14, 0x32, 0x2c, 0x36, 0x4c, 0x43, 0x2c,
517259453Shselasky	0x2e, 0x36, 0x30, 0x6e
518259453Shselasky};
519259453Shselasky
520203134Sthompsastatic const struct rfprog {
521203134Sthompsa	uint8_t		chan;
522203134Sthompsa	uint32_t	r1, r2, r3, r4;
523203134Sthompsa} rt2860_rf2850[] = {
524203134Sthompsa	RT2860_RF2850
525203134Sthompsa};
526203134Sthompsa
527203134Sthompsastruct {
528203134Sthompsa	uint8_t	n, r, k;
529205042Sthompsa} rt3070_freqs[] = {
530205042Sthompsa	RT3070_RF3052
531203134Sthompsa};
532203134Sthompsa
533259453Shselaskystatic const struct rt5592_freqs {
534259453Shselasky	uint16_t	n;
535259453Shselasky	uint8_t		k, m, r;
536259453Shselasky} rt5592_freqs_20mhz[] = {
537259453Shselasky	RT5592_RF5592_20MHZ
538259453Shselasky},rt5592_freqs_40mhz[] = {
539259453Shselasky	RT5592_RF5592_40MHZ
540259453Shselasky};
541259453Shselasky
542203134Sthompsastatic const struct {
543203134Sthompsa	uint8_t	reg;
544203134Sthompsa	uint8_t	val;
545203134Sthompsa} rt3070_def_rf[] = {
546203134Sthompsa	RT3070_DEF_RF
547205042Sthompsa},rt3572_def_rf[] = {
548205042Sthompsa	RT3572_DEF_RF
549261868Skevlo},rt3593_def_rf[] = {
550261868Skevlo	RT3593_DEF_RF
551259453Shselasky},rt5390_def_rf[] = {
552259453Shselasky	RT5390_DEF_RF
553259453Shselasky},rt5392_def_rf[] = {
554259453Shselasky	RT5392_DEF_RF
555259453Shselasky},rt5592_def_rf[] = {
556259453Shselasky	RT5592_DEF_RF
557259453Shselasky},rt5592_2ghz_def_rf[] = {
558259453Shselasky	RT5592_2GHZ_DEF_RF
559259453Shselasky},rt5592_5ghz_def_rf[] = {
560259453Shselasky	RT5592_5GHZ_DEF_RF
561203134Sthompsa};
562203134Sthompsa
563259453Shselaskystatic const struct {
564259453Shselasky	u_int	firstchan;
565259453Shselasky	u_int	lastchan;
566259453Shselasky	uint8_t	reg;
567259453Shselasky	uint8_t	val;
568259453Shselasky} rt5592_chan_5ghz[] = {
569259453Shselasky	RT5592_CHAN_5GHZ
570259453Shselasky};
571259453Shselasky
572203134Sthompsastatic const struct usb_config run_config[RUN_N_XFER] = {
573203134Sthompsa    [RUN_BULK_TX_BE] = {
574203134Sthompsa	.type = UE_BULK,
575203134Sthompsa	.endpoint = UE_ADDR_ANY,
576203134Sthompsa	.ep_index = 0,
577203134Sthompsa	.direction = UE_DIR_OUT,
578203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
579203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
580203134Sthompsa	.callback = run_bulk_tx_callback0,
581203134Sthompsa	.timeout = 5000,	/* ms */
582203134Sthompsa    },
583203134Sthompsa    [RUN_BULK_TX_BK] = {
584203134Sthompsa	.type = UE_BULK,
585203134Sthompsa	.endpoint = UE_ADDR_ANY,
586203134Sthompsa	.direction = UE_DIR_OUT,
587203134Sthompsa	.ep_index = 1,
588203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
589203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
590203134Sthompsa	.callback = run_bulk_tx_callback1,
591203134Sthompsa	.timeout = 5000,	/* ms */
592203134Sthompsa    },
593203134Sthompsa    [RUN_BULK_TX_VI] = {
594203134Sthompsa	.type = UE_BULK,
595203134Sthompsa	.endpoint = UE_ADDR_ANY,
596203134Sthompsa	.direction = UE_DIR_OUT,
597203134Sthompsa	.ep_index = 2,
598203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
599203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
600203134Sthompsa	.callback = run_bulk_tx_callback2,
601203134Sthompsa	.timeout = 5000,	/* ms */
602203134Sthompsa    },
603203134Sthompsa    [RUN_BULK_TX_VO] = {
604203134Sthompsa	.type = UE_BULK,
605203134Sthompsa	.endpoint = UE_ADDR_ANY,
606203134Sthompsa	.direction = UE_DIR_OUT,
607203134Sthompsa	.ep_index = 3,
608203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
609203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
610203134Sthompsa	.callback = run_bulk_tx_callback3,
611203134Sthompsa	.timeout = 5000,	/* ms */
612203134Sthompsa    },
613203134Sthompsa    [RUN_BULK_TX_HCCA] = {
614203134Sthompsa	.type = UE_BULK,
615203134Sthompsa	.endpoint = UE_ADDR_ANY,
616203134Sthompsa	.direction = UE_DIR_OUT,
617203134Sthompsa	.ep_index = 4,
618203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
619203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
620203134Sthompsa	.callback = run_bulk_tx_callback4,
621203134Sthompsa	.timeout = 5000,	/* ms */
622203134Sthompsa    },
623203134Sthompsa    [RUN_BULK_TX_PRIO] = {
624203134Sthompsa	.type = UE_BULK,
625203134Sthompsa	.endpoint = UE_ADDR_ANY,
626203134Sthompsa	.direction = UE_DIR_OUT,
627203134Sthompsa	.ep_index = 5,
628203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
629203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
630203134Sthompsa	.callback = run_bulk_tx_callback5,
631203134Sthompsa	.timeout = 5000,	/* ms */
632203134Sthompsa    },
633203134Sthompsa    [RUN_BULK_RX] = {
634203134Sthompsa	.type = UE_BULK,
635203134Sthompsa	.endpoint = UE_ADDR_ANY,
636203134Sthompsa	.direction = UE_DIR_IN,
637203134Sthompsa	.bufsize = RUN_MAX_RXSZ,
638203134Sthompsa	.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
639203134Sthompsa	.callback = run_bulk_rx_callback,
640203134Sthompsa    }
641203134Sthompsa};
642203134Sthompsa
643261868Skevlostatic void
644261868Skevlorun_autoinst(void *arg, struct usb_device *udev,
645261868Skevlo    struct usb_attach_arg *uaa)
646261868Skevlo{
647261868Skevlo	struct usb_interface *iface;
648261868Skevlo	struct usb_interface_descriptor *id;
649261868Skevlo
650261868Skevlo	if (uaa->dev_state != UAA_DEV_READY)
651261868Skevlo		return;
652261868Skevlo
653261868Skevlo	iface = usbd_get_iface(udev, 0);
654261868Skevlo	if (iface == NULL)
655261868Skevlo		return;
656261868Skevlo	id = iface->idesc;
657261868Skevlo	if (id == NULL || id->bInterfaceClass != UICLASS_MASS)
658261868Skevlo		return;
659261868Skevlo	if (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa))
660261868Skevlo		return;
661261868Skevlo
662261868Skevlo	if (usb_msc_eject(udev, 0, MSC_EJECT_STOPUNIT) == 0)
663261868Skevlo		uaa->dev_state = UAA_DEV_EJECTING;
664261868Skevlo}
665261868Skevlo
666220235Skevlostatic int
667261868Skevlorun_driver_loaded(struct module *mod, int what, void *arg)
668261868Skevlo{
669261868Skevlo	switch (what) {
670261868Skevlo	case MOD_LOAD:
671261868Skevlo		run_etag = EVENTHANDLER_REGISTER(usb_dev_configured,
672261868Skevlo		    run_autoinst, NULL, EVENTHANDLER_PRI_ANY);
673261868Skevlo		break;
674261868Skevlo	case MOD_UNLOAD:
675261868Skevlo		EVENTHANDLER_DEREGISTER(usb_dev_configured, run_etag);
676261868Skevlo		break;
677261868Skevlo	default:
678261868Skevlo		return (EOPNOTSUPP);
679261868Skevlo	}
680261868Skevlo	return (0);
681261868Skevlo}
682261868Skevlo
683261868Skevlostatic int
684203134Sthompsarun_match(device_t self)
685203134Sthompsa{
686203134Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(self);
687203134Sthompsa
688203134Sthompsa	if (uaa->usb_mode != USB_MODE_HOST)
689203134Sthompsa		return (ENXIO);
690203134Sthompsa	if (uaa->info.bConfigIndex != 0)
691203134Sthompsa		return (ENXIO);
692203134Sthompsa	if (uaa->info.bIfaceIndex != RT2860_IFACE_INDEX)
693203134Sthompsa		return (ENXIO);
694203134Sthompsa
695203134Sthompsa	return (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa));
696203134Sthompsa}
697203134Sthompsa
698203134Sthompsastatic int
699203134Sthompsarun_attach(device_t self)
700203134Sthompsa{
701203134Sthompsa	struct run_softc *sc = device_get_softc(self);
702203134Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(self);
703203134Sthompsa	struct ieee80211com *ic;
704203134Sthompsa	struct ifnet *ifp;
705205042Sthompsa	uint32_t ver;
706259453Shselasky	int ntries, error;
707203134Sthompsa	uint8_t iface_index, bands;
708203134Sthompsa
709203134Sthompsa	device_set_usb_desc(self);
710203134Sthompsa	sc->sc_udev = uaa->device;
711203134Sthompsa	sc->sc_dev = self;
712262604Skevlo	if (USB_GET_DRIVER_INFO(uaa) != RUN_EJECT)
713262604Skevlo		sc->sc_flags |= RUN_FLAG_FWLOAD_NEEDED;
714203134Sthompsa
715203134Sthompsa	mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev),
716203134Sthompsa	    MTX_NETWORK_LOCK, MTX_DEF);
717203134Sthompsa
718203134Sthompsa	iface_index = RT2860_IFACE_INDEX;
719208019Sthompsa
720203134Sthompsa	error = usbd_transfer_setup(uaa->device, &iface_index,
721203134Sthompsa	    sc->sc_xfer, run_config, RUN_N_XFER, sc, &sc->sc_mtx);
722203134Sthompsa	if (error) {
723205042Sthompsa		device_printf(self, "could not allocate USB transfers, "
724203134Sthompsa		    "err=%s\n", usbd_errstr(error));
725203134Sthompsa		goto detach;
726203134Sthompsa	}
727203134Sthompsa
728203134Sthompsa	RUN_LOCK(sc);
729203134Sthompsa
730203134Sthompsa	/* wait for the chip to settle */
731203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
732209917Sthompsa		if (run_read(sc, RT2860_ASIC_VER_ID, &ver) != 0) {
733203134Sthompsa			RUN_UNLOCK(sc);
734203134Sthompsa			goto detach;
735203134Sthompsa		}
736205042Sthompsa		if (ver != 0 && ver != 0xffffffff)
737203134Sthompsa			break;
738203134Sthompsa		run_delay(sc, 10);
739203134Sthompsa	}
740203134Sthompsa	if (ntries == 100) {
741203138Sthompsa		device_printf(sc->sc_dev,
742203138Sthompsa		    "timeout waiting for NIC to initialize\n");
743203134Sthompsa		RUN_UNLOCK(sc);
744203134Sthompsa		goto detach;
745203134Sthompsa	}
746205042Sthompsa	sc->mac_ver = ver >> 16;
747205042Sthompsa	sc->mac_rev = ver & 0xffff;
748203134Sthompsa
749203134Sthompsa	/* retrieve RF rev. no and various other things from EEPROM */
750203134Sthompsa	run_read_eeprom(sc);
751203134Sthompsa
752203138Sthompsa	device_printf(sc->sc_dev,
753203138Sthompsa	    "MAC/BBP RT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), address %s\n",
754205042Sthompsa	    sc->mac_ver, sc->mac_rev, run_get_rf(sc->rf_rev),
755203138Sthompsa	    sc->ntxchains, sc->nrxchains, ether_sprintf(sc->sc_bssid));
756203134Sthompsa
757203134Sthompsa	RUN_UNLOCK(sc);
758203134Sthompsa
759203134Sthompsa	ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
760220235Skevlo	if (ifp == NULL) {
761203138Sthompsa		device_printf(sc->sc_dev, "can not if_alloc()\n");
762203134Sthompsa		goto detach;
763203134Sthompsa	}
764203134Sthompsa	ic = ifp->if_l2com;
765203134Sthompsa
766203134Sthompsa	ifp->if_softc = sc;
767203134Sthompsa	if_initname(ifp, "run", device_get_unit(sc->sc_dev));
768203134Sthompsa	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
769203134Sthompsa	ifp->if_init = run_init;
770203134Sthompsa	ifp->if_ioctl = run_ioctl;
771203134Sthompsa	ifp->if_start = run_start;
772207554Ssobomax	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
773207554Ssobomax	ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
774203134Sthompsa	IFQ_SET_READY(&ifp->if_snd);
775203134Sthompsa
776203134Sthompsa	ic->ic_ifp = ifp;
777203134Sthompsa	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
778203134Sthompsa	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
779208019Sthompsa
780203134Sthompsa	/* set device capabilities */
781203134Sthompsa	ic->ic_caps =
782203134Sthompsa	    IEEE80211_C_STA |		/* station mode supported */
783203134Sthompsa	    IEEE80211_C_MONITOR |	/* monitor mode supported */
784203134Sthompsa	    IEEE80211_C_IBSS |
785203134Sthompsa	    IEEE80211_C_HOSTAP |
786208019Sthompsa	    IEEE80211_C_WDS |		/* 4-address traffic works */
787208019Sthompsa	    IEEE80211_C_MBSS |
788203134Sthompsa	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
789203134Sthompsa	    IEEE80211_C_SHSLOT |	/* short slot time supported */
790203134Sthompsa	    IEEE80211_C_WME |		/* WME */
791214894Sbschmidt	    IEEE80211_C_WPA;		/* WPA1|WPA2(RSN) */
792203134Sthompsa
793203134Sthompsa	ic->ic_cryptocaps =
794203134Sthompsa	    IEEE80211_CRYPTO_WEP |
795203134Sthompsa	    IEEE80211_CRYPTO_AES_CCM |
796203134Sthompsa	    IEEE80211_CRYPTO_TKIPMIC |
797203134Sthompsa	    IEEE80211_CRYPTO_TKIP;
798203134Sthompsa
799203134Sthompsa	ic->ic_flags |= IEEE80211_F_DATAPAD;
800203134Sthompsa	ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;
801203134Sthompsa
802203134Sthompsa	bands = 0;
803203134Sthompsa	setbit(&bands, IEEE80211_MODE_11B);
804203134Sthompsa	setbit(&bands, IEEE80211_MODE_11G);
805259453Shselasky	if (sc->rf_rev == RT2860_RF_2750 || sc->rf_rev == RT2860_RF_2850 ||
806261868Skevlo	    sc->rf_rev == RT3070_RF_3052 || sc->rf_rev == RT3593_RF_3053 ||
807261868Skevlo	    sc->rf_rev == RT5592_RF_5592)
808259453Shselasky		setbit(&bands, IEEE80211_MODE_11A);
809203134Sthompsa	ieee80211_init_channels(ic, NULL, &bands);
810203134Sthompsa
811203134Sthompsa	ieee80211_ifattach(ic, sc->sc_bssid);
812203134Sthompsa
813203134Sthompsa	ic->ic_scan_start = run_scan_start;
814203134Sthompsa	ic->ic_scan_end = run_scan_end;
815203134Sthompsa	ic->ic_set_channel = run_set_channel;
816203134Sthompsa	ic->ic_node_alloc = run_node_alloc;
817203134Sthompsa	ic->ic_newassoc = run_newassoc;
818218492Sbschmidt	ic->ic_updateslot = run_updateslot;
819208019Sthompsa	ic->ic_update_mcast = run_update_mcast;
820203134Sthompsa	ic->ic_wme.wme_update = run_wme_update;
821203134Sthompsa	ic->ic_raw_xmit = run_raw_xmit;
822203134Sthompsa	ic->ic_update_promisc = run_update_promisc;
823203134Sthompsa
824203134Sthompsa	ic->ic_vap_create = run_vap_create;
825203134Sthompsa	ic->ic_vap_delete = run_vap_delete;
826203134Sthompsa
827203134Sthompsa	ieee80211_radiotap_attach(ic,
828203134Sthompsa	    &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap),
829203134Sthompsa		RUN_TX_RADIOTAP_PRESENT,
830203134Sthompsa	    &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap),
831203134Sthompsa		RUN_RX_RADIOTAP_PRESENT);
832203134Sthompsa
833208019Sthompsa	TASK_INIT(&sc->cmdq_task, 0, run_cmdq_cb, sc);
834208019Sthompsa	TASK_INIT(&sc->ratectl_task, 0, run_ratectl_cb, sc);
835259453Shselasky	usb_callout_init_mtx(&sc->ratectl_ch, &sc->sc_mtx, 0);
836208019Sthompsa
837203134Sthompsa	if (bootverbose)
838203134Sthompsa		ieee80211_announce(ic);
839203134Sthompsa
840209917Sthompsa	return (0);
841203134Sthompsa
842203134Sthompsadetach:
843203134Sthompsa	run_detach(self);
844209917Sthompsa	return (ENXIO);
845203134Sthompsa}
846203134Sthompsa
847203134Sthompsastatic int
848203134Sthompsarun_detach(device_t self)
849203134Sthompsa{
850203134Sthompsa	struct run_softc *sc = device_get_softc(self);
851203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
852203134Sthompsa	struct ieee80211com *ic;
853203134Sthompsa	int i;
854203134Sthompsa
855246614Shselasky	RUN_LOCK(sc);
856246614Shselasky	sc->sc_detached = 1;
857246614Shselasky	RUN_UNLOCK(sc);
858246614Shselasky
859203134Sthompsa	/* stop all USB transfers */
860203134Sthompsa	usbd_transfer_unsetup(sc->sc_xfer, RUN_N_XFER);
861203134Sthompsa
862203134Sthompsa	RUN_LOCK(sc);
863209144Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
864209144Sthompsa	sc->cmdq_run = sc->cmdq_key_set = RUN_CMDQ_ABORT;
865209144Sthompsa
866203134Sthompsa	/* free TX list, if any */
867203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
868203134Sthompsa		run_unsetup_tx_list(sc, &sc->sc_epq[i]);
869203134Sthompsa	RUN_UNLOCK(sc);
870203134Sthompsa
871203134Sthompsa	if (ifp) {
872203134Sthompsa		ic = ifp->if_l2com;
873208019Sthompsa		/* drain tasks */
874208019Sthompsa		usb_callout_drain(&sc->ratectl_ch);
875208019Sthompsa		ieee80211_draintask(ic, &sc->cmdq_task);
876208019Sthompsa		ieee80211_draintask(ic, &sc->ratectl_task);
877203134Sthompsa		ieee80211_ifdetach(ic);
878203134Sthompsa		if_free(ifp);
879203134Sthompsa	}
880203134Sthompsa
881203134Sthompsa	mtx_destroy(&sc->sc_mtx);
882203134Sthompsa
883203134Sthompsa	return (0);
884203134Sthompsa}
885203134Sthompsa
886203134Sthompsastatic struct ieee80211vap *
887228621Sbschmidtrun_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
888228621Sbschmidt    enum ieee80211_opmode opmode, int flags,
889203134Sthompsa    const uint8_t bssid[IEEE80211_ADDR_LEN],
890203134Sthompsa    const uint8_t mac[IEEE80211_ADDR_LEN])
891203134Sthompsa{
892208019Sthompsa	struct ifnet *ifp = ic->ic_ifp;
893208019Sthompsa	struct run_softc *sc = ifp->if_softc;
894203134Sthompsa	struct run_vap *rvp;
895203134Sthompsa	struct ieee80211vap *vap;
896208019Sthompsa	int i;
897203134Sthompsa
898209917Sthompsa	if (sc->rvp_cnt >= RUN_VAP_MAX) {
899208019Sthompsa		if_printf(ifp, "number of VAPs maxed out\n");
900209917Sthompsa		return (NULL);
901208019Sthompsa	}
902208019Sthompsa
903208019Sthompsa	switch (opmode) {
904208019Sthompsa	case IEEE80211_M_STA:
905208019Sthompsa		/* enable s/w bmiss handling for sta mode */
906208019Sthompsa		flags |= IEEE80211_CLONE_NOBEACONS;
907208019Sthompsa		/* fall though */
908208019Sthompsa	case IEEE80211_M_IBSS:
909208019Sthompsa	case IEEE80211_M_MONITOR:
910208019Sthompsa	case IEEE80211_M_HOSTAP:
911208019Sthompsa	case IEEE80211_M_MBSS:
912208019Sthompsa		/* other than WDS vaps, only one at a time */
913208019Sthompsa		if (!TAILQ_EMPTY(&ic->ic_vaps))
914209917Sthompsa			return (NULL);
915208019Sthompsa		break;
916208019Sthompsa	case IEEE80211_M_WDS:
917208019Sthompsa		TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next){
918208019Sthompsa			if(vap->iv_opmode != IEEE80211_M_HOSTAP)
919208019Sthompsa				continue;
920208019Sthompsa			/* WDS vap's always share the local mac address. */
921208019Sthompsa			flags &= ~IEEE80211_CLONE_BSSID;
922208019Sthompsa			break;
923208019Sthompsa		}
924209917Sthompsa		if (vap == NULL) {
925208019Sthompsa			if_printf(ifp, "wds only supported in ap mode\n");
926209917Sthompsa			return (NULL);
927208019Sthompsa		}
928208019Sthompsa		break;
929208019Sthompsa	default:
930208019Sthompsa		if_printf(ifp, "unknown opmode %d\n", opmode);
931209917Sthompsa		return (NULL);
932208019Sthompsa	}
933208019Sthompsa
934208019Sthompsa	rvp = (struct run_vap *) malloc(sizeof(struct run_vap),
935203134Sthompsa	    M_80211_VAP, M_NOWAIT | M_ZERO);
936203134Sthompsa	if (rvp == NULL)
937209917Sthompsa		return (NULL);
938203134Sthompsa	vap = &rvp->vap;
939203134Sthompsa
940259453Shselasky	if (ieee80211_vap_setup(ic, vap, name, unit,
941259453Shselasky	    opmode, flags, bssid, mac) != 0) {
942259453Shselasky		/* out of memory */
943259453Shselasky		free(rvp, M_80211_VAP);
944259453Shselasky		return (NULL);
945259453Shselasky	}
946259453Shselasky
947203134Sthompsa	vap->iv_key_update_begin = run_key_update_begin;
948203134Sthompsa	vap->iv_key_update_end = run_key_update_end;
949203134Sthompsa	vap->iv_update_beacon = run_update_beacon;
950208019Sthompsa	vap->iv_max_aid = RT2870_WCID_MAX;
951208019Sthompsa	/*
952208019Sthompsa	 * To delete the right key from h/w, we need wcid.
953208019Sthompsa	 * Luckily, there is unused space in ieee80211_key{}, wk_pad,
954208019Sthompsa	 * and matching wcid will be written into there. So, cast
955208019Sthompsa	 * some spells to remove 'const' from ieee80211_key{}
956208019Sthompsa	 */
957208019Sthompsa	vap->iv_key_delete = (void *)run_key_delete;
958208019Sthompsa	vap->iv_key_set = (void *)run_key_set;
959203134Sthompsa
960203134Sthompsa	/* override state transition machine */
961203134Sthompsa	rvp->newstate = vap->iv_newstate;
962203134Sthompsa	vap->iv_newstate = run_newstate;
963203134Sthompsa
964206358Srpaulo	ieee80211_ratectl_init(vap);
965206358Srpaulo	ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */);
966203134Sthompsa
967203134Sthompsa	/* complete setup */
968203134Sthompsa	ieee80211_vap_attach(vap, run_media_change, ieee80211_media_status);
969208019Sthompsa
970208019Sthompsa	/* make sure id is always unique */
971209917Sthompsa	for (i = 0; i < RUN_VAP_MAX; i++) {
972208019Sthompsa		if((sc->rvp_bmap & 1 << i) == 0){
973208019Sthompsa			sc->rvp_bmap |= 1 << i;
974208019Sthompsa			rvp->rvp_id = i;
975208019Sthompsa			break;
976208019Sthompsa		}
977208019Sthompsa	}
978209917Sthompsa	if (sc->rvp_cnt++ == 0)
979208019Sthompsa		ic->ic_opmode = opmode;
980208019Sthompsa
981209917Sthompsa	if (opmode == IEEE80211_M_HOSTAP)
982209144Sthompsa		sc->cmdq_run = RUN_CMDQ_GO;
983209144Sthompsa
984208019Sthompsa	DPRINTF("rvp_id=%d bmap=%x rvp_cnt=%d\n",
985208019Sthompsa	    rvp->rvp_id, sc->rvp_bmap, sc->rvp_cnt);
986208019Sthompsa
987209917Sthompsa	return (vap);
988203134Sthompsa}
989203134Sthompsa
990203134Sthompsastatic void
991203134Sthompsarun_vap_delete(struct ieee80211vap *vap)
992203134Sthompsa{
993203134Sthompsa	struct run_vap *rvp = RUN_VAP(vap);
994203134Sthompsa	struct ifnet *ifp;
995203134Sthompsa	struct ieee80211com *ic;
996203134Sthompsa	struct run_softc *sc;
997208019Sthompsa	uint8_t rvp_id;
998203134Sthompsa
999209917Sthompsa	if (vap == NULL)
1000203134Sthompsa		return;
1001203134Sthompsa
1002203134Sthompsa	ic = vap->iv_ic;
1003203134Sthompsa	ifp = ic->ic_ifp;
1004203134Sthompsa
1005203134Sthompsa	sc = ifp->if_softc;
1006203134Sthompsa
1007205042Sthompsa	RUN_LOCK(sc);
1008208019Sthompsa
1009218492Sbschmidt	m_freem(rvp->beacon_mbuf);
1010218492Sbschmidt	rvp->beacon_mbuf = NULL;
1011218492Sbschmidt
1012208019Sthompsa	rvp_id = rvp->rvp_id;
1013208019Sthompsa	sc->ratectl_run &= ~(1 << rvp_id);
1014208019Sthompsa	sc->rvp_bmap &= ~(1 << rvp_id);
1015208019Sthompsa	run_set_region_4(sc, RT2860_SKEY(rvp_id, 0), 0, 128);
1016208019Sthompsa	run_set_region_4(sc, RT2860_BCN_BASE(rvp_id), 0, 512);
1017208019Sthompsa	--sc->rvp_cnt;
1018208019Sthompsa
1019208019Sthompsa	DPRINTF("vap=%p rvp_id=%d bmap=%x rvp_cnt=%d\n",
1020208019Sthompsa	    vap, rvp_id, sc->rvp_bmap, sc->rvp_cnt);
1021208019Sthompsa
1022205042Sthompsa	RUN_UNLOCK(sc);
1023203134Sthompsa
1024206358Srpaulo	ieee80211_ratectl_deinit(vap);
1025203134Sthompsa	ieee80211_vap_detach(vap);
1026203134Sthompsa	free(rvp, M_80211_VAP);
1027203134Sthompsa}
1028203134Sthompsa
1029208019Sthompsa/*
1030208019Sthompsa * There are numbers of functions need to be called in context thread.
1031208019Sthompsa * Rather than creating taskqueue event for each of those functions,
1032208019Sthompsa * here is all-for-one taskqueue callback function. This function
1033208019Sthompsa * gurantees deferred functions are executed in the same order they
1034208019Sthompsa * were enqueued.
1035208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[].
1036208019Sthompsa */
1037203134Sthompsastatic void
1038208019Sthompsarun_cmdq_cb(void *arg, int pending)
1039208019Sthompsa{
1040208019Sthompsa	struct run_softc *sc = arg;
1041208019Sthompsa	uint8_t i;
1042208019Sthompsa
1043208019Sthompsa	/* call cmdq[].func locked */
1044208019Sthompsa	RUN_LOCK(sc);
1045209917Sthompsa	for (i = sc->cmdq_exec; sc->cmdq[i].func && pending;
1046209917Sthompsa	    i = sc->cmdq_exec, pending--) {
1047208019Sthompsa		DPRINTFN(6, "cmdq_exec=%d pending=%d\n", i, pending);
1048209917Sthompsa		if (sc->cmdq_run == RUN_CMDQ_GO) {
1049208019Sthompsa			/*
1050208019Sthompsa			 * If arg0 is NULL, callback func needs more
1051208019Sthompsa			 * than one arg. So, pass ptr to cmdq struct.
1052208019Sthompsa			 */
1053209917Sthompsa			if (sc->cmdq[i].arg0)
1054208019Sthompsa				sc->cmdq[i].func(sc->cmdq[i].arg0);
1055208019Sthompsa			else
1056208019Sthompsa				sc->cmdq[i].func(&sc->cmdq[i]);
1057208019Sthompsa		}
1058208019Sthompsa		sc->cmdq[i].arg0 = NULL;
1059208019Sthompsa		sc->cmdq[i].func = NULL;
1060208019Sthompsa		sc->cmdq_exec++;
1061208019Sthompsa		sc->cmdq_exec &= RUN_CMDQ_MASQ;
1062208019Sthompsa	}
1063208019Sthompsa	RUN_UNLOCK(sc);
1064208019Sthompsa}
1065208019Sthompsa
1066208019Sthompsastatic void
1067203134Sthompsarun_setup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
1068203134Sthompsa{
1069203134Sthompsa	struct run_tx_data *data;
1070203134Sthompsa
1071203134Sthompsa	memset(pq, 0, sizeof(*pq));
1072203134Sthompsa
1073203134Sthompsa	STAILQ_INIT(&pq->tx_qh);
1074203134Sthompsa	STAILQ_INIT(&pq->tx_fh);
1075203134Sthompsa
1076203134Sthompsa	for (data = &pq->tx_data[0];
1077203134Sthompsa	    data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) {
1078203134Sthompsa		data->sc = sc;
1079203134Sthompsa		STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
1080203134Sthompsa	}
1081203134Sthompsa	pq->tx_nfree = RUN_TX_RING_COUNT;
1082203134Sthompsa}
1083203134Sthompsa
1084203134Sthompsastatic void
1085203134Sthompsarun_unsetup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
1086203134Sthompsa{
1087203134Sthompsa	struct run_tx_data *data;
1088203134Sthompsa
1089203134Sthompsa	/* make sure any subsequent use of the queues will fail */
1090203134Sthompsa	pq->tx_nfree = 0;
1091203134Sthompsa	STAILQ_INIT(&pq->tx_fh);
1092203134Sthompsa	STAILQ_INIT(&pq->tx_qh);
1093203134Sthompsa
1094203134Sthompsa	/* free up all node references and mbufs */
1095203134Sthompsa	for (data = &pq->tx_data[0];
1096209917Sthompsa	    data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) {
1097203134Sthompsa		if (data->m != NULL) {
1098203134Sthompsa			m_freem(data->m);
1099203134Sthompsa			data->m = NULL;
1100203134Sthompsa		}
1101203134Sthompsa		if (data->ni != NULL) {
1102203134Sthompsa			ieee80211_free_node(data->ni);
1103203134Sthompsa			data->ni = NULL;
1104203134Sthompsa		}
1105203134Sthompsa	}
1106203134Sthompsa}
1107203134Sthompsa
1108220235Skevlostatic int
1109203134Sthompsarun_load_microcode(struct run_softc *sc)
1110203134Sthompsa{
1111203134Sthompsa	usb_device_request_t req;
1112203137Sthompsa	const struct firmware *fw;
1113203134Sthompsa	const u_char *base;
1114203134Sthompsa	uint32_t tmp;
1115203134Sthompsa	int ntries, error;
1116203134Sthompsa	const uint64_t *temp;
1117203134Sthompsa	uint64_t bytes;
1118203134Sthompsa
1119205042Sthompsa	RUN_UNLOCK(sc);
1120203137Sthompsa	fw = firmware_get("runfw");
1121205042Sthompsa	RUN_LOCK(sc);
1122209917Sthompsa	if (fw == NULL) {
1123203138Sthompsa		device_printf(sc->sc_dev,
1124203138Sthompsa		    "failed loadfirmware of file %s\n", "runfw");
1125203134Sthompsa		return ENOENT;
1126203134Sthompsa	}
1127203134Sthompsa
1128203137Sthompsa	if (fw->datasize != 8192) {
1129203138Sthompsa		device_printf(sc->sc_dev,
1130203138Sthompsa		    "invalid firmware size (should be 8KB)\n");
1131203137Sthompsa		error = EINVAL;
1132203137Sthompsa		goto fail;
1133203134Sthompsa	}
1134203134Sthompsa
1135203134Sthompsa	/*
1136203134Sthompsa	 * RT3071/RT3072 use a different firmware
1137203134Sthompsa	 * run-rt2870 (8KB) contains both,
1138203134Sthompsa	 * first half (4KB) is for rt2870,
1139203134Sthompsa	 * last half is for rt3071.
1140203134Sthompsa	 */
1141203137Sthompsa	base = fw->data;
1142205042Sthompsa	if ((sc->mac_ver) != 0x2860 &&
1143205042Sthompsa	    (sc->mac_ver) != 0x2872 &&
1144209917Sthompsa	    (sc->mac_ver) != 0x3070) {
1145203134Sthompsa		base += 4096;
1146205042Sthompsa	}
1147203134Sthompsa
1148203134Sthompsa	/* cheap sanity check */
1149203137Sthompsa	temp = fw->data;
1150203134Sthompsa	bytes = *temp;
1151259453Shselasky	if (bytes != be64toh(0xffffff0210280210ULL)) {
1152203138Sthompsa		device_printf(sc->sc_dev, "firmware checksum failed\n");
1153203137Sthompsa		error = EINVAL;
1154203137Sthompsa		goto fail;
1155203137Sthompsa	}
1156203134Sthompsa
1157203134Sthompsa	/* write microcode image */
1158262604Skevlo	if (sc->sc_flags & RUN_FLAG_FWLOAD_NEEDED) {
1159261868Skevlo		run_write_region_1(sc, RT2870_FW_BASE, base, 4096);
1160261868Skevlo		run_write(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff);
1161261868Skevlo		run_write(sc, RT2860_H2M_MAILBOX_STATUS, 0xffffffff);
1162261868Skevlo	}
1163203134Sthompsa
1164203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1165203134Sthompsa	req.bRequest = RT2870_RESET;
1166203134Sthompsa	USETW(req.wValue, 8);
1167203134Sthompsa	USETW(req.wIndex, 0);
1168203134Sthompsa	USETW(req.wLength, 0);
1169220235Skevlo	if ((error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL))
1170220235Skevlo	    != 0) {
1171203138Sthompsa		device_printf(sc->sc_dev, "firmware reset failed\n");
1172203137Sthompsa		goto fail;
1173203137Sthompsa	}
1174203134Sthompsa
1175203134Sthompsa	run_delay(sc, 10);
1176203134Sthompsa
1177261868Skevlo	run_write(sc, RT2860_H2M_BBPAGENT, 0);
1178203134Sthompsa	run_write(sc, RT2860_H2M_MAILBOX, 0);
1179261868Skevlo	run_write(sc, RT2860_H2M_INTSRC, 0);
1180205042Sthompsa	if ((error = run_mcu_cmd(sc, RT2860_MCU_CMD_RFRESET, 0)) != 0)
1181203137Sthompsa		goto fail;
1182203134Sthompsa
1183203134Sthompsa	/* wait until microcontroller is ready */
1184203134Sthompsa	for (ntries = 0; ntries < 1000; ntries++) {
1185261868Skevlo		if ((error = run_read(sc, RT2860_SYS_CTRL, &tmp)) != 0)
1186203137Sthompsa			goto fail;
1187203134Sthompsa		if (tmp & RT2860_MCU_READY)
1188203134Sthompsa			break;
1189203134Sthompsa		run_delay(sc, 10);
1190203134Sthompsa	}
1191203134Sthompsa	if (ntries == 1000) {
1192203138Sthompsa		device_printf(sc->sc_dev,
1193203138Sthompsa		    "timeout waiting for MCU to initialize\n");
1194203137Sthompsa		error = ETIMEDOUT;
1195203137Sthompsa		goto fail;
1196203134Sthompsa	}
1197233283Sbschmidt	device_printf(sc->sc_dev, "firmware %s ver. %u.%u loaded\n",
1198233283Sbschmidt	    (base == fw->data) ? "RT2870" : "RT3071",
1199233283Sbschmidt	    *(base + 4092), *(base + 4093));
1200203134Sthompsa
1201203137Sthompsafail:
1202203137Sthompsa	firmware_put(fw, FIRMWARE_UNLOAD);
1203203137Sthompsa	return (error);
1204203134Sthompsa}
1205203134Sthompsa
1206259453Shselaskystatic int
1207203134Sthompsarun_reset(struct run_softc *sc)
1208203134Sthompsa{
1209203134Sthompsa	usb_device_request_t req;
1210203134Sthompsa
1211203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1212203134Sthompsa	req.bRequest = RT2870_RESET;
1213203134Sthompsa	USETW(req.wValue, 1);
1214203134Sthompsa	USETW(req.wIndex, 0);
1215203134Sthompsa	USETW(req.wLength, 0);
1216209917Sthompsa	return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL));
1217203134Sthompsa}
1218203134Sthompsa
1219203134Sthompsastatic usb_error_t
1220203134Sthompsarun_do_request(struct run_softc *sc,
1221203134Sthompsa    struct usb_device_request *req, void *data)
1222203134Sthompsa{
1223203134Sthompsa	usb_error_t err;
1224203134Sthompsa	int ntries = 10;
1225203134Sthompsa
1226203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
1227203134Sthompsa
1228203134Sthompsa	while (ntries--) {
1229203134Sthompsa		err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx,
1230203134Sthompsa		    req, data, 0, NULL, 250 /* ms */);
1231203134Sthompsa		if (err == 0)
1232203134Sthompsa			break;
1233203134Sthompsa		DPRINTFN(1, "Control request failed, %s (retrying)\n",
1234203134Sthompsa		    usbd_errstr(err));
1235203134Sthompsa		run_delay(sc, 10);
1236203134Sthompsa	}
1237203134Sthompsa	return (err);
1238203134Sthompsa}
1239203134Sthompsa
1240203134Sthompsastatic int
1241203134Sthompsarun_read(struct run_softc *sc, uint16_t reg, uint32_t *val)
1242203134Sthompsa{
1243203134Sthompsa	uint32_t tmp;
1244203134Sthompsa	int error;
1245203134Sthompsa
1246203134Sthompsa	error = run_read_region_1(sc, reg, (uint8_t *)&tmp, sizeof tmp);
1247203134Sthompsa	if (error == 0)
1248203134Sthompsa		*val = le32toh(tmp);
1249203134Sthompsa	else
1250203134Sthompsa		*val = 0xffffffff;
1251209917Sthompsa	return (error);
1252203134Sthompsa}
1253203134Sthompsa
1254203134Sthompsastatic int
1255203134Sthompsarun_read_region_1(struct run_softc *sc, uint16_t reg, uint8_t *buf, int len)
1256203134Sthompsa{
1257203134Sthompsa	usb_device_request_t req;
1258203134Sthompsa
1259203134Sthompsa	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1260203134Sthompsa	req.bRequest = RT2870_READ_REGION_1;
1261203134Sthompsa	USETW(req.wValue, 0);
1262203134Sthompsa	USETW(req.wIndex, reg);
1263203134Sthompsa	USETW(req.wLength, len);
1264203134Sthompsa
1265209917Sthompsa	return (run_do_request(sc, &req, buf));
1266203134Sthompsa}
1267203134Sthompsa
1268203134Sthompsastatic int
1269203134Sthompsarun_write_2(struct run_softc *sc, uint16_t reg, uint16_t val)
1270203134Sthompsa{
1271203134Sthompsa	usb_device_request_t req;
1272203134Sthompsa
1273203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1274203134Sthompsa	req.bRequest = RT2870_WRITE_2;
1275203134Sthompsa	USETW(req.wValue, val);
1276203134Sthompsa	USETW(req.wIndex, reg);
1277203134Sthompsa	USETW(req.wLength, 0);
1278203134Sthompsa
1279209917Sthompsa	return (run_do_request(sc, &req, NULL));
1280203134Sthompsa}
1281203134Sthompsa
1282203134Sthompsastatic int
1283203134Sthompsarun_write(struct run_softc *sc, uint16_t reg, uint32_t val)
1284203134Sthompsa{
1285203134Sthompsa	int error;
1286203134Sthompsa
1287203134Sthompsa	if ((error = run_write_2(sc, reg, val & 0xffff)) == 0)
1288203134Sthompsa		error = run_write_2(sc, reg + 2, val >> 16);
1289209917Sthompsa	return (error);
1290203134Sthompsa}
1291203134Sthompsa
1292203134Sthompsastatic int
1293203134Sthompsarun_write_region_1(struct run_softc *sc, uint16_t reg, const uint8_t *buf,
1294203134Sthompsa    int len)
1295203134Sthompsa{
1296203134Sthompsa#if 1
1297203134Sthompsa	int i, error = 0;
1298203134Sthompsa	/*
1299203134Sthompsa	 * NB: the WRITE_REGION_1 command is not stable on RT2860.
1300203134Sthompsa	 * We thus issue multiple WRITE_2 commands instead.
1301203134Sthompsa	 */
1302203134Sthompsa	KASSERT((len & 1) == 0, ("run_write_region_1: Data too long.\n"));
1303203134Sthompsa	for (i = 0; i < len && error == 0; i += 2)
1304203134Sthompsa		error = run_write_2(sc, reg + i, buf[i] | buf[i + 1] << 8);
1305209917Sthompsa	return (error);
1306203134Sthompsa#else
1307203134Sthompsa	usb_device_request_t req;
1308259453Shselasky	int error = 0;
1309203134Sthompsa
1310259453Shselasky	/*
1311259453Shselasky	 * NOTE: It appears the WRITE_REGION_1 command cannot be
1312259453Shselasky	 * passed a huge amount of data, which will crash the
1313259453Shselasky	 * firmware. Limit amount of data passed to 64-bytes at a
1314259453Shselasky	 * time.
1315259453Shselasky	 */
1316259453Shselasky	while (len > 0) {
1317259453Shselasky		int delta = 64;
1318259453Shselasky		if (delta > len)
1319259453Shselasky			delta = len;
1320259453Shselasky
1321259453Shselasky		req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1322259453Shselasky		req.bRequest = RT2870_WRITE_REGION_1;
1323259453Shselasky		USETW(req.wValue, 0);
1324259453Shselasky		USETW(req.wIndex, reg);
1325259453Shselasky		USETW(req.wLength, delta);
1326259453Shselasky		error = run_do_request(sc, &req, __DECONST(uint8_t *, buf));
1327259453Shselasky		if (error != 0)
1328259453Shselasky			break;
1329259453Shselasky		reg += delta;
1330259453Shselasky		buf += delta;
1331259453Shselasky		len -= delta;
1332259453Shselasky	}
1333259453Shselasky	return (error);
1334203134Sthompsa#endif
1335203134Sthompsa}
1336203134Sthompsa
1337203134Sthompsastatic int
1338203134Sthompsarun_set_region_4(struct run_softc *sc, uint16_t reg, uint32_t val, int len)
1339203134Sthompsa{
1340203134Sthompsa	int i, error = 0;
1341203134Sthompsa
1342203134Sthompsa	KASSERT((len & 3) == 0, ("run_set_region_4: Invalid data length.\n"));
1343203134Sthompsa	for (i = 0; i < len && error == 0; i += 4)
1344203134Sthompsa		error = run_write(sc, reg + i, val);
1345209917Sthompsa	return (error);
1346203134Sthompsa}
1347203134Sthompsa
1348203134Sthompsastatic int
1349261868Skevlorun_efuse_read(struct run_softc *sc, uint16_t addr, uint16_t *val, int count)
1350203134Sthompsa{
1351203134Sthompsa	uint32_t tmp;
1352203134Sthompsa	uint16_t reg;
1353203134Sthompsa	int error, ntries;
1354203134Sthompsa
1355203134Sthompsa	if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
1356209917Sthompsa		return (error);
1357203134Sthompsa
1358261868Skevlo	if (count == 2)
1359261868Skevlo		addr *= 2;
1360203134Sthompsa	/*-
1361203134Sthompsa	 * Read one 16-byte block into registers EFUSE_DATA[0-3]:
1362203134Sthompsa	 * DATA0: F E D C
1363203134Sthompsa	 * DATA1: B A 9 8
1364203134Sthompsa	 * DATA2: 7 6 5 4
1365203134Sthompsa	 * DATA3: 3 2 1 0
1366203134Sthompsa	 */
1367203134Sthompsa	tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK);
1368203134Sthompsa	tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK;
1369203134Sthompsa	run_write(sc, RT3070_EFUSE_CTRL, tmp);
1370203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1371203134Sthompsa		if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
1372209917Sthompsa			return (error);
1373203134Sthompsa		if (!(tmp & RT3070_EFSROM_KICK))
1374203134Sthompsa			break;
1375203134Sthompsa		run_delay(sc, 2);
1376203134Sthompsa	}
1377203134Sthompsa	if (ntries == 100)
1378209917Sthompsa		return (ETIMEDOUT);
1379203134Sthompsa
1380203134Sthompsa	if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK) {
1381203134Sthompsa		*val = 0xffff;	/* address not found */
1382209917Sthompsa		return (0);
1383203134Sthompsa	}
1384203134Sthompsa	/* determine to which 32-bit register our 16-bit word belongs */
1385203134Sthompsa	reg = RT3070_EFUSE_DATA3 - (addr & 0xc);
1386203134Sthompsa	if ((error = run_read(sc, reg, &tmp)) != 0)
1387209917Sthompsa		return (error);
1388203134Sthompsa
1389261868Skevlo	tmp >>= (8 * (addr & 0x3));
1390261868Skevlo	*val = (addr & 1) ? tmp >> 16 : tmp & 0xffff;
1391261868Skevlo
1392209917Sthompsa	return (0);
1393203134Sthompsa}
1394203134Sthompsa
1395261868Skevlo/* Read 16-bit from eFUSE ROM for RT3xxx. */
1396203134Sthompsastatic int
1397261868Skevlorun_efuse_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
1398261868Skevlo{
1399261868Skevlo	return (run_efuse_read(sc, addr, val, 2));
1400261868Skevlo}
1401261868Skevlo
1402261868Skevlostatic int
1403203134Sthompsarun_eeprom_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
1404203134Sthompsa{
1405203134Sthompsa	usb_device_request_t req;
1406203134Sthompsa	uint16_t tmp;
1407203134Sthompsa	int error;
1408203134Sthompsa
1409203134Sthompsa	addr *= 2;
1410203134Sthompsa	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1411203134Sthompsa	req.bRequest = RT2870_EEPROM_READ;
1412203134Sthompsa	USETW(req.wValue, 0);
1413203134Sthompsa	USETW(req.wIndex, addr);
1414261868Skevlo	USETW(req.wLength, sizeof(tmp));
1415203134Sthompsa
1416203134Sthompsa	error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, &tmp);
1417203134Sthompsa	if (error == 0)
1418203134Sthompsa		*val = le16toh(tmp);
1419203134Sthompsa	else
1420203134Sthompsa		*val = 0xffff;
1421209917Sthompsa	return (error);
1422203134Sthompsa}
1423203134Sthompsa
1424203134Sthompsastatic __inline int
1425203134Sthompsarun_srom_read(struct run_softc *sc, uint16_t addr, uint16_t *val)
1426203134Sthompsa{
1427203134Sthompsa	/* either eFUSE ROM or EEPROM */
1428203134Sthompsa	return sc->sc_srom_read(sc, addr, val);
1429203134Sthompsa}
1430203134Sthompsa
1431203134Sthompsastatic int
1432259453Shselaskyrun_rt2870_rf_write(struct run_softc *sc, uint32_t val)
1433203134Sthompsa{
1434203134Sthompsa	uint32_t tmp;
1435203134Sthompsa	int error, ntries;
1436203134Sthompsa
1437203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1438203134Sthompsa		if ((error = run_read(sc, RT2860_RF_CSR_CFG0, &tmp)) != 0)
1439209917Sthompsa			return (error);
1440203134Sthompsa		if (!(tmp & RT2860_RF_REG_CTRL))
1441203134Sthompsa			break;
1442203134Sthompsa	}
1443203134Sthompsa	if (ntries == 10)
1444209917Sthompsa		return (ETIMEDOUT);
1445203134Sthompsa
1446259453Shselasky	return (run_write(sc, RT2860_RF_CSR_CFG0, val));
1447203134Sthompsa}
1448203134Sthompsa
1449203134Sthompsastatic int
1450203134Sthompsarun_rt3070_rf_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
1451203134Sthompsa{
1452203134Sthompsa	uint32_t tmp;
1453203134Sthompsa	int error, ntries;
1454203134Sthompsa
1455203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1456203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1457209917Sthompsa			return (error);
1458203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1459203134Sthompsa			break;
1460203134Sthompsa	}
1461203134Sthompsa	if (ntries == 100)
1462209917Sthompsa		return (ETIMEDOUT);
1463203134Sthompsa
1464203134Sthompsa	tmp = RT3070_RF_KICK | reg << 8;
1465203134Sthompsa	if ((error = run_write(sc, RT3070_RF_CSR_CFG, tmp)) != 0)
1466209917Sthompsa		return (error);
1467203134Sthompsa
1468203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1469203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1470209917Sthompsa			return (error);
1471203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1472203134Sthompsa			break;
1473203134Sthompsa	}
1474203134Sthompsa	if (ntries == 100)
1475209917Sthompsa		return (ETIMEDOUT);
1476203134Sthompsa
1477203134Sthompsa	*val = tmp & 0xff;
1478209917Sthompsa	return (0);
1479203134Sthompsa}
1480203134Sthompsa
1481203134Sthompsastatic int
1482203134Sthompsarun_rt3070_rf_write(struct run_softc *sc, uint8_t reg, uint8_t val)
1483203134Sthompsa{
1484203134Sthompsa	uint32_t tmp;
1485203134Sthompsa	int error, ntries;
1486203134Sthompsa
1487203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1488203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1489209917Sthompsa			return (error);
1490203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1491203134Sthompsa			break;
1492203134Sthompsa	}
1493203134Sthompsa	if (ntries == 10)
1494209917Sthompsa		return (ETIMEDOUT);
1495203134Sthompsa
1496203134Sthompsa	tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val;
1497209917Sthompsa	return (run_write(sc, RT3070_RF_CSR_CFG, tmp));
1498203134Sthompsa}
1499203134Sthompsa
1500203134Sthompsastatic int
1501203134Sthompsarun_bbp_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
1502203134Sthompsa{
1503203134Sthompsa	uint32_t tmp;
1504203134Sthompsa	int ntries, error;
1505203134Sthompsa
1506203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1507203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1508209917Sthompsa			return (error);
1509203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1510203134Sthompsa			break;
1511203134Sthompsa	}
1512203134Sthompsa	if (ntries == 10)
1513209917Sthompsa		return (ETIMEDOUT);
1514203134Sthompsa
1515203134Sthompsa	tmp = RT2860_BBP_CSR_READ | RT2860_BBP_CSR_KICK | reg << 8;
1516203134Sthompsa	if ((error = run_write(sc, RT2860_BBP_CSR_CFG, tmp)) != 0)
1517209917Sthompsa		return (error);
1518203134Sthompsa
1519203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1520203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1521209917Sthompsa			return (error);
1522203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1523203134Sthompsa			break;
1524203134Sthompsa	}
1525203134Sthompsa	if (ntries == 10)
1526209917Sthompsa		return (ETIMEDOUT);
1527203134Sthompsa
1528203134Sthompsa	*val = tmp & 0xff;
1529209917Sthompsa	return (0);
1530203134Sthompsa}
1531203134Sthompsa
1532203134Sthompsastatic int
1533203134Sthompsarun_bbp_write(struct run_softc *sc, uint8_t reg, uint8_t val)
1534203134Sthompsa{
1535203134Sthompsa	uint32_t tmp;
1536203134Sthompsa	int ntries, error;
1537203134Sthompsa
1538203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1539203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1540209917Sthompsa			return (error);
1541203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1542203134Sthompsa			break;
1543203134Sthompsa	}
1544203134Sthompsa	if (ntries == 10)
1545209917Sthompsa		return (ETIMEDOUT);
1546203134Sthompsa
1547203134Sthompsa	tmp = RT2860_BBP_CSR_KICK | reg << 8 | val;
1548209917Sthompsa	return (run_write(sc, RT2860_BBP_CSR_CFG, tmp));
1549203134Sthompsa}
1550203134Sthompsa
1551203134Sthompsa/*
1552203134Sthompsa * Send a command to the 8051 microcontroller unit.
1553203134Sthompsa */
1554203134Sthompsastatic int
1555203134Sthompsarun_mcu_cmd(struct run_softc *sc, uint8_t cmd, uint16_t arg)
1556203134Sthompsa{
1557203134Sthompsa	uint32_t tmp;
1558203134Sthompsa	int error, ntries;
1559203134Sthompsa
1560203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1561203134Sthompsa		if ((error = run_read(sc, RT2860_H2M_MAILBOX, &tmp)) != 0)
1562203134Sthompsa			return error;
1563203134Sthompsa		if (!(tmp & RT2860_H2M_BUSY))
1564203134Sthompsa			break;
1565203134Sthompsa	}
1566203134Sthompsa	if (ntries == 100)
1567203134Sthompsa		return ETIMEDOUT;
1568203134Sthompsa
1569203134Sthompsa	tmp = RT2860_H2M_BUSY | RT2860_TOKEN_NO_INTR << 16 | arg;
1570203134Sthompsa	if ((error = run_write(sc, RT2860_H2M_MAILBOX, tmp)) == 0)
1571203134Sthompsa		error = run_write(sc, RT2860_HOST_CMD, cmd);
1572209917Sthompsa	return (error);
1573203134Sthompsa}
1574203134Sthompsa
1575203134Sthompsa/*
1576203134Sthompsa * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word.
1577203134Sthompsa * Used to adjust per-rate Tx power registers.
1578203134Sthompsa */
1579203134Sthompsastatic __inline uint32_t
1580203134Sthompsab4inc(uint32_t b32, int8_t delta)
1581203134Sthompsa{
1582203134Sthompsa	int8_t i, b4;
1583203134Sthompsa
1584203134Sthompsa	for (i = 0; i < 8; i++) {
1585203134Sthompsa		b4 = b32 & 0xf;
1586203134Sthompsa		b4 += delta;
1587203134Sthompsa		if (b4 < 0)
1588203134Sthompsa			b4 = 0;
1589203134Sthompsa		else if (b4 > 0xf)
1590203134Sthompsa			b4 = 0xf;
1591203134Sthompsa		b32 = b32 >> 4 | b4 << 28;
1592203134Sthompsa	}
1593209917Sthompsa	return (b32);
1594203134Sthompsa}
1595203134Sthompsa
1596203134Sthompsastatic const char *
1597259453Shselaskyrun_get_rf(uint16_t rev)
1598203134Sthompsa{
1599203134Sthompsa	switch (rev) {
1600203134Sthompsa	case RT2860_RF_2820:	return "RT2820";
1601203134Sthompsa	case RT2860_RF_2850:	return "RT2850";
1602203134Sthompsa	case RT2860_RF_2720:	return "RT2720";
1603203134Sthompsa	case RT2860_RF_2750:	return "RT2750";
1604203134Sthompsa	case RT3070_RF_3020:	return "RT3020";
1605203134Sthompsa	case RT3070_RF_2020:	return "RT2020";
1606203134Sthompsa	case RT3070_RF_3021:	return "RT3021";
1607203134Sthompsa	case RT3070_RF_3022:	return "RT3022";
1608203134Sthompsa	case RT3070_RF_3052:	return "RT3052";
1609261868Skevlo	case RT3593_RF_3053:	return "RT3053";
1610259453Shselasky	case RT5592_RF_5592:	return "RT5592";
1611259453Shselasky	case RT5390_RF_5370:	return "RT5370";
1612259453Shselasky	case RT5390_RF_5372:	return "RT5372";
1613203134Sthompsa	}
1614209917Sthompsa	return ("unknown");
1615203134Sthompsa}
1616203134Sthompsa
1617261868Skevlostatic void
1618261868Skevlorun_rt3593_get_txpower(struct run_softc *sc)
1619261868Skevlo{
1620261868Skevlo	uint16_t addr, val;
1621261868Skevlo	int i;
1622261868Skevlo
1623261868Skevlo	/* Read power settings for 2GHz channels. */
1624261868Skevlo	for (i = 0; i < 14; i += 2) {
1625261868Skevlo		addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE1 :
1626261868Skevlo		    RT2860_EEPROM_PWR2GHZ_BASE1;
1627261868Skevlo		run_srom_read(sc, addr + i / 2, &val);
1628261868Skevlo		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
1629261868Skevlo		sc->txpow1[i + 1] = (int8_t)(val >> 8);
1630261868Skevlo
1631261868Skevlo		addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE2 :
1632261868Skevlo		    RT2860_EEPROM_PWR2GHZ_BASE2;
1633261868Skevlo		run_srom_read(sc, addr + i / 2, &val);
1634261868Skevlo		sc->txpow2[i + 0] = (int8_t)(val & 0xff);
1635261868Skevlo		sc->txpow2[i + 1] = (int8_t)(val >> 8);
1636261868Skevlo
1637261868Skevlo		if (sc->ntxchains == 3) {
1638261868Skevlo			run_srom_read(sc, RT3593_EEPROM_PWR2GHZ_BASE3 + i / 2,
1639261868Skevlo			    &val);
1640261868Skevlo			sc->txpow3[i + 0] = (int8_t)(val & 0xff);
1641261868Skevlo			sc->txpow3[i + 1] = (int8_t)(val >> 8);
1642261868Skevlo		}
1643261868Skevlo	}
1644261868Skevlo	/* Fix broken Tx power entries. */
1645261868Skevlo	for (i = 0; i < 14; i++) {
1646261868Skevlo		if (sc->txpow1[i] > 31)
1647261868Skevlo			sc->txpow1[i] = 5;
1648261868Skevlo		if (sc->txpow2[i] > 31)
1649261868Skevlo			sc->txpow2[i] = 5;
1650261868Skevlo		if (sc->ntxchains == 3) {
1651261868Skevlo			if (sc->txpow3[i] > 31)
1652261868Skevlo				sc->txpow3[i] = 5;
1653261868Skevlo		}
1654261868Skevlo	}
1655261868Skevlo	/* Read power settings for 5GHz channels. */
1656261868Skevlo	for (i = 0; i < 40; i += 2) {
1657261868Skevlo		run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
1658261868Skevlo		sc->txpow1[i + 14] = (int8_t)(val & 0xff);
1659261868Skevlo		sc->txpow1[i + 15] = (int8_t)(val >> 8);
1660261868Skevlo
1661261868Skevlo		run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
1662261868Skevlo		sc->txpow2[i + 14] = (int8_t)(val & 0xff);
1663261868Skevlo		sc->txpow2[i + 15] = (int8_t)(val >> 8);
1664261868Skevlo
1665261868Skevlo		if (sc->ntxchains == 3) {
1666261868Skevlo			run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE3 + i / 2,
1667261868Skevlo			    &val);
1668261868Skevlo			sc->txpow3[i + 14] = (int8_t)(val & 0xff);
1669261868Skevlo			sc->txpow3[i + 15] = (int8_t)(val >> 8);
1670261868Skevlo		}
1671261868Skevlo	}
1672261868Skevlo}
1673261868Skevlo
1674261868Skevlostatic void
1675261868Skevlorun_get_txpower(struct run_softc *sc)
1676261868Skevlo{
1677261868Skevlo	uint16_t val;
1678261868Skevlo	int i;
1679261868Skevlo
1680261868Skevlo	/* Read power settings for 2GHz channels. */
1681261868Skevlo	for (i = 0; i < 14; i += 2) {
1682261868Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE1 + i / 2, &val);
1683261868Skevlo		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
1684261868Skevlo		sc->txpow1[i + 1] = (int8_t)(val >> 8);
1685261868Skevlo
1686261868Skevlo		if (sc->mac_ver != 0x5390) {
1687261868Skevlo			run_srom_read(sc,
1688261868Skevlo			    RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2, &val);
1689261868Skevlo			sc->txpow2[i + 0] = (int8_t)(val & 0xff);
1690261868Skevlo			sc->txpow2[i + 1] = (int8_t)(val >> 8);
1691261868Skevlo		}
1692261868Skevlo	}
1693261868Skevlo	/* Fix broken Tx power entries. */
1694261868Skevlo	for (i = 0; i < 14; i++) {
1695261868Skevlo		if (sc->mac_ver >= 0x5390) {
1696261868Skevlo			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 27)
1697261868Skevlo				sc->txpow1[i] = 5;
1698261868Skevlo		} else {
1699261868Skevlo			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31)
1700261868Skevlo				sc->txpow1[i] = 5;
1701261868Skevlo		}
1702261868Skevlo		if (sc->mac_ver > 0x5390) {
1703261868Skevlo			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 27)
1704261868Skevlo				sc->txpow2[i] = 5;
1705261868Skevlo		} else if (sc->mac_ver < 0x5390) {
1706261868Skevlo			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31)
1707261868Skevlo				sc->txpow2[i] = 5;
1708261868Skevlo		}
1709261868Skevlo		DPRINTF("chan %d: power1=%d, power2=%d\n",
1710261868Skevlo		    rt2860_rf2850[i].chan, sc->txpow1[i], sc->txpow2[i]);
1711261868Skevlo	}
1712261868Skevlo	/* Read power settings for 5GHz channels. */
1713261868Skevlo	for (i = 0; i < 40; i += 2) {
1714261868Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
1715261868Skevlo		sc->txpow1[i + 14] = (int8_t)(val & 0xff);
1716261868Skevlo		sc->txpow1[i + 15] = (int8_t)(val >> 8);
1717261868Skevlo
1718261868Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
1719261868Skevlo		sc->txpow2[i + 14] = (int8_t)(val & 0xff);
1720261868Skevlo		sc->txpow2[i + 15] = (int8_t)(val >> 8);
1721261868Skevlo	}
1722261868Skevlo	/* Fix broken Tx power entries. */
1723261868Skevlo	for (i = 0; i < 40; i++ ) {
1724261868Skevlo		if (sc->mac_ver != 0x5592) {
1725261868Skevlo			if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15)
1726261868Skevlo				sc->txpow1[14 + i] = 5;
1727261868Skevlo			if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15)
1728261868Skevlo				sc->txpow2[14 + i] = 5;
1729261868Skevlo		}
1730261868Skevlo		DPRINTF("chan %d: power1=%d, power2=%d\n",
1731261868Skevlo		    rt2860_rf2850[14 + i].chan, sc->txpow1[14 + i],
1732261868Skevlo		    sc->txpow2[14 + i]);
1733261868Skevlo	}
1734261868Skevlo}
1735261868Skevlo
1736259453Shselaskystatic int
1737203134Sthompsarun_read_eeprom(struct run_softc *sc)
1738203134Sthompsa{
1739203134Sthompsa	int8_t delta_2ghz, delta_5ghz;
1740203134Sthompsa	uint32_t tmp;
1741203134Sthompsa	uint16_t val;
1742203134Sthompsa	int ridx, ant, i;
1743203134Sthompsa
1744203134Sthompsa	/* check whether the ROM is eFUSE ROM or EEPROM */
1745203134Sthompsa	sc->sc_srom_read = run_eeprom_read_2;
1746205042Sthompsa	if (sc->mac_ver >= 0x3070) {
1747203134Sthompsa		run_read(sc, RT3070_EFUSE_CTRL, &tmp);
1748203134Sthompsa		DPRINTF("EFUSE_CTRL=0x%08x\n", tmp);
1749261868Skevlo		if ((tmp & RT3070_SEL_EFUSE) || sc->mac_ver == 0x3593)
1750203134Sthompsa			sc->sc_srom_read = run_efuse_read_2;
1751203134Sthompsa	}
1752203134Sthompsa
1753203134Sthompsa	/* read ROM version */
1754203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_VERSION, &val);
1755203134Sthompsa	DPRINTF("EEPROM rev=%d, FAE=%d\n", val & 0xff, val >> 8);
1756203134Sthompsa
1757203134Sthompsa	/* read MAC address */
1758203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC01, &val);
1759203134Sthompsa	sc->sc_bssid[0] = val & 0xff;
1760203134Sthompsa	sc->sc_bssid[1] = val >> 8;
1761203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC23, &val);
1762203134Sthompsa	sc->sc_bssid[2] = val & 0xff;
1763203134Sthompsa	sc->sc_bssid[3] = val >> 8;
1764203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC45, &val);
1765203134Sthompsa	sc->sc_bssid[4] = val & 0xff;
1766203134Sthompsa	sc->sc_bssid[5] = val >> 8;
1767203134Sthompsa
1768261868Skevlo	if (sc->mac_ver < 0x3593) {
1769259453Shselasky		/* read vender BBP settings */
1770205042Sthompsa		for (i = 0; i < 10; i++) {
1771259453Shselasky			run_srom_read(sc, RT2860_EEPROM_BBP_BASE + i, &val);
1772259453Shselasky			sc->bbp[i].val = val & 0xff;
1773259453Shselasky			sc->bbp[i].reg = val >> 8;
1774259453Shselasky			DPRINTF("BBP%d=0x%02x\n", sc->bbp[i].reg,
1775259453Shselasky			    sc->bbp[i].val);
1776205042Sthompsa		}
1777259453Shselasky		if (sc->mac_ver >= 0x3071) {
1778259453Shselasky			/* read vendor RF settings */
1779259453Shselasky			for (i = 0; i < 10; i++) {
1780259453Shselasky				run_srom_read(sc, RT3071_EEPROM_RF_BASE + i,
1781259453Shselasky				   &val);
1782259453Shselasky				sc->rf[i].val = val & 0xff;
1783259453Shselasky				sc->rf[i].reg = val >> 8;
1784259453Shselasky				DPRINTF("RF%d=0x%02x\n", sc->rf[i].reg,
1785259453Shselasky				    sc->rf[i].val);
1786259453Shselasky			}
1787259453Shselasky		}
1788205042Sthompsa	}
1789203134Sthompsa
1790203134Sthompsa	/* read RF frequency offset from EEPROM */
1791261868Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS :
1792261868Skevlo	    RT3593_EEPROM_FREQ, &val);
1793203134Sthompsa	sc->freq = ((val & 0xff) != 0xff) ? val & 0xff : 0;
1794203134Sthompsa	DPRINTF("EEPROM freq offset %d\n", sc->freq & 0xff);
1795203134Sthompsa
1796261868Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS :
1797261868Skevlo	    RT3593_EEPROM_FREQ_LEDS, &val);
1798205042Sthompsa	if (val >> 8 != 0xff) {
1799203134Sthompsa		/* read LEDs operating mode */
1800205042Sthompsa		sc->leds = val >> 8;
1801261868Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED1 :
1802261868Skevlo		    RT3593_EEPROM_LED1, &sc->led[0]);
1803261868Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED2 :
1804261868Skevlo		    RT3593_EEPROM_LED2, &sc->led[1]);
1805261868Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED3 :
1806261868Skevlo		    RT3593_EEPROM_LED3, &sc->led[2]);
1807203134Sthompsa	} else {
1808203134Sthompsa		/* broken EEPROM, use default settings */
1809203134Sthompsa		sc->leds = 0x01;
1810203134Sthompsa		sc->led[0] = 0x5555;
1811203134Sthompsa		sc->led[1] = 0x2221;
1812203134Sthompsa		sc->led[2] = 0x5627;	/* differs from RT2860 */
1813203134Sthompsa	}
1814203134Sthompsa	DPRINTF("EEPROM LED mode=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n",
1815203134Sthompsa	    sc->leds, sc->led[0], sc->led[1], sc->led[2]);
1816203134Sthompsa
1817203134Sthompsa	/* read RF information */
1818259453Shselasky	if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392)
1819259453Shselasky		run_srom_read(sc, 0x00, &val);
1820259453Shselasky	else
1821259453Shselasky		run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
1822259453Shselasky
1823203134Sthompsa	if (val == 0xffff) {
1824261868Skevlo		device_printf(sc->sc_dev,
1825261868Skevlo		    "invalid EEPROM antenna info, using default\n");
1826203134Sthompsa		DPRINTF("invalid EEPROM antenna info, using default\n");
1827205042Sthompsa		if (sc->mac_ver == 0x3572) {
1828205042Sthompsa			/* default to RF3052 2T2R */
1829205042Sthompsa			sc->rf_rev = RT3070_RF_3052;
1830205042Sthompsa			sc->ntxchains = 2;
1831205042Sthompsa			sc->nrxchains = 2;
1832205042Sthompsa		} else if (sc->mac_ver >= 0x3070) {
1833203134Sthompsa			/* default to RF3020 1T1R */
1834203134Sthompsa			sc->rf_rev = RT3070_RF_3020;
1835203134Sthompsa			sc->ntxchains = 1;
1836203134Sthompsa			sc->nrxchains = 1;
1837203134Sthompsa		} else {
1838203134Sthompsa			/* default to RF2820 1T2R */
1839203134Sthompsa			sc->rf_rev = RT2860_RF_2820;
1840203134Sthompsa			sc->ntxchains = 1;
1841203134Sthompsa			sc->nrxchains = 2;
1842203134Sthompsa		}
1843203134Sthompsa	} else {
1844259453Shselasky		if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392) {
1845259453Shselasky			sc->rf_rev = val;
1846259453Shselasky			run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
1847259453Shselasky		} else
1848259453Shselasky			sc->rf_rev = (val >> 8) & 0xf;
1849203134Sthompsa		sc->ntxchains = (val >> 4) & 0xf;
1850203134Sthompsa		sc->nrxchains = val & 0xf;
1851203134Sthompsa	}
1852259453Shselasky	DPRINTF("EEPROM RF rev=0x%04x chains=%dT%dR\n",
1853203134Sthompsa	    sc->rf_rev, sc->ntxchains, sc->nrxchains);
1854203134Sthompsa
1855208019Sthompsa	/* check if RF supports automatic Tx access gain control */
1856203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_CONFIG, &val);
1857203134Sthompsa	DPRINTF("EEPROM CFG 0x%04x\n", val);
1858205042Sthompsa	/* check if driver should patch the DAC issue */
1859205042Sthompsa	if ((val >> 8) != 0xff)
1860205042Sthompsa		sc->patch_dac = (val >> 15) & 1;
1861203134Sthompsa	if ((val & 0xff) != 0xff) {
1862203134Sthompsa		sc->ext_5ghz_lna = (val >> 3) & 1;
1863203134Sthompsa		sc->ext_2ghz_lna = (val >> 2) & 1;
1864205042Sthompsa		/* check if RF supports automatic Tx access gain control */
1865203134Sthompsa		sc->calib_2ghz = sc->calib_5ghz = (val >> 1) & 1;
1866205042Sthompsa		/* check if we have a hardware radio switch */
1867205042Sthompsa		sc->rfswitch = val & 1;
1868203134Sthompsa	}
1869203134Sthompsa
1870261868Skevlo	/* Read Tx power settings. */
1871261868Skevlo	if (sc->mac_ver == 0x3593)
1872261868Skevlo		run_rt3593_get_txpower(sc);
1873261868Skevlo	else
1874261868Skevlo		run_get_txpower(sc);
1875203134Sthompsa
1876203134Sthompsa	/* read Tx power compensation for each Tx rate */
1877203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_DELTAPWR, &val);
1878203134Sthompsa	delta_2ghz = delta_5ghz = 0;
1879203134Sthompsa	if ((val & 0xff) != 0xff && (val & 0x80)) {
1880203134Sthompsa		delta_2ghz = val & 0xf;
1881203134Sthompsa		if (!(val & 0x40))	/* negative number */
1882203134Sthompsa			delta_2ghz = -delta_2ghz;
1883203134Sthompsa	}
1884203134Sthompsa	val >>= 8;
1885203134Sthompsa	if ((val & 0xff) != 0xff && (val & 0x80)) {
1886203134Sthompsa		delta_5ghz = val & 0xf;
1887203134Sthompsa		if (!(val & 0x40))	/* negative number */
1888203134Sthompsa			delta_5ghz = -delta_5ghz;
1889203134Sthompsa	}
1890203134Sthompsa	DPRINTF("power compensation=%d (2GHz), %d (5GHz)\n",
1891203134Sthompsa	    delta_2ghz, delta_5ghz);
1892203134Sthompsa
1893203134Sthompsa	for (ridx = 0; ridx < 5; ridx++) {
1894203134Sthompsa		uint32_t reg;
1895203134Sthompsa
1896208019Sthompsa		run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2, &val);
1897208019Sthompsa		reg = val;
1898208019Sthompsa		run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2 + 1, &val);
1899208019Sthompsa		reg |= (uint32_t)val << 16;
1900203134Sthompsa
1901203134Sthompsa		sc->txpow20mhz[ridx] = reg;
1902203134Sthompsa		sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz);
1903203134Sthompsa		sc->txpow40mhz_5ghz[ridx] = b4inc(reg, delta_5ghz);
1904203134Sthompsa
1905203134Sthompsa		DPRINTF("ridx %d: power 20MHz=0x%08x, 40MHz/2GHz=0x%08x, "
1906203134Sthompsa		    "40MHz/5GHz=0x%08x\n", ridx, sc->txpow20mhz[ridx],
1907203134Sthompsa		    sc->txpow40mhz_2ghz[ridx], sc->txpow40mhz_5ghz[ridx]);
1908203134Sthompsa	}
1909203134Sthompsa
1910261868Skevlo	/* Read RSSI offsets and LNA gains from EEPROM. */
1911261868Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_2GHZ :
1912261868Skevlo	    RT3593_EEPROM_RSSI1_2GHZ, &val);
1913203134Sthompsa	sc->rssi_2ghz[0] = val & 0xff;	/* Ant A */
1914203134Sthompsa	sc->rssi_2ghz[1] = val >> 8;	/* Ant B */
1915261868Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_2GHZ :
1916261868Skevlo	    RT3593_EEPROM_RSSI2_2GHZ, &val);
1917205042Sthompsa	if (sc->mac_ver >= 0x3070) {
1918261868Skevlo		if (sc->mac_ver == 0x3593) {
1919261868Skevlo			sc->txmixgain_2ghz = 0;
1920261868Skevlo			sc->rssi_2ghz[2] = val & 0xff;	/* Ant C */
1921261868Skevlo		} else {
1922261868Skevlo			/*
1923261868Skevlo			 * On RT3070 chips (limited to 2 Rx chains), this ROM
1924261868Skevlo			 * field contains the Tx mixer gain for the 2GHz band.
1925261868Skevlo			 */
1926261868Skevlo			if ((val & 0xff) != 0xff)
1927261868Skevlo				sc->txmixgain_2ghz = val & 0x7;
1928261868Skevlo		}
1929205042Sthompsa		DPRINTF("tx mixer gain=%u (2GHz)\n", sc->txmixgain_2ghz);
1930205042Sthompsa	} else
1931205042Sthompsa		sc->rssi_2ghz[2] = val & 0xff;	/* Ant C */
1932261868Skevlo	if (sc->mac_ver == 0x3593)
1933261868Skevlo		run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val);
1934203134Sthompsa	sc->lna[2] = val >> 8;		/* channel group 2 */
1935203134Sthompsa
1936261868Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_5GHZ :
1937261868Skevlo	    RT3593_EEPROM_RSSI1_5GHZ, &val);
1938203134Sthompsa	sc->rssi_5ghz[0] = val & 0xff;	/* Ant A */
1939203134Sthompsa	sc->rssi_5ghz[1] = val >> 8;	/* Ant B */
1940261868Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_5GHZ :
1941261868Skevlo	    RT3593_EEPROM_RSSI2_5GHZ, &val);
1942205042Sthompsa	if (sc->mac_ver == 0x3572) {
1943205042Sthompsa		/*
1944205042Sthompsa		 * On RT3572 chips (limited to 2 Rx chains), this ROM
1945205042Sthompsa		 * field contains the Tx mixer gain for the 5GHz band.
1946205042Sthompsa		 */
1947205042Sthompsa		if ((val & 0xff) != 0xff)
1948205042Sthompsa			sc->txmixgain_5ghz = val & 0x7;
1949205042Sthompsa		DPRINTF("tx mixer gain=%u (5GHz)\n", sc->txmixgain_5ghz);
1950205042Sthompsa	} else
1951205042Sthompsa		sc->rssi_5ghz[2] = val & 0xff;	/* Ant C */
1952261868Skevlo	if (sc->mac_ver == 0x3593) {
1953261868Skevlo		sc->txmixgain_5ghz = 0;
1954261868Skevlo		run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val);
1955261868Skevlo	}
1956203134Sthompsa	sc->lna[3] = val >> 8;		/* channel group 3 */
1957203134Sthompsa
1958261868Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LNA :
1959261868Skevlo	    RT3593_EEPROM_LNA, &val);
1960203134Sthompsa	sc->lna[0] = val & 0xff;	/* channel group 0 */
1961203134Sthompsa	sc->lna[1] = val >> 8;		/* channel group 1 */
1962203134Sthompsa
1963203134Sthompsa	/* fix broken 5GHz LNA entries */
1964203134Sthompsa	if (sc->lna[2] == 0 || sc->lna[2] == 0xff) {
1965203134Sthompsa		DPRINTF("invalid LNA for channel group %d\n", 2);
1966203134Sthompsa		sc->lna[2] = sc->lna[1];
1967203134Sthompsa	}
1968203134Sthompsa	if (sc->lna[3] == 0 || sc->lna[3] == 0xff) {
1969203134Sthompsa		DPRINTF("invalid LNA for channel group %d\n", 3);
1970203134Sthompsa		sc->lna[3] = sc->lna[1];
1971203134Sthompsa	}
1972203134Sthompsa
1973203134Sthompsa	/* fix broken RSSI offset entries */
1974203134Sthompsa	for (ant = 0; ant < 3; ant++) {
1975203134Sthompsa		if (sc->rssi_2ghz[ant] < -10 || sc->rssi_2ghz[ant] > 10) {
1976203134Sthompsa			DPRINTF("invalid RSSI%d offset: %d (2GHz)\n",
1977203134Sthompsa			    ant + 1, sc->rssi_2ghz[ant]);
1978203134Sthompsa			sc->rssi_2ghz[ant] = 0;
1979203134Sthompsa		}
1980203134Sthompsa		if (sc->rssi_5ghz[ant] < -10 || sc->rssi_5ghz[ant] > 10) {
1981203134Sthompsa			DPRINTF("invalid RSSI%d offset: %d (5GHz)\n",
1982203134Sthompsa			    ant + 1, sc->rssi_5ghz[ant]);
1983203134Sthompsa			sc->rssi_5ghz[ant] = 0;
1984203134Sthompsa		}
1985203134Sthompsa	}
1986209917Sthompsa	return (0);
1987203134Sthompsa}
1988203134Sthompsa
1989218676Shselaskystatic struct ieee80211_node *
1990203134Sthompsarun_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
1991203134Sthompsa{
1992203134Sthompsa	return malloc(sizeof (struct run_node), M_DEVBUF, M_NOWAIT | M_ZERO);
1993203134Sthompsa}
1994203134Sthompsa
1995203134Sthompsastatic int
1996203134Sthompsarun_media_change(struct ifnet *ifp)
1997203134Sthompsa{
1998208019Sthompsa	struct ieee80211vap *vap = ifp->if_softc;
1999208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2000203134Sthompsa	const struct ieee80211_txparam *tp;
2001208019Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2002203134Sthompsa	uint8_t rate, ridx;
2003203134Sthompsa	int error;
2004203134Sthompsa
2005203134Sthompsa	RUN_LOCK(sc);
2006203134Sthompsa
2007203134Sthompsa	error = ieee80211_media_change(ifp);
2008209917Sthompsa	if (error != ENETRESET) {
2009203134Sthompsa		RUN_UNLOCK(sc);
2010209917Sthompsa		return (error);
2011208019Sthompsa	}
2012203134Sthompsa
2013203134Sthompsa	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
2014203134Sthompsa	if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
2015212127Sthompsa		struct ieee80211_node *ni;
2016212127Sthompsa		struct run_node	*rn;
2017212127Sthompsa
2018203134Sthompsa		rate = ic->ic_sup_rates[ic->ic_curmode].
2019203134Sthompsa		    rs_rates[tp->ucastrate] & IEEE80211_RATE_VAL;
2020203134Sthompsa		for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2021203134Sthompsa			if (rt2860_rates[ridx].rate == rate)
2022203134Sthompsa				break;
2023212127Sthompsa		ni = ieee80211_ref_node(vap->iv_bss);
2024212127Sthompsa		rn = (struct run_node *)ni;
2025208019Sthompsa		rn->fix_ridx = ridx;
2026208019Sthompsa		DPRINTF("rate=%d, fix_ridx=%d\n", rate, rn->fix_ridx);
2027212127Sthompsa		ieee80211_free_node(ni);
2028203134Sthompsa	}
2029203134Sthompsa
2030208019Sthompsa#if 0
2031203134Sthompsa	if ((ifp->if_flags & IFF_UP) &&
2032203134Sthompsa	    (ifp->if_drv_flags &  IFF_DRV_RUNNING)){
2033203134Sthompsa		run_init_locked(sc);
2034203134Sthompsa	}
2035208019Sthompsa#endif
2036203134Sthompsa
2037203134Sthompsa	RUN_UNLOCK(sc);
2038203134Sthompsa
2039209917Sthompsa	return (0);
2040203134Sthompsa}
2041203134Sthompsa
2042203134Sthompsastatic int
2043203134Sthompsarun_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
2044203134Sthompsa{
2045203134Sthompsa	const struct ieee80211_txparam *tp;
2046203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2047203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2048203134Sthompsa	struct run_vap *rvp = RUN_VAP(vap);
2049203134Sthompsa	enum ieee80211_state ostate;
2050208019Sthompsa	uint32_t sta[3];
2051203134Sthompsa	uint32_t tmp;
2052208019Sthompsa	uint8_t ratectl;
2053208019Sthompsa	uint8_t restart_ratectl = 0;
2054208019Sthompsa	uint8_t bid = 1 << rvp->rvp_id;
2055203134Sthompsa
2056203134Sthompsa	ostate = vap->iv_state;
2057203134Sthompsa	DPRINTF("%s -> %s\n",
2058203134Sthompsa		ieee80211_state_name[ostate],
2059203134Sthompsa		ieee80211_state_name[nstate]);
2060203134Sthompsa
2061203134Sthompsa	IEEE80211_UNLOCK(ic);
2062203134Sthompsa	RUN_LOCK(sc);
2063203134Sthompsa
2064208019Sthompsa	ratectl = sc->ratectl_run; /* remember current state */
2065208019Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
2066208019Sthompsa	usb_callout_stop(&sc->ratectl_ch);
2067203134Sthompsa
2068203134Sthompsa	if (ostate == IEEE80211_S_RUN) {
2069203134Sthompsa		/* turn link LED off */
2070203134Sthompsa		run_set_leds(sc, RT2860_LED_RADIO);
2071203134Sthompsa	}
2072203134Sthompsa
2073203134Sthompsa	switch (nstate) {
2074203134Sthompsa	case IEEE80211_S_INIT:
2075208019Sthompsa		restart_ratectl = 1;
2076208019Sthompsa
2077208019Sthompsa		if (ostate != IEEE80211_S_RUN)
2078208019Sthompsa			break;
2079208019Sthompsa
2080208019Sthompsa		ratectl &= ~bid;
2081208019Sthompsa		sc->runbmap &= ~bid;
2082208019Sthompsa
2083208019Sthompsa		/* abort TSF synchronization if there is no vap running */
2084209917Sthompsa		if (--sc->running == 0) {
2085203134Sthompsa			run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
2086203134Sthompsa			run_write(sc, RT2860_BCN_TIME_CFG,
2087203134Sthompsa			    tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
2088203134Sthompsa			    RT2860_TBTT_TIMER_EN));
2089203134Sthompsa		}
2090203134Sthompsa		break;
2091203134Sthompsa
2092203134Sthompsa	case IEEE80211_S_RUN:
2093209917Sthompsa		if (!(sc->runbmap & bid)) {
2094208019Sthompsa			if(sc->running++)
2095208019Sthompsa				restart_ratectl = 1;
2096208019Sthompsa			sc->runbmap |= bid;
2097208019Sthompsa		}
2098203134Sthompsa
2099218492Sbschmidt		m_freem(rvp->beacon_mbuf);
2100218492Sbschmidt		rvp->beacon_mbuf = NULL;
2101218492Sbschmidt
2102209917Sthompsa		switch (vap->iv_opmode) {
2103208019Sthompsa		case IEEE80211_M_HOSTAP:
2104208019Sthompsa		case IEEE80211_M_MBSS:
2105208019Sthompsa			sc->ap_running |= bid;
2106208019Sthompsa			ic->ic_opmode = vap->iv_opmode;
2107208019Sthompsa			run_update_beacon_cb(vap);
2108208019Sthompsa			break;
2109208019Sthompsa		case IEEE80211_M_IBSS:
2110208019Sthompsa			sc->adhoc_running |= bid;
2111209917Sthompsa			if (!sc->ap_running)
2112208019Sthompsa				ic->ic_opmode = vap->iv_opmode;
2113208019Sthompsa			run_update_beacon_cb(vap);
2114208019Sthompsa			break;
2115208019Sthompsa		case IEEE80211_M_STA:
2116208019Sthompsa			sc->sta_running |= bid;
2117209917Sthompsa			if (!sc->ap_running && !sc->adhoc_running)
2118208019Sthompsa				ic->ic_opmode = vap->iv_opmode;
2119208019Sthompsa
2120208019Sthompsa			/* read statistic counters (clear on read) */
2121208019Sthompsa			run_read_region_1(sc, RT2860_TX_STA_CNT0,
2122208019Sthompsa			    (uint8_t *)sta, sizeof sta);
2123208019Sthompsa
2124208019Sthompsa			break;
2125208019Sthompsa		default:
2126208019Sthompsa			ic->ic_opmode = vap->iv_opmode;
2127208019Sthompsa			break;
2128208019Sthompsa		}
2129208019Sthompsa
2130203134Sthompsa		if (vap->iv_opmode != IEEE80211_M_MONITOR) {
2131212127Sthompsa			struct ieee80211_node *ni;
2132212127Sthompsa
2133236439Shselasky			if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) {
2134236439Shselasky				RUN_UNLOCK(sc);
2135236439Shselasky				IEEE80211_LOCK(ic);
2136236439Shselasky				return (-1);
2137236439Shselasky			}
2138203134Sthompsa			run_updateslot(ic->ic_ifp);
2139203134Sthompsa			run_enable_mrr(sc);
2140203134Sthompsa			run_set_txpreamble(sc);
2141203134Sthompsa			run_set_basicrates(sc);
2142212127Sthompsa			ni = ieee80211_ref_node(vap->iv_bss);
2143203134Sthompsa			IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid);
2144203134Sthompsa			run_set_bssid(sc, ni->ni_bssid);
2145212127Sthompsa			ieee80211_free_node(ni);
2146208019Sthompsa			run_enable_tsf_sync(sc);
2147203134Sthompsa
2148208019Sthompsa			/* enable automatic rate adaptation */
2149208019Sthompsa			tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
2150208019Sthompsa			if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
2151208019Sthompsa				ratectl |= bid;
2152203134Sthompsa		}
2153203134Sthompsa
2154203134Sthompsa		/* turn link LED on */
2155203134Sthompsa		run_set_leds(sc, RT2860_LED_RADIO |
2156208019Sthompsa		    (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ?
2157203134Sthompsa		     RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ));
2158203134Sthompsa
2159203134Sthompsa		break;
2160203134Sthompsa	default:
2161203134Sthompsa		DPRINTFN(6, "undefined case\n");
2162203134Sthompsa		break;
2163203134Sthompsa	}
2164203134Sthompsa
2165208019Sthompsa	/* restart amrr for running VAPs */
2166209917Sthompsa	if ((sc->ratectl_run = ratectl) && restart_ratectl)
2167208019Sthompsa		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2168208019Sthompsa
2169203134Sthompsa	RUN_UNLOCK(sc);
2170203134Sthompsa	IEEE80211_LOCK(ic);
2171203134Sthompsa
2172203134Sthompsa	return(rvp->newstate(vap, nstate, arg));
2173203134Sthompsa}
2174203134Sthompsa
2175203134Sthompsa/* ARGSUSED */
2176203134Sthompsastatic void
2177208019Sthompsarun_wme_update_cb(void *arg)
2178203134Sthompsa{
2179203134Sthompsa	struct ieee80211com *ic = arg;
2180203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2181203134Sthompsa	struct ieee80211_wme_state *wmesp = &ic->ic_wme;
2182203134Sthompsa	int aci, error = 0;
2183203134Sthompsa
2184208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2185203134Sthompsa
2186203134Sthompsa	/* update MAC TX configuration registers */
2187203134Sthompsa	for (aci = 0; aci < WME_NUM_AC; aci++) {
2188203134Sthompsa		error = run_write(sc, RT2860_EDCA_AC_CFG(aci),
2189203134Sthompsa		    wmesp->wme_params[aci].wmep_logcwmax << 16 |
2190203134Sthompsa		    wmesp->wme_params[aci].wmep_logcwmin << 12 |
2191203134Sthompsa		    wmesp->wme_params[aci].wmep_aifsn  <<  8 |
2192203134Sthompsa		    wmesp->wme_params[aci].wmep_txopLimit);
2193209917Sthompsa		if (error) goto err;
2194203134Sthompsa	}
2195203134Sthompsa
2196203134Sthompsa	/* update SCH/DMA registers too */
2197203134Sthompsa	error = run_write(sc, RT2860_WMM_AIFSN_CFG,
2198203134Sthompsa	    wmesp->wme_params[WME_AC_VO].wmep_aifsn  << 12 |
2199203134Sthompsa	    wmesp->wme_params[WME_AC_VI].wmep_aifsn  <<  8 |
2200203134Sthompsa	    wmesp->wme_params[WME_AC_BK].wmep_aifsn  <<  4 |
2201203134Sthompsa	    wmesp->wme_params[WME_AC_BE].wmep_aifsn);
2202209917Sthompsa	if (error) goto err;
2203203134Sthompsa	error = run_write(sc, RT2860_WMM_CWMIN_CFG,
2204203134Sthompsa	    wmesp->wme_params[WME_AC_VO].wmep_logcwmin << 12 |
2205203134Sthompsa	    wmesp->wme_params[WME_AC_VI].wmep_logcwmin <<  8 |
2206203134Sthompsa	    wmesp->wme_params[WME_AC_BK].wmep_logcwmin <<  4 |
2207203134Sthompsa	    wmesp->wme_params[WME_AC_BE].wmep_logcwmin);
2208209917Sthompsa	if (error) goto err;
2209203134Sthompsa	error = run_write(sc, RT2860_WMM_CWMAX_CFG,
2210203134Sthompsa	    wmesp->wme_params[WME_AC_VO].wmep_logcwmax << 12 |
2211203134Sthompsa	    wmesp->wme_params[WME_AC_VI].wmep_logcwmax <<  8 |
2212203134Sthompsa	    wmesp->wme_params[WME_AC_BK].wmep_logcwmax <<  4 |
2213203134Sthompsa	    wmesp->wme_params[WME_AC_BE].wmep_logcwmax);
2214209917Sthompsa	if (error) goto err;
2215203134Sthompsa	error = run_write(sc, RT2860_WMM_TXOP0_CFG,
2216203134Sthompsa	    wmesp->wme_params[WME_AC_BK].wmep_txopLimit << 16 |
2217203134Sthompsa	    wmesp->wme_params[WME_AC_BE].wmep_txopLimit);
2218209917Sthompsa	if (error) goto err;
2219203134Sthompsa	error = run_write(sc, RT2860_WMM_TXOP1_CFG,
2220203134Sthompsa	    wmesp->wme_params[WME_AC_VO].wmep_txopLimit << 16 |
2221203134Sthompsa	    wmesp->wme_params[WME_AC_VI].wmep_txopLimit);
2222203134Sthompsa
2223203134Sthompsaerr:
2224209917Sthompsa	if (error)
2225203134Sthompsa		DPRINTF("WME update failed\n");
2226203134Sthompsa
2227203134Sthompsa	return;
2228203134Sthompsa}
2229203134Sthompsa
2230208019Sthompsastatic int
2231208019Sthompsarun_wme_update(struct ieee80211com *ic)
2232208019Sthompsa{
2233208019Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2234208019Sthompsa
2235208019Sthompsa	/* sometime called wothout lock */
2236209917Sthompsa	if (mtx_owned(&ic->ic_comlock.mtx)) {
2237208019Sthompsa		uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
2238208019Sthompsa		DPRINTF("cmdq_store=%d\n", i);
2239208019Sthompsa		sc->cmdq[i].func = run_wme_update_cb;
2240208019Sthompsa		sc->cmdq[i].arg0 = ic;
2241208019Sthompsa		ieee80211_runtask(ic, &sc->cmdq_task);
2242209918Sthompsa		return (0);
2243208019Sthompsa	}
2244208019Sthompsa
2245208019Sthompsa	RUN_LOCK(sc);
2246208019Sthompsa	run_wme_update_cb(ic);
2247208019Sthompsa	RUN_UNLOCK(sc);
2248208019Sthompsa
2249208019Sthompsa	/* return whatever, upper layer desn't care anyway */
2250208019Sthompsa	return (0);
2251208019Sthompsa}
2252208019Sthompsa
2253203134Sthompsastatic void
2254203134Sthompsarun_key_update_begin(struct ieee80211vap *vap)
2255203134Sthompsa{
2256203134Sthompsa	/*
2257208019Sthompsa	 * To avoid out-of-order events, both run_key_set() and
2258208019Sthompsa	 * _delete() are deferred and handled by run_cmdq_cb().
2259208019Sthompsa	 * So, there is nothing we need to do here.
2260203134Sthompsa	 */
2261203134Sthompsa}
2262203134Sthompsa
2263203134Sthompsastatic void
2264203134Sthompsarun_key_update_end(struct ieee80211vap *vap)
2265203134Sthompsa{
2266203134Sthompsa	/* null */
2267203134Sthompsa}
2268203134Sthompsa
2269208019Sthompsastatic void
2270208019Sthompsarun_key_set_cb(void *arg)
2271203134Sthompsa{
2272208019Sthompsa	struct run_cmdq *cmdq = arg;
2273208019Sthompsa	struct ieee80211vap *vap = cmdq->arg1;
2274208019Sthompsa	struct ieee80211_key *k = cmdq->k;
2275203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2276208019Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2277203134Sthompsa	struct ieee80211_node *ni;
2278203134Sthompsa	uint32_t attr;
2279203134Sthompsa	uint16_t base, associd;
2280209144Sthompsa	uint8_t mode, wcid, iv[8];
2281203134Sthompsa
2282208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2283203134Sthompsa
2284209917Sthompsa	if (vap->iv_opmode == IEEE80211_M_HOSTAP)
2285208019Sthompsa		ni = ieee80211_find_vap_node(&ic->ic_sta, vap, cmdq->mac);
2286209144Sthompsa	else
2287203134Sthompsa		ni = vap->iv_bss;
2288208019Sthompsa	associd = (ni != NULL) ? ni->ni_associd : 0;
2289203134Sthompsa
2290203134Sthompsa	/* map net80211 cipher to RT2860 security mode */
2291203134Sthompsa	switch (k->wk_cipher->ic_cipher) {
2292203134Sthompsa	case IEEE80211_CIPHER_WEP:
2293203134Sthompsa		if(k->wk_keylen < 8)
2294203134Sthompsa			mode = RT2860_MODE_WEP40;
2295203134Sthompsa		else
2296203134Sthompsa			mode = RT2860_MODE_WEP104;
2297203134Sthompsa		break;
2298203134Sthompsa	case IEEE80211_CIPHER_TKIP:
2299203134Sthompsa		mode = RT2860_MODE_TKIP;
2300203134Sthompsa		break;
2301203134Sthompsa	case IEEE80211_CIPHER_AES_CCM:
2302203134Sthompsa		mode = RT2860_MODE_AES_CCMP;
2303203134Sthompsa		break;
2304203134Sthompsa	default:
2305203134Sthompsa		DPRINTF("undefined case\n");
2306208019Sthompsa		return;
2307203134Sthompsa	}
2308203134Sthompsa
2309208019Sthompsa	DPRINTFN(1, "associd=%x, keyix=%d, mode=%x, type=%s, tx=%s, rx=%s\n",
2310203134Sthompsa	    associd, k->wk_keyix, mode,
2311208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_GROUP) ? "group" : "pairwise",
2312208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_XMIT) ? "on" : "off",
2313208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_RECV) ? "on" : "off");
2314203134Sthompsa
2315203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2316203134Sthompsa		wcid = 0;	/* NB: update WCID0 for group keys */
2317208019Sthompsa		base = RT2860_SKEY(RUN_VAP(vap)->rvp_id, k->wk_keyix);
2318203134Sthompsa	} else {
2319245047Shselasky		wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
2320245047Shselasky		    1 : RUN_AID2WCID(associd);
2321203134Sthompsa		base = RT2860_PKEY(wcid);
2322203134Sthompsa	}
2323203134Sthompsa
2324203134Sthompsa	if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) {
2325203134Sthompsa		if(run_write_region_1(sc, base, k->wk_key, 16))
2326208019Sthompsa			return;
2327209144Sthompsa		if(run_write_region_1(sc, base + 16, &k->wk_key[16], 8))	/* wk_txmic */
2328208019Sthompsa			return;
2329209144Sthompsa		if(run_write_region_1(sc, base + 24, &k->wk_key[24], 8))	/* wk_rxmic */
2330208019Sthompsa			return;
2331203134Sthompsa	} else {
2332203134Sthompsa		/* roundup len to 16-bit: XXX fix write_region_1() instead */
2333203134Sthompsa		if(run_write_region_1(sc, base, k->wk_key, (k->wk_keylen + 1) & ~1))
2334208019Sthompsa			return;
2335203134Sthompsa	}
2336203134Sthompsa
2337203134Sthompsa	if (!(k->wk_flags & IEEE80211_KEY_GROUP) ||
2338203134Sthompsa	    (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))) {
2339203134Sthompsa		/* set initial packet number in IV+EIV */
2340209917Sthompsa		if (k->wk_cipher == IEEE80211_CIPHER_WEP) {
2341203134Sthompsa			memset(iv, 0, sizeof iv);
2342208019Sthompsa			iv[3] = vap->iv_def_txkey << 6;
2343203134Sthompsa		} else {
2344203134Sthompsa			if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) {
2345203134Sthompsa				iv[0] = k->wk_keytsc >> 8;
2346203134Sthompsa				iv[1] = (iv[0] | 0x20) & 0x7f;
2347203134Sthompsa				iv[2] = k->wk_keytsc;
2348203134Sthompsa			} else /* CCMP */ {
2349203134Sthompsa				iv[0] = k->wk_keytsc;
2350203134Sthompsa				iv[1] = k->wk_keytsc >> 8;
2351203134Sthompsa				iv[2] = 0;
2352203134Sthompsa			}
2353203134Sthompsa			iv[3] = k->wk_keyix << 6 | IEEE80211_WEP_EXTIV;
2354203134Sthompsa			iv[4] = k->wk_keytsc >> 16;
2355203134Sthompsa			iv[5] = k->wk_keytsc >> 24;
2356203134Sthompsa			iv[6] = k->wk_keytsc >> 32;
2357203134Sthompsa			iv[7] = k->wk_keytsc >> 40;
2358203134Sthompsa		}
2359209917Sthompsa		if (run_write_region_1(sc, RT2860_IVEIV(wcid), iv, 8))
2360208019Sthompsa			return;
2361203134Sthompsa	}
2362203134Sthompsa
2363203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2364203134Sthompsa		/* install group key */
2365209917Sthompsa		if (run_read(sc, RT2860_SKEY_MODE_0_7, &attr))
2366208019Sthompsa			return;
2367203134Sthompsa		attr &= ~(0xf << (k->wk_keyix * 4));
2368203134Sthompsa		attr |= mode << (k->wk_keyix * 4);
2369209917Sthompsa		if (run_write(sc, RT2860_SKEY_MODE_0_7, attr))
2370208019Sthompsa			return;
2371203134Sthompsa	} else {
2372203134Sthompsa		/* install pairwise key */
2373209917Sthompsa		if (run_read(sc, RT2860_WCID_ATTR(wcid), &attr))
2374208019Sthompsa			return;
2375203134Sthompsa		attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN;
2376209917Sthompsa		if (run_write(sc, RT2860_WCID_ATTR(wcid), attr))
2377208019Sthompsa			return;
2378203134Sthompsa	}
2379203134Sthompsa
2380203134Sthompsa	/* TODO create a pass-thru key entry? */
2381203134Sthompsa
2382208019Sthompsa	/* need wcid to delete the right key later */
2383208019Sthompsa	k->wk_pad = wcid;
2384203134Sthompsa}
2385203134Sthompsa
2386203134Sthompsa/*
2387208019Sthompsa * Don't have to be deferred, but in order to keep order of
2388208019Sthompsa * execution, i.e. with run_key_delete(), defer this and let
2389208019Sthompsa * run_cmdq_cb() maintain the order.
2390208019Sthompsa *
2391203134Sthompsa * return 0 on error
2392203134Sthompsa */
2393203134Sthompsastatic int
2394208019Sthompsarun_key_set(struct ieee80211vap *vap, struct ieee80211_key *k,
2395208019Sthompsa		const uint8_t mac[IEEE80211_ADDR_LEN])
2396203134Sthompsa{
2397203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2398203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2399208019Sthompsa	uint32_t i;
2400208019Sthompsa
2401208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
2402208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
2403208019Sthompsa	sc->cmdq[i].func = run_key_set_cb;
2404208019Sthompsa	sc->cmdq[i].arg0 = NULL;
2405208019Sthompsa	sc->cmdq[i].arg1 = vap;
2406208019Sthompsa	sc->cmdq[i].k = k;
2407208019Sthompsa	IEEE80211_ADDR_COPY(sc->cmdq[i].mac, mac);
2408208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
2409208019Sthompsa
2410209144Sthompsa	/*
2411209144Sthompsa	 * To make sure key will be set when hostapd
2412209144Sthompsa	 * calls iv_key_set() before if_init().
2413209144Sthompsa	 */
2414209917Sthompsa	if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
2415209144Sthompsa		RUN_LOCK(sc);
2416209144Sthompsa		sc->cmdq_key_set = RUN_CMDQ_GO;
2417209144Sthompsa		RUN_UNLOCK(sc);
2418209144Sthompsa	}
2419209144Sthompsa
2420209917Sthompsa	return (1);
2421208019Sthompsa}
2422208019Sthompsa
2423208019Sthompsa/*
2424208019Sthompsa * If wlan is destroyed without being brought down i.e. without
2425208019Sthompsa * wlan down or wpa_cli terminate, this function is called after
2426208019Sthompsa * vap is gone. Don't refer it.
2427208019Sthompsa */
2428208019Sthompsastatic void
2429208019Sthompsarun_key_delete_cb(void *arg)
2430208019Sthompsa{
2431208019Sthompsa	struct run_cmdq *cmdq = arg;
2432208019Sthompsa	struct run_softc *sc = cmdq->arg1;
2433208019Sthompsa	struct ieee80211_key *k = &cmdq->key;
2434203134Sthompsa	uint32_t attr;
2435203134Sthompsa	uint8_t wcid;
2436203134Sthompsa
2437208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2438203134Sthompsa
2439203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2440203134Sthompsa		/* remove group key */
2441208019Sthompsa		DPRINTF("removing group key\n");
2442208019Sthompsa		run_read(sc, RT2860_SKEY_MODE_0_7, &attr);
2443203134Sthompsa		attr &= ~(0xf << (k->wk_keyix * 4));
2444208019Sthompsa		run_write(sc, RT2860_SKEY_MODE_0_7, attr);
2445203134Sthompsa	} else {
2446203134Sthompsa		/* remove pairwise key */
2447208019Sthompsa		DPRINTF("removing key for wcid %x\n", k->wk_pad);
2448208019Sthompsa		/* matching wcid was written to wk_pad in run_key_set() */
2449208019Sthompsa		wcid = k->wk_pad;
2450208019Sthompsa		run_read(sc, RT2860_WCID_ATTR(wcid), &attr);
2451203134Sthompsa		attr &= ~0xf;
2452208019Sthompsa		run_write(sc, RT2860_WCID_ATTR(wcid), attr);
2453208019Sthompsa		run_set_region_4(sc, RT2860_WCID_ENTRY(wcid), 0, 8);
2454203134Sthompsa	}
2455203134Sthompsa
2456208019Sthompsa	k->wk_pad = 0;
2457203134Sthompsa}
2458203134Sthompsa
2459208019Sthompsa/*
2460208019Sthompsa * return 0 on error
2461208019Sthompsa */
2462208019Sthompsastatic int
2463208019Sthompsarun_key_delete(struct ieee80211vap *vap, struct ieee80211_key *k)
2464203134Sthompsa{
2465208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2466208019Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2467208019Sthompsa	struct ieee80211_key *k0;
2468208019Sthompsa	uint32_t i;
2469203134Sthompsa
2470208019Sthompsa	/*
2471208019Sthompsa	 * When called back, key might be gone. So, make a copy
2472208019Sthompsa	 * of some values need to delete keys before deferring.
2473208019Sthompsa	 * But, because of LOR with node lock, cannot use lock here.
2474208019Sthompsa	 * So, use atomic instead.
2475208019Sthompsa	 */
2476208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
2477208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
2478208019Sthompsa	sc->cmdq[i].func = run_key_delete_cb;
2479208019Sthompsa	sc->cmdq[i].arg0 = NULL;
2480208019Sthompsa	sc->cmdq[i].arg1 = sc;
2481208019Sthompsa	k0 = &sc->cmdq[i].key;
2482208019Sthompsa	k0->wk_flags = k->wk_flags;
2483208019Sthompsa	k0->wk_keyix = k->wk_keyix;
2484208019Sthompsa	/* matching wcid was written to wk_pad in run_key_set() */
2485208019Sthompsa	k0->wk_pad = k->wk_pad;
2486208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
2487208019Sthompsa	return (1);	/* return fake success */
2488203134Sthompsa
2489203134Sthompsa}
2490203134Sthompsa
2491203134Sthompsastatic void
2492206358Srpaulorun_ratectl_to(void *arg)
2493203134Sthompsa{
2494208019Sthompsa	struct run_softc *sc = arg;
2495203134Sthompsa
2496203134Sthompsa	/* do it in a process context, so it can go sleep */
2497208019Sthompsa	ieee80211_runtask(sc->sc_ifp->if_l2com, &sc->ratectl_task);
2498203134Sthompsa	/* next timeout will be rescheduled in the callback task */
2499203134Sthompsa}
2500203134Sthompsa
2501203134Sthompsa/* ARGSUSED */
2502203134Sthompsastatic void
2503206358Srpaulorun_ratectl_cb(void *arg, int pending)
2504203134Sthompsa{
2505208019Sthompsa	struct run_softc *sc = arg;
2506208019Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
2507208019Sthompsa	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
2508203134Sthompsa
2509209917Sthompsa	if (vap == NULL)
2510208019Sthompsa		return;
2511208019Sthompsa
2512263073Shselasky	if (sc->rvp_cnt > 1 || vap->iv_opmode != IEEE80211_M_STA) {
2513203134Sthompsa		/*
2514203134Sthompsa		 * run_reset_livelock() doesn't do anything with AMRR,
2515203134Sthompsa		 * but Ralink wants us to call it every 1 sec. So, we
2516203134Sthompsa		 * piggyback here rather than creating another callout.
2517203134Sthompsa		 * Livelock may occur only in HOSTAP or IBSS mode
2518203134Sthompsa		 * (when h/w is sending beacons).
2519203134Sthompsa		 */
2520203134Sthompsa		RUN_LOCK(sc);
2521203134Sthompsa		run_reset_livelock(sc);
2522208019Sthompsa		/* just in case, there are some stats to drain */
2523208019Sthompsa		run_drain_fifo(sc);
2524203134Sthompsa		RUN_UNLOCK(sc);
2525203134Sthompsa	}
2526203134Sthompsa
2527263073Shselasky	ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, sc);
2528263073Shselasky
2529259453Shselasky	RUN_LOCK(sc);
2530208019Sthompsa	if(sc->ratectl_run != RUN_RATECTL_OFF)
2531208019Sthompsa		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2532259453Shselasky	RUN_UNLOCK(sc);
2533203134Sthompsa}
2534203134Sthompsa
2535203134Sthompsastatic void
2536208019Sthompsarun_drain_fifo(void *arg)
2537203134Sthompsa{
2538208019Sthompsa	struct run_softc *sc = arg;
2539208019Sthompsa	struct ifnet *ifp = sc->sc_ifp;
2540208019Sthompsa	uint32_t stat;
2541218676Shselasky	uint16_t (*wstat)[3];
2542203134Sthompsa	uint8_t wcid, mcs, pid;
2543218676Shselasky	int8_t retry;
2544203134Sthompsa
2545208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2546203134Sthompsa
2547208019Sthompsa	for (;;) {
2548203134Sthompsa		/* drain Tx status FIFO (maxsize = 16) */
2549203134Sthompsa		run_read(sc, RT2860_TX_STAT_FIFO, &stat);
2550208019Sthompsa		DPRINTFN(4, "tx stat 0x%08x\n", stat);
2551209917Sthompsa		if (!(stat & RT2860_TXQ_VLD))
2552208019Sthompsa			break;
2553203134Sthompsa
2554208019Sthompsa		wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff;
2555203134Sthompsa
2556208019Sthompsa		/* if no ACK was requested, no feedback is available */
2557208019Sthompsa		if (!(stat & RT2860_TXQ_ACKREQ) || wcid > RT2870_WCID_MAX ||
2558208019Sthompsa		    wcid == 0)
2559208019Sthompsa			continue;
2560203134Sthompsa
2561218676Shselasky		/*
2562218676Shselasky		 * Even though each stat is Tx-complete-status like format,
2563218676Shselasky		 * the device can poll stats. Because there is no guarantee
2564218676Shselasky		 * that the referring node is still around when read the stats.
2565218676Shselasky		 * So that, if we use ieee80211_ratectl_tx_update(), we will
2566218676Shselasky		 * have hard time not to refer already freed node.
2567218676Shselasky		 *
2568218676Shselasky		 * To eliminate such page faults, we poll stats in softc.
2569218676Shselasky		 * Then, update the rates later with ieee80211_ratectl_tx_update().
2570218676Shselasky		 */
2571218676Shselasky		wstat = &(sc->wcid_stats[wcid]);
2572218676Shselasky		(*wstat)[RUN_TXCNT]++;
2573218676Shselasky		if (stat & RT2860_TXQ_OK)
2574218676Shselasky			(*wstat)[RUN_SUCCESS]++;
2575218676Shselasky		else
2576208019Sthompsa			ifp->if_oerrors++;
2577218676Shselasky		/*
2578218676Shselasky		 * Check if there were retries, ie if the Tx success rate is
2579218676Shselasky		 * different from the requested rate. Note that it works only
2580218676Shselasky		 * because we do not allow rate fallback from OFDM to CCK.
2581218676Shselasky		 */
2582218676Shselasky		mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f;
2583218676Shselasky		pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf;
2584218676Shselasky		if ((retry = pid -1 - mcs) > 0) {
2585218676Shselasky			(*wstat)[RUN_TXCNT] += retry;
2586218676Shselasky			(*wstat)[RUN_RETRY] += retry;
2587203134Sthompsa		}
2588208019Sthompsa	}
2589208019Sthompsa	DPRINTFN(3, "count=%d\n", sc->fifo_cnt);
2590208019Sthompsa
2591208019Sthompsa	sc->fifo_cnt = 0;
2592208019Sthompsa}
2593208019Sthompsa
2594208019Sthompsastatic void
2595208019Sthompsarun_iter_func(void *arg, struct ieee80211_node *ni)
2596208019Sthompsa{
2597208019Sthompsa	struct run_softc *sc = arg;
2598208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
2599208019Sthompsa	struct ieee80211com *ic = ni->ni_ic;
2600208019Sthompsa	struct ifnet *ifp = ic->ic_ifp;
2601208019Sthompsa	struct run_node *rn = (void *)ni;
2602218676Shselasky	union run_stats sta[2];
2603218676Shselasky	uint16_t (*wstat)[3];
2604218676Shselasky	int txcnt, success, retrycnt, error;
2605208019Sthompsa
2606218676Shselasky	RUN_LOCK(sc);
2607218676Shselasky
2608263073Shselasky	/* Check for special case */
2609263073Shselasky	if (sc->rvp_cnt <= 1 && vap->iv_opmode == IEEE80211_M_STA &&
2610263073Shselasky	    ni != vap->iv_bss)
2611263073Shselasky		goto fail;
2612263073Shselasky
2613209917Sthompsa	if (sc->rvp_cnt <= 1 && (vap->iv_opmode == IEEE80211_M_IBSS ||
2614209917Sthompsa	    vap->iv_opmode == IEEE80211_M_STA)) {
2615203134Sthompsa		/* read statistic counters (clear on read) and update AMRR state */
2616203134Sthompsa		error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta,
2617203134Sthompsa		    sizeof sta);
2618203134Sthompsa		if (error != 0)
2619218676Shselasky			goto fail;
2620203134Sthompsa
2621203134Sthompsa		/* count failed TX as errors */
2622218676Shselasky		ifp->if_oerrors += le16toh(sta[0].error.fail);
2623203134Sthompsa
2624218676Shselasky		retrycnt = le16toh(sta[1].tx.retry);
2625218676Shselasky		success = le16toh(sta[1].tx.success);
2626218676Shselasky		txcnt = retrycnt + success + le16toh(sta[0].error.fail);
2627203134Sthompsa
2628218676Shselasky		DPRINTFN(3, "retrycnt=%d success=%d failcnt=%d\n",
2629218676Shselasky			retrycnt, success, le16toh(sta[0].error.fail));
2630218676Shselasky	} else {
2631218676Shselasky		wstat = &(sc->wcid_stats[RUN_AID2WCID(ni->ni_associd)]);
2632203134Sthompsa
2633218676Shselasky		if (wstat == &(sc->wcid_stats[0]) ||
2634218676Shselasky		    wstat > &(sc->wcid_stats[RT2870_WCID_MAX]))
2635218676Shselasky			goto fail;
2636208019Sthompsa
2637218676Shselasky		txcnt = (*wstat)[RUN_TXCNT];
2638218676Shselasky		success = (*wstat)[RUN_SUCCESS];
2639218676Shselasky		retrycnt = (*wstat)[RUN_RETRY];
2640218676Shselasky		DPRINTFN(3, "retrycnt=%d txcnt=%d success=%d\n",
2641218676Shselasky		    retrycnt, txcnt, success);
2642208019Sthompsa
2643218676Shselasky		memset(wstat, 0, sizeof(*wstat));
2644203134Sthompsa	}
2645203134Sthompsa
2646218676Shselasky	ieee80211_ratectl_tx_update(vap, ni, &txcnt, &success, &retrycnt);
2647208019Sthompsa	rn->amrr_ridx = ieee80211_ratectl_rate(ni, NULL, 0);
2648218676Shselasky
2649218676Shselaskyfail:
2650218676Shselasky	RUN_UNLOCK(sc);
2651218676Shselasky
2652208019Sthompsa	DPRINTFN(3, "ridx=%d\n", rn->amrr_ridx);
2653208019Sthompsa}
2654203134Sthompsa
2655208019Sthompsastatic void
2656208019Sthompsarun_newassoc_cb(void *arg)
2657208019Sthompsa{
2658208019Sthompsa	struct run_cmdq *cmdq = arg;
2659208019Sthompsa	struct ieee80211_node *ni = cmdq->arg1;
2660208019Sthompsa	struct run_softc *sc = ni->ni_vap->iv_ic->ic_ifp->if_softc;
2661208019Sthompsa	uint8_t wcid = cmdq->wcid;
2662203134Sthompsa
2663208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2664208019Sthompsa
2665208019Sthompsa	run_write_region_1(sc, RT2860_WCID_ENTRY(wcid),
2666208019Sthompsa	    ni->ni_macaddr, IEEE80211_ADDR_LEN);
2667218676Shselasky
2668218676Shselasky	memset(&(sc->wcid_stats[wcid]), 0, sizeof(sc->wcid_stats[wcid]));
2669203134Sthompsa}
2670203134Sthompsa
2671203134Sthompsastatic void
2672203134Sthompsarun_newassoc(struct ieee80211_node *ni, int isnew)
2673203134Sthompsa{
2674203134Sthompsa	struct run_node *rn = (void *)ni;
2675203134Sthompsa	struct ieee80211_rateset *rs = &ni->ni_rates;
2676208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
2677208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2678208019Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2679203134Sthompsa	uint8_t rate;
2680208019Sthompsa	uint8_t ridx;
2681245047Shselasky	uint8_t wcid;
2682208019Sthompsa	int i, j;
2683203134Sthompsa
2684245047Shselasky	wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
2685245047Shselasky	    1 : RUN_AID2WCID(ni->ni_associd);
2686245047Shselasky
2687209917Sthompsa	if (wcid > RT2870_WCID_MAX) {
2688208019Sthompsa		device_printf(sc->sc_dev, "wcid=%d out of range\n", wcid);
2689208019Sthompsa		return;
2690208019Sthompsa	}
2691203134Sthompsa
2692208019Sthompsa	/* only interested in true associations */
2693209917Sthompsa	if (isnew && ni->ni_associd != 0) {
2694208019Sthompsa
2695208019Sthompsa		/*
2696208019Sthompsa		 * This function could is called though timeout function.
2697208019Sthompsa		 * Need to defer.
2698208019Sthompsa		 */
2699208019Sthompsa		uint32_t cnt = RUN_CMDQ_GET(&sc->cmdq_store);
2700208019Sthompsa		DPRINTF("cmdq_store=%d\n", cnt);
2701208019Sthompsa		sc->cmdq[cnt].func = run_newassoc_cb;
2702208019Sthompsa		sc->cmdq[cnt].arg0 = NULL;
2703208019Sthompsa		sc->cmdq[cnt].arg1 = ni;
2704208019Sthompsa		sc->cmdq[cnt].wcid = wcid;
2705208019Sthompsa		ieee80211_runtask(ic, &sc->cmdq_task);
2706208019Sthompsa	}
2707208019Sthompsa
2708208019Sthompsa	DPRINTF("new assoc isnew=%d associd=%x addr=%s\n",
2709208019Sthompsa	    isnew, ni->ni_associd, ether_sprintf(ni->ni_macaddr));
2710208019Sthompsa
2711203134Sthompsa	for (i = 0; i < rs->rs_nrates; i++) {
2712203134Sthompsa		rate = rs->rs_rates[i] & IEEE80211_RATE_VAL;
2713203134Sthompsa		/* convert 802.11 rate to hardware rate index */
2714203134Sthompsa		for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2715203134Sthompsa			if (rt2860_rates[ridx].rate == rate)
2716203134Sthompsa				break;
2717203134Sthompsa		rn->ridx[i] = ridx;
2718203134Sthompsa		/* determine rate of control response frames */
2719203134Sthompsa		for (j = i; j >= 0; j--) {
2720203134Sthompsa			if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) &&
2721203134Sthompsa			    rt2860_rates[rn->ridx[i]].phy ==
2722203134Sthompsa			    rt2860_rates[rn->ridx[j]].phy)
2723203134Sthompsa				break;
2724203134Sthompsa		}
2725203134Sthompsa		if (j >= 0) {
2726203134Sthompsa			rn->ctl_ridx[i] = rn->ridx[j];
2727203134Sthompsa		} else {
2728203134Sthompsa			/* no basic rate found, use mandatory one */
2729203134Sthompsa			rn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx;
2730203134Sthompsa		}
2731203134Sthompsa		DPRINTF("rate=0x%02x ridx=%d ctl_ridx=%d\n",
2732203134Sthompsa		    rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]);
2733203134Sthompsa	}
2734208019Sthompsa	rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate;
2735208019Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2736208019Sthompsa		if (rt2860_rates[ridx].rate == rate)
2737208019Sthompsa			break;
2738208019Sthompsa	rn->mgt_ridx = ridx;
2739208019Sthompsa	DPRINTF("rate=%d, mgmt_ridx=%d\n", rate, rn->mgt_ridx);
2740208019Sthompsa
2741263073Shselasky	RUN_LOCK(sc);
2742263073Shselasky	if(sc->ratectl_run != RUN_RATECTL_OFF)
2743263073Shselasky		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2744263073Shselasky	RUN_UNLOCK(sc);
2745203134Sthompsa}
2746203134Sthompsa
2747203134Sthompsa/*
2748203134Sthompsa * Return the Rx chain with the highest RSSI for a given frame.
2749203134Sthompsa */
2750203134Sthompsastatic __inline uint8_t
2751203134Sthompsarun_maxrssi_chain(struct run_softc *sc, const struct rt2860_rxwi *rxwi)
2752203134Sthompsa{
2753203134Sthompsa	uint8_t rxchain = 0;
2754203134Sthompsa
2755203134Sthompsa	if (sc->nrxchains > 1) {
2756203134Sthompsa		if (rxwi->rssi[1] > rxwi->rssi[rxchain])
2757203134Sthompsa			rxchain = 1;
2758203134Sthompsa		if (sc->nrxchains > 2)
2759203134Sthompsa			if (rxwi->rssi[2] > rxwi->rssi[rxchain])
2760203134Sthompsa				rxchain = 2;
2761203134Sthompsa	}
2762209917Sthompsa	return (rxchain);
2763203134Sthompsa}
2764203134Sthompsa
2765203134Sthompsastatic void
2766203134Sthompsarun_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen)
2767203134Sthompsa{
2768203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
2769203134Sthompsa	struct ieee80211com *ic = ifp->if_l2com;
2770203134Sthompsa	struct ieee80211_frame *wh;
2771203134Sthompsa	struct ieee80211_node *ni;
2772203134Sthompsa	struct rt2870_rxd *rxd;
2773203134Sthompsa	struct rt2860_rxwi *rxwi;
2774203134Sthompsa	uint32_t flags;
2775259453Shselasky	uint16_t len, rxwisize;
2776203134Sthompsa	uint8_t ant, rssi;
2777203134Sthompsa	int8_t nf;
2778203134Sthompsa
2779203134Sthompsa	rxwi = mtod(m, struct rt2860_rxwi *);
2780203134Sthompsa	len = le16toh(rxwi->len) & 0xfff;
2781261868Skevlo	rxwisize = sizeof(struct rt2860_rxwi);
2782261868Skevlo	if (sc->mac_ver == 0x5592)
2783261868Skevlo		rxwisize += sizeof(uint64_t);
2784261868Skevlo	else if (sc->mac_ver == 0x3593)
2785261868Skevlo		rxwisize += sizeof(uint32_t);
2786203134Sthompsa	if (__predict_false(len > dmalen)) {
2787203134Sthompsa		m_freem(m);
2788203134Sthompsa		ifp->if_ierrors++;
2789203134Sthompsa		DPRINTF("bad RXWI length %u > %u\n", len, dmalen);
2790203134Sthompsa		return;
2791203134Sthompsa	}
2792203134Sthompsa	/* Rx descriptor is located at the end */
2793203134Sthompsa	rxd = (struct rt2870_rxd *)(mtod(m, caddr_t) + dmalen);
2794203134Sthompsa	flags = le32toh(rxd->flags);
2795203134Sthompsa
2796203134Sthompsa	if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) {
2797203134Sthompsa		m_freem(m);
2798203134Sthompsa		ifp->if_ierrors++;
2799203134Sthompsa		DPRINTF("%s error.\n", (flags & RT2860_RX_CRCERR)?"CRC":"ICV");
2800203134Sthompsa		return;
2801203134Sthompsa	}
2802203134Sthompsa
2803259453Shselasky	m->m_data += rxwisize;
2804259453Shselasky	m->m_pkthdr.len = m->m_len -= rxwisize;
2805203134Sthompsa
2806203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
2807203134Sthompsa
2808262007Skevlo	if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
2809262007Skevlo		wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
2810203134Sthompsa		m->m_flags |= M_WEP;
2811203134Sthompsa	}
2812203134Sthompsa
2813209917Sthompsa	if (flags & RT2860_RX_L2PAD) {
2814203134Sthompsa		DPRINTFN(8, "received RT2860_RX_L2PAD frame\n");
2815203134Sthompsa		len += 2;
2816203134Sthompsa	}
2817203134Sthompsa
2818208019Sthompsa	ni = ieee80211_find_rxnode(ic,
2819208019Sthompsa	    mtod(m, struct ieee80211_frame_min *));
2820208019Sthompsa
2821203134Sthompsa	if (__predict_false(flags & RT2860_RX_MICERR)) {
2822203134Sthompsa		/* report MIC failures to net80211 for TKIP */
2823209917Sthompsa		if (ni != NULL)
2824259453Shselasky			ieee80211_notify_michael_failure(ni->ni_vap, wh,
2825259453Shselasky			    rxwi->keyidx);
2826203134Sthompsa		m_freem(m);
2827203134Sthompsa		ifp->if_ierrors++;
2828203134Sthompsa		DPRINTF("MIC error. Someone is lying.\n");
2829203134Sthompsa		return;
2830203134Sthompsa	}
2831203134Sthompsa
2832203134Sthompsa	ant = run_maxrssi_chain(sc, rxwi);
2833203134Sthompsa	rssi = rxwi->rssi[ant];
2834203134Sthompsa	nf = run_rssi2dbm(sc, rssi, ant);
2835203134Sthompsa
2836203134Sthompsa	m->m_pkthdr.rcvif = ifp;
2837203134Sthompsa	m->m_pkthdr.len = m->m_len = len;
2838203134Sthompsa
2839203134Sthompsa	if (ni != NULL) {
2840203134Sthompsa		(void)ieee80211_input(ni, m, rssi, nf);
2841203134Sthompsa		ieee80211_free_node(ni);
2842203134Sthompsa	} else {
2843203134Sthompsa		(void)ieee80211_input_all(ic, m, rssi, nf);
2844203134Sthompsa	}
2845203134Sthompsa
2846209917Sthompsa	if (__predict_false(ieee80211_radiotap_active(ic))) {
2847203134Sthompsa		struct run_rx_radiotap_header *tap = &sc->sc_rxtap;
2848259453Shselasky		uint16_t phy;
2849203134Sthompsa
2850203134Sthompsa		tap->wr_flags = 0;
2851236439Shselasky		tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
2852236439Shselasky		tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
2853203134Sthompsa		tap->wr_antsignal = rssi;
2854203134Sthompsa		tap->wr_antenna = ant;
2855203134Sthompsa		tap->wr_dbm_antsignal = run_rssi2dbm(sc, rssi, ant);
2856203134Sthompsa		tap->wr_rate = 2;	/* in case it can't be found below */
2857203134Sthompsa		phy = le16toh(rxwi->phy);
2858203134Sthompsa		switch (phy & RT2860_PHY_MODE) {
2859203134Sthompsa		case RT2860_PHY_CCK:
2860203134Sthompsa			switch ((phy & RT2860_PHY_MCS) & ~RT2860_PHY_SHPRE) {
2861203134Sthompsa			case 0:	tap->wr_rate =   2; break;
2862203134Sthompsa			case 1:	tap->wr_rate =   4; break;
2863203134Sthompsa			case 2:	tap->wr_rate =  11; break;
2864203134Sthompsa			case 3:	tap->wr_rate =  22; break;
2865203134Sthompsa			}
2866203134Sthompsa			if (phy & RT2860_PHY_SHPRE)
2867203134Sthompsa				tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
2868203134Sthompsa			break;
2869203134Sthompsa		case RT2860_PHY_OFDM:
2870203134Sthompsa			switch (phy & RT2860_PHY_MCS) {
2871203134Sthompsa			case 0:	tap->wr_rate =  12; break;
2872203134Sthompsa			case 1:	tap->wr_rate =  18; break;
2873203134Sthompsa			case 2:	tap->wr_rate =  24; break;
2874203134Sthompsa			case 3:	tap->wr_rate =  36; break;
2875203134Sthompsa			case 4:	tap->wr_rate =  48; break;
2876203134Sthompsa			case 5:	tap->wr_rate =  72; break;
2877203134Sthompsa			case 6:	tap->wr_rate =  96; break;
2878203134Sthompsa			case 7:	tap->wr_rate = 108; break;
2879203134Sthompsa			}
2880203134Sthompsa			break;
2881203134Sthompsa		}
2882203134Sthompsa	}
2883203134Sthompsa}
2884203134Sthompsa
2885203134Sthompsastatic void
2886203134Sthompsarun_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error)
2887203134Sthompsa{
2888203134Sthompsa	struct run_softc *sc = usbd_xfer_softc(xfer);
2889203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
2890203134Sthompsa	struct mbuf *m = NULL;
2891203134Sthompsa	struct mbuf *m0;
2892203134Sthompsa	uint32_t dmalen;
2893259453Shselasky	uint16_t rxwisize;
2894203134Sthompsa	int xferlen;
2895203134Sthompsa
2896261868Skevlo	rxwisize = sizeof(struct rt2860_rxwi);
2897261868Skevlo	if (sc->mac_ver == 0x5592)
2898261868Skevlo		rxwisize += sizeof(uint64_t);
2899261868Skevlo	else if (sc->mac_ver == 0x3593)
2900261868Skevlo		rxwisize += sizeof(uint32_t);
2901259453Shselasky
2902203134Sthompsa	usbd_xfer_status(xfer, &xferlen, NULL, NULL, NULL);
2903203134Sthompsa
2904203134Sthompsa	switch (USB_GET_STATE(xfer)) {
2905203134Sthompsa	case USB_ST_TRANSFERRED:
2906203134Sthompsa
2907203134Sthompsa		DPRINTFN(15, "rx done, actlen=%d\n", xferlen);
2908203134Sthompsa
2909259453Shselasky		if (xferlen < (int)(sizeof(uint32_t) + rxwisize +
2910259453Shselasky		    sizeof(struct rt2870_rxd))) {
2911203134Sthompsa			DPRINTF("xfer too short %d\n", xferlen);
2912203134Sthompsa			goto tr_setup;
2913203134Sthompsa		}
2914203134Sthompsa
2915203134Sthompsa		m = sc->rx_m;
2916203134Sthompsa		sc->rx_m = NULL;
2917203134Sthompsa
2918203134Sthompsa		/* FALLTHROUGH */
2919203134Sthompsa	case USB_ST_SETUP:
2920203134Sthompsatr_setup:
2921203134Sthompsa		if (sc->rx_m == NULL) {
2922243857Sglebius			sc->rx_m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR,
2923203134Sthompsa			    MJUMPAGESIZE /* xfer can be bigger than MCLBYTES */);
2924203134Sthompsa		}
2925203134Sthompsa		if (sc->rx_m == NULL) {
2926203134Sthompsa			DPRINTF("could not allocate mbuf - idle with stall\n");
2927203134Sthompsa			ifp->if_ierrors++;
2928203134Sthompsa			usbd_xfer_set_stall(xfer);
2929203134Sthompsa			usbd_xfer_set_frames(xfer, 0);
2930203134Sthompsa		} else {
2931203134Sthompsa			/*
2932203134Sthompsa			 * Directly loading a mbuf cluster into DMA to
2933203134Sthompsa			 * save some data copying. This works because
2934203134Sthompsa			 * there is only one cluster.
2935203134Sthompsa			 */
2936203134Sthompsa			usbd_xfer_set_frame_data(xfer, 0,
2937203134Sthompsa			    mtod(sc->rx_m, caddr_t), RUN_MAX_RXSZ);
2938203134Sthompsa			usbd_xfer_set_frames(xfer, 1);
2939203134Sthompsa		}
2940203134Sthompsa		usbd_transfer_submit(xfer);
2941203134Sthompsa		break;
2942203134Sthompsa
2943203134Sthompsa	default:	/* Error */
2944203134Sthompsa		if (error != USB_ERR_CANCELLED) {
2945203134Sthompsa			/* try to clear stall first */
2946203134Sthompsa			usbd_xfer_set_stall(xfer);
2947203134Sthompsa
2948203134Sthompsa			if (error == USB_ERR_TIMEOUT)
2949203134Sthompsa				device_printf(sc->sc_dev, "device timeout\n");
2950203134Sthompsa
2951203134Sthompsa			ifp->if_ierrors++;
2952203134Sthompsa
2953203134Sthompsa			goto tr_setup;
2954203134Sthompsa		}
2955209917Sthompsa		if (sc->rx_m != NULL) {
2956203134Sthompsa			m_freem(sc->rx_m);
2957203134Sthompsa			sc->rx_m = NULL;
2958203134Sthompsa		}
2959203134Sthompsa		break;
2960203134Sthompsa	}
2961203134Sthompsa
2962203134Sthompsa	if (m == NULL)
2963203134Sthompsa		return;
2964203134Sthompsa
2965203134Sthompsa	/* inputting all the frames must be last */
2966203134Sthompsa
2967203134Sthompsa	RUN_UNLOCK(sc);
2968203134Sthompsa
2969203134Sthompsa	m->m_pkthdr.len = m->m_len = xferlen;
2970203134Sthompsa
2971203134Sthompsa	/* HW can aggregate multiple 802.11 frames in a single USB xfer */
2972203134Sthompsa	for(;;) {
2973203134Sthompsa		dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff;
2974203134Sthompsa
2975233774Shselasky		if ((dmalen >= (uint32_t)-8) || (dmalen == 0) ||
2976233774Shselasky		    ((dmalen & 3) != 0)) {
2977203134Sthompsa			DPRINTF("bad DMA length %u\n", dmalen);
2978203134Sthompsa			break;
2979203134Sthompsa		}
2980233774Shselasky		if ((dmalen + 8) > (uint32_t)xferlen) {
2981203134Sthompsa			DPRINTF("bad DMA length %u > %d\n",
2982203134Sthompsa			dmalen + 8, xferlen);
2983203134Sthompsa			break;
2984203134Sthompsa		}
2985203134Sthompsa
2986203134Sthompsa		/* If it is the last one or a single frame, we won't copy. */
2987209917Sthompsa		if ((xferlen -= dmalen + 8) <= 8) {
2988203134Sthompsa			/* trim 32-bit DMA-len header */
2989203134Sthompsa			m->m_data += 4;
2990203134Sthompsa			m->m_pkthdr.len = m->m_len -= 4;
2991203134Sthompsa			run_rx_frame(sc, m, dmalen);
2992259453Shselasky			m = NULL;	/* don't free source buffer */
2993203134Sthompsa			break;
2994203134Sthompsa		}
2995203134Sthompsa
2996203134Sthompsa		/* copy aggregated frames to another mbuf */
2997243857Sglebius		m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
2998203134Sthompsa		if (__predict_false(m0 == NULL)) {
2999203134Sthompsa			DPRINTF("could not allocate mbuf\n");
3000203134Sthompsa			ifp->if_ierrors++;
3001203134Sthompsa			break;
3002203134Sthompsa		}
3003203134Sthompsa		m_copydata(m, 4 /* skip 32-bit DMA-len header */,
3004203134Sthompsa		    dmalen + sizeof(struct rt2870_rxd), mtod(m0, caddr_t));
3005203134Sthompsa		m0->m_pkthdr.len = m0->m_len =
3006203134Sthompsa		    dmalen + sizeof(struct rt2870_rxd);
3007203134Sthompsa		run_rx_frame(sc, m0, dmalen);
3008203134Sthompsa
3009203134Sthompsa		/* update data ptr */
3010203134Sthompsa		m->m_data += dmalen + 8;
3011203134Sthompsa		m->m_pkthdr.len = m->m_len -= dmalen + 8;
3012203134Sthompsa	}
3013203134Sthompsa
3014259453Shselasky	/* make sure we free the source buffer, if any */
3015259453Shselasky	m_freem(m);
3016259453Shselasky
3017203134Sthompsa	RUN_LOCK(sc);
3018203134Sthompsa}
3019203134Sthompsa
3020203134Sthompsastatic void
3021203134Sthompsarun_tx_free(struct run_endpoint_queue *pq,
3022203134Sthompsa    struct run_tx_data *data, int txerr)
3023203134Sthompsa{
3024203134Sthompsa	if (data->m != NULL) {
3025203134Sthompsa		if (data->m->m_flags & M_TXCB)
3026203134Sthompsa			ieee80211_process_callback(data->ni, data->m,
3027203134Sthompsa			    txerr ? ETIMEDOUT : 0);
3028203134Sthompsa		m_freem(data->m);
3029203134Sthompsa		data->m = NULL;
3030203134Sthompsa
3031209917Sthompsa		if (data->ni == NULL) {
3032203134Sthompsa			DPRINTF("no node\n");
3033203134Sthompsa		} else {
3034203134Sthompsa			ieee80211_free_node(data->ni);
3035203134Sthompsa			data->ni = NULL;
3036203134Sthompsa		}
3037203134Sthompsa	}
3038203134Sthompsa
3039203134Sthompsa	STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
3040203134Sthompsa	pq->tx_nfree++;
3041203134Sthompsa}
3042203134Sthompsa
3043203134Sthompsastatic void
3044259453Shselaskyrun_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, u_int index)
3045203134Sthompsa{
3046203134Sthompsa	struct run_softc *sc = usbd_xfer_softc(xfer);
3047203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
3048208019Sthompsa	struct ieee80211com *ic = ifp->if_l2com;
3049203134Sthompsa	struct run_tx_data *data;
3050203134Sthompsa	struct ieee80211vap *vap = NULL;
3051203134Sthompsa	struct usb_page_cache *pc;
3052203134Sthompsa	struct run_endpoint_queue *pq = &sc->sc_epq[index];
3053203134Sthompsa	struct mbuf *m;
3054203134Sthompsa	usb_frlength_t size;
3055203134Sthompsa	int actlen;
3056203134Sthompsa	int sumlen;
3057203134Sthompsa
3058203134Sthompsa	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
3059203134Sthompsa
3060209917Sthompsa	switch (USB_GET_STATE(xfer)) {
3061203134Sthompsa	case USB_ST_TRANSFERRED:
3062203134Sthompsa		DPRINTFN(11, "transfer complete: %d "
3063203134Sthompsa		    "bytes @ index %d\n", actlen, index);
3064203134Sthompsa
3065203134Sthompsa		data = usbd_xfer_get_priv(xfer);
3066203134Sthompsa
3067203134Sthompsa		run_tx_free(pq, data, 0);
3068203134Sthompsa		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
3069203134Sthompsa
3070203134Sthompsa		usbd_xfer_set_priv(xfer, NULL);
3071203134Sthompsa
3072203134Sthompsa		ifp->if_opackets++;
3073203134Sthompsa
3074203134Sthompsa		/* FALLTHROUGH */
3075203134Sthompsa	case USB_ST_SETUP:
3076203134Sthompsatr_setup:
3077203134Sthompsa		data = STAILQ_FIRST(&pq->tx_qh);
3078209917Sthompsa		if (data == NULL)
3079203134Sthompsa			break;
3080203134Sthompsa
3081203134Sthompsa		STAILQ_REMOVE_HEAD(&pq->tx_qh, next);
3082203134Sthompsa
3083203134Sthompsa		m = data->m;
3084261868Skevlo		size = (sc->mac_ver == 0x5592) ?
3085261868Skevlo		    sizeof(data->desc) + sizeof(uint32_t) : sizeof(data->desc);
3086228508Shselasky		if ((m->m_pkthdr.len +
3087261868Skevlo		    size + 3 + 8) > RUN_MAX_TXSZ) {
3088203134Sthompsa			DPRINTF("data overflow, %u bytes\n",
3089203134Sthompsa			    m->m_pkthdr.len);
3090203134Sthompsa
3091203134Sthompsa			ifp->if_oerrors++;
3092203134Sthompsa
3093203134Sthompsa			run_tx_free(pq, data, 1);
3094203134Sthompsa
3095203134Sthompsa			goto tr_setup;
3096203134Sthompsa		}
3097203134Sthompsa
3098203134Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
3099203134Sthompsa		usbd_copy_in(pc, 0, &data->desc, size);
3100203134Sthompsa		usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len);
3101228508Shselasky		size += m->m_pkthdr.len;
3102228508Shselasky		/*
3103228508Shselasky		 * Align end on a 4-byte boundary, pad 8 bytes (CRC +
3104228508Shselasky		 * 4-byte padding), and be sure to zero those trailing
3105228508Shselasky		 * bytes:
3106228508Shselasky		 */
3107228508Shselasky		usbd_frame_zero(pc, size, ((-size) & 3) + 8);
3108228508Shselasky		size += ((-size) & 3) + 8;
3109203134Sthompsa
3110203134Sthompsa		vap = data->ni->ni_vap;
3111203134Sthompsa		if (ieee80211_radiotap_active_vap(vap)) {
3112203134Sthompsa			struct run_tx_radiotap_header *tap = &sc->sc_txtap;
3113259453Shselasky			struct rt2860_txwi *txwi =
3114208019Sthompsa			    (struct rt2860_txwi *)(&data->desc + sizeof(struct rt2870_txd));
3115203134Sthompsa			tap->wt_flags = 0;
3116203134Sthompsa			tap->wt_rate = rt2860_rates[data->ridx].rate;
3117236439Shselasky			tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
3118236439Shselasky			tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
3119203134Sthompsa			tap->wt_hwqueue = index;
3120208019Sthompsa			if (le16toh(txwi->phy) & RT2860_PHY_SHPRE)
3121203134Sthompsa				tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
3122203134Sthompsa
3123203134Sthompsa			ieee80211_radiotap_tx(vap, m);
3124203134Sthompsa		}
3125203134Sthompsa
3126228508Shselasky		DPRINTFN(11, "sending frame len=%u/%u  @ index %d\n",
3127228508Shselasky		    m->m_pkthdr.len, size, index);
3128203134Sthompsa
3129228508Shselasky		usbd_xfer_set_frame_len(xfer, 0, size);
3130203134Sthompsa		usbd_xfer_set_priv(xfer, data);
3131203134Sthompsa
3132203134Sthompsa		usbd_transfer_submit(xfer);
3133203134Sthompsa
3134203134Sthompsa		RUN_UNLOCK(sc);
3135203134Sthompsa		run_start(ifp);
3136203134Sthompsa		RUN_LOCK(sc);
3137203134Sthompsa
3138203134Sthompsa		break;
3139203134Sthompsa
3140203134Sthompsa	default:
3141203134Sthompsa		DPRINTF("USB transfer error, %s\n",
3142203134Sthompsa		    usbd_errstr(error));
3143203134Sthompsa
3144203134Sthompsa		data = usbd_xfer_get_priv(xfer);
3145203134Sthompsa
3146203134Sthompsa		ifp->if_oerrors++;
3147203134Sthompsa
3148203134Sthompsa		if (data != NULL) {
3149208019Sthompsa			if(data->ni != NULL)
3150208019Sthompsa				vap = data->ni->ni_vap;
3151203134Sthompsa			run_tx_free(pq, data, error);
3152203134Sthompsa			usbd_xfer_set_priv(xfer, NULL);
3153203134Sthompsa		}
3154209917Sthompsa		if (vap == NULL)
3155208019Sthompsa			vap = TAILQ_FIRST(&ic->ic_vaps);
3156203134Sthompsa
3157203134Sthompsa		if (error != USB_ERR_CANCELLED) {
3158203134Sthompsa			if (error == USB_ERR_TIMEOUT) {
3159203134Sthompsa				device_printf(sc->sc_dev, "device timeout\n");
3160208019Sthompsa				uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
3161208019Sthompsa				DPRINTF("cmdq_store=%d\n", i);
3162208019Sthompsa				sc->cmdq[i].func = run_usb_timeout_cb;
3163208019Sthompsa				sc->cmdq[i].arg0 = vap;
3164208019Sthompsa				ieee80211_runtask(ic, &sc->cmdq_task);
3165203134Sthompsa			}
3166203134Sthompsa
3167203134Sthompsa			/*
3168203134Sthompsa			 * Try to clear stall first, also if other
3169203134Sthompsa			 * errors occur, hence clearing stall
3170203134Sthompsa			 * introduces a 50 ms delay:
3171203134Sthompsa			 */
3172203134Sthompsa			usbd_xfer_set_stall(xfer);
3173203134Sthompsa			goto tr_setup;
3174203134Sthompsa		}
3175203134Sthompsa		break;
3176203134Sthompsa	}
3177203134Sthompsa}
3178203134Sthompsa
3179203134Sthompsastatic void
3180203134Sthompsarun_bulk_tx_callback0(struct usb_xfer *xfer, usb_error_t error)
3181203134Sthompsa{
3182203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 0);
3183203134Sthompsa}
3184203134Sthompsa
3185203134Sthompsastatic void
3186203134Sthompsarun_bulk_tx_callback1(struct usb_xfer *xfer, usb_error_t error)
3187203134Sthompsa{
3188203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 1);
3189203134Sthompsa}
3190203134Sthompsa
3191203134Sthompsastatic void
3192203134Sthompsarun_bulk_tx_callback2(struct usb_xfer *xfer, usb_error_t error)
3193203134Sthompsa{
3194203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 2);
3195203134Sthompsa}
3196203134Sthompsa
3197203134Sthompsastatic void
3198203134Sthompsarun_bulk_tx_callback3(struct usb_xfer *xfer, usb_error_t error)
3199203134Sthompsa{
3200203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 3);
3201203134Sthompsa}
3202203134Sthompsa
3203203134Sthompsastatic void
3204203134Sthompsarun_bulk_tx_callback4(struct usb_xfer *xfer, usb_error_t error)
3205203134Sthompsa{
3206203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 4);
3207203134Sthompsa}
3208203134Sthompsa
3209203134Sthompsastatic void
3210203134Sthompsarun_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error)
3211203134Sthompsa{
3212203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 5);
3213203134Sthompsa}
3214203134Sthompsa
3215203134Sthompsastatic void
3216208019Sthompsarun_set_tx_desc(struct run_softc *sc, struct run_tx_data *data)
3217203134Sthompsa{
3218203134Sthompsa	struct mbuf *m = data->m;
3219203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
3220208019Sthompsa	struct ieee80211vap *vap = data->ni->ni_vap;
3221203134Sthompsa	struct ieee80211_frame *wh;
3222203134Sthompsa	struct rt2870_txd *txd;
3223203134Sthompsa	struct rt2860_txwi *txwi;
3224259453Shselasky	uint16_t xferlen, txwisize;
3225208019Sthompsa	uint16_t mcs;
3226203134Sthompsa	uint8_t ridx = data->ridx;
3227208019Sthompsa	uint8_t pad;
3228203134Sthompsa
3229203134Sthompsa	/* get MCS code from rate index */
3230208019Sthompsa	mcs = rt2860_rates[ridx].mcs;
3231203134Sthompsa
3232259453Shselasky	txwisize = (sc->mac_ver == 0x5592) ?
3233259453Shselasky	    sizeof(*txwi) + sizeof(uint32_t) : sizeof(*txwi);
3234259453Shselasky	xferlen = txwisize + m->m_pkthdr.len;
3235203134Sthompsa
3236203134Sthompsa	/* roundup to 32-bit alignment */
3237203134Sthompsa	xferlen = (xferlen + 3) & ~3;
3238203134Sthompsa
3239203134Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3240203134Sthompsa	txd->len = htole16(xferlen);
3241203134Sthompsa
3242208019Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3243208019Sthompsa
3244208019Sthompsa	/*
3245208019Sthompsa	 * Ether both are true or both are false, the header
3246208019Sthompsa	 * are nicely aligned to 32-bit. So, no L2 padding.
3247208019Sthompsa	 */
3248208019Sthompsa	if(IEEE80211_HAS_ADDR4(wh) == IEEE80211_QOS_HAS_SEQ(wh))
3249208019Sthompsa		pad = 0;
3250208019Sthompsa	else
3251208019Sthompsa		pad = 2;
3252208019Sthompsa
3253203134Sthompsa	/* setup TX Wireless Information */
3254203134Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3255203134Sthompsa	txwi->len = htole16(m->m_pkthdr.len - pad);
3256203134Sthompsa	if (rt2860_rates[ridx].phy == IEEE80211_T_DS) {
3257270515Skevlo		mcs |= RT2860_PHY_CCK;
3258203134Sthompsa		if (ridx != RT2860_RIDX_CCK1 &&
3259203134Sthompsa		    (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
3260203134Sthompsa			mcs |= RT2860_PHY_SHPRE;
3261203134Sthompsa	} else
3262270515Skevlo		mcs |= RT2860_PHY_OFDM;
3263270515Skevlo	txwi->phy = htole16(mcs);
3264203134Sthompsa
3265203134Sthompsa	/* check if RTS/CTS or CTS-to-self protection is required */
3266203134Sthompsa	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
3267203134Sthompsa	    (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold ||
3268203134Sthompsa	     ((ic->ic_flags & IEEE80211_F_USEPROT) &&
3269203134Sthompsa	      rt2860_rates[ridx].phy == IEEE80211_T_OFDM)))
3270208019Sthompsa		txwi->txop |= RT2860_TX_TXOP_HT;
3271203134Sthompsa	else
3272208019Sthompsa		txwi->txop |= RT2860_TX_TXOP_BACKOFF;
3273209144Sthompsa
3274209917Sthompsa	if (vap->iv_opmode != IEEE80211_M_STA && !IEEE80211_QOS_HAS_SEQ(wh))
3275209144Sthompsa		txwi->xflags |= RT2860_TX_NSEQ;
3276203134Sthompsa}
3277203134Sthompsa
3278203134Sthompsa/* This function must be called locked */
3279203134Sthompsastatic int
3280203134Sthompsarun_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
3281203134Sthompsa{
3282203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
3283208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
3284203134Sthompsa	struct ieee80211_frame *wh;
3285208019Sthompsa	struct ieee80211_channel *chan;
3286203134Sthompsa	const struct ieee80211_txparam *tp;
3287208019Sthompsa	struct run_node *rn = (void *)ni;
3288203134Sthompsa	struct run_tx_data *data;
3289208019Sthompsa	struct rt2870_txd *txd;
3290208019Sthompsa	struct rt2860_txwi *txwi;
3291203134Sthompsa	uint16_t qos;
3292203134Sthompsa	uint16_t dur;
3293208019Sthompsa	uint16_t qid;
3294203134Sthompsa	uint8_t type;
3295203134Sthompsa	uint8_t tid;
3296208019Sthompsa	uint8_t ridx;
3297208019Sthompsa	uint8_t ctl_ridx;
3298203134Sthompsa	uint8_t qflags;
3299203134Sthompsa	uint8_t xflags = 0;
3300203134Sthompsa	int hasqos;
3301203134Sthompsa
3302203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3303203134Sthompsa
3304203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3305203134Sthompsa
3306203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3307203134Sthompsa
3308203134Sthompsa	/*
3309203134Sthompsa	 * There are 7 bulk endpoints: 1 for RX
3310203134Sthompsa	 * and 6 for TX (4 EDCAs + HCCA + Prio).
3311203134Sthompsa	 * Update 03-14-2009:  some devices like the Planex GW-US300MiniS
3312203134Sthompsa	 * seem to have only 4 TX bulk endpoints (Fukaumi Naoki).
3313203134Sthompsa	 */
3314203134Sthompsa	if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) {
3315203134Sthompsa		uint8_t *frm;
3316203134Sthompsa
3317203134Sthompsa		if(IEEE80211_HAS_ADDR4(wh))
3318203134Sthompsa			frm = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos;
3319203134Sthompsa		else
3320203134Sthompsa			frm =((struct ieee80211_qosframe *)wh)->i_qos;
3321203134Sthompsa
3322203134Sthompsa		qos = le16toh(*(const uint16_t *)frm);
3323203134Sthompsa		tid = qos & IEEE80211_QOS_TID;
3324203134Sthompsa		qid = TID_TO_WME_AC(tid);
3325203134Sthompsa	} else {
3326203134Sthompsa		qos = 0;
3327203134Sthompsa		tid = 0;
3328203134Sthompsa		qid = WME_AC_BE;
3329203134Sthompsa	}
3330203134Sthompsa	qflags = (qid < 4) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA;
3331203134Sthompsa
3332203134Sthompsa	DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n",
3333203134Sthompsa	    qos, qid, tid, qflags);
3334203134Sthompsa
3335208019Sthompsa	chan = (ni->ni_chan != IEEE80211_CHAN_ANYC)?ni->ni_chan:ic->ic_curchan;
3336208019Sthompsa	tp = &vap->iv_txparms[ieee80211_chan2mode(chan)];
3337203134Sthompsa
3338203134Sthompsa	/* pickup a rate index */
3339203134Sthompsa	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
3340270515Skevlo	    type != IEEE80211_FC0_TYPE_DATA || m->m_flags & M_EAPOL) {
3341203134Sthompsa		ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
3342203134Sthompsa		    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
3343203134Sthompsa		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
3344203134Sthompsa	} else {
3345208019Sthompsa		if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
3346208019Sthompsa			ridx = rn->fix_ridx;
3347208019Sthompsa		else
3348208019Sthompsa			ridx = rn->amrr_ridx;
3349203134Sthompsa		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
3350203134Sthompsa	}
3351203134Sthompsa
3352203134Sthompsa	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
3353203134Sthompsa	    (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) !=
3354203134Sthompsa	     IEEE80211_QOS_ACKPOLICY_NOACK)) {
3355209144Sthompsa		xflags |= RT2860_TX_ACK;
3356203134Sthompsa		if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
3357208019Sthompsa			dur = rt2860_rates[ctl_ridx].sp_ack_dur;
3358203134Sthompsa		else
3359208019Sthompsa			dur = rt2860_rates[ctl_ridx].lp_ack_dur;
3360259453Shselasky		USETW(wh->i_dur, dur);
3361203134Sthompsa	}
3362203134Sthompsa
3363203134Sthompsa	/* reserve slots for mgmt packets, just in case */
3364203134Sthompsa	if (sc->sc_epq[qid].tx_nfree < 3) {
3365203134Sthompsa		DPRINTFN(10, "tx ring %d is full\n", qid);
3366203134Sthompsa		return (-1);
3367203134Sthompsa	}
3368203134Sthompsa
3369203134Sthompsa	data = STAILQ_FIRST(&sc->sc_epq[qid].tx_fh);
3370203134Sthompsa	STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next);
3371203134Sthompsa	sc->sc_epq[qid].tx_nfree--;
3372203134Sthompsa
3373208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3374208019Sthompsa	txd->flags = qflags;
3375208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3376208019Sthompsa	txwi->xflags = xflags;
3377259453Shselasky	if (IEEE80211_IS_MULTICAST(wh->i_addr1))
3378245047Shselasky		txwi->wcid = 0;
3379259453Shselasky	else
3380245047Shselasky		txwi->wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
3381245047Shselasky		    1 : RUN_AID2WCID(ni->ni_associd);
3382259453Shselasky
3383208019Sthompsa	/* clear leftover garbage bits */
3384208019Sthompsa	txwi->flags = 0;
3385208019Sthompsa	txwi->txop = 0;
3386208019Sthompsa
3387203134Sthompsa	data->m = m;
3388203134Sthompsa	data->ni = ni;
3389203134Sthompsa	data->ridx = ridx;
3390203134Sthompsa
3391208019Sthompsa	run_set_tx_desc(sc, data);
3392203134Sthompsa
3393208019Sthompsa	/*
3394208019Sthompsa	 * The chip keeps track of 2 kind of Tx stats,
3395208019Sthompsa	 *  * TX_STAT_FIFO, for per WCID stats, and
3396208019Sthompsa	 *  * TX_STA_CNT0 for all-TX-in-one stats.
3397208019Sthompsa	 *
3398208019Sthompsa	 * To use FIFO stats, we need to store MCS into the driver-private
3399208019Sthompsa 	 * PacketID field. So that, we can tell whose stats when we read them.
3400208019Sthompsa 	 * We add 1 to the MCS because setting the PacketID field to 0 means
3401208019Sthompsa 	 * that we don't want feedback in TX_STAT_FIFO.
3402208019Sthompsa 	 * And, that's what we want for STA mode, since TX_STA_CNT0 does the job.
3403208019Sthompsa 	 *
3404208019Sthompsa 	 * FIFO stats doesn't count Tx with WCID 0xff, so we do this in run_tx().
3405208019Sthompsa 	 */
3406209917Sthompsa	if (sc->rvp_cnt > 1 || vap->iv_opmode == IEEE80211_M_HOSTAP ||
3407209917Sthompsa	    vap->iv_opmode == IEEE80211_M_MBSS) {
3408208019Sthompsa		uint16_t pid = (rt2860_rates[ridx].mcs + 1) & 0xf;
3409208019Sthompsa		txwi->len |= htole16(pid << RT2860_TX_PID_SHIFT);
3410208019Sthompsa
3411208019Sthompsa		/*
3412208019Sthompsa		 * Unlike PCI based devices, we don't get any interrupt from
3413208019Sthompsa		 * USB devices, so we simulate FIFO-is-full interrupt here.
3414208019Sthompsa		 * Ralink recomends to drain FIFO stats every 100 ms, but 16 slots
3415208019Sthompsa		 * quickly get fulled. To prevent overflow, increment a counter on
3416208019Sthompsa		 * every FIFO stat request, so we know how many slots are left.
3417208019Sthompsa		 * We do this only in HOSTAP or multiple vap mode since FIFO stats
3418208019Sthompsa		 * are used only in those modes.
3419208019Sthompsa		 * We just drain stats. AMRR gets updated every 1 sec by
3420208019Sthompsa		 * run_ratectl_cb() via callout.
3421208019Sthompsa		 * Call it early. Otherwise overflow.
3422208019Sthompsa		 */
3423209917Sthompsa		if (sc->fifo_cnt++ == 10) {
3424208019Sthompsa			/*
3425208019Sthompsa			 * With multiple vaps or if_bridge, if_start() is called
3426208019Sthompsa			 * with a non-sleepable lock, tcpinp. So, need to defer.
3427208019Sthompsa			 */
3428208019Sthompsa			uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
3429208019Sthompsa			DPRINTFN(6, "cmdq_store=%d\n", i);
3430208019Sthompsa			sc->cmdq[i].func = run_drain_fifo;
3431208019Sthompsa			sc->cmdq[i].arg0 = sc;
3432208019Sthompsa			ieee80211_runtask(ic, &sc->cmdq_task);
3433208019Sthompsa		}
3434208019Sthompsa	}
3435208019Sthompsa
3436203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next);
3437203134Sthompsa
3438203134Sthompsa	usbd_transfer_start(sc->sc_xfer[qid]);
3439203134Sthompsa
3440259453Shselasky	DPRINTFN(8, "sending data frame len=%d rate=%d qid=%d\n",
3441259453Shselasky	    m->m_pkthdr.len + (int)(sizeof(struct rt2870_txd) +
3442259453Shselasky	    sizeof(struct rt2860_txwi)), rt2860_rates[ridx].rate, qid);
3443203134Sthompsa
3444203134Sthompsa	return (0);
3445203134Sthompsa}
3446203134Sthompsa
3447203134Sthompsastatic int
3448203134Sthompsarun_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
3449203134Sthompsa{
3450203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
3451203134Sthompsa	struct ieee80211com *ic = ifp->if_l2com;
3452208019Sthompsa	struct run_node *rn = (void *)ni;
3453203134Sthompsa	struct run_tx_data *data;
3454203134Sthompsa	struct ieee80211_frame *wh;
3455208019Sthompsa	struct rt2870_txd *txd;
3456208019Sthompsa	struct rt2860_txwi *txwi;
3457203134Sthompsa	uint16_t dur;
3458208019Sthompsa	uint8_t ridx = rn->mgt_ridx;
3459203134Sthompsa	uint8_t type;
3460203134Sthompsa	uint8_t xflags = 0;
3461208019Sthompsa	uint8_t wflags = 0;
3462203134Sthompsa
3463203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3464203134Sthompsa
3465203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3466203134Sthompsa
3467203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3468203134Sthompsa
3469208019Sthompsa	/* tell hardware to add timestamp for probe responses */
3470208019Sthompsa	if ((wh->i_fc[0] &
3471208019Sthompsa	    (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==
3472208019Sthompsa	    (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP))
3473208019Sthompsa		wflags |= RT2860_TX_TS;
3474208019Sthompsa	else if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3475203134Sthompsa		xflags |= RT2860_TX_ACK;
3476203134Sthompsa
3477208019Sthompsa		dur = ieee80211_ack_duration(ic->ic_rt, rt2860_rates[ridx].rate,
3478203134Sthompsa		    ic->ic_flags & IEEE80211_F_SHPREAMBLE);
3479259453Shselasky		USETW(wh->i_dur, dur);
3480203134Sthompsa	}
3481203134Sthompsa
3482203134Sthompsa	if (sc->sc_epq[0].tx_nfree == 0) {
3483203134Sthompsa		/* let caller free mbuf */
3484203134Sthompsa		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
3485203134Sthompsa		return (EIO);
3486203134Sthompsa	}
3487203134Sthompsa	data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3488203134Sthompsa	STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3489203134Sthompsa	sc->sc_epq[0].tx_nfree--;
3490203134Sthompsa
3491208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3492208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3493208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3494208019Sthompsa	txwi->wcid = 0xff;
3495208019Sthompsa	txwi->flags = wflags;
3496208019Sthompsa	txwi->xflags = xflags;
3497208019Sthompsa	txwi->txop = 0;	/* clear leftover garbage bits */
3498208019Sthompsa
3499203134Sthompsa	data->m = m;
3500203134Sthompsa	data->ni = ni;
3501203134Sthompsa	data->ridx = ridx;
3502203134Sthompsa
3503208019Sthompsa	run_set_tx_desc(sc, data);
3504203134Sthompsa
3505203134Sthompsa	DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m->m_pkthdr.len +
3506259453Shselasky	    (int)(sizeof(struct rt2870_txd) + sizeof(struct rt2860_txwi)),
3507208019Sthompsa	    rt2860_rates[ridx].rate);
3508203134Sthompsa
3509203134Sthompsa	STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3510203134Sthompsa
3511203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3512203134Sthompsa
3513203134Sthompsa	return (0);
3514203134Sthompsa}
3515203134Sthompsa
3516203134Sthompsastatic int
3517203134Sthompsarun_sendprot(struct run_softc *sc,
3518203134Sthompsa    const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate)
3519203134Sthompsa{
3520203134Sthompsa	struct ieee80211com *ic = ni->ni_ic;
3521203134Sthompsa	struct ieee80211_frame *wh;
3522203134Sthompsa	struct run_tx_data *data;
3523208019Sthompsa	struct rt2870_txd *txd;
3524208019Sthompsa	struct rt2860_txwi *txwi;
3525203134Sthompsa	struct mbuf *mprot;
3526203134Sthompsa	int ridx;
3527203134Sthompsa	int protrate;
3528203134Sthompsa	int ackrate;
3529203134Sthompsa	int pktlen;
3530203134Sthompsa	int isshort;
3531203134Sthompsa	uint16_t dur;
3532203134Sthompsa	uint8_t type;
3533208019Sthompsa	uint8_t wflags = 0;
3534208019Sthompsa	uint8_t xflags = 0;
3535203134Sthompsa
3536203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3537203134Sthompsa
3538203134Sthompsa	KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY,
3539203134Sthompsa	    ("protection %d", prot));
3540203134Sthompsa
3541203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3542203134Sthompsa	pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN;
3543203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3544203134Sthompsa
3545203134Sthompsa	protrate = ieee80211_ctl_rate(ic->ic_rt, rate);
3546203134Sthompsa	ackrate = ieee80211_ack_rate(ic->ic_rt, rate);
3547203134Sthompsa
3548203134Sthompsa	isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
3549209189Sjkim	dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort)
3550203134Sthompsa	    + ieee80211_ack_duration(ic->ic_rt, rate, isshort);
3551203134Sthompsa	wflags = RT2860_TX_FRAG;
3552203134Sthompsa
3553203134Sthompsa	/* check that there are free slots before allocating the mbuf */
3554203134Sthompsa	if (sc->sc_epq[0].tx_nfree == 0) {
3555203134Sthompsa		/* let caller free mbuf */
3556203134Sthompsa		sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE;
3557203134Sthompsa		return (ENOBUFS);
3558203134Sthompsa	}
3559203134Sthompsa
3560203134Sthompsa	if (prot == IEEE80211_PROT_RTSCTS) {
3561203134Sthompsa		/* NB: CTS is the same size as an ACK */
3562203134Sthompsa		dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort);
3563208019Sthompsa		xflags |= RT2860_TX_ACK;
3564203134Sthompsa		mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur);
3565203134Sthompsa	} else {
3566203134Sthompsa		mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur);
3567203134Sthompsa	}
3568203134Sthompsa	if (mprot == NULL) {
3569203134Sthompsa		sc->sc_ifp->if_oerrors++;
3570203134Sthompsa		DPRINTF("could not allocate mbuf\n");
3571203134Sthompsa		return (ENOBUFS);
3572203134Sthompsa	}
3573203134Sthompsa
3574203134Sthompsa        data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3575203134Sthompsa        STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3576203134Sthompsa        sc->sc_epq[0].tx_nfree--;
3577203134Sthompsa
3578208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3579208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3580208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3581208019Sthompsa	txwi->wcid = 0xff;
3582208019Sthompsa	txwi->flags = wflags;
3583208019Sthompsa	txwi->xflags = xflags;
3584208019Sthompsa	txwi->txop = 0;	/* clear leftover garbage bits */
3585208019Sthompsa
3586203134Sthompsa	data->m = mprot;
3587203134Sthompsa	data->ni = ieee80211_ref_node(ni);
3588203134Sthompsa
3589203134Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
3590203134Sthompsa		if (rt2860_rates[ridx].rate == protrate)
3591203134Sthompsa			break;
3592203134Sthompsa	data->ridx = ridx;
3593203134Sthompsa
3594208019Sthompsa	run_set_tx_desc(sc, data);
3595203134Sthompsa
3596203134Sthompsa        DPRINTFN(1, "sending prot len=%u rate=%u\n",
3597203134Sthompsa            m->m_pkthdr.len, rate);
3598203134Sthompsa
3599203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3600203134Sthompsa
3601203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3602203134Sthompsa
3603203134Sthompsa	return (0);
3604203134Sthompsa}
3605203134Sthompsa
3606203134Sthompsastatic int
3607203134Sthompsarun_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni,
3608203134Sthompsa    const struct ieee80211_bpf_params *params)
3609203134Sthompsa{
3610203134Sthompsa	struct ieee80211com *ic = ni->ni_ic;
3611203134Sthompsa	struct ieee80211_frame *wh;
3612203134Sthompsa	struct run_tx_data *data;
3613208019Sthompsa	struct rt2870_txd *txd;
3614208019Sthompsa	struct rt2860_txwi *txwi;
3615203134Sthompsa	uint8_t type;
3616208019Sthompsa	uint8_t ridx;
3617208019Sthompsa	uint8_t rate;
3618208019Sthompsa	uint8_t opflags = 0;
3619208019Sthompsa	uint8_t xflags = 0;
3620203134Sthompsa	int error;
3621203134Sthompsa
3622203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3623203134Sthompsa
3624203134Sthompsa	KASSERT(params != NULL, ("no raw xmit params"));
3625203134Sthompsa
3626203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3627203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3628203134Sthompsa
3629203134Sthompsa	rate = params->ibp_rate0;
3630203134Sthompsa	if (!ieee80211_isratevalid(ic->ic_rt, rate)) {
3631203134Sthompsa		/* let caller free mbuf */
3632203134Sthompsa		return (EINVAL);
3633203134Sthompsa	}
3634203134Sthompsa
3635203134Sthompsa	if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0)
3636208019Sthompsa		xflags |= RT2860_TX_ACK;
3637203134Sthompsa	if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) {
3638203134Sthompsa		error = run_sendprot(sc, m, ni,
3639203134Sthompsa		    params->ibp_flags & IEEE80211_BPF_RTS ?
3640203134Sthompsa			IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY,
3641203134Sthompsa		    rate);
3642203134Sthompsa		if (error) {
3643203134Sthompsa			/* let caller free mbuf */
3644209917Sthompsa			return error;
3645203134Sthompsa		}
3646203134Sthompsa		opflags |= /*XXX RT2573_TX_LONG_RETRY |*/ RT2860_TX_TXOP_SIFS;
3647203134Sthompsa	}
3648203134Sthompsa
3649203134Sthompsa	if (sc->sc_epq[0].tx_nfree == 0) {
3650203134Sthompsa		/* let caller free mbuf */
3651203134Sthompsa		sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE;
3652203134Sthompsa		DPRINTF("sending raw frame, but tx ring is full\n");
3653203134Sthompsa		return (EIO);
3654203134Sthompsa	}
3655203134Sthompsa        data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3656203134Sthompsa        STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3657203134Sthompsa        sc->sc_epq[0].tx_nfree--;
3658203134Sthompsa
3659208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3660208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3661208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3662208019Sthompsa	txwi->wcid = 0xff;
3663208019Sthompsa	txwi->xflags = xflags;
3664208019Sthompsa	txwi->txop = opflags;
3665208019Sthompsa	txwi->flags = 0;	/* clear leftover garbage bits */
3666208019Sthompsa
3667203134Sthompsa        data->m = m;
3668203134Sthompsa        data->ni = ni;
3669203134Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
3670203134Sthompsa		if (rt2860_rates[ridx].rate == rate)
3671203134Sthompsa			break;
3672203134Sthompsa	data->ridx = ridx;
3673203134Sthompsa
3674208019Sthompsa        run_set_tx_desc(sc, data);
3675203134Sthompsa
3676203134Sthompsa        DPRINTFN(10, "sending raw frame len=%u rate=%u\n",
3677203134Sthompsa            m->m_pkthdr.len, rate);
3678203134Sthompsa
3679203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3680203134Sthompsa
3681203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3682203134Sthompsa
3683209917Sthompsa        return (0);
3684203134Sthompsa}
3685203134Sthompsa
3686203134Sthompsastatic int
3687203134Sthompsarun_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
3688203134Sthompsa    const struct ieee80211_bpf_params *params)
3689203134Sthompsa{
3690203134Sthompsa	struct ifnet *ifp = ni->ni_ic->ic_ifp;
3691203134Sthompsa	struct run_softc *sc = ifp->if_softc;
3692208019Sthompsa	int error = 0;
3693208019Sthompsa
3694203134Sthompsa	RUN_LOCK(sc);
3695203134Sthompsa
3696203134Sthompsa	/* prevent management frames from being sent if we're not ready */
3697203134Sthompsa	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
3698203134Sthompsa		error =  ENETDOWN;
3699208019Sthompsa		goto done;
3700203134Sthompsa	}
3701203134Sthompsa
3702203134Sthompsa	if (params == NULL) {
3703203134Sthompsa		/* tx mgt packet */
3704209917Sthompsa		if ((error = run_tx_mgt(sc, m, ni)) != 0) {
3705203134Sthompsa			ifp->if_oerrors++;
3706203134Sthompsa			DPRINTF("mgt tx failed\n");
3707208019Sthompsa			goto done;
3708203134Sthompsa		}
3709203134Sthompsa	} else {
3710203134Sthompsa		/* tx raw packet with param */
3711209917Sthompsa		if ((error = run_tx_param(sc, m, ni, params)) != 0) {
3712203134Sthompsa			ifp->if_oerrors++;
3713203134Sthompsa			DPRINTF("tx with param failed\n");
3714208019Sthompsa			goto done;
3715203134Sthompsa		}
3716203134Sthompsa	}
3717203134Sthompsa
3718203134Sthompsa	ifp->if_opackets++;
3719203134Sthompsa
3720208019Sthompsadone:
3721203134Sthompsa	RUN_UNLOCK(sc);
3722203134Sthompsa
3723209917Sthompsa	if (error != 0) {
3724208019Sthompsa		if(m != NULL)
3725208019Sthompsa			m_freem(m);
3726208019Sthompsa		ieee80211_free_node(ni);
3727208019Sthompsa	}
3728203134Sthompsa
3729203134Sthompsa	return (error);
3730203134Sthompsa}
3731203134Sthompsa
3732203134Sthompsastatic void
3733203134Sthompsarun_start(struct ifnet *ifp)
3734203134Sthompsa{
3735203134Sthompsa	struct run_softc *sc = ifp->if_softc;
3736203134Sthompsa	struct ieee80211_node *ni;
3737203134Sthompsa	struct mbuf *m;
3738203134Sthompsa
3739203134Sthompsa	RUN_LOCK(sc);
3740203134Sthompsa
3741203134Sthompsa	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
3742203134Sthompsa		RUN_UNLOCK(sc);
3743203134Sthompsa		return;
3744203134Sthompsa	}
3745203134Sthompsa
3746203134Sthompsa	for (;;) {
3747203134Sthompsa		/* send data frames */
3748203134Sthompsa		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
3749203134Sthompsa		if (m == NULL)
3750203134Sthompsa			break;
3751203134Sthompsa
3752203134Sthompsa		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
3753203134Sthompsa		if (run_tx(sc, m, ni) != 0) {
3754203134Sthompsa			IFQ_DRV_PREPEND(&ifp->if_snd, m);
3755203134Sthompsa			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
3756203134Sthompsa			break;
3757203134Sthompsa		}
3758203134Sthompsa	}
3759203134Sthompsa
3760203134Sthompsa	RUN_UNLOCK(sc);
3761203134Sthompsa}
3762203134Sthompsa
3763203134Sthompsastatic int
3764203134Sthompsarun_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
3765203134Sthompsa{
3766203134Sthompsa	struct run_softc *sc = ifp->if_softc;
3767203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
3768203134Sthompsa	struct ifreq *ifr = (struct ifreq *) data;
3769208019Sthompsa	int startall = 0;
3770246614Shselasky	int error;
3771203134Sthompsa
3772246614Shselasky	RUN_LOCK(sc);
3773246614Shselasky	error = sc->sc_detached ? ENXIO : 0;
3774246614Shselasky	RUN_UNLOCK(sc);
3775246614Shselasky	if (error)
3776246614Shselasky		return (error);
3777246614Shselasky
3778203134Sthompsa	switch (cmd) {
3779203134Sthompsa	case SIOCSIFFLAGS:
3780203134Sthompsa		RUN_LOCK(sc);
3781203134Sthompsa		if (ifp->if_flags & IFF_UP) {
3782203134Sthompsa			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)){
3783208019Sthompsa				startall = 1;
3784203134Sthompsa				run_init_locked(sc);
3785203134Sthompsa			} else
3786203134Sthompsa				run_update_promisc_locked(ifp);
3787203134Sthompsa		} else {
3788209917Sthompsa			if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
3789209917Sthompsa			    (ic->ic_nrunning == 0 || sc->rvp_cnt <= 1)) {
3790208019Sthompsa					run_stop(sc);
3791208019Sthompsa			}
3792203134Sthompsa		}
3793203134Sthompsa		RUN_UNLOCK(sc);
3794209917Sthompsa		if (startall)
3795208019Sthompsa			ieee80211_start_all(ic);
3796203134Sthompsa		break;
3797203134Sthompsa	case SIOCGIFMEDIA:
3798203134Sthompsa		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
3799203134Sthompsa		break;
3800203134Sthompsa	case SIOCGIFADDR:
3801203134Sthompsa		error = ether_ioctl(ifp, cmd, data);
3802203134Sthompsa		break;
3803203134Sthompsa	default:
3804203134Sthompsa		error = EINVAL;
3805203134Sthompsa		break;
3806203134Sthompsa	}
3807203134Sthompsa
3808203134Sthompsa	return (error);
3809203134Sthompsa}
3810203134Sthompsa
3811203134Sthompsastatic void
3812261868Skevlorun_iq_calib(struct run_softc *sc, u_int chan)
3813261868Skevlo{
3814261868Skevlo	uint16_t val;
3815261868Skevlo
3816261868Skevlo	/* Tx0 IQ gain. */
3817261868Skevlo	run_bbp_write(sc, 158, 0x2c);
3818261868Skevlo	if (chan <= 14)
3819261868Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX0_2GHZ, &val, 1);
3820261868Skevlo	else if (chan <= 64) {
3821261868Skevlo		run_efuse_read(sc,
3822261868Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH36_TO_CH64_5GHZ,
3823261868Skevlo		    &val, 1);
3824261868Skevlo	} else if (chan <= 138) {
3825261868Skevlo		run_efuse_read(sc,
3826261868Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH100_TO_CH138_5GHZ,
3827261868Skevlo		    &val, 1);
3828261868Skevlo	} else if (chan <= 165) {
3829261868Skevlo		run_efuse_read(sc,
3830261868Skevlo	    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH140_TO_CH165_5GHZ,
3831261868Skevlo		    &val, 1);
3832261868Skevlo	} else
3833261868Skevlo		val = 0;
3834261868Skevlo	run_bbp_write(sc, 159, val);
3835261868Skevlo
3836261868Skevlo	/* Tx0 IQ phase. */
3837261868Skevlo	run_bbp_write(sc, 158, 0x2d);
3838261868Skevlo	if (chan <= 14) {
3839261868Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX0_2GHZ,
3840261868Skevlo		    &val, 1);
3841261868Skevlo	} else if (chan <= 64) {
3842261868Skevlo		run_efuse_read(sc,
3843261868Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH36_TO_CH64_5GHZ,
3844261868Skevlo		    &val, 1);
3845261868Skevlo	} else if (chan <= 138) {
3846261868Skevlo		run_efuse_read(sc,
3847261868Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH100_TO_CH138_5GHZ,
3848261868Skevlo		    &val, 1);
3849261868Skevlo	} else if (chan <= 165) {
3850261868Skevlo		run_efuse_read(sc,
3851261868Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH140_TO_CH165_5GHZ,
3852261868Skevlo		    &val, 1);
3853261868Skevlo	} else
3854261868Skevlo		val = 0;
3855261868Skevlo	run_bbp_write(sc, 159, val);
3856261868Skevlo
3857261868Skevlo	/* Tx1 IQ gain. */
3858261868Skevlo	run_bbp_write(sc, 158, 0x4a);
3859261868Skevlo	if (chan <= 14) {
3860261868Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX1_2GHZ,
3861261868Skevlo		    &val, 1);
3862261868Skevlo	} else if (chan <= 64) {
3863261868Skevlo		run_efuse_read(sc,
3864261868Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH36_TO_CH64_5GHZ,
3865261868Skevlo		    &val, 1);
3866261868Skevlo	} else if (chan <= 138) {
3867261868Skevlo		run_efuse_read(sc,
3868261868Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH100_TO_CH138_5GHZ,
3869261868Skevlo		    &val, 1);
3870261868Skevlo	} else if (chan <= 165) {
3871261868Skevlo		run_efuse_read(sc,
3872261868Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH140_TO_CH165_5GHZ,
3873261868Skevlo		    &val, 1);
3874261868Skevlo	} else
3875261868Skevlo		val = 0;
3876261868Skevlo	run_bbp_write(sc, 159, val);
3877261868Skevlo
3878261868Skevlo	/* Tx1 IQ phase. */
3879261868Skevlo	run_bbp_write(sc, 158, 0x4b);
3880261868Skevlo	if (chan <= 14) {
3881261868Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX1_2GHZ,
3882261868Skevlo		    &val, 1);
3883261868Skevlo	} else if (chan <= 64) {
3884261868Skevlo		run_efuse_read(sc,
3885261868Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH36_TO_CH64_5GHZ,
3886261868Skevlo		    &val, 1);
3887261868Skevlo	} else if (chan <= 138) {
3888261868Skevlo		run_efuse_read(sc,
3889261868Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH100_TO_CH138_5GHZ,
3890261868Skevlo		    &val, 1);
3891261868Skevlo	} else if (chan <= 165) {
3892261868Skevlo		run_efuse_read(sc,
3893261868Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH140_TO_CH165_5GHZ,
3894261868Skevlo		    &val, 1);
3895261868Skevlo	} else
3896261868Skevlo		val = 0;
3897261868Skevlo	run_bbp_write(sc, 159, val);
3898261868Skevlo
3899261868Skevlo	/* RF IQ compensation control. */
3900261868Skevlo	run_bbp_write(sc, 158, 0x04);
3901261868Skevlo	run_efuse_read(sc, RT5390_EEPROM_RF_IQ_COMPENSATION_CTL,
3902261868Skevlo	    &val, 1);
3903261868Skevlo	run_bbp_write(sc, 159, val);
3904261868Skevlo
3905261868Skevlo	/* RF IQ imbalance compensation control. */
3906261868Skevlo	run_bbp_write(sc, 158, 0x03);
3907261868Skevlo	run_efuse_read(sc,
3908261868Skevlo	    RT5390_EEPROM_RF_IQ_IMBALANCE_COMPENSATION_CTL, &val, 1);
3909261868Skevlo	run_bbp_write(sc, 159, val);
3910261868Skevlo}
3911261868Skevlo
3912261868Skevlostatic void
3913205042Sthompsarun_set_agc(struct run_softc *sc, uint8_t agc)
3914205042Sthompsa{
3915205042Sthompsa	uint8_t bbp;
3916205042Sthompsa
3917205042Sthompsa	if (sc->mac_ver == 0x3572) {
3918205042Sthompsa		run_bbp_read(sc, 27, &bbp);
3919205042Sthompsa		bbp &= ~(0x3 << 5);
3920205042Sthompsa		run_bbp_write(sc, 27, bbp | 0 << 5);	/* select Rx0 */
3921205042Sthompsa		run_bbp_write(sc, 66, agc);
3922205042Sthompsa		run_bbp_write(sc, 27, bbp | 1 << 5);	/* select Rx1 */
3923205042Sthompsa		run_bbp_write(sc, 66, agc);
3924205042Sthompsa	} else
3925205042Sthompsa		run_bbp_write(sc, 66, agc);
3926205042Sthompsa}
3927205042Sthompsa
3928205042Sthompsastatic void
3929203134Sthompsarun_select_chan_group(struct run_softc *sc, int group)
3930203134Sthompsa{
3931203134Sthompsa	uint32_t tmp;
3932205042Sthompsa	uint8_t agc;
3933203134Sthompsa
3934203134Sthompsa	run_bbp_write(sc, 62, 0x37 - sc->lna[group]);
3935203134Sthompsa	run_bbp_write(sc, 63, 0x37 - sc->lna[group]);
3936203134Sthompsa	run_bbp_write(sc, 64, 0x37 - sc->lna[group]);
3937259453Shselasky	if (sc->mac_ver < 0x3572)
3938259453Shselasky		run_bbp_write(sc, 86, 0x00);
3939203134Sthompsa
3940261868Skevlo	if (sc->mac_ver == 0x3593) {
3941261868Skevlo		run_bbp_write(sc, 77, 0x98);
3942261868Skevlo		run_bbp_write(sc, 83, (group == 0) ? 0x8a : 0x9a);
3943261868Skevlo	}
3944261868Skevlo
3945203134Sthompsa	if (group == 0) {
3946203134Sthompsa		if (sc->ext_2ghz_lna) {
3947259453Shselasky			if (sc->mac_ver >= 0x5390)
3948259453Shselasky				run_bbp_write(sc, 75, 0x52);
3949259453Shselasky			else {
3950259453Shselasky				run_bbp_write(sc, 82, 0x62);
3951259453Shselasky				run_bbp_write(sc, 75, 0x46);
3952259453Shselasky			}
3953203134Sthompsa		} else {
3954259453Shselasky			if (sc->mac_ver == 0x5592) {
3955259453Shselasky				run_bbp_write(sc, 79, 0x1c);
3956259453Shselasky				run_bbp_write(sc, 80, 0x0e);
3957259453Shselasky				run_bbp_write(sc, 81, 0x3a);
3958259453Shselasky				run_bbp_write(sc, 82, 0x62);
3959259453Shselasky
3960259453Shselasky				run_bbp_write(sc, 195, 0x80);
3961259453Shselasky				run_bbp_write(sc, 196, 0xe0);
3962259453Shselasky				run_bbp_write(sc, 195, 0x81);
3963259453Shselasky				run_bbp_write(sc, 196, 0x1f);
3964259453Shselasky				run_bbp_write(sc, 195, 0x82);
3965259453Shselasky				run_bbp_write(sc, 196, 0x38);
3966259453Shselasky				run_bbp_write(sc, 195, 0x83);
3967259453Shselasky				run_bbp_write(sc, 196, 0x32);
3968259453Shselasky				run_bbp_write(sc, 195, 0x85);
3969259453Shselasky				run_bbp_write(sc, 196, 0x28);
3970259453Shselasky				run_bbp_write(sc, 195, 0x86);
3971259453Shselasky				run_bbp_write(sc, 196, 0x19);
3972259453Shselasky			} else if (sc->mac_ver >= 0x5390)
3973259453Shselasky				run_bbp_write(sc, 75, 0x50);
3974259453Shselasky			else {
3975261868Skevlo				run_bbp_write(sc, 82,
3976261868Skevlo				    (sc->mac_ver == 0x3593) ? 0x62 : 0x84);
3977259453Shselasky				run_bbp_write(sc, 75, 0x50);
3978259453Shselasky			}
3979203134Sthompsa		}
3980203134Sthompsa	} else {
3981259453Shselasky		if (sc->mac_ver == 0x5592) {
3982259453Shselasky			run_bbp_write(sc, 79, 0x18);
3983259453Shselasky			run_bbp_write(sc, 80, 0x08);
3984259453Shselasky			run_bbp_write(sc, 81, 0x38);
3985259453Shselasky			run_bbp_write(sc, 82, 0x92);
3986259453Shselasky
3987259453Shselasky			run_bbp_write(sc, 195, 0x80);
3988259453Shselasky			run_bbp_write(sc, 196, 0xf0);
3989259453Shselasky			run_bbp_write(sc, 195, 0x81);
3990259453Shselasky			run_bbp_write(sc, 196, 0x1e);
3991259453Shselasky			run_bbp_write(sc, 195, 0x82);
3992259453Shselasky			run_bbp_write(sc, 196, 0x28);
3993259453Shselasky			run_bbp_write(sc, 195, 0x83);
3994259453Shselasky			run_bbp_write(sc, 196, 0x20);
3995259453Shselasky			run_bbp_write(sc, 195, 0x85);
3996259453Shselasky			run_bbp_write(sc, 196, 0x7f);
3997259453Shselasky			run_bbp_write(sc, 195, 0x86);
3998259453Shselasky			run_bbp_write(sc, 196, 0x7f);
3999259453Shselasky		} else if (sc->mac_ver == 0x3572)
4000205042Sthompsa			run_bbp_write(sc, 82, 0x94);
4001205042Sthompsa		else
4002261868Skevlo			run_bbp_write(sc, 82,
4003261868Skevlo			    (sc->mac_ver == 0x3593) ? 0x82 : 0xf2);
4004205042Sthompsa		if (sc->ext_5ghz_lna)
4005203134Sthompsa			run_bbp_write(sc, 75, 0x46);
4006205042Sthompsa		else
4007203134Sthompsa			run_bbp_write(sc, 75, 0x50);
4008203134Sthompsa	}
4009203134Sthompsa
4010203134Sthompsa	run_read(sc, RT2860_TX_BAND_CFG, &tmp);
4011203134Sthompsa	tmp &= ~(RT2860_5G_BAND_SEL_N | RT2860_5G_BAND_SEL_P);
4012203134Sthompsa	tmp |= (group == 0) ? RT2860_5G_BAND_SEL_N : RT2860_5G_BAND_SEL_P;
4013203134Sthompsa	run_write(sc, RT2860_TX_BAND_CFG, tmp);
4014203134Sthompsa
4015203134Sthompsa	/* enable appropriate Power Amplifiers and Low Noise Amplifiers */
4016208019Sthompsa	tmp = RT2860_RFTR_EN | RT2860_TRSW_EN | RT2860_LNA_PE0_EN;
4017261868Skevlo	if (sc->mac_ver == 0x3593)
4018261868Skevlo		tmp |= 1 << 29 | 1 << 28;
4019208019Sthompsa	if (sc->nrxchains > 1)
4020208019Sthompsa		tmp |= RT2860_LNA_PE1_EN;
4021203134Sthompsa	if (group == 0) {	/* 2GHz */
4022208019Sthompsa		tmp |= RT2860_PA_PE_G0_EN;
4023203134Sthompsa		if (sc->ntxchains > 1)
4024203134Sthompsa			tmp |= RT2860_PA_PE_G1_EN;
4025261868Skevlo		if (sc->mac_ver == 0x3593) {
4026261868Skevlo			if (sc->ntxchains > 2)
4027261868Skevlo				tmp |= 1 << 25;
4028261868Skevlo		}
4029203134Sthompsa	} else {		/* 5GHz */
4030208019Sthompsa		tmp |= RT2860_PA_PE_A0_EN;
4031203134Sthompsa		if (sc->ntxchains > 1)
4032203134Sthompsa			tmp |= RT2860_PA_PE_A1_EN;
4033203134Sthompsa	}
4034205042Sthompsa	if (sc->mac_ver == 0x3572) {
4035205042Sthompsa		run_rt3070_rf_write(sc, 8, 0x00);
4036205042Sthompsa		run_write(sc, RT2860_TX_PIN_CFG, tmp);
4037205042Sthompsa		run_rt3070_rf_write(sc, 8, 0x80);
4038205042Sthompsa	} else
4039205042Sthompsa		run_write(sc, RT2860_TX_PIN_CFG, tmp);
4040203134Sthompsa
4041259453Shselasky	if (sc->mac_ver == 0x5592) {
4042259453Shselasky		run_bbp_write(sc, 195, 0x8d);
4043259453Shselasky		run_bbp_write(sc, 196, 0x1a);
4044259453Shselasky	}
4045259453Shselasky
4046261868Skevlo	if (sc->mac_ver == 0x3593) {
4047261868Skevlo		run_read(sc, RT2860_GPIO_CTRL, &tmp);
4048261868Skevlo		tmp &= ~0x01010000;
4049261868Skevlo		if (group == 0)
4050261868Skevlo			tmp |= 0x00010000;
4051261868Skevlo		tmp = (tmp & ~0x00009090) | 0x00000090;
4052261868Skevlo		run_write(sc, RT2860_GPIO_CTRL, tmp);
4053261868Skevlo	}
4054261868Skevlo
4055203134Sthompsa	/* set initial AGC value */
4056205042Sthompsa	if (group == 0) {	/* 2GHz band */
4057205042Sthompsa		if (sc->mac_ver >= 0x3070)
4058205042Sthompsa			agc = 0x1c + sc->lna[0] * 2;
4059205042Sthompsa		else
4060205042Sthompsa			agc = 0x2e + sc->lna[0];
4061205042Sthompsa	} else {		/* 5GHz band */
4062259453Shselasky		if (sc->mac_ver == 0x5592)
4063259453Shselasky			agc = 0x24 + sc->lna[group] * 2;
4064261868Skevlo		else if (sc->mac_ver == 0x3572 || sc->mac_ver == 0x3593)
4065205042Sthompsa			agc = 0x22 + (sc->lna[group] * 5) / 3;
4066205042Sthompsa		else
4067205042Sthompsa			agc = 0x32 + (sc->lna[group] * 5) / 3;
4068205042Sthompsa	}
4069205042Sthompsa	run_set_agc(sc, agc);
4070203134Sthompsa}
4071203134Sthompsa
4072203134Sthompsastatic void
4073259453Shselaskyrun_rt2870_set_chan(struct run_softc *sc, u_int chan)
4074203134Sthompsa{
4075203134Sthompsa	const struct rfprog *rfprog = rt2860_rf2850;
4076203134Sthompsa	uint32_t r2, r3, r4;
4077203134Sthompsa	int8_t txpow1, txpow2;
4078203134Sthompsa	int i;
4079203134Sthompsa
4080203134Sthompsa	/* find the settings for this channel (we know it exists) */
4081203134Sthompsa	for (i = 0; rfprog[i].chan != chan; i++);
4082203134Sthompsa
4083203134Sthompsa	r2 = rfprog[i].r2;
4084203134Sthompsa	if (sc->ntxchains == 1)
4085259453Shselasky		r2 |= 1 << 14;		/* 1T: disable Tx chain 2 */
4086203134Sthompsa	if (sc->nrxchains == 1)
4087259453Shselasky		r2 |= 1 << 17 | 1 << 6;	/* 1R: disable Rx chains 2 & 3 */
4088203134Sthompsa	else if (sc->nrxchains == 2)
4089259453Shselasky		r2 |= 1 << 6;		/* 2R: disable Rx chain 3 */
4090203134Sthompsa
4091203134Sthompsa	/* use Tx power values from EEPROM */
4092203134Sthompsa	txpow1 = sc->txpow1[i];
4093203134Sthompsa	txpow2 = sc->txpow2[i];
4094259453Shselasky
4095259453Shselasky	/* Initialize RF R3 and R4. */
4096259453Shselasky	r3 = rfprog[i].r3 & 0xffffc1ff;
4097259453Shselasky	r4 = (rfprog[i].r4 & ~(0x001f87c0)) | (sc->freq << 15);
4098203134Sthompsa	if (chan > 14) {
4099259453Shselasky		if (txpow1 >= 0) {
4100259453Shselasky			txpow1 = (txpow1 > 0xf) ? (0xf) : (txpow1);
4101259453Shselasky			r3 |= (txpow1 << 10) | (1 << 9);
4102259453Shselasky		} else {
4103259453Shselasky			txpow1 += 7;
4104259453Shselasky
4105259453Shselasky			/* txpow1 is not possible larger than 15. */
4106259453Shselasky			r3 |= (txpow1 << 10);
4107259453Shselasky		}
4108259453Shselasky		if (txpow2 >= 0) {
4109259453Shselasky			txpow2 = (txpow2 > 0xf) ? (0xf) : (txpow2);
4110259453Shselasky			r4 |= (txpow2 << 7) | (1 << 6);
4111259453Shselasky		} else {
4112259453Shselasky			txpow2 += 7;
4113259453Shselasky			r4 |= (txpow2 << 7);
4114259453Shselasky		}
4115259453Shselasky	} else {
4116259453Shselasky		/* Set Tx0 power. */
4117259453Shselasky		r3 |= (txpow1 << 9);
4118259453Shselasky
4119259453Shselasky		/* Set frequency offset and Tx1 power. */
4120259453Shselasky		r4 |= (txpow2 << 6);
4121203134Sthompsa	}
4122203134Sthompsa
4123259453Shselasky	run_rt2870_rf_write(sc, rfprog[i].r1);
4124259453Shselasky	run_rt2870_rf_write(sc, r2);
4125259453Shselasky	run_rt2870_rf_write(sc, r3 & ~(1 << 2));
4126259453Shselasky	run_rt2870_rf_write(sc, r4);
4127203134Sthompsa
4128203134Sthompsa	run_delay(sc, 10);
4129203134Sthompsa
4130259453Shselasky	run_rt2870_rf_write(sc, rfprog[i].r1);
4131259453Shselasky	run_rt2870_rf_write(sc, r2);
4132259453Shselasky	run_rt2870_rf_write(sc, r3 | (1 << 2));
4133259453Shselasky	run_rt2870_rf_write(sc, r4);
4134203134Sthompsa
4135203134Sthompsa	run_delay(sc, 10);
4136203134Sthompsa
4137259453Shselasky	run_rt2870_rf_write(sc, rfprog[i].r1);
4138259453Shselasky	run_rt2870_rf_write(sc, r2);
4139259453Shselasky	run_rt2870_rf_write(sc, r3 & ~(1 << 2));
4140259453Shselasky	run_rt2870_rf_write(sc, r4);
4141203134Sthompsa}
4142203134Sthompsa
4143203134Sthompsastatic void
4144259453Shselaskyrun_rt3070_set_chan(struct run_softc *sc, u_int chan)
4145203134Sthompsa{
4146203134Sthompsa	int8_t txpow1, txpow2;
4147203134Sthompsa	uint8_t rf;
4148205042Sthompsa	int i;
4149203134Sthompsa
4150205042Sthompsa	/* find the settings for this channel (we know it exists) */
4151205042Sthompsa	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4152205042Sthompsa
4153203134Sthompsa	/* use Tx power values from EEPROM */
4154205042Sthompsa	txpow1 = sc->txpow1[i];
4155205042Sthompsa	txpow2 = sc->txpow2[i];
4156203134Sthompsa
4157205042Sthompsa	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
4158259453Shselasky
4159259453Shselasky	/* RT3370/RT3390: RF R3 [7:4] is not reserved bits. */
4160259453Shselasky	run_rt3070_rf_read(sc, 3, &rf);
4161259453Shselasky	rf = (rf & ~0x0f) | rt3070_freqs[i].k;
4162259453Shselasky	run_rt3070_rf_write(sc, 3, rf);
4163259453Shselasky
4164203134Sthompsa	run_rt3070_rf_read(sc, 6, &rf);
4165205042Sthompsa	rf = (rf & ~0x03) | rt3070_freqs[i].r;
4166203134Sthompsa	run_rt3070_rf_write(sc, 6, rf);
4167203134Sthompsa
4168203134Sthompsa	/* set Tx0 power */
4169203134Sthompsa	run_rt3070_rf_read(sc, 12, &rf);
4170203134Sthompsa	rf = (rf & ~0x1f) | txpow1;
4171203134Sthompsa	run_rt3070_rf_write(sc, 12, rf);
4172203134Sthompsa
4173203134Sthompsa	/* set Tx1 power */
4174203134Sthompsa	run_rt3070_rf_read(sc, 13, &rf);
4175203134Sthompsa	rf = (rf & ~0x1f) | txpow2;
4176203134Sthompsa	run_rt3070_rf_write(sc, 13, rf);
4177203134Sthompsa
4178203134Sthompsa	run_rt3070_rf_read(sc, 1, &rf);
4179203134Sthompsa	rf &= ~0xfc;
4180203134Sthompsa	if (sc->ntxchains == 1)
4181203134Sthompsa		rf |= 1 << 7 | 1 << 5;	/* 1T: disable Tx chains 2 & 3 */
4182203134Sthompsa	else if (sc->ntxchains == 2)
4183203134Sthompsa		rf |= 1 << 7;		/* 2T: disable Tx chain 3 */
4184203134Sthompsa	if (sc->nrxchains == 1)
4185203134Sthompsa		rf |= 1 << 6 | 1 << 4;	/* 1R: disable Rx chains 2 & 3 */
4186203134Sthompsa	else if (sc->nrxchains == 2)
4187203134Sthompsa		rf |= 1 << 6;		/* 2R: disable Rx chain 3 */
4188203134Sthompsa	run_rt3070_rf_write(sc, 1, rf);
4189203134Sthompsa
4190203134Sthompsa	/* set RF offset */
4191203134Sthompsa	run_rt3070_rf_read(sc, 23, &rf);
4192203134Sthompsa	rf = (rf & ~0x7f) | sc->freq;
4193203134Sthompsa	run_rt3070_rf_write(sc, 23, rf);
4194203134Sthompsa
4195203134Sthompsa	/* program RF filter */
4196205042Sthompsa	run_rt3070_rf_read(sc, 24, &rf);	/* Tx */
4197205042Sthompsa	rf = (rf & ~0x3f) | sc->rf24_20mhz;
4198205042Sthompsa	run_rt3070_rf_write(sc, 24, rf);
4199205042Sthompsa	run_rt3070_rf_read(sc, 31, &rf);	/* Rx */
4200205042Sthompsa	rf = (rf & ~0x3f) | sc->rf24_20mhz;
4201205042Sthompsa	run_rt3070_rf_write(sc, 31, rf);
4202203134Sthompsa
4203203134Sthompsa	/* enable RF tuning */
4204203134Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4205203134Sthompsa	run_rt3070_rf_write(sc, 7, rf | 0x01);
4206203134Sthompsa}
4207203134Sthompsa
4208203134Sthompsastatic void
4209205042Sthompsarun_rt3572_set_chan(struct run_softc *sc, u_int chan)
4210205042Sthompsa{
4211205042Sthompsa	int8_t txpow1, txpow2;
4212205042Sthompsa	uint32_t tmp;
4213205042Sthompsa	uint8_t rf;
4214205042Sthompsa	int i;
4215205042Sthompsa
4216205042Sthompsa	/* find the settings for this channel (we know it exists) */
4217205042Sthompsa	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4218205042Sthompsa
4219205042Sthompsa	/* use Tx power values from EEPROM */
4220205042Sthompsa	txpow1 = sc->txpow1[i];
4221205042Sthompsa	txpow2 = sc->txpow2[i];
4222205042Sthompsa
4223205042Sthompsa	if (chan <= 14) {
4224205042Sthompsa		run_bbp_write(sc, 25, sc->bbp25);
4225205042Sthompsa		run_bbp_write(sc, 26, sc->bbp26);
4226205042Sthompsa	} else {
4227205042Sthompsa		/* enable IQ phase correction */
4228205042Sthompsa		run_bbp_write(sc, 25, 0x09);
4229205042Sthompsa		run_bbp_write(sc, 26, 0xff);
4230205042Sthompsa	}
4231205042Sthompsa
4232205042Sthompsa	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
4233205042Sthompsa	run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k);
4234205042Sthompsa	run_rt3070_rf_read(sc, 6, &rf);
4235205042Sthompsa	rf  = (rf & ~0x0f) | rt3070_freqs[i].r;
4236205042Sthompsa	rf |= (chan <= 14) ? 0x08 : 0x04;
4237205042Sthompsa	run_rt3070_rf_write(sc, 6, rf);
4238205042Sthompsa
4239205042Sthompsa	/* set PLL mode */
4240205042Sthompsa	run_rt3070_rf_read(sc, 5, &rf);
4241205042Sthompsa	rf &= ~(0x08 | 0x04);
4242205042Sthompsa	rf |= (chan <= 14) ? 0x04 : 0x08;
4243205042Sthompsa	run_rt3070_rf_write(sc, 5, rf);
4244205042Sthompsa
4245205042Sthompsa	/* set Tx power for chain 0 */
4246205042Sthompsa	if (chan <= 14)
4247205042Sthompsa		rf = 0x60 | txpow1;
4248205042Sthompsa	else
4249205042Sthompsa		rf = 0xe0 | (txpow1 & 0xc) << 1 | (txpow1 & 0x3);
4250205042Sthompsa	run_rt3070_rf_write(sc, 12, rf);
4251205042Sthompsa
4252205042Sthompsa	/* set Tx power for chain 1 */
4253205042Sthompsa	if (chan <= 14)
4254205042Sthompsa		rf = 0x60 | txpow2;
4255205042Sthompsa	else
4256205042Sthompsa		rf = 0xe0 | (txpow2 & 0xc) << 1 | (txpow2 & 0x3);
4257205042Sthompsa	run_rt3070_rf_write(sc, 13, rf);
4258205042Sthompsa
4259205042Sthompsa	/* set Tx/Rx streams */
4260205042Sthompsa	run_rt3070_rf_read(sc, 1, &rf);
4261205042Sthompsa	rf &= ~0xfc;
4262205042Sthompsa	if (sc->ntxchains == 1)
4263205042Sthompsa		rf |= 1 << 7 | 1 << 5;  /* 1T: disable Tx chains 2 & 3 */
4264205042Sthompsa	else if (sc->ntxchains == 2)
4265205042Sthompsa		rf |= 1 << 7;           /* 2T: disable Tx chain 3 */
4266205042Sthompsa	if (sc->nrxchains == 1)
4267205042Sthompsa		rf |= 1 << 6 | 1 << 4;  /* 1R: disable Rx chains 2 & 3 */
4268205042Sthompsa	else if (sc->nrxchains == 2)
4269205042Sthompsa		rf |= 1 << 6;           /* 2R: disable Rx chain 3 */
4270205042Sthompsa	run_rt3070_rf_write(sc, 1, rf);
4271205042Sthompsa
4272205042Sthompsa	/* set RF offset */
4273205042Sthompsa	run_rt3070_rf_read(sc, 23, &rf);
4274205042Sthompsa	rf = (rf & ~0x7f) | sc->freq;
4275205042Sthompsa	run_rt3070_rf_write(sc, 23, rf);
4276205042Sthompsa
4277205042Sthompsa	/* program RF filter */
4278205042Sthompsa	rf = sc->rf24_20mhz;
4279205042Sthompsa	run_rt3070_rf_write(sc, 24, rf);	/* Tx */
4280205042Sthompsa	run_rt3070_rf_write(sc, 31, rf);	/* Rx */
4281205042Sthompsa
4282205042Sthompsa	/* enable RF tuning */
4283205042Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4284205042Sthompsa	rf = (chan <= 14) ? 0xd8 : ((rf & ~0xc8) | 0x14);
4285205042Sthompsa	run_rt3070_rf_write(sc, 7, rf);
4286205042Sthompsa
4287205042Sthompsa	/* TSSI */
4288205042Sthompsa	rf = (chan <= 14) ? 0xc3 : 0xc0;
4289205042Sthompsa	run_rt3070_rf_write(sc, 9, rf);
4290205042Sthompsa
4291205042Sthompsa	/* set loop filter 1 */
4292205042Sthompsa	run_rt3070_rf_write(sc, 10, 0xf1);
4293205042Sthompsa	/* set loop filter 2 */
4294205042Sthompsa	run_rt3070_rf_write(sc, 11, (chan <= 14) ? 0xb9 : 0x00);
4295205042Sthompsa
4296205042Sthompsa	/* set tx_mx2_ic */
4297205042Sthompsa	run_rt3070_rf_write(sc, 15, (chan <= 14) ? 0x53 : 0x43);
4298205042Sthompsa	/* set tx_mx1_ic */
4299205042Sthompsa	if (chan <= 14)
4300205042Sthompsa		rf = 0x48 | sc->txmixgain_2ghz;
4301205042Sthompsa	else
4302205042Sthompsa		rf = 0x78 | sc->txmixgain_5ghz;
4303205042Sthompsa	run_rt3070_rf_write(sc, 16, rf);
4304205042Sthompsa
4305205042Sthompsa	/* set tx_lo1 */
4306205042Sthompsa	run_rt3070_rf_write(sc, 17, 0x23);
4307205042Sthompsa	/* set tx_lo2 */
4308205042Sthompsa	if (chan <= 14)
4309205042Sthompsa		rf = 0x93;
4310205042Sthompsa	else if (chan <= 64)
4311205042Sthompsa		rf = 0xb7;
4312205042Sthompsa	else if (chan <= 128)
4313205042Sthompsa		rf = 0x74;
4314205042Sthompsa	else
4315205042Sthompsa		rf = 0x72;
4316205042Sthompsa	run_rt3070_rf_write(sc, 19, rf);
4317205042Sthompsa
4318205042Sthompsa	/* set rx_lo1 */
4319205042Sthompsa	if (chan <= 14)
4320205042Sthompsa		rf = 0xb3;
4321205042Sthompsa	else if (chan <= 64)
4322205042Sthompsa		rf = 0xf6;
4323205042Sthompsa	else if (chan <= 128)
4324205042Sthompsa		rf = 0xf4;
4325205042Sthompsa	else
4326205042Sthompsa		rf = 0xf3;
4327205042Sthompsa	run_rt3070_rf_write(sc, 20, rf);
4328205042Sthompsa
4329205042Sthompsa	/* set pfd_delay */
4330205042Sthompsa	if (chan <= 14)
4331205042Sthompsa		rf = 0x15;
4332205042Sthompsa	else if (chan <= 64)
4333205042Sthompsa		rf = 0x3d;
4334205042Sthompsa	else
4335205042Sthompsa		rf = 0x01;
4336205042Sthompsa	run_rt3070_rf_write(sc, 25, rf);
4337205042Sthompsa
4338205042Sthompsa	/* set rx_lo2 */
4339205042Sthompsa	run_rt3070_rf_write(sc, 26, (chan <= 14) ? 0x85 : 0x87);
4340205042Sthompsa	/* set ldo_rf_vc */
4341205042Sthompsa	run_rt3070_rf_write(sc, 27, (chan <= 14) ? 0x00 : 0x01);
4342205042Sthompsa	/* set drv_cc */
4343205042Sthompsa	run_rt3070_rf_write(sc, 29, (chan <= 14) ? 0x9b : 0x9f);
4344205042Sthompsa
4345205042Sthompsa	run_read(sc, RT2860_GPIO_CTRL, &tmp);
4346205042Sthompsa	tmp &= ~0x8080;
4347205042Sthompsa	if (chan <= 14)
4348205042Sthompsa		tmp |= 0x80;
4349205042Sthompsa	run_write(sc, RT2860_GPIO_CTRL, tmp);
4350205042Sthompsa
4351205042Sthompsa	/* enable RF tuning */
4352205042Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4353205042Sthompsa	run_rt3070_rf_write(sc, 7, rf | 0x01);
4354205042Sthompsa
4355205042Sthompsa	run_delay(sc, 2);
4356205042Sthompsa}
4357205042Sthompsa
4358205042Sthompsastatic void
4359261868Skevlorun_rt3593_set_chan(struct run_softc *sc, u_int chan)
4360261868Skevlo{
4361261868Skevlo	int8_t txpow1, txpow2, txpow3;
4362261868Skevlo	uint8_t h20mhz, rf;
4363261868Skevlo	int i;
4364261868Skevlo
4365261868Skevlo	/* find the settings for this channel (we know it exists) */
4366261868Skevlo	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4367261868Skevlo
4368261868Skevlo	/* use Tx power values from EEPROM */
4369261868Skevlo	txpow1 = sc->txpow1[i];
4370261868Skevlo	txpow2 = sc->txpow2[i];
4371261868Skevlo	txpow3 = (sc->ntxchains == 3) ? sc->txpow3[i] : 0;
4372261868Skevlo
4373261868Skevlo	if (chan <= 14) {
4374261868Skevlo		run_bbp_write(sc, 25, sc->bbp25);
4375261868Skevlo		run_bbp_write(sc, 26, sc->bbp26);
4376261868Skevlo	} else {
4377261868Skevlo		/* Enable IQ phase correction. */
4378261868Skevlo		run_bbp_write(sc, 25, 0x09);
4379261868Skevlo		run_bbp_write(sc, 26, 0xff);
4380261868Skevlo	}
4381261868Skevlo
4382261868Skevlo	run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n);
4383261868Skevlo	run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f);
4384261868Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4385261868Skevlo	rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03);
4386261868Skevlo	run_rt3070_rf_write(sc, 11, rf);
4387261868Skevlo
4388261868Skevlo	/* Set pll_idoh. */
4389261868Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4390261868Skevlo	rf &= ~0x4c;
4391261868Skevlo	rf |= (chan <= 14) ? 0x44 : 0x48;
4392261868Skevlo	run_rt3070_rf_write(sc, 11, rf);
4393261868Skevlo
4394261868Skevlo	if (chan <= 14)
4395261868Skevlo		rf = txpow1 & 0x1f;
4396261868Skevlo	else
4397261868Skevlo		rf = 0x40 | ((txpow1 & 0x18) << 1) | (txpow1 & 0x07);
4398261868Skevlo	run_rt3070_rf_write(sc, 53, rf);
4399261868Skevlo
4400261868Skevlo	if (chan <= 14)
4401261868Skevlo		rf = txpow2 & 0x1f;
4402261868Skevlo	else
4403261868Skevlo		rf = 0x40 | ((txpow2 & 0x18) << 1) | (txpow2 & 0x07);
4404261868Skevlo	run_rt3070_rf_write(sc, 55, rf);
4405261868Skevlo
4406261868Skevlo	if (chan <= 14)
4407261868Skevlo		rf = txpow3 & 0x1f;
4408261868Skevlo	else
4409261868Skevlo		rf = 0x40 | ((txpow3 & 0x18) << 1) | (txpow3 & 0x07);
4410261868Skevlo	run_rt3070_rf_write(sc, 54, rf);
4411261868Skevlo
4412261868Skevlo	rf = RT3070_RF_BLOCK | RT3070_PLL_PD;
4413261868Skevlo	if (sc->ntxchains == 3)
4414261868Skevlo		rf |= RT3070_TX0_PD | RT3070_TX1_PD | RT3070_TX2_PD;
4415261868Skevlo	else
4416261868Skevlo		rf |= RT3070_TX0_PD | RT3070_TX1_PD;
4417261868Skevlo	rf |= RT3070_RX0_PD | RT3070_RX1_PD | RT3070_RX2_PD;
4418261868Skevlo	run_rt3070_rf_write(sc, 1, rf);
4419261868Skevlo
4420261868Skevlo	run_adjust_freq_offset(sc);
4421261868Skevlo
4422261868Skevlo	run_rt3070_rf_write(sc, 31, (chan <= 14) ? 0xa0 : 0x80);
4423261868Skevlo
4424261868Skevlo	h20mhz = (sc->rf24_20mhz & 0x20) >> 5;
4425261868Skevlo	run_rt3070_rf_read(sc, 30, &rf);
4426261868Skevlo	rf = (rf & ~0x06) | (h20mhz << 1) | (h20mhz << 2);
4427261868Skevlo	run_rt3070_rf_write(sc, 30, rf);
4428261868Skevlo
4429261868Skevlo	run_rt3070_rf_read(sc, 36, &rf);
4430261868Skevlo	if (chan <= 14)
4431261868Skevlo		rf |= 0x80;
4432261868Skevlo	else
4433261868Skevlo		rf &= ~0x80;
4434261868Skevlo	run_rt3070_rf_write(sc, 36, rf);
4435261868Skevlo
4436261868Skevlo	/* Set vcolo_bs. */
4437261868Skevlo	run_rt3070_rf_write(sc, 34, (chan <= 14) ? 0x3c : 0x20);
4438261868Skevlo	/* Set pfd_delay. */
4439261868Skevlo	run_rt3070_rf_write(sc, 12, (chan <= 14) ? 0x1a : 0x12);
4440261868Skevlo
4441261868Skevlo	/* Set vco bias current control. */
4442261868Skevlo	run_rt3070_rf_read(sc, 6, &rf);
4443261868Skevlo	rf &= ~0xc0;
4444261868Skevlo	if (chan <= 14)
4445261868Skevlo		rf |= 0x40;
4446261868Skevlo	else if (chan <= 128)
4447261868Skevlo		rf |= 0x80;
4448261868Skevlo	else
4449261868Skevlo		rf |= 0x40;
4450261868Skevlo	run_rt3070_rf_write(sc, 6, rf);
4451261868Skevlo
4452261868Skevlo	run_rt3070_rf_read(sc, 30, &rf);
4453261868Skevlo	rf = (rf & ~0x18) | 0x10;
4454261868Skevlo	run_rt3070_rf_write(sc, 30, rf);
4455261868Skevlo
4456261868Skevlo	run_rt3070_rf_write(sc, 10, (chan <= 14) ? 0xd3 : 0xd8);
4457261868Skevlo	run_rt3070_rf_write(sc, 13, (chan <= 14) ? 0x12 : 0x23);
4458261868Skevlo
4459261868Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4460261868Skevlo	rf = (rf & ~0x03) | 0x01;
4461261868Skevlo	run_rt3070_rf_write(sc, 51, rf);
4462261868Skevlo	/* Set tx_mx1_cc. */
4463261868Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4464261868Skevlo	rf &= ~0x1c;
4465261868Skevlo	rf |= (chan <= 14) ? 0x14 : 0x10;
4466261868Skevlo	run_rt3070_rf_write(sc, 51, rf);
4467261868Skevlo	/* Set tx_mx1_ic. */
4468261868Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4469261868Skevlo	rf &= ~0xe0;
4470261868Skevlo	rf |= (chan <= 14) ? 0x60 : 0x40;
4471261868Skevlo	run_rt3070_rf_write(sc, 51, rf);
4472261868Skevlo	/* Set tx_lo1_ic. */
4473261868Skevlo	run_rt3070_rf_read(sc, 49, &rf);
4474261868Skevlo	rf &= ~0x1c;
4475261868Skevlo	rf |= (chan <= 14) ? 0x0c : 0x08;
4476261868Skevlo	run_rt3070_rf_write(sc, 49, rf);
4477261868Skevlo	/* Set tx_lo1_en. */
4478261868Skevlo	run_rt3070_rf_read(sc, 50, &rf);
4479261868Skevlo	run_rt3070_rf_write(sc, 50, rf & ~0x20);
4480261868Skevlo	/* Set drv_cc. */
4481261868Skevlo	run_rt3070_rf_read(sc, 57, &rf);
4482261868Skevlo	rf &= ~0xfc;
4483261868Skevlo	rf |= (chan <= 14) ?  0x6c : 0x3c;
4484261868Skevlo	run_rt3070_rf_write(sc, 57, rf);
4485261868Skevlo	/* Set rx_mix1_ic, rxa_lnactr, lna_vc, lna_inbias_en and lna_en. */
4486261868Skevlo	run_rt3070_rf_write(sc, 44, (chan <= 14) ? 0x93 : 0x9b);
4487261868Skevlo	/* Set drv_gnd_a, tx_vga_cc_a and tx_mx2_gain. */
4488261868Skevlo	run_rt3070_rf_write(sc, 52, (chan <= 14) ? 0x45 : 0x05);
4489261868Skevlo	/* Enable VCO calibration. */
4490261868Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4491261868Skevlo	rf &= ~RT5390_VCOCAL;
4492261868Skevlo	rf |= (chan <= 14) ? RT5390_VCOCAL : 0xbe;
4493261868Skevlo	run_rt3070_rf_write(sc, 3, rf);
4494261868Skevlo
4495261868Skevlo	if (chan <= 14)
4496261868Skevlo		rf = 0x23;
4497261868Skevlo	else if (chan <= 64)
4498261868Skevlo		rf = 0x36;
4499261868Skevlo	else if (chan <= 128)
4500261868Skevlo		rf = 0x32;
4501261868Skevlo	else
4502261868Skevlo		rf = 0x30;
4503261868Skevlo	run_rt3070_rf_write(sc, 39, rf);
4504261868Skevlo	if (chan <= 14)
4505261868Skevlo		rf = 0xbb;
4506261868Skevlo	else if (chan <= 64)
4507261868Skevlo		rf = 0xeb;
4508261868Skevlo	else if (chan <= 128)
4509261868Skevlo		rf = 0xb3;
4510261868Skevlo	else
4511261868Skevlo		rf = 0x9b;
4512261868Skevlo	run_rt3070_rf_write(sc, 45, rf);
4513261868Skevlo
4514261868Skevlo	/* Set FEQ/AEQ control. */
4515261868Skevlo	run_bbp_write(sc, 105, 0x34);
4516261868Skevlo}
4517261868Skevlo
4518261868Skevlostatic void
4519259453Shselaskyrun_rt5390_set_chan(struct run_softc *sc, u_int chan)
4520259453Shselasky{
4521259453Shselasky	int8_t txpow1, txpow2;
4522259453Shselasky	uint8_t rf;
4523259453Shselasky	int i;
4524259453Shselasky
4525259453Shselasky	/* find the settings for this channel (we know it exists) */
4526259453Shselasky	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4527259453Shselasky
4528259453Shselasky	/* use Tx power values from EEPROM */
4529259453Shselasky	txpow1 = sc->txpow1[i];
4530259453Shselasky	txpow2 = sc->txpow2[i];
4531259453Shselasky
4532259453Shselasky	run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n);
4533259453Shselasky	run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f);
4534259453Shselasky	run_rt3070_rf_read(sc, 11, &rf);
4535259453Shselasky	rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03);
4536259453Shselasky	run_rt3070_rf_write(sc, 11, rf);
4537259453Shselasky
4538259453Shselasky	run_rt3070_rf_read(sc, 49, &rf);
4539259453Shselasky	rf = (rf & ~0x3f) | (txpow1 & 0x3f);
4540259453Shselasky	/* The valid range of the RF R49 is 0x00 to 0x27. */
4541259453Shselasky	if ((rf & 0x3f) > 0x27)
4542259453Shselasky		rf = (rf & ~0x3f) | 0x27;
4543259453Shselasky	run_rt3070_rf_write(sc, 49, rf);
4544259453Shselasky
4545259453Shselasky	if (sc->mac_ver == 0x5392) {
4546259453Shselasky		run_rt3070_rf_read(sc, 50, &rf);
4547259453Shselasky		rf = (rf & ~0x3f) | (txpow2 & 0x3f);
4548259453Shselasky		/* The valid range of the RF R50 is 0x00 to 0x27. */
4549259453Shselasky		if ((rf & 0x3f) > 0x27)
4550259453Shselasky			rf = (rf & ~0x3f) | 0x27;
4551259453Shselasky		run_rt3070_rf_write(sc, 50, rf);
4552259453Shselasky	}
4553259453Shselasky
4554259453Shselasky	run_rt3070_rf_read(sc, 1, &rf);
4555259453Shselasky	rf |= RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD;
4556259453Shselasky	if (sc->mac_ver == 0x5392)
4557259453Shselasky		rf |= RT3070_RX1_PD | RT3070_TX1_PD;
4558259453Shselasky	run_rt3070_rf_write(sc, 1, rf);
4559259453Shselasky
4560259453Shselasky	if (sc->mac_ver != 0x5392) {
4561259453Shselasky		run_rt3070_rf_read(sc, 2, &rf);
4562259453Shselasky		rf |= 0x80;
4563259453Shselasky		run_rt3070_rf_write(sc, 2, rf);
4564259453Shselasky		run_delay(sc, 10);
4565259453Shselasky		rf &= 0x7f;
4566259453Shselasky		run_rt3070_rf_write(sc, 2, rf);
4567259453Shselasky	}
4568259453Shselasky
4569259453Shselasky	run_adjust_freq_offset(sc);
4570259453Shselasky
4571259453Shselasky	if (sc->mac_ver == 0x5392) {
4572259453Shselasky		/* Fix for RT5392C. */
4573259453Shselasky		if (sc->mac_rev >= 0x0223) {
4574259453Shselasky			if (chan <= 4)
4575259453Shselasky				rf = 0x0f;
4576259453Shselasky			else if (chan >= 5 && chan <= 7)
4577259453Shselasky				rf = 0x0e;
4578259453Shselasky			else
4579259453Shselasky				rf = 0x0d;
4580259453Shselasky			run_rt3070_rf_write(sc, 23, rf);
4581259453Shselasky
4582259453Shselasky			if (chan <= 4)
4583259453Shselasky				rf = 0x0c;
4584259453Shselasky			else if (chan == 5)
4585259453Shselasky				rf = 0x0b;
4586259453Shselasky			else if (chan >= 6 && chan <= 7)
4587259453Shselasky				rf = 0x0a;
4588259453Shselasky			else if (chan >= 8 && chan <= 10)
4589259453Shselasky				rf = 0x09;
4590259453Shselasky			else
4591259453Shselasky				rf = 0x08;
4592259453Shselasky			run_rt3070_rf_write(sc, 59, rf);
4593259453Shselasky		} else {
4594259453Shselasky			if (chan <= 11)
4595259453Shselasky				rf = 0x0f;
4596259453Shselasky			else
4597259453Shselasky				rf = 0x0b;
4598259453Shselasky			run_rt3070_rf_write(sc, 59, rf);
4599259453Shselasky		}
4600259453Shselasky	} else {
4601259453Shselasky		/* Fix for RT5390F. */
4602259453Shselasky		if (sc->mac_rev >= 0x0502) {
4603259453Shselasky			if (chan <= 11)
4604259453Shselasky				rf = 0x43;
4605259453Shselasky			else
4606259453Shselasky				rf = 0x23;
4607259453Shselasky			run_rt3070_rf_write(sc, 55, rf);
4608259453Shselasky
4609259453Shselasky			if (chan <= 11)
4610259453Shselasky				rf = 0x0f;
4611259453Shselasky			else if (chan == 12)
4612259453Shselasky				rf = 0x0d;
4613259453Shselasky			else
4614259453Shselasky				rf = 0x0b;
4615259453Shselasky			run_rt3070_rf_write(sc, 59, rf);
4616259453Shselasky		} else {
4617259453Shselasky			run_rt3070_rf_write(sc, 55, 0x44);
4618259453Shselasky			run_rt3070_rf_write(sc, 59, 0x8f);
4619259453Shselasky		}
4620259453Shselasky	}
4621259453Shselasky
4622259453Shselasky	/* Enable VCO calibration. */
4623259453Shselasky	run_rt3070_rf_read(sc, 3, &rf);
4624259453Shselasky	rf |= RT5390_VCOCAL;
4625259453Shselasky	run_rt3070_rf_write(sc, 3, rf);
4626259453Shselasky}
4627259453Shselasky
4628259453Shselaskystatic void
4629259453Shselaskyrun_rt5592_set_chan(struct run_softc *sc, u_int chan)
4630259453Shselasky{
4631259453Shselasky	const struct rt5592_freqs *freqs;
4632259453Shselasky	uint32_t tmp;
4633259453Shselasky	uint8_t reg, rf, txpow_bound;
4634259453Shselasky	int8_t txpow1, txpow2;
4635259453Shselasky	int i;
4636259453Shselasky
4637259453Shselasky	run_read(sc, RT5592_DEBUG_INDEX, &tmp);
4638259453Shselasky	freqs = (tmp & RT5592_SEL_XTAL) ?
4639259453Shselasky	    rt5592_freqs_40mhz : rt5592_freqs_20mhz;
4640259453Shselasky
4641259453Shselasky	/* find the settings for this channel (we know it exists) */
4642259453Shselasky	for (i = 0; rt2860_rf2850[i].chan != chan; i++, freqs++);
4643259453Shselasky
4644259453Shselasky	/* use Tx power values from EEPROM */
4645259453Shselasky	txpow1 = sc->txpow1[i];
4646259453Shselasky	txpow2 = sc->txpow2[i];
4647259453Shselasky
4648259453Shselasky	run_read(sc, RT3070_LDO_CFG0, &tmp);
4649259453Shselasky	tmp &= ~0x1c000000;
4650259453Shselasky	if (chan > 14)
4651259453Shselasky		tmp |= 0x14000000;
4652259453Shselasky	run_write(sc, RT3070_LDO_CFG0, tmp);
4653259453Shselasky
4654259453Shselasky	/* N setting. */
4655259453Shselasky	run_rt3070_rf_write(sc, 8, freqs->n & 0xff);
4656259453Shselasky	run_rt3070_rf_read(sc, 9, &rf);
4657259453Shselasky	rf &= ~(1 << 4);
4658259453Shselasky	rf |= ((freqs->n & 0x0100) >> 8) << 4;
4659259453Shselasky	run_rt3070_rf_write(sc, 9, rf);
4660259453Shselasky
4661259453Shselasky	/* K setting. */
4662259453Shselasky	run_rt3070_rf_read(sc, 9, &rf);
4663259453Shselasky	rf &= ~0x0f;
4664259453Shselasky	rf |= (freqs->k & 0x0f);
4665259453Shselasky	run_rt3070_rf_write(sc, 9, rf);
4666259453Shselasky
4667259453Shselasky	/* Mode setting. */
4668259453Shselasky	run_rt3070_rf_read(sc, 11, &rf);
4669259453Shselasky	rf &= ~0x0c;
4670259453Shselasky	rf |= ((freqs->m - 0x8) & 0x3) << 2;
4671259453Shselasky	run_rt3070_rf_write(sc, 11, rf);
4672259453Shselasky	run_rt3070_rf_read(sc, 9, &rf);
4673259453Shselasky	rf &= ~(1 << 7);
4674259453Shselasky	rf |= (((freqs->m - 0x8) & 0x4) >> 2) << 7;
4675259453Shselasky	run_rt3070_rf_write(sc, 9, rf);
4676259453Shselasky
4677259453Shselasky	/* R setting. */
4678259453Shselasky	run_rt3070_rf_read(sc, 11, &rf);
4679259453Shselasky	rf &= ~0x03;
4680259453Shselasky	rf |= (freqs->r - 0x1);
4681259453Shselasky	run_rt3070_rf_write(sc, 11, rf);
4682259453Shselasky
4683259453Shselasky	if (chan <= 14) {
4684259453Shselasky		/* Initialize RF registers for 2GHZ. */
4685259453Shselasky		for (i = 0; i < nitems(rt5592_2ghz_def_rf); i++) {
4686259453Shselasky			run_rt3070_rf_write(sc, rt5592_2ghz_def_rf[i].reg,
4687259453Shselasky			    rt5592_2ghz_def_rf[i].val);
4688259453Shselasky		}
4689259453Shselasky
4690259453Shselasky		rf = (chan <= 10) ? 0x07 : 0x06;
4691259453Shselasky		run_rt3070_rf_write(sc, 23, rf);
4692259453Shselasky		run_rt3070_rf_write(sc, 59, rf);
4693259453Shselasky
4694259453Shselasky		run_rt3070_rf_write(sc, 55, 0x43);
4695259453Shselasky
4696259453Shselasky		/*
4697259453Shselasky		 * RF R49/R50 Tx power ALC code.
4698259453Shselasky		 * G-band bit<7:6>=1:0, bit<5:0> range from 0x0 ~ 0x27.
4699259453Shselasky		 */
4700259453Shselasky		reg = 2;
4701259453Shselasky		txpow_bound = 0x27;
4702259453Shselasky	} else {
4703259453Shselasky		/* Initialize RF registers for 5GHZ. */
4704259453Shselasky		for (i = 0; i < nitems(rt5592_5ghz_def_rf); i++) {
4705259453Shselasky			run_rt3070_rf_write(sc, rt5592_5ghz_def_rf[i].reg,
4706259453Shselasky			    rt5592_5ghz_def_rf[i].val);
4707259453Shselasky		}
4708259453Shselasky		for (i = 0; i < nitems(rt5592_chan_5ghz); i++) {
4709259453Shselasky			if (chan >= rt5592_chan_5ghz[i].firstchan &&
4710259453Shselasky			    chan <= rt5592_chan_5ghz[i].lastchan) {
4711259453Shselasky				run_rt3070_rf_write(sc, rt5592_chan_5ghz[i].reg,
4712259453Shselasky				    rt5592_chan_5ghz[i].val);
4713259453Shselasky			}
4714259453Shselasky		}
4715259453Shselasky
4716259453Shselasky		/*
4717259453Shselasky		 * RF R49/R50 Tx power ALC code.
4718259453Shselasky		 * A-band bit<7:6>=1:1, bit<5:0> range from 0x0 ~ 0x2b.
4719259453Shselasky		 */
4720259453Shselasky		reg = 3;
4721259453Shselasky		txpow_bound = 0x2b;
4722259453Shselasky	}
4723259453Shselasky
4724259453Shselasky	/* RF R49 ch0 Tx power ALC code. */
4725259453Shselasky	run_rt3070_rf_read(sc, 49, &rf);
4726259453Shselasky	rf &= ~0xc0;
4727259453Shselasky	rf |= (reg << 6);
4728259453Shselasky	rf = (rf & ~0x3f) | (txpow1 & 0x3f);
4729259453Shselasky	if ((rf & 0x3f) > txpow_bound)
4730259453Shselasky		rf = (rf & ~0x3f) | txpow_bound;
4731259453Shselasky	run_rt3070_rf_write(sc, 49, rf);
4732259453Shselasky
4733259453Shselasky	/* RF R50 ch1 Tx power ALC code. */
4734259453Shselasky	run_rt3070_rf_read(sc, 50, &rf);
4735259453Shselasky	rf &= ~(1 << 7 | 1 << 6);
4736259453Shselasky	rf |= (reg << 6);
4737259453Shselasky	rf = (rf & ~0x3f) | (txpow2 & 0x3f);
4738259453Shselasky	if ((rf & 0x3f) > txpow_bound)
4739259453Shselasky		rf = (rf & ~0x3f) | txpow_bound;
4740259453Shselasky	run_rt3070_rf_write(sc, 50, rf);
4741259453Shselasky
4742259453Shselasky	/* Enable RF_BLOCK, PLL_PD, RX0_PD, and TX0_PD. */
4743259453Shselasky	run_rt3070_rf_read(sc, 1, &rf);
4744259453Shselasky	rf |= (RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD);
4745259453Shselasky	if (sc->ntxchains > 1)
4746259453Shselasky		rf |= RT3070_TX1_PD;
4747259453Shselasky	if (sc->nrxchains > 1)
4748259453Shselasky		rf |= RT3070_RX1_PD;
4749259453Shselasky	run_rt3070_rf_write(sc, 1, rf);
4750259453Shselasky
4751259453Shselasky	run_rt3070_rf_write(sc, 6, 0xe4);
4752259453Shselasky
4753259453Shselasky	run_rt3070_rf_write(sc, 30, 0x10);
4754259453Shselasky	run_rt3070_rf_write(sc, 31, 0x80);
4755259453Shselasky	run_rt3070_rf_write(sc, 32, 0x80);
4756259453Shselasky
4757259453Shselasky	run_adjust_freq_offset(sc);
4758259453Shselasky
4759259453Shselasky	/* Enable VCO calibration. */
4760259453Shselasky	run_rt3070_rf_read(sc, 3, &rf);
4761259453Shselasky	rf |= RT5390_VCOCAL;
4762259453Shselasky	run_rt3070_rf_write(sc, 3, rf);
4763259453Shselasky}
4764259453Shselasky
4765259453Shselaskystatic void
4766203134Sthompsarun_set_rx_antenna(struct run_softc *sc, int aux)
4767203134Sthompsa{
4768203134Sthompsa	uint32_t tmp;
4769259453Shselasky	uint8_t bbp152;
4770203134Sthompsa
4771203134Sthompsa	if (aux) {
4772259453Shselasky		if (sc->rf_rev == RT5390_RF_5370) {
4773259453Shselasky			run_bbp_read(sc, 152, &bbp152);
4774259453Shselasky			run_bbp_write(sc, 152, bbp152 & ~0x80);
4775259453Shselasky		} else {
4776259453Shselasky			run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 0);
4777259453Shselasky			run_read(sc, RT2860_GPIO_CTRL, &tmp);
4778259453Shselasky			run_write(sc, RT2860_GPIO_CTRL, (tmp & ~0x0808) | 0x08);
4779259453Shselasky		}
4780203134Sthompsa	} else {
4781259453Shselasky		if (sc->rf_rev == RT5390_RF_5370) {
4782259453Shselasky			run_bbp_read(sc, 152, &bbp152);
4783259453Shselasky			run_bbp_write(sc, 152, bbp152 | 0x80);
4784259453Shselasky		} else {
4785259453Shselasky			run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 1);
4786259453Shselasky			run_read(sc, RT2860_GPIO_CTRL, &tmp);
4787259453Shselasky			run_write(sc, RT2860_GPIO_CTRL, tmp & ~0x0808);
4788259453Shselasky		}
4789203134Sthompsa	}
4790203134Sthompsa}
4791203134Sthompsa
4792203134Sthompsastatic int
4793203134Sthompsarun_set_chan(struct run_softc *sc, struct ieee80211_channel *c)
4794203134Sthompsa{
4795203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
4796259453Shselasky	u_int chan, group;
4797203134Sthompsa
4798203134Sthompsa	chan = ieee80211_chan2ieee(ic, c);
4799203134Sthompsa	if (chan == 0 || chan == IEEE80211_CHAN_ANY)
4800209917Sthompsa		return (EINVAL);
4801203134Sthompsa
4802259453Shselasky	if (sc->mac_ver == 0x5592)
4803259453Shselasky		run_rt5592_set_chan(sc, chan);
4804259453Shselasky	else if (sc->mac_ver >= 0x5390)
4805259453Shselasky		run_rt5390_set_chan(sc, chan);
4806261868Skevlo	else if (sc->mac_ver == 0x3593)
4807261868Skevlo		run_rt3593_set_chan(sc, chan);
4808259453Shselasky	else if (sc->mac_ver == 0x3572)
4809205042Sthompsa		run_rt3572_set_chan(sc, chan);
4810205042Sthompsa	else if (sc->mac_ver >= 0x3070)
4811203134Sthompsa		run_rt3070_set_chan(sc, chan);
4812203134Sthompsa	else
4813203134Sthompsa		run_rt2870_set_chan(sc, chan);
4814203134Sthompsa
4815203134Sthompsa	/* determine channel group */
4816203134Sthompsa	if (chan <= 14)
4817203134Sthompsa		group = 0;
4818203134Sthompsa	else if (chan <= 64)
4819203134Sthompsa		group = 1;
4820203134Sthompsa	else if (chan <= 128)
4821203134Sthompsa		group = 2;
4822203134Sthompsa	else
4823203134Sthompsa		group = 3;
4824203134Sthompsa
4825203134Sthompsa	/* XXX necessary only when group has changed! */
4826203134Sthompsa	run_select_chan_group(sc, group);
4827203134Sthompsa
4828203134Sthompsa	run_delay(sc, 10);
4829203134Sthompsa
4830261868Skevlo	/* Perform IQ calibration. */
4831261868Skevlo	if (sc->mac_ver >= 0x5392)
4832261868Skevlo		run_iq_calib(sc, chan);
4833261868Skevlo
4834209917Sthompsa	return (0);
4835203134Sthompsa}
4836203134Sthompsa
4837203134Sthompsastatic void
4838203134Sthompsarun_set_channel(struct ieee80211com *ic)
4839203134Sthompsa{
4840203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
4841203134Sthompsa
4842203134Sthompsa	RUN_LOCK(sc);
4843203134Sthompsa	run_set_chan(sc, ic->ic_curchan);
4844203134Sthompsa	RUN_UNLOCK(sc);
4845203134Sthompsa
4846203134Sthompsa	return;
4847203134Sthompsa}
4848203134Sthompsa
4849203134Sthompsastatic void
4850203134Sthompsarun_scan_start(struct ieee80211com *ic)
4851203134Sthompsa{
4852203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
4853203134Sthompsa	uint32_t tmp;
4854203134Sthompsa
4855203134Sthompsa	RUN_LOCK(sc);
4856203134Sthompsa
4857203134Sthompsa	/* abort TSF synchronization */
4858203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
4859203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG,
4860203134Sthompsa	    tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
4861203134Sthompsa	    RT2860_TBTT_TIMER_EN));
4862203134Sthompsa	run_set_bssid(sc, sc->sc_ifp->if_broadcastaddr);
4863203134Sthompsa
4864203134Sthompsa	RUN_UNLOCK(sc);
4865203134Sthompsa
4866203134Sthompsa	return;
4867203134Sthompsa}
4868203134Sthompsa
4869203134Sthompsastatic void
4870203134Sthompsarun_scan_end(struct ieee80211com *ic)
4871203134Sthompsa{
4872203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
4873203134Sthompsa
4874203134Sthompsa	RUN_LOCK(sc);
4875203134Sthompsa
4876203134Sthompsa	run_enable_tsf_sync(sc);
4877203134Sthompsa	/* XXX keep local copy */
4878203134Sthompsa	run_set_bssid(sc, sc->sc_bssid);
4879203134Sthompsa
4880203134Sthompsa	RUN_UNLOCK(sc);
4881203134Sthompsa
4882203134Sthompsa	return;
4883203134Sthompsa}
4884203134Sthompsa
4885208019Sthompsa/*
4886208019Sthompsa * Could be called from ieee80211_node_timeout()
4887208019Sthompsa * (non-sleepable thread)
4888208019Sthompsa */
4889208019Sthompsastatic void
4890208019Sthompsarun_update_beacon(struct ieee80211vap *vap, int item)
4891203134Sthompsa{
4892208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
4893208019Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
4894218492Sbschmidt	struct run_vap *rvp = RUN_VAP(vap);
4895218492Sbschmidt	int mcast = 0;
4896208019Sthompsa	uint32_t i;
4897208019Sthompsa
4898218492Sbschmidt	KASSERT(vap != NULL, ("no beacon"));
4899218492Sbschmidt
4900218492Sbschmidt	switch (item) {
4901218492Sbschmidt	case IEEE80211_BEACON_ERP:
4902218492Sbschmidt		run_updateslot(ic->ic_ifp);
4903218492Sbschmidt		break;
4904218492Sbschmidt	case IEEE80211_BEACON_HTINFO:
4905218492Sbschmidt		run_updateprot(ic);
4906218492Sbschmidt		break;
4907218492Sbschmidt	case IEEE80211_BEACON_TIM:
4908218492Sbschmidt		mcast = 1;	/*TODO*/
4909218492Sbschmidt		break;
4910218492Sbschmidt	default:
4911218492Sbschmidt		break;
4912218492Sbschmidt	}
4913218492Sbschmidt
4914218492Sbschmidt	setbit(rvp->bo.bo_flags, item);
4915273636Skevlo	if (rvp->beacon_mbuf == NULL) {
4916273636Skevlo		rvp->beacon_mbuf = ieee80211_beacon_alloc(vap->iv_bss,
4917273636Skevlo		    &rvp->bo);
4918273636Skevlo		if (rvp->beacon_mbuf == NULL)
4919273636Skevlo			return;
4920273636Skevlo	}
4921218492Sbschmidt	ieee80211_beacon_update(vap->iv_bss, &rvp->bo, rvp->beacon_mbuf, mcast);
4922218492Sbschmidt
4923208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
4924208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
4925208019Sthompsa	sc->cmdq[i].func = run_update_beacon_cb;
4926208019Sthompsa	sc->cmdq[i].arg0 = vap;
4927208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
4928208019Sthompsa
4929208019Sthompsa	return;
4930203134Sthompsa}
4931203134Sthompsa
4932203134Sthompsastatic void
4933208019Sthompsarun_update_beacon_cb(void *arg)
4934203134Sthompsa{
4935208019Sthompsa	struct ieee80211vap *vap = arg;
4936218492Sbschmidt	struct run_vap *rvp = RUN_VAP(vap);
4937203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
4938203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
4939203134Sthompsa	struct rt2860_txwi txwi;
4940203134Sthompsa	struct mbuf *m;
4941259453Shselasky	uint16_t txwisize;
4942208019Sthompsa	uint8_t ridx;
4943203134Sthompsa
4944209917Sthompsa	if (vap->iv_bss->ni_chan == IEEE80211_CHAN_ANYC)
4945208019Sthompsa		return;
4946236439Shselasky	if (ic->ic_bsschan == IEEE80211_CHAN_ANYC)
4947236439Shselasky		return;
4948208019Sthompsa
4949218492Sbschmidt	/*
4950218492Sbschmidt	 * No need to call ieee80211_beacon_update(), run_update_beacon()
4951218492Sbschmidt	 * is taking care of apropriate calls.
4952218492Sbschmidt	 */
4953218492Sbschmidt	if (rvp->beacon_mbuf == NULL) {
4954218492Sbschmidt		rvp->beacon_mbuf = ieee80211_beacon_alloc(vap->iv_bss,
4955218492Sbschmidt		    &rvp->bo);
4956218492Sbschmidt		if (rvp->beacon_mbuf == NULL)
4957218492Sbschmidt			return;
4958218492Sbschmidt	}
4959218492Sbschmidt	m = rvp->beacon_mbuf;
4960203134Sthompsa
4961259453Shselasky	memset(&txwi, 0, sizeof(txwi));
4962203134Sthompsa	txwi.wcid = 0xff;
4963203134Sthompsa	txwi.len = htole16(m->m_pkthdr.len);
4964259453Shselasky
4965203134Sthompsa	/* send beacons at the lowest available rate */
4966208019Sthompsa	ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
4967208019Sthompsa	    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
4968208019Sthompsa	txwi.phy = htole16(rt2860_rates[ridx].mcs);
4969208019Sthompsa	if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM)
4970259453Shselasky		txwi.phy |= htole16(RT2860_PHY_OFDM);
4971203134Sthompsa	txwi.txop = RT2860_TX_TXOP_HT;
4972203134Sthompsa	txwi.flags = RT2860_TX_TS;
4973209144Sthompsa	txwi.xflags = RT2860_TX_NSEQ;
4974203134Sthompsa
4975259453Shselasky	txwisize = (sc->mac_ver == 0x5592) ?
4976259453Shselasky	    sizeof(txwi) + sizeof(uint32_t) : sizeof(txwi);
4977259453Shselasky	run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id), (uint8_t *)&txwi,
4978259453Shselasky	    txwisize);
4979259453Shselasky	run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id) + txwisize,
4980259453Shselasky	    mtod(m, uint8_t *), (m->m_pkthdr.len + 1) & ~1);
4981203134Sthompsa}
4982203134Sthompsa
4983203134Sthompsastatic void
4984203134Sthompsarun_updateprot(struct ieee80211com *ic)
4985203134Sthompsa{
4986203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
4987218492Sbschmidt	uint32_t i;
4988218492Sbschmidt
4989218492Sbschmidt	i = RUN_CMDQ_GET(&sc->cmdq_store);
4990218492Sbschmidt	DPRINTF("cmdq_store=%d\n", i);
4991218492Sbschmidt	sc->cmdq[i].func = run_updateprot_cb;
4992218492Sbschmidt	sc->cmdq[i].arg0 = ic;
4993218492Sbschmidt	ieee80211_runtask(ic, &sc->cmdq_task);
4994218492Sbschmidt}
4995218492Sbschmidt
4996218492Sbschmidtstatic void
4997218492Sbschmidtrun_updateprot_cb(void *arg)
4998218492Sbschmidt{
4999218492Sbschmidt	struct ieee80211com *ic = arg;
5000218492Sbschmidt	struct run_softc *sc = ic->ic_ifp->if_softc;
5001203134Sthompsa	uint32_t tmp;
5002203134Sthompsa
5003203134Sthompsa	tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL;
5004203134Sthompsa	/* setup protection frame rate (MCS code) */
5005203134Sthompsa	tmp |= (ic->ic_curmode == IEEE80211_MODE_11A) ?
5006270515Skevlo	    rt2860_rates[RT2860_RIDX_OFDM6].mcs | RT2860_PHY_OFDM :
5007203134Sthompsa	    rt2860_rates[RT2860_RIDX_CCK11].mcs;
5008203134Sthompsa
5009203134Sthompsa	/* CCK frames don't require protection */
5010203134Sthompsa	run_write(sc, RT2860_CCK_PROT_CFG, tmp);
5011203134Sthompsa	if (ic->ic_flags & IEEE80211_F_USEPROT) {
5012203134Sthompsa		if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
5013203134Sthompsa			tmp |= RT2860_PROT_CTRL_RTS_CTS;
5014203134Sthompsa		else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
5015203134Sthompsa			tmp |= RT2860_PROT_CTRL_CTS;
5016203134Sthompsa	}
5017203134Sthompsa	run_write(sc, RT2860_OFDM_PROT_CFG, tmp);
5018203134Sthompsa}
5019203134Sthompsa
5020203134Sthompsastatic void
5021208019Sthompsarun_usb_timeout_cb(void *arg)
5022203134Sthompsa{
5023208019Sthompsa	struct ieee80211vap *vap = arg;
5024208019Sthompsa	struct run_softc *sc = vap->iv_ic->ic_ifp->if_softc;
5025203134Sthompsa
5026208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
5027203134Sthompsa
5028203134Sthompsa	if(vap->iv_state == IEEE80211_S_RUN &&
5029203134Sthompsa	    vap->iv_opmode != IEEE80211_M_STA)
5030203134Sthompsa		run_reset_livelock(sc);
5031209917Sthompsa	else if (vap->iv_state == IEEE80211_S_SCAN) {
5032203134Sthompsa		DPRINTF("timeout caused by scan\n");
5033203134Sthompsa		/* cancel bgscan */
5034203134Sthompsa		ieee80211_cancel_scan(vap);
5035203134Sthompsa	} else
5036203134Sthompsa		DPRINTF("timeout by unknown cause\n");
5037203134Sthompsa}
5038203134Sthompsa
5039203134Sthompsastatic void
5040203134Sthompsarun_reset_livelock(struct run_softc *sc)
5041203134Sthompsa{
5042203134Sthompsa	uint32_t tmp;
5043203134Sthompsa
5044208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
5045208019Sthompsa
5046203134Sthompsa	/*
5047203134Sthompsa	 * In IBSS or HostAP modes (when the hardware sends beacons), the MAC
5048203134Sthompsa	 * can run into a livelock and start sending CTS-to-self frames like
5049203134Sthompsa	 * crazy if protection is enabled.  Reset MAC/BBP for a while
5050203134Sthompsa	 */
5051203134Sthompsa	run_read(sc, RT2860_DEBUG, &tmp);
5052208019Sthompsa	DPRINTFN(3, "debug reg %08x\n", tmp);
5053209917Sthompsa	if ((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))) {
5054203134Sthompsa		DPRINTF("CTS-to-self livelock detected\n");
5055203134Sthompsa		run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST);
5056203134Sthompsa		run_delay(sc, 1);
5057203134Sthompsa		run_write(sc, RT2860_MAC_SYS_CTRL,
5058203134Sthompsa		    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
5059203134Sthompsa	}
5060203134Sthompsa}
5061203134Sthompsa
5062203134Sthompsastatic void
5063203134Sthompsarun_update_promisc_locked(struct ifnet *ifp)
5064203134Sthompsa{
5065203134Sthompsa	struct run_softc *sc = ifp->if_softc;
5066203134Sthompsa        uint32_t tmp;
5067203134Sthompsa
5068203134Sthompsa	run_read(sc, RT2860_RX_FILTR_CFG, &tmp);
5069203134Sthompsa
5070203134Sthompsa	tmp |= RT2860_DROP_UC_NOME;
5071203134Sthompsa        if (ifp->if_flags & IFF_PROMISC)
5072203134Sthompsa		tmp &= ~RT2860_DROP_UC_NOME;
5073203134Sthompsa
5074203134Sthompsa	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
5075203134Sthompsa
5076203134Sthompsa        DPRINTF("%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ?
5077203134Sthompsa            "entering" : "leaving");
5078203134Sthompsa}
5079203134Sthompsa
5080203134Sthompsastatic void
5081203134Sthompsarun_update_promisc(struct ifnet *ifp)
5082203134Sthompsa{
5083203134Sthompsa	struct run_softc *sc = ifp->if_softc;
5084203134Sthompsa
5085203134Sthompsa	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
5086203134Sthompsa		return;
5087203134Sthompsa
5088203134Sthompsa	RUN_LOCK(sc);
5089203134Sthompsa	run_update_promisc_locked(ifp);
5090203134Sthompsa	RUN_UNLOCK(sc);
5091203134Sthompsa}
5092203134Sthompsa
5093203134Sthompsastatic void
5094203134Sthompsarun_enable_tsf_sync(struct run_softc *sc)
5095203134Sthompsa{
5096208019Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
5097203134Sthompsa	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
5098203134Sthompsa	uint32_t tmp;
5099203134Sthompsa
5100259453Shselasky	DPRINTF("rvp_id=%d ic_opmode=%d\n", RUN_VAP(vap)->rvp_id,
5101259453Shselasky	    ic->ic_opmode);
5102208019Sthompsa
5103203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
5104203134Sthompsa	tmp &= ~0x1fffff;
5105203134Sthompsa	tmp |= vap->iv_bss->ni_intval * 16;
5106203134Sthompsa	tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN;
5107203134Sthompsa
5108208019Sthompsa	if (ic->ic_opmode == IEEE80211_M_STA) {
5109203134Sthompsa		/*
5110203134Sthompsa		 * Local TSF is always updated with remote TSF on beacon
5111203134Sthompsa		 * reception.
5112203134Sthompsa		 */
5113203134Sthompsa		tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT;
5114208019Sthompsa	} else if (ic->ic_opmode == IEEE80211_M_IBSS) {
5115203134Sthompsa	        tmp |= RT2860_BCN_TX_EN;
5116203134Sthompsa	        /*
5117203134Sthompsa	         * Local TSF is updated with remote TSF on beacon reception
5118203134Sthompsa	         * only if the remote TSF is greater than local TSF.
5119203134Sthompsa	         */
5120203134Sthompsa	        tmp |= 2 << RT2860_TSF_SYNC_MODE_SHIFT;
5121208019Sthompsa	} else if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
5122208019Sthompsa		    ic->ic_opmode == IEEE80211_M_MBSS) {
5123203134Sthompsa	        tmp |= RT2860_BCN_TX_EN;
5124203134Sthompsa	        /* SYNC with nobody */
5125203134Sthompsa	        tmp |= 3 << RT2860_TSF_SYNC_MODE_SHIFT;
5126208019Sthompsa	} else {
5127203134Sthompsa		DPRINTF("Enabling TSF failed. undefined opmode\n");
5128208019Sthompsa		return;
5129208019Sthompsa	}
5130203134Sthompsa
5131203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
5132203134Sthompsa}
5133203134Sthompsa
5134203134Sthompsastatic void
5135203134Sthompsarun_enable_mrr(struct run_softc *sc)
5136203134Sthompsa{
5137261868Skevlo#define	CCK(mcs)	(mcs)
5138261868Skevlo#define	OFDM(mcs)	(1 << 3 | (mcs))
5139203134Sthompsa	run_write(sc, RT2860_LG_FBK_CFG0,
5140203134Sthompsa	    OFDM(6) << 28 |	/* 54->48 */
5141203134Sthompsa	    OFDM(5) << 24 |	/* 48->36 */
5142203134Sthompsa	    OFDM(4) << 20 |	/* 36->24 */
5143203134Sthompsa	    OFDM(3) << 16 |	/* 24->18 */
5144203134Sthompsa	    OFDM(2) << 12 |	/* 18->12 */
5145203134Sthompsa	    OFDM(1) <<  8 |	/* 12-> 9 */
5146203134Sthompsa	    OFDM(0) <<  4 |	/*  9-> 6 */
5147203134Sthompsa	    OFDM(0));		/*  6-> 6 */
5148203134Sthompsa
5149203134Sthompsa	run_write(sc, RT2860_LG_FBK_CFG1,
5150203134Sthompsa	    CCK(2) << 12 |	/* 11->5.5 */
5151203134Sthompsa	    CCK(1) <<  8 |	/* 5.5-> 2 */
5152203134Sthompsa	    CCK(0) <<  4 |	/*   2-> 1 */
5153203134Sthompsa	    CCK(0));		/*   1-> 1 */
5154203134Sthompsa#undef OFDM
5155203134Sthompsa#undef CCK
5156203134Sthompsa}
5157203134Sthompsa
5158203134Sthompsastatic void
5159203134Sthompsarun_set_txpreamble(struct run_softc *sc)
5160203134Sthompsa{
5161203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
5162203134Sthompsa	uint32_t tmp;
5163203134Sthompsa
5164203134Sthompsa	run_read(sc, RT2860_AUTO_RSP_CFG, &tmp);
5165203134Sthompsa	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
5166203134Sthompsa		tmp |= RT2860_CCK_SHORT_EN;
5167203134Sthompsa	else
5168203134Sthompsa		tmp &= ~RT2860_CCK_SHORT_EN;
5169203134Sthompsa	run_write(sc, RT2860_AUTO_RSP_CFG, tmp);
5170203134Sthompsa}
5171203134Sthompsa
5172203134Sthompsastatic void
5173203134Sthompsarun_set_basicrates(struct run_softc *sc)
5174203134Sthompsa{
5175203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
5176203134Sthompsa
5177203134Sthompsa	/* set basic rates mask */
5178203134Sthompsa	if (ic->ic_curmode == IEEE80211_MODE_11B)
5179203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x003);
5180203134Sthompsa	else if (ic->ic_curmode == IEEE80211_MODE_11A)
5181203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x150);
5182203134Sthompsa	else	/* 11g */
5183203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x15f);
5184203134Sthompsa}
5185203134Sthompsa
5186203134Sthompsastatic void
5187203134Sthompsarun_set_leds(struct run_softc *sc, uint16_t which)
5188203134Sthompsa{
5189203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LEDS,
5190203134Sthompsa	    which | (sc->leds & 0x7f));
5191203134Sthompsa}
5192203134Sthompsa
5193203134Sthompsastatic void
5194203134Sthompsarun_set_bssid(struct run_softc *sc, const uint8_t *bssid)
5195203134Sthompsa{
5196203134Sthompsa	run_write(sc, RT2860_MAC_BSSID_DW0,
5197203134Sthompsa	    bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24);
5198203134Sthompsa	run_write(sc, RT2860_MAC_BSSID_DW1,
5199203134Sthompsa	    bssid[4] | bssid[5] << 8);
5200203134Sthompsa}
5201203134Sthompsa
5202203134Sthompsastatic void
5203203134Sthompsarun_set_macaddr(struct run_softc *sc, const uint8_t *addr)
5204203134Sthompsa{
5205203134Sthompsa	run_write(sc, RT2860_MAC_ADDR_DW0,
5206203134Sthompsa	    addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24);
5207203134Sthompsa	run_write(sc, RT2860_MAC_ADDR_DW1,
5208203134Sthompsa	    addr[4] | addr[5] << 8 | 0xff << 16);
5209203134Sthompsa}
5210203134Sthompsa
5211203134Sthompsastatic void
5212203134Sthompsarun_updateslot(struct ifnet *ifp)
5213203134Sthompsa{
5214203134Sthompsa	struct run_softc *sc = ifp->if_softc;
5215203134Sthompsa	struct ieee80211com *ic = ifp->if_l2com;
5216218492Sbschmidt	uint32_t i;
5217218492Sbschmidt
5218218492Sbschmidt	i = RUN_CMDQ_GET(&sc->cmdq_store);
5219218492Sbschmidt	DPRINTF("cmdq_store=%d\n", i);
5220218492Sbschmidt	sc->cmdq[i].func = run_updateslot_cb;
5221218492Sbschmidt	sc->cmdq[i].arg0 = ifp;
5222218492Sbschmidt	ieee80211_runtask(ic, &sc->cmdq_task);
5223218492Sbschmidt
5224218492Sbschmidt	return;
5225218492Sbschmidt}
5226218492Sbschmidt
5227218492Sbschmidt/* ARGSUSED */
5228218492Sbschmidtstatic void
5229218492Sbschmidtrun_updateslot_cb(void *arg)
5230218492Sbschmidt{
5231218492Sbschmidt	struct ifnet *ifp = arg;
5232218492Sbschmidt	struct run_softc *sc = ifp->if_softc;
5233218492Sbschmidt	struct ieee80211com *ic = ifp->if_l2com;
5234203134Sthompsa	uint32_t tmp;
5235203134Sthompsa
5236203134Sthompsa	run_read(sc, RT2860_BKOFF_SLOT_CFG, &tmp);
5237203134Sthompsa	tmp &= ~0xff;
5238203134Sthompsa	tmp |= (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20;
5239203134Sthompsa	run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp);
5240203134Sthompsa}
5241203134Sthompsa
5242208019Sthompsastatic void
5243208019Sthompsarun_update_mcast(struct ifnet *ifp)
5244208019Sthompsa{
5245208019Sthompsa	/* h/w filter supports getting everything or nothing */
5246208019Sthompsa	ifp->if_flags |= IFF_ALLMULTI;
5247208019Sthompsa}
5248208019Sthompsa
5249203134Sthompsastatic int8_t
5250203134Sthompsarun_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain)
5251203134Sthompsa{
5252203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
5253203134Sthompsa	struct ieee80211_channel *c = ic->ic_curchan;
5254203134Sthompsa	int delta;
5255203134Sthompsa
5256203134Sthompsa	if (IEEE80211_IS_CHAN_5GHZ(c)) {
5257259453Shselasky		u_int chan = ieee80211_chan2ieee(ic, c);
5258203134Sthompsa		delta = sc->rssi_5ghz[rxchain];
5259203134Sthompsa
5260203134Sthompsa		/* determine channel group */
5261203134Sthompsa		if (chan <= 64)
5262203134Sthompsa			delta -= sc->lna[1];
5263203134Sthompsa		else if (chan <= 128)
5264203134Sthompsa			delta -= sc->lna[2];
5265203134Sthompsa		else
5266203134Sthompsa			delta -= sc->lna[3];
5267203134Sthompsa	} else
5268203134Sthompsa		delta = sc->rssi_2ghz[rxchain] - sc->lna[0];
5269203134Sthompsa
5270209917Sthompsa	return (-12 - delta - rssi);
5271203134Sthompsa}
5272203134Sthompsa
5273259453Shselaskystatic void
5274259453Shselaskyrun_rt5390_bbp_init(struct run_softc *sc)
5275259453Shselasky{
5276259453Shselasky	int i;
5277259453Shselasky	uint8_t bbp;
5278259453Shselasky
5279259453Shselasky	/* Apply maximum likelihood detection for 2 stream case. */
5280259453Shselasky	run_bbp_read(sc, 105, &bbp);
5281259453Shselasky	if (sc->nrxchains > 1)
5282259453Shselasky		run_bbp_write(sc, 105, bbp | RT5390_MLD);
5283259453Shselasky
5284259453Shselasky	/* Avoid data lost and CRC error. */
5285259453Shselasky	run_bbp_read(sc, 4, &bbp);
5286259453Shselasky	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5287259453Shselasky
5288259453Shselasky	if (sc->mac_ver == 0x5592) {
5289259453Shselasky		for (i = 0; i < nitems(rt5592_def_bbp); i++) {
5290259453Shselasky			run_bbp_write(sc, rt5592_def_bbp[i].reg,
5291259453Shselasky			    rt5592_def_bbp[i].val);
5292259453Shselasky		}
5293259453Shselasky		for (i = 0; i < nitems(rt5592_bbp_r196); i++) {
5294259453Shselasky			run_bbp_write(sc, 195, i + 0x80);
5295259453Shselasky			run_bbp_write(sc, 196, rt5592_bbp_r196[i]);
5296259453Shselasky		}
5297259453Shselasky	} else {
5298259453Shselasky		for (i = 0; i < nitems(rt5390_def_bbp); i++) {
5299259453Shselasky			run_bbp_write(sc, rt5390_def_bbp[i].reg,
5300259453Shselasky			    rt5390_def_bbp[i].val);
5301259453Shselasky		}
5302259453Shselasky	}
5303259453Shselasky	if (sc->mac_ver == 0x5392) {
5304259453Shselasky		run_bbp_write(sc, 88, 0x90);
5305259453Shselasky		run_bbp_write(sc, 95, 0x9a);
5306259453Shselasky		run_bbp_write(sc, 98, 0x12);
5307259453Shselasky		run_bbp_write(sc, 106, 0x12);
5308259453Shselasky		run_bbp_write(sc, 134, 0xd0);
5309259453Shselasky		run_bbp_write(sc, 135, 0xf6);
5310259453Shselasky		run_bbp_write(sc, 148, 0x84);
5311259453Shselasky	}
5312259453Shselasky
5313259453Shselasky	run_bbp_read(sc, 152, &bbp);
5314259453Shselasky	run_bbp_write(sc, 152, bbp | 0x80);
5315259453Shselasky
5316259453Shselasky	/* Fix BBP254 for RT5592C. */
5317259453Shselasky	if (sc->mac_ver == 0x5592 && sc->mac_rev >= 0x0221) {
5318259453Shselasky		run_bbp_read(sc, 254, &bbp);
5319259453Shselasky		run_bbp_write(sc, 254, bbp | 0x80);
5320259453Shselasky	}
5321259453Shselasky
5322259453Shselasky	/* Disable hardware antenna diversity. */
5323259453Shselasky	if (sc->mac_ver == 0x5390)
5324259453Shselasky		run_bbp_write(sc, 154, 0);
5325259453Shselasky
5326259453Shselasky	/* Initialize Rx CCK/OFDM frequency offset report. */
5327259453Shselasky	run_bbp_write(sc, 142, 1);
5328259453Shselasky	run_bbp_write(sc, 143, 57);
5329259453Shselasky}
5330259453Shselasky
5331203134Sthompsastatic int
5332203134Sthompsarun_bbp_init(struct run_softc *sc)
5333203134Sthompsa{
5334203134Sthompsa	int i, error, ntries;
5335203134Sthompsa	uint8_t bbp0;
5336203134Sthompsa
5337203134Sthompsa	/* wait for BBP to wake up */
5338203134Sthompsa	for (ntries = 0; ntries < 20; ntries++) {
5339203134Sthompsa		if ((error = run_bbp_read(sc, 0, &bbp0)) != 0)
5340203134Sthompsa			return error;
5341203134Sthompsa		if (bbp0 != 0 && bbp0 != 0xff)
5342203134Sthompsa			break;
5343203134Sthompsa	}
5344203134Sthompsa	if (ntries == 20)
5345209917Sthompsa		return (ETIMEDOUT);
5346203134Sthompsa
5347203134Sthompsa	/* initialize BBP registers to default values */
5348259453Shselasky	if (sc->mac_ver >= 0x5390)
5349259453Shselasky		run_rt5390_bbp_init(sc);
5350259453Shselasky	else {
5351259453Shselasky		for (i = 0; i < nitems(rt2860_def_bbp); i++) {
5352259453Shselasky			run_bbp_write(sc, rt2860_def_bbp[i].reg,
5353259453Shselasky			    rt2860_def_bbp[i].val);
5354259453Shselasky		}
5355203134Sthompsa	}
5356203134Sthompsa
5357261868Skevlo	if (sc->mac_ver == 0x3593) {
5358261868Skevlo		run_bbp_write(sc, 79, 0x13);
5359261868Skevlo		run_bbp_write(sc, 80, 0x05);
5360261868Skevlo		run_bbp_write(sc, 81, 0x33);
5361261868Skevlo		run_bbp_write(sc, 86, 0x46);
5362261868Skevlo		run_bbp_write(sc, 137, 0x0f);
5363261868Skevlo	}
5364261868Skevlo
5365203134Sthompsa	/* fix BBP84 for RT2860E */
5366205042Sthompsa	if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0101)
5367205042Sthompsa		run_bbp_write(sc, 84, 0x19);
5368203134Sthompsa
5369261868Skevlo	if (sc->mac_ver >= 0x3070 && (sc->mac_ver != 0x3593 &&
5370261868Skevlo	    sc->mac_ver != 0x5592)) {
5371203134Sthompsa		run_bbp_write(sc, 79, 0x13);
5372203134Sthompsa		run_bbp_write(sc, 80, 0x05);
5373203134Sthompsa		run_bbp_write(sc, 81, 0x33);
5374205042Sthompsa	} else if (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) {
5375203134Sthompsa		run_bbp_write(sc, 69, 0x16);
5376203134Sthompsa		run_bbp_write(sc, 73, 0x12);
5377203134Sthompsa	}
5378209917Sthompsa	return (0);
5379203134Sthompsa}
5380203134Sthompsa
5381203134Sthompsastatic int
5382203134Sthompsarun_rt3070_rf_init(struct run_softc *sc)
5383203134Sthompsa{
5384203134Sthompsa	uint32_t tmp;
5385259453Shselasky	uint8_t bbp4, mingain, rf, target;
5386203134Sthompsa	int i;
5387203134Sthompsa
5388203134Sthompsa	run_rt3070_rf_read(sc, 30, &rf);
5389203134Sthompsa	/* toggle RF R30 bit 7 */
5390203134Sthompsa	run_rt3070_rf_write(sc, 30, rf | 0x80);
5391203134Sthompsa	run_delay(sc, 10);
5392203134Sthompsa	run_rt3070_rf_write(sc, 30, rf & ~0x80);
5393203134Sthompsa
5394203134Sthompsa	/* initialize RF registers to default value */
5395205042Sthompsa	if (sc->mac_ver == 0x3572) {
5396259453Shselasky		for (i = 0; i < nitems(rt3572_def_rf); i++) {
5397205042Sthompsa			run_rt3070_rf_write(sc, rt3572_def_rf[i].reg,
5398205042Sthompsa			    rt3572_def_rf[i].val);
5399205042Sthompsa		}
5400205042Sthompsa	} else {
5401259453Shselasky		for (i = 0; i < nitems(rt3070_def_rf); i++) {
5402205042Sthompsa			run_rt3070_rf_write(sc, rt3070_def_rf[i].reg,
5403205042Sthompsa			    rt3070_def_rf[i].val);
5404205042Sthompsa		}
5405203134Sthompsa	}
5406205042Sthompsa
5407259453Shselasky	if (sc->mac_ver == 0x3070 && sc->mac_rev < 0x0201) {
5408259453Shselasky		/*
5409259453Shselasky		 * Change voltage from 1.2V to 1.35V for RT3070.
5410259453Shselasky		 * The DAC issue (RT3070_LDO_CFG0) has been fixed
5411259453Shselasky		 * in RT3070(F).
5412259453Shselasky		 */
5413203134Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5414203134Sthompsa		tmp = (tmp & ~0x0f000000) | 0x0d000000;
5415203134Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5416203134Sthompsa
5417205042Sthompsa	} else if (sc->mac_ver == 0x3071) {
5418203134Sthompsa		run_rt3070_rf_read(sc, 6, &rf);
5419203134Sthompsa		run_rt3070_rf_write(sc, 6, rf | 0x40);
5420203134Sthompsa		run_rt3070_rf_write(sc, 31, 0x14);
5421203134Sthompsa
5422203134Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5423203134Sthompsa		tmp &= ~0x1f000000;
5424205042Sthompsa		if (sc->mac_rev < 0x0211)
5425205042Sthompsa			tmp |= 0x0d000000;	/* 1.3V */
5426203134Sthompsa		else
5427205042Sthompsa			tmp |= 0x01000000;	/* 1.2V */
5428203134Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5429203134Sthompsa
5430203134Sthompsa		/* patch LNA_PE_G1 */
5431203134Sthompsa		run_read(sc, RT3070_GPIO_SWITCH, &tmp);
5432203134Sthompsa		run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20);
5433208019Sthompsa
5434209917Sthompsa	} else if (sc->mac_ver == 0x3572) {
5435205042Sthompsa		run_rt3070_rf_read(sc, 6, &rf);
5436205042Sthompsa		run_rt3070_rf_write(sc, 6, rf | 0x40);
5437205042Sthompsa
5438208019Sthompsa		/* increase voltage from 1.2V to 1.35V */
5439208019Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5440208019Sthompsa		tmp = (tmp & ~0x1f000000) | 0x0d000000;
5441208019Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5442203134Sthompsa
5443209917Sthompsa		if (sc->mac_rev < 0x0211 || !sc->patch_dac) {
5444203134Sthompsa			run_delay(sc, 1);	/* wait for 1msec */
5445205042Sthompsa			/* decrease voltage back to 1.2V */
5446203134Sthompsa			tmp = (tmp & ~0x1f000000) | 0x01000000;
5447203134Sthompsa			run_write(sc, RT3070_LDO_CFG0, tmp);
5448203134Sthompsa		}
5449203134Sthompsa	}
5450203134Sthompsa
5451203134Sthompsa	/* select 20MHz bandwidth */
5452203134Sthompsa	run_rt3070_rf_read(sc, 31, &rf);
5453203134Sthompsa	run_rt3070_rf_write(sc, 31, rf & ~0x20);
5454203134Sthompsa
5455203134Sthompsa	/* calibrate filter for 20MHz bandwidth */
5456203134Sthompsa	sc->rf24_20mhz = 0x1f;	/* default value */
5457205042Sthompsa	target = (sc->mac_ver < 0x3071) ? 0x16 : 0x13;
5458205042Sthompsa	run_rt3070_filter_calib(sc, 0x07, target, &sc->rf24_20mhz);
5459203134Sthompsa
5460203134Sthompsa	/* select 40MHz bandwidth */
5461203134Sthompsa	run_bbp_read(sc, 4, &bbp4);
5462259453Shselasky	run_bbp_write(sc, 4, (bbp4 & ~0x18) | 0x10);
5463205042Sthompsa	run_rt3070_rf_read(sc, 31, &rf);
5464205042Sthompsa	run_rt3070_rf_write(sc, 31, rf | 0x20);
5465203134Sthompsa
5466203134Sthompsa	/* calibrate filter for 40MHz bandwidth */
5467203134Sthompsa	sc->rf24_40mhz = 0x2f;	/* default value */
5468205042Sthompsa	target = (sc->mac_ver < 0x3071) ? 0x19 : 0x15;
5469205042Sthompsa	run_rt3070_filter_calib(sc, 0x27, target, &sc->rf24_40mhz);
5470203134Sthompsa
5471203134Sthompsa	/* go back to 20MHz bandwidth */
5472203134Sthompsa	run_bbp_read(sc, 4, &bbp4);
5473203134Sthompsa	run_bbp_write(sc, 4, bbp4 & ~0x18);
5474203134Sthompsa
5475205042Sthompsa	if (sc->mac_ver == 0x3572) {
5476205042Sthompsa		/* save default BBP registers 25 and 26 values */
5477205042Sthompsa		run_bbp_read(sc, 25, &sc->bbp25);
5478205042Sthompsa		run_bbp_read(sc, 26, &sc->bbp26);
5479259453Shselasky	} else if (sc->mac_rev < 0x0201 || sc->mac_rev < 0x0211)
5480203134Sthompsa		run_rt3070_rf_write(sc, 27, 0x03);
5481203134Sthompsa
5482203134Sthompsa	run_read(sc, RT3070_OPT_14, &tmp);
5483203134Sthompsa	run_write(sc, RT3070_OPT_14, tmp | 1);
5484203134Sthompsa
5485205042Sthompsa	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
5486205042Sthompsa		run_rt3070_rf_read(sc, 17, &rf);
5487205042Sthompsa		rf &= ~RT3070_TX_LO1;
5488205042Sthompsa		if ((sc->mac_ver == 0x3070 ||
5489205042Sthompsa		     (sc->mac_ver == 0x3071 && sc->mac_rev >= 0x0211)) &&
5490205042Sthompsa		    !sc->ext_2ghz_lna)
5491205042Sthompsa			rf |= 0x20;	/* fix for long range Rx issue */
5492259453Shselasky		mingain = (sc->mac_ver == 0x3070) ? 1 : 2;
5493259453Shselasky		if (sc->txmixgain_2ghz >= mingain)
5494205042Sthompsa			rf = (rf & ~0x7) | sc->txmixgain_2ghz;
5495205042Sthompsa		run_rt3070_rf_write(sc, 17, rf);
5496205042Sthompsa	}
5497205042Sthompsa
5498270843Skevlo	if (sc->mac_ver == 0x3071) {
5499203134Sthompsa		run_rt3070_rf_read(sc, 1, &rf);
5500203134Sthompsa		rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD);
5501203134Sthompsa		rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD;
5502203134Sthompsa		run_rt3070_rf_write(sc, 1, rf);
5503203134Sthompsa
5504203134Sthompsa		run_rt3070_rf_read(sc, 15, &rf);
5505203134Sthompsa		run_rt3070_rf_write(sc, 15, rf & ~RT3070_TX_LO2);
5506203134Sthompsa
5507203134Sthompsa		run_rt3070_rf_read(sc, 20, &rf);
5508203134Sthompsa		run_rt3070_rf_write(sc, 20, rf & ~RT3070_RX_LO1);
5509203134Sthompsa
5510203134Sthompsa		run_rt3070_rf_read(sc, 21, &rf);
5511203134Sthompsa		run_rt3070_rf_write(sc, 21, rf & ~RT3070_RX_LO2);
5512205042Sthompsa	}
5513203134Sthompsa
5514205042Sthompsa	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
5515205042Sthompsa		/* fix Tx to Rx IQ glitch by raising RF voltage */
5516203134Sthompsa		run_rt3070_rf_read(sc, 27, &rf);
5517203134Sthompsa		rf &= ~0x77;
5518205042Sthompsa		if (sc->mac_rev < 0x0211)
5519203134Sthompsa			rf |= 0x03;
5520203134Sthompsa		run_rt3070_rf_write(sc, 27, rf);
5521203134Sthompsa	}
5522209917Sthompsa	return (0);
5523203134Sthompsa}
5524203134Sthompsa
5525259453Shselaskystatic void
5526261868Skevlorun_rt3593_rf_init(struct run_softc *sc)
5527261868Skevlo{
5528261868Skevlo	uint32_t tmp;
5529261868Skevlo	uint8_t rf;
5530261868Skevlo	int i;
5531261868Skevlo
5532261868Skevlo	/* Disable the GPIO bits 4 and 7 for LNA PE control. */
5533261868Skevlo	run_read(sc, RT3070_GPIO_SWITCH, &tmp);
5534261868Skevlo	tmp &= ~(1 << 4 | 1 << 7);
5535261868Skevlo	run_write(sc, RT3070_GPIO_SWITCH, tmp);
5536261868Skevlo
5537261868Skevlo	/* Initialize RF registers to default value. */
5538261868Skevlo	for (i = 0; i < nitems(rt3593_def_rf); i++) {
5539261868Skevlo		run_rt3070_rf_write(sc, rt3593_def_rf[i].reg,
5540261868Skevlo		    rt3593_def_rf[i].val);
5541261868Skevlo	}
5542261868Skevlo
5543261868Skevlo	/* Toggle RF R2 to initiate calibration. */
5544261868Skevlo	run_rt3070_rf_write(sc, 2, RT5390_RESCAL);
5545261868Skevlo
5546261868Skevlo	/* Initialize RF frequency offset. */
5547261868Skevlo	run_adjust_freq_offset(sc);
5548261868Skevlo
5549261868Skevlo	run_rt3070_rf_read(sc, 18, &rf);
5550261868Skevlo	run_rt3070_rf_write(sc, 18, rf | RT3593_AUTOTUNE_BYPASS);
5551261868Skevlo
5552261868Skevlo	/*
5553261868Skevlo	 * Increase voltage from 1.2V to 1.35V, wait for 1 msec to
5554261868Skevlo	 * decrease voltage back to 1.2V.
5555261868Skevlo	 */
5556261868Skevlo	run_read(sc, RT3070_LDO_CFG0, &tmp);
5557261868Skevlo	tmp = (tmp & ~0x1f000000) | 0x0d000000;
5558261868Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
5559261868Skevlo	run_delay(sc, 1);
5560261868Skevlo	tmp = (tmp & ~0x1f000000) | 0x01000000;
5561261868Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
5562261868Skevlo
5563261868Skevlo	sc->rf24_20mhz = 0x1f;
5564261868Skevlo	sc->rf24_40mhz = 0x2f;
5565261868Skevlo
5566261868Skevlo	/* Save default BBP registers 25 and 26 values. */
5567261868Skevlo	run_bbp_read(sc, 25, &sc->bbp25);
5568261868Skevlo	run_bbp_read(sc, 26, &sc->bbp26);
5569261868Skevlo
5570261868Skevlo	run_read(sc, RT3070_OPT_14, &tmp);
5571261868Skevlo	run_write(sc, RT3070_OPT_14, tmp | 1);
5572261868Skevlo}
5573261868Skevlo
5574261868Skevlostatic void
5575259453Shselaskyrun_rt5390_rf_init(struct run_softc *sc)
5576259453Shselasky{
5577259453Shselasky	uint32_t tmp;
5578259453Shselasky	uint8_t rf;
5579259453Shselasky	int i;
5580259453Shselasky
5581259453Shselasky	/* Toggle RF R2 to initiate calibration. */
5582259453Shselasky	if (sc->mac_ver == 0x5390) {
5583259453Shselasky		run_rt3070_rf_read(sc, 2, &rf);
5584259453Shselasky		run_rt3070_rf_write(sc, 2, rf | RT5390_RESCAL);
5585259453Shselasky		run_delay(sc, 10);
5586259453Shselasky		run_rt3070_rf_write(sc, 2, rf & ~RT5390_RESCAL);
5587259453Shselasky	} else {
5588259453Shselasky		run_rt3070_rf_write(sc, 2, RT5390_RESCAL);
5589259453Shselasky		run_delay(sc, 10);
5590259453Shselasky	}
5591259453Shselasky
5592259453Shselasky	/* Initialize RF registers to default value. */
5593259453Shselasky	if (sc->mac_ver == 0x5592) {
5594259453Shselasky		for (i = 0; i < nitems(rt5592_def_rf); i++) {
5595259453Shselasky			run_rt3070_rf_write(sc, rt5592_def_rf[i].reg,
5596259453Shselasky			    rt5592_def_rf[i].val);
5597259453Shselasky		}
5598259453Shselasky		/* Initialize RF frequency offset. */
5599259453Shselasky		run_adjust_freq_offset(sc);
5600259453Shselasky	} else if (sc->mac_ver == 0x5392) {
5601259453Shselasky		for (i = 0; i < nitems(rt5392_def_rf); i++) {
5602259453Shselasky			run_rt3070_rf_write(sc, rt5392_def_rf[i].reg,
5603259453Shselasky			    rt5392_def_rf[i].val);
5604259453Shselasky		}
5605259453Shselasky		if (sc->mac_rev >= 0x0223) {
5606259453Shselasky			run_rt3070_rf_write(sc, 23, 0x0f);
5607259453Shselasky			run_rt3070_rf_write(sc, 24, 0x3e);
5608259453Shselasky			run_rt3070_rf_write(sc, 51, 0x32);
5609259453Shselasky			run_rt3070_rf_write(sc, 53, 0x22);
5610259453Shselasky			run_rt3070_rf_write(sc, 56, 0xc1);
5611259453Shselasky			run_rt3070_rf_write(sc, 59, 0x0f);
5612259453Shselasky		}
5613259453Shselasky	} else {
5614259453Shselasky		for (i = 0; i < nitems(rt5390_def_rf); i++) {
5615259453Shselasky			run_rt3070_rf_write(sc, rt5390_def_rf[i].reg,
5616259453Shselasky			    rt5390_def_rf[i].val);
5617259453Shselasky		}
5618259453Shselasky		if (sc->mac_rev >= 0x0502) {
5619259453Shselasky			run_rt3070_rf_write(sc, 6, 0xe0);
5620259453Shselasky			run_rt3070_rf_write(sc, 25, 0x80);
5621259453Shselasky			run_rt3070_rf_write(sc, 46, 0x73);
5622259453Shselasky			run_rt3070_rf_write(sc, 53, 0x00);
5623259453Shselasky			run_rt3070_rf_write(sc, 56, 0x42);
5624259453Shselasky			run_rt3070_rf_write(sc, 61, 0xd1);
5625259453Shselasky		}
5626259453Shselasky	}
5627259453Shselasky
5628259453Shselasky	sc->rf24_20mhz = 0x1f;	/* default value */
5629259453Shselasky	sc->rf24_40mhz = (sc->mac_ver == 0x5592) ? 0 : 0x2f;
5630259453Shselasky
5631259453Shselasky	if (sc->mac_rev < 0x0211)
5632259453Shselasky		run_rt3070_rf_write(sc, 27, 0x3);
5633259453Shselasky
5634259453Shselasky	run_read(sc, RT3070_OPT_14, &tmp);
5635259453Shselasky	run_write(sc, RT3070_OPT_14, tmp | 1);
5636259453Shselasky}
5637259453Shselasky
5638203134Sthompsastatic int
5639203134Sthompsarun_rt3070_filter_calib(struct run_softc *sc, uint8_t init, uint8_t target,
5640203134Sthompsa    uint8_t *val)
5641203134Sthompsa{
5642203134Sthompsa	uint8_t rf22, rf24;
5643203134Sthompsa	uint8_t bbp55_pb, bbp55_sb, delta;
5644203134Sthompsa	int ntries;
5645203134Sthompsa
5646203134Sthompsa	/* program filter */
5647205042Sthompsa	run_rt3070_rf_read(sc, 24, &rf24);
5648205042Sthompsa	rf24 = (rf24 & 0xc0) | init;	/* initial filter value */
5649203134Sthompsa	run_rt3070_rf_write(sc, 24, rf24);
5650203134Sthompsa
5651203134Sthompsa	/* enable baseband loopback mode */
5652203134Sthompsa	run_rt3070_rf_read(sc, 22, &rf22);
5653203134Sthompsa	run_rt3070_rf_write(sc, 22, rf22 | 0x01);
5654203134Sthompsa
5655203134Sthompsa	/* set power and frequency of passband test tone */
5656203134Sthompsa	run_bbp_write(sc, 24, 0x00);
5657203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5658203134Sthompsa		/* transmit test tone */
5659203134Sthompsa		run_bbp_write(sc, 25, 0x90);
5660203134Sthompsa		run_delay(sc, 10);
5661203134Sthompsa		/* read received power */
5662203134Sthompsa		run_bbp_read(sc, 55, &bbp55_pb);
5663203134Sthompsa		if (bbp55_pb != 0)
5664203134Sthompsa			break;
5665203134Sthompsa	}
5666203134Sthompsa	if (ntries == 100)
5667259453Shselasky		return (ETIMEDOUT);
5668203134Sthompsa
5669203134Sthompsa	/* set power and frequency of stopband test tone */
5670203134Sthompsa	run_bbp_write(sc, 24, 0x06);
5671203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5672203134Sthompsa		/* transmit test tone */
5673203134Sthompsa		run_bbp_write(sc, 25, 0x90);
5674203134Sthompsa		run_delay(sc, 10);
5675203134Sthompsa		/* read received power */
5676203134Sthompsa		run_bbp_read(sc, 55, &bbp55_sb);
5677203134Sthompsa
5678203134Sthompsa		delta = bbp55_pb - bbp55_sb;
5679203134Sthompsa		if (delta > target)
5680203134Sthompsa			break;
5681203134Sthompsa
5682203134Sthompsa		/* reprogram filter */
5683203134Sthompsa		rf24++;
5684203134Sthompsa		run_rt3070_rf_write(sc, 24, rf24);
5685203134Sthompsa	}
5686203134Sthompsa	if (ntries < 100) {
5687203134Sthompsa		if (rf24 != init)
5688203134Sthompsa			rf24--;	/* backtrack */
5689203134Sthompsa		*val = rf24;
5690203134Sthompsa		run_rt3070_rf_write(sc, 24, rf24);
5691203134Sthompsa	}
5692203134Sthompsa
5693203134Sthompsa	/* restore initial state */
5694203134Sthompsa	run_bbp_write(sc, 24, 0x00);
5695203134Sthompsa
5696203134Sthompsa	/* disable baseband loopback mode */
5697203134Sthompsa	run_rt3070_rf_read(sc, 22, &rf22);
5698203134Sthompsa	run_rt3070_rf_write(sc, 22, rf22 & ~0x01);
5699203134Sthompsa
5700209917Sthompsa	return (0);
5701203134Sthompsa}
5702203134Sthompsa
5703205042Sthompsastatic void
5704205042Sthompsarun_rt3070_rf_setup(struct run_softc *sc)
5705205042Sthompsa{
5706205042Sthompsa	uint8_t bbp, rf;
5707205042Sthompsa	int i;
5708205042Sthompsa
5709261868Skevlo	if (sc->mac_ver == 0x3572) {
5710205042Sthompsa		/* enable DC filter */
5711205042Sthompsa		if (sc->mac_rev >= 0x0201)
5712205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5713205042Sthompsa
5714205042Sthompsa		run_bbp_read(sc, 138, &bbp);
5715205042Sthompsa		if (sc->ntxchains == 1)
5716205042Sthompsa			bbp |= 0x20;	/* turn off DAC1 */
5717205042Sthompsa		if (sc->nrxchains == 1)
5718205042Sthompsa			bbp &= ~0x02;	/* turn off ADC1 */
5719205042Sthompsa		run_bbp_write(sc, 138, bbp);
5720205042Sthompsa
5721205042Sthompsa		if (sc->mac_rev >= 0x0211) {
5722205042Sthompsa			/* improve power consumption */
5723205042Sthompsa			run_bbp_read(sc, 31, &bbp);
5724205042Sthompsa			run_bbp_write(sc, 31, bbp & ~0x03);
5725205042Sthompsa		}
5726205042Sthompsa
5727205042Sthompsa		run_rt3070_rf_read(sc, 16, &rf);
5728205042Sthompsa		rf = (rf & ~0x07) | sc->txmixgain_2ghz;
5729205042Sthompsa		run_rt3070_rf_write(sc, 16, rf);
5730205042Sthompsa
5731205042Sthompsa	} else if (sc->mac_ver == 0x3071) {
5732259453Shselasky		if (sc->mac_rev >= 0x0211) {
5733259453Shselasky			/* enable DC filter */
5734205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5735205042Sthompsa
5736259453Shselasky			/* improve power consumption */
5737259453Shselasky			run_bbp_read(sc, 31, &bbp);
5738259453Shselasky			run_bbp_write(sc, 31, bbp & ~0x03);
5739259453Shselasky		}
5740259453Shselasky
5741205042Sthompsa		run_bbp_read(sc, 138, &bbp);
5742205042Sthompsa		if (sc->ntxchains == 1)
5743205042Sthompsa			bbp |= 0x20;	/* turn off DAC1 */
5744205042Sthompsa		if (sc->nrxchains == 1)
5745205042Sthompsa			bbp &= ~0x02;	/* turn off ADC1 */
5746205042Sthompsa		run_bbp_write(sc, 138, bbp);
5747205042Sthompsa
5748205042Sthompsa		run_write(sc, RT2860_TX_SW_CFG1, 0);
5749205042Sthompsa		if (sc->mac_rev < 0x0211) {
5750205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2,
5751205042Sthompsa			    sc->patch_dac ? 0x2c : 0x0f);
5752205042Sthompsa		} else
5753205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0);
5754205042Sthompsa
5755205042Sthompsa	} else if (sc->mac_ver == 0x3070) {
5756205042Sthompsa		if (sc->mac_rev >= 0x0201) {
5757205042Sthompsa			/* enable DC filter */
5758205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5759205042Sthompsa
5760205042Sthompsa			/* improve power consumption */
5761205042Sthompsa			run_bbp_read(sc, 31, &bbp);
5762205042Sthompsa			run_bbp_write(sc, 31, bbp & ~0x03);
5763205042Sthompsa		}
5764205042Sthompsa
5765259453Shselasky		if (sc->mac_rev < 0x0201) {
5766205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG1, 0);
5767205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0x2c);
5768205042Sthompsa		} else
5769205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0);
5770205042Sthompsa	}
5771205042Sthompsa
5772205042Sthompsa	/* initialize RF registers from ROM for >=RT3071*/
5773261868Skevlo	if (sc->mac_ver >= 0x3071) {
5774205042Sthompsa		for (i = 0; i < 10; i++) {
5775205042Sthompsa			if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff)
5776205042Sthompsa				continue;
5777205042Sthompsa			run_rt3070_rf_write(sc, sc->rf[i].reg, sc->rf[i].val);
5778205042Sthompsa		}
5779205042Sthompsa	}
5780205042Sthompsa}
5781205042Sthompsa
5782261868Skevlostatic void
5783261868Skevlorun_rt3593_rf_setup(struct run_softc *sc)
5784261868Skevlo{
5785261868Skevlo	uint8_t bbp, rf;
5786261868Skevlo
5787261868Skevlo	if (sc->mac_rev >= 0x0211) {
5788261868Skevlo		/* Enable DC filter. */
5789261868Skevlo		run_bbp_write(sc, 103, 0xc0);
5790261868Skevlo	}
5791261868Skevlo	run_write(sc, RT2860_TX_SW_CFG1, 0);
5792261868Skevlo	if (sc->mac_rev < 0x0211) {
5793261868Skevlo		run_write(sc, RT2860_TX_SW_CFG2,
5794261868Skevlo		    sc->patch_dac ? 0x2c : 0x0f);
5795261868Skevlo	} else
5796261868Skevlo		run_write(sc, RT2860_TX_SW_CFG2, 0);
5797261868Skevlo
5798261868Skevlo	run_rt3070_rf_read(sc, 50, &rf);
5799261868Skevlo	run_rt3070_rf_write(sc, 50, rf & ~RT3593_TX_LO2);
5800261868Skevlo
5801261868Skevlo	run_rt3070_rf_read(sc, 51, &rf);
5802261868Skevlo	rf = (rf & ~(RT3593_TX_LO1 | 0x0c)) |
5803261868Skevlo	    ((sc->txmixgain_2ghz & 0x07) << 2);
5804261868Skevlo	run_rt3070_rf_write(sc, 51, rf);
5805261868Skevlo
5806261868Skevlo	run_rt3070_rf_read(sc, 38, &rf);
5807261868Skevlo	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
5808261868Skevlo
5809261868Skevlo	run_rt3070_rf_read(sc, 39, &rf);
5810261868Skevlo	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
5811261868Skevlo
5812261868Skevlo	run_rt3070_rf_read(sc, 1, &rf);
5813261868Skevlo	run_rt3070_rf_write(sc, 1, rf & ~(RT3070_RF_BLOCK | RT3070_PLL_PD));
5814261868Skevlo
5815261868Skevlo	run_rt3070_rf_read(sc, 30, &rf);
5816261868Skevlo	rf = (rf & ~0x18) | 0x10;
5817261868Skevlo	run_rt3070_rf_write(sc, 30, rf);
5818261868Skevlo
5819261868Skevlo	/* Apply maximum likelihood detection for 2 stream case. */
5820261868Skevlo	run_bbp_read(sc, 105, &bbp);
5821261868Skevlo	if (sc->nrxchains > 1)
5822261868Skevlo		run_bbp_write(sc, 105, bbp | RT5390_MLD);
5823261868Skevlo
5824261868Skevlo	/* Avoid data lost and CRC error. */
5825261868Skevlo	run_bbp_read(sc, 4, &bbp);
5826261868Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5827261868Skevlo
5828261868Skevlo	run_bbp_write(sc, 92, 0x02);
5829261868Skevlo	run_bbp_write(sc, 82, 0x82);
5830261868Skevlo	run_bbp_write(sc, 106, 0x05);
5831261868Skevlo	run_bbp_write(sc, 104, 0x92);
5832261868Skevlo	run_bbp_write(sc, 88, 0x90);
5833261868Skevlo	run_bbp_write(sc, 148, 0xc8);
5834261868Skevlo	run_bbp_write(sc, 47, 0x48);
5835261868Skevlo	run_bbp_write(sc, 120, 0x50);
5836261868Skevlo
5837261868Skevlo	run_bbp_write(sc, 163, 0x9d);
5838261868Skevlo
5839261868Skevlo	/* SNR mapping. */
5840261868Skevlo	run_bbp_write(sc, 142, 0x06);
5841261868Skevlo	run_bbp_write(sc, 143, 0xa0);
5842261868Skevlo	run_bbp_write(sc, 142, 0x07);
5843261868Skevlo	run_bbp_write(sc, 143, 0xa1);
5844261868Skevlo	run_bbp_write(sc, 142, 0x08);
5845261868Skevlo	run_bbp_write(sc, 143, 0xa2);
5846261868Skevlo
5847261868Skevlo	run_bbp_write(sc, 31, 0x08);
5848261868Skevlo	run_bbp_write(sc, 68, 0x0b);
5849261868Skevlo	run_bbp_write(sc, 105, 0x04);
5850261868Skevlo}
5851261868Skevlo
5852261868Skevlostatic void
5853261868Skevlorun_rt5390_rf_setup(struct run_softc *sc)
5854261868Skevlo{
5855261868Skevlo	uint8_t bbp, rf;
5856261868Skevlo
5857261868Skevlo	if (sc->mac_rev >= 0x0211) {
5858261868Skevlo		/* Enable DC filter. */
5859261868Skevlo		run_bbp_write(sc, 103, 0xc0);
5860261868Skevlo
5861261868Skevlo		if (sc->mac_ver != 0x5592) {
5862261868Skevlo			/* Improve power consumption. */
5863261868Skevlo			run_bbp_read(sc, 31, &bbp);
5864261868Skevlo			run_bbp_write(sc, 31, bbp & ~0x03);
5865261868Skevlo		}
5866261868Skevlo	}
5867261868Skevlo
5868261868Skevlo	run_bbp_read(sc, 138, &bbp);
5869261868Skevlo	if (sc->ntxchains == 1)
5870261868Skevlo		bbp |= 0x20;	/* turn off DAC1 */
5871261868Skevlo	if (sc->nrxchains == 1)
5872261868Skevlo		bbp &= ~0x02;	/* turn off ADC1 */
5873261868Skevlo	run_bbp_write(sc, 138, bbp);
5874261868Skevlo
5875261868Skevlo	run_rt3070_rf_read(sc, 38, &rf);
5876261868Skevlo	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
5877261868Skevlo
5878261868Skevlo	run_rt3070_rf_read(sc, 39, &rf);
5879261868Skevlo	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
5880261868Skevlo
5881261868Skevlo	/* Avoid data lost and CRC error. */
5882261868Skevlo	run_bbp_read(sc, 4, &bbp);
5883261868Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5884261868Skevlo
5885261868Skevlo	run_rt3070_rf_read(sc, 30, &rf);
5886261868Skevlo	rf = (rf & ~0x18) | 0x10;
5887261868Skevlo	run_rt3070_rf_write(sc, 30, rf);
5888261868Skevlo
5889261868Skevlo	if (sc->mac_ver != 0x5592) {
5890261868Skevlo		run_write(sc, RT2860_TX_SW_CFG1, 0);
5891261868Skevlo		if (sc->mac_rev < 0x0211) {
5892261868Skevlo			run_write(sc, RT2860_TX_SW_CFG2,
5893261868Skevlo			    sc->patch_dac ? 0x2c : 0x0f);
5894261868Skevlo		} else
5895261868Skevlo			run_write(sc, RT2860_TX_SW_CFG2, 0);
5896261868Skevlo	}
5897261868Skevlo}
5898261868Skevlo
5899203134Sthompsastatic int
5900203134Sthompsarun_txrx_enable(struct run_softc *sc)
5901203134Sthompsa{
5902203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
5903203134Sthompsa	uint32_t tmp;
5904203134Sthompsa	int error, ntries;
5905203134Sthompsa
5906203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_TX_EN);
5907203134Sthompsa	for (ntries = 0; ntries < 200; ntries++) {
5908203134Sthompsa		if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0)
5909259453Shselasky			return (error);
5910203134Sthompsa		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
5911203134Sthompsa			break;
5912203134Sthompsa		run_delay(sc, 50);
5913203134Sthompsa	}
5914203134Sthompsa	if (ntries == 200)
5915259453Shselasky		return (ETIMEDOUT);
5916203134Sthompsa
5917203134Sthompsa	run_delay(sc, 50);
5918203134Sthompsa
5919203134Sthompsa	tmp |= RT2860_RX_DMA_EN | RT2860_TX_DMA_EN | RT2860_TX_WB_DDONE;
5920203134Sthompsa	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
5921203134Sthompsa
5922203134Sthompsa	/* enable Rx bulk aggregation (set timeout and limit) */
5923203134Sthompsa	tmp = RT2860_USB_TX_EN | RT2860_USB_RX_EN | RT2860_USB_RX_AGG_EN |
5924203134Sthompsa	    RT2860_USB_RX_AGG_TO(128) | RT2860_USB_RX_AGG_LMT(2);
5925203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, tmp);
5926203134Sthompsa
5927203134Sthompsa	/* set Rx filter */
5928203134Sthompsa	tmp = RT2860_DROP_CRC_ERR | RT2860_DROP_PHY_ERR;
5929203134Sthompsa	if (ic->ic_opmode != IEEE80211_M_MONITOR) {
5930203134Sthompsa		tmp |= RT2860_DROP_UC_NOME | RT2860_DROP_DUPL |
5931203134Sthompsa		    RT2860_DROP_CTS | RT2860_DROP_BA | RT2860_DROP_ACK |
5932203134Sthompsa		    RT2860_DROP_VER_ERR | RT2860_DROP_CTRL_RSV |
5933203134Sthompsa		    RT2860_DROP_CFACK | RT2860_DROP_CFEND;
5934203134Sthompsa		if (ic->ic_opmode == IEEE80211_M_STA)
5935203134Sthompsa			tmp |= RT2860_DROP_RTS | RT2860_DROP_PSPOLL;
5936203134Sthompsa	}
5937203134Sthompsa	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
5938203134Sthompsa
5939203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL,
5940203134Sthompsa	    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
5941203134Sthompsa
5942209917Sthompsa	return (0);
5943203134Sthompsa}
5944203134Sthompsa
5945203134Sthompsastatic void
5946259453Shselaskyrun_adjust_freq_offset(struct run_softc *sc)
5947259453Shselasky{
5948259453Shselasky	uint8_t rf, tmp;
5949259453Shselasky
5950259453Shselasky	run_rt3070_rf_read(sc, 17, &rf);
5951259453Shselasky	tmp = rf;
5952259453Shselasky	rf = (rf & ~0x7f) | (sc->freq & 0x7f);
5953259453Shselasky	rf = MIN(rf, 0x5f);
5954259453Shselasky
5955259453Shselasky	if (tmp != rf)
5956259453Shselasky		run_mcu_cmd(sc, 0x74, (tmp << 8 ) | rf);
5957259453Shselasky}
5958259453Shselasky
5959259453Shselaskystatic void
5960203134Sthompsarun_init_locked(struct run_softc *sc)
5961203134Sthompsa{
5962203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
5963203134Sthompsa	struct ieee80211com *ic = ifp->if_l2com;
5964203134Sthompsa	uint32_t tmp;
5965203134Sthompsa	uint8_t bbp1, bbp3;
5966203134Sthompsa	int i;
5967203134Sthompsa	int ridx;
5968203134Sthompsa	int ntries;
5969203134Sthompsa
5970209917Sthompsa	if (ic->ic_nrunning > 1)
5971208019Sthompsa		return;
5972208019Sthompsa
5973203134Sthompsa	run_stop(sc);
5974203134Sthompsa
5975233283Sbschmidt	if (run_load_microcode(sc) != 0) {
5976233283Sbschmidt		device_printf(sc->sc_dev, "could not load 8051 microcode\n");
5977233283Sbschmidt		goto fail;
5978233283Sbschmidt	}
5979233283Sbschmidt
5980203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5981203134Sthompsa		if (run_read(sc, RT2860_ASIC_VER_ID, &tmp) != 0)
5982203134Sthompsa			goto fail;
5983203134Sthompsa		if (tmp != 0 && tmp != 0xffffffff)
5984203134Sthompsa			break;
5985203134Sthompsa		run_delay(sc, 10);
5986203134Sthompsa	}
5987203134Sthompsa	if (ntries == 100)
5988203134Sthompsa		goto fail;
5989203134Sthompsa
5990203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
5991203134Sthompsa		run_setup_tx_list(sc, &sc->sc_epq[i]);
5992203134Sthompsa
5993203134Sthompsa	run_set_macaddr(sc, IF_LLADDR(ifp));
5994203134Sthompsa
5995203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5996203134Sthompsa		if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
5997203134Sthompsa			goto fail;
5998203134Sthompsa		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
5999203134Sthompsa			break;
6000203134Sthompsa		run_delay(sc, 10);
6001203134Sthompsa	}
6002203134Sthompsa	if (ntries == 100) {
6003203138Sthompsa		device_printf(sc->sc_dev, "timeout waiting for DMA engine\n");
6004203134Sthompsa		goto fail;
6005203134Sthompsa	}
6006203134Sthompsa	tmp &= 0xff0;
6007203134Sthompsa	tmp |= RT2860_TX_WB_DDONE;
6008203134Sthompsa	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
6009203134Sthompsa
6010203134Sthompsa	/* turn off PME_OEN to solve high-current issue */
6011203134Sthompsa	run_read(sc, RT2860_SYS_CTRL, &tmp);
6012203134Sthompsa	run_write(sc, RT2860_SYS_CTRL, tmp & ~RT2860_PME_OEN);
6013203134Sthompsa
6014203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL,
6015203134Sthompsa	    RT2860_BBP_HRST | RT2860_MAC_SRST);
6016203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, 0);
6017203134Sthompsa
6018203134Sthompsa	if (run_reset(sc) != 0) {
6019203138Sthompsa		device_printf(sc->sc_dev, "could not reset chipset\n");
6020203134Sthompsa		goto fail;
6021203134Sthompsa	}
6022203134Sthompsa
6023203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
6024203134Sthompsa
6025203134Sthompsa	/* init Tx power for all Tx rates (from EEPROM) */
6026203134Sthompsa	for (ridx = 0; ridx < 5; ridx++) {
6027203134Sthompsa		if (sc->txpow20mhz[ridx] == 0xffffffff)
6028203134Sthompsa			continue;
6029203134Sthompsa		run_write(sc, RT2860_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]);
6030203134Sthompsa	}
6031203134Sthompsa
6032259453Shselasky	for (i = 0; i < nitems(rt2870_def_mac); i++)
6033203134Sthompsa		run_write(sc, rt2870_def_mac[i].reg, rt2870_def_mac[i].val);
6034203134Sthompsa	run_write(sc, RT2860_WMM_AIFSN_CFG, 0x00002273);
6035203134Sthompsa	run_write(sc, RT2860_WMM_CWMIN_CFG, 0x00002344);
6036203134Sthompsa	run_write(sc, RT2860_WMM_CWMAX_CFG, 0x000034aa);
6037203134Sthompsa
6038259453Shselasky	if (sc->mac_ver >= 0x5390) {
6039259453Shselasky		run_write(sc, RT2860_TX_SW_CFG0,
6040259453Shselasky		    4 << RT2860_DLY_PAPE_EN_SHIFT | 4);
6041259453Shselasky		if (sc->mac_ver >= 0x5392) {
6042259453Shselasky			run_write(sc, RT2860_MAX_LEN_CFG, 0x00002fff);
6043259453Shselasky			if (sc->mac_ver == 0x5592) {
6044259453Shselasky				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcba980);
6045259453Shselasky				run_write(sc, RT2860_TXOP_HLDR_ET, 0x00000082);
6046259453Shselasky			} else {
6047259453Shselasky				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcb4980);
6048259453Shselasky				run_write(sc, RT2860_LG_FBK_CFG0, 0xedcba322);
6049259453Shselasky			}
6050259453Shselasky		}
6051261868Skevlo	} else if (sc->mac_ver == 0x3593) {
6052261868Skevlo		run_write(sc, RT2860_TX_SW_CFG0,
6053261868Skevlo		    4 << RT2860_DLY_PAPE_EN_SHIFT | 2);
6054259453Shselasky	} else if (sc->mac_ver >= 0x3070) {
6055203134Sthompsa		/* set delay of PA_PE assertion to 1us (unit of 0.25us) */
6056203134Sthompsa		run_write(sc, RT2860_TX_SW_CFG0,
6057203134Sthompsa		    4 << RT2860_DLY_PAPE_EN_SHIFT);
6058203134Sthompsa	}
6059203134Sthompsa
6060203134Sthompsa	/* wait while MAC is busy */
6061203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
6062203134Sthompsa		if (run_read(sc, RT2860_MAC_STATUS_REG, &tmp) != 0)
6063203134Sthompsa			goto fail;
6064203134Sthompsa		if (!(tmp & (RT2860_RX_STATUS_BUSY | RT2860_TX_STATUS_BUSY)))
6065203134Sthompsa			break;
6066203134Sthompsa		run_delay(sc, 10);
6067203134Sthompsa	}
6068203134Sthompsa	if (ntries == 100)
6069203134Sthompsa		goto fail;
6070203134Sthompsa
6071203134Sthompsa	/* clear Host to MCU mailbox */
6072203134Sthompsa	run_write(sc, RT2860_H2M_BBPAGENT, 0);
6073203134Sthompsa	run_write(sc, RT2860_H2M_MAILBOX, 0);
6074203134Sthompsa	run_delay(sc, 10);
6075203134Sthompsa
6076203134Sthompsa	if (run_bbp_init(sc) != 0) {
6077203138Sthompsa		device_printf(sc->sc_dev, "could not initialize BBP\n");
6078203134Sthompsa		goto fail;
6079203134Sthompsa	}
6080203134Sthompsa
6081203134Sthompsa	/* abort TSF synchronization */
6082203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
6083203134Sthompsa	tmp &= ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
6084203134Sthompsa	    RT2860_TBTT_TIMER_EN);
6085203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
6086203134Sthompsa
6087203134Sthompsa	/* clear RX WCID search table */
6088203134Sthompsa	run_set_region_4(sc, RT2860_WCID_ENTRY(0), 0, 512);
6089203134Sthompsa	/* clear WCID attribute table */
6090203134Sthompsa	run_set_region_4(sc, RT2860_WCID_ATTR(0), 0, 8 * 32);
6091203134Sthompsa
6092209144Sthompsa	/* hostapd sets a key before init. So, don't clear it. */
6093209917Sthompsa	if (sc->cmdq_key_set != RUN_CMDQ_GO) {
6094209144Sthompsa		/* clear shared key table */
6095209144Sthompsa		run_set_region_4(sc, RT2860_SKEY(0, 0), 0, 8 * 32);
6096209144Sthompsa		/* clear shared key mode */
6097209144Sthompsa		run_set_region_4(sc, RT2860_SKEY_MODE_0_7, 0, 4);
6098209144Sthompsa	}
6099209144Sthompsa
6100203134Sthompsa	run_read(sc, RT2860_US_CYC_CNT, &tmp);
6101203134Sthompsa	tmp = (tmp & ~0xff) | 0x1e;
6102203134Sthompsa	run_write(sc, RT2860_US_CYC_CNT, tmp);
6103203134Sthompsa
6104205042Sthompsa	if (sc->mac_rev != 0x0101)
6105203134Sthompsa		run_write(sc, RT2860_TXOP_CTRL_CFG, 0x0000583f);
6106203134Sthompsa
6107203134Sthompsa	run_write(sc, RT2860_WMM_TXOP0_CFG, 0);
6108203134Sthompsa	run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96);
6109203134Sthompsa
6110203134Sthompsa	/* write vendor-specific BBP values (from EEPROM) */
6111261868Skevlo	if (sc->mac_ver < 0x3593) {
6112259453Shselasky		for (i = 0; i < 10; i++) {
6113259453Shselasky			if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff)
6114259453Shselasky				continue;
6115259453Shselasky			run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val);
6116259453Shselasky		}
6117203134Sthompsa	}
6118203134Sthompsa
6119203134Sthompsa	/* select Main antenna for 1T1R devices */
6120259453Shselasky	if (sc->rf_rev == RT3070_RF_3020 || sc->rf_rev == RT5390_RF_5370)
6121203134Sthompsa		run_set_rx_antenna(sc, 0);
6122203134Sthompsa
6123203134Sthompsa	/* send LEDs operating mode to microcontroller */
6124203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0]);
6125203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1]);
6126203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2]);
6127203134Sthompsa
6128259453Shselasky	if (sc->mac_ver >= 0x5390)
6129259453Shselasky		run_rt5390_rf_init(sc);
6130261868Skevlo	else if (sc->mac_ver == 0x3593)
6131261868Skevlo		run_rt3593_rf_init(sc);
6132259453Shselasky	else if (sc->mac_ver >= 0x3070)
6133205042Sthompsa		run_rt3070_rf_init(sc);
6134205042Sthompsa
6135203134Sthompsa	/* disable non-existing Rx chains */
6136203134Sthompsa	run_bbp_read(sc, 3, &bbp3);
6137203134Sthompsa	bbp3 &= ~(1 << 3 | 1 << 4);
6138203134Sthompsa	if (sc->nrxchains == 2)
6139203134Sthompsa		bbp3 |= 1 << 3;
6140203134Sthompsa	else if (sc->nrxchains == 3)
6141203134Sthompsa		bbp3 |= 1 << 4;
6142203134Sthompsa	run_bbp_write(sc, 3, bbp3);
6143203134Sthompsa
6144203134Sthompsa	/* disable non-existing Tx chains */
6145203134Sthompsa	run_bbp_read(sc, 1, &bbp1);
6146203134Sthompsa	if (sc->ntxchains == 1)
6147203134Sthompsa		bbp1 &= ~(1 << 3 | 1 << 4);
6148203134Sthompsa	run_bbp_write(sc, 1, bbp1);
6149203134Sthompsa
6150261868Skevlo	if (sc->mac_ver >= 0x5390)
6151261868Skevlo		run_rt5390_rf_setup(sc);
6152261868Skevlo	else if (sc->mac_ver == 0x3593)
6153261868Skevlo		run_rt3593_rf_setup(sc);
6154261868Skevlo	else if (sc->mac_ver >= 0x3070)
6155205042Sthompsa		run_rt3070_rf_setup(sc);
6156203134Sthompsa
6157203134Sthompsa	/* select default channel */
6158203134Sthompsa	run_set_chan(sc, ic->ic_curchan);
6159203134Sthompsa
6160203134Sthompsa	/* setup initial protection mode */
6161218492Sbschmidt	run_updateprot_cb(ic);
6162203134Sthompsa
6163203134Sthompsa	/* turn radio LED on */
6164203134Sthompsa	run_set_leds(sc, RT2860_LED_RADIO);
6165203134Sthompsa
6166203134Sthompsa	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
6167203134Sthompsa	ifp->if_drv_flags |= IFF_DRV_RUNNING;
6168208019Sthompsa	sc->cmdq_run = RUN_CMDQ_GO;
6169203134Sthompsa
6170209917Sthompsa	for (i = 0; i != RUN_N_XFER; i++)
6171203134Sthompsa		usbd_xfer_set_stall(sc->sc_xfer[i]);
6172203134Sthompsa
6173203134Sthompsa	usbd_transfer_start(sc->sc_xfer[RUN_BULK_RX]);
6174203134Sthompsa
6175203134Sthompsa	if (run_txrx_enable(sc) != 0)
6176203134Sthompsa		goto fail;
6177203134Sthompsa
6178203134Sthompsa	return;
6179203134Sthompsa
6180203134Sthompsafail:
6181203134Sthompsa	run_stop(sc);
6182203134Sthompsa}
6183203134Sthompsa
6184203134Sthompsastatic void
6185203134Sthompsarun_init(void *arg)
6186203134Sthompsa{
6187203134Sthompsa	struct run_softc *sc = arg;
6188203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
6189203134Sthompsa	struct ieee80211com *ic = ifp->if_l2com;
6190203134Sthompsa
6191203134Sthompsa	RUN_LOCK(sc);
6192203134Sthompsa	run_init_locked(sc);
6193203134Sthompsa	RUN_UNLOCK(sc);
6194203134Sthompsa
6195203134Sthompsa	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
6196208019Sthompsa		ieee80211_start_all(ic);
6197203134Sthompsa}
6198203134Sthompsa
6199203134Sthompsastatic void
6200203134Sthompsarun_stop(void *arg)
6201203134Sthompsa{
6202203134Sthompsa	struct run_softc *sc = (struct run_softc *)arg;
6203203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
6204203134Sthompsa	uint32_t tmp;
6205203134Sthompsa	int i;
6206203134Sthompsa	int ntries;
6207203134Sthompsa
6208203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
6209203134Sthompsa
6210203134Sthompsa	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
6211203134Sthompsa		run_set_leds(sc, 0);	/* turn all LEDs off */
6212203134Sthompsa
6213203134Sthompsa	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
6214203134Sthompsa
6215208019Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
6216209144Sthompsa	sc->cmdq_run = sc->cmdq_key_set;
6217208019Sthompsa
6218203134Sthompsa	RUN_UNLOCK(sc);
6219203134Sthompsa
6220203134Sthompsa	for(i = 0; i < RUN_N_XFER; i++)
6221203134Sthompsa		usbd_transfer_drain(sc->sc_xfer[i]);
6222203134Sthompsa
6223203134Sthompsa	RUN_LOCK(sc);
6224203134Sthompsa
6225209917Sthompsa	if (sc->rx_m != NULL) {
6226203134Sthompsa		m_free(sc->rx_m);
6227203134Sthompsa		sc->rx_m = NULL;
6228203134Sthompsa	}
6229203134Sthompsa
6230259453Shselasky	/* Disable Tx/Rx DMA. */
6231259453Shselasky	if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
6232259453Shselasky		return;
6233259453Shselasky	tmp &= ~(RT2860_RX_DMA_EN | RT2860_TX_DMA_EN);
6234259453Shselasky	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
6235259453Shselasky
6236259453Shselasky	for (ntries = 0; ntries < 100; ntries++) {
6237259453Shselasky		if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
6238259453Shselasky			return;
6239259453Shselasky		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
6240259453Shselasky				break;
6241259453Shselasky		run_delay(sc, 10);
6242259453Shselasky	}
6243259453Shselasky	if (ntries == 100) {
6244259453Shselasky		device_printf(sc->sc_dev, "timeout waiting for DMA engine\n");
6245259453Shselasky		return;
6246259453Shselasky	}
6247259453Shselasky
6248203134Sthompsa	/* disable Tx/Rx */
6249203134Sthompsa	run_read(sc, RT2860_MAC_SYS_CTRL, &tmp);
6250203134Sthompsa	tmp &= ~(RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
6251203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, tmp);
6252203134Sthompsa
6253203134Sthompsa	/* wait for pending Tx to complete */
6254203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
6255209917Sthompsa		if (run_read(sc, RT2860_TXRXQ_PCNT, &tmp) != 0) {
6256203134Sthompsa			DPRINTF("Cannot read Tx queue count\n");
6257203134Sthompsa			break;
6258203134Sthompsa		}
6259209917Sthompsa		if ((tmp & RT2860_TX2Q_PCNT_MASK) == 0) {
6260203134Sthompsa			DPRINTF("All Tx cleared\n");
6261203134Sthompsa			break;
6262203134Sthompsa		}
6263203134Sthompsa		run_delay(sc, 10);
6264203134Sthompsa	}
6265209917Sthompsa	if (ntries >= 100)
6266203134Sthompsa		DPRINTF("There are still pending Tx\n");
6267203134Sthompsa	run_delay(sc, 10);
6268203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, 0);
6269203134Sthompsa
6270203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST);
6271203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
6272203134Sthompsa
6273203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
6274203134Sthompsa		run_unsetup_tx_list(sc, &sc->sc_epq[i]);
6275203134Sthompsa}
6276203134Sthompsa
6277203134Sthompsastatic void
6278259453Shselaskyrun_delay(struct run_softc *sc, u_int ms)
6279203134Sthompsa{
6280203134Sthompsa	usb_pause_mtx(mtx_owned(&sc->sc_mtx) ?
6281203134Sthompsa	    &sc->sc_mtx : NULL, USB_MS_TO_TICKS(ms));
6282203134Sthompsa}
6283203134Sthompsa
6284203134Sthompsastatic device_method_t run_methods[] = {
6285203134Sthompsa	/* Device interface */
6286203134Sthompsa	DEVMETHOD(device_probe,		run_match),
6287203134Sthompsa	DEVMETHOD(device_attach,	run_attach),
6288203134Sthompsa	DEVMETHOD(device_detach,	run_detach),
6289246614Shselasky	DEVMETHOD_END
6290203134Sthompsa};
6291203134Sthompsa
6292203134Sthompsastatic driver_t run_driver = {
6293233774Shselasky	.name = "run",
6294233774Shselasky	.methods = run_methods,
6295233774Shselasky	.size = sizeof(struct run_softc)
6296203134Sthompsa};
6297203134Sthompsa
6298203134Sthompsastatic devclass_t run_devclass;
6299203134Sthompsa
6300261868SkevloDRIVER_MODULE(run, uhub, run_driver, run_devclass, run_driver_loaded, NULL);
6301212122SthompsaMODULE_DEPEND(run, wlan, 1, 1, 1);
6302212122SthompsaMODULE_DEPEND(run, usb, 1, 1, 1);
6303212122SthompsaMODULE_DEPEND(run, firmware, 1, 1, 1);
6304212122SthompsaMODULE_VERSION(run, 1);
6305