if_run.c revision 271866
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>
5260219Skevlo * 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: head/sys/dev/usb/wlan/if_run.c 271866 2014-09-19 10:35:56Z glebius $");
22203134Sthompsa
23203134Sthompsa/*-
24257955Skevlo * 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>
51257176Sglebius#include <net/if_var.h>
52203134Sthompsa#include <net/if_arp.h>
53203134Sthompsa#include <net/ethernet.h>
54203134Sthompsa#include <net/if_dl.h>
55203134Sthompsa#include <net/if_media.h>
56203134Sthompsa#include <net/if_types.h>
57203134Sthompsa
58203134Sthompsa#include <netinet/in.h>
59203134Sthompsa#include <netinet/in_systm.h>
60203134Sthompsa#include <netinet/in_var.h>
61203134Sthompsa#include <netinet/if_ether.h>
62203134Sthompsa#include <netinet/ip.h>
63203134Sthompsa
64203134Sthompsa#include <net80211/ieee80211_var.h>
65203134Sthompsa#include <net80211/ieee80211_regdomain.h>
66203134Sthompsa#include <net80211/ieee80211_radiotap.h>
67206358Srpaulo#include <net80211/ieee80211_ratectl.h>
68203134Sthompsa
69203134Sthompsa#include <dev/usb/usb.h>
70203134Sthompsa#include <dev/usb/usbdi.h>
71203134Sthompsa#include "usbdevs.h"
72203134Sthompsa
73259546Skevlo#define	USB_DEBUG_VAR	run_debug
74203134Sthompsa#include <dev/usb/usb_debug.h>
75259812Skevlo#include <dev/usb/usb_msctest.h>
76203134Sthompsa
77220235Skevlo#include <dev/usb/wlan/if_runreg.h>
78220235Skevlo#include <dev/usb/wlan/if_runvar.h>
79203134Sthompsa
80207077Sthompsa#ifdef	USB_DEBUG
81259546Skevlo#define	RUN_DEBUG
82203134Sthompsa#endif
83203134Sthompsa
84203134Sthompsa#ifdef	RUN_DEBUG
85203134Sthompsaint run_debug = 0;
86227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, run, CTLFLAG_RW, 0, "USB run");
87203134SthompsaSYSCTL_INT(_hw_usb_run, OID_AUTO, debug, CTLFLAG_RW, &run_debug, 0,
88203134Sthompsa    "run debug level");
89203134Sthompsa#endif
90203134Sthompsa
91259546Skevlo#define	IEEE80211_HAS_ADDR4(wh)	\
92203134Sthompsa	(((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
93203134Sthompsa
94208019Sthompsa/*
95208019Sthompsa * Because of LOR in run_key_delete(), use atomic instead.
96208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[].
97208019Sthompsa */
98259546Skevlo#define	RUN_CMDQ_GET(c)	(atomic_fetchadd_32((c), 1) & RUN_CMDQ_MASQ)
99208019Sthompsa
100223486Shselaskystatic const STRUCT_USB_HOST_ID run_devs[] = {
101259546Skevlo#define	RUN_DEV(v,p)	{ USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) }
102259812Skevlo#define	RUN_DEV_EJECT(v,p)	\
103262465Skevlo	{ USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RUN_EJECT) }
104262465Skevlo#define	RUN_EJECT	1
105209918Sthompsa    RUN_DEV(ABOCOM,		RT2770),
106209918Sthompsa    RUN_DEV(ABOCOM,		RT2870),
107209918Sthompsa    RUN_DEV(ABOCOM,		RT3070),
108209918Sthompsa    RUN_DEV(ABOCOM,		RT3071),
109209918Sthompsa    RUN_DEV(ABOCOM,		RT3072),
110209918Sthompsa    RUN_DEV(ABOCOM2,		RT2870_1),
111209918Sthompsa    RUN_DEV(ACCTON,		RT2770),
112209918Sthompsa    RUN_DEV(ACCTON,		RT2870_1),
113209918Sthompsa    RUN_DEV(ACCTON,		RT2870_2),
114209918Sthompsa    RUN_DEV(ACCTON,		RT2870_3),
115209918Sthompsa    RUN_DEV(ACCTON,		RT2870_4),
116209918Sthompsa    RUN_DEV(ACCTON,		RT2870_5),
117209918Sthompsa    RUN_DEV(ACCTON,		RT3070),
118209918Sthompsa    RUN_DEV(ACCTON,		RT3070_1),
119209918Sthompsa    RUN_DEV(ACCTON,		RT3070_2),
120209918Sthompsa    RUN_DEV(ACCTON,		RT3070_3),
121209918Sthompsa    RUN_DEV(ACCTON,		RT3070_4),
122209918Sthompsa    RUN_DEV(ACCTON,		RT3070_5),
123209918Sthompsa    RUN_DEV(AIRTIES,		RT3070),
124209918Sthompsa    RUN_DEV(ALLWIN,		RT2070),
125209918Sthompsa    RUN_DEV(ALLWIN,		RT2770),
126209918Sthompsa    RUN_DEV(ALLWIN,		RT2870),
127209918Sthompsa    RUN_DEV(ALLWIN,		RT3070),
128209918Sthompsa    RUN_DEV(ALLWIN,		RT3071),
129209918Sthompsa    RUN_DEV(ALLWIN,		RT3072),
130209918Sthompsa    RUN_DEV(ALLWIN,		RT3572),
131209918Sthompsa    RUN_DEV(AMIGO,		RT2870_1),
132209918Sthompsa    RUN_DEV(AMIGO,		RT2870_2),
133209918Sthompsa    RUN_DEV(AMIT,		CGWLUSB2GNR),
134209918Sthompsa    RUN_DEV(AMIT,		RT2870_1),
135209918Sthompsa    RUN_DEV(AMIT2,		RT2870),
136209918Sthompsa    RUN_DEV(ASUS,		RT2870_1),
137209918Sthompsa    RUN_DEV(ASUS,		RT2870_2),
138209918Sthompsa    RUN_DEV(ASUS,		RT2870_3),
139209918Sthompsa    RUN_DEV(ASUS,		RT2870_4),
140209918Sthompsa    RUN_DEV(ASUS,		RT2870_5),
141209918Sthompsa    RUN_DEV(ASUS,		USBN13),
142209918Sthompsa    RUN_DEV(ASUS,		RT3070_1),
143260219Skevlo    RUN_DEV(ASUS,		USBN66),
144239358Shselasky    RUN_DEV(ASUS,		USB_N53),
145209918Sthompsa    RUN_DEV(ASUS2,		USBN11),
146209918Sthompsa    RUN_DEV(AZUREWAVE,		RT2870_1),
147209918Sthompsa    RUN_DEV(AZUREWAVE,		RT2870_2),
148209918Sthompsa    RUN_DEV(AZUREWAVE,		RT3070_1),
149209918Sthompsa    RUN_DEV(AZUREWAVE,		RT3070_2),
150209918Sthompsa    RUN_DEV(AZUREWAVE,		RT3070_3),
151260219Skevlo    RUN_DEV(BELKIN,		F9L1103),
152209918Sthompsa    RUN_DEV(BELKIN,		F5D8053V3),
153209918Sthompsa    RUN_DEV(BELKIN,		F5D8055),
154226534Shselasky    RUN_DEV(BELKIN,		F5D8055V2),
155209918Sthompsa    RUN_DEV(BELKIN,		F6D4050V1),
156256500Shselasky    RUN_DEV(BELKIN,		F6D4050V2),
157209918Sthompsa    RUN_DEV(BELKIN,		RT2870_1),
158209918Sthompsa    RUN_DEV(BELKIN,		RT2870_2),
159226534Shselasky    RUN_DEV(CISCOLINKSYS,	AE1000),
160209918Sthompsa    RUN_DEV(CISCOLINKSYS2,	RT3070),
161209918Sthompsa    RUN_DEV(CISCOLINKSYS3,	RT3070),
162209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_1),
163209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_2),
164209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_3),
165209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_4),
166209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_5),
167209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_6),
168209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_7),
169209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_8),
170209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT3070_1),
171209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT3070_2),
172209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	VIGORN61),
173209918Sthompsa    RUN_DEV(COREGA,		CGWLUSB300GNM),
174209918Sthompsa    RUN_DEV(COREGA,		RT2870_1),
175209918Sthompsa    RUN_DEV(COREGA,		RT2870_2),
176209918Sthompsa    RUN_DEV(COREGA,		RT2870_3),
177209918Sthompsa    RUN_DEV(COREGA,		RT3070),
178209918Sthompsa    RUN_DEV(CYBERTAN,		RT2870),
179209918Sthompsa    RUN_DEV(DLINK,		RT2870),
180209918Sthompsa    RUN_DEV(DLINK,		RT3072),
181255238Sbr    RUN_DEV(DLINK,		DWA127),
182257955Skevlo    RUN_DEV(DLINK,		DWA140B3),
183259032Skevlo    RUN_DEV(DLINK,		DWA160B2),
184267089Skevlo    RUN_DEV(DLINK,		DWA140D1),
185260219Skevlo    RUN_DEV(DLINK,		DWA162),
186209918Sthompsa    RUN_DEV(DLINK2,		DWA130),
187209918Sthompsa    RUN_DEV(DLINK2,		RT2870_1),
188209918Sthompsa    RUN_DEV(DLINK2,		RT2870_2),
189209918Sthompsa    RUN_DEV(DLINK2,		RT3070_1),
190209918Sthompsa    RUN_DEV(DLINK2,		RT3070_2),
191209918Sthompsa    RUN_DEV(DLINK2,		RT3070_3),
192209918Sthompsa    RUN_DEV(DLINK2,		RT3070_4),
193209918Sthompsa    RUN_DEV(DLINK2,		RT3070_5),
194209918Sthompsa    RUN_DEV(DLINK2,		RT3072),
195209918Sthompsa    RUN_DEV(DLINK2,		RT3072_1),
196209918Sthompsa    RUN_DEV(EDIMAX,		EW7717),
197209918Sthompsa    RUN_DEV(EDIMAX,		EW7718),
198260219Skevlo    RUN_DEV(EDIMAX,		EW7733UND),
199209918Sthompsa    RUN_DEV(EDIMAX,		RT2870_1),
200209918Sthompsa    RUN_DEV(ENCORE,		RT3070_1),
201209918Sthompsa    RUN_DEV(ENCORE,		RT3070_2),
202209918Sthompsa    RUN_DEV(ENCORE,		RT3070_3),
203209918Sthompsa    RUN_DEV(GIGABYTE,		GNWB31N),
204209918Sthompsa    RUN_DEV(GIGABYTE,		GNWB32L),
205209918Sthompsa    RUN_DEV(GIGABYTE,		RT2870_1),
206209918Sthompsa    RUN_DEV(GIGASET,		RT3070_1),
207209918Sthompsa    RUN_DEV(GIGASET,		RT3070_2),
208209918Sthompsa    RUN_DEV(GUILLEMOT,		HWNU300),
209209918Sthompsa    RUN_DEV(HAWKING,		HWUN2),
210209918Sthompsa    RUN_DEV(HAWKING,		RT2870_1),
211209918Sthompsa    RUN_DEV(HAWKING,		RT2870_2),
212209918Sthompsa    RUN_DEV(HAWKING,		RT3070),
213209918Sthompsa    RUN_DEV(IODATA,		RT3072_1),
214209918Sthompsa    RUN_DEV(IODATA,		RT3072_2),
215209918Sthompsa    RUN_DEV(IODATA,		RT3072_3),
216209918Sthompsa    RUN_DEV(IODATA,		RT3072_4),
217209918Sthompsa    RUN_DEV(LINKSYS4,		RT3070),
218209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB100),
219209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB54GCV3),
220209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB600N),
221209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB600NV2),
222209918Sthompsa    RUN_DEV(LOGITEC,		RT2870_1),
223209918Sthompsa    RUN_DEV(LOGITEC,		RT2870_2),
224209918Sthompsa    RUN_DEV(LOGITEC,		RT2870_3),
225230333Shselasky    RUN_DEV(LOGITEC,		LANW300NU2),
226238274Shrs    RUN_DEV(LOGITEC,		LANW150NU2),
227248458Shselasky    RUN_DEV(LOGITEC,		LANW300NU2S),
228209918Sthompsa    RUN_DEV(MELCO,		RT2870_1),
229209918Sthompsa    RUN_DEV(MELCO,		RT2870_2),
230209918Sthompsa    RUN_DEV(MELCO,		WLIUCAG300N),
231209918Sthompsa    RUN_DEV(MELCO,		WLIUCG300N),
232219257Sdaichi    RUN_DEV(MELCO,		WLIUCG301N),
233209918Sthompsa    RUN_DEV(MELCO,		WLIUCGN),
234227781Shselasky    RUN_DEV(MELCO,		WLIUCGNM),
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),
270260219Skevlo    RUN_DEV(RALINK,		RT3573),
271257955Skevlo    RUN_DEV(RALINK,		RT5370),
272259032Skevlo    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),
320263985Shselasky    RUN_DEV(ZYXEL,		RT3070),
321262465Skevlo    RUN_DEV_EJECT(ZYXEL,	NWD2705),
322259812Skevlo    RUN_DEV_EJECT(RALINK,	RT_STOR),
323259812Skevlo#undef RUN_DEV_EJECT
324209918Sthompsa#undef RUN_DEV
325203134Sthompsa};
326203134Sthompsa
327203134Sthompsastatic device_probe_t	run_match;
328203134Sthompsastatic device_attach_t	run_attach;
329203134Sthompsastatic device_detach_t	run_detach;
330203134Sthompsa
331203134Sthompsastatic usb_callback_t	run_bulk_rx_callback;
332203134Sthompsastatic usb_callback_t	run_bulk_tx_callback0;
333203134Sthompsastatic usb_callback_t	run_bulk_tx_callback1;
334203134Sthompsastatic usb_callback_t	run_bulk_tx_callback2;
335203134Sthompsastatic usb_callback_t	run_bulk_tx_callback3;
336203134Sthompsastatic usb_callback_t	run_bulk_tx_callback4;
337203134Sthompsastatic usb_callback_t	run_bulk_tx_callback5;
338203134Sthompsa
339259812Skevlostatic void	run_autoinst(void *, struct usb_device *,
340259812Skevlo		    struct usb_attach_arg *);
341259812Skevlostatic int	run_driver_loaded(struct module *, int, void *);
342203134Sthompsastatic void	run_bulk_tx_callbackN(struct usb_xfer *xfer,
343257429Shselasky		    usb_error_t error, u_int index);
344203134Sthompsastatic struct ieee80211vap *run_vap_create(struct ieee80211com *,
345228621Sbschmidt		    const char [IFNAMSIZ], int, enum ieee80211_opmode, int,
346228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN],
347228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN]);
348203134Sthompsastatic void	run_vap_delete(struct ieee80211vap *);
349208019Sthompsastatic void	run_cmdq_cb(void *, int);
350203134Sthompsastatic void	run_setup_tx_list(struct run_softc *,
351203134Sthompsa		    struct run_endpoint_queue *);
352203134Sthompsastatic void	run_unsetup_tx_list(struct run_softc *,
353203134Sthompsa		    struct run_endpoint_queue *);
354203134Sthompsastatic int	run_load_microcode(struct run_softc *);
355203134Sthompsastatic int	run_reset(struct run_softc *);
356203134Sthompsastatic usb_error_t run_do_request(struct run_softc *,
357203134Sthompsa		    struct usb_device_request *, void *);
358203134Sthompsastatic int	run_read(struct run_softc *, uint16_t, uint32_t *);
359203134Sthompsastatic int	run_read_region_1(struct run_softc *, uint16_t, uint8_t *, int);
360203134Sthompsastatic int	run_write_2(struct run_softc *, uint16_t, uint16_t);
361203134Sthompsastatic int	run_write(struct run_softc *, uint16_t, uint32_t);
362203134Sthompsastatic int	run_write_region_1(struct run_softc *, uint16_t,
363203134Sthompsa		    const uint8_t *, int);
364203134Sthompsastatic int	run_set_region_4(struct run_softc *, uint16_t, uint32_t, int);
365259544Skevlostatic int	run_efuse_read(struct run_softc *, uint16_t, uint16_t *, int);
366203134Sthompsastatic int	run_efuse_read_2(struct run_softc *, uint16_t, uint16_t *);
367203134Sthompsastatic int	run_eeprom_read_2(struct run_softc *, uint16_t, uint16_t *);
368258733Skevlostatic int	run_rt2870_rf_write(struct run_softc *, uint32_t);
369203134Sthompsastatic int	run_rt3070_rf_read(struct run_softc *, uint8_t, uint8_t *);
370203134Sthompsastatic int	run_rt3070_rf_write(struct run_softc *, uint8_t, uint8_t);
371203134Sthompsastatic int	run_bbp_read(struct run_softc *, uint8_t, uint8_t *);
372203134Sthompsastatic int	run_bbp_write(struct run_softc *, uint8_t, uint8_t);
373203134Sthompsastatic int	run_mcu_cmd(struct run_softc *, uint8_t, uint16_t);
374257955Skevlostatic const char *run_get_rf(uint16_t);
375260219Skevlostatic void	run_rt3593_get_txpower(struct run_softc *);
376260219Skevlostatic void	run_get_txpower(struct run_softc *);
377203134Sthompsastatic int	run_read_eeprom(struct run_softc *);
378203134Sthompsastatic struct ieee80211_node *run_node_alloc(struct ieee80211vap *,
379203134Sthompsa			    const uint8_t mac[IEEE80211_ADDR_LEN]);
380203134Sthompsastatic int	run_media_change(struct ifnet *);
381203134Sthompsastatic int	run_newstate(struct ieee80211vap *, enum ieee80211_state, int);
382203134Sthompsastatic int	run_wme_update(struct ieee80211com *);
383208019Sthompsastatic void	run_wme_update_cb(void *);
384203134Sthompsastatic void	run_key_update_begin(struct ieee80211vap *);
385203134Sthompsastatic void	run_key_update_end(struct ieee80211vap *);
386208019Sthompsastatic void	run_key_set_cb(void *);
387208019Sthompsastatic int	run_key_set(struct ieee80211vap *, struct ieee80211_key *,
388257955Skevlo		    const uint8_t mac[IEEE80211_ADDR_LEN]);
389208019Sthompsastatic void	run_key_delete_cb(void *);
390208019Sthompsastatic int	run_key_delete(struct ieee80211vap *, struct ieee80211_key *);
391206358Srpaulostatic void	run_ratectl_to(void *);
392206358Srpaulostatic void	run_ratectl_cb(void *, int);
393208019Sthompsastatic void	run_drain_fifo(void *);
394203134Sthompsastatic void	run_iter_func(void *, struct ieee80211_node *);
395208019Sthompsastatic void	run_newassoc_cb(void *);
396203134Sthompsastatic void	run_newassoc(struct ieee80211_node *, int);
397203134Sthompsastatic void	run_rx_frame(struct run_softc *, struct mbuf *, uint32_t);
398203134Sthompsastatic void	run_tx_free(struct run_endpoint_queue *pq,
399203134Sthompsa		    struct run_tx_data *, int);
400208019Sthompsastatic void	run_set_tx_desc(struct run_softc *, struct run_tx_data *);
401203134Sthompsastatic int	run_tx(struct run_softc *, struct mbuf *,
402203134Sthompsa		    struct ieee80211_node *);
403203134Sthompsastatic int	run_tx_mgt(struct run_softc *, struct mbuf *,
404203134Sthompsa		    struct ieee80211_node *);
405203134Sthompsastatic int	run_sendprot(struct run_softc *, const struct mbuf *,
406203134Sthompsa		    struct ieee80211_node *, int, int);
407203134Sthompsastatic int	run_tx_param(struct run_softc *, struct mbuf *,
408203134Sthompsa		    struct ieee80211_node *,
409203134Sthompsa		    const struct ieee80211_bpf_params *);
410203134Sthompsastatic int	run_raw_xmit(struct ieee80211_node *, struct mbuf *,
411203134Sthompsa		    const struct ieee80211_bpf_params *);
412203134Sthompsastatic void	run_start(struct ifnet *);
413203134Sthompsastatic int	run_ioctl(struct ifnet *, u_long, caddr_t);
414259544Skevlostatic void	run_iq_calib(struct run_softc *, u_int);
415205042Sthompsastatic void	run_set_agc(struct run_softc *, uint8_t);
416203134Sthompsastatic void	run_select_chan_group(struct run_softc *, int);
417203134Sthompsastatic void	run_set_rx_antenna(struct run_softc *, int);
418203134Sthompsastatic void	run_rt2870_set_chan(struct run_softc *, u_int);
419203134Sthompsastatic void	run_rt3070_set_chan(struct run_softc *, u_int);
420205042Sthompsastatic void	run_rt3572_set_chan(struct run_softc *, u_int);
421260219Skevlostatic void	run_rt3593_set_chan(struct run_softc *, u_int);
422257955Skevlostatic void	run_rt5390_set_chan(struct run_softc *, u_int);
423259032Skevlostatic void	run_rt5592_set_chan(struct run_softc *, u_int);
424203134Sthompsastatic int	run_set_chan(struct run_softc *, struct ieee80211_channel *);
425203134Sthompsastatic void	run_set_channel(struct ieee80211com *);
426203134Sthompsastatic void	run_scan_start(struct ieee80211com *);
427203134Sthompsastatic void	run_scan_end(struct ieee80211com *);
428203134Sthompsastatic void	run_update_beacon(struct ieee80211vap *, int);
429208019Sthompsastatic void	run_update_beacon_cb(void *);
430203134Sthompsastatic void	run_updateprot(struct ieee80211com *);
431218492Sbschmidtstatic void	run_updateprot_cb(void *);
432208019Sthompsastatic void	run_usb_timeout_cb(void *);
433203134Sthompsastatic void	run_reset_livelock(struct run_softc *);
434203134Sthompsastatic void	run_enable_tsf_sync(struct run_softc *);
435203134Sthompsastatic void	run_enable_mrr(struct run_softc *);
436203134Sthompsastatic void	run_set_txpreamble(struct run_softc *);
437203134Sthompsastatic void	run_set_basicrates(struct run_softc *);
438203134Sthompsastatic void	run_set_leds(struct run_softc *, uint16_t);
439203134Sthompsastatic void	run_set_bssid(struct run_softc *, const uint8_t *);
440203134Sthompsastatic void	run_set_macaddr(struct run_softc *, const uint8_t *);
441203134Sthompsastatic void	run_updateslot(struct ifnet *);
442218492Sbschmidtstatic void	run_updateslot_cb(void *);
443208019Sthompsastatic void	run_update_mcast(struct ifnet *);
444203134Sthompsastatic int8_t	run_rssi2dbm(struct run_softc *, uint8_t, uint8_t);
445203134Sthompsastatic void	run_update_promisc_locked(struct ifnet *);
446203134Sthompsastatic void	run_update_promisc(struct ifnet *);
447257955Skevlostatic void	run_rt5390_bbp_init(struct run_softc *);
448203134Sthompsastatic int	run_bbp_init(struct run_softc *);
449203134Sthompsastatic int	run_rt3070_rf_init(struct run_softc *);
450260219Skevlostatic void	run_rt3593_rf_init(struct run_softc *);
451257955Skevlostatic void	run_rt5390_rf_init(struct run_softc *);
452203134Sthompsastatic int	run_rt3070_filter_calib(struct run_softc *, uint8_t, uint8_t,
453203134Sthompsa		    uint8_t *);
454205042Sthompsastatic void	run_rt3070_rf_setup(struct run_softc *);
455260219Skevlostatic void	run_rt3593_rf_setup(struct run_softc *);
456260219Skevlostatic void	run_rt5390_rf_setup(struct run_softc *);
457203134Sthompsastatic int	run_txrx_enable(struct run_softc *);
458257955Skevlostatic void	run_adjust_freq_offset(struct run_softc *);
459203134Sthompsastatic void	run_init(void *);
460203134Sthompsastatic void	run_init_locked(struct run_softc *);
461203134Sthompsastatic void	run_stop(void *);
462257429Shselaskystatic void	run_delay(struct run_softc *, u_int);
463203134Sthompsa
464259812Skevlostatic eventhandler_tag run_etag;
465259812Skevlo
466259544Skevlostatic const struct rt2860_rate {
467259544Skevlo	uint8_t		rate;
468259544Skevlo	uint8_t		mcs;
469259544Skevlo	enum		ieee80211_phytype phy;
470259544Skevlo	uint8_t		ctl_ridx;
471259544Skevlo	uint16_t	sp_ack_dur;
472259544Skevlo	uint16_t	lp_ack_dur;
473259544Skevlo} rt2860_rates[] = {
474259544Skevlo	{   2, 0, IEEE80211_T_DS,   0, 314, 314 },
475259544Skevlo	{   4, 1, IEEE80211_T_DS,   1, 258, 162 },
476259544Skevlo	{  11, 2, IEEE80211_T_DS,   2, 223, 127 },
477259544Skevlo	{  22, 3, IEEE80211_T_DS,   3, 213, 117 },
478259544Skevlo	{  12, 0, IEEE80211_T_OFDM, 4,  60,  60 },
479259544Skevlo	{  18, 1, IEEE80211_T_OFDM, 4,  52,  52 },
480259544Skevlo	{  24, 2, IEEE80211_T_OFDM, 6,  48,  48 },
481259544Skevlo	{  36, 3, IEEE80211_T_OFDM, 6,  44,  44 },
482259544Skevlo	{  48, 4, IEEE80211_T_OFDM, 8,  44,  44 },
483259544Skevlo	{  72, 5, IEEE80211_T_OFDM, 8,  40,  40 },
484259544Skevlo	{  96, 6, IEEE80211_T_OFDM, 8,  40,  40 },
485259544Skevlo	{ 108, 7, IEEE80211_T_OFDM, 8,  40,  40 }
486259544Skevlo};
487259544Skevlo
488203134Sthompsastatic const struct {
489208019Sthompsa	uint16_t	reg;
490203134Sthompsa	uint32_t	val;
491203134Sthompsa} rt2870_def_mac[] = {
492203134Sthompsa	RT2870_DEF_MAC
493203134Sthompsa};
494203134Sthompsa
495203134Sthompsastatic const struct {
496203134Sthompsa	uint8_t	reg;
497203134Sthompsa	uint8_t	val;
498203134Sthompsa} rt2860_def_bbp[] = {
499203134Sthompsa	RT2860_DEF_BBP
500257955Skevlo},rt5390_def_bbp[] = {
501257955Skevlo	RT5390_DEF_BBP
502259032Skevlo},rt5592_def_bbp[] = {
503259032Skevlo	RT5592_DEF_BBP
504203134Sthompsa};
505203134Sthompsa
506259032Skevlo/*
507259032Skevlo * Default values for BBP register R196 for RT5592.
508259032Skevlo */
509259032Skevlostatic const uint8_t rt5592_bbp_r196[] = {
510259032Skevlo	0xe0, 0x1f, 0x38, 0x32, 0x08, 0x28, 0x19, 0x0a, 0xff, 0x00,
511259032Skevlo	0x16, 0x10, 0x10, 0x0b, 0x36, 0x2c, 0x26, 0x24, 0x42, 0x36,
512259032Skevlo	0x30, 0x2d, 0x4c, 0x46, 0x3d, 0x40, 0x3e, 0x42, 0x3d, 0x40,
513259032Skevlo	0x3c, 0x34, 0x2c, 0x2f, 0x3c, 0x35, 0x2e, 0x2a, 0x49, 0x41,
514259032Skevlo	0x36, 0x31, 0x30, 0x30, 0x0e, 0x0d, 0x28, 0x21, 0x1c, 0x16,
515259032Skevlo	0x50, 0x4a, 0x43, 0x40, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00,
516259032Skevlo	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
517259032Skevlo	0x00, 0x00, 0x7d, 0x14, 0x32, 0x2c, 0x36, 0x4c, 0x43, 0x2c,
518259032Skevlo	0x2e, 0x36, 0x30, 0x6e
519259032Skevlo};
520259032Skevlo
521203134Sthompsastatic const struct rfprog {
522203134Sthompsa	uint8_t		chan;
523203134Sthompsa	uint32_t	r1, r2, r3, r4;
524203134Sthompsa} rt2860_rf2850[] = {
525203134Sthompsa	RT2860_RF2850
526203134Sthompsa};
527203134Sthompsa
528203134Sthompsastruct {
529203134Sthompsa	uint8_t	n, r, k;
530205042Sthompsa} rt3070_freqs[] = {
531205042Sthompsa	RT3070_RF3052
532203134Sthompsa};
533203134Sthompsa
534259032Skevlostatic const struct rt5592_freqs {
535259032Skevlo	uint16_t	n;
536259032Skevlo	uint8_t		k, m, r;
537259032Skevlo} rt5592_freqs_20mhz[] = {
538259032Skevlo	RT5592_RF5592_20MHZ
539259032Skevlo},rt5592_freqs_40mhz[] = {
540259032Skevlo	RT5592_RF5592_40MHZ
541259032Skevlo};
542259032Skevlo
543203134Sthompsastatic const struct {
544203134Sthompsa	uint8_t	reg;
545203134Sthompsa	uint8_t	val;
546203134Sthompsa} rt3070_def_rf[] = {
547203134Sthompsa	RT3070_DEF_RF
548205042Sthompsa},rt3572_def_rf[] = {
549205042Sthompsa	RT3572_DEF_RF
550260219Skevlo},rt3593_def_rf[] = {
551260219Skevlo	RT3593_DEF_RF
552257955Skevlo},rt5390_def_rf[] = {
553257955Skevlo	RT5390_DEF_RF
554257955Skevlo},rt5392_def_rf[] = {
555257955Skevlo	RT5392_DEF_RF
556259032Skevlo},rt5592_def_rf[] = {
557259032Skevlo	RT5592_DEF_RF
558259032Skevlo},rt5592_2ghz_def_rf[] = {
559259032Skevlo	RT5592_2GHZ_DEF_RF
560259032Skevlo},rt5592_5ghz_def_rf[] = {
561259032Skevlo	RT5592_5GHZ_DEF_RF
562203134Sthompsa};
563203134Sthompsa
564259032Skevlostatic const struct {
565259032Skevlo	u_int	firstchan;
566259032Skevlo	u_int	lastchan;
567259032Skevlo	uint8_t	reg;
568259032Skevlo	uint8_t	val;
569259032Skevlo} rt5592_chan_5ghz[] = {
570259032Skevlo	RT5592_CHAN_5GHZ
571259032Skevlo};
572259032Skevlo
573203134Sthompsastatic const struct usb_config run_config[RUN_N_XFER] = {
574203134Sthompsa    [RUN_BULK_TX_BE] = {
575203134Sthompsa	.type = UE_BULK,
576203134Sthompsa	.endpoint = UE_ADDR_ANY,
577203134Sthompsa	.ep_index = 0,
578203134Sthompsa	.direction = UE_DIR_OUT,
579203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
580203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
581203134Sthompsa	.callback = run_bulk_tx_callback0,
582203134Sthompsa	.timeout = 5000,	/* ms */
583203134Sthompsa    },
584203134Sthompsa    [RUN_BULK_TX_BK] = {
585203134Sthompsa	.type = UE_BULK,
586203134Sthompsa	.endpoint = UE_ADDR_ANY,
587203134Sthompsa	.direction = UE_DIR_OUT,
588203134Sthompsa	.ep_index = 1,
589203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
590203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
591203134Sthompsa	.callback = run_bulk_tx_callback1,
592203134Sthompsa	.timeout = 5000,	/* ms */
593203134Sthompsa    },
594203134Sthompsa    [RUN_BULK_TX_VI] = {
595203134Sthompsa	.type = UE_BULK,
596203134Sthompsa	.endpoint = UE_ADDR_ANY,
597203134Sthompsa	.direction = UE_DIR_OUT,
598203134Sthompsa	.ep_index = 2,
599203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
600203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
601203134Sthompsa	.callback = run_bulk_tx_callback2,
602203134Sthompsa	.timeout = 5000,	/* ms */
603203134Sthompsa    },
604203134Sthompsa    [RUN_BULK_TX_VO] = {
605203134Sthompsa	.type = UE_BULK,
606203134Sthompsa	.endpoint = UE_ADDR_ANY,
607203134Sthompsa	.direction = UE_DIR_OUT,
608203134Sthompsa	.ep_index = 3,
609203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
610203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
611203134Sthompsa	.callback = run_bulk_tx_callback3,
612203134Sthompsa	.timeout = 5000,	/* ms */
613203134Sthompsa    },
614203134Sthompsa    [RUN_BULK_TX_HCCA] = {
615203134Sthompsa	.type = UE_BULK,
616203134Sthompsa	.endpoint = UE_ADDR_ANY,
617203134Sthompsa	.direction = UE_DIR_OUT,
618203134Sthompsa	.ep_index = 4,
619203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
620203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
621203134Sthompsa	.callback = run_bulk_tx_callback4,
622203134Sthompsa	.timeout = 5000,	/* ms */
623203134Sthompsa    },
624203134Sthompsa    [RUN_BULK_TX_PRIO] = {
625203134Sthompsa	.type = UE_BULK,
626203134Sthompsa	.endpoint = UE_ADDR_ANY,
627203134Sthompsa	.direction = UE_DIR_OUT,
628203134Sthompsa	.ep_index = 5,
629203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
630203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
631203134Sthompsa	.callback = run_bulk_tx_callback5,
632203134Sthompsa	.timeout = 5000,	/* ms */
633203134Sthompsa    },
634203134Sthompsa    [RUN_BULK_RX] = {
635203134Sthompsa	.type = UE_BULK,
636203134Sthompsa	.endpoint = UE_ADDR_ANY,
637203134Sthompsa	.direction = UE_DIR_IN,
638203134Sthompsa	.bufsize = RUN_MAX_RXSZ,
639203134Sthompsa	.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
640203134Sthompsa	.callback = run_bulk_rx_callback,
641203134Sthompsa    }
642203134Sthompsa};
643203134Sthompsa
644259812Skevlostatic void
645259812Skevlorun_autoinst(void *arg, struct usb_device *udev,
646259812Skevlo    struct usb_attach_arg *uaa)
647259812Skevlo{
648259812Skevlo	struct usb_interface *iface;
649259812Skevlo	struct usb_interface_descriptor *id;
650259812Skevlo
651259812Skevlo	if (uaa->dev_state != UAA_DEV_READY)
652259812Skevlo		return;
653259812Skevlo
654259812Skevlo	iface = usbd_get_iface(udev, 0);
655259812Skevlo	if (iface == NULL)
656259812Skevlo		return;
657259812Skevlo	id = iface->idesc;
658259812Skevlo	if (id == NULL || id->bInterfaceClass != UICLASS_MASS)
659259812Skevlo		return;
660259812Skevlo	if (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa))
661259812Skevlo		return;
662259812Skevlo
663259812Skevlo	if (usb_msc_eject(udev, 0, MSC_EJECT_STOPUNIT) == 0)
664259812Skevlo		uaa->dev_state = UAA_DEV_EJECTING;
665259812Skevlo}
666259812Skevlo
667220235Skevlostatic int
668259812Skevlorun_driver_loaded(struct module *mod, int what, void *arg)
669259812Skevlo{
670259812Skevlo	switch (what) {
671259812Skevlo	case MOD_LOAD:
672259812Skevlo		run_etag = EVENTHANDLER_REGISTER(usb_dev_configured,
673259812Skevlo		    run_autoinst, NULL, EVENTHANDLER_PRI_ANY);
674259812Skevlo		break;
675259812Skevlo	case MOD_UNLOAD:
676259812Skevlo		EVENTHANDLER_DEREGISTER(usb_dev_configured, run_etag);
677259812Skevlo		break;
678259812Skevlo	default:
679259812Skevlo		return (EOPNOTSUPP);
680259812Skevlo	}
681259812Skevlo	return (0);
682259812Skevlo}
683259812Skevlo
684259812Skevlostatic int
685203134Sthompsarun_match(device_t self)
686203134Sthompsa{
687203134Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(self);
688203134Sthompsa
689203134Sthompsa	if (uaa->usb_mode != USB_MODE_HOST)
690203134Sthompsa		return (ENXIO);
691203134Sthompsa	if (uaa->info.bConfigIndex != 0)
692203134Sthompsa		return (ENXIO);
693203134Sthompsa	if (uaa->info.bIfaceIndex != RT2860_IFACE_INDEX)
694203134Sthompsa		return (ENXIO);
695203134Sthompsa
696203134Sthompsa	return (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa));
697203134Sthompsa}
698203134Sthompsa
699203134Sthompsastatic int
700203134Sthompsarun_attach(device_t self)
701203134Sthompsa{
702203134Sthompsa	struct run_softc *sc = device_get_softc(self);
703203134Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(self);
704203134Sthompsa	struct ieee80211com *ic;
705203134Sthompsa	struct ifnet *ifp;
706205042Sthompsa	uint32_t ver;
707258082Skevlo	int ntries, error;
708203134Sthompsa	uint8_t iface_index, bands;
709203134Sthompsa
710203134Sthompsa	device_set_usb_desc(self);
711203134Sthompsa	sc->sc_udev = uaa->device;
712203134Sthompsa	sc->sc_dev = self;
713262465Skevlo	if (USB_GET_DRIVER_INFO(uaa) != RUN_EJECT)
714262465Skevlo		sc->sc_flags |= RUN_FLAG_FWLOAD_NEEDED;
715203134Sthompsa
716203134Sthompsa	mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev),
717203134Sthompsa	    MTX_NETWORK_LOCK, MTX_DEF);
718203134Sthompsa
719203134Sthompsa	iface_index = RT2860_IFACE_INDEX;
720208019Sthompsa
721203134Sthompsa	error = usbd_transfer_setup(uaa->device, &iface_index,
722203134Sthompsa	    sc->sc_xfer, run_config, RUN_N_XFER, sc, &sc->sc_mtx);
723203134Sthompsa	if (error) {
724205042Sthompsa		device_printf(self, "could not allocate USB transfers, "
725203134Sthompsa		    "err=%s\n", usbd_errstr(error));
726203134Sthompsa		goto detach;
727203134Sthompsa	}
728203134Sthompsa
729203134Sthompsa	RUN_LOCK(sc);
730203134Sthompsa
731203134Sthompsa	/* wait for the chip to settle */
732203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
733209917Sthompsa		if (run_read(sc, RT2860_ASIC_VER_ID, &ver) != 0) {
734203134Sthompsa			RUN_UNLOCK(sc);
735203134Sthompsa			goto detach;
736203134Sthompsa		}
737205042Sthompsa		if (ver != 0 && ver != 0xffffffff)
738203134Sthompsa			break;
739203134Sthompsa		run_delay(sc, 10);
740203134Sthompsa	}
741203134Sthompsa	if (ntries == 100) {
742203138Sthompsa		device_printf(sc->sc_dev,
743203138Sthompsa		    "timeout waiting for NIC to initialize\n");
744203134Sthompsa		RUN_UNLOCK(sc);
745203134Sthompsa		goto detach;
746203134Sthompsa	}
747205042Sthompsa	sc->mac_ver = ver >> 16;
748205042Sthompsa	sc->mac_rev = ver & 0xffff;
749203134Sthompsa
750203134Sthompsa	/* retrieve RF rev. no and various other things from EEPROM */
751203134Sthompsa	run_read_eeprom(sc);
752203134Sthompsa
753203138Sthompsa	device_printf(sc->sc_dev,
754203138Sthompsa	    "MAC/BBP RT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), address %s\n",
755205042Sthompsa	    sc->mac_ver, sc->mac_rev, run_get_rf(sc->rf_rev),
756203138Sthompsa	    sc->ntxchains, sc->nrxchains, ether_sprintf(sc->sc_bssid));
757203134Sthompsa
758203134Sthompsa	RUN_UNLOCK(sc);
759203134Sthompsa
760203134Sthompsa	ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
761220235Skevlo	if (ifp == NULL) {
762203138Sthompsa		device_printf(sc->sc_dev, "can not if_alloc()\n");
763203134Sthompsa		goto detach;
764203134Sthompsa	}
765203134Sthompsa	ic = ifp->if_l2com;
766203134Sthompsa
767203134Sthompsa	ifp->if_softc = sc;
768203134Sthompsa	if_initname(ifp, "run", device_get_unit(sc->sc_dev));
769203134Sthompsa	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
770203134Sthompsa	ifp->if_init = run_init;
771203134Sthompsa	ifp->if_ioctl = run_ioctl;
772203134Sthompsa	ifp->if_start = run_start;
773207554Ssobomax	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
774207554Ssobomax	ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
775203134Sthompsa	IFQ_SET_READY(&ifp->if_snd);
776203134Sthompsa
777203134Sthompsa	ic->ic_ifp = ifp;
778203134Sthompsa	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
779203134Sthompsa	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
780208019Sthompsa
781203134Sthompsa	/* set device capabilities */
782203134Sthompsa	ic->ic_caps =
783203134Sthompsa	    IEEE80211_C_STA |		/* station mode supported */
784203134Sthompsa	    IEEE80211_C_MONITOR |	/* monitor mode supported */
785203134Sthompsa	    IEEE80211_C_IBSS |
786203134Sthompsa	    IEEE80211_C_HOSTAP |
787208019Sthompsa	    IEEE80211_C_WDS |		/* 4-address traffic works */
788208019Sthompsa	    IEEE80211_C_MBSS |
789203134Sthompsa	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
790203134Sthompsa	    IEEE80211_C_SHSLOT |	/* short slot time supported */
791203134Sthompsa	    IEEE80211_C_WME |		/* WME */
792214894Sbschmidt	    IEEE80211_C_WPA;		/* WPA1|WPA2(RSN) */
793203134Sthompsa
794203134Sthompsa	ic->ic_cryptocaps =
795203134Sthompsa	    IEEE80211_CRYPTO_WEP |
796203134Sthompsa	    IEEE80211_CRYPTO_AES_CCM |
797203134Sthompsa	    IEEE80211_CRYPTO_TKIPMIC |
798203134Sthompsa	    IEEE80211_CRYPTO_TKIP;
799203134Sthompsa
800203134Sthompsa	ic->ic_flags |= IEEE80211_F_DATAPAD;
801203134Sthompsa	ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;
802203134Sthompsa
803203134Sthompsa	bands = 0;
804203134Sthompsa	setbit(&bands, IEEE80211_MODE_11B);
805203134Sthompsa	setbit(&bands, IEEE80211_MODE_11G);
806258082Skevlo	if (sc->rf_rev == RT2860_RF_2750 || sc->rf_rev == RT2860_RF_2850 ||
807260219Skevlo	    sc->rf_rev == RT3070_RF_3052 || sc->rf_rev == RT3593_RF_3053 ||
808260219Skevlo	    sc->rf_rev == RT5592_RF_5592)
809258082Skevlo		setbit(&bands, IEEE80211_MODE_11A);
810203134Sthompsa	ieee80211_init_channels(ic, NULL, &bands);
811203134Sthompsa
812203134Sthompsa	ieee80211_ifattach(ic, sc->sc_bssid);
813203134Sthompsa
814203134Sthompsa	ic->ic_scan_start = run_scan_start;
815203134Sthompsa	ic->ic_scan_end = run_scan_end;
816203134Sthompsa	ic->ic_set_channel = run_set_channel;
817203134Sthompsa	ic->ic_node_alloc = run_node_alloc;
818203134Sthompsa	ic->ic_newassoc = run_newassoc;
819218492Sbschmidt	ic->ic_updateslot = run_updateslot;
820208019Sthompsa	ic->ic_update_mcast = run_update_mcast;
821203134Sthompsa	ic->ic_wme.wme_update = run_wme_update;
822203134Sthompsa	ic->ic_raw_xmit = run_raw_xmit;
823203134Sthompsa	ic->ic_update_promisc = run_update_promisc;
824203134Sthompsa
825203134Sthompsa	ic->ic_vap_create = run_vap_create;
826203134Sthompsa	ic->ic_vap_delete = run_vap_delete;
827203134Sthompsa
828203134Sthompsa	ieee80211_radiotap_attach(ic,
829203134Sthompsa	    &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap),
830203134Sthompsa		RUN_TX_RADIOTAP_PRESENT,
831203134Sthompsa	    &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap),
832203134Sthompsa		RUN_RX_RADIOTAP_PRESENT);
833203134Sthompsa
834208019Sthompsa	TASK_INIT(&sc->cmdq_task, 0, run_cmdq_cb, sc);
835208019Sthompsa	TASK_INIT(&sc->ratectl_task, 0, run_ratectl_cb, sc);
836257712Shselasky	usb_callout_init_mtx(&sc->ratectl_ch, &sc->sc_mtx, 0);
837208019Sthompsa
838203134Sthompsa	if (bootverbose)
839203134Sthompsa		ieee80211_announce(ic);
840203134Sthompsa
841209917Sthompsa	return (0);
842203134Sthompsa
843203134Sthompsadetach:
844203134Sthompsa	run_detach(self);
845209917Sthompsa	return (ENXIO);
846203134Sthompsa}
847203134Sthompsa
848203134Sthompsastatic int
849203134Sthompsarun_detach(device_t self)
850203134Sthompsa{
851203134Sthompsa	struct run_softc *sc = device_get_softc(self);
852203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
853203134Sthompsa	struct ieee80211com *ic;
854203134Sthompsa	int i;
855203134Sthompsa
856246614Shselasky	RUN_LOCK(sc);
857246614Shselasky	sc->sc_detached = 1;
858246614Shselasky	RUN_UNLOCK(sc);
859246614Shselasky
860203134Sthompsa	/* stop all USB transfers */
861203134Sthompsa	usbd_transfer_unsetup(sc->sc_xfer, RUN_N_XFER);
862203134Sthompsa
863203134Sthompsa	RUN_LOCK(sc);
864209144Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
865209144Sthompsa	sc->cmdq_run = sc->cmdq_key_set = RUN_CMDQ_ABORT;
866209144Sthompsa
867203134Sthompsa	/* free TX list, if any */
868203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
869203134Sthompsa		run_unsetup_tx_list(sc, &sc->sc_epq[i]);
870203134Sthompsa	RUN_UNLOCK(sc);
871203134Sthompsa
872203134Sthompsa	if (ifp) {
873203134Sthompsa		ic = ifp->if_l2com;
874208019Sthompsa		/* drain tasks */
875208019Sthompsa		usb_callout_drain(&sc->ratectl_ch);
876208019Sthompsa		ieee80211_draintask(ic, &sc->cmdq_task);
877208019Sthompsa		ieee80211_draintask(ic, &sc->ratectl_task);
878203134Sthompsa		ieee80211_ifdetach(ic);
879203134Sthompsa		if_free(ifp);
880203134Sthompsa	}
881203134Sthompsa
882203134Sthompsa	mtx_destroy(&sc->sc_mtx);
883203134Sthompsa
884203134Sthompsa	return (0);
885203134Sthompsa}
886203134Sthompsa
887203134Sthompsastatic struct ieee80211vap *
888228621Sbschmidtrun_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
889228621Sbschmidt    enum ieee80211_opmode opmode, int flags,
890203134Sthompsa    const uint8_t bssid[IEEE80211_ADDR_LEN],
891203134Sthompsa    const uint8_t mac[IEEE80211_ADDR_LEN])
892203134Sthompsa{
893208019Sthompsa	struct ifnet *ifp = ic->ic_ifp;
894208019Sthompsa	struct run_softc *sc = ifp->if_softc;
895203134Sthompsa	struct run_vap *rvp;
896203134Sthompsa	struct ieee80211vap *vap;
897208019Sthompsa	int i;
898203134Sthompsa
899209917Sthompsa	if (sc->rvp_cnt >= RUN_VAP_MAX) {
900208019Sthompsa		if_printf(ifp, "number of VAPs maxed out\n");
901209917Sthompsa		return (NULL);
902208019Sthompsa	}
903208019Sthompsa
904208019Sthompsa	switch (opmode) {
905208019Sthompsa	case IEEE80211_M_STA:
906208019Sthompsa		/* enable s/w bmiss handling for sta mode */
907208019Sthompsa		flags |= IEEE80211_CLONE_NOBEACONS;
908208019Sthompsa		/* fall though */
909208019Sthompsa	case IEEE80211_M_IBSS:
910208019Sthompsa	case IEEE80211_M_MONITOR:
911208019Sthompsa	case IEEE80211_M_HOSTAP:
912208019Sthompsa	case IEEE80211_M_MBSS:
913208019Sthompsa		/* other than WDS vaps, only one at a time */
914208019Sthompsa		if (!TAILQ_EMPTY(&ic->ic_vaps))
915209917Sthompsa			return (NULL);
916208019Sthompsa		break;
917208019Sthompsa	case IEEE80211_M_WDS:
918208019Sthompsa		TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next){
919208019Sthompsa			if(vap->iv_opmode != IEEE80211_M_HOSTAP)
920208019Sthompsa				continue;
921208019Sthompsa			/* WDS vap's always share the local mac address. */
922208019Sthompsa			flags &= ~IEEE80211_CLONE_BSSID;
923208019Sthompsa			break;
924208019Sthompsa		}
925209917Sthompsa		if (vap == NULL) {
926208019Sthompsa			if_printf(ifp, "wds only supported in ap mode\n");
927209917Sthompsa			return (NULL);
928208019Sthompsa		}
929208019Sthompsa		break;
930208019Sthompsa	default:
931208019Sthompsa		if_printf(ifp, "unknown opmode %d\n", opmode);
932209917Sthompsa		return (NULL);
933208019Sthompsa	}
934208019Sthompsa
935208019Sthompsa	rvp = (struct run_vap *) malloc(sizeof(struct run_vap),
936203134Sthompsa	    M_80211_VAP, M_NOWAIT | M_ZERO);
937203134Sthompsa	if (rvp == NULL)
938209917Sthompsa		return (NULL);
939203134Sthompsa	vap = &rvp->vap;
940203134Sthompsa
941257743Shselasky	if (ieee80211_vap_setup(ic, vap, name, unit,
942257743Shselasky	    opmode, flags, bssid, mac) != 0) {
943257743Shselasky		/* out of memory */
944257743Shselasky		free(rvp, M_80211_VAP);
945257743Shselasky		return (NULL);
946257743Shselasky	}
947257743Shselasky
948203134Sthompsa	vap->iv_key_update_begin = run_key_update_begin;
949203134Sthompsa	vap->iv_key_update_end = run_key_update_end;
950203134Sthompsa	vap->iv_update_beacon = run_update_beacon;
951208019Sthompsa	vap->iv_max_aid = RT2870_WCID_MAX;
952208019Sthompsa	/*
953208019Sthompsa	 * To delete the right key from h/w, we need wcid.
954208019Sthompsa	 * Luckily, there is unused space in ieee80211_key{}, wk_pad,
955208019Sthompsa	 * and matching wcid will be written into there. So, cast
956208019Sthompsa	 * some spells to remove 'const' from ieee80211_key{}
957208019Sthompsa	 */
958208019Sthompsa	vap->iv_key_delete = (void *)run_key_delete;
959208019Sthompsa	vap->iv_key_set = (void *)run_key_set;
960203134Sthompsa
961203134Sthompsa	/* override state transition machine */
962203134Sthompsa	rvp->newstate = vap->iv_newstate;
963203134Sthompsa	vap->iv_newstate = run_newstate;
964203134Sthompsa
965206358Srpaulo	ieee80211_ratectl_init(vap);
966206358Srpaulo	ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */);
967203134Sthompsa
968203134Sthompsa	/* complete setup */
969203134Sthompsa	ieee80211_vap_attach(vap, run_media_change, ieee80211_media_status);
970208019Sthompsa
971208019Sthompsa	/* make sure id is always unique */
972209917Sthompsa	for (i = 0; i < RUN_VAP_MAX; i++) {
973208019Sthompsa		if((sc->rvp_bmap & 1 << i) == 0){
974208019Sthompsa			sc->rvp_bmap |= 1 << i;
975208019Sthompsa			rvp->rvp_id = i;
976208019Sthompsa			break;
977208019Sthompsa		}
978208019Sthompsa	}
979209917Sthompsa	if (sc->rvp_cnt++ == 0)
980208019Sthompsa		ic->ic_opmode = opmode;
981208019Sthompsa
982209917Sthompsa	if (opmode == IEEE80211_M_HOSTAP)
983209144Sthompsa		sc->cmdq_run = RUN_CMDQ_GO;
984209144Sthompsa
985208019Sthompsa	DPRINTF("rvp_id=%d bmap=%x rvp_cnt=%d\n",
986208019Sthompsa	    rvp->rvp_id, sc->rvp_bmap, sc->rvp_cnt);
987208019Sthompsa
988209917Sthompsa	return (vap);
989203134Sthompsa}
990203134Sthompsa
991203134Sthompsastatic void
992203134Sthompsarun_vap_delete(struct ieee80211vap *vap)
993203134Sthompsa{
994203134Sthompsa	struct run_vap *rvp = RUN_VAP(vap);
995203134Sthompsa	struct ifnet *ifp;
996203134Sthompsa	struct ieee80211com *ic;
997203134Sthompsa	struct run_softc *sc;
998208019Sthompsa	uint8_t rvp_id;
999203134Sthompsa
1000209917Sthompsa	if (vap == NULL)
1001203134Sthompsa		return;
1002203134Sthompsa
1003203134Sthompsa	ic = vap->iv_ic;
1004203134Sthompsa	ifp = ic->ic_ifp;
1005203134Sthompsa
1006203134Sthompsa	sc = ifp->if_softc;
1007203134Sthompsa
1008205042Sthompsa	RUN_LOCK(sc);
1009208019Sthompsa
1010218492Sbschmidt	m_freem(rvp->beacon_mbuf);
1011218492Sbschmidt	rvp->beacon_mbuf = NULL;
1012218492Sbschmidt
1013208019Sthompsa	rvp_id = rvp->rvp_id;
1014208019Sthompsa	sc->ratectl_run &= ~(1 << rvp_id);
1015208019Sthompsa	sc->rvp_bmap &= ~(1 << rvp_id);
1016208019Sthompsa	run_set_region_4(sc, RT2860_SKEY(rvp_id, 0), 0, 128);
1017208019Sthompsa	run_set_region_4(sc, RT2860_BCN_BASE(rvp_id), 0, 512);
1018208019Sthompsa	--sc->rvp_cnt;
1019208019Sthompsa
1020208019Sthompsa	DPRINTF("vap=%p rvp_id=%d bmap=%x rvp_cnt=%d\n",
1021208019Sthompsa	    vap, rvp_id, sc->rvp_bmap, sc->rvp_cnt);
1022208019Sthompsa
1023205042Sthompsa	RUN_UNLOCK(sc);
1024203134Sthompsa
1025206358Srpaulo	ieee80211_ratectl_deinit(vap);
1026203134Sthompsa	ieee80211_vap_detach(vap);
1027203134Sthompsa	free(rvp, M_80211_VAP);
1028203134Sthompsa}
1029203134Sthompsa
1030208019Sthompsa/*
1031208019Sthompsa * There are numbers of functions need to be called in context thread.
1032208019Sthompsa * Rather than creating taskqueue event for each of those functions,
1033208019Sthompsa * here is all-for-one taskqueue callback function. This function
1034208019Sthompsa * gurantees deferred functions are executed in the same order they
1035208019Sthompsa * were enqueued.
1036208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[].
1037208019Sthompsa */
1038203134Sthompsastatic void
1039208019Sthompsarun_cmdq_cb(void *arg, int pending)
1040208019Sthompsa{
1041208019Sthompsa	struct run_softc *sc = arg;
1042208019Sthompsa	uint8_t i;
1043208019Sthompsa
1044208019Sthompsa	/* call cmdq[].func locked */
1045208019Sthompsa	RUN_LOCK(sc);
1046209917Sthompsa	for (i = sc->cmdq_exec; sc->cmdq[i].func && pending;
1047209917Sthompsa	    i = sc->cmdq_exec, pending--) {
1048208019Sthompsa		DPRINTFN(6, "cmdq_exec=%d pending=%d\n", i, pending);
1049209917Sthompsa		if (sc->cmdq_run == RUN_CMDQ_GO) {
1050208019Sthompsa			/*
1051208019Sthompsa			 * If arg0 is NULL, callback func needs more
1052208019Sthompsa			 * than one arg. So, pass ptr to cmdq struct.
1053208019Sthompsa			 */
1054209917Sthompsa			if (sc->cmdq[i].arg0)
1055208019Sthompsa				sc->cmdq[i].func(sc->cmdq[i].arg0);
1056208019Sthompsa			else
1057208019Sthompsa				sc->cmdq[i].func(&sc->cmdq[i]);
1058208019Sthompsa		}
1059208019Sthompsa		sc->cmdq[i].arg0 = NULL;
1060208019Sthompsa		sc->cmdq[i].func = NULL;
1061208019Sthompsa		sc->cmdq_exec++;
1062208019Sthompsa		sc->cmdq_exec &= RUN_CMDQ_MASQ;
1063208019Sthompsa	}
1064208019Sthompsa	RUN_UNLOCK(sc);
1065208019Sthompsa}
1066208019Sthompsa
1067208019Sthompsastatic void
1068203134Sthompsarun_setup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
1069203134Sthompsa{
1070203134Sthompsa	struct run_tx_data *data;
1071203134Sthompsa
1072203134Sthompsa	memset(pq, 0, sizeof(*pq));
1073203134Sthompsa
1074203134Sthompsa	STAILQ_INIT(&pq->tx_qh);
1075203134Sthompsa	STAILQ_INIT(&pq->tx_fh);
1076203134Sthompsa
1077203134Sthompsa	for (data = &pq->tx_data[0];
1078203134Sthompsa	    data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) {
1079203134Sthompsa		data->sc = sc;
1080203134Sthompsa		STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
1081203134Sthompsa	}
1082203134Sthompsa	pq->tx_nfree = RUN_TX_RING_COUNT;
1083203134Sthompsa}
1084203134Sthompsa
1085203134Sthompsastatic void
1086203134Sthompsarun_unsetup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
1087203134Sthompsa{
1088203134Sthompsa	struct run_tx_data *data;
1089203134Sthompsa
1090203134Sthompsa	/* make sure any subsequent use of the queues will fail */
1091203134Sthompsa	pq->tx_nfree = 0;
1092203134Sthompsa	STAILQ_INIT(&pq->tx_fh);
1093203134Sthompsa	STAILQ_INIT(&pq->tx_qh);
1094203134Sthompsa
1095203134Sthompsa	/* free up all node references and mbufs */
1096203134Sthompsa	for (data = &pq->tx_data[0];
1097209917Sthompsa	    data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) {
1098203134Sthompsa		if (data->m != NULL) {
1099203134Sthompsa			m_freem(data->m);
1100203134Sthompsa			data->m = NULL;
1101203134Sthompsa		}
1102203134Sthompsa		if (data->ni != NULL) {
1103203134Sthompsa			ieee80211_free_node(data->ni);
1104203134Sthompsa			data->ni = NULL;
1105203134Sthompsa		}
1106203134Sthompsa	}
1107203134Sthompsa}
1108203134Sthompsa
1109220235Skevlostatic int
1110203134Sthompsarun_load_microcode(struct run_softc *sc)
1111203134Sthompsa{
1112203134Sthompsa	usb_device_request_t req;
1113203137Sthompsa	const struct firmware *fw;
1114203134Sthompsa	const u_char *base;
1115203134Sthompsa	uint32_t tmp;
1116203134Sthompsa	int ntries, error;
1117203134Sthompsa	const uint64_t *temp;
1118203134Sthompsa	uint64_t bytes;
1119203134Sthompsa
1120205042Sthompsa	RUN_UNLOCK(sc);
1121203137Sthompsa	fw = firmware_get("runfw");
1122205042Sthompsa	RUN_LOCK(sc);
1123209917Sthompsa	if (fw == NULL) {
1124203138Sthompsa		device_printf(sc->sc_dev,
1125203138Sthompsa		    "failed loadfirmware of file %s\n", "runfw");
1126203134Sthompsa		return ENOENT;
1127203134Sthompsa	}
1128203134Sthompsa
1129203137Sthompsa	if (fw->datasize != 8192) {
1130203138Sthompsa		device_printf(sc->sc_dev,
1131203138Sthompsa		    "invalid firmware size (should be 8KB)\n");
1132203137Sthompsa		error = EINVAL;
1133203137Sthompsa		goto fail;
1134203134Sthompsa	}
1135203134Sthompsa
1136203134Sthompsa	/*
1137203134Sthompsa	 * RT3071/RT3072 use a different firmware
1138203134Sthompsa	 * run-rt2870 (8KB) contains both,
1139203134Sthompsa	 * first half (4KB) is for rt2870,
1140203134Sthompsa	 * last half is for rt3071.
1141203134Sthompsa	 */
1142203137Sthompsa	base = fw->data;
1143205042Sthompsa	if ((sc->mac_ver) != 0x2860 &&
1144205042Sthompsa	    (sc->mac_ver) != 0x2872 &&
1145209917Sthompsa	    (sc->mac_ver) != 0x3070) {
1146203134Sthompsa		base += 4096;
1147205042Sthompsa	}
1148203134Sthompsa
1149203134Sthompsa	/* cheap sanity check */
1150203137Sthompsa	temp = fw->data;
1151203134Sthompsa	bytes = *temp;
1152257712Shselasky	if (bytes != be64toh(0xffffff0210280210ULL)) {
1153203138Sthompsa		device_printf(sc->sc_dev, "firmware checksum failed\n");
1154203137Sthompsa		error = EINVAL;
1155203137Sthompsa		goto fail;
1156203137Sthompsa	}
1157203134Sthompsa
1158203134Sthompsa	/* write microcode image */
1159262465Skevlo	if (sc->sc_flags & RUN_FLAG_FWLOAD_NEEDED) {
1160260219Skevlo		run_write_region_1(sc, RT2870_FW_BASE, base, 4096);
1161260219Skevlo		run_write(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff);
1162260219Skevlo		run_write(sc, RT2860_H2M_MAILBOX_STATUS, 0xffffffff);
1163260219Skevlo	}
1164203134Sthompsa
1165203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1166203134Sthompsa	req.bRequest = RT2870_RESET;
1167203134Sthompsa	USETW(req.wValue, 8);
1168203134Sthompsa	USETW(req.wIndex, 0);
1169203134Sthompsa	USETW(req.wLength, 0);
1170220235Skevlo	if ((error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL))
1171220235Skevlo	    != 0) {
1172203138Sthompsa		device_printf(sc->sc_dev, "firmware reset failed\n");
1173203137Sthompsa		goto fail;
1174203137Sthompsa	}
1175203134Sthompsa
1176203134Sthompsa	run_delay(sc, 10);
1177203134Sthompsa
1178260219Skevlo	run_write(sc, RT2860_H2M_BBPAGENT, 0);
1179203134Sthompsa	run_write(sc, RT2860_H2M_MAILBOX, 0);
1180260219Skevlo	run_write(sc, RT2860_H2M_INTSRC, 0);
1181205042Sthompsa	if ((error = run_mcu_cmd(sc, RT2860_MCU_CMD_RFRESET, 0)) != 0)
1182203137Sthompsa		goto fail;
1183203134Sthompsa
1184203134Sthompsa	/* wait until microcontroller is ready */
1185203134Sthompsa	for (ntries = 0; ntries < 1000; ntries++) {
1186260219Skevlo		if ((error = run_read(sc, RT2860_SYS_CTRL, &tmp)) != 0)
1187203137Sthompsa			goto fail;
1188203134Sthompsa		if (tmp & RT2860_MCU_READY)
1189203134Sthompsa			break;
1190203134Sthompsa		run_delay(sc, 10);
1191203134Sthompsa	}
1192203134Sthompsa	if (ntries == 1000) {
1193203138Sthompsa		device_printf(sc->sc_dev,
1194203138Sthompsa		    "timeout waiting for MCU to initialize\n");
1195203137Sthompsa		error = ETIMEDOUT;
1196203137Sthompsa		goto fail;
1197203134Sthompsa	}
1198233283Sbschmidt	device_printf(sc->sc_dev, "firmware %s ver. %u.%u loaded\n",
1199233283Sbschmidt	    (base == fw->data) ? "RT2870" : "RT3071",
1200233283Sbschmidt	    *(base + 4092), *(base + 4093));
1201203134Sthompsa
1202203137Sthompsafail:
1203203137Sthompsa	firmware_put(fw, FIRMWARE_UNLOAD);
1204203137Sthompsa	return (error);
1205203134Sthompsa}
1206203134Sthompsa
1207258641Shselaskystatic int
1208203134Sthompsarun_reset(struct run_softc *sc)
1209203134Sthompsa{
1210203134Sthompsa	usb_device_request_t req;
1211203134Sthompsa
1212203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1213203134Sthompsa	req.bRequest = RT2870_RESET;
1214203134Sthompsa	USETW(req.wValue, 1);
1215203134Sthompsa	USETW(req.wIndex, 0);
1216203134Sthompsa	USETW(req.wLength, 0);
1217209917Sthompsa	return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL));
1218203134Sthompsa}
1219203134Sthompsa
1220203134Sthompsastatic usb_error_t
1221203134Sthompsarun_do_request(struct run_softc *sc,
1222203134Sthompsa    struct usb_device_request *req, void *data)
1223203134Sthompsa{
1224203134Sthompsa	usb_error_t err;
1225203134Sthompsa	int ntries = 10;
1226203134Sthompsa
1227203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
1228203134Sthompsa
1229203134Sthompsa	while (ntries--) {
1230203134Sthompsa		err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx,
1231203134Sthompsa		    req, data, 0, NULL, 250 /* ms */);
1232203134Sthompsa		if (err == 0)
1233203134Sthompsa			break;
1234203134Sthompsa		DPRINTFN(1, "Control request failed, %s (retrying)\n",
1235203134Sthompsa		    usbd_errstr(err));
1236203134Sthompsa		run_delay(sc, 10);
1237203134Sthompsa	}
1238203134Sthompsa	return (err);
1239203134Sthompsa}
1240203134Sthompsa
1241203134Sthompsastatic int
1242203134Sthompsarun_read(struct run_softc *sc, uint16_t reg, uint32_t *val)
1243203134Sthompsa{
1244203134Sthompsa	uint32_t tmp;
1245203134Sthompsa	int error;
1246203134Sthompsa
1247203134Sthompsa	error = run_read_region_1(sc, reg, (uint8_t *)&tmp, sizeof tmp);
1248203134Sthompsa	if (error == 0)
1249203134Sthompsa		*val = le32toh(tmp);
1250203134Sthompsa	else
1251203134Sthompsa		*val = 0xffffffff;
1252209917Sthompsa	return (error);
1253203134Sthompsa}
1254203134Sthompsa
1255203134Sthompsastatic int
1256203134Sthompsarun_read_region_1(struct run_softc *sc, uint16_t reg, uint8_t *buf, int len)
1257203134Sthompsa{
1258203134Sthompsa	usb_device_request_t req;
1259203134Sthompsa
1260203134Sthompsa	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1261203134Sthompsa	req.bRequest = RT2870_READ_REGION_1;
1262203134Sthompsa	USETW(req.wValue, 0);
1263203134Sthompsa	USETW(req.wIndex, reg);
1264203134Sthompsa	USETW(req.wLength, len);
1265203134Sthompsa
1266209917Sthompsa	return (run_do_request(sc, &req, buf));
1267203134Sthompsa}
1268203134Sthompsa
1269203134Sthompsastatic int
1270203134Sthompsarun_write_2(struct run_softc *sc, uint16_t reg, uint16_t val)
1271203134Sthompsa{
1272203134Sthompsa	usb_device_request_t req;
1273203134Sthompsa
1274203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1275203134Sthompsa	req.bRequest = RT2870_WRITE_2;
1276203134Sthompsa	USETW(req.wValue, val);
1277203134Sthompsa	USETW(req.wIndex, reg);
1278203134Sthompsa	USETW(req.wLength, 0);
1279203134Sthompsa
1280209917Sthompsa	return (run_do_request(sc, &req, NULL));
1281203134Sthompsa}
1282203134Sthompsa
1283203134Sthompsastatic int
1284203134Sthompsarun_write(struct run_softc *sc, uint16_t reg, uint32_t val)
1285203134Sthompsa{
1286203134Sthompsa	int error;
1287203134Sthompsa
1288203134Sthompsa	if ((error = run_write_2(sc, reg, val & 0xffff)) == 0)
1289203134Sthompsa		error = run_write_2(sc, reg + 2, val >> 16);
1290209917Sthompsa	return (error);
1291203134Sthompsa}
1292203134Sthompsa
1293203134Sthompsastatic int
1294203134Sthompsarun_write_region_1(struct run_softc *sc, uint16_t reg, const uint8_t *buf,
1295203134Sthompsa    int len)
1296203134Sthompsa{
1297203134Sthompsa#if 1
1298203134Sthompsa	int i, error = 0;
1299203134Sthompsa	/*
1300203134Sthompsa	 * NB: the WRITE_REGION_1 command is not stable on RT2860.
1301203134Sthompsa	 * We thus issue multiple WRITE_2 commands instead.
1302203134Sthompsa	 */
1303203134Sthompsa	KASSERT((len & 1) == 0, ("run_write_region_1: Data too long.\n"));
1304203134Sthompsa	for (i = 0; i < len && error == 0; i += 2)
1305203134Sthompsa		error = run_write_2(sc, reg + i, buf[i] | buf[i + 1] << 8);
1306209917Sthompsa	return (error);
1307203134Sthompsa#else
1308203134Sthompsa	usb_device_request_t req;
1309257958Skevlo	int error = 0;
1310203134Sthompsa
1311257958Skevlo	/*
1312257958Skevlo	 * NOTE: It appears the WRITE_REGION_1 command cannot be
1313257958Skevlo	 * passed a huge amount of data, which will crash the
1314257958Skevlo	 * firmware. Limit amount of data passed to 64-bytes at a
1315257958Skevlo	 * time.
1316257958Skevlo	 */
1317257958Skevlo	while (len > 0) {
1318257958Skevlo		int delta = 64;
1319257958Skevlo		if (delta > len)
1320257958Skevlo			delta = len;
1321257958Skevlo
1322257958Skevlo		req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1323257958Skevlo		req.bRequest = RT2870_WRITE_REGION_1;
1324257958Skevlo		USETW(req.wValue, 0);
1325257958Skevlo		USETW(req.wIndex, reg);
1326257958Skevlo		USETW(req.wLength, delta);
1327257958Skevlo		error = run_do_request(sc, &req, __DECONST(uint8_t *, buf));
1328257958Skevlo		if (error != 0)
1329257958Skevlo			break;
1330257958Skevlo		reg += delta;
1331257958Skevlo		buf += delta;
1332257958Skevlo		len -= delta;
1333257958Skevlo	}
1334257958Skevlo	return (error);
1335203134Sthompsa#endif
1336203134Sthompsa}
1337203134Sthompsa
1338203134Sthompsastatic int
1339203134Sthompsarun_set_region_4(struct run_softc *sc, uint16_t reg, uint32_t val, int len)
1340203134Sthompsa{
1341203134Sthompsa	int i, error = 0;
1342203134Sthompsa
1343203134Sthompsa	KASSERT((len & 3) == 0, ("run_set_region_4: Invalid data length.\n"));
1344203134Sthompsa	for (i = 0; i < len && error == 0; i += 4)
1345203134Sthompsa		error = run_write(sc, reg + i, val);
1346209917Sthompsa	return (error);
1347203134Sthompsa}
1348203134Sthompsa
1349203134Sthompsastatic int
1350259544Skevlorun_efuse_read(struct run_softc *sc, uint16_t addr, uint16_t *val, int count)
1351203134Sthompsa{
1352203134Sthompsa	uint32_t tmp;
1353203134Sthompsa	uint16_t reg;
1354203134Sthompsa	int error, ntries;
1355203134Sthompsa
1356203134Sthompsa	if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
1357209917Sthompsa		return (error);
1358203134Sthompsa
1359261076Shselasky	if (count == 2)
1360261076Shselasky		addr *= 2;
1361203134Sthompsa	/*-
1362203134Sthompsa	 * Read one 16-byte block into registers EFUSE_DATA[0-3]:
1363203134Sthompsa	 * DATA0: F E D C
1364203134Sthompsa	 * DATA1: B A 9 8
1365203134Sthompsa	 * DATA2: 7 6 5 4
1366203134Sthompsa	 * DATA3: 3 2 1 0
1367203134Sthompsa	 */
1368203134Sthompsa	tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK);
1369203134Sthompsa	tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK;
1370203134Sthompsa	run_write(sc, RT3070_EFUSE_CTRL, tmp);
1371203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1372203134Sthompsa		if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
1373209917Sthompsa			return (error);
1374203134Sthompsa		if (!(tmp & RT3070_EFSROM_KICK))
1375203134Sthompsa			break;
1376203134Sthompsa		run_delay(sc, 2);
1377203134Sthompsa	}
1378203134Sthompsa	if (ntries == 100)
1379209917Sthompsa		return (ETIMEDOUT);
1380203134Sthompsa
1381261076Shselasky	if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK) {
1382261076Shselasky		*val = 0xffff;	/* address not found */
1383209917Sthompsa		return (0);
1384261076Shselasky	}
1385203134Sthompsa	/* determine to which 32-bit register our 16-bit word belongs */
1386203134Sthompsa	reg = RT3070_EFUSE_DATA3 - (addr & 0xc);
1387203134Sthompsa	if ((error = run_read(sc, reg, &tmp)) != 0)
1388209917Sthompsa		return (error);
1389203134Sthompsa
1390261118Skevlo	tmp >>= (8 * (addr & 0x3));
1391261118Skevlo	*val = (addr & 1) ? tmp >> 16 : tmp & 0xffff;
1392261118Skevlo
1393209917Sthompsa	return (0);
1394203134Sthompsa}
1395203134Sthompsa
1396261124Skevlo/* Read 16-bit from eFUSE ROM for RT3xxx. */
1397203134Sthompsastatic int
1398259544Skevlorun_efuse_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
1399259544Skevlo{
1400259544Skevlo	return (run_efuse_read(sc, addr, val, 2));
1401259544Skevlo}
1402259544Skevlo
1403259544Skevlostatic int
1404203134Sthompsarun_eeprom_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
1405203134Sthompsa{
1406203134Sthompsa	usb_device_request_t req;
1407203134Sthompsa	uint16_t tmp;
1408203134Sthompsa	int error;
1409203134Sthompsa
1410203134Sthompsa	addr *= 2;
1411203134Sthompsa	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1412203134Sthompsa	req.bRequest = RT2870_EEPROM_READ;
1413203134Sthompsa	USETW(req.wValue, 0);
1414203134Sthompsa	USETW(req.wIndex, addr);
1415260219Skevlo	USETW(req.wLength, sizeof(tmp));
1416203134Sthompsa
1417203134Sthompsa	error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, &tmp);
1418203134Sthompsa	if (error == 0)
1419203134Sthompsa		*val = le16toh(tmp);
1420203134Sthompsa	else
1421203134Sthompsa		*val = 0xffff;
1422209917Sthompsa	return (error);
1423203134Sthompsa}
1424203134Sthompsa
1425203134Sthompsastatic __inline int
1426203134Sthompsarun_srom_read(struct run_softc *sc, uint16_t addr, uint16_t *val)
1427203134Sthompsa{
1428203134Sthompsa	/* either eFUSE ROM or EEPROM */
1429203134Sthompsa	return sc->sc_srom_read(sc, addr, val);
1430203134Sthompsa}
1431203134Sthompsa
1432203134Sthompsastatic int
1433258733Skevlorun_rt2870_rf_write(struct run_softc *sc, uint32_t val)
1434203134Sthompsa{
1435203134Sthompsa	uint32_t tmp;
1436203134Sthompsa	int error, ntries;
1437203134Sthompsa
1438203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1439203134Sthompsa		if ((error = run_read(sc, RT2860_RF_CSR_CFG0, &tmp)) != 0)
1440209917Sthompsa			return (error);
1441203134Sthompsa		if (!(tmp & RT2860_RF_REG_CTRL))
1442203134Sthompsa			break;
1443203134Sthompsa	}
1444203134Sthompsa	if (ntries == 10)
1445209917Sthompsa		return (ETIMEDOUT);
1446203134Sthompsa
1447258732Skevlo	return (run_write(sc, RT2860_RF_CSR_CFG0, val));
1448203134Sthompsa}
1449203134Sthompsa
1450203134Sthompsastatic int
1451203134Sthompsarun_rt3070_rf_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
1452203134Sthompsa{
1453203134Sthompsa	uint32_t tmp;
1454203134Sthompsa	int error, ntries;
1455203134Sthompsa
1456203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1457203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1458209917Sthompsa			return (error);
1459203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1460203134Sthompsa			break;
1461203134Sthompsa	}
1462203134Sthompsa	if (ntries == 100)
1463209917Sthompsa		return (ETIMEDOUT);
1464203134Sthompsa
1465203134Sthompsa	tmp = RT3070_RF_KICK | reg << 8;
1466203134Sthompsa	if ((error = run_write(sc, RT3070_RF_CSR_CFG, tmp)) != 0)
1467209917Sthompsa		return (error);
1468203134Sthompsa
1469203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1470203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1471209917Sthompsa			return (error);
1472203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1473203134Sthompsa			break;
1474203134Sthompsa	}
1475203134Sthompsa	if (ntries == 100)
1476209917Sthompsa		return (ETIMEDOUT);
1477203134Sthompsa
1478203134Sthompsa	*val = tmp & 0xff;
1479209917Sthompsa	return (0);
1480203134Sthompsa}
1481203134Sthompsa
1482203134Sthompsastatic int
1483203134Sthompsarun_rt3070_rf_write(struct run_softc *sc, uint8_t reg, uint8_t val)
1484203134Sthompsa{
1485203134Sthompsa	uint32_t tmp;
1486203134Sthompsa	int error, ntries;
1487203134Sthompsa
1488203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1489203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1490209917Sthompsa			return (error);
1491203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1492203134Sthompsa			break;
1493203134Sthompsa	}
1494203134Sthompsa	if (ntries == 10)
1495209917Sthompsa		return (ETIMEDOUT);
1496203134Sthompsa
1497203134Sthompsa	tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val;
1498209917Sthompsa	return (run_write(sc, RT3070_RF_CSR_CFG, tmp));
1499203134Sthompsa}
1500203134Sthompsa
1501203134Sthompsastatic int
1502203134Sthompsarun_bbp_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
1503203134Sthompsa{
1504203134Sthompsa	uint32_t tmp;
1505203134Sthompsa	int ntries, error;
1506203134Sthompsa
1507203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1508203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1509209917Sthompsa			return (error);
1510203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1511203134Sthompsa			break;
1512203134Sthompsa	}
1513203134Sthompsa	if (ntries == 10)
1514209917Sthompsa		return (ETIMEDOUT);
1515203134Sthompsa
1516203134Sthompsa	tmp = RT2860_BBP_CSR_READ | RT2860_BBP_CSR_KICK | reg << 8;
1517203134Sthompsa	if ((error = run_write(sc, RT2860_BBP_CSR_CFG, tmp)) != 0)
1518209917Sthompsa		return (error);
1519203134Sthompsa
1520203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1521203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1522209917Sthompsa			return (error);
1523203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1524203134Sthompsa			break;
1525203134Sthompsa	}
1526203134Sthompsa	if (ntries == 10)
1527209917Sthompsa		return (ETIMEDOUT);
1528203134Sthompsa
1529203134Sthompsa	*val = tmp & 0xff;
1530209917Sthompsa	return (0);
1531203134Sthompsa}
1532203134Sthompsa
1533203134Sthompsastatic int
1534203134Sthompsarun_bbp_write(struct run_softc *sc, uint8_t reg, uint8_t val)
1535203134Sthompsa{
1536203134Sthompsa	uint32_t tmp;
1537203134Sthompsa	int ntries, error;
1538203134Sthompsa
1539203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1540203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1541209917Sthompsa			return (error);
1542203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1543203134Sthompsa			break;
1544203134Sthompsa	}
1545203134Sthompsa	if (ntries == 10)
1546209917Sthompsa		return (ETIMEDOUT);
1547203134Sthompsa
1548203134Sthompsa	tmp = RT2860_BBP_CSR_KICK | reg << 8 | val;
1549209917Sthompsa	return (run_write(sc, RT2860_BBP_CSR_CFG, tmp));
1550203134Sthompsa}
1551203134Sthompsa
1552203134Sthompsa/*
1553203134Sthompsa * Send a command to the 8051 microcontroller unit.
1554203134Sthompsa */
1555203134Sthompsastatic int
1556203134Sthompsarun_mcu_cmd(struct run_softc *sc, uint8_t cmd, uint16_t arg)
1557203134Sthompsa{
1558203134Sthompsa	uint32_t tmp;
1559203134Sthompsa	int error, ntries;
1560203134Sthompsa
1561203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1562203134Sthompsa		if ((error = run_read(sc, RT2860_H2M_MAILBOX, &tmp)) != 0)
1563203134Sthompsa			return error;
1564203134Sthompsa		if (!(tmp & RT2860_H2M_BUSY))
1565203134Sthompsa			break;
1566203134Sthompsa	}
1567203134Sthompsa	if (ntries == 100)
1568203134Sthompsa		return ETIMEDOUT;
1569203134Sthompsa
1570203134Sthompsa	tmp = RT2860_H2M_BUSY | RT2860_TOKEN_NO_INTR << 16 | arg;
1571203134Sthompsa	if ((error = run_write(sc, RT2860_H2M_MAILBOX, tmp)) == 0)
1572203134Sthompsa		error = run_write(sc, RT2860_HOST_CMD, cmd);
1573209917Sthompsa	return (error);
1574203134Sthompsa}
1575203134Sthompsa
1576203134Sthompsa/*
1577203134Sthompsa * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word.
1578203134Sthompsa * Used to adjust per-rate Tx power registers.
1579203134Sthompsa */
1580203134Sthompsastatic __inline uint32_t
1581203134Sthompsab4inc(uint32_t b32, int8_t delta)
1582203134Sthompsa{
1583203134Sthompsa	int8_t i, b4;
1584203134Sthompsa
1585203134Sthompsa	for (i = 0; i < 8; i++) {
1586203134Sthompsa		b4 = b32 & 0xf;
1587203134Sthompsa		b4 += delta;
1588203134Sthompsa		if (b4 < 0)
1589203134Sthompsa			b4 = 0;
1590203134Sthompsa		else if (b4 > 0xf)
1591203134Sthompsa			b4 = 0xf;
1592203134Sthompsa		b32 = b32 >> 4 | b4 << 28;
1593203134Sthompsa	}
1594209917Sthompsa	return (b32);
1595203134Sthompsa}
1596203134Sthompsa
1597203134Sthompsastatic const char *
1598257955Skevlorun_get_rf(uint16_t rev)
1599203134Sthompsa{
1600203134Sthompsa	switch (rev) {
1601203134Sthompsa	case RT2860_RF_2820:	return "RT2820";
1602203134Sthompsa	case RT2860_RF_2850:	return "RT2850";
1603203134Sthompsa	case RT2860_RF_2720:	return "RT2720";
1604203134Sthompsa	case RT2860_RF_2750:	return "RT2750";
1605203134Sthompsa	case RT3070_RF_3020:	return "RT3020";
1606203134Sthompsa	case RT3070_RF_2020:	return "RT2020";
1607203134Sthompsa	case RT3070_RF_3021:	return "RT3021";
1608203134Sthompsa	case RT3070_RF_3022:	return "RT3022";
1609203134Sthompsa	case RT3070_RF_3052:	return "RT3052";
1610260219Skevlo	case RT3593_RF_3053:	return "RT3053";
1611259032Skevlo	case RT5592_RF_5592:	return "RT5592";
1612257955Skevlo	case RT5390_RF_5370:	return "RT5370";
1613257955Skevlo	case RT5390_RF_5372:	return "RT5372";
1614203134Sthompsa	}
1615209917Sthompsa	return ("unknown");
1616203134Sthompsa}
1617203134Sthompsa
1618260219Skevlostatic void
1619260219Skevlorun_rt3593_get_txpower(struct run_softc *sc)
1620260219Skevlo{
1621260219Skevlo	uint16_t addr, val;
1622260219Skevlo	int i;
1623260219Skevlo
1624260219Skevlo	/* Read power settings for 2GHz channels. */
1625260219Skevlo	for (i = 0; i < 14; i += 2) {
1626260219Skevlo		addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE1 :
1627260219Skevlo		    RT2860_EEPROM_PWR2GHZ_BASE1;
1628260219Skevlo		run_srom_read(sc, addr + i / 2, &val);
1629260219Skevlo		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
1630260219Skevlo		sc->txpow1[i + 1] = (int8_t)(val >> 8);
1631260219Skevlo
1632260219Skevlo		addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE2 :
1633260219Skevlo		    RT2860_EEPROM_PWR2GHZ_BASE2;
1634260219Skevlo		run_srom_read(sc, addr + i / 2, &val);
1635260219Skevlo		sc->txpow2[i + 0] = (int8_t)(val & 0xff);
1636260219Skevlo		sc->txpow2[i + 1] = (int8_t)(val >> 8);
1637260219Skevlo
1638260219Skevlo		if (sc->ntxchains == 3) {
1639260219Skevlo			run_srom_read(sc, RT3593_EEPROM_PWR2GHZ_BASE3 + i / 2,
1640260219Skevlo			    &val);
1641260219Skevlo			sc->txpow3[i + 0] = (int8_t)(val & 0xff);
1642260219Skevlo			sc->txpow3[i + 1] = (int8_t)(val >> 8);
1643260219Skevlo		}
1644260219Skevlo	}
1645260219Skevlo	/* Fix broken Tx power entries. */
1646260219Skevlo	for (i = 0; i < 14; i++) {
1647260542Skevlo		if (sc->txpow1[i] > 31)
1648260219Skevlo			sc->txpow1[i] = 5;
1649260542Skevlo		if (sc->txpow2[i] > 31)
1650260219Skevlo			sc->txpow2[i] = 5;
1651260219Skevlo		if (sc->ntxchains == 3) {
1652260542Skevlo			if (sc->txpow3[i] > 31)
1653260219Skevlo				sc->txpow3[i] = 5;
1654260219Skevlo		}
1655260219Skevlo	}
1656260219Skevlo	/* Read power settings for 5GHz channels. */
1657260219Skevlo	for (i = 0; i < 40; i += 2) {
1658260219Skevlo		run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
1659260219Skevlo		sc->txpow1[i + 14] = (int8_t)(val & 0xff);
1660260219Skevlo		sc->txpow1[i + 15] = (int8_t)(val >> 8);
1661260219Skevlo
1662260219Skevlo		run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
1663260219Skevlo		sc->txpow2[i + 14] = (int8_t)(val & 0xff);
1664260219Skevlo		sc->txpow2[i + 15] = (int8_t)(val >> 8);
1665260219Skevlo
1666260219Skevlo		if (sc->ntxchains == 3) {
1667260219Skevlo			run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE3 + i / 2,
1668260219Skevlo			    &val);
1669260219Skevlo			sc->txpow3[i + 14] = (int8_t)(val & 0xff);
1670260219Skevlo			sc->txpow3[i + 15] = (int8_t)(val >> 8);
1671260219Skevlo		}
1672260219Skevlo	}
1673260219Skevlo}
1674260219Skevlo
1675260219Skevlostatic void
1676260219Skevlorun_get_txpower(struct run_softc *sc)
1677260219Skevlo{
1678260219Skevlo	uint16_t val;
1679260219Skevlo	int i;
1680260219Skevlo
1681260219Skevlo	/* Read power settings for 2GHz channels. */
1682260219Skevlo	for (i = 0; i < 14; i += 2) {
1683260219Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE1 + i / 2, &val);
1684260219Skevlo		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
1685260219Skevlo		sc->txpow1[i + 1] = (int8_t)(val >> 8);
1686260219Skevlo
1687260219Skevlo		if (sc->mac_ver != 0x5390) {
1688260219Skevlo			run_srom_read(sc,
1689260219Skevlo			    RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2, &val);
1690260219Skevlo			sc->txpow2[i + 0] = (int8_t)(val & 0xff);
1691260219Skevlo			sc->txpow2[i + 1] = (int8_t)(val >> 8);
1692260219Skevlo		}
1693260219Skevlo	}
1694260219Skevlo	/* Fix broken Tx power entries. */
1695260219Skevlo	for (i = 0; i < 14; i++) {
1696260219Skevlo		if (sc->mac_ver >= 0x5390) {
1697260219Skevlo			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 27)
1698260219Skevlo				sc->txpow1[i] = 5;
1699260219Skevlo		} else {
1700260219Skevlo			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31)
1701260219Skevlo				sc->txpow1[i] = 5;
1702260219Skevlo		}
1703260219Skevlo		if (sc->mac_ver > 0x5390) {
1704260219Skevlo			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 27)
1705260219Skevlo				sc->txpow2[i] = 5;
1706260219Skevlo		} else if (sc->mac_ver < 0x5390) {
1707260219Skevlo			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31)
1708260219Skevlo				sc->txpow2[i] = 5;
1709260219Skevlo		}
1710260219Skevlo		DPRINTF("chan %d: power1=%d, power2=%d\n",
1711260219Skevlo		    rt2860_rf2850[i].chan, sc->txpow1[i], sc->txpow2[i]);
1712260219Skevlo	}
1713260219Skevlo	/* Read power settings for 5GHz channels. */
1714260219Skevlo	for (i = 0; i < 40; i += 2) {
1715260219Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
1716260219Skevlo		sc->txpow1[i + 14] = (int8_t)(val & 0xff);
1717260219Skevlo		sc->txpow1[i + 15] = (int8_t)(val >> 8);
1718260219Skevlo
1719260219Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
1720260219Skevlo		sc->txpow2[i + 14] = (int8_t)(val & 0xff);
1721260219Skevlo		sc->txpow2[i + 15] = (int8_t)(val >> 8);
1722260219Skevlo	}
1723260219Skevlo	/* Fix broken Tx power entries. */
1724260219Skevlo	for (i = 0; i < 40; i++ ) {
1725260219Skevlo		if (sc->mac_ver != 0x5592) {
1726260219Skevlo			if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15)
1727260219Skevlo				sc->txpow1[14 + i] = 5;
1728260219Skevlo			if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15)
1729260219Skevlo				sc->txpow2[14 + i] = 5;
1730260219Skevlo		}
1731260219Skevlo		DPRINTF("chan %d: power1=%d, power2=%d\n",
1732260219Skevlo		    rt2860_rf2850[14 + i].chan, sc->txpow1[14 + i],
1733260219Skevlo		    sc->txpow2[14 + i]);
1734260219Skevlo	}
1735260219Skevlo}
1736260219Skevlo
1737258641Shselaskystatic int
1738203134Sthompsarun_read_eeprom(struct run_softc *sc)
1739203134Sthompsa{
1740203134Sthompsa	int8_t delta_2ghz, delta_5ghz;
1741203134Sthompsa	uint32_t tmp;
1742203134Sthompsa	uint16_t val;
1743203134Sthompsa	int ridx, ant, i;
1744203134Sthompsa
1745203134Sthompsa	/* check whether the ROM is eFUSE ROM or EEPROM */
1746203134Sthompsa	sc->sc_srom_read = run_eeprom_read_2;
1747205042Sthompsa	if (sc->mac_ver >= 0x3070) {
1748203134Sthompsa		run_read(sc, RT3070_EFUSE_CTRL, &tmp);
1749203134Sthompsa		DPRINTF("EFUSE_CTRL=0x%08x\n", tmp);
1750261118Skevlo		if ((tmp & RT3070_SEL_EFUSE) || sc->mac_ver == 0x3593)
1751203134Sthompsa			sc->sc_srom_read = run_efuse_read_2;
1752203134Sthompsa	}
1753203134Sthompsa
1754203134Sthompsa	/* read ROM version */
1755203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_VERSION, &val);
1756203134Sthompsa	DPRINTF("EEPROM rev=%d, FAE=%d\n", val & 0xff, val >> 8);
1757203134Sthompsa
1758203134Sthompsa	/* read MAC address */
1759203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC01, &val);
1760203134Sthompsa	sc->sc_bssid[0] = val & 0xff;
1761203134Sthompsa	sc->sc_bssid[1] = val >> 8;
1762203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC23, &val);
1763203134Sthompsa	sc->sc_bssid[2] = val & 0xff;
1764203134Sthompsa	sc->sc_bssid[3] = val >> 8;
1765203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC45, &val);
1766203134Sthompsa	sc->sc_bssid[4] = val & 0xff;
1767203134Sthompsa	sc->sc_bssid[5] = val >> 8;
1768203134Sthompsa
1769260219Skevlo	if (sc->mac_ver < 0x3593) {
1770257955Skevlo		/* read vender BBP settings */
1771205042Sthompsa		for (i = 0; i < 10; i++) {
1772257955Skevlo			run_srom_read(sc, RT2860_EEPROM_BBP_BASE + i, &val);
1773257955Skevlo			sc->bbp[i].val = val & 0xff;
1774257955Skevlo			sc->bbp[i].reg = val >> 8;
1775257955Skevlo			DPRINTF("BBP%d=0x%02x\n", sc->bbp[i].reg,
1776257955Skevlo			    sc->bbp[i].val);
1777205042Sthompsa		}
1778257955Skevlo		if (sc->mac_ver >= 0x3071) {
1779257955Skevlo			/* read vendor RF settings */
1780257955Skevlo			for (i = 0; i < 10; i++) {
1781257955Skevlo				run_srom_read(sc, RT3071_EEPROM_RF_BASE + i,
1782257955Skevlo				   &val);
1783257955Skevlo				sc->rf[i].val = val & 0xff;
1784257955Skevlo				sc->rf[i].reg = val >> 8;
1785257955Skevlo				DPRINTF("RF%d=0x%02x\n", sc->rf[i].reg,
1786257955Skevlo				    sc->rf[i].val);
1787257955Skevlo			}
1788257955Skevlo		}
1789205042Sthompsa	}
1790203134Sthompsa
1791203134Sthompsa	/* read RF frequency offset from EEPROM */
1792260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS :
1793260219Skevlo	    RT3593_EEPROM_FREQ, &val);
1794203134Sthompsa	sc->freq = ((val & 0xff) != 0xff) ? val & 0xff : 0;
1795203134Sthompsa	DPRINTF("EEPROM freq offset %d\n", sc->freq & 0xff);
1796203134Sthompsa
1797260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS :
1798260219Skevlo	    RT3593_EEPROM_FREQ_LEDS, &val);
1799205042Sthompsa	if (val >> 8 != 0xff) {
1800203134Sthompsa		/* read LEDs operating mode */
1801205042Sthompsa		sc->leds = val >> 8;
1802260219Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED1 :
1803260219Skevlo		    RT3593_EEPROM_LED1, &sc->led[0]);
1804260219Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED2 :
1805260219Skevlo		    RT3593_EEPROM_LED2, &sc->led[1]);
1806260219Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED3 :
1807260219Skevlo		    RT3593_EEPROM_LED3, &sc->led[2]);
1808203134Sthompsa	} else {
1809203134Sthompsa		/* broken EEPROM, use default settings */
1810203134Sthompsa		sc->leds = 0x01;
1811203134Sthompsa		sc->led[0] = 0x5555;
1812203134Sthompsa		sc->led[1] = 0x2221;
1813203134Sthompsa		sc->led[2] = 0x5627;	/* differs from RT2860 */
1814203134Sthompsa	}
1815203134Sthompsa	DPRINTF("EEPROM LED mode=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n",
1816203134Sthompsa	    sc->leds, sc->led[0], sc->led[1], sc->led[2]);
1817203134Sthompsa
1818203134Sthompsa	/* read RF information */
1819259032Skevlo	if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392)
1820257955Skevlo		run_srom_read(sc, 0x00, &val);
1821257955Skevlo	else
1822257955Skevlo		run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
1823257955Skevlo
1824203134Sthompsa	if (val == 0xffff) {
1825260219Skevlo		device_printf(sc->sc_dev,
1826260219Skevlo		    "invalid EEPROM antenna info, using default\n");
1827203134Sthompsa		DPRINTF("invalid EEPROM antenna info, using default\n");
1828205042Sthompsa		if (sc->mac_ver == 0x3572) {
1829205042Sthompsa			/* default to RF3052 2T2R */
1830205042Sthompsa			sc->rf_rev = RT3070_RF_3052;
1831205042Sthompsa			sc->ntxchains = 2;
1832205042Sthompsa			sc->nrxchains = 2;
1833205042Sthompsa		} else if (sc->mac_ver >= 0x3070) {
1834203134Sthompsa			/* default to RF3020 1T1R */
1835203134Sthompsa			sc->rf_rev = RT3070_RF_3020;
1836203134Sthompsa			sc->ntxchains = 1;
1837203134Sthompsa			sc->nrxchains = 1;
1838203134Sthompsa		} else {
1839203134Sthompsa			/* default to RF2820 1T2R */
1840203134Sthompsa			sc->rf_rev = RT2860_RF_2820;
1841203134Sthompsa			sc->ntxchains = 1;
1842203134Sthompsa			sc->nrxchains = 2;
1843203134Sthompsa		}
1844203134Sthompsa	} else {
1845259032Skevlo		if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392) {
1846257955Skevlo			sc->rf_rev = val;
1847257955Skevlo			run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
1848257955Skevlo		} else
1849257955Skevlo			sc->rf_rev = (val >> 8) & 0xf;
1850203134Sthompsa		sc->ntxchains = (val >> 4) & 0xf;
1851203134Sthompsa		sc->nrxchains = val & 0xf;
1852203134Sthompsa	}
1853257955Skevlo	DPRINTF("EEPROM RF rev=0x%04x chains=%dT%dR\n",
1854203134Sthompsa	    sc->rf_rev, sc->ntxchains, sc->nrxchains);
1855203134Sthompsa
1856208019Sthompsa	/* check if RF supports automatic Tx access gain control */
1857203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_CONFIG, &val);
1858203134Sthompsa	DPRINTF("EEPROM CFG 0x%04x\n", val);
1859205042Sthompsa	/* check if driver should patch the DAC issue */
1860205042Sthompsa	if ((val >> 8) != 0xff)
1861205042Sthompsa		sc->patch_dac = (val >> 15) & 1;
1862203134Sthompsa	if ((val & 0xff) != 0xff) {
1863203134Sthompsa		sc->ext_5ghz_lna = (val >> 3) & 1;
1864203134Sthompsa		sc->ext_2ghz_lna = (val >> 2) & 1;
1865205042Sthompsa		/* check if RF supports automatic Tx access gain control */
1866203134Sthompsa		sc->calib_2ghz = sc->calib_5ghz = (val >> 1) & 1;
1867205042Sthompsa		/* check if we have a hardware radio switch */
1868205042Sthompsa		sc->rfswitch = val & 1;
1869203134Sthompsa	}
1870203134Sthompsa
1871260219Skevlo	/* Read Tx power settings. */
1872260219Skevlo	if (sc->mac_ver == 0x3593)
1873260219Skevlo		run_rt3593_get_txpower(sc);
1874260219Skevlo	else
1875260219Skevlo		run_get_txpower(sc);
1876203134Sthompsa
1877203134Sthompsa	/* read Tx power compensation for each Tx rate */
1878203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_DELTAPWR, &val);
1879203134Sthompsa	delta_2ghz = delta_5ghz = 0;
1880203134Sthompsa	if ((val & 0xff) != 0xff && (val & 0x80)) {
1881203134Sthompsa		delta_2ghz = val & 0xf;
1882203134Sthompsa		if (!(val & 0x40))	/* negative number */
1883203134Sthompsa			delta_2ghz = -delta_2ghz;
1884203134Sthompsa	}
1885203134Sthompsa	val >>= 8;
1886203134Sthompsa	if ((val & 0xff) != 0xff && (val & 0x80)) {
1887203134Sthompsa		delta_5ghz = val & 0xf;
1888203134Sthompsa		if (!(val & 0x40))	/* negative number */
1889203134Sthompsa			delta_5ghz = -delta_5ghz;
1890203134Sthompsa	}
1891203134Sthompsa	DPRINTF("power compensation=%d (2GHz), %d (5GHz)\n",
1892203134Sthompsa	    delta_2ghz, delta_5ghz);
1893203134Sthompsa
1894203134Sthompsa	for (ridx = 0; ridx < 5; ridx++) {
1895203134Sthompsa		uint32_t reg;
1896203134Sthompsa
1897208019Sthompsa		run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2, &val);
1898208019Sthompsa		reg = val;
1899208019Sthompsa		run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2 + 1, &val);
1900208019Sthompsa		reg |= (uint32_t)val << 16;
1901203134Sthompsa
1902203134Sthompsa		sc->txpow20mhz[ridx] = reg;
1903203134Sthompsa		sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz);
1904203134Sthompsa		sc->txpow40mhz_5ghz[ridx] = b4inc(reg, delta_5ghz);
1905203134Sthompsa
1906203134Sthompsa		DPRINTF("ridx %d: power 20MHz=0x%08x, 40MHz/2GHz=0x%08x, "
1907203134Sthompsa		    "40MHz/5GHz=0x%08x\n", ridx, sc->txpow20mhz[ridx],
1908203134Sthompsa		    sc->txpow40mhz_2ghz[ridx], sc->txpow40mhz_5ghz[ridx]);
1909203134Sthompsa	}
1910203134Sthompsa
1911260219Skevlo	/* Read RSSI offsets and LNA gains from EEPROM. */
1912260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_2GHZ :
1913260219Skevlo	    RT3593_EEPROM_RSSI1_2GHZ, &val);
1914203134Sthompsa	sc->rssi_2ghz[0] = val & 0xff;	/* Ant A */
1915203134Sthompsa	sc->rssi_2ghz[1] = val >> 8;	/* Ant B */
1916260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_2GHZ :
1917260219Skevlo	    RT3593_EEPROM_RSSI2_2GHZ, &val);
1918205042Sthompsa	if (sc->mac_ver >= 0x3070) {
1919260219Skevlo		if (sc->mac_ver == 0x3593) {
1920260219Skevlo			sc->txmixgain_2ghz = 0;
1921260219Skevlo			sc->rssi_2ghz[2] = val & 0xff;	/* Ant C */
1922260219Skevlo		} else {
1923260219Skevlo			/*
1924260219Skevlo			 * On RT3070 chips (limited to 2 Rx chains), this ROM
1925260219Skevlo			 * field contains the Tx mixer gain for the 2GHz band.
1926260219Skevlo			 */
1927260219Skevlo			if ((val & 0xff) != 0xff)
1928260219Skevlo				sc->txmixgain_2ghz = val & 0x7;
1929260219Skevlo		}
1930205042Sthompsa		DPRINTF("tx mixer gain=%u (2GHz)\n", sc->txmixgain_2ghz);
1931205042Sthompsa	} else
1932205042Sthompsa		sc->rssi_2ghz[2] = val & 0xff;	/* Ant C */
1933260219Skevlo	if (sc->mac_ver == 0x3593)
1934260219Skevlo		run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val);
1935203134Sthompsa	sc->lna[2] = val >> 8;		/* channel group 2 */
1936203134Sthompsa
1937260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_5GHZ :
1938260219Skevlo	    RT3593_EEPROM_RSSI1_5GHZ, &val);
1939203134Sthompsa	sc->rssi_5ghz[0] = val & 0xff;	/* Ant A */
1940203134Sthompsa	sc->rssi_5ghz[1] = val >> 8;	/* Ant B */
1941260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_5GHZ :
1942260219Skevlo	    RT3593_EEPROM_RSSI2_5GHZ, &val);
1943205042Sthompsa	if (sc->mac_ver == 0x3572) {
1944205042Sthompsa		/*
1945205042Sthompsa		 * On RT3572 chips (limited to 2 Rx chains), this ROM
1946205042Sthompsa		 * field contains the Tx mixer gain for the 5GHz band.
1947205042Sthompsa		 */
1948205042Sthompsa		if ((val & 0xff) != 0xff)
1949205042Sthompsa			sc->txmixgain_5ghz = val & 0x7;
1950205042Sthompsa		DPRINTF("tx mixer gain=%u (5GHz)\n", sc->txmixgain_5ghz);
1951205042Sthompsa	} else
1952205042Sthompsa		sc->rssi_5ghz[2] = val & 0xff;	/* Ant C */
1953260219Skevlo	if (sc->mac_ver == 0x3593) {
1954260219Skevlo		sc->txmixgain_5ghz = 0;
1955260219Skevlo		run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val);
1956260219Skevlo	}
1957203134Sthompsa	sc->lna[3] = val >> 8;		/* channel group 3 */
1958203134Sthompsa
1959260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LNA :
1960260219Skevlo	    RT3593_EEPROM_LNA, &val);
1961203134Sthompsa	sc->lna[0] = val & 0xff;	/* channel group 0 */
1962203134Sthompsa	sc->lna[1] = val >> 8;		/* channel group 1 */
1963203134Sthompsa
1964203134Sthompsa	/* fix broken 5GHz LNA entries */
1965203134Sthompsa	if (sc->lna[2] == 0 || sc->lna[2] == 0xff) {
1966203134Sthompsa		DPRINTF("invalid LNA for channel group %d\n", 2);
1967203134Sthompsa		sc->lna[2] = sc->lna[1];
1968203134Sthompsa	}
1969203134Sthompsa	if (sc->lna[3] == 0 || sc->lna[3] == 0xff) {
1970203134Sthompsa		DPRINTF("invalid LNA for channel group %d\n", 3);
1971203134Sthompsa		sc->lna[3] = sc->lna[1];
1972203134Sthompsa	}
1973203134Sthompsa
1974203134Sthompsa	/* fix broken RSSI offset entries */
1975203134Sthompsa	for (ant = 0; ant < 3; ant++) {
1976203134Sthompsa		if (sc->rssi_2ghz[ant] < -10 || sc->rssi_2ghz[ant] > 10) {
1977203134Sthompsa			DPRINTF("invalid RSSI%d offset: %d (2GHz)\n",
1978203134Sthompsa			    ant + 1, sc->rssi_2ghz[ant]);
1979203134Sthompsa			sc->rssi_2ghz[ant] = 0;
1980203134Sthompsa		}
1981203134Sthompsa		if (sc->rssi_5ghz[ant] < -10 || sc->rssi_5ghz[ant] > 10) {
1982203134Sthompsa			DPRINTF("invalid RSSI%d offset: %d (5GHz)\n",
1983203134Sthompsa			    ant + 1, sc->rssi_5ghz[ant]);
1984203134Sthompsa			sc->rssi_5ghz[ant] = 0;
1985203134Sthompsa		}
1986203134Sthompsa	}
1987209917Sthompsa	return (0);
1988203134Sthompsa}
1989203134Sthompsa
1990218676Shselaskystatic struct ieee80211_node *
1991203134Sthompsarun_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
1992203134Sthompsa{
1993203134Sthompsa	return malloc(sizeof (struct run_node), M_DEVBUF, M_NOWAIT | M_ZERO);
1994203134Sthompsa}
1995203134Sthompsa
1996203134Sthompsastatic int
1997203134Sthompsarun_media_change(struct ifnet *ifp)
1998203134Sthompsa{
1999208019Sthompsa	struct ieee80211vap *vap = ifp->if_softc;
2000208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2001203134Sthompsa	const struct ieee80211_txparam *tp;
2002208019Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2003203134Sthompsa	uint8_t rate, ridx;
2004203134Sthompsa	int error;
2005203134Sthompsa
2006203134Sthompsa	RUN_LOCK(sc);
2007203134Sthompsa
2008203134Sthompsa	error = ieee80211_media_change(ifp);
2009209917Sthompsa	if (error != ENETRESET) {
2010203134Sthompsa		RUN_UNLOCK(sc);
2011209917Sthompsa		return (error);
2012208019Sthompsa	}
2013203134Sthompsa
2014203134Sthompsa	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
2015203134Sthompsa	if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
2016212127Sthompsa		struct ieee80211_node *ni;
2017212127Sthompsa		struct run_node	*rn;
2018212127Sthompsa
2019203134Sthompsa		rate = ic->ic_sup_rates[ic->ic_curmode].
2020203134Sthompsa		    rs_rates[tp->ucastrate] & IEEE80211_RATE_VAL;
2021203134Sthompsa		for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2022203134Sthompsa			if (rt2860_rates[ridx].rate == rate)
2023203134Sthompsa				break;
2024212127Sthompsa		ni = ieee80211_ref_node(vap->iv_bss);
2025212127Sthompsa		rn = (struct run_node *)ni;
2026208019Sthompsa		rn->fix_ridx = ridx;
2027208019Sthompsa		DPRINTF("rate=%d, fix_ridx=%d\n", rate, rn->fix_ridx);
2028212127Sthompsa		ieee80211_free_node(ni);
2029203134Sthompsa	}
2030203134Sthompsa
2031208019Sthompsa#if 0
2032203134Sthompsa	if ((ifp->if_flags & IFF_UP) &&
2033203134Sthompsa	    (ifp->if_drv_flags &  IFF_DRV_RUNNING)){
2034203134Sthompsa		run_init_locked(sc);
2035203134Sthompsa	}
2036208019Sthompsa#endif
2037203134Sthompsa
2038203134Sthompsa	RUN_UNLOCK(sc);
2039203134Sthompsa
2040209917Sthompsa	return (0);
2041203134Sthompsa}
2042203134Sthompsa
2043203134Sthompsastatic int
2044203134Sthompsarun_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
2045203134Sthompsa{
2046203134Sthompsa	const struct ieee80211_txparam *tp;
2047203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2048203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2049203134Sthompsa	struct run_vap *rvp = RUN_VAP(vap);
2050203134Sthompsa	enum ieee80211_state ostate;
2051208019Sthompsa	uint32_t sta[3];
2052203134Sthompsa	uint32_t tmp;
2053208019Sthompsa	uint8_t ratectl;
2054208019Sthompsa	uint8_t restart_ratectl = 0;
2055208019Sthompsa	uint8_t bid = 1 << rvp->rvp_id;
2056203134Sthompsa
2057203134Sthompsa	ostate = vap->iv_state;
2058203134Sthompsa	DPRINTF("%s -> %s\n",
2059203134Sthompsa		ieee80211_state_name[ostate],
2060203134Sthompsa		ieee80211_state_name[nstate]);
2061203134Sthompsa
2062203134Sthompsa	IEEE80211_UNLOCK(ic);
2063203134Sthompsa	RUN_LOCK(sc);
2064203134Sthompsa
2065208019Sthompsa	ratectl = sc->ratectl_run; /* remember current state */
2066208019Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
2067208019Sthompsa	usb_callout_stop(&sc->ratectl_ch);
2068203134Sthompsa
2069203134Sthompsa	if (ostate == IEEE80211_S_RUN) {
2070203134Sthompsa		/* turn link LED off */
2071203134Sthompsa		run_set_leds(sc, RT2860_LED_RADIO);
2072203134Sthompsa	}
2073203134Sthompsa
2074203134Sthompsa	switch (nstate) {
2075203134Sthompsa	case IEEE80211_S_INIT:
2076208019Sthompsa		restart_ratectl = 1;
2077208019Sthompsa
2078208019Sthompsa		if (ostate != IEEE80211_S_RUN)
2079208019Sthompsa			break;
2080208019Sthompsa
2081208019Sthompsa		ratectl &= ~bid;
2082208019Sthompsa		sc->runbmap &= ~bid;
2083208019Sthompsa
2084208019Sthompsa		/* abort TSF synchronization if there is no vap running */
2085209917Sthompsa		if (--sc->running == 0) {
2086203134Sthompsa			run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
2087203134Sthompsa			run_write(sc, RT2860_BCN_TIME_CFG,
2088203134Sthompsa			    tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
2089203134Sthompsa			    RT2860_TBTT_TIMER_EN));
2090203134Sthompsa		}
2091203134Sthompsa		break;
2092203134Sthompsa
2093203134Sthompsa	case IEEE80211_S_RUN:
2094209917Sthompsa		if (!(sc->runbmap & bid)) {
2095208019Sthompsa			if(sc->running++)
2096208019Sthompsa				restart_ratectl = 1;
2097208019Sthompsa			sc->runbmap |= bid;
2098208019Sthompsa		}
2099203134Sthompsa
2100218492Sbschmidt		m_freem(rvp->beacon_mbuf);
2101218492Sbschmidt		rvp->beacon_mbuf = NULL;
2102218492Sbschmidt
2103209917Sthompsa		switch (vap->iv_opmode) {
2104208019Sthompsa		case IEEE80211_M_HOSTAP:
2105208019Sthompsa		case IEEE80211_M_MBSS:
2106208019Sthompsa			sc->ap_running |= bid;
2107208019Sthompsa			ic->ic_opmode = vap->iv_opmode;
2108208019Sthompsa			run_update_beacon_cb(vap);
2109208019Sthompsa			break;
2110208019Sthompsa		case IEEE80211_M_IBSS:
2111208019Sthompsa			sc->adhoc_running |= bid;
2112209917Sthompsa			if (!sc->ap_running)
2113208019Sthompsa				ic->ic_opmode = vap->iv_opmode;
2114208019Sthompsa			run_update_beacon_cb(vap);
2115208019Sthompsa			break;
2116208019Sthompsa		case IEEE80211_M_STA:
2117208019Sthompsa			sc->sta_running |= bid;
2118209917Sthompsa			if (!sc->ap_running && !sc->adhoc_running)
2119208019Sthompsa				ic->ic_opmode = vap->iv_opmode;
2120208019Sthompsa
2121208019Sthompsa			/* read statistic counters (clear on read) */
2122208019Sthompsa			run_read_region_1(sc, RT2860_TX_STA_CNT0,
2123208019Sthompsa			    (uint8_t *)sta, sizeof sta);
2124208019Sthompsa
2125208019Sthompsa			break;
2126208019Sthompsa		default:
2127208019Sthompsa			ic->ic_opmode = vap->iv_opmode;
2128208019Sthompsa			break;
2129208019Sthompsa		}
2130208019Sthompsa
2131203134Sthompsa		if (vap->iv_opmode != IEEE80211_M_MONITOR) {
2132212127Sthompsa			struct ieee80211_node *ni;
2133212127Sthompsa
2134236439Shselasky			if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) {
2135236439Shselasky				RUN_UNLOCK(sc);
2136236439Shselasky				IEEE80211_LOCK(ic);
2137236439Shselasky				return (-1);
2138236439Shselasky			}
2139203134Sthompsa			run_updateslot(ic->ic_ifp);
2140203134Sthompsa			run_enable_mrr(sc);
2141203134Sthompsa			run_set_txpreamble(sc);
2142203134Sthompsa			run_set_basicrates(sc);
2143212127Sthompsa			ni = ieee80211_ref_node(vap->iv_bss);
2144203134Sthompsa			IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid);
2145203134Sthompsa			run_set_bssid(sc, ni->ni_bssid);
2146212127Sthompsa			ieee80211_free_node(ni);
2147208019Sthompsa			run_enable_tsf_sync(sc);
2148203134Sthompsa
2149208019Sthompsa			/* enable automatic rate adaptation */
2150208019Sthompsa			tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
2151208019Sthompsa			if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
2152208019Sthompsa				ratectl |= bid;
2153203134Sthompsa		}
2154203134Sthompsa
2155203134Sthompsa		/* turn link LED on */
2156203134Sthompsa		run_set_leds(sc, RT2860_LED_RADIO |
2157208019Sthompsa		    (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ?
2158203134Sthompsa		     RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ));
2159203134Sthompsa
2160203134Sthompsa		break;
2161203134Sthompsa	default:
2162203134Sthompsa		DPRINTFN(6, "undefined case\n");
2163203134Sthompsa		break;
2164203134Sthompsa	}
2165203134Sthompsa
2166208019Sthompsa	/* restart amrr for running VAPs */
2167209917Sthompsa	if ((sc->ratectl_run = ratectl) && restart_ratectl)
2168208019Sthompsa		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2169208019Sthompsa
2170203134Sthompsa	RUN_UNLOCK(sc);
2171203134Sthompsa	IEEE80211_LOCK(ic);
2172203134Sthompsa
2173203134Sthompsa	return(rvp->newstate(vap, nstate, arg));
2174203134Sthompsa}
2175203134Sthompsa
2176203134Sthompsa/* ARGSUSED */
2177203134Sthompsastatic void
2178208019Sthompsarun_wme_update_cb(void *arg)
2179203134Sthompsa{
2180203134Sthompsa	struct ieee80211com *ic = arg;
2181203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2182203134Sthompsa	struct ieee80211_wme_state *wmesp = &ic->ic_wme;
2183203134Sthompsa	int aci, error = 0;
2184203134Sthompsa
2185208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2186203134Sthompsa
2187203134Sthompsa	/* update MAC TX configuration registers */
2188203134Sthompsa	for (aci = 0; aci < WME_NUM_AC; aci++) {
2189203134Sthompsa		error = run_write(sc, RT2860_EDCA_AC_CFG(aci),
2190203134Sthompsa		    wmesp->wme_params[aci].wmep_logcwmax << 16 |
2191203134Sthompsa		    wmesp->wme_params[aci].wmep_logcwmin << 12 |
2192203134Sthompsa		    wmesp->wme_params[aci].wmep_aifsn  <<  8 |
2193203134Sthompsa		    wmesp->wme_params[aci].wmep_txopLimit);
2194209917Sthompsa		if (error) goto err;
2195203134Sthompsa	}
2196203134Sthompsa
2197203134Sthompsa	/* update SCH/DMA registers too */
2198203134Sthompsa	error = run_write(sc, RT2860_WMM_AIFSN_CFG,
2199203134Sthompsa	    wmesp->wme_params[WME_AC_VO].wmep_aifsn  << 12 |
2200203134Sthompsa	    wmesp->wme_params[WME_AC_VI].wmep_aifsn  <<  8 |
2201203134Sthompsa	    wmesp->wme_params[WME_AC_BK].wmep_aifsn  <<  4 |
2202203134Sthompsa	    wmesp->wme_params[WME_AC_BE].wmep_aifsn);
2203209917Sthompsa	if (error) goto err;
2204203134Sthompsa	error = run_write(sc, RT2860_WMM_CWMIN_CFG,
2205203134Sthompsa	    wmesp->wme_params[WME_AC_VO].wmep_logcwmin << 12 |
2206203134Sthompsa	    wmesp->wme_params[WME_AC_VI].wmep_logcwmin <<  8 |
2207203134Sthompsa	    wmesp->wme_params[WME_AC_BK].wmep_logcwmin <<  4 |
2208203134Sthompsa	    wmesp->wme_params[WME_AC_BE].wmep_logcwmin);
2209209917Sthompsa	if (error) goto err;
2210203134Sthompsa	error = run_write(sc, RT2860_WMM_CWMAX_CFG,
2211203134Sthompsa	    wmesp->wme_params[WME_AC_VO].wmep_logcwmax << 12 |
2212203134Sthompsa	    wmesp->wme_params[WME_AC_VI].wmep_logcwmax <<  8 |
2213203134Sthompsa	    wmesp->wme_params[WME_AC_BK].wmep_logcwmax <<  4 |
2214203134Sthompsa	    wmesp->wme_params[WME_AC_BE].wmep_logcwmax);
2215209917Sthompsa	if (error) goto err;
2216203134Sthompsa	error = run_write(sc, RT2860_WMM_TXOP0_CFG,
2217203134Sthompsa	    wmesp->wme_params[WME_AC_BK].wmep_txopLimit << 16 |
2218203134Sthompsa	    wmesp->wme_params[WME_AC_BE].wmep_txopLimit);
2219209917Sthompsa	if (error) goto err;
2220203134Sthompsa	error = run_write(sc, RT2860_WMM_TXOP1_CFG,
2221203134Sthompsa	    wmesp->wme_params[WME_AC_VO].wmep_txopLimit << 16 |
2222203134Sthompsa	    wmesp->wme_params[WME_AC_VI].wmep_txopLimit);
2223203134Sthompsa
2224203134Sthompsaerr:
2225209917Sthompsa	if (error)
2226203134Sthompsa		DPRINTF("WME update failed\n");
2227203134Sthompsa
2228203134Sthompsa	return;
2229203134Sthompsa}
2230203134Sthompsa
2231208019Sthompsastatic int
2232208019Sthompsarun_wme_update(struct ieee80211com *ic)
2233208019Sthompsa{
2234208019Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2235208019Sthompsa
2236208019Sthompsa	/* sometime called wothout lock */
2237209917Sthompsa	if (mtx_owned(&ic->ic_comlock.mtx)) {
2238208019Sthompsa		uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
2239208019Sthompsa		DPRINTF("cmdq_store=%d\n", i);
2240208019Sthompsa		sc->cmdq[i].func = run_wme_update_cb;
2241208019Sthompsa		sc->cmdq[i].arg0 = ic;
2242208019Sthompsa		ieee80211_runtask(ic, &sc->cmdq_task);
2243209918Sthompsa		return (0);
2244208019Sthompsa	}
2245208019Sthompsa
2246208019Sthompsa	RUN_LOCK(sc);
2247208019Sthompsa	run_wme_update_cb(ic);
2248208019Sthompsa	RUN_UNLOCK(sc);
2249208019Sthompsa
2250208019Sthompsa	/* return whatever, upper layer desn't care anyway */
2251208019Sthompsa	return (0);
2252208019Sthompsa}
2253208019Sthompsa
2254203134Sthompsastatic void
2255203134Sthompsarun_key_update_begin(struct ieee80211vap *vap)
2256203134Sthompsa{
2257203134Sthompsa	/*
2258208019Sthompsa	 * To avoid out-of-order events, both run_key_set() and
2259208019Sthompsa	 * _delete() are deferred and handled by run_cmdq_cb().
2260208019Sthompsa	 * So, there is nothing we need to do here.
2261203134Sthompsa	 */
2262203134Sthompsa}
2263203134Sthompsa
2264203134Sthompsastatic void
2265203134Sthompsarun_key_update_end(struct ieee80211vap *vap)
2266203134Sthompsa{
2267203134Sthompsa	/* null */
2268203134Sthompsa}
2269203134Sthompsa
2270208019Sthompsastatic void
2271208019Sthompsarun_key_set_cb(void *arg)
2272203134Sthompsa{
2273208019Sthompsa	struct run_cmdq *cmdq = arg;
2274208019Sthompsa	struct ieee80211vap *vap = cmdq->arg1;
2275208019Sthompsa	struct ieee80211_key *k = cmdq->k;
2276203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2277208019Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2278203134Sthompsa	struct ieee80211_node *ni;
2279203134Sthompsa	uint32_t attr;
2280203134Sthompsa	uint16_t base, associd;
2281209144Sthompsa	uint8_t mode, wcid, iv[8];
2282203134Sthompsa
2283208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2284203134Sthompsa
2285209917Sthompsa	if (vap->iv_opmode == IEEE80211_M_HOSTAP)
2286208019Sthompsa		ni = ieee80211_find_vap_node(&ic->ic_sta, vap, cmdq->mac);
2287209144Sthompsa	else
2288203134Sthompsa		ni = vap->iv_bss;
2289208019Sthompsa	associd = (ni != NULL) ? ni->ni_associd : 0;
2290203134Sthompsa
2291203134Sthompsa	/* map net80211 cipher to RT2860 security mode */
2292203134Sthompsa	switch (k->wk_cipher->ic_cipher) {
2293203134Sthompsa	case IEEE80211_CIPHER_WEP:
2294203134Sthompsa		if(k->wk_keylen < 8)
2295203134Sthompsa			mode = RT2860_MODE_WEP40;
2296203134Sthompsa		else
2297203134Sthompsa			mode = RT2860_MODE_WEP104;
2298203134Sthompsa		break;
2299203134Sthompsa	case IEEE80211_CIPHER_TKIP:
2300203134Sthompsa		mode = RT2860_MODE_TKIP;
2301203134Sthompsa		break;
2302203134Sthompsa	case IEEE80211_CIPHER_AES_CCM:
2303203134Sthompsa		mode = RT2860_MODE_AES_CCMP;
2304203134Sthompsa		break;
2305203134Sthompsa	default:
2306203134Sthompsa		DPRINTF("undefined case\n");
2307208019Sthompsa		return;
2308203134Sthompsa	}
2309203134Sthompsa
2310208019Sthompsa	DPRINTFN(1, "associd=%x, keyix=%d, mode=%x, type=%s, tx=%s, rx=%s\n",
2311203134Sthompsa	    associd, k->wk_keyix, mode,
2312208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_GROUP) ? "group" : "pairwise",
2313208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_XMIT) ? "on" : "off",
2314208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_RECV) ? "on" : "off");
2315203134Sthompsa
2316203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2317203134Sthompsa		wcid = 0;	/* NB: update WCID0 for group keys */
2318208019Sthompsa		base = RT2860_SKEY(RUN_VAP(vap)->rvp_id, k->wk_keyix);
2319203134Sthompsa	} else {
2320245047Shselasky		wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
2321245047Shselasky		    1 : RUN_AID2WCID(associd);
2322203134Sthompsa		base = RT2860_PKEY(wcid);
2323203134Sthompsa	}
2324203134Sthompsa
2325203134Sthompsa	if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) {
2326203134Sthompsa		if(run_write_region_1(sc, base, k->wk_key, 16))
2327208019Sthompsa			return;
2328209144Sthompsa		if(run_write_region_1(sc, base + 16, &k->wk_key[16], 8))	/* wk_txmic */
2329208019Sthompsa			return;
2330209144Sthompsa		if(run_write_region_1(sc, base + 24, &k->wk_key[24], 8))	/* wk_rxmic */
2331208019Sthompsa			return;
2332203134Sthompsa	} else {
2333203134Sthompsa		/* roundup len to 16-bit: XXX fix write_region_1() instead */
2334203134Sthompsa		if(run_write_region_1(sc, base, k->wk_key, (k->wk_keylen + 1) & ~1))
2335208019Sthompsa			return;
2336203134Sthompsa	}
2337203134Sthompsa
2338203134Sthompsa	if (!(k->wk_flags & IEEE80211_KEY_GROUP) ||
2339203134Sthompsa	    (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))) {
2340203134Sthompsa		/* set initial packet number in IV+EIV */
2341209917Sthompsa		if (k->wk_cipher == IEEE80211_CIPHER_WEP) {
2342203134Sthompsa			memset(iv, 0, sizeof iv);
2343208019Sthompsa			iv[3] = vap->iv_def_txkey << 6;
2344203134Sthompsa		} else {
2345203134Sthompsa			if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) {
2346203134Sthompsa				iv[0] = k->wk_keytsc >> 8;
2347203134Sthompsa				iv[1] = (iv[0] | 0x20) & 0x7f;
2348203134Sthompsa				iv[2] = k->wk_keytsc;
2349203134Sthompsa			} else /* CCMP */ {
2350203134Sthompsa				iv[0] = k->wk_keytsc;
2351203134Sthompsa				iv[1] = k->wk_keytsc >> 8;
2352203134Sthompsa				iv[2] = 0;
2353203134Sthompsa			}
2354203134Sthompsa			iv[3] = k->wk_keyix << 6 | IEEE80211_WEP_EXTIV;
2355203134Sthompsa			iv[4] = k->wk_keytsc >> 16;
2356203134Sthompsa			iv[5] = k->wk_keytsc >> 24;
2357203134Sthompsa			iv[6] = k->wk_keytsc >> 32;
2358203134Sthompsa			iv[7] = k->wk_keytsc >> 40;
2359203134Sthompsa		}
2360209917Sthompsa		if (run_write_region_1(sc, RT2860_IVEIV(wcid), iv, 8))
2361208019Sthompsa			return;
2362203134Sthompsa	}
2363203134Sthompsa
2364203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2365203134Sthompsa		/* install group key */
2366209917Sthompsa		if (run_read(sc, RT2860_SKEY_MODE_0_7, &attr))
2367208019Sthompsa			return;
2368203134Sthompsa		attr &= ~(0xf << (k->wk_keyix * 4));
2369203134Sthompsa		attr |= mode << (k->wk_keyix * 4);
2370209917Sthompsa		if (run_write(sc, RT2860_SKEY_MODE_0_7, attr))
2371208019Sthompsa			return;
2372203134Sthompsa	} else {
2373203134Sthompsa		/* install pairwise key */
2374209917Sthompsa		if (run_read(sc, RT2860_WCID_ATTR(wcid), &attr))
2375208019Sthompsa			return;
2376203134Sthompsa		attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN;
2377209917Sthompsa		if (run_write(sc, RT2860_WCID_ATTR(wcid), attr))
2378208019Sthompsa			return;
2379203134Sthompsa	}
2380203134Sthompsa
2381203134Sthompsa	/* TODO create a pass-thru key entry? */
2382203134Sthompsa
2383208019Sthompsa	/* need wcid to delete the right key later */
2384208019Sthompsa	k->wk_pad = wcid;
2385203134Sthompsa}
2386203134Sthompsa
2387203134Sthompsa/*
2388208019Sthompsa * Don't have to be deferred, but in order to keep order of
2389208019Sthompsa * execution, i.e. with run_key_delete(), defer this and let
2390208019Sthompsa * run_cmdq_cb() maintain the order.
2391208019Sthompsa *
2392203134Sthompsa * return 0 on error
2393203134Sthompsa */
2394203134Sthompsastatic int
2395208019Sthompsarun_key_set(struct ieee80211vap *vap, struct ieee80211_key *k,
2396208019Sthompsa		const uint8_t mac[IEEE80211_ADDR_LEN])
2397203134Sthompsa{
2398203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2399203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2400208019Sthompsa	uint32_t i;
2401208019Sthompsa
2402208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
2403208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
2404208019Sthompsa	sc->cmdq[i].func = run_key_set_cb;
2405208019Sthompsa	sc->cmdq[i].arg0 = NULL;
2406208019Sthompsa	sc->cmdq[i].arg1 = vap;
2407208019Sthompsa	sc->cmdq[i].k = k;
2408208019Sthompsa	IEEE80211_ADDR_COPY(sc->cmdq[i].mac, mac);
2409208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
2410208019Sthompsa
2411209144Sthompsa	/*
2412209144Sthompsa	 * To make sure key will be set when hostapd
2413209144Sthompsa	 * calls iv_key_set() before if_init().
2414209144Sthompsa	 */
2415209917Sthompsa	if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
2416209144Sthompsa		RUN_LOCK(sc);
2417209144Sthompsa		sc->cmdq_key_set = RUN_CMDQ_GO;
2418209144Sthompsa		RUN_UNLOCK(sc);
2419209144Sthompsa	}
2420209144Sthompsa
2421209917Sthompsa	return (1);
2422208019Sthompsa}
2423208019Sthompsa
2424208019Sthompsa/*
2425208019Sthompsa * If wlan is destroyed without being brought down i.e. without
2426208019Sthompsa * wlan down or wpa_cli terminate, this function is called after
2427208019Sthompsa * vap is gone. Don't refer it.
2428208019Sthompsa */
2429208019Sthompsastatic void
2430208019Sthompsarun_key_delete_cb(void *arg)
2431208019Sthompsa{
2432208019Sthompsa	struct run_cmdq *cmdq = arg;
2433208019Sthompsa	struct run_softc *sc = cmdq->arg1;
2434208019Sthompsa	struct ieee80211_key *k = &cmdq->key;
2435203134Sthompsa	uint32_t attr;
2436203134Sthompsa	uint8_t wcid;
2437203134Sthompsa
2438208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2439203134Sthompsa
2440203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2441203134Sthompsa		/* remove group key */
2442208019Sthompsa		DPRINTF("removing group key\n");
2443208019Sthompsa		run_read(sc, RT2860_SKEY_MODE_0_7, &attr);
2444203134Sthompsa		attr &= ~(0xf << (k->wk_keyix * 4));
2445208019Sthompsa		run_write(sc, RT2860_SKEY_MODE_0_7, attr);
2446203134Sthompsa	} else {
2447203134Sthompsa		/* remove pairwise key */
2448208019Sthompsa		DPRINTF("removing key for wcid %x\n", k->wk_pad);
2449208019Sthompsa		/* matching wcid was written to wk_pad in run_key_set() */
2450208019Sthompsa		wcid = k->wk_pad;
2451208019Sthompsa		run_read(sc, RT2860_WCID_ATTR(wcid), &attr);
2452203134Sthompsa		attr &= ~0xf;
2453208019Sthompsa		run_write(sc, RT2860_WCID_ATTR(wcid), attr);
2454208019Sthompsa		run_set_region_4(sc, RT2860_WCID_ENTRY(wcid), 0, 8);
2455203134Sthompsa	}
2456203134Sthompsa
2457208019Sthompsa	k->wk_pad = 0;
2458203134Sthompsa}
2459203134Sthompsa
2460208019Sthompsa/*
2461208019Sthompsa * return 0 on error
2462208019Sthompsa */
2463208019Sthompsastatic int
2464208019Sthompsarun_key_delete(struct ieee80211vap *vap, struct ieee80211_key *k)
2465203134Sthompsa{
2466208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2467208019Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2468208019Sthompsa	struct ieee80211_key *k0;
2469208019Sthompsa	uint32_t i;
2470203134Sthompsa
2471208019Sthompsa	/*
2472208019Sthompsa	 * When called back, key might be gone. So, make a copy
2473208019Sthompsa	 * of some values need to delete keys before deferring.
2474208019Sthompsa	 * But, because of LOR with node lock, cannot use lock here.
2475208019Sthompsa	 * So, use atomic instead.
2476208019Sthompsa	 */
2477208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
2478208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
2479208019Sthompsa	sc->cmdq[i].func = run_key_delete_cb;
2480208019Sthompsa	sc->cmdq[i].arg0 = NULL;
2481208019Sthompsa	sc->cmdq[i].arg1 = sc;
2482208019Sthompsa	k0 = &sc->cmdq[i].key;
2483208019Sthompsa	k0->wk_flags = k->wk_flags;
2484208019Sthompsa	k0->wk_keyix = k->wk_keyix;
2485208019Sthompsa	/* matching wcid was written to wk_pad in run_key_set() */
2486208019Sthompsa	k0->wk_pad = k->wk_pad;
2487208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
2488208019Sthompsa	return (1);	/* return fake success */
2489203134Sthompsa
2490203134Sthompsa}
2491203134Sthompsa
2492203134Sthompsastatic void
2493206358Srpaulorun_ratectl_to(void *arg)
2494203134Sthompsa{
2495208019Sthompsa	struct run_softc *sc = arg;
2496203134Sthompsa
2497203134Sthompsa	/* do it in a process context, so it can go sleep */
2498208019Sthompsa	ieee80211_runtask(sc->sc_ifp->if_l2com, &sc->ratectl_task);
2499203134Sthompsa	/* next timeout will be rescheduled in the callback task */
2500203134Sthompsa}
2501203134Sthompsa
2502203134Sthompsa/* ARGSUSED */
2503203134Sthompsastatic void
2504206358Srpaulorun_ratectl_cb(void *arg, int pending)
2505203134Sthompsa{
2506208019Sthompsa	struct run_softc *sc = arg;
2507208019Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
2508208019Sthompsa	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
2509203134Sthompsa
2510209917Sthompsa	if (vap == NULL)
2511208019Sthompsa		return;
2512208019Sthompsa
2513262795Shselasky	if (sc->rvp_cnt > 1 || vap->iv_opmode != IEEE80211_M_STA) {
2514203134Sthompsa		/*
2515203134Sthompsa		 * run_reset_livelock() doesn't do anything with AMRR,
2516203134Sthompsa		 * but Ralink wants us to call it every 1 sec. So, we
2517203134Sthompsa		 * piggyback here rather than creating another callout.
2518203134Sthompsa		 * Livelock may occur only in HOSTAP or IBSS mode
2519203134Sthompsa		 * (when h/w is sending beacons).
2520203134Sthompsa		 */
2521203134Sthompsa		RUN_LOCK(sc);
2522203134Sthompsa		run_reset_livelock(sc);
2523208019Sthompsa		/* just in case, there are some stats to drain */
2524208019Sthompsa		run_drain_fifo(sc);
2525203134Sthompsa		RUN_UNLOCK(sc);
2526203134Sthompsa	}
2527203134Sthompsa
2528262795Shselasky	ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, sc);
2529262795Shselasky
2530257712Shselasky	RUN_LOCK(sc);
2531208019Sthompsa	if(sc->ratectl_run != RUN_RATECTL_OFF)
2532208019Sthompsa		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2533257712Shselasky	RUN_UNLOCK(sc);
2534203134Sthompsa}
2535203134Sthompsa
2536203134Sthompsastatic void
2537208019Sthompsarun_drain_fifo(void *arg)
2538203134Sthompsa{
2539208019Sthompsa	struct run_softc *sc = arg;
2540208019Sthompsa	struct ifnet *ifp = sc->sc_ifp;
2541208019Sthompsa	uint32_t stat;
2542218676Shselasky	uint16_t (*wstat)[3];
2543203134Sthompsa	uint8_t wcid, mcs, pid;
2544218676Shselasky	int8_t retry;
2545203134Sthompsa
2546208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2547203134Sthompsa
2548208019Sthompsa	for (;;) {
2549203134Sthompsa		/* drain Tx status FIFO (maxsize = 16) */
2550203134Sthompsa		run_read(sc, RT2860_TX_STAT_FIFO, &stat);
2551208019Sthompsa		DPRINTFN(4, "tx stat 0x%08x\n", stat);
2552209917Sthompsa		if (!(stat & RT2860_TXQ_VLD))
2553208019Sthompsa			break;
2554203134Sthompsa
2555208019Sthompsa		wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff;
2556203134Sthompsa
2557208019Sthompsa		/* if no ACK was requested, no feedback is available */
2558208019Sthompsa		if (!(stat & RT2860_TXQ_ACKREQ) || wcid > RT2870_WCID_MAX ||
2559208019Sthompsa		    wcid == 0)
2560208019Sthompsa			continue;
2561203134Sthompsa
2562218676Shselasky		/*
2563218676Shselasky		 * Even though each stat is Tx-complete-status like format,
2564218676Shselasky		 * the device can poll stats. Because there is no guarantee
2565218676Shselasky		 * that the referring node is still around when read the stats.
2566218676Shselasky		 * So that, if we use ieee80211_ratectl_tx_update(), we will
2567218676Shselasky		 * have hard time not to refer already freed node.
2568218676Shselasky		 *
2569218676Shselasky		 * To eliminate such page faults, we poll stats in softc.
2570218676Shselasky		 * Then, update the rates later with ieee80211_ratectl_tx_update().
2571218676Shselasky		 */
2572218676Shselasky		wstat = &(sc->wcid_stats[wcid]);
2573218676Shselasky		(*wstat)[RUN_TXCNT]++;
2574218676Shselasky		if (stat & RT2860_TXQ_OK)
2575218676Shselasky			(*wstat)[RUN_SUCCESS]++;
2576218676Shselasky		else
2577271866Sglebius			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
2578218676Shselasky		/*
2579218676Shselasky		 * Check if there were retries, ie if the Tx success rate is
2580218676Shselasky		 * different from the requested rate. Note that it works only
2581218676Shselasky		 * because we do not allow rate fallback from OFDM to CCK.
2582218676Shselasky		 */
2583218676Shselasky		mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f;
2584218676Shselasky		pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf;
2585218676Shselasky		if ((retry = pid -1 - mcs) > 0) {
2586218676Shselasky			(*wstat)[RUN_TXCNT] += retry;
2587218676Shselasky			(*wstat)[RUN_RETRY] += retry;
2588203134Sthompsa		}
2589208019Sthompsa	}
2590208019Sthompsa	DPRINTFN(3, "count=%d\n", sc->fifo_cnt);
2591208019Sthompsa
2592208019Sthompsa	sc->fifo_cnt = 0;
2593208019Sthompsa}
2594208019Sthompsa
2595208019Sthompsastatic void
2596208019Sthompsarun_iter_func(void *arg, struct ieee80211_node *ni)
2597208019Sthompsa{
2598208019Sthompsa	struct run_softc *sc = arg;
2599208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
2600208019Sthompsa	struct ieee80211com *ic = ni->ni_ic;
2601208019Sthompsa	struct ifnet *ifp = ic->ic_ifp;
2602208019Sthompsa	struct run_node *rn = (void *)ni;
2603218676Shselasky	union run_stats sta[2];
2604218676Shselasky	uint16_t (*wstat)[3];
2605218676Shselasky	int txcnt, success, retrycnt, error;
2606208019Sthompsa
2607218676Shselasky	RUN_LOCK(sc);
2608218676Shselasky
2609262795Shselasky	/* Check for special case */
2610262795Shselasky	if (sc->rvp_cnt <= 1 && vap->iv_opmode == IEEE80211_M_STA &&
2611262795Shselasky	    ni != vap->iv_bss)
2612262795Shselasky		goto fail;
2613262795Shselasky
2614209917Sthompsa	if (sc->rvp_cnt <= 1 && (vap->iv_opmode == IEEE80211_M_IBSS ||
2615209917Sthompsa	    vap->iv_opmode == IEEE80211_M_STA)) {
2616203134Sthompsa		/* read statistic counters (clear on read) and update AMRR state */
2617203134Sthompsa		error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta,
2618203134Sthompsa		    sizeof sta);
2619203134Sthompsa		if (error != 0)
2620218676Shselasky			goto fail;
2621203134Sthompsa
2622203134Sthompsa		/* count failed TX as errors */
2623271866Sglebius		if_inc_counter(ifp, IFCOUNTER_OERRORS, le16toh(sta[0].error.fail));
2624203134Sthompsa
2625218676Shselasky		retrycnt = le16toh(sta[1].tx.retry);
2626218676Shselasky		success = le16toh(sta[1].tx.success);
2627218676Shselasky		txcnt = retrycnt + success + le16toh(sta[0].error.fail);
2628203134Sthompsa
2629218676Shselasky		DPRINTFN(3, "retrycnt=%d success=%d failcnt=%d\n",
2630218676Shselasky			retrycnt, success, le16toh(sta[0].error.fail));
2631218676Shselasky	} else {
2632218676Shselasky		wstat = &(sc->wcid_stats[RUN_AID2WCID(ni->ni_associd)]);
2633203134Sthompsa
2634218676Shselasky		if (wstat == &(sc->wcid_stats[0]) ||
2635218676Shselasky		    wstat > &(sc->wcid_stats[RT2870_WCID_MAX]))
2636218676Shselasky			goto fail;
2637208019Sthompsa
2638218676Shselasky		txcnt = (*wstat)[RUN_TXCNT];
2639218676Shselasky		success = (*wstat)[RUN_SUCCESS];
2640218676Shselasky		retrycnt = (*wstat)[RUN_RETRY];
2641218676Shselasky		DPRINTFN(3, "retrycnt=%d txcnt=%d success=%d\n",
2642218676Shselasky		    retrycnt, txcnt, success);
2643208019Sthompsa
2644218676Shselasky		memset(wstat, 0, sizeof(*wstat));
2645203134Sthompsa	}
2646203134Sthompsa
2647218676Shselasky	ieee80211_ratectl_tx_update(vap, ni, &txcnt, &success, &retrycnt);
2648208019Sthompsa	rn->amrr_ridx = ieee80211_ratectl_rate(ni, NULL, 0);
2649218676Shselasky
2650218676Shselaskyfail:
2651218676Shselasky	RUN_UNLOCK(sc);
2652218676Shselasky
2653208019Sthompsa	DPRINTFN(3, "ridx=%d\n", rn->amrr_ridx);
2654208019Sthompsa}
2655203134Sthompsa
2656208019Sthompsastatic void
2657208019Sthompsarun_newassoc_cb(void *arg)
2658208019Sthompsa{
2659208019Sthompsa	struct run_cmdq *cmdq = arg;
2660208019Sthompsa	struct ieee80211_node *ni = cmdq->arg1;
2661208019Sthompsa	struct run_softc *sc = ni->ni_vap->iv_ic->ic_ifp->if_softc;
2662208019Sthompsa	uint8_t wcid = cmdq->wcid;
2663203134Sthompsa
2664208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2665208019Sthompsa
2666208019Sthompsa	run_write_region_1(sc, RT2860_WCID_ENTRY(wcid),
2667208019Sthompsa	    ni->ni_macaddr, IEEE80211_ADDR_LEN);
2668218676Shselasky
2669218676Shselasky	memset(&(sc->wcid_stats[wcid]), 0, sizeof(sc->wcid_stats[wcid]));
2670203134Sthompsa}
2671203134Sthompsa
2672203134Sthompsastatic void
2673203134Sthompsarun_newassoc(struct ieee80211_node *ni, int isnew)
2674203134Sthompsa{
2675203134Sthompsa	struct run_node *rn = (void *)ni;
2676203134Sthompsa	struct ieee80211_rateset *rs = &ni->ni_rates;
2677208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
2678208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2679208019Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
2680203134Sthompsa	uint8_t rate;
2681208019Sthompsa	uint8_t ridx;
2682245047Shselasky	uint8_t wcid;
2683208019Sthompsa	int i, j;
2684203134Sthompsa
2685245047Shselasky	wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
2686245047Shselasky	    1 : RUN_AID2WCID(ni->ni_associd);
2687245047Shselasky
2688209917Sthompsa	if (wcid > RT2870_WCID_MAX) {
2689208019Sthompsa		device_printf(sc->sc_dev, "wcid=%d out of range\n", wcid);
2690208019Sthompsa		return;
2691208019Sthompsa	}
2692203134Sthompsa
2693208019Sthompsa	/* only interested in true associations */
2694209917Sthompsa	if (isnew && ni->ni_associd != 0) {
2695208019Sthompsa
2696208019Sthompsa		/*
2697208019Sthompsa		 * This function could is called though timeout function.
2698208019Sthompsa		 * Need to defer.
2699208019Sthompsa		 */
2700208019Sthompsa		uint32_t cnt = RUN_CMDQ_GET(&sc->cmdq_store);
2701208019Sthompsa		DPRINTF("cmdq_store=%d\n", cnt);
2702208019Sthompsa		sc->cmdq[cnt].func = run_newassoc_cb;
2703208019Sthompsa		sc->cmdq[cnt].arg0 = NULL;
2704208019Sthompsa		sc->cmdq[cnt].arg1 = ni;
2705208019Sthompsa		sc->cmdq[cnt].wcid = wcid;
2706208019Sthompsa		ieee80211_runtask(ic, &sc->cmdq_task);
2707208019Sthompsa	}
2708208019Sthompsa
2709208019Sthompsa	DPRINTF("new assoc isnew=%d associd=%x addr=%s\n",
2710208019Sthompsa	    isnew, ni->ni_associd, ether_sprintf(ni->ni_macaddr));
2711208019Sthompsa
2712203134Sthompsa	for (i = 0; i < rs->rs_nrates; i++) {
2713203134Sthompsa		rate = rs->rs_rates[i] & IEEE80211_RATE_VAL;
2714203134Sthompsa		/* convert 802.11 rate to hardware rate index */
2715203134Sthompsa		for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2716203134Sthompsa			if (rt2860_rates[ridx].rate == rate)
2717203134Sthompsa				break;
2718203134Sthompsa		rn->ridx[i] = ridx;
2719203134Sthompsa		/* determine rate of control response frames */
2720203134Sthompsa		for (j = i; j >= 0; j--) {
2721203134Sthompsa			if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) &&
2722203134Sthompsa			    rt2860_rates[rn->ridx[i]].phy ==
2723203134Sthompsa			    rt2860_rates[rn->ridx[j]].phy)
2724203134Sthompsa				break;
2725203134Sthompsa		}
2726203134Sthompsa		if (j >= 0) {
2727203134Sthompsa			rn->ctl_ridx[i] = rn->ridx[j];
2728203134Sthompsa		} else {
2729203134Sthompsa			/* no basic rate found, use mandatory one */
2730203134Sthompsa			rn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx;
2731203134Sthompsa		}
2732203134Sthompsa		DPRINTF("rate=0x%02x ridx=%d ctl_ridx=%d\n",
2733203134Sthompsa		    rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]);
2734203134Sthompsa	}
2735208019Sthompsa	rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate;
2736208019Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2737208019Sthompsa		if (rt2860_rates[ridx].rate == rate)
2738208019Sthompsa			break;
2739208019Sthompsa	rn->mgt_ridx = ridx;
2740208019Sthompsa	DPRINTF("rate=%d, mgmt_ridx=%d\n", rate, rn->mgt_ridx);
2741208019Sthompsa
2742262795Shselasky	RUN_LOCK(sc);
2743262795Shselasky	if(sc->ratectl_run != RUN_RATECTL_OFF)
2744262795Shselasky		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2745262795Shselasky	RUN_UNLOCK(sc);
2746203134Sthompsa}
2747203134Sthompsa
2748203134Sthompsa/*
2749203134Sthompsa * Return the Rx chain with the highest RSSI for a given frame.
2750203134Sthompsa */
2751203134Sthompsastatic __inline uint8_t
2752203134Sthompsarun_maxrssi_chain(struct run_softc *sc, const struct rt2860_rxwi *rxwi)
2753203134Sthompsa{
2754203134Sthompsa	uint8_t rxchain = 0;
2755203134Sthompsa
2756203134Sthompsa	if (sc->nrxchains > 1) {
2757203134Sthompsa		if (rxwi->rssi[1] > rxwi->rssi[rxchain])
2758203134Sthompsa			rxchain = 1;
2759203134Sthompsa		if (sc->nrxchains > 2)
2760203134Sthompsa			if (rxwi->rssi[2] > rxwi->rssi[rxchain])
2761203134Sthompsa				rxchain = 2;
2762203134Sthompsa	}
2763209917Sthompsa	return (rxchain);
2764203134Sthompsa}
2765203134Sthompsa
2766203134Sthompsastatic void
2767203134Sthompsarun_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen)
2768203134Sthompsa{
2769203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
2770203134Sthompsa	struct ieee80211com *ic = ifp->if_l2com;
2771203134Sthompsa	struct ieee80211_frame *wh;
2772203134Sthompsa	struct ieee80211_node *ni;
2773203134Sthompsa	struct rt2870_rxd *rxd;
2774203134Sthompsa	struct rt2860_rxwi *rxwi;
2775203134Sthompsa	uint32_t flags;
2776259032Skevlo	uint16_t len, rxwisize;
2777203134Sthompsa	uint8_t ant, rssi;
2778203134Sthompsa	int8_t nf;
2779203134Sthompsa
2780203134Sthompsa	rxwi = mtod(m, struct rt2860_rxwi *);
2781203134Sthompsa	len = le16toh(rxwi->len) & 0xfff;
2782260219Skevlo	rxwisize = sizeof(struct rt2860_rxwi);
2783260219Skevlo	if (sc->mac_ver == 0x5592)
2784260219Skevlo		rxwisize += sizeof(uint64_t);
2785260219Skevlo	else if (sc->mac_ver == 0x3593)
2786260219Skevlo		rxwisize += sizeof(uint32_t);
2787203134Sthompsa	if (__predict_false(len > dmalen)) {
2788203134Sthompsa		m_freem(m);
2789271866Sglebius		if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
2790203134Sthompsa		DPRINTF("bad RXWI length %u > %u\n", len, dmalen);
2791203134Sthompsa		return;
2792203134Sthompsa	}
2793203134Sthompsa	/* Rx descriptor is located at the end */
2794203134Sthompsa	rxd = (struct rt2870_rxd *)(mtod(m, caddr_t) + dmalen);
2795203134Sthompsa	flags = le32toh(rxd->flags);
2796203134Sthompsa
2797203134Sthompsa	if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) {
2798203134Sthompsa		m_freem(m);
2799271866Sglebius		if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
2800203134Sthompsa		DPRINTF("%s error.\n", (flags & RT2860_RX_CRCERR)?"CRC":"ICV");
2801203134Sthompsa		return;
2802203134Sthompsa	}
2803203134Sthompsa
2804259032Skevlo	m->m_data += rxwisize;
2805259032Skevlo	m->m_pkthdr.len = m->m_len -= rxwisize;
2806203134Sthompsa
2807203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
2808203134Sthompsa
2809260444Skevlo	if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
2810260444Skevlo		wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
2811203134Sthompsa		m->m_flags |= M_WEP;
2812203134Sthompsa	}
2813203134Sthompsa
2814209917Sthompsa	if (flags & RT2860_RX_L2PAD) {
2815203134Sthompsa		DPRINTFN(8, "received RT2860_RX_L2PAD frame\n");
2816203134Sthompsa		len += 2;
2817203134Sthompsa	}
2818203134Sthompsa
2819208019Sthompsa	ni = ieee80211_find_rxnode(ic,
2820208019Sthompsa	    mtod(m, struct ieee80211_frame_min *));
2821208019Sthompsa
2822203134Sthompsa	if (__predict_false(flags & RT2860_RX_MICERR)) {
2823203134Sthompsa		/* report MIC failures to net80211 for TKIP */
2824209917Sthompsa		if (ni != NULL)
2825259032Skevlo			ieee80211_notify_michael_failure(ni->ni_vap, wh,
2826259032Skevlo			    rxwi->keyidx);
2827203134Sthompsa		m_freem(m);
2828271866Sglebius		if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
2829203134Sthompsa		DPRINTF("MIC error. Someone is lying.\n");
2830203134Sthompsa		return;
2831203134Sthompsa	}
2832203134Sthompsa
2833203134Sthompsa	ant = run_maxrssi_chain(sc, rxwi);
2834203134Sthompsa	rssi = rxwi->rssi[ant];
2835203134Sthompsa	nf = run_rssi2dbm(sc, rssi, ant);
2836203134Sthompsa
2837203134Sthompsa	m->m_pkthdr.rcvif = ifp;
2838203134Sthompsa	m->m_pkthdr.len = m->m_len = len;
2839203134Sthompsa
2840203134Sthompsa	if (ni != NULL) {
2841203134Sthompsa		(void)ieee80211_input(ni, m, rssi, nf);
2842203134Sthompsa		ieee80211_free_node(ni);
2843203134Sthompsa	} else {
2844203134Sthompsa		(void)ieee80211_input_all(ic, m, rssi, nf);
2845203134Sthompsa	}
2846203134Sthompsa
2847209917Sthompsa	if (__predict_false(ieee80211_radiotap_active(ic))) {
2848203134Sthompsa		struct run_rx_radiotap_header *tap = &sc->sc_rxtap;
2849258643Shselasky		uint16_t phy;
2850203134Sthompsa
2851203134Sthompsa		tap->wr_flags = 0;
2852236439Shselasky		tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
2853236439Shselasky		tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
2854203134Sthompsa		tap->wr_antsignal = rssi;
2855203134Sthompsa		tap->wr_antenna = ant;
2856203134Sthompsa		tap->wr_dbm_antsignal = run_rssi2dbm(sc, rssi, ant);
2857203134Sthompsa		tap->wr_rate = 2;	/* in case it can't be found below */
2858203134Sthompsa		phy = le16toh(rxwi->phy);
2859203134Sthompsa		switch (phy & RT2860_PHY_MODE) {
2860203134Sthompsa		case RT2860_PHY_CCK:
2861203134Sthompsa			switch ((phy & RT2860_PHY_MCS) & ~RT2860_PHY_SHPRE) {
2862203134Sthompsa			case 0:	tap->wr_rate =   2; break;
2863203134Sthompsa			case 1:	tap->wr_rate =   4; break;
2864203134Sthompsa			case 2:	tap->wr_rate =  11; break;
2865203134Sthompsa			case 3:	tap->wr_rate =  22; break;
2866203134Sthompsa			}
2867203134Sthompsa			if (phy & RT2860_PHY_SHPRE)
2868203134Sthompsa				tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
2869203134Sthompsa			break;
2870203134Sthompsa		case RT2860_PHY_OFDM:
2871203134Sthompsa			switch (phy & RT2860_PHY_MCS) {
2872203134Sthompsa			case 0:	tap->wr_rate =  12; break;
2873203134Sthompsa			case 1:	tap->wr_rate =  18; break;
2874203134Sthompsa			case 2:	tap->wr_rate =  24; break;
2875203134Sthompsa			case 3:	tap->wr_rate =  36; break;
2876203134Sthompsa			case 4:	tap->wr_rate =  48; break;
2877203134Sthompsa			case 5:	tap->wr_rate =  72; break;
2878203134Sthompsa			case 6:	tap->wr_rate =  96; break;
2879203134Sthompsa			case 7:	tap->wr_rate = 108; break;
2880203134Sthompsa			}
2881203134Sthompsa			break;
2882203134Sthompsa		}
2883203134Sthompsa	}
2884203134Sthompsa}
2885203134Sthompsa
2886203134Sthompsastatic void
2887203134Sthompsarun_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error)
2888203134Sthompsa{
2889203134Sthompsa	struct run_softc *sc = usbd_xfer_softc(xfer);
2890203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
2891203134Sthompsa	struct mbuf *m = NULL;
2892203134Sthompsa	struct mbuf *m0;
2893203134Sthompsa	uint32_t dmalen;
2894259032Skevlo	uint16_t rxwisize;
2895203134Sthompsa	int xferlen;
2896203134Sthompsa
2897260219Skevlo	rxwisize = sizeof(struct rt2860_rxwi);
2898260219Skevlo	if (sc->mac_ver == 0x5592)
2899260219Skevlo		rxwisize += sizeof(uint64_t);
2900260219Skevlo	else if (sc->mac_ver == 0x3593)
2901260219Skevlo		rxwisize += sizeof(uint32_t);
2902259032Skevlo
2903203134Sthompsa	usbd_xfer_status(xfer, &xferlen, NULL, NULL, NULL);
2904203134Sthompsa
2905203134Sthompsa	switch (USB_GET_STATE(xfer)) {
2906203134Sthompsa	case USB_ST_TRANSFERRED:
2907203134Sthompsa
2908203134Sthompsa		DPRINTFN(15, "rx done, actlen=%d\n", xferlen);
2909203134Sthompsa
2910259032Skevlo		if (xferlen < (int)(sizeof(uint32_t) + rxwisize +
2911259032Skevlo		    sizeof(struct rt2870_rxd))) {
2912203134Sthompsa			DPRINTF("xfer too short %d\n", xferlen);
2913203134Sthompsa			goto tr_setup;
2914203134Sthompsa		}
2915203134Sthompsa
2916203134Sthompsa		m = sc->rx_m;
2917203134Sthompsa		sc->rx_m = NULL;
2918203134Sthompsa
2919203134Sthompsa		/* FALLTHROUGH */
2920203134Sthompsa	case USB_ST_SETUP:
2921203134Sthompsatr_setup:
2922203134Sthompsa		if (sc->rx_m == NULL) {
2923243857Sglebius			sc->rx_m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR,
2924203134Sthompsa			    MJUMPAGESIZE /* xfer can be bigger than MCLBYTES */);
2925203134Sthompsa		}
2926203134Sthompsa		if (sc->rx_m == NULL) {
2927203134Sthompsa			DPRINTF("could not allocate mbuf - idle with stall\n");
2928271866Sglebius			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
2929203134Sthompsa			usbd_xfer_set_stall(xfer);
2930203134Sthompsa			usbd_xfer_set_frames(xfer, 0);
2931203134Sthompsa		} else {
2932203134Sthompsa			/*
2933203134Sthompsa			 * Directly loading a mbuf cluster into DMA to
2934203134Sthompsa			 * save some data copying. This works because
2935203134Sthompsa			 * there is only one cluster.
2936203134Sthompsa			 */
2937203134Sthompsa			usbd_xfer_set_frame_data(xfer, 0,
2938203134Sthompsa			    mtod(sc->rx_m, caddr_t), RUN_MAX_RXSZ);
2939203134Sthompsa			usbd_xfer_set_frames(xfer, 1);
2940203134Sthompsa		}
2941203134Sthompsa		usbd_transfer_submit(xfer);
2942203134Sthompsa		break;
2943203134Sthompsa
2944203134Sthompsa	default:	/* Error */
2945203134Sthompsa		if (error != USB_ERR_CANCELLED) {
2946203134Sthompsa			/* try to clear stall first */
2947203134Sthompsa			usbd_xfer_set_stall(xfer);
2948203134Sthompsa
2949203134Sthompsa			if (error == USB_ERR_TIMEOUT)
2950203134Sthompsa				device_printf(sc->sc_dev, "device timeout\n");
2951203134Sthompsa
2952271866Sglebius			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
2953203134Sthompsa
2954203134Sthompsa			goto tr_setup;
2955203134Sthompsa		}
2956209917Sthompsa		if (sc->rx_m != NULL) {
2957203134Sthompsa			m_freem(sc->rx_m);
2958203134Sthompsa			sc->rx_m = NULL;
2959203134Sthompsa		}
2960203134Sthompsa		break;
2961203134Sthompsa	}
2962203134Sthompsa
2963203134Sthompsa	if (m == NULL)
2964203134Sthompsa		return;
2965203134Sthompsa
2966203134Sthompsa	/* inputting all the frames must be last */
2967203134Sthompsa
2968203134Sthompsa	RUN_UNLOCK(sc);
2969203134Sthompsa
2970203134Sthompsa	m->m_pkthdr.len = m->m_len = xferlen;
2971203134Sthompsa
2972203134Sthompsa	/* HW can aggregate multiple 802.11 frames in a single USB xfer */
2973203134Sthompsa	for(;;) {
2974203134Sthompsa		dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff;
2975203134Sthompsa
2976233774Shselasky		if ((dmalen >= (uint32_t)-8) || (dmalen == 0) ||
2977233774Shselasky		    ((dmalen & 3) != 0)) {
2978203134Sthompsa			DPRINTF("bad DMA length %u\n", dmalen);
2979203134Sthompsa			break;
2980203134Sthompsa		}
2981233774Shselasky		if ((dmalen + 8) > (uint32_t)xferlen) {
2982203134Sthompsa			DPRINTF("bad DMA length %u > %d\n",
2983203134Sthompsa			dmalen + 8, xferlen);
2984203134Sthompsa			break;
2985203134Sthompsa		}
2986203134Sthompsa
2987203134Sthompsa		/* If it is the last one or a single frame, we won't copy. */
2988209917Sthompsa		if ((xferlen -= dmalen + 8) <= 8) {
2989203134Sthompsa			/* trim 32-bit DMA-len header */
2990203134Sthompsa			m->m_data += 4;
2991203134Sthompsa			m->m_pkthdr.len = m->m_len -= 4;
2992203134Sthompsa			run_rx_frame(sc, m, dmalen);
2993257435Shselasky			m = NULL;	/* don't free source buffer */
2994203134Sthompsa			break;
2995203134Sthompsa		}
2996203134Sthompsa
2997203134Sthompsa		/* copy aggregated frames to another mbuf */
2998243857Sglebius		m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
2999203134Sthompsa		if (__predict_false(m0 == NULL)) {
3000203134Sthompsa			DPRINTF("could not allocate mbuf\n");
3001271866Sglebius			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
3002203134Sthompsa			break;
3003203134Sthompsa		}
3004203134Sthompsa		m_copydata(m, 4 /* skip 32-bit DMA-len header */,
3005203134Sthompsa		    dmalen + sizeof(struct rt2870_rxd), mtod(m0, caddr_t));
3006203134Sthompsa		m0->m_pkthdr.len = m0->m_len =
3007203134Sthompsa		    dmalen + sizeof(struct rt2870_rxd);
3008203134Sthompsa		run_rx_frame(sc, m0, dmalen);
3009203134Sthompsa
3010203134Sthompsa		/* update data ptr */
3011203134Sthompsa		m->m_data += dmalen + 8;
3012203134Sthompsa		m->m_pkthdr.len = m->m_len -= dmalen + 8;
3013203134Sthompsa	}
3014203134Sthompsa
3015257435Shselasky	/* make sure we free the source buffer, if any */
3016257435Shselasky	m_freem(m);
3017257435Shselasky
3018203134Sthompsa	RUN_LOCK(sc);
3019203134Sthompsa}
3020203134Sthompsa
3021203134Sthompsastatic void
3022203134Sthompsarun_tx_free(struct run_endpoint_queue *pq,
3023203134Sthompsa    struct run_tx_data *data, int txerr)
3024203134Sthompsa{
3025203134Sthompsa	if (data->m != NULL) {
3026203134Sthompsa		if (data->m->m_flags & M_TXCB)
3027203134Sthompsa			ieee80211_process_callback(data->ni, data->m,
3028203134Sthompsa			    txerr ? ETIMEDOUT : 0);
3029203134Sthompsa		m_freem(data->m);
3030203134Sthompsa		data->m = NULL;
3031203134Sthompsa
3032209917Sthompsa		if (data->ni == NULL) {
3033203134Sthompsa			DPRINTF("no node\n");
3034203134Sthompsa		} else {
3035203134Sthompsa			ieee80211_free_node(data->ni);
3036203134Sthompsa			data->ni = NULL;
3037203134Sthompsa		}
3038203134Sthompsa	}
3039203134Sthompsa
3040203134Sthompsa	STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
3041203134Sthompsa	pq->tx_nfree++;
3042203134Sthompsa}
3043203134Sthompsa
3044203134Sthompsastatic void
3045257429Shselaskyrun_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, u_int index)
3046203134Sthompsa{
3047203134Sthompsa	struct run_softc *sc = usbd_xfer_softc(xfer);
3048203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
3049208019Sthompsa	struct ieee80211com *ic = ifp->if_l2com;
3050203134Sthompsa	struct run_tx_data *data;
3051203134Sthompsa	struct ieee80211vap *vap = NULL;
3052203134Sthompsa	struct usb_page_cache *pc;
3053203134Sthompsa	struct run_endpoint_queue *pq = &sc->sc_epq[index];
3054203134Sthompsa	struct mbuf *m;
3055203134Sthompsa	usb_frlength_t size;
3056203134Sthompsa	int actlen;
3057203134Sthompsa	int sumlen;
3058203134Sthompsa
3059203134Sthompsa	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
3060203134Sthompsa
3061209917Sthompsa	switch (USB_GET_STATE(xfer)) {
3062203134Sthompsa	case USB_ST_TRANSFERRED:
3063203134Sthompsa		DPRINTFN(11, "transfer complete: %d "
3064203134Sthompsa		    "bytes @ index %d\n", actlen, index);
3065203134Sthompsa
3066203134Sthompsa		data = usbd_xfer_get_priv(xfer);
3067203134Sthompsa
3068203134Sthompsa		run_tx_free(pq, data, 0);
3069203134Sthompsa		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
3070203134Sthompsa
3071203134Sthompsa		usbd_xfer_set_priv(xfer, NULL);
3072203134Sthompsa
3073271866Sglebius		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
3074203134Sthompsa
3075203134Sthompsa		/* FALLTHROUGH */
3076203134Sthompsa	case USB_ST_SETUP:
3077203134Sthompsatr_setup:
3078203134Sthompsa		data = STAILQ_FIRST(&pq->tx_qh);
3079209917Sthompsa		if (data == NULL)
3080203134Sthompsa			break;
3081203134Sthompsa
3082203134Sthompsa		STAILQ_REMOVE_HEAD(&pq->tx_qh, next);
3083203134Sthompsa
3084203134Sthompsa		m = data->m;
3085261330Shselasky		size = (sc->mac_ver == 0x5592) ?
3086261330Shselasky		    sizeof(data->desc) + sizeof(uint32_t) : sizeof(data->desc);
3087261076Shselasky		if ((m->m_pkthdr.len +
3088261330Shselasky		    size + 3 + 8) > RUN_MAX_TXSZ) {
3089203134Sthompsa			DPRINTF("data overflow, %u bytes\n",
3090203134Sthompsa			    m->m_pkthdr.len);
3091203134Sthompsa
3092271866Sglebius			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
3093203134Sthompsa
3094203134Sthompsa			run_tx_free(pq, data, 1);
3095203134Sthompsa
3096203134Sthompsa			goto tr_setup;
3097203134Sthompsa		}
3098203134Sthompsa
3099203134Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
3100203134Sthompsa		usbd_copy_in(pc, 0, &data->desc, size);
3101203134Sthompsa		usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len);
3102228508Shselasky		size += m->m_pkthdr.len;
3103228508Shselasky		/*
3104228508Shselasky		 * Align end on a 4-byte boundary, pad 8 bytes (CRC +
3105228508Shselasky		 * 4-byte padding), and be sure to zero those trailing
3106228508Shselasky		 * bytes:
3107228508Shselasky		 */
3108228508Shselasky		usbd_frame_zero(pc, size, ((-size) & 3) + 8);
3109228508Shselasky		size += ((-size) & 3) + 8;
3110203134Sthompsa
3111203134Sthompsa		vap = data->ni->ni_vap;
3112203134Sthompsa		if (ieee80211_radiotap_active_vap(vap)) {
3113203134Sthompsa			struct run_tx_radiotap_header *tap = &sc->sc_txtap;
3114259032Skevlo			struct rt2860_txwi *txwi =
3115208019Sthompsa			    (struct rt2860_txwi *)(&data->desc + sizeof(struct rt2870_txd));
3116203134Sthompsa			tap->wt_flags = 0;
3117203134Sthompsa			tap->wt_rate = rt2860_rates[data->ridx].rate;
3118236439Shselasky			tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
3119236439Shselasky			tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
3120203134Sthompsa			tap->wt_hwqueue = index;
3121208019Sthompsa			if (le16toh(txwi->phy) & RT2860_PHY_SHPRE)
3122203134Sthompsa				tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
3123203134Sthompsa
3124203134Sthompsa			ieee80211_radiotap_tx(vap, m);
3125203134Sthompsa		}
3126203134Sthompsa
3127228508Shselasky		DPRINTFN(11, "sending frame len=%u/%u  @ index %d\n",
3128228508Shselasky		    m->m_pkthdr.len, size, index);
3129203134Sthompsa
3130228508Shselasky		usbd_xfer_set_frame_len(xfer, 0, size);
3131203134Sthompsa		usbd_xfer_set_priv(xfer, data);
3132203134Sthompsa
3133203134Sthompsa		usbd_transfer_submit(xfer);
3134203134Sthompsa
3135203134Sthompsa		RUN_UNLOCK(sc);
3136203134Sthompsa		run_start(ifp);
3137203134Sthompsa		RUN_LOCK(sc);
3138203134Sthompsa
3139203134Sthompsa		break;
3140203134Sthompsa
3141203134Sthompsa	default:
3142203134Sthompsa		DPRINTF("USB transfer error, %s\n",
3143203134Sthompsa		    usbd_errstr(error));
3144203134Sthompsa
3145203134Sthompsa		data = usbd_xfer_get_priv(xfer);
3146203134Sthompsa
3147271866Sglebius		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
3148203134Sthompsa
3149203134Sthompsa		if (data != NULL) {
3150208019Sthompsa			if(data->ni != NULL)
3151208019Sthompsa				vap = data->ni->ni_vap;
3152203134Sthompsa			run_tx_free(pq, data, error);
3153203134Sthompsa			usbd_xfer_set_priv(xfer, NULL);
3154203134Sthompsa		}
3155209917Sthompsa		if (vap == NULL)
3156208019Sthompsa			vap = TAILQ_FIRST(&ic->ic_vaps);
3157203134Sthompsa
3158203134Sthompsa		if (error != USB_ERR_CANCELLED) {
3159203134Sthompsa			if (error == USB_ERR_TIMEOUT) {
3160203134Sthompsa				device_printf(sc->sc_dev, "device timeout\n");
3161208019Sthompsa				uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
3162208019Sthompsa				DPRINTF("cmdq_store=%d\n", i);
3163208019Sthompsa				sc->cmdq[i].func = run_usb_timeout_cb;
3164208019Sthompsa				sc->cmdq[i].arg0 = vap;
3165208019Sthompsa				ieee80211_runtask(ic, &sc->cmdq_task);
3166203134Sthompsa			}
3167203134Sthompsa
3168203134Sthompsa			/*
3169203134Sthompsa			 * Try to clear stall first, also if other
3170203134Sthompsa			 * errors occur, hence clearing stall
3171203134Sthompsa			 * introduces a 50 ms delay:
3172203134Sthompsa			 */
3173203134Sthompsa			usbd_xfer_set_stall(xfer);
3174203134Sthompsa			goto tr_setup;
3175203134Sthompsa		}
3176203134Sthompsa		break;
3177203134Sthompsa	}
3178203134Sthompsa}
3179203134Sthompsa
3180203134Sthompsastatic void
3181203134Sthompsarun_bulk_tx_callback0(struct usb_xfer *xfer, usb_error_t error)
3182203134Sthompsa{
3183203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 0);
3184203134Sthompsa}
3185203134Sthompsa
3186203134Sthompsastatic void
3187203134Sthompsarun_bulk_tx_callback1(struct usb_xfer *xfer, usb_error_t error)
3188203134Sthompsa{
3189203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 1);
3190203134Sthompsa}
3191203134Sthompsa
3192203134Sthompsastatic void
3193203134Sthompsarun_bulk_tx_callback2(struct usb_xfer *xfer, usb_error_t error)
3194203134Sthompsa{
3195203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 2);
3196203134Sthompsa}
3197203134Sthompsa
3198203134Sthompsastatic void
3199203134Sthompsarun_bulk_tx_callback3(struct usb_xfer *xfer, usb_error_t error)
3200203134Sthompsa{
3201203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 3);
3202203134Sthompsa}
3203203134Sthompsa
3204203134Sthompsastatic void
3205203134Sthompsarun_bulk_tx_callback4(struct usb_xfer *xfer, usb_error_t error)
3206203134Sthompsa{
3207203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 4);
3208203134Sthompsa}
3209203134Sthompsa
3210203134Sthompsastatic void
3211203134Sthompsarun_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error)
3212203134Sthompsa{
3213203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 5);
3214203134Sthompsa}
3215203134Sthompsa
3216203134Sthompsastatic void
3217208019Sthompsarun_set_tx_desc(struct run_softc *sc, struct run_tx_data *data)
3218203134Sthompsa{
3219203134Sthompsa	struct mbuf *m = data->m;
3220203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
3221208019Sthompsa	struct ieee80211vap *vap = data->ni->ni_vap;
3222203134Sthompsa	struct ieee80211_frame *wh;
3223203134Sthompsa	struct rt2870_txd *txd;
3224203134Sthompsa	struct rt2860_txwi *txwi;
3225259032Skevlo	uint16_t xferlen, txwisize;
3226208019Sthompsa	uint16_t mcs;
3227203134Sthompsa	uint8_t ridx = data->ridx;
3228208019Sthompsa	uint8_t pad;
3229203134Sthompsa
3230203134Sthompsa	/* get MCS code from rate index */
3231208019Sthompsa	mcs = rt2860_rates[ridx].mcs;
3232203134Sthompsa
3233259032Skevlo	txwisize = (sc->mac_ver == 0x5592) ?
3234259032Skevlo	    sizeof(*txwi) + sizeof(uint32_t) : sizeof(*txwi);
3235259032Skevlo	xferlen = txwisize + m->m_pkthdr.len;
3236203134Sthompsa
3237203134Sthompsa	/* roundup to 32-bit alignment */
3238203134Sthompsa	xferlen = (xferlen + 3) & ~3;
3239203134Sthompsa
3240203134Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3241203134Sthompsa	txd->len = htole16(xferlen);
3242203134Sthompsa
3243208019Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3244208019Sthompsa
3245208019Sthompsa	/*
3246208019Sthompsa	 * Ether both are true or both are false, the header
3247208019Sthompsa	 * are nicely aligned to 32-bit. So, no L2 padding.
3248208019Sthompsa	 */
3249208019Sthompsa	if(IEEE80211_HAS_ADDR4(wh) == IEEE80211_QOS_HAS_SEQ(wh))
3250208019Sthompsa		pad = 0;
3251208019Sthompsa	else
3252208019Sthompsa		pad = 2;
3253208019Sthompsa
3254203134Sthompsa	/* setup TX Wireless Information */
3255203134Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3256203134Sthompsa	txwi->len = htole16(m->m_pkthdr.len - pad);
3257203134Sthompsa	if (rt2860_rates[ridx].phy == IEEE80211_T_DS) {
3258270192Skevlo		mcs |= RT2860_PHY_CCK;
3259203134Sthompsa		if (ridx != RT2860_RIDX_CCK1 &&
3260203134Sthompsa		    (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
3261203134Sthompsa			mcs |= RT2860_PHY_SHPRE;
3262203134Sthompsa	} else
3263270192Skevlo		mcs |= RT2860_PHY_OFDM;
3264270192Skevlo	txwi->phy = htole16(mcs);
3265203134Sthompsa
3266203134Sthompsa	/* check if RTS/CTS or CTS-to-self protection is required */
3267203134Sthompsa	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
3268203134Sthompsa	    (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold ||
3269203134Sthompsa	     ((ic->ic_flags & IEEE80211_F_USEPROT) &&
3270203134Sthompsa	      rt2860_rates[ridx].phy == IEEE80211_T_OFDM)))
3271208019Sthompsa		txwi->txop |= RT2860_TX_TXOP_HT;
3272203134Sthompsa	else
3273208019Sthompsa		txwi->txop |= RT2860_TX_TXOP_BACKOFF;
3274209144Sthompsa
3275209917Sthompsa	if (vap->iv_opmode != IEEE80211_M_STA && !IEEE80211_QOS_HAS_SEQ(wh))
3276209144Sthompsa		txwi->xflags |= RT2860_TX_NSEQ;
3277203134Sthompsa}
3278203134Sthompsa
3279203134Sthompsa/* This function must be called locked */
3280203134Sthompsastatic int
3281203134Sthompsarun_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
3282203134Sthompsa{
3283203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
3284208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
3285203134Sthompsa	struct ieee80211_frame *wh;
3286208019Sthompsa	struct ieee80211_channel *chan;
3287203134Sthompsa	const struct ieee80211_txparam *tp;
3288208019Sthompsa	struct run_node *rn = (void *)ni;
3289203134Sthompsa	struct run_tx_data *data;
3290208019Sthompsa	struct rt2870_txd *txd;
3291208019Sthompsa	struct rt2860_txwi *txwi;
3292203134Sthompsa	uint16_t qos;
3293203134Sthompsa	uint16_t dur;
3294208019Sthompsa	uint16_t qid;
3295203134Sthompsa	uint8_t type;
3296203134Sthompsa	uint8_t tid;
3297208019Sthompsa	uint8_t ridx;
3298208019Sthompsa	uint8_t ctl_ridx;
3299203134Sthompsa	uint8_t qflags;
3300203134Sthompsa	uint8_t xflags = 0;
3301203134Sthompsa	int hasqos;
3302203134Sthompsa
3303203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3304203134Sthompsa
3305203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3306203134Sthompsa
3307203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3308203134Sthompsa
3309203134Sthompsa	/*
3310203134Sthompsa	 * There are 7 bulk endpoints: 1 for RX
3311203134Sthompsa	 * and 6 for TX (4 EDCAs + HCCA + Prio).
3312203134Sthompsa	 * Update 03-14-2009:  some devices like the Planex GW-US300MiniS
3313203134Sthompsa	 * seem to have only 4 TX bulk endpoints (Fukaumi Naoki).
3314203134Sthompsa	 */
3315203134Sthompsa	if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) {
3316203134Sthompsa		uint8_t *frm;
3317203134Sthompsa
3318203134Sthompsa		if(IEEE80211_HAS_ADDR4(wh))
3319203134Sthompsa			frm = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos;
3320203134Sthompsa		else
3321203134Sthompsa			frm =((struct ieee80211_qosframe *)wh)->i_qos;
3322203134Sthompsa
3323203134Sthompsa		qos = le16toh(*(const uint16_t *)frm);
3324203134Sthompsa		tid = qos & IEEE80211_QOS_TID;
3325203134Sthompsa		qid = TID_TO_WME_AC(tid);
3326203134Sthompsa	} else {
3327203134Sthompsa		qos = 0;
3328203134Sthompsa		tid = 0;
3329203134Sthompsa		qid = WME_AC_BE;
3330203134Sthompsa	}
3331203134Sthompsa	qflags = (qid < 4) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA;
3332203134Sthompsa
3333203134Sthompsa	DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n",
3334203134Sthompsa	    qos, qid, tid, qflags);
3335203134Sthompsa
3336208019Sthompsa	chan = (ni->ni_chan != IEEE80211_CHAN_ANYC)?ni->ni_chan:ic->ic_curchan;
3337208019Sthompsa	tp = &vap->iv_txparms[ieee80211_chan2mode(chan)];
3338203134Sthompsa
3339203134Sthompsa	/* pickup a rate index */
3340203134Sthompsa	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
3341270192Skevlo	    type != IEEE80211_FC0_TYPE_DATA || m->m_flags & M_EAPOL) {
3342203134Sthompsa		ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
3343203134Sthompsa		    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
3344203134Sthompsa		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
3345203134Sthompsa	} else {
3346208019Sthompsa		if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
3347208019Sthompsa			ridx = rn->fix_ridx;
3348208019Sthompsa		else
3349208019Sthompsa			ridx = rn->amrr_ridx;
3350203134Sthompsa		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
3351203134Sthompsa	}
3352203134Sthompsa
3353203134Sthompsa	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
3354203134Sthompsa	    (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) !=
3355203134Sthompsa	     IEEE80211_QOS_ACKPOLICY_NOACK)) {
3356209144Sthompsa		xflags |= RT2860_TX_ACK;
3357203134Sthompsa		if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
3358208019Sthompsa			dur = rt2860_rates[ctl_ridx].sp_ack_dur;
3359203134Sthompsa		else
3360208019Sthompsa			dur = rt2860_rates[ctl_ridx].lp_ack_dur;
3361258919Shselasky		USETW(wh->i_dur, dur);
3362203134Sthompsa	}
3363203134Sthompsa
3364203134Sthompsa	/* reserve slots for mgmt packets, just in case */
3365203134Sthompsa	if (sc->sc_epq[qid].tx_nfree < 3) {
3366203134Sthompsa		DPRINTFN(10, "tx ring %d is full\n", qid);
3367203134Sthompsa		return (-1);
3368203134Sthompsa	}
3369203134Sthompsa
3370203134Sthompsa	data = STAILQ_FIRST(&sc->sc_epq[qid].tx_fh);
3371203134Sthompsa	STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next);
3372203134Sthompsa	sc->sc_epq[qid].tx_nfree--;
3373203134Sthompsa
3374208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3375208019Sthompsa	txd->flags = qflags;
3376208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3377208019Sthompsa	txwi->xflags = xflags;
3378259032Skevlo	if (IEEE80211_IS_MULTICAST(wh->i_addr1))
3379245047Shselasky		txwi->wcid = 0;
3380259032Skevlo	else
3381245047Shselasky		txwi->wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
3382245047Shselasky		    1 : RUN_AID2WCID(ni->ni_associd);
3383259032Skevlo
3384208019Sthompsa	/* clear leftover garbage bits */
3385208019Sthompsa	txwi->flags = 0;
3386208019Sthompsa	txwi->txop = 0;
3387208019Sthompsa
3388203134Sthompsa	data->m = m;
3389203134Sthompsa	data->ni = ni;
3390203134Sthompsa	data->ridx = ridx;
3391203134Sthompsa
3392208019Sthompsa	run_set_tx_desc(sc, data);
3393203134Sthompsa
3394208019Sthompsa	/*
3395208019Sthompsa	 * The chip keeps track of 2 kind of Tx stats,
3396208019Sthompsa	 *  * TX_STAT_FIFO, for per WCID stats, and
3397208019Sthompsa	 *  * TX_STA_CNT0 for all-TX-in-one stats.
3398208019Sthompsa	 *
3399208019Sthompsa	 * To use FIFO stats, we need to store MCS into the driver-private
3400208019Sthompsa 	 * PacketID field. So that, we can tell whose stats when we read them.
3401208019Sthompsa 	 * We add 1 to the MCS because setting the PacketID field to 0 means
3402208019Sthompsa 	 * that we don't want feedback in TX_STAT_FIFO.
3403208019Sthompsa 	 * And, that's what we want for STA mode, since TX_STA_CNT0 does the job.
3404208019Sthompsa 	 *
3405208019Sthompsa 	 * FIFO stats doesn't count Tx with WCID 0xff, so we do this in run_tx().
3406208019Sthompsa 	 */
3407209917Sthompsa	if (sc->rvp_cnt > 1 || vap->iv_opmode == IEEE80211_M_HOSTAP ||
3408209917Sthompsa	    vap->iv_opmode == IEEE80211_M_MBSS) {
3409208019Sthompsa		uint16_t pid = (rt2860_rates[ridx].mcs + 1) & 0xf;
3410208019Sthompsa		txwi->len |= htole16(pid << RT2860_TX_PID_SHIFT);
3411208019Sthompsa
3412208019Sthompsa		/*
3413208019Sthompsa		 * Unlike PCI based devices, we don't get any interrupt from
3414208019Sthompsa		 * USB devices, so we simulate FIFO-is-full interrupt here.
3415208019Sthompsa		 * Ralink recomends to drain FIFO stats every 100 ms, but 16 slots
3416208019Sthompsa		 * quickly get fulled. To prevent overflow, increment a counter on
3417208019Sthompsa		 * every FIFO stat request, so we know how many slots are left.
3418208019Sthompsa		 * We do this only in HOSTAP or multiple vap mode since FIFO stats
3419208019Sthompsa		 * are used only in those modes.
3420208019Sthompsa		 * We just drain stats. AMRR gets updated every 1 sec by
3421208019Sthompsa		 * run_ratectl_cb() via callout.
3422208019Sthompsa		 * Call it early. Otherwise overflow.
3423208019Sthompsa		 */
3424209917Sthompsa		if (sc->fifo_cnt++ == 10) {
3425208019Sthompsa			/*
3426208019Sthompsa			 * With multiple vaps or if_bridge, if_start() is called
3427208019Sthompsa			 * with a non-sleepable lock, tcpinp. So, need to defer.
3428208019Sthompsa			 */
3429208019Sthompsa			uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
3430208019Sthompsa			DPRINTFN(6, "cmdq_store=%d\n", i);
3431208019Sthompsa			sc->cmdq[i].func = run_drain_fifo;
3432208019Sthompsa			sc->cmdq[i].arg0 = sc;
3433208019Sthompsa			ieee80211_runtask(ic, &sc->cmdq_task);
3434208019Sthompsa		}
3435208019Sthompsa	}
3436208019Sthompsa
3437203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next);
3438203134Sthompsa
3439203134Sthompsa	usbd_transfer_start(sc->sc_xfer[qid]);
3440203134Sthompsa
3441258840Skevlo	DPRINTFN(8, "sending data frame len=%d rate=%d qid=%d\n",
3442259032Skevlo	    m->m_pkthdr.len + (int)(sizeof(struct rt2870_txd) +
3443259046Shselasky	    sizeof(struct rt2860_txwi)), rt2860_rates[ridx].rate, qid);
3444203134Sthompsa
3445203134Sthompsa	return (0);
3446203134Sthompsa}
3447203134Sthompsa
3448203134Sthompsastatic int
3449203134Sthompsarun_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
3450203134Sthompsa{
3451203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
3452203134Sthompsa	struct ieee80211com *ic = ifp->if_l2com;
3453208019Sthompsa	struct run_node *rn = (void *)ni;
3454203134Sthompsa	struct run_tx_data *data;
3455203134Sthompsa	struct ieee80211_frame *wh;
3456208019Sthompsa	struct rt2870_txd *txd;
3457208019Sthompsa	struct rt2860_txwi *txwi;
3458203134Sthompsa	uint16_t dur;
3459208019Sthompsa	uint8_t ridx = rn->mgt_ridx;
3460203134Sthompsa	uint8_t type;
3461203134Sthompsa	uint8_t xflags = 0;
3462208019Sthompsa	uint8_t wflags = 0;
3463203134Sthompsa
3464203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3465203134Sthompsa
3466203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3467203134Sthompsa
3468203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3469203134Sthompsa
3470208019Sthompsa	/* tell hardware to add timestamp for probe responses */
3471208019Sthompsa	if ((wh->i_fc[0] &
3472208019Sthompsa	    (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==
3473208019Sthompsa	    (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP))
3474208019Sthompsa		wflags |= RT2860_TX_TS;
3475208019Sthompsa	else if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3476203134Sthompsa		xflags |= RT2860_TX_ACK;
3477203134Sthompsa
3478208019Sthompsa		dur = ieee80211_ack_duration(ic->ic_rt, rt2860_rates[ridx].rate,
3479203134Sthompsa		    ic->ic_flags & IEEE80211_F_SHPREAMBLE);
3480258919Shselasky		USETW(wh->i_dur, dur);
3481203134Sthompsa	}
3482203134Sthompsa
3483203134Sthompsa	if (sc->sc_epq[0].tx_nfree == 0) {
3484203134Sthompsa		/* let caller free mbuf */
3485203134Sthompsa		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
3486203134Sthompsa		return (EIO);
3487203134Sthompsa	}
3488203134Sthompsa	data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3489203134Sthompsa	STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3490203134Sthompsa	sc->sc_epq[0].tx_nfree--;
3491203134Sthompsa
3492208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3493208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3494208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3495208019Sthompsa	txwi->wcid = 0xff;
3496208019Sthompsa	txwi->flags = wflags;
3497208019Sthompsa	txwi->xflags = xflags;
3498208019Sthompsa	txwi->txop = 0;	/* clear leftover garbage bits */
3499208019Sthompsa
3500203134Sthompsa	data->m = m;
3501203134Sthompsa	data->ni = ni;
3502203134Sthompsa	data->ridx = ridx;
3503203134Sthompsa
3504208019Sthompsa	run_set_tx_desc(sc, data);
3505203134Sthompsa
3506203134Sthompsa	DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m->m_pkthdr.len +
3507258840Skevlo	    (int)(sizeof(struct rt2870_txd) + sizeof(struct rt2860_txwi)),
3508208019Sthompsa	    rt2860_rates[ridx].rate);
3509203134Sthompsa
3510203134Sthompsa	STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3511203134Sthompsa
3512203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3513203134Sthompsa
3514203134Sthompsa	return (0);
3515203134Sthompsa}
3516203134Sthompsa
3517203134Sthompsastatic int
3518203134Sthompsarun_sendprot(struct run_softc *sc,
3519203134Sthompsa    const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate)
3520203134Sthompsa{
3521203134Sthompsa	struct ieee80211com *ic = ni->ni_ic;
3522203134Sthompsa	struct ieee80211_frame *wh;
3523203134Sthompsa	struct run_tx_data *data;
3524208019Sthompsa	struct rt2870_txd *txd;
3525208019Sthompsa	struct rt2860_txwi *txwi;
3526203134Sthompsa	struct mbuf *mprot;
3527203134Sthompsa	int ridx;
3528203134Sthompsa	int protrate;
3529203134Sthompsa	int ackrate;
3530203134Sthompsa	int pktlen;
3531203134Sthompsa	int isshort;
3532203134Sthompsa	uint16_t dur;
3533203134Sthompsa	uint8_t type;
3534208019Sthompsa	uint8_t wflags = 0;
3535208019Sthompsa	uint8_t xflags = 0;
3536203134Sthompsa
3537203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3538203134Sthompsa
3539203134Sthompsa	KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY,
3540203134Sthompsa	    ("protection %d", prot));
3541203134Sthompsa
3542203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3543203134Sthompsa	pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN;
3544203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3545203134Sthompsa
3546203134Sthompsa	protrate = ieee80211_ctl_rate(ic->ic_rt, rate);
3547203134Sthompsa	ackrate = ieee80211_ack_rate(ic->ic_rt, rate);
3548203134Sthompsa
3549203134Sthompsa	isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
3550209189Sjkim	dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort)
3551203134Sthompsa	    + ieee80211_ack_duration(ic->ic_rt, rate, isshort);
3552203134Sthompsa	wflags = RT2860_TX_FRAG;
3553203134Sthompsa
3554203134Sthompsa	/* check that there are free slots before allocating the mbuf */
3555203134Sthompsa	if (sc->sc_epq[0].tx_nfree == 0) {
3556203134Sthompsa		/* let caller free mbuf */
3557203134Sthompsa		sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE;
3558203134Sthompsa		return (ENOBUFS);
3559203134Sthompsa	}
3560203134Sthompsa
3561203134Sthompsa	if (prot == IEEE80211_PROT_RTSCTS) {
3562203134Sthompsa		/* NB: CTS is the same size as an ACK */
3563203134Sthompsa		dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort);
3564208019Sthompsa		xflags |= RT2860_TX_ACK;
3565203134Sthompsa		mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur);
3566203134Sthompsa	} else {
3567203134Sthompsa		mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur);
3568203134Sthompsa	}
3569203134Sthompsa	if (mprot == NULL) {
3570271866Sglebius		if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1);
3571203134Sthompsa		DPRINTF("could not allocate mbuf\n");
3572203134Sthompsa		return (ENOBUFS);
3573203134Sthompsa	}
3574203134Sthompsa
3575203134Sthompsa        data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3576203134Sthompsa        STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3577203134Sthompsa        sc->sc_epq[0].tx_nfree--;
3578203134Sthompsa
3579208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3580208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3581208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3582208019Sthompsa	txwi->wcid = 0xff;
3583208019Sthompsa	txwi->flags = wflags;
3584208019Sthompsa	txwi->xflags = xflags;
3585208019Sthompsa	txwi->txop = 0;	/* clear leftover garbage bits */
3586208019Sthompsa
3587203134Sthompsa	data->m = mprot;
3588203134Sthompsa	data->ni = ieee80211_ref_node(ni);
3589203134Sthompsa
3590203134Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
3591203134Sthompsa		if (rt2860_rates[ridx].rate == protrate)
3592203134Sthompsa			break;
3593203134Sthompsa	data->ridx = ridx;
3594203134Sthompsa
3595208019Sthompsa	run_set_tx_desc(sc, data);
3596203134Sthompsa
3597203134Sthompsa        DPRINTFN(1, "sending prot len=%u rate=%u\n",
3598203134Sthompsa            m->m_pkthdr.len, rate);
3599203134Sthompsa
3600203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3601203134Sthompsa
3602203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3603203134Sthompsa
3604203134Sthompsa	return (0);
3605203134Sthompsa}
3606203134Sthompsa
3607203134Sthompsastatic int
3608203134Sthompsarun_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni,
3609203134Sthompsa    const struct ieee80211_bpf_params *params)
3610203134Sthompsa{
3611203134Sthompsa	struct ieee80211com *ic = ni->ni_ic;
3612203134Sthompsa	struct ieee80211_frame *wh;
3613203134Sthompsa	struct run_tx_data *data;
3614208019Sthompsa	struct rt2870_txd *txd;
3615208019Sthompsa	struct rt2860_txwi *txwi;
3616203134Sthompsa	uint8_t type;
3617208019Sthompsa	uint8_t ridx;
3618208019Sthompsa	uint8_t rate;
3619208019Sthompsa	uint8_t opflags = 0;
3620208019Sthompsa	uint8_t xflags = 0;
3621203134Sthompsa	int error;
3622203134Sthompsa
3623203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3624203134Sthompsa
3625203134Sthompsa	KASSERT(params != NULL, ("no raw xmit params"));
3626203134Sthompsa
3627203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3628203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3629203134Sthompsa
3630203134Sthompsa	rate = params->ibp_rate0;
3631203134Sthompsa	if (!ieee80211_isratevalid(ic->ic_rt, rate)) {
3632203134Sthompsa		/* let caller free mbuf */
3633203134Sthompsa		return (EINVAL);
3634203134Sthompsa	}
3635203134Sthompsa
3636203134Sthompsa	if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0)
3637208019Sthompsa		xflags |= RT2860_TX_ACK;
3638203134Sthompsa	if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) {
3639203134Sthompsa		error = run_sendprot(sc, m, ni,
3640203134Sthompsa		    params->ibp_flags & IEEE80211_BPF_RTS ?
3641203134Sthompsa			IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY,
3642203134Sthompsa		    rate);
3643203134Sthompsa		if (error) {
3644203134Sthompsa			/* let caller free mbuf */
3645209917Sthompsa			return error;
3646203134Sthompsa		}
3647203134Sthompsa		opflags |= /*XXX RT2573_TX_LONG_RETRY |*/ RT2860_TX_TXOP_SIFS;
3648203134Sthompsa	}
3649203134Sthompsa
3650203134Sthompsa	if (sc->sc_epq[0].tx_nfree == 0) {
3651203134Sthompsa		/* let caller free mbuf */
3652203134Sthompsa		sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE;
3653203134Sthompsa		DPRINTF("sending raw frame, but tx ring is full\n");
3654203134Sthompsa		return (EIO);
3655203134Sthompsa	}
3656203134Sthompsa        data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3657203134Sthompsa        STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3658203134Sthompsa        sc->sc_epq[0].tx_nfree--;
3659203134Sthompsa
3660208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3661208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3662208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3663208019Sthompsa	txwi->wcid = 0xff;
3664208019Sthompsa	txwi->xflags = xflags;
3665208019Sthompsa	txwi->txop = opflags;
3666208019Sthompsa	txwi->flags = 0;	/* clear leftover garbage bits */
3667208019Sthompsa
3668203134Sthompsa        data->m = m;
3669203134Sthompsa        data->ni = ni;
3670203134Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
3671203134Sthompsa		if (rt2860_rates[ridx].rate == rate)
3672203134Sthompsa			break;
3673203134Sthompsa	data->ridx = ridx;
3674203134Sthompsa
3675208019Sthompsa        run_set_tx_desc(sc, data);
3676203134Sthompsa
3677203134Sthompsa        DPRINTFN(10, "sending raw frame len=%u rate=%u\n",
3678203134Sthompsa            m->m_pkthdr.len, rate);
3679203134Sthompsa
3680203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3681203134Sthompsa
3682203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3683203134Sthompsa
3684209917Sthompsa        return (0);
3685203134Sthompsa}
3686203134Sthompsa
3687203134Sthompsastatic int
3688203134Sthompsarun_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
3689203134Sthompsa    const struct ieee80211_bpf_params *params)
3690203134Sthompsa{
3691203134Sthompsa	struct ifnet *ifp = ni->ni_ic->ic_ifp;
3692203134Sthompsa	struct run_softc *sc = ifp->if_softc;
3693208019Sthompsa	int error = 0;
3694208019Sthompsa
3695203134Sthompsa	RUN_LOCK(sc);
3696203134Sthompsa
3697203134Sthompsa	/* prevent management frames from being sent if we're not ready */
3698203134Sthompsa	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
3699203134Sthompsa		error =  ENETDOWN;
3700208019Sthompsa		goto done;
3701203134Sthompsa	}
3702203134Sthompsa
3703203134Sthompsa	if (params == NULL) {
3704203134Sthompsa		/* tx mgt packet */
3705209917Sthompsa		if ((error = run_tx_mgt(sc, m, ni)) != 0) {
3706271866Sglebius			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
3707203134Sthompsa			DPRINTF("mgt tx failed\n");
3708208019Sthompsa			goto done;
3709203134Sthompsa		}
3710203134Sthompsa	} else {
3711203134Sthompsa		/* tx raw packet with param */
3712209917Sthompsa		if ((error = run_tx_param(sc, m, ni, params)) != 0) {
3713271866Sglebius			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
3714203134Sthompsa			DPRINTF("tx with param failed\n");
3715208019Sthompsa			goto done;
3716203134Sthompsa		}
3717203134Sthompsa	}
3718203134Sthompsa
3719271866Sglebius	if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
3720203134Sthompsa
3721208019Sthompsadone:
3722203134Sthompsa	RUN_UNLOCK(sc);
3723203134Sthompsa
3724209917Sthompsa	if (error != 0) {
3725208019Sthompsa		if(m != NULL)
3726208019Sthompsa			m_freem(m);
3727208019Sthompsa		ieee80211_free_node(ni);
3728208019Sthompsa	}
3729203134Sthompsa
3730203134Sthompsa	return (error);
3731203134Sthompsa}
3732203134Sthompsa
3733203134Sthompsastatic void
3734203134Sthompsarun_start(struct ifnet *ifp)
3735203134Sthompsa{
3736203134Sthompsa	struct run_softc *sc = ifp->if_softc;
3737203134Sthompsa	struct ieee80211_node *ni;
3738203134Sthompsa	struct mbuf *m;
3739203134Sthompsa
3740203134Sthompsa	RUN_LOCK(sc);
3741203134Sthompsa
3742203134Sthompsa	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
3743203134Sthompsa		RUN_UNLOCK(sc);
3744203134Sthompsa		return;
3745203134Sthompsa	}
3746203134Sthompsa
3747203134Sthompsa	for (;;) {
3748203134Sthompsa		/* send data frames */
3749203134Sthompsa		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
3750203134Sthompsa		if (m == NULL)
3751203134Sthompsa			break;
3752203134Sthompsa
3753203134Sthompsa		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
3754203134Sthompsa		if (run_tx(sc, m, ni) != 0) {
3755203134Sthompsa			IFQ_DRV_PREPEND(&ifp->if_snd, m);
3756203134Sthompsa			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
3757203134Sthompsa			break;
3758203134Sthompsa		}
3759203134Sthompsa	}
3760203134Sthompsa
3761203134Sthompsa	RUN_UNLOCK(sc);
3762203134Sthompsa}
3763203134Sthompsa
3764203134Sthompsastatic int
3765203134Sthompsarun_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
3766203134Sthompsa{
3767203134Sthompsa	struct run_softc *sc = ifp->if_softc;
3768203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
3769203134Sthompsa	struct ifreq *ifr = (struct ifreq *) data;
3770208019Sthompsa	int startall = 0;
3771246614Shselasky	int error;
3772203134Sthompsa
3773246614Shselasky	RUN_LOCK(sc);
3774246614Shselasky	error = sc->sc_detached ? ENXIO : 0;
3775246614Shselasky	RUN_UNLOCK(sc);
3776246614Shselasky	if (error)
3777246614Shselasky		return (error);
3778246614Shselasky
3779203134Sthompsa	switch (cmd) {
3780203134Sthompsa	case SIOCSIFFLAGS:
3781203134Sthompsa		RUN_LOCK(sc);
3782203134Sthompsa		if (ifp->if_flags & IFF_UP) {
3783203134Sthompsa			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)){
3784208019Sthompsa				startall = 1;
3785203134Sthompsa				run_init_locked(sc);
3786203134Sthompsa			} else
3787203134Sthompsa				run_update_promisc_locked(ifp);
3788203134Sthompsa		} else {
3789209917Sthompsa			if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
3790209917Sthompsa			    (ic->ic_nrunning == 0 || sc->rvp_cnt <= 1)) {
3791208019Sthompsa					run_stop(sc);
3792208019Sthompsa			}
3793203134Sthompsa		}
3794203134Sthompsa		RUN_UNLOCK(sc);
3795209917Sthompsa		if (startall)
3796208019Sthompsa			ieee80211_start_all(ic);
3797203134Sthompsa		break;
3798203134Sthompsa	case SIOCGIFMEDIA:
3799203134Sthompsa		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
3800203134Sthompsa		break;
3801203134Sthompsa	case SIOCGIFADDR:
3802203134Sthompsa		error = ether_ioctl(ifp, cmd, data);
3803203134Sthompsa		break;
3804203134Sthompsa	default:
3805203134Sthompsa		error = EINVAL;
3806203134Sthompsa		break;
3807203134Sthompsa	}
3808203134Sthompsa
3809203134Sthompsa	return (error);
3810203134Sthompsa}
3811203134Sthompsa
3812203134Sthompsastatic void
3813259544Skevlorun_iq_calib(struct run_softc *sc, u_int chan)
3814259544Skevlo{
3815259544Skevlo	uint16_t val;
3816259544Skevlo
3817259544Skevlo	/* Tx0 IQ gain. */
3818259544Skevlo	run_bbp_write(sc, 158, 0x2c);
3819259544Skevlo	if (chan <= 14)
3820259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX0_2GHZ, &val, 1);
3821259544Skevlo	else if (chan <= 64) {
3822259544Skevlo		run_efuse_read(sc,
3823259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH36_TO_CH64_5GHZ,
3824259544Skevlo		    &val, 1);
3825259544Skevlo	} else if (chan <= 138) {
3826259544Skevlo		run_efuse_read(sc,
3827259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH100_TO_CH138_5GHZ,
3828259544Skevlo		    &val, 1);
3829259544Skevlo	} else if (chan <= 165) {
3830259544Skevlo		run_efuse_read(sc,
3831259544Skevlo	    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH140_TO_CH165_5GHZ,
3832259544Skevlo		    &val, 1);
3833259544Skevlo	} else
3834259544Skevlo		val = 0;
3835259547Skevlo	run_bbp_write(sc, 159, val);
3836259544Skevlo
3837259544Skevlo	/* Tx0 IQ phase. */
3838259544Skevlo	run_bbp_write(sc, 158, 0x2d);
3839259544Skevlo	if (chan <= 14) {
3840259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX0_2GHZ,
3841259544Skevlo		    &val, 1);
3842259544Skevlo	} else if (chan <= 64) {
3843259544Skevlo		run_efuse_read(sc,
3844259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH36_TO_CH64_5GHZ,
3845259544Skevlo		    &val, 1);
3846259544Skevlo	} else if (chan <= 138) {
3847259544Skevlo		run_efuse_read(sc,
3848259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH100_TO_CH138_5GHZ,
3849259544Skevlo		    &val, 1);
3850259544Skevlo	} else if (chan <= 165) {
3851259544Skevlo		run_efuse_read(sc,
3852259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH140_TO_CH165_5GHZ,
3853259544Skevlo		    &val, 1);
3854259544Skevlo	} else
3855259544Skevlo		val = 0;
3856259547Skevlo	run_bbp_write(sc, 159, val);
3857259544Skevlo
3858259544Skevlo	/* Tx1 IQ gain. */
3859259544Skevlo	run_bbp_write(sc, 158, 0x4a);
3860259544Skevlo	if (chan <= 14) {
3861259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX1_2GHZ,
3862259544Skevlo		    &val, 1);
3863259544Skevlo	} else if (chan <= 64) {
3864259544Skevlo		run_efuse_read(sc,
3865259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH36_TO_CH64_5GHZ,
3866259544Skevlo		    &val, 1);
3867259544Skevlo	} else if (chan <= 138) {
3868259544Skevlo		run_efuse_read(sc,
3869259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH100_TO_CH138_5GHZ,
3870259544Skevlo		    &val, 1);
3871259544Skevlo	} else if (chan <= 165) {
3872259544Skevlo		run_efuse_read(sc,
3873259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH140_TO_CH165_5GHZ,
3874259544Skevlo		    &val, 1);
3875259544Skevlo	} else
3876259544Skevlo		val = 0;
3877259547Skevlo	run_bbp_write(sc, 159, val);
3878259544Skevlo
3879259544Skevlo	/* Tx1 IQ phase. */
3880259544Skevlo	run_bbp_write(sc, 158, 0x4b);
3881259544Skevlo	if (chan <= 14) {
3882259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX1_2GHZ,
3883259544Skevlo		    &val, 1);
3884259544Skevlo	} else if (chan <= 64) {
3885259544Skevlo		run_efuse_read(sc,
3886259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH36_TO_CH64_5GHZ,
3887259544Skevlo		    &val, 1);
3888259544Skevlo	} else if (chan <= 138) {
3889259544Skevlo		run_efuse_read(sc,
3890259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH100_TO_CH138_5GHZ,
3891259544Skevlo		    &val, 1);
3892259544Skevlo	} else if (chan <= 165) {
3893259544Skevlo		run_efuse_read(sc,
3894259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH140_TO_CH165_5GHZ,
3895259544Skevlo		    &val, 1);
3896259544Skevlo	} else
3897259544Skevlo		val = 0;
3898259547Skevlo	run_bbp_write(sc, 159, val);
3899259544Skevlo
3900259544Skevlo	/* RF IQ compensation control. */
3901259544Skevlo	run_bbp_write(sc, 158, 0x04);
3902259544Skevlo	run_efuse_read(sc, RT5390_EEPROM_RF_IQ_COMPENSATION_CTL,
3903259544Skevlo	    &val, 1);
3904259547Skevlo	run_bbp_write(sc, 159, val);
3905259544Skevlo
3906259544Skevlo	/* RF IQ imbalance compensation control. */
3907259544Skevlo	run_bbp_write(sc, 158, 0x03);
3908259544Skevlo	run_efuse_read(sc,
3909259544Skevlo	    RT5390_EEPROM_RF_IQ_IMBALANCE_COMPENSATION_CTL, &val, 1);
3910259547Skevlo	run_bbp_write(sc, 159, val);
3911259544Skevlo}
3912259544Skevlo
3913259544Skevlostatic void
3914205042Sthompsarun_set_agc(struct run_softc *sc, uint8_t agc)
3915205042Sthompsa{
3916205042Sthompsa	uint8_t bbp;
3917205042Sthompsa
3918205042Sthompsa	if (sc->mac_ver == 0x3572) {
3919205042Sthompsa		run_bbp_read(sc, 27, &bbp);
3920205042Sthompsa		bbp &= ~(0x3 << 5);
3921205042Sthompsa		run_bbp_write(sc, 27, bbp | 0 << 5);	/* select Rx0 */
3922205042Sthompsa		run_bbp_write(sc, 66, agc);
3923205042Sthompsa		run_bbp_write(sc, 27, bbp | 1 << 5);	/* select Rx1 */
3924205042Sthompsa		run_bbp_write(sc, 66, agc);
3925205042Sthompsa	} else
3926205042Sthompsa		run_bbp_write(sc, 66, agc);
3927205042Sthompsa}
3928205042Sthompsa
3929205042Sthompsastatic void
3930203134Sthompsarun_select_chan_group(struct run_softc *sc, int group)
3931203134Sthompsa{
3932203134Sthompsa	uint32_t tmp;
3933205042Sthompsa	uint8_t agc;
3934203134Sthompsa
3935203134Sthompsa	run_bbp_write(sc, 62, 0x37 - sc->lna[group]);
3936203134Sthompsa	run_bbp_write(sc, 63, 0x37 - sc->lna[group]);
3937203134Sthompsa	run_bbp_write(sc, 64, 0x37 - sc->lna[group]);
3938258082Skevlo	if (sc->mac_ver < 0x3572)
3939257955Skevlo		run_bbp_write(sc, 86, 0x00);
3940203134Sthompsa
3941260219Skevlo	if (sc->mac_ver == 0x3593) {
3942260219Skevlo		run_bbp_write(sc, 77, 0x98);
3943260219Skevlo		run_bbp_write(sc, 83, (group == 0) ? 0x8a : 0x9a);
3944260219Skevlo	}
3945260219Skevlo
3946203134Sthompsa	if (group == 0) {
3947203134Sthompsa		if (sc->ext_2ghz_lna) {
3948257955Skevlo			if (sc->mac_ver >= 0x5390)
3949257955Skevlo				run_bbp_write(sc, 75, 0x52);
3950257955Skevlo			else {
3951257955Skevlo				run_bbp_write(sc, 82, 0x62);
3952257955Skevlo				run_bbp_write(sc, 75, 0x46);
3953257955Skevlo			}
3954203134Sthompsa		} else {
3955259032Skevlo			if (sc->mac_ver == 0x5592) {
3956259032Skevlo				run_bbp_write(sc, 79, 0x1c);
3957259032Skevlo				run_bbp_write(sc, 80, 0x0e);
3958259032Skevlo				run_bbp_write(sc, 81, 0x3a);
3959259032Skevlo				run_bbp_write(sc, 82, 0x62);
3960259032Skevlo
3961259032Skevlo				run_bbp_write(sc, 195, 0x80);
3962259032Skevlo				run_bbp_write(sc, 196, 0xe0);
3963259032Skevlo				run_bbp_write(sc, 195, 0x81);
3964259032Skevlo				run_bbp_write(sc, 196, 0x1f);
3965259032Skevlo				run_bbp_write(sc, 195, 0x82);
3966259032Skevlo				run_bbp_write(sc, 196, 0x38);
3967259032Skevlo				run_bbp_write(sc, 195, 0x83);
3968259032Skevlo				run_bbp_write(sc, 196, 0x32);
3969259032Skevlo				run_bbp_write(sc, 195, 0x85);
3970259032Skevlo				run_bbp_write(sc, 196, 0x28);
3971259032Skevlo				run_bbp_write(sc, 195, 0x86);
3972259032Skevlo				run_bbp_write(sc, 196, 0x19);
3973259032Skevlo			} else if (sc->mac_ver >= 0x5390)
3974257955Skevlo				run_bbp_write(sc, 75, 0x50);
3975257955Skevlo			else {
3976260219Skevlo				run_bbp_write(sc, 82,
3977260219Skevlo				    (sc->mac_ver == 0x3593) ? 0x62 : 0x84);
3978257955Skevlo				run_bbp_write(sc, 75, 0x50);
3979257955Skevlo			}
3980203134Sthompsa		}
3981203134Sthompsa	} else {
3982259032Skevlo		if (sc->mac_ver == 0x5592) {
3983259032Skevlo			run_bbp_write(sc, 79, 0x18);
3984259032Skevlo			run_bbp_write(sc, 80, 0x08);
3985259032Skevlo			run_bbp_write(sc, 81, 0x38);
3986259032Skevlo			run_bbp_write(sc, 82, 0x92);
3987259032Skevlo
3988259032Skevlo			run_bbp_write(sc, 195, 0x80);
3989259032Skevlo			run_bbp_write(sc, 196, 0xf0);
3990259032Skevlo			run_bbp_write(sc, 195, 0x81);
3991259032Skevlo			run_bbp_write(sc, 196, 0x1e);
3992259032Skevlo			run_bbp_write(sc, 195, 0x82);
3993259032Skevlo			run_bbp_write(sc, 196, 0x28);
3994259032Skevlo			run_bbp_write(sc, 195, 0x83);
3995259032Skevlo			run_bbp_write(sc, 196, 0x20);
3996259032Skevlo			run_bbp_write(sc, 195, 0x85);
3997259032Skevlo			run_bbp_write(sc, 196, 0x7f);
3998259032Skevlo			run_bbp_write(sc, 195, 0x86);
3999259032Skevlo			run_bbp_write(sc, 196, 0x7f);
4000259032Skevlo		} else if (sc->mac_ver == 0x3572)
4001205042Sthompsa			run_bbp_write(sc, 82, 0x94);
4002205042Sthompsa		else
4003260219Skevlo			run_bbp_write(sc, 82,
4004260219Skevlo			    (sc->mac_ver == 0x3593) ? 0x82 : 0xf2);
4005205042Sthompsa		if (sc->ext_5ghz_lna)
4006203134Sthompsa			run_bbp_write(sc, 75, 0x46);
4007205042Sthompsa		else
4008203134Sthompsa			run_bbp_write(sc, 75, 0x50);
4009203134Sthompsa	}
4010203134Sthompsa
4011203134Sthompsa	run_read(sc, RT2860_TX_BAND_CFG, &tmp);
4012203134Sthompsa	tmp &= ~(RT2860_5G_BAND_SEL_N | RT2860_5G_BAND_SEL_P);
4013203134Sthompsa	tmp |= (group == 0) ? RT2860_5G_BAND_SEL_N : RT2860_5G_BAND_SEL_P;
4014203134Sthompsa	run_write(sc, RT2860_TX_BAND_CFG, tmp);
4015203134Sthompsa
4016203134Sthompsa	/* enable appropriate Power Amplifiers and Low Noise Amplifiers */
4017208019Sthompsa	tmp = RT2860_RFTR_EN | RT2860_TRSW_EN | RT2860_LNA_PE0_EN;
4018260219Skevlo	if (sc->mac_ver == 0x3593)
4019260219Skevlo		tmp |= 1 << 29 | 1 << 28;
4020208019Sthompsa	if (sc->nrxchains > 1)
4021208019Sthompsa		tmp |= RT2860_LNA_PE1_EN;
4022203134Sthompsa	if (group == 0) {	/* 2GHz */
4023208019Sthompsa		tmp |= RT2860_PA_PE_G0_EN;
4024203134Sthompsa		if (sc->ntxchains > 1)
4025203134Sthompsa			tmp |= RT2860_PA_PE_G1_EN;
4026260219Skevlo		if (sc->mac_ver == 0x3593) {
4027260219Skevlo			if (sc->ntxchains > 2)
4028260219Skevlo				tmp |= 1 << 25;
4029260219Skevlo		}
4030203134Sthompsa	} else {		/* 5GHz */
4031208019Sthompsa		tmp |= RT2860_PA_PE_A0_EN;
4032203134Sthompsa		if (sc->ntxchains > 1)
4033203134Sthompsa			tmp |= RT2860_PA_PE_A1_EN;
4034203134Sthompsa	}
4035205042Sthompsa	if (sc->mac_ver == 0x3572) {
4036205042Sthompsa		run_rt3070_rf_write(sc, 8, 0x00);
4037205042Sthompsa		run_write(sc, RT2860_TX_PIN_CFG, tmp);
4038205042Sthompsa		run_rt3070_rf_write(sc, 8, 0x80);
4039205042Sthompsa	} else
4040205042Sthompsa		run_write(sc, RT2860_TX_PIN_CFG, tmp);
4041203134Sthompsa
4042259032Skevlo	if (sc->mac_ver == 0x5592) {
4043259032Skevlo		run_bbp_write(sc, 195, 0x8d);
4044259032Skevlo		run_bbp_write(sc, 196, 0x1a);
4045259032Skevlo	}
4046259032Skevlo
4047260219Skevlo	if (sc->mac_ver == 0x3593) {
4048260219Skevlo		run_read(sc, RT2860_GPIO_CTRL, &tmp);
4049260219Skevlo		tmp &= ~0x01010000;
4050260219Skevlo		if (group == 0)
4051260219Skevlo			tmp |= 0x00010000;
4052260219Skevlo		tmp = (tmp & ~0x00009090) | 0x00000090;
4053260219Skevlo		run_write(sc, RT2860_GPIO_CTRL, tmp);
4054260219Skevlo	}
4055260219Skevlo
4056203134Sthompsa	/* set initial AGC value */
4057205042Sthompsa	if (group == 0) {	/* 2GHz band */
4058205042Sthompsa		if (sc->mac_ver >= 0x3070)
4059205042Sthompsa			agc = 0x1c + sc->lna[0] * 2;
4060205042Sthompsa		else
4061205042Sthompsa			agc = 0x2e + sc->lna[0];
4062205042Sthompsa	} else {		/* 5GHz band */
4063259032Skevlo		if (sc->mac_ver == 0x5592)
4064259032Skevlo			agc = 0x24 + sc->lna[group] * 2;
4065260219Skevlo		else if (sc->mac_ver == 0x3572 || sc->mac_ver == 0x3593)
4066205042Sthompsa			agc = 0x22 + (sc->lna[group] * 5) / 3;
4067205042Sthompsa		else
4068205042Sthompsa			agc = 0x32 + (sc->lna[group] * 5) / 3;
4069205042Sthompsa	}
4070205042Sthompsa	run_set_agc(sc, agc);
4071203134Sthompsa}
4072203134Sthompsa
4073203134Sthompsastatic void
4074257429Shselaskyrun_rt2870_set_chan(struct run_softc *sc, u_int chan)
4075203134Sthompsa{
4076203134Sthompsa	const struct rfprog *rfprog = rt2860_rf2850;
4077203134Sthompsa	uint32_t r2, r3, r4;
4078203134Sthompsa	int8_t txpow1, txpow2;
4079203134Sthompsa	int i;
4080203134Sthompsa
4081203134Sthompsa	/* find the settings for this channel (we know it exists) */
4082203134Sthompsa	for (i = 0; rfprog[i].chan != chan; i++);
4083203134Sthompsa
4084203134Sthompsa	r2 = rfprog[i].r2;
4085203134Sthompsa	if (sc->ntxchains == 1)
4086258732Skevlo		r2 |= 1 << 14;		/* 1T: disable Tx chain 2 */
4087203134Sthompsa	if (sc->nrxchains == 1)
4088258732Skevlo		r2 |= 1 << 17 | 1 << 6;	/* 1R: disable Rx chains 2 & 3 */
4089203134Sthompsa	else if (sc->nrxchains == 2)
4090258732Skevlo		r2 |= 1 << 6;		/* 2R: disable Rx chain 3 */
4091203134Sthompsa
4092203134Sthompsa	/* use Tx power values from EEPROM */
4093203134Sthompsa	txpow1 = sc->txpow1[i];
4094203134Sthompsa	txpow2 = sc->txpow2[i];
4095258732Skevlo
4096258732Skevlo	/* Initialize RF R3 and R4. */
4097258732Skevlo	r3 = rfprog[i].r3 & 0xffffc1ff;
4098258732Skevlo	r4 = (rfprog[i].r4 & ~(0x001f87c0)) | (sc->freq << 15);
4099203134Sthompsa	if (chan > 14) {
4100258732Skevlo		if (txpow1 >= 0) {
4101258732Skevlo			txpow1 = (txpow1 > 0xf) ? (0xf) : (txpow1);
4102258732Skevlo			r3 |= (txpow1 << 10) | (1 << 9);
4103258732Skevlo		} else {
4104258732Skevlo			txpow1 += 7;
4105258732Skevlo
4106258732Skevlo			/* txpow1 is not possible larger than 15. */
4107258732Skevlo			r3 |= (txpow1 << 10);
4108258732Skevlo		}
4109258732Skevlo		if (txpow2 >= 0) {
4110258732Skevlo			txpow2 = (txpow2 > 0xf) ? (0xf) : (txpow2);
4111258921Shselasky			r4 |= (txpow2 << 7) | (1 << 6);
4112258732Skevlo		} else {
4113258732Skevlo			txpow2 += 7;
4114258732Skevlo			r4 |= (txpow2 << 7);
4115258732Skevlo		}
4116258732Skevlo	} else {
4117258732Skevlo		/* Set Tx0 power. */
4118258732Skevlo		r3 |= (txpow1 << 9);
4119258732Skevlo
4120258732Skevlo		/* Set frequency offset and Tx1 power. */
4121258732Skevlo		r4 |= (txpow2 << 6);
4122203134Sthompsa	}
4123203134Sthompsa
4124258733Skevlo	run_rt2870_rf_write(sc, rfprog[i].r1);
4125258733Skevlo	run_rt2870_rf_write(sc, r2);
4126258733Skevlo	run_rt2870_rf_write(sc, r3 & ~(1 << 2));
4127258733Skevlo	run_rt2870_rf_write(sc, r4);
4128203134Sthompsa
4129203134Sthompsa	run_delay(sc, 10);
4130203134Sthompsa
4131258733Skevlo	run_rt2870_rf_write(sc, rfprog[i].r1);
4132258733Skevlo	run_rt2870_rf_write(sc, r2);
4133258733Skevlo	run_rt2870_rf_write(sc, r3 | (1 << 2));
4134258733Skevlo	run_rt2870_rf_write(sc, r4);
4135203134Sthompsa
4136203134Sthompsa	run_delay(sc, 10);
4137203134Sthompsa
4138258733Skevlo	run_rt2870_rf_write(sc, rfprog[i].r1);
4139258733Skevlo	run_rt2870_rf_write(sc, r2);
4140258733Skevlo	run_rt2870_rf_write(sc, r3 & ~(1 << 2));
4141258733Skevlo	run_rt2870_rf_write(sc, r4);
4142203134Sthompsa}
4143203134Sthompsa
4144203134Sthompsastatic void
4145257429Shselaskyrun_rt3070_set_chan(struct run_softc *sc, u_int chan)
4146203134Sthompsa{
4147203134Sthompsa	int8_t txpow1, txpow2;
4148203134Sthompsa	uint8_t rf;
4149205042Sthompsa	int i;
4150203134Sthompsa
4151205042Sthompsa	/* find the settings for this channel (we know it exists) */
4152205042Sthompsa	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4153205042Sthompsa
4154203134Sthompsa	/* use Tx power values from EEPROM */
4155205042Sthompsa	txpow1 = sc->txpow1[i];
4156205042Sthompsa	txpow2 = sc->txpow2[i];
4157203134Sthompsa
4158205042Sthompsa	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
4159256720Skevlo
4160256720Skevlo	/* RT3370/RT3390: RF R3 [7:4] is not reserved bits. */
4161256720Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4162256720Skevlo	rf = (rf & ~0x0f) | rt3070_freqs[i].k;
4163256720Skevlo	run_rt3070_rf_write(sc, 3, rf);
4164256720Skevlo
4165203134Sthompsa	run_rt3070_rf_read(sc, 6, &rf);
4166205042Sthompsa	rf = (rf & ~0x03) | rt3070_freqs[i].r;
4167203134Sthompsa	run_rt3070_rf_write(sc, 6, rf);
4168203134Sthompsa
4169203134Sthompsa	/* set Tx0 power */
4170203134Sthompsa	run_rt3070_rf_read(sc, 12, &rf);
4171203134Sthompsa	rf = (rf & ~0x1f) | txpow1;
4172203134Sthompsa	run_rt3070_rf_write(sc, 12, rf);
4173203134Sthompsa
4174203134Sthompsa	/* set Tx1 power */
4175203134Sthompsa	run_rt3070_rf_read(sc, 13, &rf);
4176203134Sthompsa	rf = (rf & ~0x1f) | txpow2;
4177203134Sthompsa	run_rt3070_rf_write(sc, 13, rf);
4178203134Sthompsa
4179203134Sthompsa	run_rt3070_rf_read(sc, 1, &rf);
4180203134Sthompsa	rf &= ~0xfc;
4181203134Sthompsa	if (sc->ntxchains == 1)
4182203134Sthompsa		rf |= 1 << 7 | 1 << 5;	/* 1T: disable Tx chains 2 & 3 */
4183203134Sthompsa	else if (sc->ntxchains == 2)
4184203134Sthompsa		rf |= 1 << 7;		/* 2T: disable Tx chain 3 */
4185203134Sthompsa	if (sc->nrxchains == 1)
4186203134Sthompsa		rf |= 1 << 6 | 1 << 4;	/* 1R: disable Rx chains 2 & 3 */
4187203134Sthompsa	else if (sc->nrxchains == 2)
4188203134Sthompsa		rf |= 1 << 6;		/* 2R: disable Rx chain 3 */
4189203134Sthompsa	run_rt3070_rf_write(sc, 1, rf);
4190203134Sthompsa
4191203134Sthompsa	/* set RF offset */
4192203134Sthompsa	run_rt3070_rf_read(sc, 23, &rf);
4193203134Sthompsa	rf = (rf & ~0x7f) | sc->freq;
4194203134Sthompsa	run_rt3070_rf_write(sc, 23, rf);
4195203134Sthompsa
4196203134Sthompsa	/* program RF filter */
4197205042Sthompsa	run_rt3070_rf_read(sc, 24, &rf);	/* Tx */
4198205042Sthompsa	rf = (rf & ~0x3f) | sc->rf24_20mhz;
4199205042Sthompsa	run_rt3070_rf_write(sc, 24, rf);
4200205042Sthompsa	run_rt3070_rf_read(sc, 31, &rf);	/* Rx */
4201205042Sthompsa	rf = (rf & ~0x3f) | sc->rf24_20mhz;
4202205042Sthompsa	run_rt3070_rf_write(sc, 31, rf);
4203203134Sthompsa
4204203134Sthompsa	/* enable RF tuning */
4205203134Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4206203134Sthompsa	run_rt3070_rf_write(sc, 7, rf | 0x01);
4207203134Sthompsa}
4208203134Sthompsa
4209203134Sthompsastatic void
4210205042Sthompsarun_rt3572_set_chan(struct run_softc *sc, u_int chan)
4211205042Sthompsa{
4212205042Sthompsa	int8_t txpow1, txpow2;
4213205042Sthompsa	uint32_t tmp;
4214205042Sthompsa	uint8_t rf;
4215205042Sthompsa	int i;
4216205042Sthompsa
4217205042Sthompsa	/* find the settings for this channel (we know it exists) */
4218205042Sthompsa	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4219205042Sthompsa
4220205042Sthompsa	/* use Tx power values from EEPROM */
4221205042Sthompsa	txpow1 = sc->txpow1[i];
4222205042Sthompsa	txpow2 = sc->txpow2[i];
4223205042Sthompsa
4224205042Sthompsa	if (chan <= 14) {
4225205042Sthompsa		run_bbp_write(sc, 25, sc->bbp25);
4226205042Sthompsa		run_bbp_write(sc, 26, sc->bbp26);
4227205042Sthompsa	} else {
4228205042Sthompsa		/* enable IQ phase correction */
4229205042Sthompsa		run_bbp_write(sc, 25, 0x09);
4230205042Sthompsa		run_bbp_write(sc, 26, 0xff);
4231205042Sthompsa	}
4232205042Sthompsa
4233205042Sthompsa	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
4234205042Sthompsa	run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k);
4235205042Sthompsa	run_rt3070_rf_read(sc, 6, &rf);
4236205042Sthompsa	rf  = (rf & ~0x0f) | rt3070_freqs[i].r;
4237205042Sthompsa	rf |= (chan <= 14) ? 0x08 : 0x04;
4238205042Sthompsa	run_rt3070_rf_write(sc, 6, rf);
4239205042Sthompsa
4240205042Sthompsa	/* set PLL mode */
4241205042Sthompsa	run_rt3070_rf_read(sc, 5, &rf);
4242205042Sthompsa	rf &= ~(0x08 | 0x04);
4243205042Sthompsa	rf |= (chan <= 14) ? 0x04 : 0x08;
4244205042Sthompsa	run_rt3070_rf_write(sc, 5, rf);
4245205042Sthompsa
4246205042Sthompsa	/* set Tx power for chain 0 */
4247205042Sthompsa	if (chan <= 14)
4248205042Sthompsa		rf = 0x60 | txpow1;
4249205042Sthompsa	else
4250205042Sthompsa		rf = 0xe0 | (txpow1 & 0xc) << 1 | (txpow1 & 0x3);
4251205042Sthompsa	run_rt3070_rf_write(sc, 12, rf);
4252205042Sthompsa
4253205042Sthompsa	/* set Tx power for chain 1 */
4254205042Sthompsa	if (chan <= 14)
4255205042Sthompsa		rf = 0x60 | txpow2;
4256205042Sthompsa	else
4257205042Sthompsa		rf = 0xe0 | (txpow2 & 0xc) << 1 | (txpow2 & 0x3);
4258205042Sthompsa	run_rt3070_rf_write(sc, 13, rf);
4259205042Sthompsa
4260205042Sthompsa	/* set Tx/Rx streams */
4261205042Sthompsa	run_rt3070_rf_read(sc, 1, &rf);
4262205042Sthompsa	rf &= ~0xfc;
4263205042Sthompsa	if (sc->ntxchains == 1)
4264205042Sthompsa		rf |= 1 << 7 | 1 << 5;  /* 1T: disable Tx chains 2 & 3 */
4265205042Sthompsa	else if (sc->ntxchains == 2)
4266205042Sthompsa		rf |= 1 << 7;           /* 2T: disable Tx chain 3 */
4267205042Sthompsa	if (sc->nrxchains == 1)
4268205042Sthompsa		rf |= 1 << 6 | 1 << 4;  /* 1R: disable Rx chains 2 & 3 */
4269205042Sthompsa	else if (sc->nrxchains == 2)
4270205042Sthompsa		rf |= 1 << 6;           /* 2R: disable Rx chain 3 */
4271205042Sthompsa	run_rt3070_rf_write(sc, 1, rf);
4272205042Sthompsa
4273205042Sthompsa	/* set RF offset */
4274205042Sthompsa	run_rt3070_rf_read(sc, 23, &rf);
4275205042Sthompsa	rf = (rf & ~0x7f) | sc->freq;
4276205042Sthompsa	run_rt3070_rf_write(sc, 23, rf);
4277205042Sthompsa
4278205042Sthompsa	/* program RF filter */
4279205042Sthompsa	rf = sc->rf24_20mhz;
4280205042Sthompsa	run_rt3070_rf_write(sc, 24, rf);	/* Tx */
4281205042Sthompsa	run_rt3070_rf_write(sc, 31, rf);	/* Rx */
4282205042Sthompsa
4283205042Sthompsa	/* enable RF tuning */
4284205042Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4285205042Sthompsa	rf = (chan <= 14) ? 0xd8 : ((rf & ~0xc8) | 0x14);
4286205042Sthompsa	run_rt3070_rf_write(sc, 7, rf);
4287205042Sthompsa
4288205042Sthompsa	/* TSSI */
4289205042Sthompsa	rf = (chan <= 14) ? 0xc3 : 0xc0;
4290205042Sthompsa	run_rt3070_rf_write(sc, 9, rf);
4291205042Sthompsa
4292205042Sthompsa	/* set loop filter 1 */
4293205042Sthompsa	run_rt3070_rf_write(sc, 10, 0xf1);
4294205042Sthompsa	/* set loop filter 2 */
4295205042Sthompsa	run_rt3070_rf_write(sc, 11, (chan <= 14) ? 0xb9 : 0x00);
4296205042Sthompsa
4297205042Sthompsa	/* set tx_mx2_ic */
4298205042Sthompsa	run_rt3070_rf_write(sc, 15, (chan <= 14) ? 0x53 : 0x43);
4299205042Sthompsa	/* set tx_mx1_ic */
4300205042Sthompsa	if (chan <= 14)
4301205042Sthompsa		rf = 0x48 | sc->txmixgain_2ghz;
4302205042Sthompsa	else
4303205042Sthompsa		rf = 0x78 | sc->txmixgain_5ghz;
4304205042Sthompsa	run_rt3070_rf_write(sc, 16, rf);
4305205042Sthompsa
4306205042Sthompsa	/* set tx_lo1 */
4307205042Sthompsa	run_rt3070_rf_write(sc, 17, 0x23);
4308205042Sthompsa	/* set tx_lo2 */
4309205042Sthompsa	if (chan <= 14)
4310205042Sthompsa		rf = 0x93;
4311205042Sthompsa	else if (chan <= 64)
4312205042Sthompsa		rf = 0xb7;
4313205042Sthompsa	else if (chan <= 128)
4314205042Sthompsa		rf = 0x74;
4315205042Sthompsa	else
4316205042Sthompsa		rf = 0x72;
4317205042Sthompsa	run_rt3070_rf_write(sc, 19, rf);
4318205042Sthompsa
4319205042Sthompsa	/* set rx_lo1 */
4320205042Sthompsa	if (chan <= 14)
4321205042Sthompsa		rf = 0xb3;
4322205042Sthompsa	else if (chan <= 64)
4323205042Sthompsa		rf = 0xf6;
4324205042Sthompsa	else if (chan <= 128)
4325205042Sthompsa		rf = 0xf4;
4326205042Sthompsa	else
4327205042Sthompsa		rf = 0xf3;
4328205042Sthompsa	run_rt3070_rf_write(sc, 20, rf);
4329205042Sthompsa
4330205042Sthompsa	/* set pfd_delay */
4331205042Sthompsa	if (chan <= 14)
4332205042Sthompsa		rf = 0x15;
4333205042Sthompsa	else if (chan <= 64)
4334205042Sthompsa		rf = 0x3d;
4335205042Sthompsa	else
4336205042Sthompsa		rf = 0x01;
4337205042Sthompsa	run_rt3070_rf_write(sc, 25, rf);
4338205042Sthompsa
4339205042Sthompsa	/* set rx_lo2 */
4340205042Sthompsa	run_rt3070_rf_write(sc, 26, (chan <= 14) ? 0x85 : 0x87);
4341205042Sthompsa	/* set ldo_rf_vc */
4342205042Sthompsa	run_rt3070_rf_write(sc, 27, (chan <= 14) ? 0x00 : 0x01);
4343205042Sthompsa	/* set drv_cc */
4344205042Sthompsa	run_rt3070_rf_write(sc, 29, (chan <= 14) ? 0x9b : 0x9f);
4345205042Sthompsa
4346205042Sthompsa	run_read(sc, RT2860_GPIO_CTRL, &tmp);
4347205042Sthompsa	tmp &= ~0x8080;
4348205042Sthompsa	if (chan <= 14)
4349205042Sthompsa		tmp |= 0x80;
4350205042Sthompsa	run_write(sc, RT2860_GPIO_CTRL, tmp);
4351205042Sthompsa
4352205042Sthompsa	/* enable RF tuning */
4353205042Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4354205042Sthompsa	run_rt3070_rf_write(sc, 7, rf | 0x01);
4355205042Sthompsa
4356205042Sthompsa	run_delay(sc, 2);
4357205042Sthompsa}
4358205042Sthompsa
4359205042Sthompsastatic void
4360260219Skevlorun_rt3593_set_chan(struct run_softc *sc, u_int chan)
4361260219Skevlo{
4362260219Skevlo	int8_t txpow1, txpow2, txpow3;
4363260219Skevlo	uint8_t h20mhz, rf;
4364260219Skevlo	int i;
4365260219Skevlo
4366260219Skevlo	/* find the settings for this channel (we know it exists) */
4367260219Skevlo	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4368260219Skevlo
4369260219Skevlo	/* use Tx power values from EEPROM */
4370260219Skevlo	txpow1 = sc->txpow1[i];
4371260219Skevlo	txpow2 = sc->txpow2[i];
4372260219Skevlo	txpow3 = (sc->ntxchains == 3) ? sc->txpow3[i] : 0;
4373260219Skevlo
4374260219Skevlo	if (chan <= 14) {
4375260219Skevlo		run_bbp_write(sc, 25, sc->bbp25);
4376260219Skevlo		run_bbp_write(sc, 26, sc->bbp26);
4377260219Skevlo	} else {
4378260219Skevlo		/* Enable IQ phase correction. */
4379260219Skevlo		run_bbp_write(sc, 25, 0x09);
4380260219Skevlo		run_bbp_write(sc, 26, 0xff);
4381260219Skevlo	}
4382260219Skevlo
4383260219Skevlo	run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n);
4384260219Skevlo	run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f);
4385260219Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4386260219Skevlo	rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03);
4387260219Skevlo	run_rt3070_rf_write(sc, 11, rf);
4388260219Skevlo
4389260219Skevlo	/* Set pll_idoh. */
4390260219Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4391260219Skevlo	rf &= ~0x4c;
4392260219Skevlo	rf |= (chan <= 14) ? 0x44 : 0x48;
4393260219Skevlo	run_rt3070_rf_write(sc, 11, rf);
4394260219Skevlo
4395260219Skevlo	if (chan <= 14)
4396260219Skevlo		rf = txpow1 & 0x1f;
4397260219Skevlo	else
4398260219Skevlo		rf = 0x40 | ((txpow1 & 0x18) << 1) | (txpow1 & 0x07);
4399260219Skevlo	run_rt3070_rf_write(sc, 53, rf);
4400260219Skevlo
4401260219Skevlo	if (chan <= 14)
4402260219Skevlo		rf = txpow2 & 0x1f;
4403260219Skevlo	else
4404260219Skevlo		rf = 0x40 | ((txpow2 & 0x18) << 1) | (txpow2 & 0x07);
4405260219Skevlo	run_rt3070_rf_write(sc, 55, rf);
4406260219Skevlo
4407260219Skevlo	if (chan <= 14)
4408260219Skevlo		rf = txpow3 & 0x1f;
4409260219Skevlo	else
4410260219Skevlo		rf = 0x40 | ((txpow3 & 0x18) << 1) | (txpow3 & 0x07);
4411260219Skevlo	run_rt3070_rf_write(sc, 54, rf);
4412260219Skevlo
4413260219Skevlo	rf = RT3070_RF_BLOCK | RT3070_PLL_PD;
4414260219Skevlo	if (sc->ntxchains == 3)
4415260219Skevlo		rf |= RT3070_TX0_PD | RT3070_TX1_PD | RT3070_TX2_PD;
4416260219Skevlo	else
4417260219Skevlo		rf |= RT3070_TX0_PD | RT3070_TX1_PD;
4418260219Skevlo	rf |= RT3070_RX0_PD | RT3070_RX1_PD | RT3070_RX2_PD;
4419260219Skevlo	run_rt3070_rf_write(sc, 1, rf);
4420260219Skevlo
4421260219Skevlo	run_adjust_freq_offset(sc);
4422260219Skevlo
4423260219Skevlo	run_rt3070_rf_write(sc, 31, (chan <= 14) ? 0xa0 : 0x80);
4424260219Skevlo
4425260219Skevlo	h20mhz = (sc->rf24_20mhz & 0x20) >> 5;
4426260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
4427260219Skevlo	rf = (rf & ~0x06) | (h20mhz << 1) | (h20mhz << 2);
4428260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
4429260219Skevlo
4430260219Skevlo	run_rt3070_rf_read(sc, 36, &rf);
4431260219Skevlo	if (chan <= 14)
4432260219Skevlo		rf |= 0x80;
4433260219Skevlo	else
4434260219Skevlo		rf &= ~0x80;
4435260219Skevlo	run_rt3070_rf_write(sc, 36, rf);
4436260219Skevlo
4437260219Skevlo	/* Set vcolo_bs. */
4438260219Skevlo	run_rt3070_rf_write(sc, 34, (chan <= 14) ? 0x3c : 0x20);
4439260219Skevlo	/* Set pfd_delay. */
4440260219Skevlo	run_rt3070_rf_write(sc, 12, (chan <= 14) ? 0x1a : 0x12);
4441260219Skevlo
4442260219Skevlo	/* Set vco bias current control. */
4443260219Skevlo	run_rt3070_rf_read(sc, 6, &rf);
4444260219Skevlo	rf &= ~0xc0;
4445260219Skevlo	if (chan <= 14)
4446260219Skevlo		rf |= 0x40;
4447260219Skevlo	else if (chan <= 128)
4448260219Skevlo		rf |= 0x80;
4449260219Skevlo	else
4450260219Skevlo		rf |= 0x40;
4451260219Skevlo	run_rt3070_rf_write(sc, 6, rf);
4452260219Skevlo
4453260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
4454260219Skevlo	rf = (rf & ~0x18) | 0x10;
4455260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
4456260219Skevlo
4457260219Skevlo	run_rt3070_rf_write(sc, 10, (chan <= 14) ? 0xd3 : 0xd8);
4458260219Skevlo	run_rt3070_rf_write(sc, 13, (chan <= 14) ? 0x12 : 0x23);
4459260219Skevlo
4460260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4461260219Skevlo	rf = (rf & ~0x03) | 0x01;
4462260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
4463260219Skevlo	/* Set tx_mx1_cc. */
4464260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4465260219Skevlo	rf &= ~0x1c;
4466260219Skevlo	rf |= (chan <= 14) ? 0x14 : 0x10;
4467260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
4468260219Skevlo	/* Set tx_mx1_ic. */
4469260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4470260219Skevlo	rf &= ~0xe0;
4471260219Skevlo	rf |= (chan <= 14) ? 0x60 : 0x40;
4472260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
4473260219Skevlo	/* Set tx_lo1_ic. */
4474260219Skevlo	run_rt3070_rf_read(sc, 49, &rf);
4475260219Skevlo	rf &= ~0x1c;
4476260219Skevlo	rf |= (chan <= 14) ? 0x0c : 0x08;
4477260219Skevlo	run_rt3070_rf_write(sc, 49, rf);
4478260219Skevlo	/* Set tx_lo1_en. */
4479260219Skevlo	run_rt3070_rf_read(sc, 50, &rf);
4480260219Skevlo	run_rt3070_rf_write(sc, 50, rf & ~0x20);
4481260219Skevlo	/* Set drv_cc. */
4482260219Skevlo	run_rt3070_rf_read(sc, 57, &rf);
4483260219Skevlo	rf &= ~0xfc;
4484260219Skevlo	rf |= (chan <= 14) ?  0x6c : 0x3c;
4485260219Skevlo	run_rt3070_rf_write(sc, 57, rf);
4486260219Skevlo	/* Set rx_mix1_ic, rxa_lnactr, lna_vc, lna_inbias_en and lna_en. */
4487260219Skevlo	run_rt3070_rf_write(sc, 44, (chan <= 14) ? 0x93 : 0x9b);
4488260219Skevlo	/* Set drv_gnd_a, tx_vga_cc_a and tx_mx2_gain. */
4489260219Skevlo	run_rt3070_rf_write(sc, 52, (chan <= 14) ? 0x45 : 0x05);
4490260219Skevlo	/* Enable VCO calibration. */
4491260219Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4492260219Skevlo	rf &= ~RT5390_VCOCAL;
4493260219Skevlo	rf |= (chan <= 14) ? RT5390_VCOCAL : 0xbe;
4494260219Skevlo	run_rt3070_rf_write(sc, 3, rf);
4495260219Skevlo
4496260219Skevlo	if (chan <= 14)
4497260219Skevlo		rf = 0x23;
4498260219Skevlo	else if (chan <= 64)
4499260219Skevlo		rf = 0x36;
4500260219Skevlo	else if (chan <= 128)
4501260219Skevlo		rf = 0x32;
4502260219Skevlo	else
4503260219Skevlo		rf = 0x30;
4504260219Skevlo	run_rt3070_rf_write(sc, 39, rf);
4505260219Skevlo	if (chan <= 14)
4506260219Skevlo		rf = 0xbb;
4507260219Skevlo	else if (chan <= 64)
4508260219Skevlo		rf = 0xeb;
4509260219Skevlo	else if (chan <= 128)
4510260219Skevlo		rf = 0xb3;
4511260219Skevlo	else
4512260219Skevlo		rf = 0x9b;
4513260219Skevlo	run_rt3070_rf_write(sc, 45, rf);
4514260219Skevlo
4515260219Skevlo	/* Set FEQ/AEQ control. */
4516260219Skevlo	run_bbp_write(sc, 105, 0x34);
4517260219Skevlo}
4518260219Skevlo
4519260219Skevlostatic void
4520257955Skevlorun_rt5390_set_chan(struct run_softc *sc, u_int chan)
4521257955Skevlo{
4522257955Skevlo	int8_t txpow1, txpow2;
4523257955Skevlo	uint8_t rf;
4524257955Skevlo	int i;
4525257955Skevlo
4526257955Skevlo	/* find the settings for this channel (we know it exists) */
4527257955Skevlo	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4528257955Skevlo
4529257955Skevlo	/* use Tx power values from EEPROM */
4530257955Skevlo	txpow1 = sc->txpow1[i];
4531257955Skevlo	txpow2 = sc->txpow2[i];
4532257955Skevlo
4533257955Skevlo	run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n);
4534257955Skevlo	run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f);
4535257955Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4536257955Skevlo	rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03);
4537257955Skevlo	run_rt3070_rf_write(sc, 11, rf);
4538257955Skevlo
4539257955Skevlo	run_rt3070_rf_read(sc, 49, &rf);
4540257955Skevlo	rf = (rf & ~0x3f) | (txpow1 & 0x3f);
4541257955Skevlo	/* The valid range of the RF R49 is 0x00 to 0x27. */
4542257955Skevlo	if ((rf & 0x3f) > 0x27)
4543257955Skevlo		rf = (rf & ~0x3f) | 0x27;
4544257955Skevlo	run_rt3070_rf_write(sc, 49, rf);
4545257955Skevlo
4546257955Skevlo	if (sc->mac_ver == 0x5392) {
4547257955Skevlo		run_rt3070_rf_read(sc, 50, &rf);
4548257955Skevlo		rf = (rf & ~0x3f) | (txpow2 & 0x3f);
4549257955Skevlo		/* The valid range of the RF R50 is 0x00 to 0x27. */
4550257955Skevlo		if ((rf & 0x3f) > 0x27)
4551257955Skevlo			rf = (rf & ~0x3f) | 0x27;
4552257955Skevlo		run_rt3070_rf_write(sc, 50, rf);
4553257955Skevlo	}
4554257955Skevlo
4555257955Skevlo	run_rt3070_rf_read(sc, 1, &rf);
4556257955Skevlo	rf |= RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD;
4557257955Skevlo	if (sc->mac_ver == 0x5392)
4558257955Skevlo		rf |= RT3070_RX1_PD | RT3070_TX1_PD;
4559257955Skevlo	run_rt3070_rf_write(sc, 1, rf);
4560257955Skevlo
4561257955Skevlo	if (sc->mac_ver != 0x5392) {
4562257955Skevlo		run_rt3070_rf_read(sc, 2, &rf);
4563257955Skevlo		rf |= 0x80;
4564257955Skevlo		run_rt3070_rf_write(sc, 2, rf);
4565257955Skevlo		run_delay(sc, 10);
4566257955Skevlo		rf &= 0x7f;
4567257955Skevlo		run_rt3070_rf_write(sc, 2, rf);
4568257955Skevlo	}
4569257955Skevlo
4570257955Skevlo	run_adjust_freq_offset(sc);
4571257955Skevlo
4572257955Skevlo	if (sc->mac_ver == 0x5392) {
4573257955Skevlo		/* Fix for RT5392C. */
4574257955Skevlo		if (sc->mac_rev >= 0x0223) {
4575259030Skevlo			if (chan <= 4)
4576257955Skevlo				rf = 0x0f;
4577259030Skevlo			else if (chan >= 5 && chan <= 7)
4578257955Skevlo				rf = 0x0e;
4579259030Skevlo			else
4580257955Skevlo				rf = 0x0d;
4581257955Skevlo			run_rt3070_rf_write(sc, 23, rf);
4582257955Skevlo
4583259030Skevlo			if (chan <= 4)
4584257955Skevlo				rf = 0x0c;
4585257955Skevlo			else if (chan == 5)
4586257955Skevlo				rf = 0x0b;
4587259030Skevlo			else if (chan >= 6 && chan <= 7)
4588257955Skevlo				rf = 0x0a;
4589259030Skevlo			else if (chan >= 8 && chan <= 10)
4590257955Skevlo				rf = 0x09;
4591259030Skevlo			else
4592257955Skevlo				rf = 0x08;
4593257955Skevlo			run_rt3070_rf_write(sc, 59, rf);
4594257955Skevlo		} else {
4595259030Skevlo			if (chan <= 11)
4596257955Skevlo				rf = 0x0f;
4597259030Skevlo			else
4598257955Skevlo				rf = 0x0b;
4599257955Skevlo			run_rt3070_rf_write(sc, 59, rf);
4600257955Skevlo		}
4601257955Skevlo	} else {
4602257955Skevlo		/* Fix for RT5390F. */
4603257955Skevlo		if (sc->mac_rev >= 0x0502) {
4604259030Skevlo			if (chan <= 11)
4605257955Skevlo				rf = 0x43;
4606259030Skevlo			else
4607257955Skevlo				rf = 0x23;
4608257955Skevlo			run_rt3070_rf_write(sc, 55, rf);
4609257955Skevlo
4610259030Skevlo			if (chan <= 11)
4611257955Skevlo				rf = 0x0f;
4612257955Skevlo			else if (chan == 12)
4613257955Skevlo				rf = 0x0d;
4614259030Skevlo			else
4615257955Skevlo				rf = 0x0b;
4616257955Skevlo			run_rt3070_rf_write(sc, 59, rf);
4617257955Skevlo		} else {
4618257955Skevlo			run_rt3070_rf_write(sc, 55, 0x44);
4619257955Skevlo			run_rt3070_rf_write(sc, 59, 0x8f);
4620257955Skevlo		}
4621257955Skevlo	}
4622257955Skevlo
4623257955Skevlo	/* Enable VCO calibration. */
4624257955Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4625257955Skevlo	rf |= RT5390_VCOCAL;
4626257955Skevlo	run_rt3070_rf_write(sc, 3, rf);
4627257955Skevlo}
4628257955Skevlo
4629257955Skevlostatic void
4630259032Skevlorun_rt5592_set_chan(struct run_softc *sc, u_int chan)
4631259032Skevlo{
4632259032Skevlo	const struct rt5592_freqs *freqs;
4633259032Skevlo	uint32_t tmp;
4634259032Skevlo	uint8_t reg, rf, txpow_bound;
4635259032Skevlo	int8_t txpow1, txpow2;
4636259032Skevlo	int i;
4637259032Skevlo
4638259032Skevlo	run_read(sc, RT5592_DEBUG_INDEX, &tmp);
4639259032Skevlo	freqs = (tmp & RT5592_SEL_XTAL) ?
4640259032Skevlo	    rt5592_freqs_40mhz : rt5592_freqs_20mhz;
4641259032Skevlo
4642259032Skevlo	/* find the settings for this channel (we know it exists) */
4643259032Skevlo	for (i = 0; rt2860_rf2850[i].chan != chan; i++, freqs++);
4644259032Skevlo
4645259032Skevlo	/* use Tx power values from EEPROM */
4646259032Skevlo	txpow1 = sc->txpow1[i];
4647259032Skevlo	txpow2 = sc->txpow2[i];
4648259032Skevlo
4649259032Skevlo	run_read(sc, RT3070_LDO_CFG0, &tmp);
4650259032Skevlo	tmp &= ~0x1c000000;
4651259032Skevlo	if (chan > 14)
4652259032Skevlo		tmp |= 0x14000000;
4653259032Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
4654259032Skevlo
4655259032Skevlo	/* N setting. */
4656259032Skevlo	run_rt3070_rf_write(sc, 8, freqs->n & 0xff);
4657259032Skevlo	run_rt3070_rf_read(sc, 9, &rf);
4658259032Skevlo	rf &= ~(1 << 4);
4659259032Skevlo	rf |= ((freqs->n & 0x0100) >> 8) << 4;
4660259032Skevlo	run_rt3070_rf_write(sc, 9, rf);
4661259032Skevlo
4662259032Skevlo	/* K setting. */
4663259032Skevlo	run_rt3070_rf_read(sc, 9, &rf);
4664259032Skevlo	rf &= ~0x0f;
4665259032Skevlo	rf |= (freqs->k & 0x0f);
4666259032Skevlo	run_rt3070_rf_write(sc, 9, rf);
4667259032Skevlo
4668259032Skevlo	/* Mode setting. */
4669259032Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4670259032Skevlo	rf &= ~0x0c;
4671259032Skevlo	rf |= ((freqs->m - 0x8) & 0x3) << 2;
4672259032Skevlo	run_rt3070_rf_write(sc, 11, rf);
4673259032Skevlo	run_rt3070_rf_read(sc, 9, &rf);
4674259032Skevlo	rf &= ~(1 << 7);
4675259032Skevlo	rf |= (((freqs->m - 0x8) & 0x4) >> 2) << 7;
4676259032Skevlo	run_rt3070_rf_write(sc, 9, rf);
4677259032Skevlo
4678259032Skevlo	/* R setting. */
4679259032Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4680259032Skevlo	rf &= ~0x03;
4681259032Skevlo	rf |= (freqs->r - 0x1);
4682259032Skevlo	run_rt3070_rf_write(sc, 11, rf);
4683259032Skevlo
4684259032Skevlo	if (chan <= 14) {
4685259032Skevlo		/* Initialize RF registers for 2GHZ. */
4686259032Skevlo		for (i = 0; i < nitems(rt5592_2ghz_def_rf); i++) {
4687259032Skevlo			run_rt3070_rf_write(sc, rt5592_2ghz_def_rf[i].reg,
4688259032Skevlo			    rt5592_2ghz_def_rf[i].val);
4689259032Skevlo		}
4690259032Skevlo
4691259032Skevlo		rf = (chan <= 10) ? 0x07 : 0x06;
4692259032Skevlo		run_rt3070_rf_write(sc, 23, rf);
4693259032Skevlo		run_rt3070_rf_write(sc, 59, rf);
4694259032Skevlo
4695259032Skevlo		run_rt3070_rf_write(sc, 55, 0x43);
4696259032Skevlo
4697259032Skevlo		/*
4698259032Skevlo		 * RF R49/R50 Tx power ALC code.
4699259032Skevlo		 * G-band bit<7:6>=1:0, bit<5:0> range from 0x0 ~ 0x27.
4700259032Skevlo		 */
4701259032Skevlo		reg = 2;
4702259032Skevlo		txpow_bound = 0x27;
4703259032Skevlo	} else {
4704259032Skevlo		/* Initialize RF registers for 5GHZ. */
4705259032Skevlo		for (i = 0; i < nitems(rt5592_5ghz_def_rf); i++) {
4706259032Skevlo			run_rt3070_rf_write(sc, rt5592_5ghz_def_rf[i].reg,
4707259032Skevlo			    rt5592_5ghz_def_rf[i].val);
4708259032Skevlo		}
4709259032Skevlo		for (i = 0; i < nitems(rt5592_chan_5ghz); i++) {
4710259032Skevlo			if (chan >= rt5592_chan_5ghz[i].firstchan &&
4711259032Skevlo			    chan <= rt5592_chan_5ghz[i].lastchan) {
4712259032Skevlo				run_rt3070_rf_write(sc, rt5592_chan_5ghz[i].reg,
4713259032Skevlo				    rt5592_chan_5ghz[i].val);
4714259032Skevlo			}
4715259032Skevlo		}
4716259032Skevlo
4717259032Skevlo		/*
4718259032Skevlo		 * RF R49/R50 Tx power ALC code.
4719259032Skevlo		 * A-band bit<7:6>=1:1, bit<5:0> range from 0x0 ~ 0x2b.
4720259032Skevlo		 */
4721259032Skevlo		reg = 3;
4722259032Skevlo		txpow_bound = 0x2b;
4723259032Skevlo	}
4724259032Skevlo
4725259032Skevlo	/* RF R49 ch0 Tx power ALC code. */
4726259032Skevlo	run_rt3070_rf_read(sc, 49, &rf);
4727259032Skevlo	rf &= ~0xc0;
4728259032Skevlo	rf |= (reg << 6);
4729259032Skevlo	rf = (rf & ~0x3f) | (txpow1 & 0x3f);
4730259032Skevlo	if ((rf & 0x3f) > txpow_bound)
4731259032Skevlo		rf = (rf & ~0x3f) | txpow_bound;
4732259032Skevlo	run_rt3070_rf_write(sc, 49, rf);
4733259032Skevlo
4734259032Skevlo	/* RF R50 ch1 Tx power ALC code. */
4735259032Skevlo	run_rt3070_rf_read(sc, 50, &rf);
4736259032Skevlo	rf &= ~(1 << 7 | 1 << 6);
4737259032Skevlo	rf |= (reg << 6);
4738259032Skevlo	rf = (rf & ~0x3f) | (txpow2 & 0x3f);
4739259032Skevlo	if ((rf & 0x3f) > txpow_bound)
4740259032Skevlo		rf = (rf & ~0x3f) | txpow_bound;
4741259032Skevlo	run_rt3070_rf_write(sc, 50, rf);
4742259032Skevlo
4743259032Skevlo	/* Enable RF_BLOCK, PLL_PD, RX0_PD, and TX0_PD. */
4744259032Skevlo	run_rt3070_rf_read(sc, 1, &rf);
4745259032Skevlo	rf |= (RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD);
4746259032Skevlo	if (sc->ntxchains > 1)
4747259032Skevlo		rf |= RT3070_TX1_PD;
4748259032Skevlo	if (sc->nrxchains > 1)
4749259032Skevlo		rf |= RT3070_RX1_PD;
4750259032Skevlo	run_rt3070_rf_write(sc, 1, rf);
4751259032Skevlo
4752259032Skevlo	run_rt3070_rf_write(sc, 6, 0xe4);
4753259032Skevlo
4754259032Skevlo	run_rt3070_rf_write(sc, 30, 0x10);
4755259032Skevlo	run_rt3070_rf_write(sc, 31, 0x80);
4756259032Skevlo	run_rt3070_rf_write(sc, 32, 0x80);
4757259032Skevlo
4758259032Skevlo	run_adjust_freq_offset(sc);
4759259032Skevlo
4760259032Skevlo	/* Enable VCO calibration. */
4761259032Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4762259032Skevlo	rf |= RT5390_VCOCAL;
4763259032Skevlo	run_rt3070_rf_write(sc, 3, rf);
4764259032Skevlo}
4765259032Skevlo
4766259032Skevlostatic void
4767203134Sthompsarun_set_rx_antenna(struct run_softc *sc, int aux)
4768203134Sthompsa{
4769203134Sthompsa	uint32_t tmp;
4770257955Skevlo	uint8_t bbp152;
4771203134Sthompsa
4772203134Sthompsa	if (aux) {
4773257955Skevlo		if (sc->rf_rev == RT5390_RF_5370) {
4774257955Skevlo			run_bbp_read(sc, 152, &bbp152);
4775257955Skevlo			run_bbp_write(sc, 152, bbp152 & ~0x80);
4776259030Skevlo		} else {
4777257955Skevlo			run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 0);
4778257955Skevlo			run_read(sc, RT2860_GPIO_CTRL, &tmp);
4779257955Skevlo			run_write(sc, RT2860_GPIO_CTRL, (tmp & ~0x0808) | 0x08);
4780257955Skevlo		}
4781203134Sthompsa	} else {
4782257955Skevlo		if (sc->rf_rev == RT5390_RF_5370) {
4783257955Skevlo			run_bbp_read(sc, 152, &bbp152);
4784257955Skevlo			run_bbp_write(sc, 152, bbp152 | 0x80);
4785259030Skevlo		} else {
4786257955Skevlo			run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 1);
4787257955Skevlo			run_read(sc, RT2860_GPIO_CTRL, &tmp);
4788257955Skevlo			run_write(sc, RT2860_GPIO_CTRL, tmp & ~0x0808);
4789257955Skevlo		}
4790203134Sthompsa	}
4791203134Sthompsa}
4792203134Sthompsa
4793203134Sthompsastatic int
4794203134Sthompsarun_set_chan(struct run_softc *sc, struct ieee80211_channel *c)
4795203134Sthompsa{
4796203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
4797257429Shselasky	u_int chan, group;
4798203134Sthompsa
4799203134Sthompsa	chan = ieee80211_chan2ieee(ic, c);
4800203134Sthompsa	if (chan == 0 || chan == IEEE80211_CHAN_ANY)
4801209917Sthompsa		return (EINVAL);
4802203134Sthompsa
4803259032Skevlo	if (sc->mac_ver == 0x5592)
4804259032Skevlo		run_rt5592_set_chan(sc, chan);
4805259032Skevlo	else if (sc->mac_ver >= 0x5390)
4806257955Skevlo		run_rt5390_set_chan(sc, chan);
4807260219Skevlo	else if (sc->mac_ver == 0x3593)
4808260219Skevlo		run_rt3593_set_chan(sc, chan);
4809257955Skevlo	else if (sc->mac_ver == 0x3572)
4810205042Sthompsa		run_rt3572_set_chan(sc, chan);
4811205042Sthompsa	else if (sc->mac_ver >= 0x3070)
4812203134Sthompsa		run_rt3070_set_chan(sc, chan);
4813203134Sthompsa	else
4814203134Sthompsa		run_rt2870_set_chan(sc, chan);
4815203134Sthompsa
4816203134Sthompsa	/* determine channel group */
4817203134Sthompsa	if (chan <= 14)
4818203134Sthompsa		group = 0;
4819203134Sthompsa	else if (chan <= 64)
4820203134Sthompsa		group = 1;
4821203134Sthompsa	else if (chan <= 128)
4822203134Sthompsa		group = 2;
4823203134Sthompsa	else
4824203134Sthompsa		group = 3;
4825203134Sthompsa
4826203134Sthompsa	/* XXX necessary only when group has changed! */
4827203134Sthompsa	run_select_chan_group(sc, group);
4828203134Sthompsa
4829203134Sthompsa	run_delay(sc, 10);
4830203134Sthompsa
4831259545Skevlo	/* Perform IQ calibration. */
4832259544Skevlo	if (sc->mac_ver >= 0x5392)
4833259544Skevlo		run_iq_calib(sc, chan);
4834259544Skevlo
4835209917Sthompsa	return (0);
4836203134Sthompsa}
4837203134Sthompsa
4838203134Sthompsastatic void
4839203134Sthompsarun_set_channel(struct ieee80211com *ic)
4840203134Sthompsa{
4841203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
4842203134Sthompsa
4843203134Sthompsa	RUN_LOCK(sc);
4844203134Sthompsa	run_set_chan(sc, ic->ic_curchan);
4845203134Sthompsa	RUN_UNLOCK(sc);
4846203134Sthompsa
4847203134Sthompsa	return;
4848203134Sthompsa}
4849203134Sthompsa
4850203134Sthompsastatic void
4851203134Sthompsarun_scan_start(struct ieee80211com *ic)
4852203134Sthompsa{
4853203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
4854203134Sthompsa	uint32_t tmp;
4855203134Sthompsa
4856203134Sthompsa	RUN_LOCK(sc);
4857203134Sthompsa
4858203134Sthompsa	/* abort TSF synchronization */
4859203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
4860203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG,
4861203134Sthompsa	    tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
4862203134Sthompsa	    RT2860_TBTT_TIMER_EN));
4863203134Sthompsa	run_set_bssid(sc, sc->sc_ifp->if_broadcastaddr);
4864203134Sthompsa
4865203134Sthompsa	RUN_UNLOCK(sc);
4866203134Sthompsa
4867203134Sthompsa	return;
4868203134Sthompsa}
4869203134Sthompsa
4870203134Sthompsastatic void
4871203134Sthompsarun_scan_end(struct ieee80211com *ic)
4872203134Sthompsa{
4873203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
4874203134Sthompsa
4875203134Sthompsa	RUN_LOCK(sc);
4876203134Sthompsa
4877203134Sthompsa	run_enable_tsf_sync(sc);
4878203134Sthompsa	/* XXX keep local copy */
4879203134Sthompsa	run_set_bssid(sc, sc->sc_bssid);
4880203134Sthompsa
4881203134Sthompsa	RUN_UNLOCK(sc);
4882203134Sthompsa
4883203134Sthompsa	return;
4884203134Sthompsa}
4885203134Sthompsa
4886208019Sthompsa/*
4887208019Sthompsa * Could be called from ieee80211_node_timeout()
4888208019Sthompsa * (non-sleepable thread)
4889208019Sthompsa */
4890208019Sthompsastatic void
4891208019Sthompsarun_update_beacon(struct ieee80211vap *vap, int item)
4892203134Sthompsa{
4893208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
4894208019Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
4895218492Sbschmidt	struct run_vap *rvp = RUN_VAP(vap);
4896218492Sbschmidt	int mcast = 0;
4897208019Sthompsa	uint32_t i;
4898208019Sthompsa
4899218492Sbschmidt	KASSERT(vap != NULL, ("no beacon"));
4900218492Sbschmidt
4901218492Sbschmidt	switch (item) {
4902218492Sbschmidt	case IEEE80211_BEACON_ERP:
4903218492Sbschmidt		run_updateslot(ic->ic_ifp);
4904218492Sbschmidt		break;
4905218492Sbschmidt	case IEEE80211_BEACON_HTINFO:
4906218492Sbschmidt		run_updateprot(ic);
4907218492Sbschmidt		break;
4908218492Sbschmidt	case IEEE80211_BEACON_TIM:
4909218492Sbschmidt		mcast = 1;	/*TODO*/
4910218492Sbschmidt		break;
4911218492Sbschmidt	default:
4912218492Sbschmidt		break;
4913218492Sbschmidt	}
4914218492Sbschmidt
4915218492Sbschmidt	setbit(rvp->bo.bo_flags, item);
4916218492Sbschmidt	ieee80211_beacon_update(vap->iv_bss, &rvp->bo, rvp->beacon_mbuf, mcast);
4917218492Sbschmidt
4918208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
4919208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
4920208019Sthompsa	sc->cmdq[i].func = run_update_beacon_cb;
4921208019Sthompsa	sc->cmdq[i].arg0 = vap;
4922208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
4923208019Sthompsa
4924208019Sthompsa	return;
4925203134Sthompsa}
4926203134Sthompsa
4927203134Sthompsastatic void
4928208019Sthompsarun_update_beacon_cb(void *arg)
4929203134Sthompsa{
4930208019Sthompsa	struct ieee80211vap *vap = arg;
4931218492Sbschmidt	struct run_vap *rvp = RUN_VAP(vap);
4932203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
4933203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
4934203134Sthompsa	struct rt2860_txwi txwi;
4935203134Sthompsa	struct mbuf *m;
4936259032Skevlo	uint16_t txwisize;
4937208019Sthompsa	uint8_t ridx;
4938203134Sthompsa
4939209917Sthompsa	if (vap->iv_bss->ni_chan == IEEE80211_CHAN_ANYC)
4940208019Sthompsa		return;
4941236439Shselasky	if (ic->ic_bsschan == IEEE80211_CHAN_ANYC)
4942236439Shselasky		return;
4943208019Sthompsa
4944218492Sbschmidt	/*
4945218492Sbschmidt	 * No need to call ieee80211_beacon_update(), run_update_beacon()
4946218492Sbschmidt	 * is taking care of apropriate calls.
4947218492Sbschmidt	 */
4948218492Sbschmidt	if (rvp->beacon_mbuf == NULL) {
4949218492Sbschmidt		rvp->beacon_mbuf = ieee80211_beacon_alloc(vap->iv_bss,
4950218492Sbschmidt		    &rvp->bo);
4951218492Sbschmidt		if (rvp->beacon_mbuf == NULL)
4952218492Sbschmidt			return;
4953218492Sbschmidt	}
4954218492Sbschmidt	m = rvp->beacon_mbuf;
4955203134Sthompsa
4956259032Skevlo	memset(&txwi, 0, sizeof(txwi));
4957203134Sthompsa	txwi.wcid = 0xff;
4958203134Sthompsa	txwi.len = htole16(m->m_pkthdr.len);
4959259032Skevlo
4960203134Sthompsa	/* send beacons at the lowest available rate */
4961208019Sthompsa	ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
4962208019Sthompsa	    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
4963208019Sthompsa	txwi.phy = htole16(rt2860_rates[ridx].mcs);
4964208019Sthompsa	if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM)
4965259032Skevlo		txwi.phy |= htole16(RT2860_PHY_OFDM);
4966203134Sthompsa	txwi.txop = RT2860_TX_TXOP_HT;
4967203134Sthompsa	txwi.flags = RT2860_TX_TS;
4968209144Sthompsa	txwi.xflags = RT2860_TX_NSEQ;
4969203134Sthompsa
4970259032Skevlo	txwisize = (sc->mac_ver == 0x5592) ?
4971259032Skevlo	    sizeof(txwi) + sizeof(uint32_t) : sizeof(txwi);
4972259032Skevlo	run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id), (uint8_t *)&txwi,
4973259032Skevlo	    txwisize);
4974259032Skevlo	run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id) + txwisize,
4975259032Skevlo	    mtod(m, uint8_t *), (m->m_pkthdr.len + 1) & ~1);
4976203134Sthompsa}
4977203134Sthompsa
4978203134Sthompsastatic void
4979203134Sthompsarun_updateprot(struct ieee80211com *ic)
4980203134Sthompsa{
4981203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
4982218492Sbschmidt	uint32_t i;
4983218492Sbschmidt
4984218492Sbschmidt	i = RUN_CMDQ_GET(&sc->cmdq_store);
4985218492Sbschmidt	DPRINTF("cmdq_store=%d\n", i);
4986218492Sbschmidt	sc->cmdq[i].func = run_updateprot_cb;
4987218492Sbschmidt	sc->cmdq[i].arg0 = ic;
4988218492Sbschmidt	ieee80211_runtask(ic, &sc->cmdq_task);
4989218492Sbschmidt}
4990218492Sbschmidt
4991218492Sbschmidtstatic void
4992218492Sbschmidtrun_updateprot_cb(void *arg)
4993218492Sbschmidt{
4994218492Sbschmidt	struct ieee80211com *ic = arg;
4995218492Sbschmidt	struct run_softc *sc = ic->ic_ifp->if_softc;
4996203134Sthompsa	uint32_t tmp;
4997203134Sthompsa
4998203134Sthompsa	tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL;
4999203134Sthompsa	/* setup protection frame rate (MCS code) */
5000203134Sthompsa	tmp |= (ic->ic_curmode == IEEE80211_MODE_11A) ?
5001270192Skevlo	    rt2860_rates[RT2860_RIDX_OFDM6].mcs | RT2860_PHY_OFDM :
5002203134Sthompsa	    rt2860_rates[RT2860_RIDX_CCK11].mcs;
5003203134Sthompsa
5004203134Sthompsa	/* CCK frames don't require protection */
5005203134Sthompsa	run_write(sc, RT2860_CCK_PROT_CFG, tmp);
5006203134Sthompsa	if (ic->ic_flags & IEEE80211_F_USEPROT) {
5007203134Sthompsa		if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
5008203134Sthompsa			tmp |= RT2860_PROT_CTRL_RTS_CTS;
5009203134Sthompsa		else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
5010203134Sthompsa			tmp |= RT2860_PROT_CTRL_CTS;
5011203134Sthompsa	}
5012203134Sthompsa	run_write(sc, RT2860_OFDM_PROT_CFG, tmp);
5013203134Sthompsa}
5014203134Sthompsa
5015203134Sthompsastatic void
5016208019Sthompsarun_usb_timeout_cb(void *arg)
5017203134Sthompsa{
5018208019Sthompsa	struct ieee80211vap *vap = arg;
5019208019Sthompsa	struct run_softc *sc = vap->iv_ic->ic_ifp->if_softc;
5020203134Sthompsa
5021208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
5022203134Sthompsa
5023203134Sthompsa	if(vap->iv_state == IEEE80211_S_RUN &&
5024203134Sthompsa	    vap->iv_opmode != IEEE80211_M_STA)
5025203134Sthompsa		run_reset_livelock(sc);
5026209917Sthompsa	else if (vap->iv_state == IEEE80211_S_SCAN) {
5027203134Sthompsa		DPRINTF("timeout caused by scan\n");
5028203134Sthompsa		/* cancel bgscan */
5029203134Sthompsa		ieee80211_cancel_scan(vap);
5030203134Sthompsa	} else
5031203134Sthompsa		DPRINTF("timeout by unknown cause\n");
5032203134Sthompsa}
5033203134Sthompsa
5034203134Sthompsastatic void
5035203134Sthompsarun_reset_livelock(struct run_softc *sc)
5036203134Sthompsa{
5037203134Sthompsa	uint32_t tmp;
5038203134Sthompsa
5039208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
5040208019Sthompsa
5041203134Sthompsa	/*
5042203134Sthompsa	 * In IBSS or HostAP modes (when the hardware sends beacons), the MAC
5043203134Sthompsa	 * can run into a livelock and start sending CTS-to-self frames like
5044203134Sthompsa	 * crazy if protection is enabled.  Reset MAC/BBP for a while
5045203134Sthompsa	 */
5046203134Sthompsa	run_read(sc, RT2860_DEBUG, &tmp);
5047208019Sthompsa	DPRINTFN(3, "debug reg %08x\n", tmp);
5048209917Sthompsa	if ((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))) {
5049203134Sthompsa		DPRINTF("CTS-to-self livelock detected\n");
5050203134Sthompsa		run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST);
5051203134Sthompsa		run_delay(sc, 1);
5052203134Sthompsa		run_write(sc, RT2860_MAC_SYS_CTRL,
5053203134Sthompsa		    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
5054203134Sthompsa	}
5055203134Sthompsa}
5056203134Sthompsa
5057203134Sthompsastatic void
5058203134Sthompsarun_update_promisc_locked(struct ifnet *ifp)
5059203134Sthompsa{
5060203134Sthompsa	struct run_softc *sc = ifp->if_softc;
5061203134Sthompsa        uint32_t tmp;
5062203134Sthompsa
5063203134Sthompsa	run_read(sc, RT2860_RX_FILTR_CFG, &tmp);
5064203134Sthompsa
5065203134Sthompsa	tmp |= RT2860_DROP_UC_NOME;
5066203134Sthompsa        if (ifp->if_flags & IFF_PROMISC)
5067203134Sthompsa		tmp &= ~RT2860_DROP_UC_NOME;
5068203134Sthompsa
5069203134Sthompsa	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
5070203134Sthompsa
5071203134Sthompsa        DPRINTF("%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ?
5072203134Sthompsa            "entering" : "leaving");
5073203134Sthompsa}
5074203134Sthompsa
5075203134Sthompsastatic void
5076203134Sthompsarun_update_promisc(struct ifnet *ifp)
5077203134Sthompsa{
5078203134Sthompsa	struct run_softc *sc = ifp->if_softc;
5079203134Sthompsa
5080203134Sthompsa	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
5081203134Sthompsa		return;
5082203134Sthompsa
5083203134Sthompsa	RUN_LOCK(sc);
5084203134Sthompsa	run_update_promisc_locked(ifp);
5085203134Sthompsa	RUN_UNLOCK(sc);
5086203134Sthompsa}
5087203134Sthompsa
5088203134Sthompsastatic void
5089203134Sthompsarun_enable_tsf_sync(struct run_softc *sc)
5090203134Sthompsa{
5091208019Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
5092203134Sthompsa	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
5093203134Sthompsa	uint32_t tmp;
5094203134Sthompsa
5095257955Skevlo	DPRINTF("rvp_id=%d ic_opmode=%d\n", RUN_VAP(vap)->rvp_id,
5096257955Skevlo	    ic->ic_opmode);
5097208019Sthompsa
5098203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
5099203134Sthompsa	tmp &= ~0x1fffff;
5100203134Sthompsa	tmp |= vap->iv_bss->ni_intval * 16;
5101203134Sthompsa	tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN;
5102203134Sthompsa
5103208019Sthompsa	if (ic->ic_opmode == IEEE80211_M_STA) {
5104203134Sthompsa		/*
5105203134Sthompsa		 * Local TSF is always updated with remote TSF on beacon
5106203134Sthompsa		 * reception.
5107203134Sthompsa		 */
5108203134Sthompsa		tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT;
5109208019Sthompsa	} else if (ic->ic_opmode == IEEE80211_M_IBSS) {
5110203134Sthompsa	        tmp |= RT2860_BCN_TX_EN;
5111203134Sthompsa	        /*
5112203134Sthompsa	         * Local TSF is updated with remote TSF on beacon reception
5113203134Sthompsa	         * only if the remote TSF is greater than local TSF.
5114203134Sthompsa	         */
5115203134Sthompsa	        tmp |= 2 << RT2860_TSF_SYNC_MODE_SHIFT;
5116208019Sthompsa	} else if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
5117208019Sthompsa		    ic->ic_opmode == IEEE80211_M_MBSS) {
5118203134Sthompsa	        tmp |= RT2860_BCN_TX_EN;
5119203134Sthompsa	        /* SYNC with nobody */
5120203134Sthompsa	        tmp |= 3 << RT2860_TSF_SYNC_MODE_SHIFT;
5121208019Sthompsa	} else {
5122203134Sthompsa		DPRINTF("Enabling TSF failed. undefined opmode\n");
5123208019Sthompsa		return;
5124208019Sthompsa	}
5125203134Sthompsa
5126203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
5127203134Sthompsa}
5128203134Sthompsa
5129203134Sthompsastatic void
5130203134Sthompsarun_enable_mrr(struct run_softc *sc)
5131203134Sthompsa{
5132259546Skevlo#define	CCK(mcs)	(mcs)
5133259546Skevlo#define	OFDM(mcs)	(1 << 3 | (mcs))
5134203134Sthompsa	run_write(sc, RT2860_LG_FBK_CFG0,
5135203134Sthompsa	    OFDM(6) << 28 |	/* 54->48 */
5136203134Sthompsa	    OFDM(5) << 24 |	/* 48->36 */
5137203134Sthompsa	    OFDM(4) << 20 |	/* 36->24 */
5138203134Sthompsa	    OFDM(3) << 16 |	/* 24->18 */
5139203134Sthompsa	    OFDM(2) << 12 |	/* 18->12 */
5140203134Sthompsa	    OFDM(1) <<  8 |	/* 12-> 9 */
5141203134Sthompsa	    OFDM(0) <<  4 |	/*  9-> 6 */
5142203134Sthompsa	    OFDM(0));		/*  6-> 6 */
5143203134Sthompsa
5144203134Sthompsa	run_write(sc, RT2860_LG_FBK_CFG1,
5145203134Sthompsa	    CCK(2) << 12 |	/* 11->5.5 */
5146203134Sthompsa	    CCK(1) <<  8 |	/* 5.5-> 2 */
5147203134Sthompsa	    CCK(0) <<  4 |	/*   2-> 1 */
5148203134Sthompsa	    CCK(0));		/*   1-> 1 */
5149203134Sthompsa#undef OFDM
5150203134Sthompsa#undef CCK
5151203134Sthompsa}
5152203134Sthompsa
5153203134Sthompsastatic void
5154203134Sthompsarun_set_txpreamble(struct run_softc *sc)
5155203134Sthompsa{
5156203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
5157203134Sthompsa	uint32_t tmp;
5158203134Sthompsa
5159203134Sthompsa	run_read(sc, RT2860_AUTO_RSP_CFG, &tmp);
5160203134Sthompsa	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
5161203134Sthompsa		tmp |= RT2860_CCK_SHORT_EN;
5162203134Sthompsa	else
5163203134Sthompsa		tmp &= ~RT2860_CCK_SHORT_EN;
5164203134Sthompsa	run_write(sc, RT2860_AUTO_RSP_CFG, tmp);
5165203134Sthompsa}
5166203134Sthompsa
5167203134Sthompsastatic void
5168203134Sthompsarun_set_basicrates(struct run_softc *sc)
5169203134Sthompsa{
5170203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
5171203134Sthompsa
5172203134Sthompsa	/* set basic rates mask */
5173203134Sthompsa	if (ic->ic_curmode == IEEE80211_MODE_11B)
5174203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x003);
5175203134Sthompsa	else if (ic->ic_curmode == IEEE80211_MODE_11A)
5176203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x150);
5177203134Sthompsa	else	/* 11g */
5178203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x15f);
5179203134Sthompsa}
5180203134Sthompsa
5181203134Sthompsastatic void
5182203134Sthompsarun_set_leds(struct run_softc *sc, uint16_t which)
5183203134Sthompsa{
5184203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LEDS,
5185203134Sthompsa	    which | (sc->leds & 0x7f));
5186203134Sthompsa}
5187203134Sthompsa
5188203134Sthompsastatic void
5189203134Sthompsarun_set_bssid(struct run_softc *sc, const uint8_t *bssid)
5190203134Sthompsa{
5191203134Sthompsa	run_write(sc, RT2860_MAC_BSSID_DW0,
5192203134Sthompsa	    bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24);
5193203134Sthompsa	run_write(sc, RT2860_MAC_BSSID_DW1,
5194203134Sthompsa	    bssid[4] | bssid[5] << 8);
5195203134Sthompsa}
5196203134Sthompsa
5197203134Sthompsastatic void
5198203134Sthompsarun_set_macaddr(struct run_softc *sc, const uint8_t *addr)
5199203134Sthompsa{
5200203134Sthompsa	run_write(sc, RT2860_MAC_ADDR_DW0,
5201203134Sthompsa	    addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24);
5202203134Sthompsa	run_write(sc, RT2860_MAC_ADDR_DW1,
5203203134Sthompsa	    addr[4] | addr[5] << 8 | 0xff << 16);
5204203134Sthompsa}
5205203134Sthompsa
5206203134Sthompsastatic void
5207203134Sthompsarun_updateslot(struct ifnet *ifp)
5208203134Sthompsa{
5209203134Sthompsa	struct run_softc *sc = ifp->if_softc;
5210203134Sthompsa	struct ieee80211com *ic = ifp->if_l2com;
5211218492Sbschmidt	uint32_t i;
5212218492Sbschmidt
5213218492Sbschmidt	i = RUN_CMDQ_GET(&sc->cmdq_store);
5214218492Sbschmidt	DPRINTF("cmdq_store=%d\n", i);
5215218492Sbschmidt	sc->cmdq[i].func = run_updateslot_cb;
5216218492Sbschmidt	sc->cmdq[i].arg0 = ifp;
5217218492Sbschmidt	ieee80211_runtask(ic, &sc->cmdq_task);
5218218492Sbschmidt
5219218492Sbschmidt	return;
5220218492Sbschmidt}
5221218492Sbschmidt
5222218492Sbschmidt/* ARGSUSED */
5223218492Sbschmidtstatic void
5224218492Sbschmidtrun_updateslot_cb(void *arg)
5225218492Sbschmidt{
5226218492Sbschmidt	struct ifnet *ifp = arg;
5227218492Sbschmidt	struct run_softc *sc = ifp->if_softc;
5228218492Sbschmidt	struct ieee80211com *ic = ifp->if_l2com;
5229203134Sthompsa	uint32_t tmp;
5230203134Sthompsa
5231203134Sthompsa	run_read(sc, RT2860_BKOFF_SLOT_CFG, &tmp);
5232203134Sthompsa	tmp &= ~0xff;
5233203134Sthompsa	tmp |= (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20;
5234203134Sthompsa	run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp);
5235203134Sthompsa}
5236203134Sthompsa
5237208019Sthompsastatic void
5238208019Sthompsarun_update_mcast(struct ifnet *ifp)
5239208019Sthompsa{
5240208019Sthompsa	/* h/w filter supports getting everything or nothing */
5241208019Sthompsa	ifp->if_flags |= IFF_ALLMULTI;
5242208019Sthompsa}
5243208019Sthompsa
5244203134Sthompsastatic int8_t
5245203134Sthompsarun_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain)
5246203134Sthompsa{
5247203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
5248203134Sthompsa	struct ieee80211_channel *c = ic->ic_curchan;
5249203134Sthompsa	int delta;
5250203134Sthompsa
5251203134Sthompsa	if (IEEE80211_IS_CHAN_5GHZ(c)) {
5252257429Shselasky		u_int chan = ieee80211_chan2ieee(ic, c);
5253203134Sthompsa		delta = sc->rssi_5ghz[rxchain];
5254203134Sthompsa
5255203134Sthompsa		/* determine channel group */
5256203134Sthompsa		if (chan <= 64)
5257203134Sthompsa			delta -= sc->lna[1];
5258203134Sthompsa		else if (chan <= 128)
5259203134Sthompsa			delta -= sc->lna[2];
5260203134Sthompsa		else
5261203134Sthompsa			delta -= sc->lna[3];
5262203134Sthompsa	} else
5263203134Sthompsa		delta = sc->rssi_2ghz[rxchain] - sc->lna[0];
5264203134Sthompsa
5265209917Sthompsa	return (-12 - delta - rssi);
5266203134Sthompsa}
5267203134Sthompsa
5268257955Skevlostatic void
5269257955Skevlorun_rt5390_bbp_init(struct run_softc *sc)
5270257955Skevlo{
5271257955Skevlo	int i;
5272259032Skevlo	uint8_t bbp;
5273257955Skevlo
5274259032Skevlo	/* Apply maximum likelihood detection for 2 stream case. */
5275259032Skevlo	run_bbp_read(sc, 105, &bbp);
5276259032Skevlo	if (sc->nrxchains > 1)
5277259032Skevlo		run_bbp_write(sc, 105, bbp | RT5390_MLD);
5278259032Skevlo
5279257955Skevlo	/* Avoid data lost and CRC error. */
5280259032Skevlo	run_bbp_read(sc, 4, &bbp);
5281259031Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5282257955Skevlo
5283259032Skevlo	if (sc->mac_ver == 0x5592) {
5284259032Skevlo		for (i = 0; i < nitems(rt5592_def_bbp); i++) {
5285259032Skevlo			run_bbp_write(sc, rt5592_def_bbp[i].reg,
5286259032Skevlo			    rt5592_def_bbp[i].val);
5287259032Skevlo		}
5288259032Skevlo		for (i = 0; i < nitems(rt5592_bbp_r196); i++) {
5289259032Skevlo			run_bbp_write(sc, 195, i + 0x80);
5290259032Skevlo			run_bbp_write(sc, 196, rt5592_bbp_r196[i]);
5291259032Skevlo		}
5292259032Skevlo	} else {
5293259032Skevlo		for (i = 0; i < nitems(rt5390_def_bbp); i++) {
5294259032Skevlo			run_bbp_write(sc, rt5390_def_bbp[i].reg,
5295259032Skevlo			    rt5390_def_bbp[i].val);
5296259032Skevlo		}
5297257955Skevlo	}
5298257955Skevlo	if (sc->mac_ver == 0x5392) {
5299257955Skevlo		run_bbp_write(sc, 88, 0x90);
5300257955Skevlo		run_bbp_write(sc, 95, 0x9a);
5301257955Skevlo		run_bbp_write(sc, 98, 0x12);
5302257955Skevlo		run_bbp_write(sc, 106, 0x12);
5303257955Skevlo		run_bbp_write(sc, 134, 0xd0);
5304257955Skevlo		run_bbp_write(sc, 135, 0xf6);
5305257955Skevlo		run_bbp_write(sc, 148, 0x84);
5306257955Skevlo	}
5307257955Skevlo
5308259032Skevlo	run_bbp_read(sc, 152, &bbp);
5309259032Skevlo	run_bbp_write(sc, 152, bbp | 0x80);
5310259032Skevlo
5311259032Skevlo	/* Fix BBP254 for RT5592C. */
5312259032Skevlo	if (sc->mac_ver == 0x5592 && sc->mac_rev >= 0x0221) {
5313259032Skevlo		run_bbp_read(sc, 254, &bbp);
5314259032Skevlo		run_bbp_write(sc, 254, bbp | 0x80);
5315259032Skevlo	}
5316259032Skevlo
5317257955Skevlo	/* Disable hardware antenna diversity. */
5318257955Skevlo	if (sc->mac_ver == 0x5390)
5319257955Skevlo		run_bbp_write(sc, 154, 0);
5320259032Skevlo
5321259032Skevlo	/* Initialize Rx CCK/OFDM frequency offset report. */
5322259032Skevlo	run_bbp_write(sc, 142, 1);
5323259032Skevlo	run_bbp_write(sc, 143, 57);
5324257955Skevlo}
5325257955Skevlo
5326203134Sthompsastatic int
5327203134Sthompsarun_bbp_init(struct run_softc *sc)
5328203134Sthompsa{
5329203134Sthompsa	int i, error, ntries;
5330203134Sthompsa	uint8_t bbp0;
5331203134Sthompsa
5332203134Sthompsa	/* wait for BBP to wake up */
5333203134Sthompsa	for (ntries = 0; ntries < 20; ntries++) {
5334203134Sthompsa		if ((error = run_bbp_read(sc, 0, &bbp0)) != 0)
5335203134Sthompsa			return error;
5336203134Sthompsa		if (bbp0 != 0 && bbp0 != 0xff)
5337203134Sthompsa			break;
5338203134Sthompsa	}
5339203134Sthompsa	if (ntries == 20)
5340209917Sthompsa		return (ETIMEDOUT);
5341203134Sthompsa
5342203134Sthompsa	/* initialize BBP registers to default values */
5343257955Skevlo	if (sc->mac_ver >= 0x5390)
5344257955Skevlo		run_rt5390_bbp_init(sc);
5345257955Skevlo	else {
5346257955Skevlo		for (i = 0; i < nitems(rt2860_def_bbp); i++) {
5347257955Skevlo			run_bbp_write(sc, rt2860_def_bbp[i].reg,
5348257955Skevlo			    rt2860_def_bbp[i].val);
5349257955Skevlo		}
5350203134Sthompsa	}
5351203134Sthompsa
5352260219Skevlo	if (sc->mac_ver == 0x3593) {
5353260219Skevlo		run_bbp_write(sc, 79, 0x13);
5354260219Skevlo		run_bbp_write(sc, 80, 0x05);
5355260219Skevlo		run_bbp_write(sc, 81, 0x33);
5356260219Skevlo		run_bbp_write(sc, 86, 0x46);
5357260219Skevlo		run_bbp_write(sc, 137, 0x0f);
5358260219Skevlo	}
5359260219Skevlo
5360203134Sthompsa	/* fix BBP84 for RT2860E */
5361205042Sthompsa	if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0101)
5362205042Sthompsa		run_bbp_write(sc, 84, 0x19);
5363203134Sthompsa
5364260219Skevlo	if (sc->mac_ver >= 0x3070 && (sc->mac_ver != 0x3593 &&
5365260219Skevlo	    sc->mac_ver != 0x5592)) {
5366203134Sthompsa		run_bbp_write(sc, 79, 0x13);
5367203134Sthompsa		run_bbp_write(sc, 80, 0x05);
5368203134Sthompsa		run_bbp_write(sc, 81, 0x33);
5369205042Sthompsa	} else if (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) {
5370203134Sthompsa		run_bbp_write(sc, 69, 0x16);
5371203134Sthompsa		run_bbp_write(sc, 73, 0x12);
5372203134Sthompsa	}
5373209917Sthompsa	return (0);
5374203134Sthompsa}
5375203134Sthompsa
5376203134Sthompsastatic int
5377203134Sthompsarun_rt3070_rf_init(struct run_softc *sc)
5378203134Sthompsa{
5379203134Sthompsa	uint32_t tmp;
5380256722Skevlo	uint8_t bbp4, mingain, rf, target;
5381203134Sthompsa	int i;
5382203134Sthompsa
5383203134Sthompsa	run_rt3070_rf_read(sc, 30, &rf);
5384203134Sthompsa	/* toggle RF R30 bit 7 */
5385203134Sthompsa	run_rt3070_rf_write(sc, 30, rf | 0x80);
5386203134Sthompsa	run_delay(sc, 10);
5387203134Sthompsa	run_rt3070_rf_write(sc, 30, rf & ~0x80);
5388203134Sthompsa
5389203134Sthompsa	/* initialize RF registers to default value */
5390205042Sthompsa	if (sc->mac_ver == 0x3572) {
5391257955Skevlo		for (i = 0; i < nitems(rt3572_def_rf); i++) {
5392205042Sthompsa			run_rt3070_rf_write(sc, rt3572_def_rf[i].reg,
5393205042Sthompsa			    rt3572_def_rf[i].val);
5394205042Sthompsa		}
5395205042Sthompsa	} else {
5396257955Skevlo		for (i = 0; i < nitems(rt3070_def_rf); i++) {
5397205042Sthompsa			run_rt3070_rf_write(sc, rt3070_def_rf[i].reg,
5398205042Sthompsa			    rt3070_def_rf[i].val);
5399205042Sthompsa		}
5400203134Sthompsa	}
5401205042Sthompsa
5402256721Skevlo	if (sc->mac_ver == 0x3070 && sc->mac_rev < 0x0201) {
5403256721Skevlo		/*
5404256721Skevlo		 * Change voltage from 1.2V to 1.35V for RT3070.
5405256721Skevlo		 * The DAC issue (RT3070_LDO_CFG0) has been fixed
5406256721Skevlo		 * in RT3070(F).
5407256721Skevlo		 */
5408203134Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5409203134Sthompsa		tmp = (tmp & ~0x0f000000) | 0x0d000000;
5410203134Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5411203134Sthompsa
5412205042Sthompsa	} else if (sc->mac_ver == 0x3071) {
5413203134Sthompsa		run_rt3070_rf_read(sc, 6, &rf);
5414203134Sthompsa		run_rt3070_rf_write(sc, 6, rf | 0x40);
5415203134Sthompsa		run_rt3070_rf_write(sc, 31, 0x14);
5416203134Sthompsa
5417203134Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5418203134Sthompsa		tmp &= ~0x1f000000;
5419205042Sthompsa		if (sc->mac_rev < 0x0211)
5420205042Sthompsa			tmp |= 0x0d000000;	/* 1.3V */
5421203134Sthompsa		else
5422205042Sthompsa			tmp |= 0x01000000;	/* 1.2V */
5423203134Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5424203134Sthompsa
5425203134Sthompsa		/* patch LNA_PE_G1 */
5426203134Sthompsa		run_read(sc, RT3070_GPIO_SWITCH, &tmp);
5427203134Sthompsa		run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20);
5428208019Sthompsa
5429209917Sthompsa	} else if (sc->mac_ver == 0x3572) {
5430205042Sthompsa		run_rt3070_rf_read(sc, 6, &rf);
5431205042Sthompsa		run_rt3070_rf_write(sc, 6, rf | 0x40);
5432205042Sthompsa
5433208019Sthompsa		/* increase voltage from 1.2V to 1.35V */
5434208019Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5435208019Sthompsa		tmp = (tmp & ~0x1f000000) | 0x0d000000;
5436208019Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5437203134Sthompsa
5438209917Sthompsa		if (sc->mac_rev < 0x0211 || !sc->patch_dac) {
5439203134Sthompsa			run_delay(sc, 1);	/* wait for 1msec */
5440205042Sthompsa			/* decrease voltage back to 1.2V */
5441203134Sthompsa			tmp = (tmp & ~0x1f000000) | 0x01000000;
5442203134Sthompsa			run_write(sc, RT3070_LDO_CFG0, tmp);
5443203134Sthompsa		}
5444203134Sthompsa	}
5445203134Sthompsa
5446203134Sthompsa	/* select 20MHz bandwidth */
5447203134Sthompsa	run_rt3070_rf_read(sc, 31, &rf);
5448203134Sthompsa	run_rt3070_rf_write(sc, 31, rf & ~0x20);
5449203134Sthompsa
5450203134Sthompsa	/* calibrate filter for 20MHz bandwidth */
5451203134Sthompsa	sc->rf24_20mhz = 0x1f;	/* default value */
5452205042Sthompsa	target = (sc->mac_ver < 0x3071) ? 0x16 : 0x13;
5453205042Sthompsa	run_rt3070_filter_calib(sc, 0x07, target, &sc->rf24_20mhz);
5454203134Sthompsa
5455203134Sthompsa	/* select 40MHz bandwidth */
5456203134Sthompsa	run_bbp_read(sc, 4, &bbp4);
5457256721Skevlo	run_bbp_write(sc, 4, (bbp4 & ~0x18) | 0x10);
5458205042Sthompsa	run_rt3070_rf_read(sc, 31, &rf);
5459205042Sthompsa	run_rt3070_rf_write(sc, 31, rf | 0x20);
5460203134Sthompsa
5461203134Sthompsa	/* calibrate filter for 40MHz bandwidth */
5462203134Sthompsa	sc->rf24_40mhz = 0x2f;	/* default value */
5463205042Sthompsa	target = (sc->mac_ver < 0x3071) ? 0x19 : 0x15;
5464205042Sthompsa	run_rt3070_filter_calib(sc, 0x27, target, &sc->rf24_40mhz);
5465203134Sthompsa
5466203134Sthompsa	/* go back to 20MHz bandwidth */
5467203134Sthompsa	run_bbp_read(sc, 4, &bbp4);
5468203134Sthompsa	run_bbp_write(sc, 4, bbp4 & ~0x18);
5469203134Sthompsa
5470205042Sthompsa	if (sc->mac_ver == 0x3572) {
5471205042Sthompsa		/* save default BBP registers 25 and 26 values */
5472205042Sthompsa		run_bbp_read(sc, 25, &sc->bbp25);
5473205042Sthompsa		run_bbp_read(sc, 26, &sc->bbp26);
5474256721Skevlo	} else if (sc->mac_rev < 0x0201 || sc->mac_rev < 0x0211)
5475203134Sthompsa		run_rt3070_rf_write(sc, 27, 0x03);
5476203134Sthompsa
5477203134Sthompsa	run_read(sc, RT3070_OPT_14, &tmp);
5478203134Sthompsa	run_write(sc, RT3070_OPT_14, tmp | 1);
5479203134Sthompsa
5480205042Sthompsa	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
5481205042Sthompsa		run_rt3070_rf_read(sc, 17, &rf);
5482205042Sthompsa		rf &= ~RT3070_TX_LO1;
5483205042Sthompsa		if ((sc->mac_ver == 0x3070 ||
5484205042Sthompsa		     (sc->mac_ver == 0x3071 && sc->mac_rev >= 0x0211)) &&
5485205042Sthompsa		    !sc->ext_2ghz_lna)
5486205042Sthompsa			rf |= 0x20;	/* fix for long range Rx issue */
5487256722Skevlo		mingain = (sc->mac_ver == 0x3070) ? 1 : 2;
5488256722Skevlo		if (sc->txmixgain_2ghz >= mingain)
5489205042Sthompsa			rf = (rf & ~0x7) | sc->txmixgain_2ghz;
5490205042Sthompsa		run_rt3070_rf_write(sc, 17, rf);
5491205042Sthompsa	}
5492205042Sthompsa
5493270643Skevlo	if (sc->mac_ver == 0x3071) {
5494203134Sthompsa		run_rt3070_rf_read(sc, 1, &rf);
5495203134Sthompsa		rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD);
5496203134Sthompsa		rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD;
5497203134Sthompsa		run_rt3070_rf_write(sc, 1, rf);
5498203134Sthompsa
5499203134Sthompsa		run_rt3070_rf_read(sc, 15, &rf);
5500203134Sthompsa		run_rt3070_rf_write(sc, 15, rf & ~RT3070_TX_LO2);
5501203134Sthompsa
5502203134Sthompsa		run_rt3070_rf_read(sc, 20, &rf);
5503203134Sthompsa		run_rt3070_rf_write(sc, 20, rf & ~RT3070_RX_LO1);
5504203134Sthompsa
5505203134Sthompsa		run_rt3070_rf_read(sc, 21, &rf);
5506203134Sthompsa		run_rt3070_rf_write(sc, 21, rf & ~RT3070_RX_LO2);
5507205042Sthompsa	}
5508203134Sthompsa
5509205042Sthompsa	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
5510205042Sthompsa		/* fix Tx to Rx IQ glitch by raising RF voltage */
5511203134Sthompsa		run_rt3070_rf_read(sc, 27, &rf);
5512203134Sthompsa		rf &= ~0x77;
5513205042Sthompsa		if (sc->mac_rev < 0x0211)
5514203134Sthompsa			rf |= 0x03;
5515203134Sthompsa		run_rt3070_rf_write(sc, 27, rf);
5516203134Sthompsa	}
5517209917Sthompsa	return (0);
5518203134Sthompsa}
5519203134Sthompsa
5520257955Skevlostatic void
5521260219Skevlorun_rt3593_rf_init(struct run_softc *sc)
5522260219Skevlo{
5523260219Skevlo	uint32_t tmp;
5524260219Skevlo	uint8_t rf;
5525260219Skevlo	int i;
5526260219Skevlo
5527260219Skevlo	/* Disable the GPIO bits 4 and 7 for LNA PE control. */
5528260219Skevlo	run_read(sc, RT3070_GPIO_SWITCH, &tmp);
5529260219Skevlo	tmp &= ~(1 << 4 | 1 << 7);
5530260219Skevlo	run_write(sc, RT3070_GPIO_SWITCH, tmp);
5531260219Skevlo
5532260219Skevlo	/* Initialize RF registers to default value. */
5533260219Skevlo	for (i = 0; i < nitems(rt3593_def_rf); i++) {
5534260219Skevlo		run_rt3070_rf_write(sc, rt3593_def_rf[i].reg,
5535260219Skevlo		    rt3593_def_rf[i].val);
5536260219Skevlo	}
5537260219Skevlo
5538260219Skevlo	/* Toggle RF R2 to initiate calibration. */
5539260219Skevlo	run_rt3070_rf_write(sc, 2, RT5390_RESCAL);
5540260219Skevlo
5541260219Skevlo	/* Initialize RF frequency offset. */
5542260219Skevlo	run_adjust_freq_offset(sc);
5543260219Skevlo
5544260219Skevlo	run_rt3070_rf_read(sc, 18, &rf);
5545260219Skevlo	run_rt3070_rf_write(sc, 18, rf | RT3593_AUTOTUNE_BYPASS);
5546260219Skevlo
5547260219Skevlo	/*
5548260219Skevlo	 * Increase voltage from 1.2V to 1.35V, wait for 1 msec to
5549260219Skevlo	 * decrease voltage back to 1.2V.
5550260219Skevlo	 */
5551260219Skevlo	run_read(sc, RT3070_LDO_CFG0, &tmp);
5552260219Skevlo	tmp = (tmp & ~0x1f000000) | 0x0d000000;
5553260219Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
5554260219Skevlo	run_delay(sc, 1);
5555260219Skevlo	tmp = (tmp & ~0x1f000000) | 0x01000000;
5556260219Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
5557260219Skevlo
5558260219Skevlo	sc->rf24_20mhz = 0x1f;
5559260219Skevlo	sc->rf24_40mhz = 0x2f;
5560260219Skevlo
5561260219Skevlo	/* Save default BBP registers 25 and 26 values. */
5562260219Skevlo	run_bbp_read(sc, 25, &sc->bbp25);
5563260219Skevlo	run_bbp_read(sc, 26, &sc->bbp26);
5564260219Skevlo
5565260219Skevlo	run_read(sc, RT3070_OPT_14, &tmp);
5566260219Skevlo	run_write(sc, RT3070_OPT_14, tmp | 1);
5567260219Skevlo}
5568260219Skevlo
5569260219Skevlostatic void
5570257955Skevlorun_rt5390_rf_init(struct run_softc *sc)
5571257955Skevlo{
5572257955Skevlo	uint32_t tmp;
5573257955Skevlo	uint8_t rf;
5574257955Skevlo	int i;
5575257955Skevlo
5576259030Skevlo	/* Toggle RF R2 to initiate calibration. */
5577259030Skevlo	if (sc->mac_ver == 0x5390) {
5578257955Skevlo		run_rt3070_rf_read(sc, 2, &rf);
5579259031Skevlo		run_rt3070_rf_write(sc, 2, rf | RT5390_RESCAL);
5580257955Skevlo		run_delay(sc, 10);
5581259031Skevlo		run_rt3070_rf_write(sc, 2, rf & ~RT5390_RESCAL);
5582259030Skevlo	} else {
5583259031Skevlo		run_rt3070_rf_write(sc, 2, RT5390_RESCAL);
5584259030Skevlo		run_delay(sc, 10);
5585257955Skevlo	}
5586257955Skevlo
5587257955Skevlo	/* Initialize RF registers to default value. */
5588259032Skevlo	if (sc->mac_ver == 0x5592) {
5589259032Skevlo		for (i = 0; i < nitems(rt5592_def_rf); i++) {
5590259032Skevlo			run_rt3070_rf_write(sc, rt5592_def_rf[i].reg,
5591259032Skevlo			    rt5592_def_rf[i].val);
5592259032Skevlo		}
5593259032Skevlo		/* Initialize RF frequency offset. */
5594259032Skevlo		run_adjust_freq_offset(sc);
5595259032Skevlo	} else if (sc->mac_ver == 0x5392) {
5596257955Skevlo		for (i = 0; i < nitems(rt5392_def_rf); i++) {
5597257955Skevlo			run_rt3070_rf_write(sc, rt5392_def_rf[i].reg,
5598257955Skevlo			    rt5392_def_rf[i].val);
5599257955Skevlo		}
5600257955Skevlo		if (sc->mac_rev >= 0x0223) {
5601257955Skevlo			run_rt3070_rf_write(sc, 23, 0x0f);
5602257955Skevlo			run_rt3070_rf_write(sc, 24, 0x3e);
5603257955Skevlo			run_rt3070_rf_write(sc, 51, 0x32);
5604257955Skevlo			run_rt3070_rf_write(sc, 53, 0x22);
5605257955Skevlo			run_rt3070_rf_write(sc, 56, 0xc1);
5606257955Skevlo			run_rt3070_rf_write(sc, 59, 0x0f);
5607257955Skevlo		}
5608257955Skevlo	} else {
5609257955Skevlo		for (i = 0; i < nitems(rt5390_def_rf); i++) {
5610257955Skevlo			run_rt3070_rf_write(sc, rt5390_def_rf[i].reg,
5611257955Skevlo			    rt5390_def_rf[i].val);
5612257955Skevlo		}
5613257955Skevlo		if (sc->mac_rev >= 0x0502) {
5614257955Skevlo			run_rt3070_rf_write(sc, 6, 0xe0);
5615257955Skevlo			run_rt3070_rf_write(sc, 25, 0x80);
5616257955Skevlo			run_rt3070_rf_write(sc, 46, 0x73);
5617257955Skevlo			run_rt3070_rf_write(sc, 53, 0x00);
5618257955Skevlo			run_rt3070_rf_write(sc, 56, 0x42);
5619257955Skevlo			run_rt3070_rf_write(sc, 61, 0xd1);
5620257955Skevlo		}
5621257955Skevlo	}
5622257955Skevlo
5623257955Skevlo	sc->rf24_20mhz = 0x1f;	/* default value */
5624259032Skevlo	sc->rf24_40mhz = (sc->mac_ver == 0x5592) ? 0 : 0x2f;
5625257955Skevlo
5626257955Skevlo	if (sc->mac_rev < 0x0211)
5627257955Skevlo		run_rt3070_rf_write(sc, 27, 0x3);
5628257955Skevlo
5629257955Skevlo	run_read(sc, RT3070_OPT_14, &tmp);
5630257955Skevlo	run_write(sc, RT3070_OPT_14, tmp | 1);
5631257955Skevlo}
5632257955Skevlo
5633203134Sthompsastatic int
5634203134Sthompsarun_rt3070_filter_calib(struct run_softc *sc, uint8_t init, uint8_t target,
5635203134Sthompsa    uint8_t *val)
5636203134Sthompsa{
5637203134Sthompsa	uint8_t rf22, rf24;
5638203134Sthompsa	uint8_t bbp55_pb, bbp55_sb, delta;
5639203134Sthompsa	int ntries;
5640203134Sthompsa
5641203134Sthompsa	/* program filter */
5642205042Sthompsa	run_rt3070_rf_read(sc, 24, &rf24);
5643205042Sthompsa	rf24 = (rf24 & 0xc0) | init;	/* initial filter value */
5644203134Sthompsa	run_rt3070_rf_write(sc, 24, rf24);
5645203134Sthompsa
5646203134Sthompsa	/* enable baseband loopback mode */
5647203134Sthompsa	run_rt3070_rf_read(sc, 22, &rf22);
5648203134Sthompsa	run_rt3070_rf_write(sc, 22, rf22 | 0x01);
5649203134Sthompsa
5650203134Sthompsa	/* set power and frequency of passband test tone */
5651203134Sthompsa	run_bbp_write(sc, 24, 0x00);
5652203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5653203134Sthompsa		/* transmit test tone */
5654203134Sthompsa		run_bbp_write(sc, 25, 0x90);
5655203134Sthompsa		run_delay(sc, 10);
5656203134Sthompsa		/* read received power */
5657203134Sthompsa		run_bbp_read(sc, 55, &bbp55_pb);
5658203134Sthompsa		if (bbp55_pb != 0)
5659203134Sthompsa			break;
5660203134Sthompsa	}
5661203134Sthompsa	if (ntries == 100)
5662257955Skevlo		return (ETIMEDOUT);
5663203134Sthompsa
5664203134Sthompsa	/* set power and frequency of stopband test tone */
5665203134Sthompsa	run_bbp_write(sc, 24, 0x06);
5666203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5667203134Sthompsa		/* transmit test tone */
5668203134Sthompsa		run_bbp_write(sc, 25, 0x90);
5669203134Sthompsa		run_delay(sc, 10);
5670203134Sthompsa		/* read received power */
5671203134Sthompsa		run_bbp_read(sc, 55, &bbp55_sb);
5672203134Sthompsa
5673203134Sthompsa		delta = bbp55_pb - bbp55_sb;
5674203134Sthompsa		if (delta > target)
5675203134Sthompsa			break;
5676203134Sthompsa
5677203134Sthompsa		/* reprogram filter */
5678203134Sthompsa		rf24++;
5679203134Sthompsa		run_rt3070_rf_write(sc, 24, rf24);
5680203134Sthompsa	}
5681203134Sthompsa	if (ntries < 100) {
5682203134Sthompsa		if (rf24 != init)
5683203134Sthompsa			rf24--;	/* backtrack */
5684203134Sthompsa		*val = rf24;
5685203134Sthompsa		run_rt3070_rf_write(sc, 24, rf24);
5686203134Sthompsa	}
5687203134Sthompsa
5688203134Sthompsa	/* restore initial state */
5689203134Sthompsa	run_bbp_write(sc, 24, 0x00);
5690203134Sthompsa
5691203134Sthompsa	/* disable baseband loopback mode */
5692203134Sthompsa	run_rt3070_rf_read(sc, 22, &rf22);
5693203134Sthompsa	run_rt3070_rf_write(sc, 22, rf22 & ~0x01);
5694203134Sthompsa
5695209917Sthompsa	return (0);
5696203134Sthompsa}
5697203134Sthompsa
5698205042Sthompsastatic void
5699205042Sthompsarun_rt3070_rf_setup(struct run_softc *sc)
5700205042Sthompsa{
5701205042Sthompsa	uint8_t bbp, rf;
5702205042Sthompsa	int i;
5703205042Sthompsa
5704260219Skevlo	if (sc->mac_ver == 0x3572) {
5705205042Sthompsa		/* enable DC filter */
5706205042Sthompsa		if (sc->mac_rev >= 0x0201)
5707205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5708205042Sthompsa
5709205042Sthompsa		run_bbp_read(sc, 138, &bbp);
5710205042Sthompsa		if (sc->ntxchains == 1)
5711205042Sthompsa			bbp |= 0x20;	/* turn off DAC1 */
5712205042Sthompsa		if (sc->nrxchains == 1)
5713205042Sthompsa			bbp &= ~0x02;	/* turn off ADC1 */
5714205042Sthompsa		run_bbp_write(sc, 138, bbp);
5715205042Sthompsa
5716205042Sthompsa		if (sc->mac_rev >= 0x0211) {
5717205042Sthompsa			/* improve power consumption */
5718205042Sthompsa			run_bbp_read(sc, 31, &bbp);
5719205042Sthompsa			run_bbp_write(sc, 31, bbp & ~0x03);
5720205042Sthompsa		}
5721205042Sthompsa
5722205042Sthompsa		run_rt3070_rf_read(sc, 16, &rf);
5723205042Sthompsa		rf = (rf & ~0x07) | sc->txmixgain_2ghz;
5724205042Sthompsa		run_rt3070_rf_write(sc, 16, rf);
5725205042Sthompsa
5726205042Sthompsa	} else if (sc->mac_ver == 0x3071) {
5727257409Skevlo		if (sc->mac_rev >= 0x0211) {
5728257409Skevlo			/* enable DC filter */
5729205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5730205042Sthompsa
5731257409Skevlo			/* improve power consumption */
5732257409Skevlo			run_bbp_read(sc, 31, &bbp);
5733257409Skevlo			run_bbp_write(sc, 31, bbp & ~0x03);
5734257409Skevlo		}
5735257409Skevlo
5736205042Sthompsa		run_bbp_read(sc, 138, &bbp);
5737205042Sthompsa		if (sc->ntxchains == 1)
5738205042Sthompsa			bbp |= 0x20;	/* turn off DAC1 */
5739205042Sthompsa		if (sc->nrxchains == 1)
5740205042Sthompsa			bbp &= ~0x02;	/* turn off ADC1 */
5741205042Sthompsa		run_bbp_write(sc, 138, bbp);
5742205042Sthompsa
5743205042Sthompsa		run_write(sc, RT2860_TX_SW_CFG1, 0);
5744205042Sthompsa		if (sc->mac_rev < 0x0211) {
5745205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2,
5746205042Sthompsa			    sc->patch_dac ? 0x2c : 0x0f);
5747205042Sthompsa		} else
5748205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0);
5749205042Sthompsa
5750205042Sthompsa	} else if (sc->mac_ver == 0x3070) {
5751205042Sthompsa		if (sc->mac_rev >= 0x0201) {
5752205042Sthompsa			/* enable DC filter */
5753205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5754205042Sthompsa
5755205042Sthompsa			/* improve power consumption */
5756205042Sthompsa			run_bbp_read(sc, 31, &bbp);
5757205042Sthompsa			run_bbp_write(sc, 31, bbp & ~0x03);
5758205042Sthompsa		}
5759205042Sthompsa
5760256955Skevlo		if (sc->mac_rev < 0x0201) {
5761205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG1, 0);
5762205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0x2c);
5763205042Sthompsa		} else
5764205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0);
5765205042Sthompsa	}
5766205042Sthompsa
5767205042Sthompsa	/* initialize RF registers from ROM for >=RT3071*/
5768260219Skevlo	if (sc->mac_ver >= 0x3071) {
5769205042Sthompsa		for (i = 0; i < 10; i++) {
5770205042Sthompsa			if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff)
5771205042Sthompsa				continue;
5772205042Sthompsa			run_rt3070_rf_write(sc, sc->rf[i].reg, sc->rf[i].val);
5773205042Sthompsa		}
5774205042Sthompsa	}
5775205042Sthompsa}
5776205042Sthompsa
5777260219Skevlostatic void
5778260219Skevlorun_rt3593_rf_setup(struct run_softc *sc)
5779260219Skevlo{
5780260219Skevlo	uint8_t bbp, rf;
5781260219Skevlo
5782260219Skevlo	if (sc->mac_rev >= 0x0211) {
5783260219Skevlo		/* Enable DC filter. */
5784260219Skevlo		run_bbp_write(sc, 103, 0xc0);
5785260219Skevlo	}
5786260219Skevlo	run_write(sc, RT2860_TX_SW_CFG1, 0);
5787260219Skevlo	if (sc->mac_rev < 0x0211) {
5788260219Skevlo		run_write(sc, RT2860_TX_SW_CFG2,
5789260219Skevlo		    sc->patch_dac ? 0x2c : 0x0f);
5790260219Skevlo	} else
5791260219Skevlo		run_write(sc, RT2860_TX_SW_CFG2, 0);
5792260219Skevlo
5793260219Skevlo	run_rt3070_rf_read(sc, 50, &rf);
5794260219Skevlo	run_rt3070_rf_write(sc, 50, rf & ~RT3593_TX_LO2);
5795260219Skevlo
5796260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
5797260219Skevlo	rf = (rf & ~(RT3593_TX_LO1 | 0x0c)) |
5798260219Skevlo	    ((sc->txmixgain_2ghz & 0x07) << 2);
5799260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
5800260219Skevlo
5801260219Skevlo	run_rt3070_rf_read(sc, 38, &rf);
5802260219Skevlo	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
5803260219Skevlo
5804260219Skevlo	run_rt3070_rf_read(sc, 39, &rf);
5805260219Skevlo	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
5806260219Skevlo
5807260219Skevlo	run_rt3070_rf_read(sc, 1, &rf);
5808260219Skevlo	run_rt3070_rf_write(sc, 1, rf & ~(RT3070_RF_BLOCK | RT3070_PLL_PD));
5809260219Skevlo
5810260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
5811260219Skevlo	rf = (rf & ~0x18) | 0x10;
5812260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
5813260219Skevlo
5814260219Skevlo	/* Apply maximum likelihood detection for 2 stream case. */
5815260219Skevlo	run_bbp_read(sc, 105, &bbp);
5816260219Skevlo	if (sc->nrxchains > 1)
5817260219Skevlo		run_bbp_write(sc, 105, bbp | RT5390_MLD);
5818260219Skevlo
5819260219Skevlo	/* Avoid data lost and CRC error. */
5820260219Skevlo	run_bbp_read(sc, 4, &bbp);
5821260219Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5822260219Skevlo
5823260219Skevlo	run_bbp_write(sc, 92, 0x02);
5824260219Skevlo	run_bbp_write(sc, 82, 0x82);
5825260219Skevlo	run_bbp_write(sc, 106, 0x05);
5826260219Skevlo	run_bbp_write(sc, 104, 0x92);
5827260219Skevlo	run_bbp_write(sc, 88, 0x90);
5828260219Skevlo	run_bbp_write(sc, 148, 0xc8);
5829260219Skevlo	run_bbp_write(sc, 47, 0x48);
5830260219Skevlo	run_bbp_write(sc, 120, 0x50);
5831260219Skevlo
5832260219Skevlo	run_bbp_write(sc, 163, 0x9d);
5833260219Skevlo
5834260219Skevlo	/* SNR mapping. */
5835260219Skevlo	run_bbp_write(sc, 142, 0x06);
5836260219Skevlo	run_bbp_write(sc, 143, 0xa0);
5837260219Skevlo	run_bbp_write(sc, 142, 0x07);
5838260219Skevlo	run_bbp_write(sc, 143, 0xa1);
5839260219Skevlo	run_bbp_write(sc, 142, 0x08);
5840260219Skevlo	run_bbp_write(sc, 143, 0xa2);
5841260219Skevlo
5842260219Skevlo	run_bbp_write(sc, 31, 0x08);
5843260219Skevlo	run_bbp_write(sc, 68, 0x0b);
5844260219Skevlo	run_bbp_write(sc, 105, 0x04);
5845260219Skevlo}
5846260219Skevlo
5847260219Skevlostatic void
5848260219Skevlorun_rt5390_rf_setup(struct run_softc *sc)
5849260219Skevlo{
5850260219Skevlo	uint8_t bbp, rf;
5851260219Skevlo
5852260219Skevlo	if (sc->mac_rev >= 0x0211) {
5853260219Skevlo		/* Enable DC filter. */
5854260219Skevlo		run_bbp_write(sc, 103, 0xc0);
5855260219Skevlo
5856260219Skevlo		if (sc->mac_ver != 0x5592) {
5857260219Skevlo			/* Improve power consumption. */
5858260219Skevlo			run_bbp_read(sc, 31, &bbp);
5859260219Skevlo			run_bbp_write(sc, 31, bbp & ~0x03);
5860260219Skevlo		}
5861260219Skevlo	}
5862260219Skevlo
5863260219Skevlo	run_bbp_read(sc, 138, &bbp);
5864260219Skevlo	if (sc->ntxchains == 1)
5865260219Skevlo		bbp |= 0x20;	/* turn off DAC1 */
5866260219Skevlo	if (sc->nrxchains == 1)
5867260219Skevlo		bbp &= ~0x02;	/* turn off ADC1 */
5868260219Skevlo	run_bbp_write(sc, 138, bbp);
5869260219Skevlo
5870260219Skevlo	run_rt3070_rf_read(sc, 38, &rf);
5871260219Skevlo	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
5872260219Skevlo
5873260219Skevlo	run_rt3070_rf_read(sc, 39, &rf);
5874260219Skevlo	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
5875260219Skevlo
5876260219Skevlo	/* Avoid data lost and CRC error. */
5877260219Skevlo	run_bbp_read(sc, 4, &bbp);
5878260219Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5879260219Skevlo
5880260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
5881260219Skevlo	rf = (rf & ~0x18) | 0x10;
5882260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
5883260219Skevlo
5884260219Skevlo	if (sc->mac_ver != 0x5592) {
5885260219Skevlo		run_write(sc, RT2860_TX_SW_CFG1, 0);
5886260219Skevlo		if (sc->mac_rev < 0x0211) {
5887260219Skevlo			run_write(sc, RT2860_TX_SW_CFG2,
5888260219Skevlo			    sc->patch_dac ? 0x2c : 0x0f);
5889260219Skevlo		} else
5890260219Skevlo			run_write(sc, RT2860_TX_SW_CFG2, 0);
5891260219Skevlo	}
5892260219Skevlo}
5893260219Skevlo
5894203134Sthompsastatic int
5895203134Sthompsarun_txrx_enable(struct run_softc *sc)
5896203134Sthompsa{
5897203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
5898203134Sthompsa	uint32_t tmp;
5899203134Sthompsa	int error, ntries;
5900203134Sthompsa
5901203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_TX_EN);
5902203134Sthompsa	for (ntries = 0; ntries < 200; ntries++) {
5903203134Sthompsa		if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0)
5904257955Skevlo			return (error);
5905203134Sthompsa		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
5906203134Sthompsa			break;
5907203134Sthompsa		run_delay(sc, 50);
5908203134Sthompsa	}
5909203134Sthompsa	if (ntries == 200)
5910257955Skevlo		return (ETIMEDOUT);
5911203134Sthompsa
5912203134Sthompsa	run_delay(sc, 50);
5913203134Sthompsa
5914203134Sthompsa	tmp |= RT2860_RX_DMA_EN | RT2860_TX_DMA_EN | RT2860_TX_WB_DDONE;
5915203134Sthompsa	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
5916203134Sthompsa
5917203134Sthompsa	/* enable Rx bulk aggregation (set timeout and limit) */
5918203134Sthompsa	tmp = RT2860_USB_TX_EN | RT2860_USB_RX_EN | RT2860_USB_RX_AGG_EN |
5919203134Sthompsa	    RT2860_USB_RX_AGG_TO(128) | RT2860_USB_RX_AGG_LMT(2);
5920203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, tmp);
5921203134Sthompsa
5922203134Sthompsa	/* set Rx filter */
5923203134Sthompsa	tmp = RT2860_DROP_CRC_ERR | RT2860_DROP_PHY_ERR;
5924203134Sthompsa	if (ic->ic_opmode != IEEE80211_M_MONITOR) {
5925203134Sthompsa		tmp |= RT2860_DROP_UC_NOME | RT2860_DROP_DUPL |
5926203134Sthompsa		    RT2860_DROP_CTS | RT2860_DROP_BA | RT2860_DROP_ACK |
5927203134Sthompsa		    RT2860_DROP_VER_ERR | RT2860_DROP_CTRL_RSV |
5928203134Sthompsa		    RT2860_DROP_CFACK | RT2860_DROP_CFEND;
5929203134Sthompsa		if (ic->ic_opmode == IEEE80211_M_STA)
5930203134Sthompsa			tmp |= RT2860_DROP_RTS | RT2860_DROP_PSPOLL;
5931203134Sthompsa	}
5932203134Sthompsa	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
5933203134Sthompsa
5934203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL,
5935203134Sthompsa	    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
5936203134Sthompsa
5937209917Sthompsa	return (0);
5938203134Sthompsa}
5939203134Sthompsa
5940203134Sthompsastatic void
5941259030Skevlorun_adjust_freq_offset(struct run_softc *sc)
5942257955Skevlo{
5943257955Skevlo	uint8_t rf, tmp;
5944257955Skevlo
5945257955Skevlo	run_rt3070_rf_read(sc, 17, &rf);
5946257955Skevlo	tmp = rf;
5947257955Skevlo	rf = (rf & ~0x7f) | (sc->freq & 0x7f);
5948257955Skevlo	rf = MIN(rf, 0x5f);
5949257955Skevlo
5950257955Skevlo	if (tmp != rf)
5951257955Skevlo		run_mcu_cmd(sc, 0x74, (tmp << 8 ) | rf);
5952257955Skevlo}
5953257955Skevlo
5954257955Skevlostatic void
5955203134Sthompsarun_init_locked(struct run_softc *sc)
5956203134Sthompsa{
5957203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
5958203134Sthompsa	struct ieee80211com *ic = ifp->if_l2com;
5959203134Sthompsa	uint32_t tmp;
5960203134Sthompsa	uint8_t bbp1, bbp3;
5961203134Sthompsa	int i;
5962203134Sthompsa	int ridx;
5963203134Sthompsa	int ntries;
5964203134Sthompsa
5965209917Sthompsa	if (ic->ic_nrunning > 1)
5966208019Sthompsa		return;
5967208019Sthompsa
5968203134Sthompsa	run_stop(sc);
5969203134Sthompsa
5970233283Sbschmidt	if (run_load_microcode(sc) != 0) {
5971233283Sbschmidt		device_printf(sc->sc_dev, "could not load 8051 microcode\n");
5972233283Sbschmidt		goto fail;
5973233283Sbschmidt	}
5974233283Sbschmidt
5975203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5976203134Sthompsa		if (run_read(sc, RT2860_ASIC_VER_ID, &tmp) != 0)
5977203134Sthompsa			goto fail;
5978203134Sthompsa		if (tmp != 0 && tmp != 0xffffffff)
5979203134Sthompsa			break;
5980203134Sthompsa		run_delay(sc, 10);
5981203134Sthompsa	}
5982203134Sthompsa	if (ntries == 100)
5983203134Sthompsa		goto fail;
5984203134Sthompsa
5985203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
5986203134Sthompsa		run_setup_tx_list(sc, &sc->sc_epq[i]);
5987203134Sthompsa
5988203134Sthompsa	run_set_macaddr(sc, IF_LLADDR(ifp));
5989203134Sthompsa
5990203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5991203134Sthompsa		if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
5992203134Sthompsa			goto fail;
5993203134Sthompsa		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
5994203134Sthompsa			break;
5995203134Sthompsa		run_delay(sc, 10);
5996203134Sthompsa	}
5997203134Sthompsa	if (ntries == 100) {
5998203138Sthompsa		device_printf(sc->sc_dev, "timeout waiting for DMA engine\n");
5999203134Sthompsa		goto fail;
6000203134Sthompsa	}
6001203134Sthompsa	tmp &= 0xff0;
6002203134Sthompsa	tmp |= RT2860_TX_WB_DDONE;
6003203134Sthompsa	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
6004203134Sthompsa
6005203134Sthompsa	/* turn off PME_OEN to solve high-current issue */
6006203134Sthompsa	run_read(sc, RT2860_SYS_CTRL, &tmp);
6007203134Sthompsa	run_write(sc, RT2860_SYS_CTRL, tmp & ~RT2860_PME_OEN);
6008203134Sthompsa
6009203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL,
6010203134Sthompsa	    RT2860_BBP_HRST | RT2860_MAC_SRST);
6011203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, 0);
6012203134Sthompsa
6013203134Sthompsa	if (run_reset(sc) != 0) {
6014203138Sthompsa		device_printf(sc->sc_dev, "could not reset chipset\n");
6015203134Sthompsa		goto fail;
6016203134Sthompsa	}
6017203134Sthompsa
6018203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
6019203134Sthompsa
6020203134Sthompsa	/* init Tx power for all Tx rates (from EEPROM) */
6021203134Sthompsa	for (ridx = 0; ridx < 5; ridx++) {
6022203134Sthompsa		if (sc->txpow20mhz[ridx] == 0xffffffff)
6023203134Sthompsa			continue;
6024203134Sthompsa		run_write(sc, RT2860_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]);
6025203134Sthompsa	}
6026203134Sthompsa
6027257955Skevlo	for (i = 0; i < nitems(rt2870_def_mac); i++)
6028203134Sthompsa		run_write(sc, rt2870_def_mac[i].reg, rt2870_def_mac[i].val);
6029203134Sthompsa	run_write(sc, RT2860_WMM_AIFSN_CFG, 0x00002273);
6030203134Sthompsa	run_write(sc, RT2860_WMM_CWMIN_CFG, 0x00002344);
6031203134Sthompsa	run_write(sc, RT2860_WMM_CWMAX_CFG, 0x000034aa);
6032203134Sthompsa
6033259030Skevlo	if (sc->mac_ver >= 0x5390) {
6034259030Skevlo		run_write(sc, RT2860_TX_SW_CFG0,
6035259030Skevlo		    4 << RT2860_DLY_PAPE_EN_SHIFT | 4);
6036259030Skevlo		if (sc->mac_ver >= 0x5392) {
6037259030Skevlo			run_write(sc, RT2860_MAX_LEN_CFG, 0x00002fff);
6038259032Skevlo			if (sc->mac_ver == 0x5592) {
6039259032Skevlo				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcba980);
6040259032Skevlo				run_write(sc, RT2860_TXOP_HLDR_ET, 0x00000082);
6041259032Skevlo			} else {
6042259032Skevlo				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcb4980);
6043259032Skevlo				run_write(sc, RT2860_LG_FBK_CFG0, 0xedcba322);
6044259032Skevlo			}
6045259030Skevlo		}
6046260219Skevlo	} else if (sc->mac_ver == 0x3593) {
6047260219Skevlo		run_write(sc, RT2860_TX_SW_CFG0,
6048260219Skevlo		    4 << RT2860_DLY_PAPE_EN_SHIFT | 2);
6049257955Skevlo	} else if (sc->mac_ver >= 0x3070) {
6050203134Sthompsa		/* set delay of PA_PE assertion to 1us (unit of 0.25us) */
6051203134Sthompsa		run_write(sc, RT2860_TX_SW_CFG0,
6052203134Sthompsa		    4 << RT2860_DLY_PAPE_EN_SHIFT);
6053203134Sthompsa	}
6054203134Sthompsa
6055203134Sthompsa	/* wait while MAC is busy */
6056203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
6057203134Sthompsa		if (run_read(sc, RT2860_MAC_STATUS_REG, &tmp) != 0)
6058203134Sthompsa			goto fail;
6059203134Sthompsa		if (!(tmp & (RT2860_RX_STATUS_BUSY | RT2860_TX_STATUS_BUSY)))
6060203134Sthompsa			break;
6061203134Sthompsa		run_delay(sc, 10);
6062203134Sthompsa	}
6063203134Sthompsa	if (ntries == 100)
6064203134Sthompsa		goto fail;
6065203134Sthompsa
6066203134Sthompsa	/* clear Host to MCU mailbox */
6067203134Sthompsa	run_write(sc, RT2860_H2M_BBPAGENT, 0);
6068203134Sthompsa	run_write(sc, RT2860_H2M_MAILBOX, 0);
6069203134Sthompsa	run_delay(sc, 10);
6070203134Sthompsa
6071203134Sthompsa	if (run_bbp_init(sc) != 0) {
6072203138Sthompsa		device_printf(sc->sc_dev, "could not initialize BBP\n");
6073203134Sthompsa		goto fail;
6074203134Sthompsa	}
6075203134Sthompsa
6076203134Sthompsa	/* abort TSF synchronization */
6077203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
6078203134Sthompsa	tmp &= ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
6079203134Sthompsa	    RT2860_TBTT_TIMER_EN);
6080203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
6081203134Sthompsa
6082203134Sthompsa	/* clear RX WCID search table */
6083203134Sthompsa	run_set_region_4(sc, RT2860_WCID_ENTRY(0), 0, 512);
6084203134Sthompsa	/* clear WCID attribute table */
6085203134Sthompsa	run_set_region_4(sc, RT2860_WCID_ATTR(0), 0, 8 * 32);
6086203134Sthompsa
6087209144Sthompsa	/* hostapd sets a key before init. So, don't clear it. */
6088209917Sthompsa	if (sc->cmdq_key_set != RUN_CMDQ_GO) {
6089209144Sthompsa		/* clear shared key table */
6090209144Sthompsa		run_set_region_4(sc, RT2860_SKEY(0, 0), 0, 8 * 32);
6091209144Sthompsa		/* clear shared key mode */
6092209144Sthompsa		run_set_region_4(sc, RT2860_SKEY_MODE_0_7, 0, 4);
6093209144Sthompsa	}
6094209144Sthompsa
6095203134Sthompsa	run_read(sc, RT2860_US_CYC_CNT, &tmp);
6096203134Sthompsa	tmp = (tmp & ~0xff) | 0x1e;
6097203134Sthompsa	run_write(sc, RT2860_US_CYC_CNT, tmp);
6098203134Sthompsa
6099205042Sthompsa	if (sc->mac_rev != 0x0101)
6100203134Sthompsa		run_write(sc, RT2860_TXOP_CTRL_CFG, 0x0000583f);
6101203134Sthompsa
6102203134Sthompsa	run_write(sc, RT2860_WMM_TXOP0_CFG, 0);
6103203134Sthompsa	run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96);
6104203134Sthompsa
6105203134Sthompsa	/* write vendor-specific BBP values (from EEPROM) */
6106260219Skevlo	if (sc->mac_ver < 0x3593) {
6107257955Skevlo		for (i = 0; i < 10; i++) {
6108257955Skevlo			if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff)
6109257955Skevlo				continue;
6110257955Skevlo			run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val);
6111257955Skevlo		}
6112203134Sthompsa	}
6113203134Sthompsa
6114203134Sthompsa	/* select Main antenna for 1T1R devices */
6115257955Skevlo	if (sc->rf_rev == RT3070_RF_3020 || sc->rf_rev == RT5390_RF_5370)
6116203134Sthompsa		run_set_rx_antenna(sc, 0);
6117203134Sthompsa
6118203134Sthompsa	/* send LEDs operating mode to microcontroller */
6119203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0]);
6120203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1]);
6121203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2]);
6122203134Sthompsa
6123257955Skevlo	if (sc->mac_ver >= 0x5390)
6124257955Skevlo		run_rt5390_rf_init(sc);
6125260219Skevlo	else if (sc->mac_ver == 0x3593)
6126260219Skevlo		run_rt3593_rf_init(sc);
6127257955Skevlo	else if (sc->mac_ver >= 0x3070)
6128205042Sthompsa		run_rt3070_rf_init(sc);
6129205042Sthompsa
6130203134Sthompsa	/* disable non-existing Rx chains */
6131203134Sthompsa	run_bbp_read(sc, 3, &bbp3);
6132203134Sthompsa	bbp3 &= ~(1 << 3 | 1 << 4);
6133203134Sthompsa	if (sc->nrxchains == 2)
6134203134Sthompsa		bbp3 |= 1 << 3;
6135203134Sthompsa	else if (sc->nrxchains == 3)
6136203134Sthompsa		bbp3 |= 1 << 4;
6137203134Sthompsa	run_bbp_write(sc, 3, bbp3);
6138203134Sthompsa
6139203134Sthompsa	/* disable non-existing Tx chains */
6140203134Sthompsa	run_bbp_read(sc, 1, &bbp1);
6141203134Sthompsa	if (sc->ntxchains == 1)
6142203134Sthompsa		bbp1 &= ~(1 << 3 | 1 << 4);
6143203134Sthompsa	run_bbp_write(sc, 1, bbp1);
6144203134Sthompsa
6145260219Skevlo	if (sc->mac_ver >= 0x5390)
6146260219Skevlo		run_rt5390_rf_setup(sc);
6147260219Skevlo	else if (sc->mac_ver == 0x3593)
6148260219Skevlo		run_rt3593_rf_setup(sc);
6149260219Skevlo	else if (sc->mac_ver >= 0x3070)
6150205042Sthompsa		run_rt3070_rf_setup(sc);
6151203134Sthompsa
6152203134Sthompsa	/* select default channel */
6153203134Sthompsa	run_set_chan(sc, ic->ic_curchan);
6154203134Sthompsa
6155203134Sthompsa	/* setup initial protection mode */
6156218492Sbschmidt	run_updateprot_cb(ic);
6157203134Sthompsa
6158203134Sthompsa	/* turn radio LED on */
6159203134Sthompsa	run_set_leds(sc, RT2860_LED_RADIO);
6160203134Sthompsa
6161203134Sthompsa	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
6162203134Sthompsa	ifp->if_drv_flags |= IFF_DRV_RUNNING;
6163208019Sthompsa	sc->cmdq_run = RUN_CMDQ_GO;
6164203134Sthompsa
6165209917Sthompsa	for (i = 0; i != RUN_N_XFER; i++)
6166203134Sthompsa		usbd_xfer_set_stall(sc->sc_xfer[i]);
6167203134Sthompsa
6168203134Sthompsa	usbd_transfer_start(sc->sc_xfer[RUN_BULK_RX]);
6169203134Sthompsa
6170203134Sthompsa	if (run_txrx_enable(sc) != 0)
6171203134Sthompsa		goto fail;
6172203134Sthompsa
6173203134Sthompsa	return;
6174203134Sthompsa
6175203134Sthompsafail:
6176203134Sthompsa	run_stop(sc);
6177203134Sthompsa}
6178203134Sthompsa
6179203134Sthompsastatic void
6180203134Sthompsarun_init(void *arg)
6181203134Sthompsa{
6182203134Sthompsa	struct run_softc *sc = arg;
6183203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
6184203134Sthompsa	struct ieee80211com *ic = ifp->if_l2com;
6185203134Sthompsa
6186203134Sthompsa	RUN_LOCK(sc);
6187203134Sthompsa	run_init_locked(sc);
6188203134Sthompsa	RUN_UNLOCK(sc);
6189203134Sthompsa
6190203134Sthompsa	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
6191208019Sthompsa		ieee80211_start_all(ic);
6192203134Sthompsa}
6193203134Sthompsa
6194203134Sthompsastatic void
6195203134Sthompsarun_stop(void *arg)
6196203134Sthompsa{
6197203134Sthompsa	struct run_softc *sc = (struct run_softc *)arg;
6198203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
6199203134Sthompsa	uint32_t tmp;
6200203134Sthompsa	int i;
6201203134Sthompsa	int ntries;
6202203134Sthompsa
6203203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
6204203134Sthompsa
6205203134Sthompsa	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
6206203134Sthompsa		run_set_leds(sc, 0);	/* turn all LEDs off */
6207203134Sthompsa
6208203134Sthompsa	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
6209203134Sthompsa
6210208019Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
6211209144Sthompsa	sc->cmdq_run = sc->cmdq_key_set;
6212208019Sthompsa
6213203134Sthompsa	RUN_UNLOCK(sc);
6214203134Sthompsa
6215203134Sthompsa	for(i = 0; i < RUN_N_XFER; i++)
6216203134Sthompsa		usbd_transfer_drain(sc->sc_xfer[i]);
6217203134Sthompsa
6218203134Sthompsa	RUN_LOCK(sc);
6219203134Sthompsa
6220209917Sthompsa	if (sc->rx_m != NULL) {
6221203134Sthompsa		m_free(sc->rx_m);
6222203134Sthompsa		sc->rx_m = NULL;
6223203134Sthompsa	}
6224203134Sthompsa
6225257955Skevlo	/* Disable Tx/Rx DMA. */
6226257955Skevlo	if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
6227257955Skevlo		return;
6228257955Skevlo	tmp &= ~(RT2860_RX_DMA_EN | RT2860_TX_DMA_EN);
6229257955Skevlo	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
6230257955Skevlo
6231258643Shselasky	for (ntries = 0; ntries < 100; ntries++) {
6232257955Skevlo		if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
6233257955Skevlo			return;
6234257955Skevlo		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
6235257955Skevlo				break;
6236257955Skevlo		run_delay(sc, 10);
6237257955Skevlo	}
6238257955Skevlo	if (ntries == 100) {
6239257955Skevlo		device_printf(sc->sc_dev, "timeout waiting for DMA engine\n");
6240257955Skevlo		return;
6241257955Skevlo	}
6242257955Skevlo
6243203134Sthompsa	/* disable Tx/Rx */
6244203134Sthompsa	run_read(sc, RT2860_MAC_SYS_CTRL, &tmp);
6245203134Sthompsa	tmp &= ~(RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
6246203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, tmp);
6247203134Sthompsa
6248203134Sthompsa	/* wait for pending Tx to complete */
6249203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
6250209917Sthompsa		if (run_read(sc, RT2860_TXRXQ_PCNT, &tmp) != 0) {
6251203134Sthompsa			DPRINTF("Cannot read Tx queue count\n");
6252203134Sthompsa			break;
6253203134Sthompsa		}
6254209917Sthompsa		if ((tmp & RT2860_TX2Q_PCNT_MASK) == 0) {
6255203134Sthompsa			DPRINTF("All Tx cleared\n");
6256203134Sthompsa			break;
6257203134Sthompsa		}
6258203134Sthompsa		run_delay(sc, 10);
6259203134Sthompsa	}
6260209917Sthompsa	if (ntries >= 100)
6261203134Sthompsa		DPRINTF("There are still pending Tx\n");
6262203134Sthompsa	run_delay(sc, 10);
6263203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, 0);
6264203134Sthompsa
6265203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST);
6266203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
6267203134Sthompsa
6268203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
6269203134Sthompsa		run_unsetup_tx_list(sc, &sc->sc_epq[i]);
6270203134Sthompsa}
6271203134Sthompsa
6272203134Sthompsastatic void
6273257429Shselaskyrun_delay(struct run_softc *sc, u_int ms)
6274203134Sthompsa{
6275203134Sthompsa	usb_pause_mtx(mtx_owned(&sc->sc_mtx) ?
6276203134Sthompsa	    &sc->sc_mtx : NULL, USB_MS_TO_TICKS(ms));
6277203134Sthompsa}
6278203134Sthompsa
6279203134Sthompsastatic device_method_t run_methods[] = {
6280203134Sthompsa	/* Device interface */
6281203134Sthompsa	DEVMETHOD(device_probe,		run_match),
6282203134Sthompsa	DEVMETHOD(device_attach,	run_attach),
6283203134Sthompsa	DEVMETHOD(device_detach,	run_detach),
6284246614Shselasky	DEVMETHOD_END
6285203134Sthompsa};
6286203134Sthompsa
6287203134Sthompsastatic driver_t run_driver = {
6288233774Shselasky	.name = "run",
6289233774Shselasky	.methods = run_methods,
6290233774Shselasky	.size = sizeof(struct run_softc)
6291203134Sthompsa};
6292203134Sthompsa
6293203134Sthompsastatic devclass_t run_devclass;
6294203134Sthompsa
6295259812SkevloDRIVER_MODULE(run, uhub, run_driver, run_devclass, run_driver_loaded, NULL);
6296212122SthompsaMODULE_DEPEND(run, wlan, 1, 1, 1);
6297212122SthompsaMODULE_DEPEND(run, usb, 1, 1, 1);
6298212122SthompsaMODULE_DEPEND(run, firmware, 1, 1, 1);
6299212122SthompsaMODULE_VERSION(run, 1);
6300