if_run.c revision 273448
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 273448 2014-10-22 03:32:27Z kevlo $");
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);
4916273448Skevlo	if (rvp->beacon_mbuf == NULL) {
4917273448Skevlo		rvp->beacon_mbuf = ieee80211_beacon_alloc(vap->iv_bss,
4918273448Skevlo		    &rvp->bo);
4919273448Skevlo		if (rvp->beacon_mbuf == NULL)
4920273448Skevlo			return;
4921273448Skevlo	}
4922218492Sbschmidt	ieee80211_beacon_update(vap->iv_bss, &rvp->bo, rvp->beacon_mbuf, mcast);
4923218492Sbschmidt
4924208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
4925208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
4926208019Sthompsa	sc->cmdq[i].func = run_update_beacon_cb;
4927208019Sthompsa	sc->cmdq[i].arg0 = vap;
4928208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
4929208019Sthompsa
4930208019Sthompsa	return;
4931203134Sthompsa}
4932203134Sthompsa
4933203134Sthompsastatic void
4934208019Sthompsarun_update_beacon_cb(void *arg)
4935203134Sthompsa{
4936208019Sthompsa	struct ieee80211vap *vap = arg;
4937218492Sbschmidt	struct run_vap *rvp = RUN_VAP(vap);
4938203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
4939203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
4940203134Sthompsa	struct rt2860_txwi txwi;
4941203134Sthompsa	struct mbuf *m;
4942259032Skevlo	uint16_t txwisize;
4943208019Sthompsa	uint8_t ridx;
4944203134Sthompsa
4945209917Sthompsa	if (vap->iv_bss->ni_chan == IEEE80211_CHAN_ANYC)
4946208019Sthompsa		return;
4947236439Shselasky	if (ic->ic_bsschan == IEEE80211_CHAN_ANYC)
4948236439Shselasky		return;
4949208019Sthompsa
4950218492Sbschmidt	/*
4951218492Sbschmidt	 * No need to call ieee80211_beacon_update(), run_update_beacon()
4952218492Sbschmidt	 * is taking care of apropriate calls.
4953218492Sbschmidt	 */
4954218492Sbschmidt	if (rvp->beacon_mbuf == NULL) {
4955218492Sbschmidt		rvp->beacon_mbuf = ieee80211_beacon_alloc(vap->iv_bss,
4956218492Sbschmidt		    &rvp->bo);
4957218492Sbschmidt		if (rvp->beacon_mbuf == NULL)
4958218492Sbschmidt			return;
4959218492Sbschmidt	}
4960218492Sbschmidt	m = rvp->beacon_mbuf;
4961203134Sthompsa
4962259032Skevlo	memset(&txwi, 0, sizeof(txwi));
4963203134Sthompsa	txwi.wcid = 0xff;
4964203134Sthompsa	txwi.len = htole16(m->m_pkthdr.len);
4965259032Skevlo
4966203134Sthompsa	/* send beacons at the lowest available rate */
4967208019Sthompsa	ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
4968208019Sthompsa	    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
4969208019Sthompsa	txwi.phy = htole16(rt2860_rates[ridx].mcs);
4970208019Sthompsa	if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM)
4971259032Skevlo		txwi.phy |= htole16(RT2860_PHY_OFDM);
4972203134Sthompsa	txwi.txop = RT2860_TX_TXOP_HT;
4973203134Sthompsa	txwi.flags = RT2860_TX_TS;
4974209144Sthompsa	txwi.xflags = RT2860_TX_NSEQ;
4975203134Sthompsa
4976259032Skevlo	txwisize = (sc->mac_ver == 0x5592) ?
4977259032Skevlo	    sizeof(txwi) + sizeof(uint32_t) : sizeof(txwi);
4978259032Skevlo	run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id), (uint8_t *)&txwi,
4979259032Skevlo	    txwisize);
4980259032Skevlo	run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id) + txwisize,
4981259032Skevlo	    mtod(m, uint8_t *), (m->m_pkthdr.len + 1) & ~1);
4982203134Sthompsa}
4983203134Sthompsa
4984203134Sthompsastatic void
4985203134Sthompsarun_updateprot(struct ieee80211com *ic)
4986203134Sthompsa{
4987203134Sthompsa	struct run_softc *sc = ic->ic_ifp->if_softc;
4988218492Sbschmidt	uint32_t i;
4989218492Sbschmidt
4990218492Sbschmidt	i = RUN_CMDQ_GET(&sc->cmdq_store);
4991218492Sbschmidt	DPRINTF("cmdq_store=%d\n", i);
4992218492Sbschmidt	sc->cmdq[i].func = run_updateprot_cb;
4993218492Sbschmidt	sc->cmdq[i].arg0 = ic;
4994218492Sbschmidt	ieee80211_runtask(ic, &sc->cmdq_task);
4995218492Sbschmidt}
4996218492Sbschmidt
4997218492Sbschmidtstatic void
4998218492Sbschmidtrun_updateprot_cb(void *arg)
4999218492Sbschmidt{
5000218492Sbschmidt	struct ieee80211com *ic = arg;
5001218492Sbschmidt	struct run_softc *sc = ic->ic_ifp->if_softc;
5002203134Sthompsa	uint32_t tmp;
5003203134Sthompsa
5004203134Sthompsa	tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL;
5005203134Sthompsa	/* setup protection frame rate (MCS code) */
5006203134Sthompsa	tmp |= (ic->ic_curmode == IEEE80211_MODE_11A) ?
5007270192Skevlo	    rt2860_rates[RT2860_RIDX_OFDM6].mcs | RT2860_PHY_OFDM :
5008203134Sthompsa	    rt2860_rates[RT2860_RIDX_CCK11].mcs;
5009203134Sthompsa
5010203134Sthompsa	/* CCK frames don't require protection */
5011203134Sthompsa	run_write(sc, RT2860_CCK_PROT_CFG, tmp);
5012203134Sthompsa	if (ic->ic_flags & IEEE80211_F_USEPROT) {
5013203134Sthompsa		if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
5014203134Sthompsa			tmp |= RT2860_PROT_CTRL_RTS_CTS;
5015203134Sthompsa		else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
5016203134Sthompsa			tmp |= RT2860_PROT_CTRL_CTS;
5017203134Sthompsa	}
5018203134Sthompsa	run_write(sc, RT2860_OFDM_PROT_CFG, tmp);
5019203134Sthompsa}
5020203134Sthompsa
5021203134Sthompsastatic void
5022208019Sthompsarun_usb_timeout_cb(void *arg)
5023203134Sthompsa{
5024208019Sthompsa	struct ieee80211vap *vap = arg;
5025208019Sthompsa	struct run_softc *sc = vap->iv_ic->ic_ifp->if_softc;
5026203134Sthompsa
5027208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
5028203134Sthompsa
5029203134Sthompsa	if(vap->iv_state == IEEE80211_S_RUN &&
5030203134Sthompsa	    vap->iv_opmode != IEEE80211_M_STA)
5031203134Sthompsa		run_reset_livelock(sc);
5032209917Sthompsa	else if (vap->iv_state == IEEE80211_S_SCAN) {
5033203134Sthompsa		DPRINTF("timeout caused by scan\n");
5034203134Sthompsa		/* cancel bgscan */
5035203134Sthompsa		ieee80211_cancel_scan(vap);
5036203134Sthompsa	} else
5037203134Sthompsa		DPRINTF("timeout by unknown cause\n");
5038203134Sthompsa}
5039203134Sthompsa
5040203134Sthompsastatic void
5041203134Sthompsarun_reset_livelock(struct run_softc *sc)
5042203134Sthompsa{
5043203134Sthompsa	uint32_t tmp;
5044203134Sthompsa
5045208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
5046208019Sthompsa
5047203134Sthompsa	/*
5048203134Sthompsa	 * In IBSS or HostAP modes (when the hardware sends beacons), the MAC
5049203134Sthompsa	 * can run into a livelock and start sending CTS-to-self frames like
5050203134Sthompsa	 * crazy if protection is enabled.  Reset MAC/BBP for a while
5051203134Sthompsa	 */
5052203134Sthompsa	run_read(sc, RT2860_DEBUG, &tmp);
5053208019Sthompsa	DPRINTFN(3, "debug reg %08x\n", tmp);
5054209917Sthompsa	if ((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))) {
5055203134Sthompsa		DPRINTF("CTS-to-self livelock detected\n");
5056203134Sthompsa		run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST);
5057203134Sthompsa		run_delay(sc, 1);
5058203134Sthompsa		run_write(sc, RT2860_MAC_SYS_CTRL,
5059203134Sthompsa		    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
5060203134Sthompsa	}
5061203134Sthompsa}
5062203134Sthompsa
5063203134Sthompsastatic void
5064203134Sthompsarun_update_promisc_locked(struct ifnet *ifp)
5065203134Sthompsa{
5066203134Sthompsa	struct run_softc *sc = ifp->if_softc;
5067203134Sthompsa        uint32_t tmp;
5068203134Sthompsa
5069203134Sthompsa	run_read(sc, RT2860_RX_FILTR_CFG, &tmp);
5070203134Sthompsa
5071203134Sthompsa	tmp |= RT2860_DROP_UC_NOME;
5072203134Sthompsa        if (ifp->if_flags & IFF_PROMISC)
5073203134Sthompsa		tmp &= ~RT2860_DROP_UC_NOME;
5074203134Sthompsa
5075203134Sthompsa	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
5076203134Sthompsa
5077203134Sthompsa        DPRINTF("%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ?
5078203134Sthompsa            "entering" : "leaving");
5079203134Sthompsa}
5080203134Sthompsa
5081203134Sthompsastatic void
5082203134Sthompsarun_update_promisc(struct ifnet *ifp)
5083203134Sthompsa{
5084203134Sthompsa	struct run_softc *sc = ifp->if_softc;
5085203134Sthompsa
5086203134Sthompsa	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
5087203134Sthompsa		return;
5088203134Sthompsa
5089203134Sthompsa	RUN_LOCK(sc);
5090203134Sthompsa	run_update_promisc_locked(ifp);
5091203134Sthompsa	RUN_UNLOCK(sc);
5092203134Sthompsa}
5093203134Sthompsa
5094203134Sthompsastatic void
5095203134Sthompsarun_enable_tsf_sync(struct run_softc *sc)
5096203134Sthompsa{
5097208019Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
5098203134Sthompsa	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
5099203134Sthompsa	uint32_t tmp;
5100203134Sthompsa
5101257955Skevlo	DPRINTF("rvp_id=%d ic_opmode=%d\n", RUN_VAP(vap)->rvp_id,
5102257955Skevlo	    ic->ic_opmode);
5103208019Sthompsa
5104203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
5105203134Sthompsa	tmp &= ~0x1fffff;
5106203134Sthompsa	tmp |= vap->iv_bss->ni_intval * 16;
5107203134Sthompsa	tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN;
5108203134Sthompsa
5109208019Sthompsa	if (ic->ic_opmode == IEEE80211_M_STA) {
5110203134Sthompsa		/*
5111203134Sthompsa		 * Local TSF is always updated with remote TSF on beacon
5112203134Sthompsa		 * reception.
5113203134Sthompsa		 */
5114203134Sthompsa		tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT;
5115208019Sthompsa	} else if (ic->ic_opmode == IEEE80211_M_IBSS) {
5116203134Sthompsa	        tmp |= RT2860_BCN_TX_EN;
5117203134Sthompsa	        /*
5118203134Sthompsa	         * Local TSF is updated with remote TSF on beacon reception
5119203134Sthompsa	         * only if the remote TSF is greater than local TSF.
5120203134Sthompsa	         */
5121203134Sthompsa	        tmp |= 2 << RT2860_TSF_SYNC_MODE_SHIFT;
5122208019Sthompsa	} else if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
5123208019Sthompsa		    ic->ic_opmode == IEEE80211_M_MBSS) {
5124203134Sthompsa	        tmp |= RT2860_BCN_TX_EN;
5125203134Sthompsa	        /* SYNC with nobody */
5126203134Sthompsa	        tmp |= 3 << RT2860_TSF_SYNC_MODE_SHIFT;
5127208019Sthompsa	} else {
5128203134Sthompsa		DPRINTF("Enabling TSF failed. undefined opmode\n");
5129208019Sthompsa		return;
5130208019Sthompsa	}
5131203134Sthompsa
5132203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
5133203134Sthompsa}
5134203134Sthompsa
5135203134Sthompsastatic void
5136203134Sthompsarun_enable_mrr(struct run_softc *sc)
5137203134Sthompsa{
5138259546Skevlo#define	CCK(mcs)	(mcs)
5139259546Skevlo#define	OFDM(mcs)	(1 << 3 | (mcs))
5140203134Sthompsa	run_write(sc, RT2860_LG_FBK_CFG0,
5141203134Sthompsa	    OFDM(6) << 28 |	/* 54->48 */
5142203134Sthompsa	    OFDM(5) << 24 |	/* 48->36 */
5143203134Sthompsa	    OFDM(4) << 20 |	/* 36->24 */
5144203134Sthompsa	    OFDM(3) << 16 |	/* 24->18 */
5145203134Sthompsa	    OFDM(2) << 12 |	/* 18->12 */
5146203134Sthompsa	    OFDM(1) <<  8 |	/* 12-> 9 */
5147203134Sthompsa	    OFDM(0) <<  4 |	/*  9-> 6 */
5148203134Sthompsa	    OFDM(0));		/*  6-> 6 */
5149203134Sthompsa
5150203134Sthompsa	run_write(sc, RT2860_LG_FBK_CFG1,
5151203134Sthompsa	    CCK(2) << 12 |	/* 11->5.5 */
5152203134Sthompsa	    CCK(1) <<  8 |	/* 5.5-> 2 */
5153203134Sthompsa	    CCK(0) <<  4 |	/*   2-> 1 */
5154203134Sthompsa	    CCK(0));		/*   1-> 1 */
5155203134Sthompsa#undef OFDM
5156203134Sthompsa#undef CCK
5157203134Sthompsa}
5158203134Sthompsa
5159203134Sthompsastatic void
5160203134Sthompsarun_set_txpreamble(struct run_softc *sc)
5161203134Sthompsa{
5162203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
5163203134Sthompsa	uint32_t tmp;
5164203134Sthompsa
5165203134Sthompsa	run_read(sc, RT2860_AUTO_RSP_CFG, &tmp);
5166203134Sthompsa	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
5167203134Sthompsa		tmp |= RT2860_CCK_SHORT_EN;
5168203134Sthompsa	else
5169203134Sthompsa		tmp &= ~RT2860_CCK_SHORT_EN;
5170203134Sthompsa	run_write(sc, RT2860_AUTO_RSP_CFG, tmp);
5171203134Sthompsa}
5172203134Sthompsa
5173203134Sthompsastatic void
5174203134Sthompsarun_set_basicrates(struct run_softc *sc)
5175203134Sthompsa{
5176203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
5177203134Sthompsa
5178203134Sthompsa	/* set basic rates mask */
5179203134Sthompsa	if (ic->ic_curmode == IEEE80211_MODE_11B)
5180203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x003);
5181203134Sthompsa	else if (ic->ic_curmode == IEEE80211_MODE_11A)
5182203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x150);
5183203134Sthompsa	else	/* 11g */
5184203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x15f);
5185203134Sthompsa}
5186203134Sthompsa
5187203134Sthompsastatic void
5188203134Sthompsarun_set_leds(struct run_softc *sc, uint16_t which)
5189203134Sthompsa{
5190203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LEDS,
5191203134Sthompsa	    which | (sc->leds & 0x7f));
5192203134Sthompsa}
5193203134Sthompsa
5194203134Sthompsastatic void
5195203134Sthompsarun_set_bssid(struct run_softc *sc, const uint8_t *bssid)
5196203134Sthompsa{
5197203134Sthompsa	run_write(sc, RT2860_MAC_BSSID_DW0,
5198203134Sthompsa	    bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24);
5199203134Sthompsa	run_write(sc, RT2860_MAC_BSSID_DW1,
5200203134Sthompsa	    bssid[4] | bssid[5] << 8);
5201203134Sthompsa}
5202203134Sthompsa
5203203134Sthompsastatic void
5204203134Sthompsarun_set_macaddr(struct run_softc *sc, const uint8_t *addr)
5205203134Sthompsa{
5206203134Sthompsa	run_write(sc, RT2860_MAC_ADDR_DW0,
5207203134Sthompsa	    addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24);
5208203134Sthompsa	run_write(sc, RT2860_MAC_ADDR_DW1,
5209203134Sthompsa	    addr[4] | addr[5] << 8 | 0xff << 16);
5210203134Sthompsa}
5211203134Sthompsa
5212203134Sthompsastatic void
5213203134Sthompsarun_updateslot(struct ifnet *ifp)
5214203134Sthompsa{
5215203134Sthompsa	struct run_softc *sc = ifp->if_softc;
5216203134Sthompsa	struct ieee80211com *ic = ifp->if_l2com;
5217218492Sbschmidt	uint32_t i;
5218218492Sbschmidt
5219218492Sbschmidt	i = RUN_CMDQ_GET(&sc->cmdq_store);
5220218492Sbschmidt	DPRINTF("cmdq_store=%d\n", i);
5221218492Sbschmidt	sc->cmdq[i].func = run_updateslot_cb;
5222218492Sbschmidt	sc->cmdq[i].arg0 = ifp;
5223218492Sbschmidt	ieee80211_runtask(ic, &sc->cmdq_task);
5224218492Sbschmidt
5225218492Sbschmidt	return;
5226218492Sbschmidt}
5227218492Sbschmidt
5228218492Sbschmidt/* ARGSUSED */
5229218492Sbschmidtstatic void
5230218492Sbschmidtrun_updateslot_cb(void *arg)
5231218492Sbschmidt{
5232218492Sbschmidt	struct ifnet *ifp = arg;
5233218492Sbschmidt	struct run_softc *sc = ifp->if_softc;
5234218492Sbschmidt	struct ieee80211com *ic = ifp->if_l2com;
5235203134Sthompsa	uint32_t tmp;
5236203134Sthompsa
5237203134Sthompsa	run_read(sc, RT2860_BKOFF_SLOT_CFG, &tmp);
5238203134Sthompsa	tmp &= ~0xff;
5239203134Sthompsa	tmp |= (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20;
5240203134Sthompsa	run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp);
5241203134Sthompsa}
5242203134Sthompsa
5243208019Sthompsastatic void
5244208019Sthompsarun_update_mcast(struct ifnet *ifp)
5245208019Sthompsa{
5246208019Sthompsa	/* h/w filter supports getting everything or nothing */
5247208019Sthompsa	ifp->if_flags |= IFF_ALLMULTI;
5248208019Sthompsa}
5249208019Sthompsa
5250203134Sthompsastatic int8_t
5251203134Sthompsarun_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain)
5252203134Sthompsa{
5253203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
5254203134Sthompsa	struct ieee80211_channel *c = ic->ic_curchan;
5255203134Sthompsa	int delta;
5256203134Sthompsa
5257203134Sthompsa	if (IEEE80211_IS_CHAN_5GHZ(c)) {
5258257429Shselasky		u_int chan = ieee80211_chan2ieee(ic, c);
5259203134Sthompsa		delta = sc->rssi_5ghz[rxchain];
5260203134Sthompsa
5261203134Sthompsa		/* determine channel group */
5262203134Sthompsa		if (chan <= 64)
5263203134Sthompsa			delta -= sc->lna[1];
5264203134Sthompsa		else if (chan <= 128)
5265203134Sthompsa			delta -= sc->lna[2];
5266203134Sthompsa		else
5267203134Sthompsa			delta -= sc->lna[3];
5268203134Sthompsa	} else
5269203134Sthompsa		delta = sc->rssi_2ghz[rxchain] - sc->lna[0];
5270203134Sthompsa
5271209917Sthompsa	return (-12 - delta - rssi);
5272203134Sthompsa}
5273203134Sthompsa
5274257955Skevlostatic void
5275257955Skevlorun_rt5390_bbp_init(struct run_softc *sc)
5276257955Skevlo{
5277257955Skevlo	int i;
5278259032Skevlo	uint8_t bbp;
5279257955Skevlo
5280259032Skevlo	/* Apply maximum likelihood detection for 2 stream case. */
5281259032Skevlo	run_bbp_read(sc, 105, &bbp);
5282259032Skevlo	if (sc->nrxchains > 1)
5283259032Skevlo		run_bbp_write(sc, 105, bbp | RT5390_MLD);
5284259032Skevlo
5285257955Skevlo	/* Avoid data lost and CRC error. */
5286259032Skevlo	run_bbp_read(sc, 4, &bbp);
5287259031Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5288257955Skevlo
5289259032Skevlo	if (sc->mac_ver == 0x5592) {
5290259032Skevlo		for (i = 0; i < nitems(rt5592_def_bbp); i++) {
5291259032Skevlo			run_bbp_write(sc, rt5592_def_bbp[i].reg,
5292259032Skevlo			    rt5592_def_bbp[i].val);
5293259032Skevlo		}
5294259032Skevlo		for (i = 0; i < nitems(rt5592_bbp_r196); i++) {
5295259032Skevlo			run_bbp_write(sc, 195, i + 0x80);
5296259032Skevlo			run_bbp_write(sc, 196, rt5592_bbp_r196[i]);
5297259032Skevlo		}
5298259032Skevlo	} else {
5299259032Skevlo		for (i = 0; i < nitems(rt5390_def_bbp); i++) {
5300259032Skevlo			run_bbp_write(sc, rt5390_def_bbp[i].reg,
5301259032Skevlo			    rt5390_def_bbp[i].val);
5302259032Skevlo		}
5303257955Skevlo	}
5304257955Skevlo	if (sc->mac_ver == 0x5392) {
5305257955Skevlo		run_bbp_write(sc, 88, 0x90);
5306257955Skevlo		run_bbp_write(sc, 95, 0x9a);
5307257955Skevlo		run_bbp_write(sc, 98, 0x12);
5308257955Skevlo		run_bbp_write(sc, 106, 0x12);
5309257955Skevlo		run_bbp_write(sc, 134, 0xd0);
5310257955Skevlo		run_bbp_write(sc, 135, 0xf6);
5311257955Skevlo		run_bbp_write(sc, 148, 0x84);
5312257955Skevlo	}
5313257955Skevlo
5314259032Skevlo	run_bbp_read(sc, 152, &bbp);
5315259032Skevlo	run_bbp_write(sc, 152, bbp | 0x80);
5316259032Skevlo
5317259032Skevlo	/* Fix BBP254 for RT5592C. */
5318259032Skevlo	if (sc->mac_ver == 0x5592 && sc->mac_rev >= 0x0221) {
5319259032Skevlo		run_bbp_read(sc, 254, &bbp);
5320259032Skevlo		run_bbp_write(sc, 254, bbp | 0x80);
5321259032Skevlo	}
5322259032Skevlo
5323257955Skevlo	/* Disable hardware antenna diversity. */
5324257955Skevlo	if (sc->mac_ver == 0x5390)
5325257955Skevlo		run_bbp_write(sc, 154, 0);
5326259032Skevlo
5327259032Skevlo	/* Initialize Rx CCK/OFDM frequency offset report. */
5328259032Skevlo	run_bbp_write(sc, 142, 1);
5329259032Skevlo	run_bbp_write(sc, 143, 57);
5330257955Skevlo}
5331257955Skevlo
5332203134Sthompsastatic int
5333203134Sthompsarun_bbp_init(struct run_softc *sc)
5334203134Sthompsa{
5335203134Sthompsa	int i, error, ntries;
5336203134Sthompsa	uint8_t bbp0;
5337203134Sthompsa
5338203134Sthompsa	/* wait for BBP to wake up */
5339203134Sthompsa	for (ntries = 0; ntries < 20; ntries++) {
5340203134Sthompsa		if ((error = run_bbp_read(sc, 0, &bbp0)) != 0)
5341203134Sthompsa			return error;
5342203134Sthompsa		if (bbp0 != 0 && bbp0 != 0xff)
5343203134Sthompsa			break;
5344203134Sthompsa	}
5345203134Sthompsa	if (ntries == 20)
5346209917Sthompsa		return (ETIMEDOUT);
5347203134Sthompsa
5348203134Sthompsa	/* initialize BBP registers to default values */
5349257955Skevlo	if (sc->mac_ver >= 0x5390)
5350257955Skevlo		run_rt5390_bbp_init(sc);
5351257955Skevlo	else {
5352257955Skevlo		for (i = 0; i < nitems(rt2860_def_bbp); i++) {
5353257955Skevlo			run_bbp_write(sc, rt2860_def_bbp[i].reg,
5354257955Skevlo			    rt2860_def_bbp[i].val);
5355257955Skevlo		}
5356203134Sthompsa	}
5357203134Sthompsa
5358260219Skevlo	if (sc->mac_ver == 0x3593) {
5359260219Skevlo		run_bbp_write(sc, 79, 0x13);
5360260219Skevlo		run_bbp_write(sc, 80, 0x05);
5361260219Skevlo		run_bbp_write(sc, 81, 0x33);
5362260219Skevlo		run_bbp_write(sc, 86, 0x46);
5363260219Skevlo		run_bbp_write(sc, 137, 0x0f);
5364260219Skevlo	}
5365260219Skevlo
5366203134Sthompsa	/* fix BBP84 for RT2860E */
5367205042Sthompsa	if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0101)
5368205042Sthompsa		run_bbp_write(sc, 84, 0x19);
5369203134Sthompsa
5370260219Skevlo	if (sc->mac_ver >= 0x3070 && (sc->mac_ver != 0x3593 &&
5371260219Skevlo	    sc->mac_ver != 0x5592)) {
5372203134Sthompsa		run_bbp_write(sc, 79, 0x13);
5373203134Sthompsa		run_bbp_write(sc, 80, 0x05);
5374203134Sthompsa		run_bbp_write(sc, 81, 0x33);
5375205042Sthompsa	} else if (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) {
5376203134Sthompsa		run_bbp_write(sc, 69, 0x16);
5377203134Sthompsa		run_bbp_write(sc, 73, 0x12);
5378203134Sthompsa	}
5379209917Sthompsa	return (0);
5380203134Sthompsa}
5381203134Sthompsa
5382203134Sthompsastatic int
5383203134Sthompsarun_rt3070_rf_init(struct run_softc *sc)
5384203134Sthompsa{
5385203134Sthompsa	uint32_t tmp;
5386256722Skevlo	uint8_t bbp4, mingain, rf, target;
5387203134Sthompsa	int i;
5388203134Sthompsa
5389203134Sthompsa	run_rt3070_rf_read(sc, 30, &rf);
5390203134Sthompsa	/* toggle RF R30 bit 7 */
5391203134Sthompsa	run_rt3070_rf_write(sc, 30, rf | 0x80);
5392203134Sthompsa	run_delay(sc, 10);
5393203134Sthompsa	run_rt3070_rf_write(sc, 30, rf & ~0x80);
5394203134Sthompsa
5395203134Sthompsa	/* initialize RF registers to default value */
5396205042Sthompsa	if (sc->mac_ver == 0x3572) {
5397257955Skevlo		for (i = 0; i < nitems(rt3572_def_rf); i++) {
5398205042Sthompsa			run_rt3070_rf_write(sc, rt3572_def_rf[i].reg,
5399205042Sthompsa			    rt3572_def_rf[i].val);
5400205042Sthompsa		}
5401205042Sthompsa	} else {
5402257955Skevlo		for (i = 0; i < nitems(rt3070_def_rf); i++) {
5403205042Sthompsa			run_rt3070_rf_write(sc, rt3070_def_rf[i].reg,
5404205042Sthompsa			    rt3070_def_rf[i].val);
5405205042Sthompsa		}
5406203134Sthompsa	}
5407205042Sthompsa
5408256721Skevlo	if (sc->mac_ver == 0x3070 && sc->mac_rev < 0x0201) {
5409256721Skevlo		/*
5410256721Skevlo		 * Change voltage from 1.2V to 1.35V for RT3070.
5411256721Skevlo		 * The DAC issue (RT3070_LDO_CFG0) has been fixed
5412256721Skevlo		 * in RT3070(F).
5413256721Skevlo		 */
5414203134Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5415203134Sthompsa		tmp = (tmp & ~0x0f000000) | 0x0d000000;
5416203134Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5417203134Sthompsa
5418205042Sthompsa	} else if (sc->mac_ver == 0x3071) {
5419203134Sthompsa		run_rt3070_rf_read(sc, 6, &rf);
5420203134Sthompsa		run_rt3070_rf_write(sc, 6, rf | 0x40);
5421203134Sthompsa		run_rt3070_rf_write(sc, 31, 0x14);
5422203134Sthompsa
5423203134Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5424203134Sthompsa		tmp &= ~0x1f000000;
5425205042Sthompsa		if (sc->mac_rev < 0x0211)
5426205042Sthompsa			tmp |= 0x0d000000;	/* 1.3V */
5427203134Sthompsa		else
5428205042Sthompsa			tmp |= 0x01000000;	/* 1.2V */
5429203134Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5430203134Sthompsa
5431203134Sthompsa		/* patch LNA_PE_G1 */
5432203134Sthompsa		run_read(sc, RT3070_GPIO_SWITCH, &tmp);
5433203134Sthompsa		run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20);
5434208019Sthompsa
5435209917Sthompsa	} else if (sc->mac_ver == 0x3572) {
5436205042Sthompsa		run_rt3070_rf_read(sc, 6, &rf);
5437205042Sthompsa		run_rt3070_rf_write(sc, 6, rf | 0x40);
5438205042Sthompsa
5439208019Sthompsa		/* increase voltage from 1.2V to 1.35V */
5440208019Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5441208019Sthompsa		tmp = (tmp & ~0x1f000000) | 0x0d000000;
5442208019Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5443203134Sthompsa
5444209917Sthompsa		if (sc->mac_rev < 0x0211 || !sc->patch_dac) {
5445203134Sthompsa			run_delay(sc, 1);	/* wait for 1msec */
5446205042Sthompsa			/* decrease voltage back to 1.2V */
5447203134Sthompsa			tmp = (tmp & ~0x1f000000) | 0x01000000;
5448203134Sthompsa			run_write(sc, RT3070_LDO_CFG0, tmp);
5449203134Sthompsa		}
5450203134Sthompsa	}
5451203134Sthompsa
5452203134Sthompsa	/* select 20MHz bandwidth */
5453203134Sthompsa	run_rt3070_rf_read(sc, 31, &rf);
5454203134Sthompsa	run_rt3070_rf_write(sc, 31, rf & ~0x20);
5455203134Sthompsa
5456203134Sthompsa	/* calibrate filter for 20MHz bandwidth */
5457203134Sthompsa	sc->rf24_20mhz = 0x1f;	/* default value */
5458205042Sthompsa	target = (sc->mac_ver < 0x3071) ? 0x16 : 0x13;
5459205042Sthompsa	run_rt3070_filter_calib(sc, 0x07, target, &sc->rf24_20mhz);
5460203134Sthompsa
5461203134Sthompsa	/* select 40MHz bandwidth */
5462203134Sthompsa	run_bbp_read(sc, 4, &bbp4);
5463256721Skevlo	run_bbp_write(sc, 4, (bbp4 & ~0x18) | 0x10);
5464205042Sthompsa	run_rt3070_rf_read(sc, 31, &rf);
5465205042Sthompsa	run_rt3070_rf_write(sc, 31, rf | 0x20);
5466203134Sthompsa
5467203134Sthompsa	/* calibrate filter for 40MHz bandwidth */
5468203134Sthompsa	sc->rf24_40mhz = 0x2f;	/* default value */
5469205042Sthompsa	target = (sc->mac_ver < 0x3071) ? 0x19 : 0x15;
5470205042Sthompsa	run_rt3070_filter_calib(sc, 0x27, target, &sc->rf24_40mhz);
5471203134Sthompsa
5472203134Sthompsa	/* go back to 20MHz bandwidth */
5473203134Sthompsa	run_bbp_read(sc, 4, &bbp4);
5474203134Sthompsa	run_bbp_write(sc, 4, bbp4 & ~0x18);
5475203134Sthompsa
5476205042Sthompsa	if (sc->mac_ver == 0x3572) {
5477205042Sthompsa		/* save default BBP registers 25 and 26 values */
5478205042Sthompsa		run_bbp_read(sc, 25, &sc->bbp25);
5479205042Sthompsa		run_bbp_read(sc, 26, &sc->bbp26);
5480256721Skevlo	} else if (sc->mac_rev < 0x0201 || sc->mac_rev < 0x0211)
5481203134Sthompsa		run_rt3070_rf_write(sc, 27, 0x03);
5482203134Sthompsa
5483203134Sthompsa	run_read(sc, RT3070_OPT_14, &tmp);
5484203134Sthompsa	run_write(sc, RT3070_OPT_14, tmp | 1);
5485203134Sthompsa
5486205042Sthompsa	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
5487205042Sthompsa		run_rt3070_rf_read(sc, 17, &rf);
5488205042Sthompsa		rf &= ~RT3070_TX_LO1;
5489205042Sthompsa		if ((sc->mac_ver == 0x3070 ||
5490205042Sthompsa		     (sc->mac_ver == 0x3071 && sc->mac_rev >= 0x0211)) &&
5491205042Sthompsa		    !sc->ext_2ghz_lna)
5492205042Sthompsa			rf |= 0x20;	/* fix for long range Rx issue */
5493256722Skevlo		mingain = (sc->mac_ver == 0x3070) ? 1 : 2;
5494256722Skevlo		if (sc->txmixgain_2ghz >= mingain)
5495205042Sthompsa			rf = (rf & ~0x7) | sc->txmixgain_2ghz;
5496205042Sthompsa		run_rt3070_rf_write(sc, 17, rf);
5497205042Sthompsa	}
5498205042Sthompsa
5499270643Skevlo	if (sc->mac_ver == 0x3071) {
5500203134Sthompsa		run_rt3070_rf_read(sc, 1, &rf);
5501203134Sthompsa		rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD);
5502203134Sthompsa		rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD;
5503203134Sthompsa		run_rt3070_rf_write(sc, 1, rf);
5504203134Sthompsa
5505203134Sthompsa		run_rt3070_rf_read(sc, 15, &rf);
5506203134Sthompsa		run_rt3070_rf_write(sc, 15, rf & ~RT3070_TX_LO2);
5507203134Sthompsa
5508203134Sthompsa		run_rt3070_rf_read(sc, 20, &rf);
5509203134Sthompsa		run_rt3070_rf_write(sc, 20, rf & ~RT3070_RX_LO1);
5510203134Sthompsa
5511203134Sthompsa		run_rt3070_rf_read(sc, 21, &rf);
5512203134Sthompsa		run_rt3070_rf_write(sc, 21, rf & ~RT3070_RX_LO2);
5513205042Sthompsa	}
5514203134Sthompsa
5515205042Sthompsa	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
5516205042Sthompsa		/* fix Tx to Rx IQ glitch by raising RF voltage */
5517203134Sthompsa		run_rt3070_rf_read(sc, 27, &rf);
5518203134Sthompsa		rf &= ~0x77;
5519205042Sthompsa		if (sc->mac_rev < 0x0211)
5520203134Sthompsa			rf |= 0x03;
5521203134Sthompsa		run_rt3070_rf_write(sc, 27, rf);
5522203134Sthompsa	}
5523209917Sthompsa	return (0);
5524203134Sthompsa}
5525203134Sthompsa
5526257955Skevlostatic void
5527260219Skevlorun_rt3593_rf_init(struct run_softc *sc)
5528260219Skevlo{
5529260219Skevlo	uint32_t tmp;
5530260219Skevlo	uint8_t rf;
5531260219Skevlo	int i;
5532260219Skevlo
5533260219Skevlo	/* Disable the GPIO bits 4 and 7 for LNA PE control. */
5534260219Skevlo	run_read(sc, RT3070_GPIO_SWITCH, &tmp);
5535260219Skevlo	tmp &= ~(1 << 4 | 1 << 7);
5536260219Skevlo	run_write(sc, RT3070_GPIO_SWITCH, tmp);
5537260219Skevlo
5538260219Skevlo	/* Initialize RF registers to default value. */
5539260219Skevlo	for (i = 0; i < nitems(rt3593_def_rf); i++) {
5540260219Skevlo		run_rt3070_rf_write(sc, rt3593_def_rf[i].reg,
5541260219Skevlo		    rt3593_def_rf[i].val);
5542260219Skevlo	}
5543260219Skevlo
5544260219Skevlo	/* Toggle RF R2 to initiate calibration. */
5545260219Skevlo	run_rt3070_rf_write(sc, 2, RT5390_RESCAL);
5546260219Skevlo
5547260219Skevlo	/* Initialize RF frequency offset. */
5548260219Skevlo	run_adjust_freq_offset(sc);
5549260219Skevlo
5550260219Skevlo	run_rt3070_rf_read(sc, 18, &rf);
5551260219Skevlo	run_rt3070_rf_write(sc, 18, rf | RT3593_AUTOTUNE_BYPASS);
5552260219Skevlo
5553260219Skevlo	/*
5554260219Skevlo	 * Increase voltage from 1.2V to 1.35V, wait for 1 msec to
5555260219Skevlo	 * decrease voltage back to 1.2V.
5556260219Skevlo	 */
5557260219Skevlo	run_read(sc, RT3070_LDO_CFG0, &tmp);
5558260219Skevlo	tmp = (tmp & ~0x1f000000) | 0x0d000000;
5559260219Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
5560260219Skevlo	run_delay(sc, 1);
5561260219Skevlo	tmp = (tmp & ~0x1f000000) | 0x01000000;
5562260219Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
5563260219Skevlo
5564260219Skevlo	sc->rf24_20mhz = 0x1f;
5565260219Skevlo	sc->rf24_40mhz = 0x2f;
5566260219Skevlo
5567260219Skevlo	/* Save default BBP registers 25 and 26 values. */
5568260219Skevlo	run_bbp_read(sc, 25, &sc->bbp25);
5569260219Skevlo	run_bbp_read(sc, 26, &sc->bbp26);
5570260219Skevlo
5571260219Skevlo	run_read(sc, RT3070_OPT_14, &tmp);
5572260219Skevlo	run_write(sc, RT3070_OPT_14, tmp | 1);
5573260219Skevlo}
5574260219Skevlo
5575260219Skevlostatic void
5576257955Skevlorun_rt5390_rf_init(struct run_softc *sc)
5577257955Skevlo{
5578257955Skevlo	uint32_t tmp;
5579257955Skevlo	uint8_t rf;
5580257955Skevlo	int i;
5581257955Skevlo
5582259030Skevlo	/* Toggle RF R2 to initiate calibration. */
5583259030Skevlo	if (sc->mac_ver == 0x5390) {
5584257955Skevlo		run_rt3070_rf_read(sc, 2, &rf);
5585259031Skevlo		run_rt3070_rf_write(sc, 2, rf | RT5390_RESCAL);
5586257955Skevlo		run_delay(sc, 10);
5587259031Skevlo		run_rt3070_rf_write(sc, 2, rf & ~RT5390_RESCAL);
5588259030Skevlo	} else {
5589259031Skevlo		run_rt3070_rf_write(sc, 2, RT5390_RESCAL);
5590259030Skevlo		run_delay(sc, 10);
5591257955Skevlo	}
5592257955Skevlo
5593257955Skevlo	/* Initialize RF registers to default value. */
5594259032Skevlo	if (sc->mac_ver == 0x5592) {
5595259032Skevlo		for (i = 0; i < nitems(rt5592_def_rf); i++) {
5596259032Skevlo			run_rt3070_rf_write(sc, rt5592_def_rf[i].reg,
5597259032Skevlo			    rt5592_def_rf[i].val);
5598259032Skevlo		}
5599259032Skevlo		/* Initialize RF frequency offset. */
5600259032Skevlo		run_adjust_freq_offset(sc);
5601259032Skevlo	} else if (sc->mac_ver == 0x5392) {
5602257955Skevlo		for (i = 0; i < nitems(rt5392_def_rf); i++) {
5603257955Skevlo			run_rt3070_rf_write(sc, rt5392_def_rf[i].reg,
5604257955Skevlo			    rt5392_def_rf[i].val);
5605257955Skevlo		}
5606257955Skevlo		if (sc->mac_rev >= 0x0223) {
5607257955Skevlo			run_rt3070_rf_write(sc, 23, 0x0f);
5608257955Skevlo			run_rt3070_rf_write(sc, 24, 0x3e);
5609257955Skevlo			run_rt3070_rf_write(sc, 51, 0x32);
5610257955Skevlo			run_rt3070_rf_write(sc, 53, 0x22);
5611257955Skevlo			run_rt3070_rf_write(sc, 56, 0xc1);
5612257955Skevlo			run_rt3070_rf_write(sc, 59, 0x0f);
5613257955Skevlo		}
5614257955Skevlo	} else {
5615257955Skevlo		for (i = 0; i < nitems(rt5390_def_rf); i++) {
5616257955Skevlo			run_rt3070_rf_write(sc, rt5390_def_rf[i].reg,
5617257955Skevlo			    rt5390_def_rf[i].val);
5618257955Skevlo		}
5619257955Skevlo		if (sc->mac_rev >= 0x0502) {
5620257955Skevlo			run_rt3070_rf_write(sc, 6, 0xe0);
5621257955Skevlo			run_rt3070_rf_write(sc, 25, 0x80);
5622257955Skevlo			run_rt3070_rf_write(sc, 46, 0x73);
5623257955Skevlo			run_rt3070_rf_write(sc, 53, 0x00);
5624257955Skevlo			run_rt3070_rf_write(sc, 56, 0x42);
5625257955Skevlo			run_rt3070_rf_write(sc, 61, 0xd1);
5626257955Skevlo		}
5627257955Skevlo	}
5628257955Skevlo
5629257955Skevlo	sc->rf24_20mhz = 0x1f;	/* default value */
5630259032Skevlo	sc->rf24_40mhz = (sc->mac_ver == 0x5592) ? 0 : 0x2f;
5631257955Skevlo
5632257955Skevlo	if (sc->mac_rev < 0x0211)
5633257955Skevlo		run_rt3070_rf_write(sc, 27, 0x3);
5634257955Skevlo
5635257955Skevlo	run_read(sc, RT3070_OPT_14, &tmp);
5636257955Skevlo	run_write(sc, RT3070_OPT_14, tmp | 1);
5637257955Skevlo}
5638257955Skevlo
5639203134Sthompsastatic int
5640203134Sthompsarun_rt3070_filter_calib(struct run_softc *sc, uint8_t init, uint8_t target,
5641203134Sthompsa    uint8_t *val)
5642203134Sthompsa{
5643203134Sthompsa	uint8_t rf22, rf24;
5644203134Sthompsa	uint8_t bbp55_pb, bbp55_sb, delta;
5645203134Sthompsa	int ntries;
5646203134Sthompsa
5647203134Sthompsa	/* program filter */
5648205042Sthompsa	run_rt3070_rf_read(sc, 24, &rf24);
5649205042Sthompsa	rf24 = (rf24 & 0xc0) | init;	/* initial filter value */
5650203134Sthompsa	run_rt3070_rf_write(sc, 24, rf24);
5651203134Sthompsa
5652203134Sthompsa	/* enable baseband loopback mode */
5653203134Sthompsa	run_rt3070_rf_read(sc, 22, &rf22);
5654203134Sthompsa	run_rt3070_rf_write(sc, 22, rf22 | 0x01);
5655203134Sthompsa
5656203134Sthompsa	/* set power and frequency of passband test tone */
5657203134Sthompsa	run_bbp_write(sc, 24, 0x00);
5658203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5659203134Sthompsa		/* transmit test tone */
5660203134Sthompsa		run_bbp_write(sc, 25, 0x90);
5661203134Sthompsa		run_delay(sc, 10);
5662203134Sthompsa		/* read received power */
5663203134Sthompsa		run_bbp_read(sc, 55, &bbp55_pb);
5664203134Sthompsa		if (bbp55_pb != 0)
5665203134Sthompsa			break;
5666203134Sthompsa	}
5667203134Sthompsa	if (ntries == 100)
5668257955Skevlo		return (ETIMEDOUT);
5669203134Sthompsa
5670203134Sthompsa	/* set power and frequency of stopband test tone */
5671203134Sthompsa	run_bbp_write(sc, 24, 0x06);
5672203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5673203134Sthompsa		/* transmit test tone */
5674203134Sthompsa		run_bbp_write(sc, 25, 0x90);
5675203134Sthompsa		run_delay(sc, 10);
5676203134Sthompsa		/* read received power */
5677203134Sthompsa		run_bbp_read(sc, 55, &bbp55_sb);
5678203134Sthompsa
5679203134Sthompsa		delta = bbp55_pb - bbp55_sb;
5680203134Sthompsa		if (delta > target)
5681203134Sthompsa			break;
5682203134Sthompsa
5683203134Sthompsa		/* reprogram filter */
5684203134Sthompsa		rf24++;
5685203134Sthompsa		run_rt3070_rf_write(sc, 24, rf24);
5686203134Sthompsa	}
5687203134Sthompsa	if (ntries < 100) {
5688203134Sthompsa		if (rf24 != init)
5689203134Sthompsa			rf24--;	/* backtrack */
5690203134Sthompsa		*val = rf24;
5691203134Sthompsa		run_rt3070_rf_write(sc, 24, rf24);
5692203134Sthompsa	}
5693203134Sthompsa
5694203134Sthompsa	/* restore initial state */
5695203134Sthompsa	run_bbp_write(sc, 24, 0x00);
5696203134Sthompsa
5697203134Sthompsa	/* disable baseband loopback mode */
5698203134Sthompsa	run_rt3070_rf_read(sc, 22, &rf22);
5699203134Sthompsa	run_rt3070_rf_write(sc, 22, rf22 & ~0x01);
5700203134Sthompsa
5701209917Sthompsa	return (0);
5702203134Sthompsa}
5703203134Sthompsa
5704205042Sthompsastatic void
5705205042Sthompsarun_rt3070_rf_setup(struct run_softc *sc)
5706205042Sthompsa{
5707205042Sthompsa	uint8_t bbp, rf;
5708205042Sthompsa	int i;
5709205042Sthompsa
5710260219Skevlo	if (sc->mac_ver == 0x3572) {
5711205042Sthompsa		/* enable DC filter */
5712205042Sthompsa		if (sc->mac_rev >= 0x0201)
5713205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5714205042Sthompsa
5715205042Sthompsa		run_bbp_read(sc, 138, &bbp);
5716205042Sthompsa		if (sc->ntxchains == 1)
5717205042Sthompsa			bbp |= 0x20;	/* turn off DAC1 */
5718205042Sthompsa		if (sc->nrxchains == 1)
5719205042Sthompsa			bbp &= ~0x02;	/* turn off ADC1 */
5720205042Sthompsa		run_bbp_write(sc, 138, bbp);
5721205042Sthompsa
5722205042Sthompsa		if (sc->mac_rev >= 0x0211) {
5723205042Sthompsa			/* improve power consumption */
5724205042Sthompsa			run_bbp_read(sc, 31, &bbp);
5725205042Sthompsa			run_bbp_write(sc, 31, bbp & ~0x03);
5726205042Sthompsa		}
5727205042Sthompsa
5728205042Sthompsa		run_rt3070_rf_read(sc, 16, &rf);
5729205042Sthompsa		rf = (rf & ~0x07) | sc->txmixgain_2ghz;
5730205042Sthompsa		run_rt3070_rf_write(sc, 16, rf);
5731205042Sthompsa
5732205042Sthompsa	} else if (sc->mac_ver == 0x3071) {
5733257409Skevlo		if (sc->mac_rev >= 0x0211) {
5734257409Skevlo			/* enable DC filter */
5735205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5736205042Sthompsa
5737257409Skevlo			/* improve power consumption */
5738257409Skevlo			run_bbp_read(sc, 31, &bbp);
5739257409Skevlo			run_bbp_write(sc, 31, bbp & ~0x03);
5740257409Skevlo		}
5741257409Skevlo
5742205042Sthompsa		run_bbp_read(sc, 138, &bbp);
5743205042Sthompsa		if (sc->ntxchains == 1)
5744205042Sthompsa			bbp |= 0x20;	/* turn off DAC1 */
5745205042Sthompsa		if (sc->nrxchains == 1)
5746205042Sthompsa			bbp &= ~0x02;	/* turn off ADC1 */
5747205042Sthompsa		run_bbp_write(sc, 138, bbp);
5748205042Sthompsa
5749205042Sthompsa		run_write(sc, RT2860_TX_SW_CFG1, 0);
5750205042Sthompsa		if (sc->mac_rev < 0x0211) {
5751205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2,
5752205042Sthompsa			    sc->patch_dac ? 0x2c : 0x0f);
5753205042Sthompsa		} else
5754205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0);
5755205042Sthompsa
5756205042Sthompsa	} else if (sc->mac_ver == 0x3070) {
5757205042Sthompsa		if (sc->mac_rev >= 0x0201) {
5758205042Sthompsa			/* enable DC filter */
5759205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5760205042Sthompsa
5761205042Sthompsa			/* improve power consumption */
5762205042Sthompsa			run_bbp_read(sc, 31, &bbp);
5763205042Sthompsa			run_bbp_write(sc, 31, bbp & ~0x03);
5764205042Sthompsa		}
5765205042Sthompsa
5766256955Skevlo		if (sc->mac_rev < 0x0201) {
5767205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG1, 0);
5768205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0x2c);
5769205042Sthompsa		} else
5770205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0);
5771205042Sthompsa	}
5772205042Sthompsa
5773205042Sthompsa	/* initialize RF registers from ROM for >=RT3071*/
5774260219Skevlo	if (sc->mac_ver >= 0x3071) {
5775205042Sthompsa		for (i = 0; i < 10; i++) {
5776205042Sthompsa			if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff)
5777205042Sthompsa				continue;
5778205042Sthompsa			run_rt3070_rf_write(sc, sc->rf[i].reg, sc->rf[i].val);
5779205042Sthompsa		}
5780205042Sthompsa	}
5781205042Sthompsa}
5782205042Sthompsa
5783260219Skevlostatic void
5784260219Skevlorun_rt3593_rf_setup(struct run_softc *sc)
5785260219Skevlo{
5786260219Skevlo	uint8_t bbp, rf;
5787260219Skevlo
5788260219Skevlo	if (sc->mac_rev >= 0x0211) {
5789260219Skevlo		/* Enable DC filter. */
5790260219Skevlo		run_bbp_write(sc, 103, 0xc0);
5791260219Skevlo	}
5792260219Skevlo	run_write(sc, RT2860_TX_SW_CFG1, 0);
5793260219Skevlo	if (sc->mac_rev < 0x0211) {
5794260219Skevlo		run_write(sc, RT2860_TX_SW_CFG2,
5795260219Skevlo		    sc->patch_dac ? 0x2c : 0x0f);
5796260219Skevlo	} else
5797260219Skevlo		run_write(sc, RT2860_TX_SW_CFG2, 0);
5798260219Skevlo
5799260219Skevlo	run_rt3070_rf_read(sc, 50, &rf);
5800260219Skevlo	run_rt3070_rf_write(sc, 50, rf & ~RT3593_TX_LO2);
5801260219Skevlo
5802260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
5803260219Skevlo	rf = (rf & ~(RT3593_TX_LO1 | 0x0c)) |
5804260219Skevlo	    ((sc->txmixgain_2ghz & 0x07) << 2);
5805260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
5806260219Skevlo
5807260219Skevlo	run_rt3070_rf_read(sc, 38, &rf);
5808260219Skevlo	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
5809260219Skevlo
5810260219Skevlo	run_rt3070_rf_read(sc, 39, &rf);
5811260219Skevlo	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
5812260219Skevlo
5813260219Skevlo	run_rt3070_rf_read(sc, 1, &rf);
5814260219Skevlo	run_rt3070_rf_write(sc, 1, rf & ~(RT3070_RF_BLOCK | RT3070_PLL_PD));
5815260219Skevlo
5816260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
5817260219Skevlo	rf = (rf & ~0x18) | 0x10;
5818260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
5819260219Skevlo
5820260219Skevlo	/* Apply maximum likelihood detection for 2 stream case. */
5821260219Skevlo	run_bbp_read(sc, 105, &bbp);
5822260219Skevlo	if (sc->nrxchains > 1)
5823260219Skevlo		run_bbp_write(sc, 105, bbp | RT5390_MLD);
5824260219Skevlo
5825260219Skevlo	/* Avoid data lost and CRC error. */
5826260219Skevlo	run_bbp_read(sc, 4, &bbp);
5827260219Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5828260219Skevlo
5829260219Skevlo	run_bbp_write(sc, 92, 0x02);
5830260219Skevlo	run_bbp_write(sc, 82, 0x82);
5831260219Skevlo	run_bbp_write(sc, 106, 0x05);
5832260219Skevlo	run_bbp_write(sc, 104, 0x92);
5833260219Skevlo	run_bbp_write(sc, 88, 0x90);
5834260219Skevlo	run_bbp_write(sc, 148, 0xc8);
5835260219Skevlo	run_bbp_write(sc, 47, 0x48);
5836260219Skevlo	run_bbp_write(sc, 120, 0x50);
5837260219Skevlo
5838260219Skevlo	run_bbp_write(sc, 163, 0x9d);
5839260219Skevlo
5840260219Skevlo	/* SNR mapping. */
5841260219Skevlo	run_bbp_write(sc, 142, 0x06);
5842260219Skevlo	run_bbp_write(sc, 143, 0xa0);
5843260219Skevlo	run_bbp_write(sc, 142, 0x07);
5844260219Skevlo	run_bbp_write(sc, 143, 0xa1);
5845260219Skevlo	run_bbp_write(sc, 142, 0x08);
5846260219Skevlo	run_bbp_write(sc, 143, 0xa2);
5847260219Skevlo
5848260219Skevlo	run_bbp_write(sc, 31, 0x08);
5849260219Skevlo	run_bbp_write(sc, 68, 0x0b);
5850260219Skevlo	run_bbp_write(sc, 105, 0x04);
5851260219Skevlo}
5852260219Skevlo
5853260219Skevlostatic void
5854260219Skevlorun_rt5390_rf_setup(struct run_softc *sc)
5855260219Skevlo{
5856260219Skevlo	uint8_t bbp, rf;
5857260219Skevlo
5858260219Skevlo	if (sc->mac_rev >= 0x0211) {
5859260219Skevlo		/* Enable DC filter. */
5860260219Skevlo		run_bbp_write(sc, 103, 0xc0);
5861260219Skevlo
5862260219Skevlo		if (sc->mac_ver != 0x5592) {
5863260219Skevlo			/* Improve power consumption. */
5864260219Skevlo			run_bbp_read(sc, 31, &bbp);
5865260219Skevlo			run_bbp_write(sc, 31, bbp & ~0x03);
5866260219Skevlo		}
5867260219Skevlo	}
5868260219Skevlo
5869260219Skevlo	run_bbp_read(sc, 138, &bbp);
5870260219Skevlo	if (sc->ntxchains == 1)
5871260219Skevlo		bbp |= 0x20;	/* turn off DAC1 */
5872260219Skevlo	if (sc->nrxchains == 1)
5873260219Skevlo		bbp &= ~0x02;	/* turn off ADC1 */
5874260219Skevlo	run_bbp_write(sc, 138, bbp);
5875260219Skevlo
5876260219Skevlo	run_rt3070_rf_read(sc, 38, &rf);
5877260219Skevlo	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
5878260219Skevlo
5879260219Skevlo	run_rt3070_rf_read(sc, 39, &rf);
5880260219Skevlo	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
5881260219Skevlo
5882260219Skevlo	/* Avoid data lost and CRC error. */
5883260219Skevlo	run_bbp_read(sc, 4, &bbp);
5884260219Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5885260219Skevlo
5886260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
5887260219Skevlo	rf = (rf & ~0x18) | 0x10;
5888260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
5889260219Skevlo
5890260219Skevlo	if (sc->mac_ver != 0x5592) {
5891260219Skevlo		run_write(sc, RT2860_TX_SW_CFG1, 0);
5892260219Skevlo		if (sc->mac_rev < 0x0211) {
5893260219Skevlo			run_write(sc, RT2860_TX_SW_CFG2,
5894260219Skevlo			    sc->patch_dac ? 0x2c : 0x0f);
5895260219Skevlo		} else
5896260219Skevlo			run_write(sc, RT2860_TX_SW_CFG2, 0);
5897260219Skevlo	}
5898260219Skevlo}
5899260219Skevlo
5900203134Sthompsastatic int
5901203134Sthompsarun_txrx_enable(struct run_softc *sc)
5902203134Sthompsa{
5903203134Sthompsa	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
5904203134Sthompsa	uint32_t tmp;
5905203134Sthompsa	int error, ntries;
5906203134Sthompsa
5907203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_TX_EN);
5908203134Sthompsa	for (ntries = 0; ntries < 200; ntries++) {
5909203134Sthompsa		if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0)
5910257955Skevlo			return (error);
5911203134Sthompsa		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
5912203134Sthompsa			break;
5913203134Sthompsa		run_delay(sc, 50);
5914203134Sthompsa	}
5915203134Sthompsa	if (ntries == 200)
5916257955Skevlo		return (ETIMEDOUT);
5917203134Sthompsa
5918203134Sthompsa	run_delay(sc, 50);
5919203134Sthompsa
5920203134Sthompsa	tmp |= RT2860_RX_DMA_EN | RT2860_TX_DMA_EN | RT2860_TX_WB_DDONE;
5921203134Sthompsa	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
5922203134Sthompsa
5923203134Sthompsa	/* enable Rx bulk aggregation (set timeout and limit) */
5924203134Sthompsa	tmp = RT2860_USB_TX_EN | RT2860_USB_RX_EN | RT2860_USB_RX_AGG_EN |
5925203134Sthompsa	    RT2860_USB_RX_AGG_TO(128) | RT2860_USB_RX_AGG_LMT(2);
5926203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, tmp);
5927203134Sthompsa
5928203134Sthompsa	/* set Rx filter */
5929203134Sthompsa	tmp = RT2860_DROP_CRC_ERR | RT2860_DROP_PHY_ERR;
5930203134Sthompsa	if (ic->ic_opmode != IEEE80211_M_MONITOR) {
5931203134Sthompsa		tmp |= RT2860_DROP_UC_NOME | RT2860_DROP_DUPL |
5932203134Sthompsa		    RT2860_DROP_CTS | RT2860_DROP_BA | RT2860_DROP_ACK |
5933203134Sthompsa		    RT2860_DROP_VER_ERR | RT2860_DROP_CTRL_RSV |
5934203134Sthompsa		    RT2860_DROP_CFACK | RT2860_DROP_CFEND;
5935203134Sthompsa		if (ic->ic_opmode == IEEE80211_M_STA)
5936203134Sthompsa			tmp |= RT2860_DROP_RTS | RT2860_DROP_PSPOLL;
5937203134Sthompsa	}
5938203134Sthompsa	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
5939203134Sthompsa
5940203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL,
5941203134Sthompsa	    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
5942203134Sthompsa
5943209917Sthompsa	return (0);
5944203134Sthompsa}
5945203134Sthompsa
5946203134Sthompsastatic void
5947259030Skevlorun_adjust_freq_offset(struct run_softc *sc)
5948257955Skevlo{
5949257955Skevlo	uint8_t rf, tmp;
5950257955Skevlo
5951257955Skevlo	run_rt3070_rf_read(sc, 17, &rf);
5952257955Skevlo	tmp = rf;
5953257955Skevlo	rf = (rf & ~0x7f) | (sc->freq & 0x7f);
5954257955Skevlo	rf = MIN(rf, 0x5f);
5955257955Skevlo
5956257955Skevlo	if (tmp != rf)
5957257955Skevlo		run_mcu_cmd(sc, 0x74, (tmp << 8 ) | rf);
5958257955Skevlo}
5959257955Skevlo
5960257955Skevlostatic void
5961203134Sthompsarun_init_locked(struct run_softc *sc)
5962203134Sthompsa{
5963203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
5964203134Sthompsa	struct ieee80211com *ic = ifp->if_l2com;
5965203134Sthompsa	uint32_t tmp;
5966203134Sthompsa	uint8_t bbp1, bbp3;
5967203134Sthompsa	int i;
5968203134Sthompsa	int ridx;
5969203134Sthompsa	int ntries;
5970203134Sthompsa
5971209917Sthompsa	if (ic->ic_nrunning > 1)
5972208019Sthompsa		return;
5973208019Sthompsa
5974203134Sthompsa	run_stop(sc);
5975203134Sthompsa
5976233283Sbschmidt	if (run_load_microcode(sc) != 0) {
5977233283Sbschmidt		device_printf(sc->sc_dev, "could not load 8051 microcode\n");
5978233283Sbschmidt		goto fail;
5979233283Sbschmidt	}
5980233283Sbschmidt
5981203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5982203134Sthompsa		if (run_read(sc, RT2860_ASIC_VER_ID, &tmp) != 0)
5983203134Sthompsa			goto fail;
5984203134Sthompsa		if (tmp != 0 && tmp != 0xffffffff)
5985203134Sthompsa			break;
5986203134Sthompsa		run_delay(sc, 10);
5987203134Sthompsa	}
5988203134Sthompsa	if (ntries == 100)
5989203134Sthompsa		goto fail;
5990203134Sthompsa
5991203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
5992203134Sthompsa		run_setup_tx_list(sc, &sc->sc_epq[i]);
5993203134Sthompsa
5994203134Sthompsa	run_set_macaddr(sc, IF_LLADDR(ifp));
5995203134Sthompsa
5996203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5997203134Sthompsa		if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
5998203134Sthompsa			goto fail;
5999203134Sthompsa		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
6000203134Sthompsa			break;
6001203134Sthompsa		run_delay(sc, 10);
6002203134Sthompsa	}
6003203134Sthompsa	if (ntries == 100) {
6004203138Sthompsa		device_printf(sc->sc_dev, "timeout waiting for DMA engine\n");
6005203134Sthompsa		goto fail;
6006203134Sthompsa	}
6007203134Sthompsa	tmp &= 0xff0;
6008203134Sthompsa	tmp |= RT2860_TX_WB_DDONE;
6009203134Sthompsa	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
6010203134Sthompsa
6011203134Sthompsa	/* turn off PME_OEN to solve high-current issue */
6012203134Sthompsa	run_read(sc, RT2860_SYS_CTRL, &tmp);
6013203134Sthompsa	run_write(sc, RT2860_SYS_CTRL, tmp & ~RT2860_PME_OEN);
6014203134Sthompsa
6015203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL,
6016203134Sthompsa	    RT2860_BBP_HRST | RT2860_MAC_SRST);
6017203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, 0);
6018203134Sthompsa
6019203134Sthompsa	if (run_reset(sc) != 0) {
6020203138Sthompsa		device_printf(sc->sc_dev, "could not reset chipset\n");
6021203134Sthompsa		goto fail;
6022203134Sthompsa	}
6023203134Sthompsa
6024203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
6025203134Sthompsa
6026203134Sthompsa	/* init Tx power for all Tx rates (from EEPROM) */
6027203134Sthompsa	for (ridx = 0; ridx < 5; ridx++) {
6028203134Sthompsa		if (sc->txpow20mhz[ridx] == 0xffffffff)
6029203134Sthompsa			continue;
6030203134Sthompsa		run_write(sc, RT2860_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]);
6031203134Sthompsa	}
6032203134Sthompsa
6033257955Skevlo	for (i = 0; i < nitems(rt2870_def_mac); i++)
6034203134Sthompsa		run_write(sc, rt2870_def_mac[i].reg, rt2870_def_mac[i].val);
6035203134Sthompsa	run_write(sc, RT2860_WMM_AIFSN_CFG, 0x00002273);
6036203134Sthompsa	run_write(sc, RT2860_WMM_CWMIN_CFG, 0x00002344);
6037203134Sthompsa	run_write(sc, RT2860_WMM_CWMAX_CFG, 0x000034aa);
6038203134Sthompsa
6039259030Skevlo	if (sc->mac_ver >= 0x5390) {
6040259030Skevlo		run_write(sc, RT2860_TX_SW_CFG0,
6041259030Skevlo		    4 << RT2860_DLY_PAPE_EN_SHIFT | 4);
6042259030Skevlo		if (sc->mac_ver >= 0x5392) {
6043259030Skevlo			run_write(sc, RT2860_MAX_LEN_CFG, 0x00002fff);
6044259032Skevlo			if (sc->mac_ver == 0x5592) {
6045259032Skevlo				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcba980);
6046259032Skevlo				run_write(sc, RT2860_TXOP_HLDR_ET, 0x00000082);
6047259032Skevlo			} else {
6048259032Skevlo				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcb4980);
6049259032Skevlo				run_write(sc, RT2860_LG_FBK_CFG0, 0xedcba322);
6050259032Skevlo			}
6051259030Skevlo		}
6052260219Skevlo	} else if (sc->mac_ver == 0x3593) {
6053260219Skevlo		run_write(sc, RT2860_TX_SW_CFG0,
6054260219Skevlo		    4 << RT2860_DLY_PAPE_EN_SHIFT | 2);
6055257955Skevlo	} else if (sc->mac_ver >= 0x3070) {
6056203134Sthompsa		/* set delay of PA_PE assertion to 1us (unit of 0.25us) */
6057203134Sthompsa		run_write(sc, RT2860_TX_SW_CFG0,
6058203134Sthompsa		    4 << RT2860_DLY_PAPE_EN_SHIFT);
6059203134Sthompsa	}
6060203134Sthompsa
6061203134Sthompsa	/* wait while MAC is busy */
6062203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
6063203134Sthompsa		if (run_read(sc, RT2860_MAC_STATUS_REG, &tmp) != 0)
6064203134Sthompsa			goto fail;
6065203134Sthompsa		if (!(tmp & (RT2860_RX_STATUS_BUSY | RT2860_TX_STATUS_BUSY)))
6066203134Sthompsa			break;
6067203134Sthompsa		run_delay(sc, 10);
6068203134Sthompsa	}
6069203134Sthompsa	if (ntries == 100)
6070203134Sthompsa		goto fail;
6071203134Sthompsa
6072203134Sthompsa	/* clear Host to MCU mailbox */
6073203134Sthompsa	run_write(sc, RT2860_H2M_BBPAGENT, 0);
6074203134Sthompsa	run_write(sc, RT2860_H2M_MAILBOX, 0);
6075203134Sthompsa	run_delay(sc, 10);
6076203134Sthompsa
6077203134Sthompsa	if (run_bbp_init(sc) != 0) {
6078203138Sthompsa		device_printf(sc->sc_dev, "could not initialize BBP\n");
6079203134Sthompsa		goto fail;
6080203134Sthompsa	}
6081203134Sthompsa
6082203134Sthompsa	/* abort TSF synchronization */
6083203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
6084203134Sthompsa	tmp &= ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
6085203134Sthompsa	    RT2860_TBTT_TIMER_EN);
6086203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
6087203134Sthompsa
6088203134Sthompsa	/* clear RX WCID search table */
6089203134Sthompsa	run_set_region_4(sc, RT2860_WCID_ENTRY(0), 0, 512);
6090203134Sthompsa	/* clear WCID attribute table */
6091203134Sthompsa	run_set_region_4(sc, RT2860_WCID_ATTR(0), 0, 8 * 32);
6092203134Sthompsa
6093209144Sthompsa	/* hostapd sets a key before init. So, don't clear it. */
6094209917Sthompsa	if (sc->cmdq_key_set != RUN_CMDQ_GO) {
6095209144Sthompsa		/* clear shared key table */
6096209144Sthompsa		run_set_region_4(sc, RT2860_SKEY(0, 0), 0, 8 * 32);
6097209144Sthompsa		/* clear shared key mode */
6098209144Sthompsa		run_set_region_4(sc, RT2860_SKEY_MODE_0_7, 0, 4);
6099209144Sthompsa	}
6100209144Sthompsa
6101203134Sthompsa	run_read(sc, RT2860_US_CYC_CNT, &tmp);
6102203134Sthompsa	tmp = (tmp & ~0xff) | 0x1e;
6103203134Sthompsa	run_write(sc, RT2860_US_CYC_CNT, tmp);
6104203134Sthompsa
6105205042Sthompsa	if (sc->mac_rev != 0x0101)
6106203134Sthompsa		run_write(sc, RT2860_TXOP_CTRL_CFG, 0x0000583f);
6107203134Sthompsa
6108203134Sthompsa	run_write(sc, RT2860_WMM_TXOP0_CFG, 0);
6109203134Sthompsa	run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96);
6110203134Sthompsa
6111203134Sthompsa	/* write vendor-specific BBP values (from EEPROM) */
6112260219Skevlo	if (sc->mac_ver < 0x3593) {
6113257955Skevlo		for (i = 0; i < 10; i++) {
6114257955Skevlo			if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff)
6115257955Skevlo				continue;
6116257955Skevlo			run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val);
6117257955Skevlo		}
6118203134Sthompsa	}
6119203134Sthompsa
6120203134Sthompsa	/* select Main antenna for 1T1R devices */
6121257955Skevlo	if (sc->rf_rev == RT3070_RF_3020 || sc->rf_rev == RT5390_RF_5370)
6122203134Sthompsa		run_set_rx_antenna(sc, 0);
6123203134Sthompsa
6124203134Sthompsa	/* send LEDs operating mode to microcontroller */
6125203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0]);
6126203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1]);
6127203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2]);
6128203134Sthompsa
6129257955Skevlo	if (sc->mac_ver >= 0x5390)
6130257955Skevlo		run_rt5390_rf_init(sc);
6131260219Skevlo	else if (sc->mac_ver == 0x3593)
6132260219Skevlo		run_rt3593_rf_init(sc);
6133257955Skevlo	else if (sc->mac_ver >= 0x3070)
6134205042Sthompsa		run_rt3070_rf_init(sc);
6135205042Sthompsa
6136203134Sthompsa	/* disable non-existing Rx chains */
6137203134Sthompsa	run_bbp_read(sc, 3, &bbp3);
6138203134Sthompsa	bbp3 &= ~(1 << 3 | 1 << 4);
6139203134Sthompsa	if (sc->nrxchains == 2)
6140203134Sthompsa		bbp3 |= 1 << 3;
6141203134Sthompsa	else if (sc->nrxchains == 3)
6142203134Sthompsa		bbp3 |= 1 << 4;
6143203134Sthompsa	run_bbp_write(sc, 3, bbp3);
6144203134Sthompsa
6145203134Sthompsa	/* disable non-existing Tx chains */
6146203134Sthompsa	run_bbp_read(sc, 1, &bbp1);
6147203134Sthompsa	if (sc->ntxchains == 1)
6148203134Sthompsa		bbp1 &= ~(1 << 3 | 1 << 4);
6149203134Sthompsa	run_bbp_write(sc, 1, bbp1);
6150203134Sthompsa
6151260219Skevlo	if (sc->mac_ver >= 0x5390)
6152260219Skevlo		run_rt5390_rf_setup(sc);
6153260219Skevlo	else if (sc->mac_ver == 0x3593)
6154260219Skevlo		run_rt3593_rf_setup(sc);
6155260219Skevlo	else if (sc->mac_ver >= 0x3070)
6156205042Sthompsa		run_rt3070_rf_setup(sc);
6157203134Sthompsa
6158203134Sthompsa	/* select default channel */
6159203134Sthompsa	run_set_chan(sc, ic->ic_curchan);
6160203134Sthompsa
6161203134Sthompsa	/* setup initial protection mode */
6162218492Sbschmidt	run_updateprot_cb(ic);
6163203134Sthompsa
6164203134Sthompsa	/* turn radio LED on */
6165203134Sthompsa	run_set_leds(sc, RT2860_LED_RADIO);
6166203134Sthompsa
6167203134Sthompsa	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
6168203134Sthompsa	ifp->if_drv_flags |= IFF_DRV_RUNNING;
6169208019Sthompsa	sc->cmdq_run = RUN_CMDQ_GO;
6170203134Sthompsa
6171209917Sthompsa	for (i = 0; i != RUN_N_XFER; i++)
6172203134Sthompsa		usbd_xfer_set_stall(sc->sc_xfer[i]);
6173203134Sthompsa
6174203134Sthompsa	usbd_transfer_start(sc->sc_xfer[RUN_BULK_RX]);
6175203134Sthompsa
6176203134Sthompsa	if (run_txrx_enable(sc) != 0)
6177203134Sthompsa		goto fail;
6178203134Sthompsa
6179203134Sthompsa	return;
6180203134Sthompsa
6181203134Sthompsafail:
6182203134Sthompsa	run_stop(sc);
6183203134Sthompsa}
6184203134Sthompsa
6185203134Sthompsastatic void
6186203134Sthompsarun_init(void *arg)
6187203134Sthompsa{
6188203134Sthompsa	struct run_softc *sc = arg;
6189203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
6190203134Sthompsa	struct ieee80211com *ic = ifp->if_l2com;
6191203134Sthompsa
6192203134Sthompsa	RUN_LOCK(sc);
6193203134Sthompsa	run_init_locked(sc);
6194203134Sthompsa	RUN_UNLOCK(sc);
6195203134Sthompsa
6196203134Sthompsa	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
6197208019Sthompsa		ieee80211_start_all(ic);
6198203134Sthompsa}
6199203134Sthompsa
6200203134Sthompsastatic void
6201203134Sthompsarun_stop(void *arg)
6202203134Sthompsa{
6203203134Sthompsa	struct run_softc *sc = (struct run_softc *)arg;
6204203134Sthompsa	struct ifnet *ifp = sc->sc_ifp;
6205203134Sthompsa	uint32_t tmp;
6206203134Sthompsa	int i;
6207203134Sthompsa	int ntries;
6208203134Sthompsa
6209203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
6210203134Sthompsa
6211203134Sthompsa	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
6212203134Sthompsa		run_set_leds(sc, 0);	/* turn all LEDs off */
6213203134Sthompsa
6214203134Sthompsa	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
6215203134Sthompsa
6216208019Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
6217209144Sthompsa	sc->cmdq_run = sc->cmdq_key_set;
6218208019Sthompsa
6219203134Sthompsa	RUN_UNLOCK(sc);
6220203134Sthompsa
6221203134Sthompsa	for(i = 0; i < RUN_N_XFER; i++)
6222203134Sthompsa		usbd_transfer_drain(sc->sc_xfer[i]);
6223203134Sthompsa
6224203134Sthompsa	RUN_LOCK(sc);
6225203134Sthompsa
6226209917Sthompsa	if (sc->rx_m != NULL) {
6227203134Sthompsa		m_free(sc->rx_m);
6228203134Sthompsa		sc->rx_m = NULL;
6229203134Sthompsa	}
6230203134Sthompsa
6231257955Skevlo	/* Disable Tx/Rx DMA. */
6232257955Skevlo	if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
6233257955Skevlo		return;
6234257955Skevlo	tmp &= ~(RT2860_RX_DMA_EN | RT2860_TX_DMA_EN);
6235257955Skevlo	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
6236257955Skevlo
6237258643Shselasky	for (ntries = 0; ntries < 100; ntries++) {
6238257955Skevlo		if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
6239257955Skevlo			return;
6240257955Skevlo		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
6241257955Skevlo				break;
6242257955Skevlo		run_delay(sc, 10);
6243257955Skevlo	}
6244257955Skevlo	if (ntries == 100) {
6245257955Skevlo		device_printf(sc->sc_dev, "timeout waiting for DMA engine\n");
6246257955Skevlo		return;
6247257955Skevlo	}
6248257955Skevlo
6249203134Sthompsa	/* disable Tx/Rx */
6250203134Sthompsa	run_read(sc, RT2860_MAC_SYS_CTRL, &tmp);
6251203134Sthompsa	tmp &= ~(RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
6252203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, tmp);
6253203134Sthompsa
6254203134Sthompsa	/* wait for pending Tx to complete */
6255203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
6256209917Sthompsa		if (run_read(sc, RT2860_TXRXQ_PCNT, &tmp) != 0) {
6257203134Sthompsa			DPRINTF("Cannot read Tx queue count\n");
6258203134Sthompsa			break;
6259203134Sthompsa		}
6260209917Sthompsa		if ((tmp & RT2860_TX2Q_PCNT_MASK) == 0) {
6261203134Sthompsa			DPRINTF("All Tx cleared\n");
6262203134Sthompsa			break;
6263203134Sthompsa		}
6264203134Sthompsa		run_delay(sc, 10);
6265203134Sthompsa	}
6266209917Sthompsa	if (ntries >= 100)
6267203134Sthompsa		DPRINTF("There are still pending Tx\n");
6268203134Sthompsa	run_delay(sc, 10);
6269203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, 0);
6270203134Sthompsa
6271203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST);
6272203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
6273203134Sthompsa
6274203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
6275203134Sthompsa		run_unsetup_tx_list(sc, &sc->sc_epq[i]);
6276203134Sthompsa}
6277203134Sthompsa
6278203134Sthompsastatic void
6279257429Shselaskyrun_delay(struct run_softc *sc, u_int ms)
6280203134Sthompsa{
6281203134Sthompsa	usb_pause_mtx(mtx_owned(&sc->sc_mtx) ?
6282203134Sthompsa	    &sc->sc_mtx : NULL, USB_MS_TO_TICKS(ms));
6283203134Sthompsa}
6284203134Sthompsa
6285203134Sthompsastatic device_method_t run_methods[] = {
6286203134Sthompsa	/* Device interface */
6287203134Sthompsa	DEVMETHOD(device_probe,		run_match),
6288203134Sthompsa	DEVMETHOD(device_attach,	run_attach),
6289203134Sthompsa	DEVMETHOD(device_detach,	run_detach),
6290246614Shselasky	DEVMETHOD_END
6291203134Sthompsa};
6292203134Sthompsa
6293203134Sthompsastatic driver_t run_driver = {
6294233774Shselasky	.name = "run",
6295233774Shselasky	.methods = run_methods,
6296233774Shselasky	.size = sizeof(struct run_softc)
6297203134Sthompsa};
6298203134Sthompsa
6299203134Sthompsastatic devclass_t run_devclass;
6300203134Sthompsa
6301259812SkevloDRIVER_MODULE(run, uhub, run_driver, run_devclass, run_driver_loaded, NULL);
6302212122SthompsaMODULE_DEPEND(run, wlan, 1, 1, 1);
6303212122SthompsaMODULE_DEPEND(run, usb, 1, 1, 1);
6304212122SthompsaMODULE_DEPEND(run, firmware, 1, 1, 1);
6305212122SthompsaMODULE_VERSION(run, 1);
6306