if_run.c revision 293339
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 293339 2016-01-07 18:41:03Z avos $");
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");
87276701ShselaskySYSCTL_INT(_hw_usb_run, OID_AUTO, debug, CTLFLAG_RWTUN, &run_debug, 0,
88203134Sthompsa    "run debug level");
89203134Sthompsa#endif
90203134Sthompsa
91287552Skevlo#define	IEEE80211_HAS_ADDR4(wh)	IEEE80211_IS_DSTODS(wh)
92203134Sthompsa
93208019Sthompsa/*
94208019Sthompsa * Because of LOR in run_key_delete(), use atomic instead.
95208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[].
96208019Sthompsa */
97259546Skevlo#define	RUN_CMDQ_GET(c)	(atomic_fetchadd_32((c), 1) & RUN_CMDQ_MASQ)
98208019Sthompsa
99223486Shselaskystatic const STRUCT_USB_HOST_ID run_devs[] = {
100259546Skevlo#define	RUN_DEV(v,p)	{ USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) }
101259812Skevlo#define	RUN_DEV_EJECT(v,p)	\
102262465Skevlo	{ USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RUN_EJECT) }
103262465Skevlo#define	RUN_EJECT	1
104209918Sthompsa    RUN_DEV(ABOCOM,		RT2770),
105209918Sthompsa    RUN_DEV(ABOCOM,		RT2870),
106209918Sthompsa    RUN_DEV(ABOCOM,		RT3070),
107209918Sthompsa    RUN_DEV(ABOCOM,		RT3071),
108209918Sthompsa    RUN_DEV(ABOCOM,		RT3072),
109209918Sthompsa    RUN_DEV(ABOCOM2,		RT2870_1),
110209918Sthompsa    RUN_DEV(ACCTON,		RT2770),
111209918Sthompsa    RUN_DEV(ACCTON,		RT2870_1),
112209918Sthompsa    RUN_DEV(ACCTON,		RT2870_2),
113209918Sthompsa    RUN_DEV(ACCTON,		RT2870_3),
114209918Sthompsa    RUN_DEV(ACCTON,		RT2870_4),
115209918Sthompsa    RUN_DEV(ACCTON,		RT2870_5),
116209918Sthompsa    RUN_DEV(ACCTON,		RT3070),
117209918Sthompsa    RUN_DEV(ACCTON,		RT3070_1),
118209918Sthompsa    RUN_DEV(ACCTON,		RT3070_2),
119209918Sthompsa    RUN_DEV(ACCTON,		RT3070_3),
120209918Sthompsa    RUN_DEV(ACCTON,		RT3070_4),
121209918Sthompsa    RUN_DEV(ACCTON,		RT3070_5),
122209918Sthompsa    RUN_DEV(AIRTIES,		RT3070),
123209918Sthompsa    RUN_DEV(ALLWIN,		RT2070),
124209918Sthompsa    RUN_DEV(ALLWIN,		RT2770),
125209918Sthompsa    RUN_DEV(ALLWIN,		RT2870),
126209918Sthompsa    RUN_DEV(ALLWIN,		RT3070),
127209918Sthompsa    RUN_DEV(ALLWIN,		RT3071),
128209918Sthompsa    RUN_DEV(ALLWIN,		RT3072),
129209918Sthompsa    RUN_DEV(ALLWIN,		RT3572),
130209918Sthompsa    RUN_DEV(AMIGO,		RT2870_1),
131209918Sthompsa    RUN_DEV(AMIGO,		RT2870_2),
132209918Sthompsa    RUN_DEV(AMIT,		CGWLUSB2GNR),
133209918Sthompsa    RUN_DEV(AMIT,		RT2870_1),
134209918Sthompsa    RUN_DEV(AMIT2,		RT2870),
135209918Sthompsa    RUN_DEV(ASUS,		RT2870_1),
136209918Sthompsa    RUN_DEV(ASUS,		RT2870_2),
137209918Sthompsa    RUN_DEV(ASUS,		RT2870_3),
138209918Sthompsa    RUN_DEV(ASUS,		RT2870_4),
139209918Sthompsa    RUN_DEV(ASUS,		RT2870_5),
140209918Sthompsa    RUN_DEV(ASUS,		USBN13),
141209918Sthompsa    RUN_DEV(ASUS,		RT3070_1),
142260219Skevlo    RUN_DEV(ASUS,		USBN66),
143239358Shselasky    RUN_DEV(ASUS,		USB_N53),
144209918Sthompsa    RUN_DEV(ASUS2,		USBN11),
145209918Sthompsa    RUN_DEV(AZUREWAVE,		RT2870_1),
146209918Sthompsa    RUN_DEV(AZUREWAVE,		RT2870_2),
147209918Sthompsa    RUN_DEV(AZUREWAVE,		RT3070_1),
148209918Sthompsa    RUN_DEV(AZUREWAVE,		RT3070_2),
149209918Sthompsa    RUN_DEV(AZUREWAVE,		RT3070_3),
150260219Skevlo    RUN_DEV(BELKIN,		F9L1103),
151209918Sthompsa    RUN_DEV(BELKIN,		F5D8053V3),
152209918Sthompsa    RUN_DEV(BELKIN,		F5D8055),
153226534Shselasky    RUN_DEV(BELKIN,		F5D8055V2),
154209918Sthompsa    RUN_DEV(BELKIN,		F6D4050V1),
155256500Shselasky    RUN_DEV(BELKIN,		F6D4050V2),
156209918Sthompsa    RUN_DEV(BELKIN,		RT2870_1),
157209918Sthompsa    RUN_DEV(BELKIN,		RT2870_2),
158226534Shselasky    RUN_DEV(CISCOLINKSYS,	AE1000),
159209918Sthompsa    RUN_DEV(CISCOLINKSYS2,	RT3070),
160209918Sthompsa    RUN_DEV(CISCOLINKSYS3,	RT3070),
161209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_1),
162209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_2),
163209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_3),
164209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_4),
165209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_5),
166209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_6),
167209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_7),
168209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT2870_8),
169209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT3070_1),
170209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	RT3070_2),
171209918Sthompsa    RUN_DEV(CONCEPTRONIC2,	VIGORN61),
172209918Sthompsa    RUN_DEV(COREGA,		CGWLUSB300GNM),
173209918Sthompsa    RUN_DEV(COREGA,		RT2870_1),
174209918Sthompsa    RUN_DEV(COREGA,		RT2870_2),
175209918Sthompsa    RUN_DEV(COREGA,		RT2870_3),
176209918Sthompsa    RUN_DEV(COREGA,		RT3070),
177209918Sthompsa    RUN_DEV(CYBERTAN,		RT2870),
178209918Sthompsa    RUN_DEV(DLINK,		RT2870),
179209918Sthompsa    RUN_DEV(DLINK,		RT3072),
180255238Sbr    RUN_DEV(DLINK,		DWA127),
181257955Skevlo    RUN_DEV(DLINK,		DWA140B3),
182259032Skevlo    RUN_DEV(DLINK,		DWA160B2),
183267089Skevlo    RUN_DEV(DLINK,		DWA140D1),
184260219Skevlo    RUN_DEV(DLINK,		DWA162),
185209918Sthompsa    RUN_DEV(DLINK2,		DWA130),
186209918Sthompsa    RUN_DEV(DLINK2,		RT2870_1),
187209918Sthompsa    RUN_DEV(DLINK2,		RT2870_2),
188209918Sthompsa    RUN_DEV(DLINK2,		RT3070_1),
189209918Sthompsa    RUN_DEV(DLINK2,		RT3070_2),
190209918Sthompsa    RUN_DEV(DLINK2,		RT3070_3),
191209918Sthompsa    RUN_DEV(DLINK2,		RT3070_4),
192209918Sthompsa    RUN_DEV(DLINK2,		RT3070_5),
193209918Sthompsa    RUN_DEV(DLINK2,		RT3072),
194209918Sthompsa    RUN_DEV(DLINK2,		RT3072_1),
195209918Sthompsa    RUN_DEV(EDIMAX,		EW7717),
196209918Sthompsa    RUN_DEV(EDIMAX,		EW7718),
197260219Skevlo    RUN_DEV(EDIMAX,		EW7733UND),
198209918Sthompsa    RUN_DEV(EDIMAX,		RT2870_1),
199209918Sthompsa    RUN_DEV(ENCORE,		RT3070_1),
200209918Sthompsa    RUN_DEV(ENCORE,		RT3070_2),
201209918Sthompsa    RUN_DEV(ENCORE,		RT3070_3),
202209918Sthompsa    RUN_DEV(GIGABYTE,		GNWB31N),
203209918Sthompsa    RUN_DEV(GIGABYTE,		GNWB32L),
204209918Sthompsa    RUN_DEV(GIGABYTE,		RT2870_1),
205209918Sthompsa    RUN_DEV(GIGASET,		RT3070_1),
206209918Sthompsa    RUN_DEV(GIGASET,		RT3070_2),
207209918Sthompsa    RUN_DEV(GUILLEMOT,		HWNU300),
208209918Sthompsa    RUN_DEV(HAWKING,		HWUN2),
209209918Sthompsa    RUN_DEV(HAWKING,		RT2870_1),
210209918Sthompsa    RUN_DEV(HAWKING,		RT2870_2),
211209918Sthompsa    RUN_DEV(HAWKING,		RT3070),
212209918Sthompsa    RUN_DEV(IODATA,		RT3072_1),
213209918Sthompsa    RUN_DEV(IODATA,		RT3072_2),
214209918Sthompsa    RUN_DEV(IODATA,		RT3072_3),
215209918Sthompsa    RUN_DEV(IODATA,		RT3072_4),
216209918Sthompsa    RUN_DEV(LINKSYS4,		RT3070),
217209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB100),
218209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB54GCV3),
219209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB600N),
220209918Sthompsa    RUN_DEV(LINKSYS4,		WUSB600NV2),
221209918Sthompsa    RUN_DEV(LOGITEC,		RT2870_1),
222209918Sthompsa    RUN_DEV(LOGITEC,		RT2870_2),
223209918Sthompsa    RUN_DEV(LOGITEC,		RT2870_3),
224230333Shselasky    RUN_DEV(LOGITEC,		LANW300NU2),
225238274Shrs    RUN_DEV(LOGITEC,		LANW150NU2),
226248458Shselasky    RUN_DEV(LOGITEC,		LANW300NU2S),
227281745Skevlo    RUN_DEV(MELCO,		WLIUCG300HP),
228209918Sthompsa    RUN_DEV(MELCO,		RT2870_2),
229209918Sthompsa    RUN_DEV(MELCO,		WLIUCAG300N),
230209918Sthompsa    RUN_DEV(MELCO,		WLIUCG300N),
231219257Sdaichi    RUN_DEV(MELCO,		WLIUCG301N),
232209918Sthompsa    RUN_DEV(MELCO,		WLIUCGN),
233227781Shselasky    RUN_DEV(MELCO,		WLIUCGNM),
234281745Skevlo    RUN_DEV(MELCO,		WLIUCG300HPV1),
235238274Shrs    RUN_DEV(MELCO,		WLIUCGNM2),
236209918Sthompsa    RUN_DEV(MOTOROLA4,		RT2770),
237209918Sthompsa    RUN_DEV(MOTOROLA4,		RT3070),
238209918Sthompsa    RUN_DEV(MSI,		RT3070_1),
239209918Sthompsa    RUN_DEV(MSI,		RT3070_2),
240209918Sthompsa    RUN_DEV(MSI,		RT3070_3),
241209918Sthompsa    RUN_DEV(MSI,		RT3070_4),
242209918Sthompsa    RUN_DEV(MSI,		RT3070_5),
243209918Sthompsa    RUN_DEV(MSI,		RT3070_6),
244209918Sthompsa    RUN_DEV(MSI,		RT3070_7),
245209918Sthompsa    RUN_DEV(MSI,		RT3070_8),
246209918Sthompsa    RUN_DEV(MSI,		RT3070_9),
247209918Sthompsa    RUN_DEV(MSI,		RT3070_10),
248209918Sthompsa    RUN_DEV(MSI,		RT3070_11),
249289028Sgavin    RUN_DEV(NETGEAR,		WNDA4100),
250209918Sthompsa    RUN_DEV(OVISLINK,		RT3072),
251209918Sthompsa    RUN_DEV(PARA,		RT3070),
252209918Sthompsa    RUN_DEV(PEGATRON,		RT2870),
253209918Sthompsa    RUN_DEV(PEGATRON,		RT3070),
254209918Sthompsa    RUN_DEV(PEGATRON,		RT3070_2),
255209918Sthompsa    RUN_DEV(PEGATRON,		RT3070_3),
256209918Sthompsa    RUN_DEV(PHILIPS,		RT2870),
257209918Sthompsa    RUN_DEV(PLANEX2,		GWUS300MINIS),
258209918Sthompsa    RUN_DEV(PLANEX2,		GWUSMICRON),
259209918Sthompsa    RUN_DEV(PLANEX2,		RT2870),
260209918Sthompsa    RUN_DEV(PLANEX2,		RT3070),
261209918Sthompsa    RUN_DEV(QCOM,		RT2870),
262209918Sthompsa    RUN_DEV(QUANTA,		RT3070),
263209918Sthompsa    RUN_DEV(RALINK,		RT2070),
264209918Sthompsa    RUN_DEV(RALINK,		RT2770),
265209918Sthompsa    RUN_DEV(RALINK,		RT2870),
266209918Sthompsa    RUN_DEV(RALINK,		RT3070),
267209918Sthompsa    RUN_DEV(RALINK,		RT3071),
268209918Sthompsa    RUN_DEV(RALINK,		RT3072),
269209918Sthompsa    RUN_DEV(RALINK,		RT3370),
270209918Sthompsa    RUN_DEV(RALINK,		RT3572),
271260219Skevlo    RUN_DEV(RALINK,		RT3573),
272257955Skevlo    RUN_DEV(RALINK,		RT5370),
273259032Skevlo    RUN_DEV(RALINK,		RT5572),
274209918Sthompsa    RUN_DEV(RALINK,		RT8070),
275226534Shselasky    RUN_DEV(SAMSUNG,		WIS09ABGN),
276209918Sthompsa    RUN_DEV(SAMSUNG2,		RT2870_1),
277209918Sthompsa    RUN_DEV(SENAO,		RT2870_1),
278209918Sthompsa    RUN_DEV(SENAO,		RT2870_2),
279209918Sthompsa    RUN_DEV(SENAO,		RT2870_3),
280209918Sthompsa    RUN_DEV(SENAO,		RT2870_4),
281209918Sthompsa    RUN_DEV(SENAO,		RT3070),
282209918Sthompsa    RUN_DEV(SENAO,		RT3071),
283209918Sthompsa    RUN_DEV(SENAO,		RT3072_1),
284209918Sthompsa    RUN_DEV(SENAO,		RT3072_2),
285209918Sthompsa    RUN_DEV(SENAO,		RT3072_3),
286209918Sthompsa    RUN_DEV(SENAO,		RT3072_4),
287209918Sthompsa    RUN_DEV(SENAO,		RT3072_5),
288209918Sthompsa    RUN_DEV(SITECOMEU,		RT2770),
289209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_1),
290209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_2),
291209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_3),
292209918Sthompsa    RUN_DEV(SITECOMEU,		RT2870_4),
293209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070),
294209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070_2),
295209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070_3),
296209918Sthompsa    RUN_DEV(SITECOMEU,		RT3070_4),
297209918Sthompsa    RUN_DEV(SITECOMEU,		RT3071),
298209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_1),
299209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_2),
300209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_3),
301209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_4),
302209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_5),
303209918Sthompsa    RUN_DEV(SITECOMEU,		RT3072_6),
304209918Sthompsa    RUN_DEV(SITECOMEU,		WL608),
305209918Sthompsa    RUN_DEV(SPARKLAN,		RT2870_1),
306209918Sthompsa    RUN_DEV(SPARKLAN,		RT3070),
307209918Sthompsa    RUN_DEV(SWEEX2,		LW153),
308209918Sthompsa    RUN_DEV(SWEEX2,		LW303),
309209918Sthompsa    RUN_DEV(SWEEX2,		LW313),
310209918Sthompsa    RUN_DEV(TOSHIBA,		RT3070),
311209918Sthompsa    RUN_DEV(UMEDIA,		RT2870_1),
312209918Sthompsa    RUN_DEV(ZCOM,		RT2870_1),
313209918Sthompsa    RUN_DEV(ZCOM,		RT2870_2),
314209918Sthompsa    RUN_DEV(ZINWELL,		RT2870_1),
315209918Sthompsa    RUN_DEV(ZINWELL,		RT2870_2),
316209918Sthompsa    RUN_DEV(ZINWELL,		RT3070),
317209918Sthompsa    RUN_DEV(ZINWELL,		RT3072_1),
318209918Sthompsa    RUN_DEV(ZINWELL,		RT3072_2),
319209918Sthompsa    RUN_DEV(ZYXEL,		RT2870_1),
320209918Sthompsa    RUN_DEV(ZYXEL,		RT2870_2),
321263985Shselasky    RUN_DEV(ZYXEL,		RT3070),
322262465Skevlo    RUN_DEV_EJECT(ZYXEL,	NWD2705),
323259812Skevlo    RUN_DEV_EJECT(RALINK,	RT_STOR),
324259812Skevlo#undef RUN_DEV_EJECT
325209918Sthompsa#undef RUN_DEV
326203134Sthompsa};
327203134Sthompsa
328203134Sthompsastatic device_probe_t	run_match;
329203134Sthompsastatic device_attach_t	run_attach;
330203134Sthompsastatic device_detach_t	run_detach;
331203134Sthompsa
332203134Sthompsastatic usb_callback_t	run_bulk_rx_callback;
333203134Sthompsastatic usb_callback_t	run_bulk_tx_callback0;
334203134Sthompsastatic usb_callback_t	run_bulk_tx_callback1;
335203134Sthompsastatic usb_callback_t	run_bulk_tx_callback2;
336203134Sthompsastatic usb_callback_t	run_bulk_tx_callback3;
337203134Sthompsastatic usb_callback_t	run_bulk_tx_callback4;
338203134Sthompsastatic usb_callback_t	run_bulk_tx_callback5;
339203134Sthompsa
340259812Skevlostatic void	run_autoinst(void *, struct usb_device *,
341259812Skevlo		    struct usb_attach_arg *);
342259812Skevlostatic int	run_driver_loaded(struct module *, int, void *);
343203134Sthompsastatic void	run_bulk_tx_callbackN(struct usb_xfer *xfer,
344257429Shselasky		    usb_error_t error, u_int index);
345203134Sthompsastatic struct ieee80211vap *run_vap_create(struct ieee80211com *,
346228621Sbschmidt		    const char [IFNAMSIZ], int, enum ieee80211_opmode, int,
347228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN],
348228621Sbschmidt		    const uint8_t [IEEE80211_ADDR_LEN]);
349203134Sthompsastatic void	run_vap_delete(struct ieee80211vap *);
350208019Sthompsastatic void	run_cmdq_cb(void *, int);
351203134Sthompsastatic void	run_setup_tx_list(struct run_softc *,
352203134Sthompsa		    struct run_endpoint_queue *);
353203134Sthompsastatic void	run_unsetup_tx_list(struct run_softc *,
354203134Sthompsa		    struct run_endpoint_queue *);
355203134Sthompsastatic int	run_load_microcode(struct run_softc *);
356203134Sthompsastatic int	run_reset(struct run_softc *);
357203134Sthompsastatic usb_error_t run_do_request(struct run_softc *,
358203134Sthompsa		    struct usb_device_request *, void *);
359203134Sthompsastatic int	run_read(struct run_softc *, uint16_t, uint32_t *);
360203134Sthompsastatic int	run_read_region_1(struct run_softc *, uint16_t, uint8_t *, int);
361203134Sthompsastatic int	run_write_2(struct run_softc *, uint16_t, uint16_t);
362203134Sthompsastatic int	run_write(struct run_softc *, uint16_t, uint32_t);
363203134Sthompsastatic int	run_write_region_1(struct run_softc *, uint16_t,
364203134Sthompsa		    const uint8_t *, int);
365203134Sthompsastatic int	run_set_region_4(struct run_softc *, uint16_t, uint32_t, int);
366259544Skevlostatic int	run_efuse_read(struct run_softc *, uint16_t, uint16_t *, int);
367203134Sthompsastatic int	run_efuse_read_2(struct run_softc *, uint16_t, uint16_t *);
368203134Sthompsastatic int	run_eeprom_read_2(struct run_softc *, uint16_t, uint16_t *);
369258733Skevlostatic int	run_rt2870_rf_write(struct run_softc *, uint32_t);
370203134Sthompsastatic int	run_rt3070_rf_read(struct run_softc *, uint8_t, uint8_t *);
371203134Sthompsastatic int	run_rt3070_rf_write(struct run_softc *, uint8_t, uint8_t);
372203134Sthompsastatic int	run_bbp_read(struct run_softc *, uint8_t, uint8_t *);
373203134Sthompsastatic int	run_bbp_write(struct run_softc *, uint8_t, uint8_t);
374203134Sthompsastatic int	run_mcu_cmd(struct run_softc *, uint8_t, uint16_t);
375257955Skevlostatic const char *run_get_rf(uint16_t);
376260219Skevlostatic void	run_rt3593_get_txpower(struct run_softc *);
377260219Skevlostatic void	run_get_txpower(struct run_softc *);
378203134Sthompsastatic int	run_read_eeprom(struct run_softc *);
379203134Sthompsastatic struct ieee80211_node *run_node_alloc(struct ieee80211vap *,
380203134Sthompsa			    const uint8_t mac[IEEE80211_ADDR_LEN]);
381203134Sthompsastatic int	run_media_change(struct ifnet *);
382203134Sthompsastatic int	run_newstate(struct ieee80211vap *, enum ieee80211_state, int);
383203134Sthompsastatic int	run_wme_update(struct ieee80211com *);
384208019Sthompsastatic void	run_key_set_cb(void *);
385288635Sadrianstatic int	run_key_set(struct ieee80211vap *, struct ieee80211_key *);
386208019Sthompsastatic void	run_key_delete_cb(void *);
387208019Sthompsastatic int	run_key_delete(struct ieee80211vap *, struct ieee80211_key *);
388206358Srpaulostatic void	run_ratectl_to(void *);
389206358Srpaulostatic void	run_ratectl_cb(void *, int);
390208019Sthompsastatic void	run_drain_fifo(void *);
391203134Sthompsastatic void	run_iter_func(void *, struct ieee80211_node *);
392208019Sthompsastatic void	run_newassoc_cb(void *);
393203134Sthompsastatic void	run_newassoc(struct ieee80211_node *, int);
394288603Sadrianstatic void	run_recv_mgmt(struct ieee80211_node *, struct mbuf *, int,
395288603Sadrian		    const struct ieee80211_rx_stats *, int, int);
396203134Sthompsastatic void	run_rx_frame(struct run_softc *, struct mbuf *, uint32_t);
397203134Sthompsastatic void	run_tx_free(struct run_endpoint_queue *pq,
398203134Sthompsa		    struct run_tx_data *, int);
399208019Sthompsastatic void	run_set_tx_desc(struct run_softc *, struct run_tx_data *);
400203134Sthompsastatic int	run_tx(struct run_softc *, struct mbuf *,
401203134Sthompsa		    struct ieee80211_node *);
402203134Sthompsastatic int	run_tx_mgt(struct run_softc *, struct mbuf *,
403203134Sthompsa		    struct ieee80211_node *);
404203134Sthompsastatic int	run_sendprot(struct run_softc *, const struct mbuf *,
405203134Sthompsa		    struct ieee80211_node *, int, int);
406203134Sthompsastatic int	run_tx_param(struct run_softc *, struct mbuf *,
407203134Sthompsa		    struct ieee80211_node *,
408203134Sthompsa		    const struct ieee80211_bpf_params *);
409203134Sthompsastatic int	run_raw_xmit(struct ieee80211_node *, struct mbuf *,
410203134Sthompsa		    const struct ieee80211_bpf_params *);
411287197Sglebiusstatic int	run_transmit(struct ieee80211com *, struct mbuf *);
412287197Sglebiusstatic void	run_start(struct run_softc *);
413287197Sglebiusstatic void	run_parent(struct ieee80211com *);
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 *);
435287555Skevlostatic void	run_enable_tsf(struct run_softc *);
436287554Skevlostatic void	run_get_tsf(struct run_softc *, uint64_t *);
437203134Sthompsastatic void	run_enable_mrr(struct run_softc *);
438203134Sthompsastatic void	run_set_txpreamble(struct run_softc *);
439203134Sthompsastatic void	run_set_basicrates(struct run_softc *);
440203134Sthompsastatic void	run_set_leds(struct run_softc *, uint16_t);
441203134Sthompsastatic void	run_set_bssid(struct run_softc *, const uint8_t *);
442203134Sthompsastatic void	run_set_macaddr(struct run_softc *, const uint8_t *);
443283540Sglebiusstatic void	run_updateslot(struct ieee80211com *);
444218492Sbschmidtstatic void	run_updateslot_cb(void *);
445283540Sglebiusstatic void	run_update_mcast(struct ieee80211com *);
446203134Sthompsastatic int8_t	run_rssi2dbm(struct run_softc *, uint8_t, uint8_t);
447283540Sglebiusstatic void	run_update_promisc_locked(struct run_softc *);
448283540Sglebiusstatic void	run_update_promisc(struct ieee80211com *);
449257955Skevlostatic void	run_rt5390_bbp_init(struct run_softc *);
450203134Sthompsastatic int	run_bbp_init(struct run_softc *);
451203134Sthompsastatic int	run_rt3070_rf_init(struct run_softc *);
452260219Skevlostatic void	run_rt3593_rf_init(struct run_softc *);
453257955Skevlostatic void	run_rt5390_rf_init(struct run_softc *);
454203134Sthompsastatic int	run_rt3070_filter_calib(struct run_softc *, uint8_t, uint8_t,
455203134Sthompsa		    uint8_t *);
456205042Sthompsastatic void	run_rt3070_rf_setup(struct run_softc *);
457260219Skevlostatic void	run_rt3593_rf_setup(struct run_softc *);
458260219Skevlostatic void	run_rt5390_rf_setup(struct run_softc *);
459203134Sthompsastatic int	run_txrx_enable(struct run_softc *);
460257955Skevlostatic void	run_adjust_freq_offset(struct run_softc *);
461203134Sthompsastatic void	run_init_locked(struct run_softc *);
462203134Sthompsastatic void	run_stop(void *);
463257429Shselaskystatic void	run_delay(struct run_softc *, u_int);
464203134Sthompsa
465259812Skevlostatic eventhandler_tag run_etag;
466259812Skevlo
467259544Skevlostatic const struct rt2860_rate {
468259544Skevlo	uint8_t		rate;
469259544Skevlo	uint8_t		mcs;
470259544Skevlo	enum		ieee80211_phytype phy;
471259544Skevlo	uint8_t		ctl_ridx;
472259544Skevlo	uint16_t	sp_ack_dur;
473259544Skevlo	uint16_t	lp_ack_dur;
474259544Skevlo} rt2860_rates[] = {
475259544Skevlo	{   2, 0, IEEE80211_T_DS,   0, 314, 314 },
476259544Skevlo	{   4, 1, IEEE80211_T_DS,   1, 258, 162 },
477259544Skevlo	{  11, 2, IEEE80211_T_DS,   2, 223, 127 },
478259544Skevlo	{  22, 3, IEEE80211_T_DS,   3, 213, 117 },
479259544Skevlo	{  12, 0, IEEE80211_T_OFDM, 4,  60,  60 },
480259544Skevlo	{  18, 1, IEEE80211_T_OFDM, 4,  52,  52 },
481259544Skevlo	{  24, 2, IEEE80211_T_OFDM, 6,  48,  48 },
482259544Skevlo	{  36, 3, IEEE80211_T_OFDM, 6,  44,  44 },
483259544Skevlo	{  48, 4, IEEE80211_T_OFDM, 8,  44,  44 },
484259544Skevlo	{  72, 5, IEEE80211_T_OFDM, 8,  40,  40 },
485259544Skevlo	{  96, 6, IEEE80211_T_OFDM, 8,  40,  40 },
486259544Skevlo	{ 108, 7, IEEE80211_T_OFDM, 8,  40,  40 }
487259544Skevlo};
488259544Skevlo
489203134Sthompsastatic const struct {
490208019Sthompsa	uint16_t	reg;
491203134Sthompsa	uint32_t	val;
492203134Sthompsa} rt2870_def_mac[] = {
493203134Sthompsa	RT2870_DEF_MAC
494203134Sthompsa};
495203134Sthompsa
496203134Sthompsastatic const struct {
497203134Sthompsa	uint8_t	reg;
498203134Sthompsa	uint8_t	val;
499203134Sthompsa} rt2860_def_bbp[] = {
500203134Sthompsa	RT2860_DEF_BBP
501257955Skevlo},rt5390_def_bbp[] = {
502257955Skevlo	RT5390_DEF_BBP
503259032Skevlo},rt5592_def_bbp[] = {
504259032Skevlo	RT5592_DEF_BBP
505203134Sthompsa};
506203134Sthompsa
507259032Skevlo/*
508259032Skevlo * Default values for BBP register R196 for RT5592.
509259032Skevlo */
510259032Skevlostatic const uint8_t rt5592_bbp_r196[] = {
511259032Skevlo	0xe0, 0x1f, 0x38, 0x32, 0x08, 0x28, 0x19, 0x0a, 0xff, 0x00,
512259032Skevlo	0x16, 0x10, 0x10, 0x0b, 0x36, 0x2c, 0x26, 0x24, 0x42, 0x36,
513259032Skevlo	0x30, 0x2d, 0x4c, 0x46, 0x3d, 0x40, 0x3e, 0x42, 0x3d, 0x40,
514259032Skevlo	0x3c, 0x34, 0x2c, 0x2f, 0x3c, 0x35, 0x2e, 0x2a, 0x49, 0x41,
515259032Skevlo	0x36, 0x31, 0x30, 0x30, 0x0e, 0x0d, 0x28, 0x21, 0x1c, 0x16,
516259032Skevlo	0x50, 0x4a, 0x43, 0x40, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00,
517259032Skevlo	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
518259032Skevlo	0x00, 0x00, 0x7d, 0x14, 0x32, 0x2c, 0x36, 0x4c, 0x43, 0x2c,
519259032Skevlo	0x2e, 0x36, 0x30, 0x6e
520259032Skevlo};
521259032Skevlo
522203134Sthompsastatic const struct rfprog {
523203134Sthompsa	uint8_t		chan;
524203134Sthompsa	uint32_t	r1, r2, r3, r4;
525203134Sthompsa} rt2860_rf2850[] = {
526203134Sthompsa	RT2860_RF2850
527203134Sthompsa};
528203134Sthompsa
529203134Sthompsastruct {
530203134Sthompsa	uint8_t	n, r, k;
531205042Sthompsa} rt3070_freqs[] = {
532205042Sthompsa	RT3070_RF3052
533203134Sthompsa};
534203134Sthompsa
535259032Skevlostatic const struct rt5592_freqs {
536259032Skevlo	uint16_t	n;
537259032Skevlo	uint8_t		k, m, r;
538259032Skevlo} rt5592_freqs_20mhz[] = {
539259032Skevlo	RT5592_RF5592_20MHZ
540259032Skevlo},rt5592_freqs_40mhz[] = {
541259032Skevlo	RT5592_RF5592_40MHZ
542259032Skevlo};
543259032Skevlo
544203134Sthompsastatic const struct {
545203134Sthompsa	uint8_t	reg;
546203134Sthompsa	uint8_t	val;
547203134Sthompsa} rt3070_def_rf[] = {
548203134Sthompsa	RT3070_DEF_RF
549205042Sthompsa},rt3572_def_rf[] = {
550205042Sthompsa	RT3572_DEF_RF
551260219Skevlo},rt3593_def_rf[] = {
552260219Skevlo	RT3593_DEF_RF
553257955Skevlo},rt5390_def_rf[] = {
554257955Skevlo	RT5390_DEF_RF
555257955Skevlo},rt5392_def_rf[] = {
556257955Skevlo	RT5392_DEF_RF
557259032Skevlo},rt5592_def_rf[] = {
558259032Skevlo	RT5592_DEF_RF
559259032Skevlo},rt5592_2ghz_def_rf[] = {
560259032Skevlo	RT5592_2GHZ_DEF_RF
561259032Skevlo},rt5592_5ghz_def_rf[] = {
562259032Skevlo	RT5592_5GHZ_DEF_RF
563203134Sthompsa};
564203134Sthompsa
565259032Skevlostatic const struct {
566259032Skevlo	u_int	firstchan;
567259032Skevlo	u_int	lastchan;
568259032Skevlo	uint8_t	reg;
569259032Skevlo	uint8_t	val;
570259032Skevlo} rt5592_chan_5ghz[] = {
571259032Skevlo	RT5592_CHAN_5GHZ
572259032Skevlo};
573259032Skevlo
574203134Sthompsastatic const struct usb_config run_config[RUN_N_XFER] = {
575203134Sthompsa    [RUN_BULK_TX_BE] = {
576203134Sthompsa	.type = UE_BULK,
577203134Sthompsa	.endpoint = UE_ADDR_ANY,
578203134Sthompsa	.ep_index = 0,
579203134Sthompsa	.direction = UE_DIR_OUT,
580203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
581203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
582203134Sthompsa	.callback = run_bulk_tx_callback0,
583203134Sthompsa	.timeout = 5000,	/* ms */
584203134Sthompsa    },
585203134Sthompsa    [RUN_BULK_TX_BK] = {
586203134Sthompsa	.type = UE_BULK,
587203134Sthompsa	.endpoint = UE_ADDR_ANY,
588203134Sthompsa	.direction = UE_DIR_OUT,
589203134Sthompsa	.ep_index = 1,
590203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
591203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
592203134Sthompsa	.callback = run_bulk_tx_callback1,
593203134Sthompsa	.timeout = 5000,	/* ms */
594203134Sthompsa    },
595203134Sthompsa    [RUN_BULK_TX_VI] = {
596203134Sthompsa	.type = UE_BULK,
597203134Sthompsa	.endpoint = UE_ADDR_ANY,
598203134Sthompsa	.direction = UE_DIR_OUT,
599203134Sthompsa	.ep_index = 2,
600203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
601203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
602203134Sthompsa	.callback = run_bulk_tx_callback2,
603203134Sthompsa	.timeout = 5000,	/* ms */
604203134Sthompsa    },
605203134Sthompsa    [RUN_BULK_TX_VO] = {
606203134Sthompsa	.type = UE_BULK,
607203134Sthompsa	.endpoint = UE_ADDR_ANY,
608203134Sthompsa	.direction = UE_DIR_OUT,
609203134Sthompsa	.ep_index = 3,
610203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
611203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
612203134Sthompsa	.callback = run_bulk_tx_callback3,
613203134Sthompsa	.timeout = 5000,	/* ms */
614203134Sthompsa    },
615203134Sthompsa    [RUN_BULK_TX_HCCA] = {
616203134Sthompsa	.type = UE_BULK,
617203134Sthompsa	.endpoint = UE_ADDR_ANY,
618203134Sthompsa	.direction = UE_DIR_OUT,
619203134Sthompsa	.ep_index = 4,
620203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
621203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
622203134Sthompsa	.callback = run_bulk_tx_callback4,
623203134Sthompsa	.timeout = 5000,	/* ms */
624203134Sthompsa    },
625203134Sthompsa    [RUN_BULK_TX_PRIO] = {
626203134Sthompsa	.type = UE_BULK,
627203134Sthompsa	.endpoint = UE_ADDR_ANY,
628203134Sthompsa	.direction = UE_DIR_OUT,
629203134Sthompsa	.ep_index = 5,
630203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
631203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
632203134Sthompsa	.callback = run_bulk_tx_callback5,
633203134Sthompsa	.timeout = 5000,	/* ms */
634203134Sthompsa    },
635203134Sthompsa    [RUN_BULK_RX] = {
636203134Sthompsa	.type = UE_BULK,
637203134Sthompsa	.endpoint = UE_ADDR_ANY,
638203134Sthompsa	.direction = UE_DIR_IN,
639203134Sthompsa	.bufsize = RUN_MAX_RXSZ,
640203134Sthompsa	.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
641203134Sthompsa	.callback = run_bulk_rx_callback,
642203134Sthompsa    }
643203134Sthompsa};
644203134Sthompsa
645259812Skevlostatic void
646259812Skevlorun_autoinst(void *arg, struct usb_device *udev,
647259812Skevlo    struct usb_attach_arg *uaa)
648259812Skevlo{
649259812Skevlo	struct usb_interface *iface;
650259812Skevlo	struct usb_interface_descriptor *id;
651259812Skevlo
652259812Skevlo	if (uaa->dev_state != UAA_DEV_READY)
653259812Skevlo		return;
654259812Skevlo
655259812Skevlo	iface = usbd_get_iface(udev, 0);
656259812Skevlo	if (iface == NULL)
657259812Skevlo		return;
658259812Skevlo	id = iface->idesc;
659259812Skevlo	if (id == NULL || id->bInterfaceClass != UICLASS_MASS)
660259812Skevlo		return;
661259812Skevlo	if (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa))
662259812Skevlo		return;
663259812Skevlo
664259812Skevlo	if (usb_msc_eject(udev, 0, MSC_EJECT_STOPUNIT) == 0)
665259812Skevlo		uaa->dev_state = UAA_DEV_EJECTING;
666259812Skevlo}
667259812Skevlo
668220235Skevlostatic int
669259812Skevlorun_driver_loaded(struct module *mod, int what, void *arg)
670259812Skevlo{
671259812Skevlo	switch (what) {
672259812Skevlo	case MOD_LOAD:
673259812Skevlo		run_etag = EVENTHANDLER_REGISTER(usb_dev_configured,
674259812Skevlo		    run_autoinst, NULL, EVENTHANDLER_PRI_ANY);
675259812Skevlo		break;
676259812Skevlo	case MOD_UNLOAD:
677259812Skevlo		EVENTHANDLER_DEREGISTER(usb_dev_configured, run_etag);
678259812Skevlo		break;
679259812Skevlo	default:
680259812Skevlo		return (EOPNOTSUPP);
681259812Skevlo	}
682259812Skevlo	return (0);
683259812Skevlo}
684259812Skevlo
685259812Skevlostatic int
686203134Sthompsarun_match(device_t self)
687203134Sthompsa{
688203134Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(self);
689203134Sthompsa
690203134Sthompsa	if (uaa->usb_mode != USB_MODE_HOST)
691203134Sthompsa		return (ENXIO);
692203134Sthompsa	if (uaa->info.bConfigIndex != 0)
693203134Sthompsa		return (ENXIO);
694203134Sthompsa	if (uaa->info.bIfaceIndex != RT2860_IFACE_INDEX)
695203134Sthompsa		return (ENXIO);
696203134Sthompsa
697203134Sthompsa	return (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa));
698203134Sthompsa}
699203134Sthompsa
700203134Sthompsastatic int
701203134Sthompsarun_attach(device_t self)
702203134Sthompsa{
703203134Sthompsa	struct run_softc *sc = device_get_softc(self);
704203134Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(self);
705287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
706205042Sthompsa	uint32_t ver;
707293339Savos	uint8_t bands[howmany(IEEE80211_MODE_MAX, 8)];
708293339Savos	uint8_t iface_index;
709258082Skevlo	int ntries, error;
710203134Sthompsa
711203134Sthompsa	device_set_usb_desc(self);
712203134Sthompsa	sc->sc_udev = uaa->device;
713203134Sthompsa	sc->sc_dev = self;
714262465Skevlo	if (USB_GET_DRIVER_INFO(uaa) != RUN_EJECT)
715262465Skevlo		sc->sc_flags |= RUN_FLAG_FWLOAD_NEEDED;
716203134Sthompsa
717203134Sthompsa	mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev),
718203134Sthompsa	    MTX_NETWORK_LOCK, MTX_DEF);
719287197Sglebius	mbufq_init(&sc->sc_snd, ifqmaxlen);
720203134Sthompsa
721203134Sthompsa	iface_index = RT2860_IFACE_INDEX;
722208019Sthompsa
723203134Sthompsa	error = usbd_transfer_setup(uaa->device, &iface_index,
724203134Sthompsa	    sc->sc_xfer, run_config, RUN_N_XFER, sc, &sc->sc_mtx);
725203134Sthompsa	if (error) {
726205042Sthompsa		device_printf(self, "could not allocate USB transfers, "
727203134Sthompsa		    "err=%s\n", usbd_errstr(error));
728203134Sthompsa		goto detach;
729203134Sthompsa	}
730203134Sthompsa
731203134Sthompsa	RUN_LOCK(sc);
732203134Sthompsa
733203134Sthompsa	/* wait for the chip to settle */
734203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
735209917Sthompsa		if (run_read(sc, RT2860_ASIC_VER_ID, &ver) != 0) {
736203134Sthompsa			RUN_UNLOCK(sc);
737203134Sthompsa			goto detach;
738203134Sthompsa		}
739205042Sthompsa		if (ver != 0 && ver != 0xffffffff)
740203134Sthompsa			break;
741203134Sthompsa		run_delay(sc, 10);
742203134Sthompsa	}
743203134Sthompsa	if (ntries == 100) {
744203138Sthompsa		device_printf(sc->sc_dev,
745203138Sthompsa		    "timeout waiting for NIC to initialize\n");
746203134Sthompsa		RUN_UNLOCK(sc);
747203134Sthompsa		goto detach;
748203134Sthompsa	}
749205042Sthompsa	sc->mac_ver = ver >> 16;
750205042Sthompsa	sc->mac_rev = ver & 0xffff;
751203134Sthompsa
752203134Sthompsa	/* retrieve RF rev. no and various other things from EEPROM */
753203134Sthompsa	run_read_eeprom(sc);
754203134Sthompsa
755203138Sthompsa	device_printf(sc->sc_dev,
756203138Sthompsa	    "MAC/BBP RT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), address %s\n",
757205042Sthompsa	    sc->mac_ver, sc->mac_rev, run_get_rf(sc->rf_rev),
758287197Sglebius	    sc->ntxchains, sc->nrxchains, ether_sprintf(ic->ic_macaddr));
759203134Sthompsa
760203134Sthompsa	RUN_UNLOCK(sc);
761203134Sthompsa
762283537Sglebius	ic->ic_softc = sc;
763283527Sglebius	ic->ic_name = device_get_nameunit(self);
764203134Sthompsa	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
765203134Sthompsa	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
766208019Sthompsa
767203134Sthompsa	/* set device capabilities */
768203134Sthompsa	ic->ic_caps =
769203134Sthompsa	    IEEE80211_C_STA |		/* station mode supported */
770203134Sthompsa	    IEEE80211_C_MONITOR |	/* monitor mode supported */
771203134Sthompsa	    IEEE80211_C_IBSS |
772203134Sthompsa	    IEEE80211_C_HOSTAP |
773208019Sthompsa	    IEEE80211_C_WDS |		/* 4-address traffic works */
774208019Sthompsa	    IEEE80211_C_MBSS |
775203134Sthompsa	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
776203134Sthompsa	    IEEE80211_C_SHSLOT |	/* short slot time supported */
777203134Sthompsa	    IEEE80211_C_WME |		/* WME */
778214894Sbschmidt	    IEEE80211_C_WPA;		/* WPA1|WPA2(RSN) */
779203134Sthompsa
780203134Sthompsa	ic->ic_cryptocaps =
781203134Sthompsa	    IEEE80211_CRYPTO_WEP |
782203134Sthompsa	    IEEE80211_CRYPTO_AES_CCM |
783203134Sthompsa	    IEEE80211_CRYPTO_TKIPMIC |
784203134Sthompsa	    IEEE80211_CRYPTO_TKIP;
785203134Sthompsa
786203134Sthompsa	ic->ic_flags |= IEEE80211_F_DATAPAD;
787203134Sthompsa	ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;
788203134Sthompsa
789293339Savos	memset(bands, 0, sizeof(bands));
790293339Savos	setbit(bands, IEEE80211_MODE_11B);
791293339Savos	setbit(bands, IEEE80211_MODE_11G);
792258082Skevlo	if (sc->rf_rev == RT2860_RF_2750 || sc->rf_rev == RT2860_RF_2850 ||
793260219Skevlo	    sc->rf_rev == RT3070_RF_3052 || sc->rf_rev == RT3593_RF_3053 ||
794260219Skevlo	    sc->rf_rev == RT5592_RF_5592)
795293339Savos		setbit(bands, IEEE80211_MODE_11A);
796293339Savos	ieee80211_init_channels(ic, NULL, bands);
797203134Sthompsa
798287197Sglebius	ieee80211_ifattach(ic);
799203134Sthompsa
800203134Sthompsa	ic->ic_scan_start = run_scan_start;
801203134Sthompsa	ic->ic_scan_end = run_scan_end;
802203134Sthompsa	ic->ic_set_channel = run_set_channel;
803203134Sthompsa	ic->ic_node_alloc = run_node_alloc;
804203134Sthompsa	ic->ic_newassoc = run_newassoc;
805218492Sbschmidt	ic->ic_updateslot = run_updateslot;
806208019Sthompsa	ic->ic_update_mcast = run_update_mcast;
807203134Sthompsa	ic->ic_wme.wme_update = run_wme_update;
808203134Sthompsa	ic->ic_raw_xmit = run_raw_xmit;
809203134Sthompsa	ic->ic_update_promisc = run_update_promisc;
810203134Sthompsa	ic->ic_vap_create = run_vap_create;
811203134Sthompsa	ic->ic_vap_delete = run_vap_delete;
812287197Sglebius	ic->ic_transmit = run_transmit;
813287197Sglebius	ic->ic_parent = run_parent;
814203134Sthompsa
815203134Sthompsa	ieee80211_radiotap_attach(ic,
816203134Sthompsa	    &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap),
817203134Sthompsa		RUN_TX_RADIOTAP_PRESENT,
818203134Sthompsa	    &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap),
819203134Sthompsa		RUN_RX_RADIOTAP_PRESENT);
820203134Sthompsa
821208019Sthompsa	TASK_INIT(&sc->cmdq_task, 0, run_cmdq_cb, sc);
822208019Sthompsa	TASK_INIT(&sc->ratectl_task, 0, run_ratectl_cb, sc);
823257712Shselasky	usb_callout_init_mtx(&sc->ratectl_ch, &sc->sc_mtx, 0);
824208019Sthompsa
825203134Sthompsa	if (bootverbose)
826203134Sthompsa		ieee80211_announce(ic);
827203134Sthompsa
828209917Sthompsa	return (0);
829203134Sthompsa
830203134Sthompsadetach:
831203134Sthompsa	run_detach(self);
832209917Sthompsa	return (ENXIO);
833203134Sthompsa}
834203134Sthompsa
835288649Sadrianstatic void
836288649Sadrianrun_drain_mbufq(struct run_softc *sc)
837288649Sadrian{
838288649Sadrian	struct mbuf *m;
839288649Sadrian	struct ieee80211_node *ni;
840288649Sadrian
841288649Sadrian	RUN_LOCK_ASSERT(sc, MA_OWNED);
842288649Sadrian	while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
843288649Sadrian		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
844288649Sadrian		m->m_pkthdr.rcvif = NULL;
845288649Sadrian		ieee80211_free_node(ni);
846288649Sadrian		m_freem(m);
847288649Sadrian	}
848288649Sadrian}
849288649Sadrian
850203134Sthompsastatic int
851203134Sthompsarun_detach(device_t self)
852203134Sthompsa{
853203134Sthompsa	struct run_softc *sc = device_get_softc(self);
854287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
855203134Sthompsa	int i;
856203134Sthompsa
857246614Shselasky	RUN_LOCK(sc);
858246614Shselasky	sc->sc_detached = 1;
859246614Shselasky	RUN_UNLOCK(sc);
860246614Shselasky
861203134Sthompsa	/* stop all USB transfers */
862203134Sthompsa	usbd_transfer_unsetup(sc->sc_xfer, RUN_N_XFER);
863203134Sthompsa
864203134Sthompsa	RUN_LOCK(sc);
865209144Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
866209144Sthompsa	sc->cmdq_run = sc->cmdq_key_set = RUN_CMDQ_ABORT;
867209144Sthompsa
868203134Sthompsa	/* free TX list, if any */
869203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
870203134Sthompsa		run_unsetup_tx_list(sc, &sc->sc_epq[i]);
871288649Sadrian
872288649Sadrian	/* Free TX queue */
873288649Sadrian	run_drain_mbufq(sc);
874203134Sthompsa	RUN_UNLOCK(sc);
875203134Sthompsa
876287197Sglebius	if (sc->sc_ic.ic_softc == sc) {
877208019Sthompsa		/* drain tasks */
878208019Sthompsa		usb_callout_drain(&sc->ratectl_ch);
879208019Sthompsa		ieee80211_draintask(ic, &sc->cmdq_task);
880208019Sthompsa		ieee80211_draintask(ic, &sc->ratectl_task);
881203134Sthompsa		ieee80211_ifdetach(ic);
882203134Sthompsa	}
883203134Sthompsa
884203134Sthompsa	mtx_destroy(&sc->sc_mtx);
885203134Sthompsa
886203134Sthompsa	return (0);
887203134Sthompsa}
888203134Sthompsa
889203134Sthompsastatic struct ieee80211vap *
890228621Sbschmidtrun_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
891228621Sbschmidt    enum ieee80211_opmode opmode, int flags,
892203134Sthompsa    const uint8_t bssid[IEEE80211_ADDR_LEN],
893203134Sthompsa    const uint8_t mac[IEEE80211_ADDR_LEN])
894203134Sthompsa{
895286950Sadrian	struct run_softc *sc = ic->ic_softc;
896203134Sthompsa	struct run_vap *rvp;
897203134Sthompsa	struct ieee80211vap *vap;
898208019Sthompsa	int i;
899203134Sthompsa
900209917Sthompsa	if (sc->rvp_cnt >= RUN_VAP_MAX) {
901287197Sglebius		device_printf(sc->sc_dev, "number of VAPs maxed out\n");
902209917Sthompsa		return (NULL);
903208019Sthompsa	}
904208019Sthompsa
905208019Sthompsa	switch (opmode) {
906208019Sthompsa	case IEEE80211_M_STA:
907208019Sthompsa		/* enable s/w bmiss handling for sta mode */
908208019Sthompsa		flags |= IEEE80211_CLONE_NOBEACONS;
909208019Sthompsa		/* fall though */
910208019Sthompsa	case IEEE80211_M_IBSS:
911208019Sthompsa	case IEEE80211_M_MONITOR:
912208019Sthompsa	case IEEE80211_M_HOSTAP:
913208019Sthompsa	case IEEE80211_M_MBSS:
914208019Sthompsa		/* other than WDS vaps, only one at a time */
915208019Sthompsa		if (!TAILQ_EMPTY(&ic->ic_vaps))
916209917Sthompsa			return (NULL);
917208019Sthompsa		break;
918208019Sthompsa	case IEEE80211_M_WDS:
919208019Sthompsa		TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next){
920208019Sthompsa			if(vap->iv_opmode != IEEE80211_M_HOSTAP)
921208019Sthompsa				continue;
922208019Sthompsa			/* WDS vap's always share the local mac address. */
923208019Sthompsa			flags &= ~IEEE80211_CLONE_BSSID;
924208019Sthompsa			break;
925208019Sthompsa		}
926209917Sthompsa		if (vap == NULL) {
927287197Sglebius			device_printf(sc->sc_dev,
928287197Sglebius			    "wds only supported in ap mode\n");
929209917Sthompsa			return (NULL);
930208019Sthompsa		}
931208019Sthompsa		break;
932208019Sthompsa	default:
933287197Sglebius		device_printf(sc->sc_dev, "unknown opmode %d\n", opmode);
934209917Sthompsa		return (NULL);
935208019Sthompsa	}
936208019Sthompsa
937287197Sglebius	rvp = malloc(sizeof(struct run_vap), M_80211_VAP, M_WAITOK | M_ZERO);
938203134Sthompsa	vap = &rvp->vap;
939203134Sthompsa
940287197Sglebius	if (ieee80211_vap_setup(ic, vap, name, unit, opmode, flags,
941287197Sglebius	    bssid) != 0) {
942257743Shselasky		/* out of memory */
943257743Shselasky		free(rvp, M_80211_VAP);
944257743Shselasky		return (NULL);
945257743Shselasky	}
946257743Shselasky
947203134Sthompsa	vap->iv_update_beacon = run_update_beacon;
948208019Sthompsa	vap->iv_max_aid = RT2870_WCID_MAX;
949208019Sthompsa	/*
950208019Sthompsa	 * To delete the right key from h/w, we need wcid.
951208019Sthompsa	 * Luckily, there is unused space in ieee80211_key{}, wk_pad,
952208019Sthompsa	 * and matching wcid will be written into there. So, cast
953208019Sthompsa	 * some spells to remove 'const' from ieee80211_key{}
954208019Sthompsa	 */
955208019Sthompsa	vap->iv_key_delete = (void *)run_key_delete;
956208019Sthompsa	vap->iv_key_set = (void *)run_key_set;
957203134Sthompsa
958203134Sthompsa	/* override state transition machine */
959203134Sthompsa	rvp->newstate = vap->iv_newstate;
960203134Sthompsa	vap->iv_newstate = run_newstate;
961288603Sadrian	if (opmode == IEEE80211_M_IBSS) {
962288603Sadrian		rvp->recv_mgmt = vap->iv_recv_mgmt;
963288603Sadrian		vap->iv_recv_mgmt = run_recv_mgmt;
964288603Sadrian	}
965203134Sthompsa
966206358Srpaulo	ieee80211_ratectl_init(vap);
967206358Srpaulo	ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */);
968203134Sthompsa
969203134Sthompsa	/* complete setup */
970287197Sglebius	ieee80211_vap_attach(vap, run_media_change, ieee80211_media_status,
971287197Sglebius	    mac);
972208019Sthompsa
973208019Sthompsa	/* make sure id is always unique */
974209917Sthompsa	for (i = 0; i < RUN_VAP_MAX; i++) {
975208019Sthompsa		if((sc->rvp_bmap & 1 << i) == 0){
976208019Sthompsa			sc->rvp_bmap |= 1 << i;
977208019Sthompsa			rvp->rvp_id = i;
978208019Sthompsa			break;
979208019Sthompsa		}
980208019Sthompsa	}
981209917Sthompsa	if (sc->rvp_cnt++ == 0)
982208019Sthompsa		ic->ic_opmode = opmode;
983208019Sthompsa
984209917Sthompsa	if (opmode == IEEE80211_M_HOSTAP)
985209144Sthompsa		sc->cmdq_run = RUN_CMDQ_GO;
986209144Sthompsa
987208019Sthompsa	DPRINTF("rvp_id=%d bmap=%x rvp_cnt=%d\n",
988208019Sthompsa	    rvp->rvp_id, sc->rvp_bmap, sc->rvp_cnt);
989208019Sthompsa
990209917Sthompsa	return (vap);
991203134Sthompsa}
992203134Sthompsa
993203134Sthompsastatic void
994203134Sthompsarun_vap_delete(struct ieee80211vap *vap)
995203134Sthompsa{
996203134Sthompsa	struct run_vap *rvp = RUN_VAP(vap);
997203134Sthompsa	struct ieee80211com *ic;
998203134Sthompsa	struct run_softc *sc;
999208019Sthompsa	uint8_t rvp_id;
1000203134Sthompsa
1001209917Sthompsa	if (vap == NULL)
1002203134Sthompsa		return;
1003203134Sthompsa
1004203134Sthompsa	ic = vap->iv_ic;
1005286950Sadrian	sc = ic->ic_softc;
1006203134Sthompsa
1007205042Sthompsa	RUN_LOCK(sc);
1008208019Sthompsa
1009218492Sbschmidt	m_freem(rvp->beacon_mbuf);
1010218492Sbschmidt	rvp->beacon_mbuf = NULL;
1011218492Sbschmidt
1012208019Sthompsa	rvp_id = rvp->rvp_id;
1013208019Sthompsa	sc->ratectl_run &= ~(1 << rvp_id);
1014208019Sthompsa	sc->rvp_bmap &= ~(1 << rvp_id);
1015208019Sthompsa	run_set_region_4(sc, RT2860_SKEY(rvp_id, 0), 0, 128);
1016208019Sthompsa	run_set_region_4(sc, RT2860_BCN_BASE(rvp_id), 0, 512);
1017208019Sthompsa	--sc->rvp_cnt;
1018208019Sthompsa
1019208019Sthompsa	DPRINTF("vap=%p rvp_id=%d bmap=%x rvp_cnt=%d\n",
1020208019Sthompsa	    vap, rvp_id, sc->rvp_bmap, sc->rvp_cnt);
1021208019Sthompsa
1022205042Sthompsa	RUN_UNLOCK(sc);
1023203134Sthompsa
1024206358Srpaulo	ieee80211_ratectl_deinit(vap);
1025203134Sthompsa	ieee80211_vap_detach(vap);
1026203134Sthompsa	free(rvp, M_80211_VAP);
1027203134Sthompsa}
1028203134Sthompsa
1029208019Sthompsa/*
1030208019Sthompsa * There are numbers of functions need to be called in context thread.
1031208019Sthompsa * Rather than creating taskqueue event for each of those functions,
1032208019Sthompsa * here is all-for-one taskqueue callback function. This function
1033208019Sthompsa * gurantees deferred functions are executed in the same order they
1034208019Sthompsa * were enqueued.
1035208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[].
1036208019Sthompsa */
1037203134Sthompsastatic void
1038208019Sthompsarun_cmdq_cb(void *arg, int pending)
1039208019Sthompsa{
1040208019Sthompsa	struct run_softc *sc = arg;
1041208019Sthompsa	uint8_t i;
1042208019Sthompsa
1043208019Sthompsa	/* call cmdq[].func locked */
1044208019Sthompsa	RUN_LOCK(sc);
1045209917Sthompsa	for (i = sc->cmdq_exec; sc->cmdq[i].func && pending;
1046209917Sthompsa	    i = sc->cmdq_exec, pending--) {
1047208019Sthompsa		DPRINTFN(6, "cmdq_exec=%d pending=%d\n", i, pending);
1048209917Sthompsa		if (sc->cmdq_run == RUN_CMDQ_GO) {
1049208019Sthompsa			/*
1050208019Sthompsa			 * If arg0 is NULL, callback func needs more
1051208019Sthompsa			 * than one arg. So, pass ptr to cmdq struct.
1052208019Sthompsa			 */
1053209917Sthompsa			if (sc->cmdq[i].arg0)
1054208019Sthompsa				sc->cmdq[i].func(sc->cmdq[i].arg0);
1055208019Sthompsa			else
1056208019Sthompsa				sc->cmdq[i].func(&sc->cmdq[i]);
1057208019Sthompsa		}
1058208019Sthompsa		sc->cmdq[i].arg0 = NULL;
1059208019Sthompsa		sc->cmdq[i].func = NULL;
1060208019Sthompsa		sc->cmdq_exec++;
1061208019Sthompsa		sc->cmdq_exec &= RUN_CMDQ_MASQ;
1062208019Sthompsa	}
1063208019Sthompsa	RUN_UNLOCK(sc);
1064208019Sthompsa}
1065208019Sthompsa
1066208019Sthompsastatic void
1067203134Sthompsarun_setup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
1068203134Sthompsa{
1069203134Sthompsa	struct run_tx_data *data;
1070203134Sthompsa
1071203134Sthompsa	memset(pq, 0, sizeof(*pq));
1072203134Sthompsa
1073203134Sthompsa	STAILQ_INIT(&pq->tx_qh);
1074203134Sthompsa	STAILQ_INIT(&pq->tx_fh);
1075203134Sthompsa
1076203134Sthompsa	for (data = &pq->tx_data[0];
1077203134Sthompsa	    data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) {
1078203134Sthompsa		data->sc = sc;
1079203134Sthompsa		STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
1080203134Sthompsa	}
1081203134Sthompsa	pq->tx_nfree = RUN_TX_RING_COUNT;
1082203134Sthompsa}
1083203134Sthompsa
1084203134Sthompsastatic void
1085203134Sthompsarun_unsetup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
1086203134Sthompsa{
1087203134Sthompsa	struct run_tx_data *data;
1088203134Sthompsa
1089203134Sthompsa	/* make sure any subsequent use of the queues will fail */
1090203134Sthompsa	pq->tx_nfree = 0;
1091203134Sthompsa	STAILQ_INIT(&pq->tx_fh);
1092203134Sthompsa	STAILQ_INIT(&pq->tx_qh);
1093203134Sthompsa
1094203134Sthompsa	/* free up all node references and mbufs */
1095203134Sthompsa	for (data = &pq->tx_data[0];
1096209917Sthompsa	    data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) {
1097203134Sthompsa		if (data->m != NULL) {
1098203134Sthompsa			m_freem(data->m);
1099203134Sthompsa			data->m = NULL;
1100203134Sthompsa		}
1101203134Sthompsa		if (data->ni != NULL) {
1102203134Sthompsa			ieee80211_free_node(data->ni);
1103203134Sthompsa			data->ni = NULL;
1104203134Sthompsa		}
1105203134Sthompsa	}
1106203134Sthompsa}
1107203134Sthompsa
1108220235Skevlostatic int
1109203134Sthompsarun_load_microcode(struct run_softc *sc)
1110203134Sthompsa{
1111203134Sthompsa	usb_device_request_t req;
1112203137Sthompsa	const struct firmware *fw;
1113203134Sthompsa	const u_char *base;
1114203134Sthompsa	uint32_t tmp;
1115203134Sthompsa	int ntries, error;
1116203134Sthompsa	const uint64_t *temp;
1117203134Sthompsa	uint64_t bytes;
1118203134Sthompsa
1119205042Sthompsa	RUN_UNLOCK(sc);
1120203137Sthompsa	fw = firmware_get("runfw");
1121205042Sthompsa	RUN_LOCK(sc);
1122209917Sthompsa	if (fw == NULL) {
1123203138Sthompsa		device_printf(sc->sc_dev,
1124203138Sthompsa		    "failed loadfirmware of file %s\n", "runfw");
1125203134Sthompsa		return ENOENT;
1126203134Sthompsa	}
1127203134Sthompsa
1128203137Sthompsa	if (fw->datasize != 8192) {
1129203138Sthompsa		device_printf(sc->sc_dev,
1130203138Sthompsa		    "invalid firmware size (should be 8KB)\n");
1131203137Sthompsa		error = EINVAL;
1132203137Sthompsa		goto fail;
1133203134Sthompsa	}
1134203134Sthompsa
1135203134Sthompsa	/*
1136203134Sthompsa	 * RT3071/RT3072 use a different firmware
1137203134Sthompsa	 * run-rt2870 (8KB) contains both,
1138203134Sthompsa	 * first half (4KB) is for rt2870,
1139203134Sthompsa	 * last half is for rt3071.
1140203134Sthompsa	 */
1141203137Sthompsa	base = fw->data;
1142205042Sthompsa	if ((sc->mac_ver) != 0x2860 &&
1143205042Sthompsa	    (sc->mac_ver) != 0x2872 &&
1144209917Sthompsa	    (sc->mac_ver) != 0x3070) {
1145203134Sthompsa		base += 4096;
1146205042Sthompsa	}
1147203134Sthompsa
1148203134Sthompsa	/* cheap sanity check */
1149203137Sthompsa	temp = fw->data;
1150203134Sthompsa	bytes = *temp;
1151257712Shselasky	if (bytes != be64toh(0xffffff0210280210ULL)) {
1152203138Sthompsa		device_printf(sc->sc_dev, "firmware checksum failed\n");
1153203137Sthompsa		error = EINVAL;
1154203137Sthompsa		goto fail;
1155203137Sthompsa	}
1156203134Sthompsa
1157203134Sthompsa	/* write microcode image */
1158262465Skevlo	if (sc->sc_flags & RUN_FLAG_FWLOAD_NEEDED) {
1159260219Skevlo		run_write_region_1(sc, RT2870_FW_BASE, base, 4096);
1160260219Skevlo		run_write(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff);
1161260219Skevlo		run_write(sc, RT2860_H2M_MAILBOX_STATUS, 0xffffffff);
1162260219Skevlo	}
1163203134Sthompsa
1164203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1165203134Sthompsa	req.bRequest = RT2870_RESET;
1166203134Sthompsa	USETW(req.wValue, 8);
1167203134Sthompsa	USETW(req.wIndex, 0);
1168203134Sthompsa	USETW(req.wLength, 0);
1169220235Skevlo	if ((error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL))
1170220235Skevlo	    != 0) {
1171203138Sthompsa		device_printf(sc->sc_dev, "firmware reset failed\n");
1172203137Sthompsa		goto fail;
1173203137Sthompsa	}
1174203134Sthompsa
1175203134Sthompsa	run_delay(sc, 10);
1176203134Sthompsa
1177260219Skevlo	run_write(sc, RT2860_H2M_BBPAGENT, 0);
1178203134Sthompsa	run_write(sc, RT2860_H2M_MAILBOX, 0);
1179260219Skevlo	run_write(sc, RT2860_H2M_INTSRC, 0);
1180205042Sthompsa	if ((error = run_mcu_cmd(sc, RT2860_MCU_CMD_RFRESET, 0)) != 0)
1181203137Sthompsa		goto fail;
1182203134Sthompsa
1183203134Sthompsa	/* wait until microcontroller is ready */
1184203134Sthompsa	for (ntries = 0; ntries < 1000; ntries++) {
1185260219Skevlo		if ((error = run_read(sc, RT2860_SYS_CTRL, &tmp)) != 0)
1186203137Sthompsa			goto fail;
1187203134Sthompsa		if (tmp & RT2860_MCU_READY)
1188203134Sthompsa			break;
1189203134Sthompsa		run_delay(sc, 10);
1190203134Sthompsa	}
1191203134Sthompsa	if (ntries == 1000) {
1192203138Sthompsa		device_printf(sc->sc_dev,
1193203138Sthompsa		    "timeout waiting for MCU to initialize\n");
1194203137Sthompsa		error = ETIMEDOUT;
1195203137Sthompsa		goto fail;
1196203134Sthompsa	}
1197233283Sbschmidt	device_printf(sc->sc_dev, "firmware %s ver. %u.%u loaded\n",
1198233283Sbschmidt	    (base == fw->data) ? "RT2870" : "RT3071",
1199233283Sbschmidt	    *(base + 4092), *(base + 4093));
1200203134Sthompsa
1201203137Sthompsafail:
1202203137Sthompsa	firmware_put(fw, FIRMWARE_UNLOAD);
1203203137Sthompsa	return (error);
1204203134Sthompsa}
1205203134Sthompsa
1206258641Shselaskystatic int
1207203134Sthompsarun_reset(struct run_softc *sc)
1208203134Sthompsa{
1209203134Sthompsa	usb_device_request_t req;
1210203134Sthompsa
1211203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1212203134Sthompsa	req.bRequest = RT2870_RESET;
1213203134Sthompsa	USETW(req.wValue, 1);
1214203134Sthompsa	USETW(req.wIndex, 0);
1215203134Sthompsa	USETW(req.wLength, 0);
1216209917Sthompsa	return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL));
1217203134Sthompsa}
1218203134Sthompsa
1219203134Sthompsastatic usb_error_t
1220203134Sthompsarun_do_request(struct run_softc *sc,
1221203134Sthompsa    struct usb_device_request *req, void *data)
1222203134Sthompsa{
1223203134Sthompsa	usb_error_t err;
1224203134Sthompsa	int ntries = 10;
1225203134Sthompsa
1226203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
1227203134Sthompsa
1228203134Sthompsa	while (ntries--) {
1229203134Sthompsa		err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx,
1230203134Sthompsa		    req, data, 0, NULL, 250 /* ms */);
1231203134Sthompsa		if (err == 0)
1232203134Sthompsa			break;
1233203134Sthompsa		DPRINTFN(1, "Control request failed, %s (retrying)\n",
1234203134Sthompsa		    usbd_errstr(err));
1235203134Sthompsa		run_delay(sc, 10);
1236203134Sthompsa	}
1237203134Sthompsa	return (err);
1238203134Sthompsa}
1239203134Sthompsa
1240203134Sthompsastatic int
1241203134Sthompsarun_read(struct run_softc *sc, uint16_t reg, uint32_t *val)
1242203134Sthompsa{
1243203134Sthompsa	uint32_t tmp;
1244203134Sthompsa	int error;
1245203134Sthompsa
1246203134Sthompsa	error = run_read_region_1(sc, reg, (uint8_t *)&tmp, sizeof tmp);
1247203134Sthompsa	if (error == 0)
1248203134Sthompsa		*val = le32toh(tmp);
1249203134Sthompsa	else
1250203134Sthompsa		*val = 0xffffffff;
1251209917Sthompsa	return (error);
1252203134Sthompsa}
1253203134Sthompsa
1254203134Sthompsastatic int
1255203134Sthompsarun_read_region_1(struct run_softc *sc, uint16_t reg, uint8_t *buf, int len)
1256203134Sthompsa{
1257203134Sthompsa	usb_device_request_t req;
1258203134Sthompsa
1259203134Sthompsa	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1260203134Sthompsa	req.bRequest = RT2870_READ_REGION_1;
1261203134Sthompsa	USETW(req.wValue, 0);
1262203134Sthompsa	USETW(req.wIndex, reg);
1263203134Sthompsa	USETW(req.wLength, len);
1264203134Sthompsa
1265209917Sthompsa	return (run_do_request(sc, &req, buf));
1266203134Sthompsa}
1267203134Sthompsa
1268203134Sthompsastatic int
1269203134Sthompsarun_write_2(struct run_softc *sc, uint16_t reg, uint16_t val)
1270203134Sthompsa{
1271203134Sthompsa	usb_device_request_t req;
1272203134Sthompsa
1273203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1274203134Sthompsa	req.bRequest = RT2870_WRITE_2;
1275203134Sthompsa	USETW(req.wValue, val);
1276203134Sthompsa	USETW(req.wIndex, reg);
1277203134Sthompsa	USETW(req.wLength, 0);
1278203134Sthompsa
1279209917Sthompsa	return (run_do_request(sc, &req, NULL));
1280203134Sthompsa}
1281203134Sthompsa
1282203134Sthompsastatic int
1283203134Sthompsarun_write(struct run_softc *sc, uint16_t reg, uint32_t val)
1284203134Sthompsa{
1285203134Sthompsa	int error;
1286203134Sthompsa
1287203134Sthompsa	if ((error = run_write_2(sc, reg, val & 0xffff)) == 0)
1288203134Sthompsa		error = run_write_2(sc, reg + 2, val >> 16);
1289209917Sthompsa	return (error);
1290203134Sthompsa}
1291203134Sthompsa
1292203134Sthompsastatic int
1293203134Sthompsarun_write_region_1(struct run_softc *sc, uint16_t reg, const uint8_t *buf,
1294203134Sthompsa    int len)
1295203134Sthompsa{
1296203134Sthompsa#if 1
1297203134Sthompsa	int i, error = 0;
1298203134Sthompsa	/*
1299203134Sthompsa	 * NB: the WRITE_REGION_1 command is not stable on RT2860.
1300203134Sthompsa	 * We thus issue multiple WRITE_2 commands instead.
1301203134Sthompsa	 */
1302203134Sthompsa	KASSERT((len & 1) == 0, ("run_write_region_1: Data too long.\n"));
1303203134Sthompsa	for (i = 0; i < len && error == 0; i += 2)
1304203134Sthompsa		error = run_write_2(sc, reg + i, buf[i] | buf[i + 1] << 8);
1305209917Sthompsa	return (error);
1306203134Sthompsa#else
1307203134Sthompsa	usb_device_request_t req;
1308257958Skevlo	int error = 0;
1309203134Sthompsa
1310257958Skevlo	/*
1311257958Skevlo	 * NOTE: It appears the WRITE_REGION_1 command cannot be
1312257958Skevlo	 * passed a huge amount of data, which will crash the
1313257958Skevlo	 * firmware. Limit amount of data passed to 64-bytes at a
1314257958Skevlo	 * time.
1315257958Skevlo	 */
1316257958Skevlo	while (len > 0) {
1317257958Skevlo		int delta = 64;
1318257958Skevlo		if (delta > len)
1319257958Skevlo			delta = len;
1320257958Skevlo
1321257958Skevlo		req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1322257958Skevlo		req.bRequest = RT2870_WRITE_REGION_1;
1323257958Skevlo		USETW(req.wValue, 0);
1324257958Skevlo		USETW(req.wIndex, reg);
1325257958Skevlo		USETW(req.wLength, delta);
1326257958Skevlo		error = run_do_request(sc, &req, __DECONST(uint8_t *, buf));
1327257958Skevlo		if (error != 0)
1328257958Skevlo			break;
1329257958Skevlo		reg += delta;
1330257958Skevlo		buf += delta;
1331257958Skevlo		len -= delta;
1332257958Skevlo	}
1333257958Skevlo	return (error);
1334203134Sthompsa#endif
1335203134Sthompsa}
1336203134Sthompsa
1337203134Sthompsastatic int
1338203134Sthompsarun_set_region_4(struct run_softc *sc, uint16_t reg, uint32_t val, int len)
1339203134Sthompsa{
1340203134Sthompsa	int i, error = 0;
1341203134Sthompsa
1342203134Sthompsa	KASSERT((len & 3) == 0, ("run_set_region_4: Invalid data length.\n"));
1343203134Sthompsa	for (i = 0; i < len && error == 0; i += 4)
1344203134Sthompsa		error = run_write(sc, reg + i, val);
1345209917Sthompsa	return (error);
1346203134Sthompsa}
1347203134Sthompsa
1348203134Sthompsastatic int
1349259544Skevlorun_efuse_read(struct run_softc *sc, uint16_t addr, uint16_t *val, int count)
1350203134Sthompsa{
1351203134Sthompsa	uint32_t tmp;
1352203134Sthompsa	uint16_t reg;
1353203134Sthompsa	int error, ntries;
1354203134Sthompsa
1355203134Sthompsa	if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
1356209917Sthompsa		return (error);
1357203134Sthompsa
1358261076Shselasky	if (count == 2)
1359261076Shselasky		addr *= 2;
1360203134Sthompsa	/*-
1361203134Sthompsa	 * Read one 16-byte block into registers EFUSE_DATA[0-3]:
1362203134Sthompsa	 * DATA0: F E D C
1363203134Sthompsa	 * DATA1: B A 9 8
1364203134Sthompsa	 * DATA2: 7 6 5 4
1365203134Sthompsa	 * DATA3: 3 2 1 0
1366203134Sthompsa	 */
1367203134Sthompsa	tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK);
1368203134Sthompsa	tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK;
1369203134Sthompsa	run_write(sc, RT3070_EFUSE_CTRL, tmp);
1370203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1371203134Sthompsa		if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
1372209917Sthompsa			return (error);
1373203134Sthompsa		if (!(tmp & RT3070_EFSROM_KICK))
1374203134Sthompsa			break;
1375203134Sthompsa		run_delay(sc, 2);
1376203134Sthompsa	}
1377203134Sthompsa	if (ntries == 100)
1378209917Sthompsa		return (ETIMEDOUT);
1379203134Sthompsa
1380261076Shselasky	if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK) {
1381261076Shselasky		*val = 0xffff;	/* address not found */
1382209917Sthompsa		return (0);
1383261076Shselasky	}
1384203134Sthompsa	/* determine to which 32-bit register our 16-bit word belongs */
1385203134Sthompsa	reg = RT3070_EFUSE_DATA3 - (addr & 0xc);
1386203134Sthompsa	if ((error = run_read(sc, reg, &tmp)) != 0)
1387209917Sthompsa		return (error);
1388203134Sthompsa
1389261118Skevlo	tmp >>= (8 * (addr & 0x3));
1390261118Skevlo	*val = (addr & 1) ? tmp >> 16 : tmp & 0xffff;
1391261118Skevlo
1392209917Sthompsa	return (0);
1393203134Sthompsa}
1394203134Sthompsa
1395261124Skevlo/* Read 16-bit from eFUSE ROM for RT3xxx. */
1396203134Sthompsastatic int
1397259544Skevlorun_efuse_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
1398259544Skevlo{
1399259544Skevlo	return (run_efuse_read(sc, addr, val, 2));
1400259544Skevlo}
1401259544Skevlo
1402259544Skevlostatic int
1403203134Sthompsarun_eeprom_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
1404203134Sthompsa{
1405203134Sthompsa	usb_device_request_t req;
1406203134Sthompsa	uint16_t tmp;
1407203134Sthompsa	int error;
1408203134Sthompsa
1409203134Sthompsa	addr *= 2;
1410203134Sthompsa	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1411203134Sthompsa	req.bRequest = RT2870_EEPROM_READ;
1412203134Sthompsa	USETW(req.wValue, 0);
1413203134Sthompsa	USETW(req.wIndex, addr);
1414260219Skevlo	USETW(req.wLength, sizeof(tmp));
1415203134Sthompsa
1416203134Sthompsa	error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, &tmp);
1417203134Sthompsa	if (error == 0)
1418203134Sthompsa		*val = le16toh(tmp);
1419203134Sthompsa	else
1420203134Sthompsa		*val = 0xffff;
1421209917Sthompsa	return (error);
1422203134Sthompsa}
1423203134Sthompsa
1424203134Sthompsastatic __inline int
1425203134Sthompsarun_srom_read(struct run_softc *sc, uint16_t addr, uint16_t *val)
1426203134Sthompsa{
1427203134Sthompsa	/* either eFUSE ROM or EEPROM */
1428203134Sthompsa	return sc->sc_srom_read(sc, addr, val);
1429203134Sthompsa}
1430203134Sthompsa
1431203134Sthompsastatic int
1432258733Skevlorun_rt2870_rf_write(struct run_softc *sc, uint32_t val)
1433203134Sthompsa{
1434203134Sthompsa	uint32_t tmp;
1435203134Sthompsa	int error, ntries;
1436203134Sthompsa
1437203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1438203134Sthompsa		if ((error = run_read(sc, RT2860_RF_CSR_CFG0, &tmp)) != 0)
1439209917Sthompsa			return (error);
1440203134Sthompsa		if (!(tmp & RT2860_RF_REG_CTRL))
1441203134Sthompsa			break;
1442203134Sthompsa	}
1443203134Sthompsa	if (ntries == 10)
1444209917Sthompsa		return (ETIMEDOUT);
1445203134Sthompsa
1446258732Skevlo	return (run_write(sc, RT2860_RF_CSR_CFG0, val));
1447203134Sthompsa}
1448203134Sthompsa
1449203134Sthompsastatic int
1450203134Sthompsarun_rt3070_rf_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
1451203134Sthompsa{
1452203134Sthompsa	uint32_t tmp;
1453203134Sthompsa	int error, ntries;
1454203134Sthompsa
1455203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1456203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1457209917Sthompsa			return (error);
1458203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1459203134Sthompsa			break;
1460203134Sthompsa	}
1461203134Sthompsa	if (ntries == 100)
1462209917Sthompsa		return (ETIMEDOUT);
1463203134Sthompsa
1464203134Sthompsa	tmp = RT3070_RF_KICK | reg << 8;
1465203134Sthompsa	if ((error = run_write(sc, RT3070_RF_CSR_CFG, tmp)) != 0)
1466209917Sthompsa		return (error);
1467203134Sthompsa
1468203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1469203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1470209917Sthompsa			return (error);
1471203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1472203134Sthompsa			break;
1473203134Sthompsa	}
1474203134Sthompsa	if (ntries == 100)
1475209917Sthompsa		return (ETIMEDOUT);
1476203134Sthompsa
1477203134Sthompsa	*val = tmp & 0xff;
1478209917Sthompsa	return (0);
1479203134Sthompsa}
1480203134Sthompsa
1481203134Sthompsastatic int
1482203134Sthompsarun_rt3070_rf_write(struct run_softc *sc, uint8_t reg, uint8_t val)
1483203134Sthompsa{
1484203134Sthompsa	uint32_t tmp;
1485203134Sthompsa	int error, ntries;
1486203134Sthompsa
1487203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1488203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1489209917Sthompsa			return (error);
1490203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1491203134Sthompsa			break;
1492203134Sthompsa	}
1493203134Sthompsa	if (ntries == 10)
1494209917Sthompsa		return (ETIMEDOUT);
1495203134Sthompsa
1496203134Sthompsa	tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val;
1497209917Sthompsa	return (run_write(sc, RT3070_RF_CSR_CFG, tmp));
1498203134Sthompsa}
1499203134Sthompsa
1500203134Sthompsastatic int
1501203134Sthompsarun_bbp_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
1502203134Sthompsa{
1503203134Sthompsa	uint32_t tmp;
1504203134Sthompsa	int ntries, error;
1505203134Sthompsa
1506203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1507203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1508209917Sthompsa			return (error);
1509203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1510203134Sthompsa			break;
1511203134Sthompsa	}
1512203134Sthompsa	if (ntries == 10)
1513209917Sthompsa		return (ETIMEDOUT);
1514203134Sthompsa
1515203134Sthompsa	tmp = RT2860_BBP_CSR_READ | RT2860_BBP_CSR_KICK | reg << 8;
1516203134Sthompsa	if ((error = run_write(sc, RT2860_BBP_CSR_CFG, tmp)) != 0)
1517209917Sthompsa		return (error);
1518203134Sthompsa
1519203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1520203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1521209917Sthompsa			return (error);
1522203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1523203134Sthompsa			break;
1524203134Sthompsa	}
1525203134Sthompsa	if (ntries == 10)
1526209917Sthompsa		return (ETIMEDOUT);
1527203134Sthompsa
1528203134Sthompsa	*val = tmp & 0xff;
1529209917Sthompsa	return (0);
1530203134Sthompsa}
1531203134Sthompsa
1532203134Sthompsastatic int
1533203134Sthompsarun_bbp_write(struct run_softc *sc, uint8_t reg, uint8_t val)
1534203134Sthompsa{
1535203134Sthompsa	uint32_t tmp;
1536203134Sthompsa	int ntries, error;
1537203134Sthompsa
1538203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1539203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1540209917Sthompsa			return (error);
1541203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1542203134Sthompsa			break;
1543203134Sthompsa	}
1544203134Sthompsa	if (ntries == 10)
1545209917Sthompsa		return (ETIMEDOUT);
1546203134Sthompsa
1547203134Sthompsa	tmp = RT2860_BBP_CSR_KICK | reg << 8 | val;
1548209917Sthompsa	return (run_write(sc, RT2860_BBP_CSR_CFG, tmp));
1549203134Sthompsa}
1550203134Sthompsa
1551203134Sthompsa/*
1552203134Sthompsa * Send a command to the 8051 microcontroller unit.
1553203134Sthompsa */
1554203134Sthompsastatic int
1555203134Sthompsarun_mcu_cmd(struct run_softc *sc, uint8_t cmd, uint16_t arg)
1556203134Sthompsa{
1557203134Sthompsa	uint32_t tmp;
1558203134Sthompsa	int error, ntries;
1559203134Sthompsa
1560203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1561203134Sthompsa		if ((error = run_read(sc, RT2860_H2M_MAILBOX, &tmp)) != 0)
1562203134Sthompsa			return error;
1563203134Sthompsa		if (!(tmp & RT2860_H2M_BUSY))
1564203134Sthompsa			break;
1565203134Sthompsa	}
1566203134Sthompsa	if (ntries == 100)
1567203134Sthompsa		return ETIMEDOUT;
1568203134Sthompsa
1569203134Sthompsa	tmp = RT2860_H2M_BUSY | RT2860_TOKEN_NO_INTR << 16 | arg;
1570203134Sthompsa	if ((error = run_write(sc, RT2860_H2M_MAILBOX, tmp)) == 0)
1571203134Sthompsa		error = run_write(sc, RT2860_HOST_CMD, cmd);
1572209917Sthompsa	return (error);
1573203134Sthompsa}
1574203134Sthompsa
1575203134Sthompsa/*
1576203134Sthompsa * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word.
1577203134Sthompsa * Used to adjust per-rate Tx power registers.
1578203134Sthompsa */
1579203134Sthompsastatic __inline uint32_t
1580203134Sthompsab4inc(uint32_t b32, int8_t delta)
1581203134Sthompsa{
1582203134Sthompsa	int8_t i, b4;
1583203134Sthompsa
1584203134Sthompsa	for (i = 0; i < 8; i++) {
1585203134Sthompsa		b4 = b32 & 0xf;
1586203134Sthompsa		b4 += delta;
1587203134Sthompsa		if (b4 < 0)
1588203134Sthompsa			b4 = 0;
1589203134Sthompsa		else if (b4 > 0xf)
1590203134Sthompsa			b4 = 0xf;
1591203134Sthompsa		b32 = b32 >> 4 | b4 << 28;
1592203134Sthompsa	}
1593209917Sthompsa	return (b32);
1594203134Sthompsa}
1595203134Sthompsa
1596203134Sthompsastatic const char *
1597257955Skevlorun_get_rf(uint16_t rev)
1598203134Sthompsa{
1599203134Sthompsa	switch (rev) {
1600203134Sthompsa	case RT2860_RF_2820:	return "RT2820";
1601203134Sthompsa	case RT2860_RF_2850:	return "RT2850";
1602203134Sthompsa	case RT2860_RF_2720:	return "RT2720";
1603203134Sthompsa	case RT2860_RF_2750:	return "RT2750";
1604203134Sthompsa	case RT3070_RF_3020:	return "RT3020";
1605203134Sthompsa	case RT3070_RF_2020:	return "RT2020";
1606203134Sthompsa	case RT3070_RF_3021:	return "RT3021";
1607203134Sthompsa	case RT3070_RF_3022:	return "RT3022";
1608203134Sthompsa	case RT3070_RF_3052:	return "RT3052";
1609260219Skevlo	case RT3593_RF_3053:	return "RT3053";
1610259032Skevlo	case RT5592_RF_5592:	return "RT5592";
1611257955Skevlo	case RT5390_RF_5370:	return "RT5370";
1612257955Skevlo	case RT5390_RF_5372:	return "RT5372";
1613203134Sthompsa	}
1614209917Sthompsa	return ("unknown");
1615203134Sthompsa}
1616203134Sthompsa
1617260219Skevlostatic void
1618260219Skevlorun_rt3593_get_txpower(struct run_softc *sc)
1619260219Skevlo{
1620260219Skevlo	uint16_t addr, val;
1621260219Skevlo	int i;
1622260219Skevlo
1623260219Skevlo	/* Read power settings for 2GHz channels. */
1624260219Skevlo	for (i = 0; i < 14; i += 2) {
1625260219Skevlo		addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE1 :
1626260219Skevlo		    RT2860_EEPROM_PWR2GHZ_BASE1;
1627260219Skevlo		run_srom_read(sc, addr + i / 2, &val);
1628260219Skevlo		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
1629260219Skevlo		sc->txpow1[i + 1] = (int8_t)(val >> 8);
1630260219Skevlo
1631260219Skevlo		addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE2 :
1632260219Skevlo		    RT2860_EEPROM_PWR2GHZ_BASE2;
1633260219Skevlo		run_srom_read(sc, addr + i / 2, &val);
1634260219Skevlo		sc->txpow2[i + 0] = (int8_t)(val & 0xff);
1635260219Skevlo		sc->txpow2[i + 1] = (int8_t)(val >> 8);
1636260219Skevlo
1637260219Skevlo		if (sc->ntxchains == 3) {
1638260219Skevlo			run_srom_read(sc, RT3593_EEPROM_PWR2GHZ_BASE3 + i / 2,
1639260219Skevlo			    &val);
1640260219Skevlo			sc->txpow3[i + 0] = (int8_t)(val & 0xff);
1641260219Skevlo			sc->txpow3[i + 1] = (int8_t)(val >> 8);
1642260219Skevlo		}
1643260219Skevlo	}
1644260219Skevlo	/* Fix broken Tx power entries. */
1645260219Skevlo	for (i = 0; i < 14; i++) {
1646260542Skevlo		if (sc->txpow1[i] > 31)
1647260219Skevlo			sc->txpow1[i] = 5;
1648260542Skevlo		if (sc->txpow2[i] > 31)
1649260219Skevlo			sc->txpow2[i] = 5;
1650260219Skevlo		if (sc->ntxchains == 3) {
1651260542Skevlo			if (sc->txpow3[i] > 31)
1652260219Skevlo				sc->txpow3[i] = 5;
1653260219Skevlo		}
1654260219Skevlo	}
1655260219Skevlo	/* Read power settings for 5GHz channels. */
1656260219Skevlo	for (i = 0; i < 40; i += 2) {
1657260219Skevlo		run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
1658260219Skevlo		sc->txpow1[i + 14] = (int8_t)(val & 0xff);
1659260219Skevlo		sc->txpow1[i + 15] = (int8_t)(val >> 8);
1660260219Skevlo
1661260219Skevlo		run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
1662260219Skevlo		sc->txpow2[i + 14] = (int8_t)(val & 0xff);
1663260219Skevlo		sc->txpow2[i + 15] = (int8_t)(val >> 8);
1664260219Skevlo
1665260219Skevlo		if (sc->ntxchains == 3) {
1666260219Skevlo			run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE3 + i / 2,
1667260219Skevlo			    &val);
1668260219Skevlo			sc->txpow3[i + 14] = (int8_t)(val & 0xff);
1669260219Skevlo			sc->txpow3[i + 15] = (int8_t)(val >> 8);
1670260219Skevlo		}
1671260219Skevlo	}
1672260219Skevlo}
1673260219Skevlo
1674260219Skevlostatic void
1675260219Skevlorun_get_txpower(struct run_softc *sc)
1676260219Skevlo{
1677260219Skevlo	uint16_t val;
1678260219Skevlo	int i;
1679260219Skevlo
1680260219Skevlo	/* Read power settings for 2GHz channels. */
1681260219Skevlo	for (i = 0; i < 14; i += 2) {
1682260219Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE1 + i / 2, &val);
1683260219Skevlo		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
1684260219Skevlo		sc->txpow1[i + 1] = (int8_t)(val >> 8);
1685260219Skevlo
1686260219Skevlo		if (sc->mac_ver != 0x5390) {
1687260219Skevlo			run_srom_read(sc,
1688260219Skevlo			    RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2, &val);
1689260219Skevlo			sc->txpow2[i + 0] = (int8_t)(val & 0xff);
1690260219Skevlo			sc->txpow2[i + 1] = (int8_t)(val >> 8);
1691260219Skevlo		}
1692260219Skevlo	}
1693260219Skevlo	/* Fix broken Tx power entries. */
1694260219Skevlo	for (i = 0; i < 14; i++) {
1695260219Skevlo		if (sc->mac_ver >= 0x5390) {
1696288666Skevlo			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 39)
1697260219Skevlo				sc->txpow1[i] = 5;
1698260219Skevlo		} else {
1699260219Skevlo			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31)
1700260219Skevlo				sc->txpow1[i] = 5;
1701260219Skevlo		}
1702260219Skevlo		if (sc->mac_ver > 0x5390) {
1703288666Skevlo			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 39)
1704260219Skevlo				sc->txpow2[i] = 5;
1705260219Skevlo		} else if (sc->mac_ver < 0x5390) {
1706260219Skevlo			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31)
1707260219Skevlo				sc->txpow2[i] = 5;
1708260219Skevlo		}
1709260219Skevlo		DPRINTF("chan %d: power1=%d, power2=%d\n",
1710260219Skevlo		    rt2860_rf2850[i].chan, sc->txpow1[i], sc->txpow2[i]);
1711260219Skevlo	}
1712260219Skevlo	/* Read power settings for 5GHz channels. */
1713260219Skevlo	for (i = 0; i < 40; i += 2) {
1714260219Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
1715260219Skevlo		sc->txpow1[i + 14] = (int8_t)(val & 0xff);
1716260219Skevlo		sc->txpow1[i + 15] = (int8_t)(val >> 8);
1717260219Skevlo
1718260219Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
1719260219Skevlo		sc->txpow2[i + 14] = (int8_t)(val & 0xff);
1720260219Skevlo		sc->txpow2[i + 15] = (int8_t)(val >> 8);
1721260219Skevlo	}
1722260219Skevlo	/* Fix broken Tx power entries. */
1723260219Skevlo	for (i = 0; i < 40; i++ ) {
1724260219Skevlo		if (sc->mac_ver != 0x5592) {
1725260219Skevlo			if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15)
1726260219Skevlo				sc->txpow1[14 + i] = 5;
1727260219Skevlo			if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15)
1728260219Skevlo				sc->txpow2[14 + i] = 5;
1729260219Skevlo		}
1730260219Skevlo		DPRINTF("chan %d: power1=%d, power2=%d\n",
1731260219Skevlo		    rt2860_rf2850[14 + i].chan, sc->txpow1[14 + i],
1732260219Skevlo		    sc->txpow2[14 + i]);
1733260219Skevlo	}
1734260219Skevlo}
1735260219Skevlo
1736258641Shselaskystatic int
1737203134Sthompsarun_read_eeprom(struct run_softc *sc)
1738203134Sthompsa{
1739287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
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);
1756287853Skevlo	DPRINTF("EEPROM rev=%d, FAE=%d\n", val >> 8, val & 0xff);
1757203134Sthompsa
1758203134Sthompsa	/* read MAC address */
1759203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC01, &val);
1760287197Sglebius	ic->ic_macaddr[0] = val & 0xff;
1761287197Sglebius	ic->ic_macaddr[1] = val >> 8;
1762203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC23, &val);
1763287197Sglebius	ic->ic_macaddr[2] = val & 0xff;
1764287197Sglebius	ic->ic_macaddr[3] = val >> 8;
1765203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC45, &val);
1766287197Sglebius	ic->ic_macaddr[4] = val & 0xff;
1767287197Sglebius	ic->ic_macaddr[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;
2002286950Sadrian	struct run_softc *sc = ic->ic_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);
2025287552Skevlo		rn = 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) &&
2033287197Sglebius	    (ifp->if_drv_flags &  RUN_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;
2048286950Sadrian	struct run_softc *sc = ic->ic_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			}
2139283540Sglebius			run_updateslot(ic);
2140203134Sthompsa			run_enable_mrr(sc);
2141203134Sthompsa			run_set_txpreamble(sc);
2142203134Sthompsa			run_set_basicrates(sc);
2143212127Sthompsa			ni = ieee80211_ref_node(vap->iv_bss);
2144287197Sglebius			IEEE80211_ADDR_COPY(ic->ic_macaddr, 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;
2153287555Skevlo		} else
2154287555Skevlo			run_enable_tsf(sc);
2155203134Sthompsa
2156203134Sthompsa		/* turn link LED on */
2157203134Sthompsa		run_set_leds(sc, RT2860_LED_RADIO |
2158208019Sthompsa		    (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ?
2159203134Sthompsa		     RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ));
2160203134Sthompsa
2161203134Sthompsa		break;
2162203134Sthompsa	default:
2163203134Sthompsa		DPRINTFN(6, "undefined case\n");
2164203134Sthompsa		break;
2165203134Sthompsa	}
2166203134Sthompsa
2167208019Sthompsa	/* restart amrr for running VAPs */
2168209917Sthompsa	if ((sc->ratectl_run = ratectl) && restart_ratectl)
2169208019Sthompsa		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2170208019Sthompsa
2171203134Sthompsa	RUN_UNLOCK(sc);
2172203134Sthompsa	IEEE80211_LOCK(ic);
2173203134Sthompsa
2174203134Sthompsa	return(rvp->newstate(vap, nstate, arg));
2175203134Sthompsa}
2176203134Sthompsa
2177290407Savosstatic int
2178290407Savosrun_wme_update(struct ieee80211com *ic)
2179203134Sthompsa{
2180286950Sadrian	struct run_softc *sc = ic->ic_softc;
2181288646Sadrian	const struct wmeParams *ac =
2182288646Sadrian	    ic->ic_wme.wme_chanParams.cap_wmeParams;
2183203134Sthompsa	int aci, error = 0;
2184203134Sthompsa
2185203134Sthompsa	/* update MAC TX configuration registers */
2186290407Savos	RUN_LOCK(sc);
2187203134Sthompsa	for (aci = 0; aci < WME_NUM_AC; aci++) {
2188203134Sthompsa		error = run_write(sc, RT2860_EDCA_AC_CFG(aci),
2189288646Sadrian		    ac[aci].wmep_logcwmax << 16 |
2190288646Sadrian		    ac[aci].wmep_logcwmin << 12 |
2191288646Sadrian		    ac[aci].wmep_aifsn    <<  8 |
2192288646Sadrian		    ac[aci].wmep_txopLimit);
2193209917Sthompsa		if (error) goto err;
2194203134Sthompsa	}
2195203134Sthompsa
2196203134Sthompsa	/* update SCH/DMA registers too */
2197203134Sthompsa	error = run_write(sc, RT2860_WMM_AIFSN_CFG,
2198288646Sadrian	    ac[WME_AC_VO].wmep_aifsn  << 12 |
2199288646Sadrian	    ac[WME_AC_VI].wmep_aifsn  <<  8 |
2200288646Sadrian	    ac[WME_AC_BK].wmep_aifsn  <<  4 |
2201288646Sadrian	    ac[WME_AC_BE].wmep_aifsn);
2202209917Sthompsa	if (error) goto err;
2203203134Sthompsa	error = run_write(sc, RT2860_WMM_CWMIN_CFG,
2204288646Sadrian	    ac[WME_AC_VO].wmep_logcwmin << 12 |
2205288646Sadrian	    ac[WME_AC_VI].wmep_logcwmin <<  8 |
2206288646Sadrian	    ac[WME_AC_BK].wmep_logcwmin <<  4 |
2207288646Sadrian	    ac[WME_AC_BE].wmep_logcwmin);
2208209917Sthompsa	if (error) goto err;
2209203134Sthompsa	error = run_write(sc, RT2860_WMM_CWMAX_CFG,
2210288646Sadrian	    ac[WME_AC_VO].wmep_logcwmax << 12 |
2211288646Sadrian	    ac[WME_AC_VI].wmep_logcwmax <<  8 |
2212288646Sadrian	    ac[WME_AC_BK].wmep_logcwmax <<  4 |
2213288646Sadrian	    ac[WME_AC_BE].wmep_logcwmax);
2214209917Sthompsa	if (error) goto err;
2215203134Sthompsa	error = run_write(sc, RT2860_WMM_TXOP0_CFG,
2216288646Sadrian	    ac[WME_AC_BK].wmep_txopLimit << 16 |
2217288646Sadrian	    ac[WME_AC_BE].wmep_txopLimit);
2218209917Sthompsa	if (error) goto err;
2219203134Sthompsa	error = run_write(sc, RT2860_WMM_TXOP1_CFG,
2220288646Sadrian	    ac[WME_AC_VO].wmep_txopLimit << 16 |
2221288646Sadrian	    ac[WME_AC_VI].wmep_txopLimit);
2222203134Sthompsa
2223203134Sthompsaerr:
2224290407Savos	RUN_UNLOCK(sc);
2225209917Sthompsa	if (error)
2226203134Sthompsa		DPRINTF("WME update failed\n");
2227203134Sthompsa
2228290407Savos	return (error);
2229203134Sthompsa}
2230203134Sthompsa
2231203134Sthompsastatic void
2232208019Sthompsarun_key_set_cb(void *arg)
2233203134Sthompsa{
2234208019Sthompsa	struct run_cmdq *cmdq = arg;
2235208019Sthompsa	struct ieee80211vap *vap = cmdq->arg1;
2236208019Sthompsa	struct ieee80211_key *k = cmdq->k;
2237203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2238286950Sadrian	struct run_softc *sc = ic->ic_softc;
2239203134Sthompsa	struct ieee80211_node *ni;
2240287553Skevlo	u_int cipher = k->wk_cipher->ic_cipher;
2241203134Sthompsa	uint32_t attr;
2242203134Sthompsa	uint16_t base, associd;
2243209144Sthompsa	uint8_t mode, wcid, iv[8];
2244203134Sthompsa
2245208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2246203134Sthompsa
2247209917Sthompsa	if (vap->iv_opmode == IEEE80211_M_HOSTAP)
2248208019Sthompsa		ni = ieee80211_find_vap_node(&ic->ic_sta, vap, cmdq->mac);
2249209144Sthompsa	else
2250203134Sthompsa		ni = vap->iv_bss;
2251208019Sthompsa	associd = (ni != NULL) ? ni->ni_associd : 0;
2252203134Sthompsa
2253203134Sthompsa	/* map net80211 cipher to RT2860 security mode */
2254287553Skevlo	switch (cipher) {
2255203134Sthompsa	case IEEE80211_CIPHER_WEP:
2256203134Sthompsa		if(k->wk_keylen < 8)
2257203134Sthompsa			mode = RT2860_MODE_WEP40;
2258203134Sthompsa		else
2259203134Sthompsa			mode = RT2860_MODE_WEP104;
2260203134Sthompsa		break;
2261203134Sthompsa	case IEEE80211_CIPHER_TKIP:
2262203134Sthompsa		mode = RT2860_MODE_TKIP;
2263203134Sthompsa		break;
2264203134Sthompsa	case IEEE80211_CIPHER_AES_CCM:
2265203134Sthompsa		mode = RT2860_MODE_AES_CCMP;
2266203134Sthompsa		break;
2267203134Sthompsa	default:
2268203134Sthompsa		DPRINTF("undefined case\n");
2269208019Sthompsa		return;
2270203134Sthompsa	}
2271203134Sthompsa
2272208019Sthompsa	DPRINTFN(1, "associd=%x, keyix=%d, mode=%x, type=%s, tx=%s, rx=%s\n",
2273203134Sthompsa	    associd, k->wk_keyix, mode,
2274208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_GROUP) ? "group" : "pairwise",
2275208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_XMIT) ? "on" : "off",
2276208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_RECV) ? "on" : "off");
2277203134Sthompsa
2278203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2279203134Sthompsa		wcid = 0;	/* NB: update WCID0 for group keys */
2280208019Sthompsa		base = RT2860_SKEY(RUN_VAP(vap)->rvp_id, k->wk_keyix);
2281203134Sthompsa	} else {
2282245047Shselasky		wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
2283245047Shselasky		    1 : RUN_AID2WCID(associd);
2284203134Sthompsa		base = RT2860_PKEY(wcid);
2285203134Sthompsa	}
2286203134Sthompsa
2287287553Skevlo	if (cipher == IEEE80211_CIPHER_TKIP) {
2288203134Sthompsa		if(run_write_region_1(sc, base, k->wk_key, 16))
2289208019Sthompsa			return;
2290209144Sthompsa		if(run_write_region_1(sc, base + 16, &k->wk_key[16], 8))	/* wk_txmic */
2291208019Sthompsa			return;
2292209144Sthompsa		if(run_write_region_1(sc, base + 24, &k->wk_key[24], 8))	/* wk_rxmic */
2293208019Sthompsa			return;
2294203134Sthompsa	} else {
2295203134Sthompsa		/* roundup len to 16-bit: XXX fix write_region_1() instead */
2296203134Sthompsa		if(run_write_region_1(sc, base, k->wk_key, (k->wk_keylen + 1) & ~1))
2297208019Sthompsa			return;
2298203134Sthompsa	}
2299203134Sthompsa
2300203134Sthompsa	if (!(k->wk_flags & IEEE80211_KEY_GROUP) ||
2301203134Sthompsa	    (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))) {
2302203134Sthompsa		/* set initial packet number in IV+EIV */
2303287553Skevlo		if (cipher == IEEE80211_CIPHER_WEP) {
2304203134Sthompsa			memset(iv, 0, sizeof iv);
2305208019Sthompsa			iv[3] = vap->iv_def_txkey << 6;
2306203134Sthompsa		} else {
2307287553Skevlo			if (cipher == IEEE80211_CIPHER_TKIP) {
2308203134Sthompsa				iv[0] = k->wk_keytsc >> 8;
2309203134Sthompsa				iv[1] = (iv[0] | 0x20) & 0x7f;
2310203134Sthompsa				iv[2] = k->wk_keytsc;
2311203134Sthompsa			} else /* CCMP */ {
2312203134Sthompsa				iv[0] = k->wk_keytsc;
2313203134Sthompsa				iv[1] = k->wk_keytsc >> 8;
2314203134Sthompsa				iv[2] = 0;
2315203134Sthompsa			}
2316203134Sthompsa			iv[3] = k->wk_keyix << 6 | IEEE80211_WEP_EXTIV;
2317203134Sthompsa			iv[4] = k->wk_keytsc >> 16;
2318203134Sthompsa			iv[5] = k->wk_keytsc >> 24;
2319203134Sthompsa			iv[6] = k->wk_keytsc >> 32;
2320203134Sthompsa			iv[7] = k->wk_keytsc >> 40;
2321203134Sthompsa		}
2322209917Sthompsa		if (run_write_region_1(sc, RT2860_IVEIV(wcid), iv, 8))
2323208019Sthompsa			return;
2324203134Sthompsa	}
2325203134Sthompsa
2326203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2327203134Sthompsa		/* install group key */
2328209917Sthompsa		if (run_read(sc, RT2860_SKEY_MODE_0_7, &attr))
2329208019Sthompsa			return;
2330203134Sthompsa		attr &= ~(0xf << (k->wk_keyix * 4));
2331203134Sthompsa		attr |= mode << (k->wk_keyix * 4);
2332209917Sthompsa		if (run_write(sc, RT2860_SKEY_MODE_0_7, attr))
2333208019Sthompsa			return;
2334203134Sthompsa	} else {
2335203134Sthompsa		/* install pairwise key */
2336209917Sthompsa		if (run_read(sc, RT2860_WCID_ATTR(wcid), &attr))
2337208019Sthompsa			return;
2338203134Sthompsa		attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN;
2339209917Sthompsa		if (run_write(sc, RT2860_WCID_ATTR(wcid), attr))
2340208019Sthompsa			return;
2341203134Sthompsa	}
2342203134Sthompsa
2343203134Sthompsa	/* TODO create a pass-thru key entry? */
2344203134Sthompsa
2345208019Sthompsa	/* need wcid to delete the right key later */
2346208019Sthompsa	k->wk_pad = wcid;
2347203134Sthompsa}
2348203134Sthompsa
2349203134Sthompsa/*
2350208019Sthompsa * Don't have to be deferred, but in order to keep order of
2351208019Sthompsa * execution, i.e. with run_key_delete(), defer this and let
2352208019Sthompsa * run_cmdq_cb() maintain the order.
2353208019Sthompsa *
2354203134Sthompsa * return 0 on error
2355203134Sthompsa */
2356203134Sthompsastatic int
2357288635Sadrianrun_key_set(struct ieee80211vap *vap, struct ieee80211_key *k)
2358203134Sthompsa{
2359203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2360286950Sadrian	struct run_softc *sc = ic->ic_softc;
2361208019Sthompsa	uint32_t i;
2362208019Sthompsa
2363208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
2364208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
2365208019Sthompsa	sc->cmdq[i].func = run_key_set_cb;
2366208019Sthompsa	sc->cmdq[i].arg0 = NULL;
2367208019Sthompsa	sc->cmdq[i].arg1 = vap;
2368208019Sthompsa	sc->cmdq[i].k = k;
2369288635Sadrian	IEEE80211_ADDR_COPY(sc->cmdq[i].mac, k->wk_macaddr);
2370208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
2371208019Sthompsa
2372209144Sthompsa	/*
2373209144Sthompsa	 * To make sure key will be set when hostapd
2374209144Sthompsa	 * calls iv_key_set() before if_init().
2375209144Sthompsa	 */
2376209917Sthompsa	if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
2377209144Sthompsa		RUN_LOCK(sc);
2378209144Sthompsa		sc->cmdq_key_set = RUN_CMDQ_GO;
2379209144Sthompsa		RUN_UNLOCK(sc);
2380209144Sthompsa	}
2381209144Sthompsa
2382209917Sthompsa	return (1);
2383208019Sthompsa}
2384208019Sthompsa
2385208019Sthompsa/*
2386208019Sthompsa * If wlan is destroyed without being brought down i.e. without
2387208019Sthompsa * wlan down or wpa_cli terminate, this function is called after
2388208019Sthompsa * vap is gone. Don't refer it.
2389208019Sthompsa */
2390208019Sthompsastatic void
2391208019Sthompsarun_key_delete_cb(void *arg)
2392208019Sthompsa{
2393208019Sthompsa	struct run_cmdq *cmdq = arg;
2394208019Sthompsa	struct run_softc *sc = cmdq->arg1;
2395208019Sthompsa	struct ieee80211_key *k = &cmdq->key;
2396203134Sthompsa	uint32_t attr;
2397203134Sthompsa	uint8_t wcid;
2398203134Sthompsa
2399208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2400203134Sthompsa
2401203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2402203134Sthompsa		/* remove group key */
2403208019Sthompsa		DPRINTF("removing group key\n");
2404208019Sthompsa		run_read(sc, RT2860_SKEY_MODE_0_7, &attr);
2405203134Sthompsa		attr &= ~(0xf << (k->wk_keyix * 4));
2406208019Sthompsa		run_write(sc, RT2860_SKEY_MODE_0_7, attr);
2407203134Sthompsa	} else {
2408203134Sthompsa		/* remove pairwise key */
2409208019Sthompsa		DPRINTF("removing key for wcid %x\n", k->wk_pad);
2410208019Sthompsa		/* matching wcid was written to wk_pad in run_key_set() */
2411208019Sthompsa		wcid = k->wk_pad;
2412208019Sthompsa		run_read(sc, RT2860_WCID_ATTR(wcid), &attr);
2413203134Sthompsa		attr &= ~0xf;
2414208019Sthompsa		run_write(sc, RT2860_WCID_ATTR(wcid), attr);
2415208019Sthompsa		run_set_region_4(sc, RT2860_WCID_ENTRY(wcid), 0, 8);
2416203134Sthompsa	}
2417203134Sthompsa
2418208019Sthompsa	k->wk_pad = 0;
2419203134Sthompsa}
2420203134Sthompsa
2421208019Sthompsa/*
2422208019Sthompsa * return 0 on error
2423208019Sthompsa */
2424208019Sthompsastatic int
2425208019Sthompsarun_key_delete(struct ieee80211vap *vap, struct ieee80211_key *k)
2426203134Sthompsa{
2427208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2428286950Sadrian	struct run_softc *sc = ic->ic_softc;
2429208019Sthompsa	struct ieee80211_key *k0;
2430208019Sthompsa	uint32_t i;
2431203134Sthompsa
2432208019Sthompsa	/*
2433208019Sthompsa	 * When called back, key might be gone. So, make a copy
2434208019Sthompsa	 * of some values need to delete keys before deferring.
2435208019Sthompsa	 * But, because of LOR with node lock, cannot use lock here.
2436208019Sthompsa	 * So, use atomic instead.
2437208019Sthompsa	 */
2438208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
2439208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
2440208019Sthompsa	sc->cmdq[i].func = run_key_delete_cb;
2441208019Sthompsa	sc->cmdq[i].arg0 = NULL;
2442208019Sthompsa	sc->cmdq[i].arg1 = sc;
2443208019Sthompsa	k0 = &sc->cmdq[i].key;
2444208019Sthompsa	k0->wk_flags = k->wk_flags;
2445208019Sthompsa	k0->wk_keyix = k->wk_keyix;
2446208019Sthompsa	/* matching wcid was written to wk_pad in run_key_set() */
2447208019Sthompsa	k0->wk_pad = k->wk_pad;
2448208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
2449208019Sthompsa	return (1);	/* return fake success */
2450203134Sthompsa
2451203134Sthompsa}
2452203134Sthompsa
2453203134Sthompsastatic void
2454206358Srpaulorun_ratectl_to(void *arg)
2455203134Sthompsa{
2456208019Sthompsa	struct run_softc *sc = arg;
2457203134Sthompsa
2458203134Sthompsa	/* do it in a process context, so it can go sleep */
2459287197Sglebius	ieee80211_runtask(&sc->sc_ic, &sc->ratectl_task);
2460203134Sthompsa	/* next timeout will be rescheduled in the callback task */
2461203134Sthompsa}
2462203134Sthompsa
2463203134Sthompsa/* ARGSUSED */
2464203134Sthompsastatic void
2465206358Srpaulorun_ratectl_cb(void *arg, int pending)
2466203134Sthompsa{
2467208019Sthompsa	struct run_softc *sc = arg;
2468287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
2469208019Sthompsa	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
2470203134Sthompsa
2471209917Sthompsa	if (vap == NULL)
2472208019Sthompsa		return;
2473208019Sthompsa
2474262795Shselasky	if (sc->rvp_cnt > 1 || vap->iv_opmode != IEEE80211_M_STA) {
2475203134Sthompsa		/*
2476203134Sthompsa		 * run_reset_livelock() doesn't do anything with AMRR,
2477203134Sthompsa		 * but Ralink wants us to call it every 1 sec. So, we
2478203134Sthompsa		 * piggyback here rather than creating another callout.
2479203134Sthompsa		 * Livelock may occur only in HOSTAP or IBSS mode
2480203134Sthompsa		 * (when h/w is sending beacons).
2481203134Sthompsa		 */
2482203134Sthompsa		RUN_LOCK(sc);
2483203134Sthompsa		run_reset_livelock(sc);
2484208019Sthompsa		/* just in case, there are some stats to drain */
2485208019Sthompsa		run_drain_fifo(sc);
2486203134Sthompsa		RUN_UNLOCK(sc);
2487203134Sthompsa	}
2488203134Sthompsa
2489262795Shselasky	ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, sc);
2490262795Shselasky
2491257712Shselasky	RUN_LOCK(sc);
2492208019Sthompsa	if(sc->ratectl_run != RUN_RATECTL_OFF)
2493208019Sthompsa		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2494257712Shselasky	RUN_UNLOCK(sc);
2495203134Sthompsa}
2496203134Sthompsa
2497203134Sthompsastatic void
2498208019Sthompsarun_drain_fifo(void *arg)
2499203134Sthompsa{
2500208019Sthompsa	struct run_softc *sc = arg;
2501208019Sthompsa	uint32_t stat;
2502218676Shselasky	uint16_t (*wstat)[3];
2503203134Sthompsa	uint8_t wcid, mcs, pid;
2504218676Shselasky	int8_t retry;
2505203134Sthompsa
2506208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2507203134Sthompsa
2508208019Sthompsa	for (;;) {
2509203134Sthompsa		/* drain Tx status FIFO (maxsize = 16) */
2510203134Sthompsa		run_read(sc, RT2860_TX_STAT_FIFO, &stat);
2511208019Sthompsa		DPRINTFN(4, "tx stat 0x%08x\n", stat);
2512209917Sthompsa		if (!(stat & RT2860_TXQ_VLD))
2513208019Sthompsa			break;
2514203134Sthompsa
2515208019Sthompsa		wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff;
2516203134Sthompsa
2517208019Sthompsa		/* if no ACK was requested, no feedback is available */
2518208019Sthompsa		if (!(stat & RT2860_TXQ_ACKREQ) || wcid > RT2870_WCID_MAX ||
2519208019Sthompsa		    wcid == 0)
2520208019Sthompsa			continue;
2521203134Sthompsa
2522218676Shselasky		/*
2523218676Shselasky		 * Even though each stat is Tx-complete-status like format,
2524218676Shselasky		 * the device can poll stats. Because there is no guarantee
2525218676Shselasky		 * that the referring node is still around when read the stats.
2526218676Shselasky		 * So that, if we use ieee80211_ratectl_tx_update(), we will
2527218676Shselasky		 * have hard time not to refer already freed node.
2528218676Shselasky		 *
2529218676Shselasky		 * To eliminate such page faults, we poll stats in softc.
2530218676Shselasky		 * Then, update the rates later with ieee80211_ratectl_tx_update().
2531218676Shselasky		 */
2532218676Shselasky		wstat = &(sc->wcid_stats[wcid]);
2533218676Shselasky		(*wstat)[RUN_TXCNT]++;
2534218676Shselasky		if (stat & RT2860_TXQ_OK)
2535218676Shselasky			(*wstat)[RUN_SUCCESS]++;
2536218676Shselasky		else
2537287197Sglebius			counter_u64_add(sc->sc_ic.ic_oerrors, 1);
2538218676Shselasky		/*
2539218676Shselasky		 * Check if there were retries, ie if the Tx success rate is
2540218676Shselasky		 * different from the requested rate. Note that it works only
2541218676Shselasky		 * because we do not allow rate fallback from OFDM to CCK.
2542218676Shselasky		 */
2543218676Shselasky		mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f;
2544218676Shselasky		pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf;
2545218676Shselasky		if ((retry = pid -1 - mcs) > 0) {
2546218676Shselasky			(*wstat)[RUN_TXCNT] += retry;
2547218676Shselasky			(*wstat)[RUN_RETRY] += retry;
2548203134Sthompsa		}
2549208019Sthompsa	}
2550208019Sthompsa	DPRINTFN(3, "count=%d\n", sc->fifo_cnt);
2551208019Sthompsa
2552208019Sthompsa	sc->fifo_cnt = 0;
2553208019Sthompsa}
2554208019Sthompsa
2555208019Sthompsastatic void
2556208019Sthompsarun_iter_func(void *arg, struct ieee80211_node *ni)
2557208019Sthompsa{
2558208019Sthompsa	struct run_softc *sc = arg;
2559208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
2560287552Skevlo	struct run_node *rn = RUN_NODE(ni);
2561218676Shselasky	union run_stats sta[2];
2562218676Shselasky	uint16_t (*wstat)[3];
2563218676Shselasky	int txcnt, success, retrycnt, error;
2564208019Sthompsa
2565218676Shselasky	RUN_LOCK(sc);
2566218676Shselasky
2567262795Shselasky	/* Check for special case */
2568262795Shselasky	if (sc->rvp_cnt <= 1 && vap->iv_opmode == IEEE80211_M_STA &&
2569262795Shselasky	    ni != vap->iv_bss)
2570262795Shselasky		goto fail;
2571262795Shselasky
2572209917Sthompsa	if (sc->rvp_cnt <= 1 && (vap->iv_opmode == IEEE80211_M_IBSS ||
2573209917Sthompsa	    vap->iv_opmode == IEEE80211_M_STA)) {
2574203134Sthompsa		/* read statistic counters (clear on read) and update AMRR state */
2575203134Sthompsa		error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta,
2576203134Sthompsa		    sizeof sta);
2577203134Sthompsa		if (error != 0)
2578218676Shselasky			goto fail;
2579203134Sthompsa
2580203134Sthompsa		/* count failed TX as errors */
2581287197Sglebius		if_inc_counter(vap->iv_ifp, IFCOUNTER_OERRORS,
2582287197Sglebius		    le16toh(sta[0].error.fail));
2583203134Sthompsa
2584218676Shselasky		retrycnt = le16toh(sta[1].tx.retry);
2585218676Shselasky		success = le16toh(sta[1].tx.success);
2586218676Shselasky		txcnt = retrycnt + success + le16toh(sta[0].error.fail);
2587203134Sthompsa
2588218676Shselasky		DPRINTFN(3, "retrycnt=%d success=%d failcnt=%d\n",
2589218676Shselasky			retrycnt, success, le16toh(sta[0].error.fail));
2590218676Shselasky	} else {
2591218676Shselasky		wstat = &(sc->wcid_stats[RUN_AID2WCID(ni->ni_associd)]);
2592203134Sthompsa
2593218676Shselasky		if (wstat == &(sc->wcid_stats[0]) ||
2594218676Shselasky		    wstat > &(sc->wcid_stats[RT2870_WCID_MAX]))
2595218676Shselasky			goto fail;
2596208019Sthompsa
2597218676Shselasky		txcnt = (*wstat)[RUN_TXCNT];
2598218676Shselasky		success = (*wstat)[RUN_SUCCESS];
2599218676Shselasky		retrycnt = (*wstat)[RUN_RETRY];
2600218676Shselasky		DPRINTFN(3, "retrycnt=%d txcnt=%d success=%d\n",
2601218676Shselasky		    retrycnt, txcnt, success);
2602208019Sthompsa
2603218676Shselasky		memset(wstat, 0, sizeof(*wstat));
2604203134Sthompsa	}
2605203134Sthompsa
2606218676Shselasky	ieee80211_ratectl_tx_update(vap, ni, &txcnt, &success, &retrycnt);
2607208019Sthompsa	rn->amrr_ridx = ieee80211_ratectl_rate(ni, NULL, 0);
2608218676Shselasky
2609218676Shselaskyfail:
2610218676Shselasky	RUN_UNLOCK(sc);
2611218676Shselasky
2612208019Sthompsa	DPRINTFN(3, "ridx=%d\n", rn->amrr_ridx);
2613208019Sthompsa}
2614203134Sthompsa
2615208019Sthompsastatic void
2616208019Sthompsarun_newassoc_cb(void *arg)
2617208019Sthompsa{
2618208019Sthompsa	struct run_cmdq *cmdq = arg;
2619208019Sthompsa	struct ieee80211_node *ni = cmdq->arg1;
2620286950Sadrian	struct run_softc *sc = ni->ni_vap->iv_ic->ic_softc;
2621208019Sthompsa	uint8_t wcid = cmdq->wcid;
2622203134Sthompsa
2623208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2624208019Sthompsa
2625208019Sthompsa	run_write_region_1(sc, RT2860_WCID_ENTRY(wcid),
2626208019Sthompsa	    ni->ni_macaddr, IEEE80211_ADDR_LEN);
2627218676Shselasky
2628218676Shselasky	memset(&(sc->wcid_stats[wcid]), 0, sizeof(sc->wcid_stats[wcid]));
2629203134Sthompsa}
2630203134Sthompsa
2631203134Sthompsastatic void
2632203134Sthompsarun_newassoc(struct ieee80211_node *ni, int isnew)
2633203134Sthompsa{
2634287552Skevlo	struct run_node *rn = RUN_NODE(ni);
2635203134Sthompsa	struct ieee80211_rateset *rs = &ni->ni_rates;
2636208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
2637208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2638286950Sadrian	struct run_softc *sc = ic->ic_softc;
2639203134Sthompsa	uint8_t rate;
2640208019Sthompsa	uint8_t ridx;
2641245047Shselasky	uint8_t wcid;
2642208019Sthompsa	int i, j;
2643203134Sthompsa
2644245047Shselasky	wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
2645245047Shselasky	    1 : RUN_AID2WCID(ni->ni_associd);
2646245047Shselasky
2647209917Sthompsa	if (wcid > RT2870_WCID_MAX) {
2648208019Sthompsa		device_printf(sc->sc_dev, "wcid=%d out of range\n", wcid);
2649208019Sthompsa		return;
2650208019Sthompsa	}
2651203134Sthompsa
2652208019Sthompsa	/* only interested in true associations */
2653209917Sthompsa	if (isnew && ni->ni_associd != 0) {
2654208019Sthompsa
2655208019Sthompsa		/*
2656208019Sthompsa		 * This function could is called though timeout function.
2657208019Sthompsa		 * Need to defer.
2658208019Sthompsa		 */
2659208019Sthompsa		uint32_t cnt = RUN_CMDQ_GET(&sc->cmdq_store);
2660208019Sthompsa		DPRINTF("cmdq_store=%d\n", cnt);
2661208019Sthompsa		sc->cmdq[cnt].func = run_newassoc_cb;
2662208019Sthompsa		sc->cmdq[cnt].arg0 = NULL;
2663208019Sthompsa		sc->cmdq[cnt].arg1 = ni;
2664208019Sthompsa		sc->cmdq[cnt].wcid = wcid;
2665208019Sthompsa		ieee80211_runtask(ic, &sc->cmdq_task);
2666208019Sthompsa	}
2667208019Sthompsa
2668208019Sthompsa	DPRINTF("new assoc isnew=%d associd=%x addr=%s\n",
2669208019Sthompsa	    isnew, ni->ni_associd, ether_sprintf(ni->ni_macaddr));
2670208019Sthompsa
2671203134Sthompsa	for (i = 0; i < rs->rs_nrates; i++) {
2672203134Sthompsa		rate = rs->rs_rates[i] & IEEE80211_RATE_VAL;
2673203134Sthompsa		/* convert 802.11 rate to hardware rate index */
2674203134Sthompsa		for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2675203134Sthompsa			if (rt2860_rates[ridx].rate == rate)
2676203134Sthompsa				break;
2677203134Sthompsa		rn->ridx[i] = ridx;
2678203134Sthompsa		/* determine rate of control response frames */
2679203134Sthompsa		for (j = i; j >= 0; j--) {
2680203134Sthompsa			if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) &&
2681203134Sthompsa			    rt2860_rates[rn->ridx[i]].phy ==
2682203134Sthompsa			    rt2860_rates[rn->ridx[j]].phy)
2683203134Sthompsa				break;
2684203134Sthompsa		}
2685203134Sthompsa		if (j >= 0) {
2686203134Sthompsa			rn->ctl_ridx[i] = rn->ridx[j];
2687203134Sthompsa		} else {
2688203134Sthompsa			/* no basic rate found, use mandatory one */
2689203134Sthompsa			rn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx;
2690203134Sthompsa		}
2691203134Sthompsa		DPRINTF("rate=0x%02x ridx=%d ctl_ridx=%d\n",
2692203134Sthompsa		    rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]);
2693203134Sthompsa	}
2694208019Sthompsa	rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate;
2695208019Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2696208019Sthompsa		if (rt2860_rates[ridx].rate == rate)
2697208019Sthompsa			break;
2698208019Sthompsa	rn->mgt_ridx = ridx;
2699208019Sthompsa	DPRINTF("rate=%d, mgmt_ridx=%d\n", rate, rn->mgt_ridx);
2700208019Sthompsa
2701262795Shselasky	RUN_LOCK(sc);
2702262795Shselasky	if(sc->ratectl_run != RUN_RATECTL_OFF)
2703262795Shselasky		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2704262795Shselasky	RUN_UNLOCK(sc);
2705203134Sthompsa}
2706203134Sthompsa
2707203134Sthompsa/*
2708203134Sthompsa * Return the Rx chain with the highest RSSI for a given frame.
2709203134Sthompsa */
2710203134Sthompsastatic __inline uint8_t
2711203134Sthompsarun_maxrssi_chain(struct run_softc *sc, const struct rt2860_rxwi *rxwi)
2712203134Sthompsa{
2713203134Sthompsa	uint8_t rxchain = 0;
2714203134Sthompsa
2715203134Sthompsa	if (sc->nrxchains > 1) {
2716203134Sthompsa		if (rxwi->rssi[1] > rxwi->rssi[rxchain])
2717203134Sthompsa			rxchain = 1;
2718203134Sthompsa		if (sc->nrxchains > 2)
2719203134Sthompsa			if (rxwi->rssi[2] > rxwi->rssi[rxchain])
2720203134Sthompsa				rxchain = 2;
2721203134Sthompsa	}
2722209917Sthompsa	return (rxchain);
2723203134Sthompsa}
2724203134Sthompsa
2725203134Sthompsastatic void
2726288603Sadrianrun_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype,
2727288603Sadrian    const struct ieee80211_rx_stats *rxs, int rssi, int nf)
2728288603Sadrian{
2729288603Sadrian	struct ieee80211vap *vap = ni->ni_vap;
2730288603Sadrian	struct run_softc *sc = vap->iv_ic->ic_softc;
2731288603Sadrian	struct run_vap *rvp = RUN_VAP(vap);
2732288603Sadrian	uint64_t ni_tstamp, rx_tstamp;
2733288603Sadrian
2734288603Sadrian	rvp->recv_mgmt(ni, m, subtype, rxs, rssi, nf);
2735288603Sadrian
2736288603Sadrian	if (vap->iv_state == IEEE80211_S_RUN &&
2737288603Sadrian	    (subtype == IEEE80211_FC0_SUBTYPE_BEACON ||
2738288603Sadrian	    subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) {
2739288603Sadrian		ni_tstamp = le64toh(ni->ni_tstamp.tsf);
2740288603Sadrian		RUN_LOCK(sc);
2741288603Sadrian		run_get_tsf(sc, &rx_tstamp);
2742288603Sadrian		RUN_UNLOCK(sc);
2743288603Sadrian		rx_tstamp = le64toh(rx_tstamp);
2744288603Sadrian
2745288603Sadrian		if (ni_tstamp >= rx_tstamp) {
2746288603Sadrian			DPRINTF("ibss merge, tsf %ju tstamp %ju\n",
2747288603Sadrian			    (uintmax_t)rx_tstamp, (uintmax_t)ni_tstamp);
2748288603Sadrian			(void) ieee80211_ibss_merge(ni);
2749288603Sadrian		}
2750288603Sadrian	}
2751288603Sadrian}
2752288603Sadrian
2753288603Sadrianstatic void
2754203134Sthompsarun_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen)
2755203134Sthompsa{
2756287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
2757203134Sthompsa	struct ieee80211_frame *wh;
2758203134Sthompsa	struct ieee80211_node *ni;
2759203134Sthompsa	struct rt2870_rxd *rxd;
2760203134Sthompsa	struct rt2860_rxwi *rxwi;
2761203134Sthompsa	uint32_t flags;
2762259032Skevlo	uint16_t len, rxwisize;
2763203134Sthompsa	uint8_t ant, rssi;
2764203134Sthompsa	int8_t nf;
2765203134Sthompsa
2766203134Sthompsa	rxwi = mtod(m, struct rt2860_rxwi *);
2767203134Sthompsa	len = le16toh(rxwi->len) & 0xfff;
2768260219Skevlo	rxwisize = sizeof(struct rt2860_rxwi);
2769260219Skevlo	if (sc->mac_ver == 0x5592)
2770260219Skevlo		rxwisize += sizeof(uint64_t);
2771260219Skevlo	else if (sc->mac_ver == 0x3593)
2772260219Skevlo		rxwisize += sizeof(uint32_t);
2773203134Sthompsa	if (__predict_false(len > dmalen)) {
2774203134Sthompsa		m_freem(m);
2775287197Sglebius		counter_u64_add(ic->ic_ierrors, 1);
2776203134Sthompsa		DPRINTF("bad RXWI length %u > %u\n", len, dmalen);
2777203134Sthompsa		return;
2778203134Sthompsa	}
2779203134Sthompsa	/* Rx descriptor is located at the end */
2780203134Sthompsa	rxd = (struct rt2870_rxd *)(mtod(m, caddr_t) + dmalen);
2781203134Sthompsa	flags = le32toh(rxd->flags);
2782203134Sthompsa
2783203134Sthompsa	if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) {
2784203134Sthompsa		m_freem(m);
2785287197Sglebius		counter_u64_add(ic->ic_ierrors, 1);
2786203134Sthompsa		DPRINTF("%s error.\n", (flags & RT2860_RX_CRCERR)?"CRC":"ICV");
2787203134Sthompsa		return;
2788203134Sthompsa	}
2789203134Sthompsa
2790259032Skevlo	m->m_data += rxwisize;
2791259032Skevlo	m->m_pkthdr.len = m->m_len -= rxwisize;
2792203134Sthompsa
2793203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
2794203134Sthompsa
2795260444Skevlo	if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
2796260444Skevlo		wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
2797203134Sthompsa		m->m_flags |= M_WEP;
2798203134Sthompsa	}
2799203134Sthompsa
2800209917Sthompsa	if (flags & RT2860_RX_L2PAD) {
2801203134Sthompsa		DPRINTFN(8, "received RT2860_RX_L2PAD frame\n");
2802203134Sthompsa		len += 2;
2803203134Sthompsa	}
2804203134Sthompsa
2805208019Sthompsa	ni = ieee80211_find_rxnode(ic,
2806208019Sthompsa	    mtod(m, struct ieee80211_frame_min *));
2807208019Sthompsa
2808203134Sthompsa	if (__predict_false(flags & RT2860_RX_MICERR)) {
2809203134Sthompsa		/* report MIC failures to net80211 for TKIP */
2810209917Sthompsa		if (ni != NULL)
2811259032Skevlo			ieee80211_notify_michael_failure(ni->ni_vap, wh,
2812259032Skevlo			    rxwi->keyidx);
2813203134Sthompsa		m_freem(m);
2814287197Sglebius		counter_u64_add(ic->ic_ierrors, 1);
2815203134Sthompsa		DPRINTF("MIC error. Someone is lying.\n");
2816203134Sthompsa		return;
2817203134Sthompsa	}
2818203134Sthompsa
2819203134Sthompsa	ant = run_maxrssi_chain(sc, rxwi);
2820203134Sthompsa	rssi = rxwi->rssi[ant];
2821203134Sthompsa	nf = run_rssi2dbm(sc, rssi, ant);
2822203134Sthompsa
2823203134Sthompsa	m->m_pkthdr.len = m->m_len = len;
2824203134Sthompsa
2825209917Sthompsa	if (__predict_false(ieee80211_radiotap_active(ic))) {
2826203134Sthompsa		struct run_rx_radiotap_header *tap = &sc->sc_rxtap;
2827258643Shselasky		uint16_t phy;
2828203134Sthompsa
2829203134Sthompsa		tap->wr_flags = 0;
2830236439Shselasky		tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
2831236439Shselasky		tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
2832203134Sthompsa		tap->wr_antsignal = rssi;
2833203134Sthompsa		tap->wr_antenna = ant;
2834203134Sthompsa		tap->wr_dbm_antsignal = run_rssi2dbm(sc, rssi, ant);
2835203134Sthompsa		tap->wr_rate = 2;	/* in case it can't be found below */
2836287554Skevlo		run_get_tsf(sc, &tap->wr_tsf);
2837203134Sthompsa		phy = le16toh(rxwi->phy);
2838203134Sthompsa		switch (phy & RT2860_PHY_MODE) {
2839203134Sthompsa		case RT2860_PHY_CCK:
2840203134Sthompsa			switch ((phy & RT2860_PHY_MCS) & ~RT2860_PHY_SHPRE) {
2841203134Sthompsa			case 0:	tap->wr_rate =   2; break;
2842203134Sthompsa			case 1:	tap->wr_rate =   4; break;
2843203134Sthompsa			case 2:	tap->wr_rate =  11; break;
2844203134Sthompsa			case 3:	tap->wr_rate =  22; break;
2845203134Sthompsa			}
2846203134Sthompsa			if (phy & RT2860_PHY_SHPRE)
2847203134Sthompsa				tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
2848203134Sthompsa			break;
2849203134Sthompsa		case RT2860_PHY_OFDM:
2850203134Sthompsa			switch (phy & RT2860_PHY_MCS) {
2851203134Sthompsa			case 0:	tap->wr_rate =  12; break;
2852203134Sthompsa			case 1:	tap->wr_rate =  18; break;
2853203134Sthompsa			case 2:	tap->wr_rate =  24; break;
2854203134Sthompsa			case 3:	tap->wr_rate =  36; break;
2855203134Sthompsa			case 4:	tap->wr_rate =  48; break;
2856203134Sthompsa			case 5:	tap->wr_rate =  72; break;
2857203134Sthompsa			case 6:	tap->wr_rate =  96; break;
2858203134Sthompsa			case 7:	tap->wr_rate = 108; break;
2859203134Sthompsa			}
2860203134Sthompsa			break;
2861203134Sthompsa		}
2862203134Sthompsa	}
2863289753Savos
2864289753Savos	if (ni != NULL) {
2865289753Savos		(void)ieee80211_input(ni, m, rssi, nf);
2866289753Savos		ieee80211_free_node(ni);
2867289753Savos	} else {
2868289753Savos		(void)ieee80211_input_all(ic, m, rssi, nf);
2869289753Savos	}
2870203134Sthompsa}
2871203134Sthompsa
2872203134Sthompsastatic void
2873203134Sthompsarun_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error)
2874203134Sthompsa{
2875203134Sthompsa	struct run_softc *sc = usbd_xfer_softc(xfer);
2876287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
2877203134Sthompsa	struct mbuf *m = NULL;
2878203134Sthompsa	struct mbuf *m0;
2879203134Sthompsa	uint32_t dmalen;
2880259032Skevlo	uint16_t rxwisize;
2881203134Sthompsa	int xferlen;
2882203134Sthompsa
2883260219Skevlo	rxwisize = sizeof(struct rt2860_rxwi);
2884260219Skevlo	if (sc->mac_ver == 0x5592)
2885260219Skevlo		rxwisize += sizeof(uint64_t);
2886260219Skevlo	else if (sc->mac_ver == 0x3593)
2887260219Skevlo		rxwisize += sizeof(uint32_t);
2888259032Skevlo
2889203134Sthompsa	usbd_xfer_status(xfer, &xferlen, NULL, NULL, NULL);
2890203134Sthompsa
2891203134Sthompsa	switch (USB_GET_STATE(xfer)) {
2892203134Sthompsa	case USB_ST_TRANSFERRED:
2893203134Sthompsa
2894203134Sthompsa		DPRINTFN(15, "rx done, actlen=%d\n", xferlen);
2895203134Sthompsa
2896259032Skevlo		if (xferlen < (int)(sizeof(uint32_t) + rxwisize +
2897259032Skevlo		    sizeof(struct rt2870_rxd))) {
2898203134Sthompsa			DPRINTF("xfer too short %d\n", xferlen);
2899203134Sthompsa			goto tr_setup;
2900203134Sthompsa		}
2901203134Sthompsa
2902203134Sthompsa		m = sc->rx_m;
2903203134Sthompsa		sc->rx_m = NULL;
2904203134Sthompsa
2905203134Sthompsa		/* FALLTHROUGH */
2906203134Sthompsa	case USB_ST_SETUP:
2907203134Sthompsatr_setup:
2908203134Sthompsa		if (sc->rx_m == NULL) {
2909243857Sglebius			sc->rx_m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR,
2910203134Sthompsa			    MJUMPAGESIZE /* xfer can be bigger than MCLBYTES */);
2911203134Sthompsa		}
2912203134Sthompsa		if (sc->rx_m == NULL) {
2913203134Sthompsa			DPRINTF("could not allocate mbuf - idle with stall\n");
2914287197Sglebius			counter_u64_add(ic->ic_ierrors, 1);
2915203134Sthompsa			usbd_xfer_set_stall(xfer);
2916203134Sthompsa			usbd_xfer_set_frames(xfer, 0);
2917203134Sthompsa		} else {
2918203134Sthompsa			/*
2919203134Sthompsa			 * Directly loading a mbuf cluster into DMA to
2920203134Sthompsa			 * save some data copying. This works because
2921203134Sthompsa			 * there is only one cluster.
2922203134Sthompsa			 */
2923203134Sthompsa			usbd_xfer_set_frame_data(xfer, 0,
2924203134Sthompsa			    mtod(sc->rx_m, caddr_t), RUN_MAX_RXSZ);
2925203134Sthompsa			usbd_xfer_set_frames(xfer, 1);
2926203134Sthompsa		}
2927203134Sthompsa		usbd_transfer_submit(xfer);
2928203134Sthompsa		break;
2929203134Sthompsa
2930203134Sthompsa	default:	/* Error */
2931203134Sthompsa		if (error != USB_ERR_CANCELLED) {
2932203134Sthompsa			/* try to clear stall first */
2933203134Sthompsa			usbd_xfer_set_stall(xfer);
2934203134Sthompsa			if (error == USB_ERR_TIMEOUT)
2935203134Sthompsa				device_printf(sc->sc_dev, "device timeout\n");
2936287197Sglebius			counter_u64_add(ic->ic_ierrors, 1);
2937203134Sthompsa			goto tr_setup;
2938203134Sthompsa		}
2939209917Sthompsa		if (sc->rx_m != NULL) {
2940203134Sthompsa			m_freem(sc->rx_m);
2941203134Sthompsa			sc->rx_m = NULL;
2942203134Sthompsa		}
2943203134Sthompsa		break;
2944203134Sthompsa	}
2945203134Sthompsa
2946203134Sthompsa	if (m == NULL)
2947203134Sthompsa		return;
2948203134Sthompsa
2949203134Sthompsa	/* inputting all the frames must be last */
2950203134Sthompsa
2951203134Sthompsa	RUN_UNLOCK(sc);
2952203134Sthompsa
2953203134Sthompsa	m->m_pkthdr.len = m->m_len = xferlen;
2954203134Sthompsa
2955203134Sthompsa	/* HW can aggregate multiple 802.11 frames in a single USB xfer */
2956203134Sthompsa	for(;;) {
2957203134Sthompsa		dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff;
2958203134Sthompsa
2959233774Shselasky		if ((dmalen >= (uint32_t)-8) || (dmalen == 0) ||
2960233774Shselasky		    ((dmalen & 3) != 0)) {
2961203134Sthompsa			DPRINTF("bad DMA length %u\n", dmalen);
2962203134Sthompsa			break;
2963203134Sthompsa		}
2964233774Shselasky		if ((dmalen + 8) > (uint32_t)xferlen) {
2965203134Sthompsa			DPRINTF("bad DMA length %u > %d\n",
2966203134Sthompsa			dmalen + 8, xferlen);
2967203134Sthompsa			break;
2968203134Sthompsa		}
2969203134Sthompsa
2970203134Sthompsa		/* If it is the last one or a single frame, we won't copy. */
2971209917Sthompsa		if ((xferlen -= dmalen + 8) <= 8) {
2972203134Sthompsa			/* trim 32-bit DMA-len header */
2973203134Sthompsa			m->m_data += 4;
2974203134Sthompsa			m->m_pkthdr.len = m->m_len -= 4;
2975203134Sthompsa			run_rx_frame(sc, m, dmalen);
2976257435Shselasky			m = NULL;	/* don't free source buffer */
2977203134Sthompsa			break;
2978203134Sthompsa		}
2979203134Sthompsa
2980203134Sthompsa		/* copy aggregated frames to another mbuf */
2981243857Sglebius		m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
2982203134Sthompsa		if (__predict_false(m0 == NULL)) {
2983203134Sthompsa			DPRINTF("could not allocate mbuf\n");
2984287197Sglebius			counter_u64_add(ic->ic_ierrors, 1);
2985203134Sthompsa			break;
2986203134Sthompsa		}
2987203134Sthompsa		m_copydata(m, 4 /* skip 32-bit DMA-len header */,
2988203134Sthompsa		    dmalen + sizeof(struct rt2870_rxd), mtod(m0, caddr_t));
2989203134Sthompsa		m0->m_pkthdr.len = m0->m_len =
2990203134Sthompsa		    dmalen + sizeof(struct rt2870_rxd);
2991203134Sthompsa		run_rx_frame(sc, m0, dmalen);
2992203134Sthompsa
2993203134Sthompsa		/* update data ptr */
2994203134Sthompsa		m->m_data += dmalen + 8;
2995203134Sthompsa		m->m_pkthdr.len = m->m_len -= dmalen + 8;
2996203134Sthompsa	}
2997203134Sthompsa
2998257435Shselasky	/* make sure we free the source buffer, if any */
2999257435Shselasky	m_freem(m);
3000257435Shselasky
3001203134Sthompsa	RUN_LOCK(sc);
3002203134Sthompsa}
3003203134Sthompsa
3004203134Sthompsastatic void
3005203134Sthompsarun_tx_free(struct run_endpoint_queue *pq,
3006203134Sthompsa    struct run_tx_data *data, int txerr)
3007203134Sthompsa{
3008203134Sthompsa
3009289841Savos	ieee80211_tx_complete(data->ni, data->m, txerr);
3010203134Sthompsa
3011289841Savos	data->m = NULL;
3012289841Savos	data->ni = NULL;
3013289841Savos
3014203134Sthompsa	STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
3015203134Sthompsa	pq->tx_nfree++;
3016203134Sthompsa}
3017203134Sthompsa
3018203134Sthompsastatic void
3019257429Shselaskyrun_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, u_int index)
3020203134Sthompsa{
3021203134Sthompsa	struct run_softc *sc = usbd_xfer_softc(xfer);
3022287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3023203134Sthompsa	struct run_tx_data *data;
3024203134Sthompsa	struct ieee80211vap *vap = NULL;
3025203134Sthompsa	struct usb_page_cache *pc;
3026203134Sthompsa	struct run_endpoint_queue *pq = &sc->sc_epq[index];
3027203134Sthompsa	struct mbuf *m;
3028203134Sthompsa	usb_frlength_t size;
3029203134Sthompsa	int actlen;
3030203134Sthompsa	int sumlen;
3031203134Sthompsa
3032203134Sthompsa	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
3033203134Sthompsa
3034209917Sthompsa	switch (USB_GET_STATE(xfer)) {
3035203134Sthompsa	case USB_ST_TRANSFERRED:
3036203134Sthompsa		DPRINTFN(11, "transfer complete: %d "
3037203134Sthompsa		    "bytes @ index %d\n", actlen, index);
3038203134Sthompsa
3039203134Sthompsa		data = usbd_xfer_get_priv(xfer);
3040203134Sthompsa		run_tx_free(pq, data, 0);
3041203134Sthompsa		usbd_xfer_set_priv(xfer, NULL);
3042203134Sthompsa
3043203134Sthompsa		/* FALLTHROUGH */
3044203134Sthompsa	case USB_ST_SETUP:
3045203134Sthompsatr_setup:
3046203134Sthompsa		data = STAILQ_FIRST(&pq->tx_qh);
3047209917Sthompsa		if (data == NULL)
3048203134Sthompsa			break;
3049203134Sthompsa
3050203134Sthompsa		STAILQ_REMOVE_HEAD(&pq->tx_qh, next);
3051203134Sthompsa
3052203134Sthompsa		m = data->m;
3053261330Shselasky		size = (sc->mac_ver == 0x5592) ?
3054261330Shselasky		    sizeof(data->desc) + sizeof(uint32_t) : sizeof(data->desc);
3055261076Shselasky		if ((m->m_pkthdr.len +
3056261330Shselasky		    size + 3 + 8) > RUN_MAX_TXSZ) {
3057203134Sthompsa			DPRINTF("data overflow, %u bytes\n",
3058203134Sthompsa			    m->m_pkthdr.len);
3059203134Sthompsa			run_tx_free(pq, data, 1);
3060203134Sthompsa			goto tr_setup;
3061203134Sthompsa		}
3062203134Sthompsa
3063203134Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
3064203134Sthompsa		usbd_copy_in(pc, 0, &data->desc, size);
3065203134Sthompsa		usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len);
3066228508Shselasky		size += m->m_pkthdr.len;
3067228508Shselasky		/*
3068228508Shselasky		 * Align end on a 4-byte boundary, pad 8 bytes (CRC +
3069228508Shselasky		 * 4-byte padding), and be sure to zero those trailing
3070228508Shselasky		 * bytes:
3071228508Shselasky		 */
3072228508Shselasky		usbd_frame_zero(pc, size, ((-size) & 3) + 8);
3073228508Shselasky		size += ((-size) & 3) + 8;
3074203134Sthompsa
3075203134Sthompsa		vap = data->ni->ni_vap;
3076203134Sthompsa		if (ieee80211_radiotap_active_vap(vap)) {
3077203134Sthompsa			struct run_tx_radiotap_header *tap = &sc->sc_txtap;
3078259032Skevlo			struct rt2860_txwi *txwi =
3079208019Sthompsa			    (struct rt2860_txwi *)(&data->desc + sizeof(struct rt2870_txd));
3080203134Sthompsa			tap->wt_flags = 0;
3081203134Sthompsa			tap->wt_rate = rt2860_rates[data->ridx].rate;
3082287554Skevlo			run_get_tsf(sc, &tap->wt_tsf);
3083236439Shselasky			tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
3084236439Shselasky			tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
3085203134Sthompsa			tap->wt_hwqueue = index;
3086208019Sthompsa			if (le16toh(txwi->phy) & RT2860_PHY_SHPRE)
3087203134Sthompsa				tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
3088203134Sthompsa
3089203134Sthompsa			ieee80211_radiotap_tx(vap, m);
3090203134Sthompsa		}
3091203134Sthompsa
3092228508Shselasky		DPRINTFN(11, "sending frame len=%u/%u  @ index %d\n",
3093228508Shselasky		    m->m_pkthdr.len, size, index);
3094203134Sthompsa
3095228508Shselasky		usbd_xfer_set_frame_len(xfer, 0, size);
3096203134Sthompsa		usbd_xfer_set_priv(xfer, data);
3097203134Sthompsa		usbd_transfer_submit(xfer);
3098287197Sglebius		run_start(sc);
3099203134Sthompsa
3100203134Sthompsa		break;
3101203134Sthompsa
3102203134Sthompsa	default:
3103203134Sthompsa		DPRINTF("USB transfer error, %s\n",
3104203134Sthompsa		    usbd_errstr(error));
3105203134Sthompsa
3106203134Sthompsa		data = usbd_xfer_get_priv(xfer);
3107203134Sthompsa
3108203134Sthompsa		if (data != NULL) {
3109208019Sthompsa			if(data->ni != NULL)
3110208019Sthompsa				vap = data->ni->ni_vap;
3111203134Sthompsa			run_tx_free(pq, data, error);
3112203134Sthompsa			usbd_xfer_set_priv(xfer, NULL);
3113203134Sthompsa		}
3114287197Sglebius
3115209917Sthompsa		if (vap == NULL)
3116208019Sthompsa			vap = TAILQ_FIRST(&ic->ic_vaps);
3117203134Sthompsa
3118203134Sthompsa		if (error != USB_ERR_CANCELLED) {
3119203134Sthompsa			if (error == USB_ERR_TIMEOUT) {
3120203134Sthompsa				device_printf(sc->sc_dev, "device timeout\n");
3121208019Sthompsa				uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
3122208019Sthompsa				DPRINTF("cmdq_store=%d\n", i);
3123208019Sthompsa				sc->cmdq[i].func = run_usb_timeout_cb;
3124208019Sthompsa				sc->cmdq[i].arg0 = vap;
3125208019Sthompsa				ieee80211_runtask(ic, &sc->cmdq_task);
3126203134Sthompsa			}
3127203134Sthompsa
3128203134Sthompsa			/*
3129203134Sthompsa			 * Try to clear stall first, also if other
3130203134Sthompsa			 * errors occur, hence clearing stall
3131203134Sthompsa			 * introduces a 50 ms delay:
3132203134Sthompsa			 */
3133203134Sthompsa			usbd_xfer_set_stall(xfer);
3134203134Sthompsa			goto tr_setup;
3135203134Sthompsa		}
3136203134Sthompsa		break;
3137203134Sthompsa	}
3138203134Sthompsa}
3139203134Sthompsa
3140203134Sthompsastatic void
3141203134Sthompsarun_bulk_tx_callback0(struct usb_xfer *xfer, usb_error_t error)
3142203134Sthompsa{
3143203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 0);
3144203134Sthompsa}
3145203134Sthompsa
3146203134Sthompsastatic void
3147203134Sthompsarun_bulk_tx_callback1(struct usb_xfer *xfer, usb_error_t error)
3148203134Sthompsa{
3149203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 1);
3150203134Sthompsa}
3151203134Sthompsa
3152203134Sthompsastatic void
3153203134Sthompsarun_bulk_tx_callback2(struct usb_xfer *xfer, usb_error_t error)
3154203134Sthompsa{
3155203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 2);
3156203134Sthompsa}
3157203134Sthompsa
3158203134Sthompsastatic void
3159203134Sthompsarun_bulk_tx_callback3(struct usb_xfer *xfer, usb_error_t error)
3160203134Sthompsa{
3161203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 3);
3162203134Sthompsa}
3163203134Sthompsa
3164203134Sthompsastatic void
3165203134Sthompsarun_bulk_tx_callback4(struct usb_xfer *xfer, usb_error_t error)
3166203134Sthompsa{
3167203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 4);
3168203134Sthompsa}
3169203134Sthompsa
3170203134Sthompsastatic void
3171203134Sthompsarun_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error)
3172203134Sthompsa{
3173203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 5);
3174203134Sthompsa}
3175203134Sthompsa
3176203134Sthompsastatic void
3177208019Sthompsarun_set_tx_desc(struct run_softc *sc, struct run_tx_data *data)
3178203134Sthompsa{
3179203134Sthompsa	struct mbuf *m = data->m;
3180287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3181208019Sthompsa	struct ieee80211vap *vap = data->ni->ni_vap;
3182203134Sthompsa	struct ieee80211_frame *wh;
3183203134Sthompsa	struct rt2870_txd *txd;
3184203134Sthompsa	struct rt2860_txwi *txwi;
3185259032Skevlo	uint16_t xferlen, txwisize;
3186208019Sthompsa	uint16_t mcs;
3187203134Sthompsa	uint8_t ridx = data->ridx;
3188208019Sthompsa	uint8_t pad;
3189203134Sthompsa
3190203134Sthompsa	/* get MCS code from rate index */
3191208019Sthompsa	mcs = rt2860_rates[ridx].mcs;
3192203134Sthompsa
3193259032Skevlo	txwisize = (sc->mac_ver == 0x5592) ?
3194259032Skevlo	    sizeof(*txwi) + sizeof(uint32_t) : sizeof(*txwi);
3195259032Skevlo	xferlen = txwisize + m->m_pkthdr.len;
3196203134Sthompsa
3197203134Sthompsa	/* roundup to 32-bit alignment */
3198203134Sthompsa	xferlen = (xferlen + 3) & ~3;
3199203134Sthompsa
3200203134Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3201203134Sthompsa	txd->len = htole16(xferlen);
3202203134Sthompsa
3203208019Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3204208019Sthompsa
3205208019Sthompsa	/*
3206208019Sthompsa	 * Ether both are true or both are false, the header
3207208019Sthompsa	 * are nicely aligned to 32-bit. So, no L2 padding.
3208208019Sthompsa	 */
3209208019Sthompsa	if(IEEE80211_HAS_ADDR4(wh) == IEEE80211_QOS_HAS_SEQ(wh))
3210208019Sthompsa		pad = 0;
3211208019Sthompsa	else
3212208019Sthompsa		pad = 2;
3213208019Sthompsa
3214203134Sthompsa	/* setup TX Wireless Information */
3215203134Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3216203134Sthompsa	txwi->len = htole16(m->m_pkthdr.len - pad);
3217203134Sthompsa	if (rt2860_rates[ridx].phy == IEEE80211_T_DS) {
3218270192Skevlo		mcs |= RT2860_PHY_CCK;
3219203134Sthompsa		if (ridx != RT2860_RIDX_CCK1 &&
3220203134Sthompsa		    (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
3221203134Sthompsa			mcs |= RT2860_PHY_SHPRE;
3222203134Sthompsa	} else
3223270192Skevlo		mcs |= RT2860_PHY_OFDM;
3224270192Skevlo	txwi->phy = htole16(mcs);
3225203134Sthompsa
3226203134Sthompsa	/* check if RTS/CTS or CTS-to-self protection is required */
3227203134Sthompsa	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
3228203134Sthompsa	    (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold ||
3229203134Sthompsa	     ((ic->ic_flags & IEEE80211_F_USEPROT) &&
3230203134Sthompsa	      rt2860_rates[ridx].phy == IEEE80211_T_OFDM)))
3231208019Sthompsa		txwi->txop |= RT2860_TX_TXOP_HT;
3232203134Sthompsa	else
3233208019Sthompsa		txwi->txop |= RT2860_TX_TXOP_BACKOFF;
3234209144Sthompsa
3235209917Sthompsa	if (vap->iv_opmode != IEEE80211_M_STA && !IEEE80211_QOS_HAS_SEQ(wh))
3236209144Sthompsa		txwi->xflags |= RT2860_TX_NSEQ;
3237203134Sthompsa}
3238203134Sthompsa
3239203134Sthompsa/* This function must be called locked */
3240203134Sthompsastatic int
3241203134Sthompsarun_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
3242203134Sthompsa{
3243287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3244208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
3245203134Sthompsa	struct ieee80211_frame *wh;
3246208019Sthompsa	struct ieee80211_channel *chan;
3247203134Sthompsa	const struct ieee80211_txparam *tp;
3248287552Skevlo	struct run_node *rn = RUN_NODE(ni);
3249203134Sthompsa	struct run_tx_data *data;
3250208019Sthompsa	struct rt2870_txd *txd;
3251208019Sthompsa	struct rt2860_txwi *txwi;
3252203134Sthompsa	uint16_t qos;
3253203134Sthompsa	uint16_t dur;
3254208019Sthompsa	uint16_t qid;
3255203134Sthompsa	uint8_t type;
3256203134Sthompsa	uint8_t tid;
3257208019Sthompsa	uint8_t ridx;
3258208019Sthompsa	uint8_t ctl_ridx;
3259203134Sthompsa	uint8_t qflags;
3260203134Sthompsa	uint8_t xflags = 0;
3261203134Sthompsa	int hasqos;
3262203134Sthompsa
3263203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3264203134Sthompsa
3265203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3266203134Sthompsa
3267203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3268203134Sthompsa
3269203134Sthompsa	/*
3270203134Sthompsa	 * There are 7 bulk endpoints: 1 for RX
3271203134Sthompsa	 * and 6 for TX (4 EDCAs + HCCA + Prio).
3272203134Sthompsa	 * Update 03-14-2009:  some devices like the Planex GW-US300MiniS
3273203134Sthompsa	 * seem to have only 4 TX bulk endpoints (Fukaumi Naoki).
3274203134Sthompsa	 */
3275203134Sthompsa	if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) {
3276203134Sthompsa		uint8_t *frm;
3277203134Sthompsa
3278203134Sthompsa		if(IEEE80211_HAS_ADDR4(wh))
3279203134Sthompsa			frm = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos;
3280203134Sthompsa		else
3281203134Sthompsa			frm =((struct ieee80211_qosframe *)wh)->i_qos;
3282203134Sthompsa
3283203134Sthompsa		qos = le16toh(*(const uint16_t *)frm);
3284203134Sthompsa		tid = qos & IEEE80211_QOS_TID;
3285203134Sthompsa		qid = TID_TO_WME_AC(tid);
3286203134Sthompsa	} else {
3287203134Sthompsa		qos = 0;
3288203134Sthompsa		tid = 0;
3289203134Sthompsa		qid = WME_AC_BE;
3290203134Sthompsa	}
3291203134Sthompsa	qflags = (qid < 4) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA;
3292203134Sthompsa
3293203134Sthompsa	DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n",
3294203134Sthompsa	    qos, qid, tid, qflags);
3295203134Sthompsa
3296208019Sthompsa	chan = (ni->ni_chan != IEEE80211_CHAN_ANYC)?ni->ni_chan:ic->ic_curchan;
3297208019Sthompsa	tp = &vap->iv_txparms[ieee80211_chan2mode(chan)];
3298203134Sthompsa
3299203134Sthompsa	/* pickup a rate index */
3300203134Sthompsa	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
3301270192Skevlo	    type != IEEE80211_FC0_TYPE_DATA || m->m_flags & M_EAPOL) {
3302203134Sthompsa		ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
3303203134Sthompsa		    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
3304203134Sthompsa		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
3305203134Sthompsa	} else {
3306208019Sthompsa		if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
3307208019Sthompsa			ridx = rn->fix_ridx;
3308208019Sthompsa		else
3309208019Sthompsa			ridx = rn->amrr_ridx;
3310203134Sthompsa		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
3311203134Sthompsa	}
3312203134Sthompsa
3313203134Sthompsa	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
3314203134Sthompsa	    (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) !=
3315203134Sthompsa	     IEEE80211_QOS_ACKPOLICY_NOACK)) {
3316209144Sthompsa		xflags |= RT2860_TX_ACK;
3317203134Sthompsa		if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
3318208019Sthompsa			dur = rt2860_rates[ctl_ridx].sp_ack_dur;
3319203134Sthompsa		else
3320208019Sthompsa			dur = rt2860_rates[ctl_ridx].lp_ack_dur;
3321258919Shselasky		USETW(wh->i_dur, dur);
3322203134Sthompsa	}
3323203134Sthompsa
3324203134Sthompsa	/* reserve slots for mgmt packets, just in case */
3325203134Sthompsa	if (sc->sc_epq[qid].tx_nfree < 3) {
3326203134Sthompsa		DPRINTFN(10, "tx ring %d is full\n", qid);
3327203134Sthompsa		return (-1);
3328203134Sthompsa	}
3329203134Sthompsa
3330203134Sthompsa	data = STAILQ_FIRST(&sc->sc_epq[qid].tx_fh);
3331203134Sthompsa	STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next);
3332203134Sthompsa	sc->sc_epq[qid].tx_nfree--;
3333203134Sthompsa
3334208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3335208019Sthompsa	txd->flags = qflags;
3336208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3337208019Sthompsa	txwi->xflags = xflags;
3338259032Skevlo	if (IEEE80211_IS_MULTICAST(wh->i_addr1))
3339245047Shselasky		txwi->wcid = 0;
3340259032Skevlo	else
3341245047Shselasky		txwi->wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
3342245047Shselasky		    1 : RUN_AID2WCID(ni->ni_associd);
3343259032Skevlo
3344208019Sthompsa	/* clear leftover garbage bits */
3345208019Sthompsa	txwi->flags = 0;
3346208019Sthompsa	txwi->txop = 0;
3347208019Sthompsa
3348203134Sthompsa	data->m = m;
3349203134Sthompsa	data->ni = ni;
3350203134Sthompsa	data->ridx = ridx;
3351203134Sthompsa
3352208019Sthompsa	run_set_tx_desc(sc, data);
3353203134Sthompsa
3354208019Sthompsa	/*
3355208019Sthompsa	 * The chip keeps track of 2 kind of Tx stats,
3356208019Sthompsa	 *  * TX_STAT_FIFO, for per WCID stats, and
3357208019Sthompsa	 *  * TX_STA_CNT0 for all-TX-in-one stats.
3358208019Sthompsa	 *
3359208019Sthompsa	 * To use FIFO stats, we need to store MCS into the driver-private
3360208019Sthompsa 	 * PacketID field. So that, we can tell whose stats when we read them.
3361208019Sthompsa 	 * We add 1 to the MCS because setting the PacketID field to 0 means
3362208019Sthompsa 	 * that we don't want feedback in TX_STAT_FIFO.
3363208019Sthompsa 	 * And, that's what we want for STA mode, since TX_STA_CNT0 does the job.
3364208019Sthompsa 	 *
3365208019Sthompsa 	 * FIFO stats doesn't count Tx with WCID 0xff, so we do this in run_tx().
3366208019Sthompsa 	 */
3367209917Sthompsa	if (sc->rvp_cnt > 1 || vap->iv_opmode == IEEE80211_M_HOSTAP ||
3368209917Sthompsa	    vap->iv_opmode == IEEE80211_M_MBSS) {
3369208019Sthompsa		uint16_t pid = (rt2860_rates[ridx].mcs + 1) & 0xf;
3370208019Sthompsa		txwi->len |= htole16(pid << RT2860_TX_PID_SHIFT);
3371208019Sthompsa
3372208019Sthompsa		/*
3373208019Sthompsa		 * Unlike PCI based devices, we don't get any interrupt from
3374208019Sthompsa		 * USB devices, so we simulate FIFO-is-full interrupt here.
3375208019Sthompsa		 * Ralink recomends to drain FIFO stats every 100 ms, but 16 slots
3376208019Sthompsa		 * quickly get fulled. To prevent overflow, increment a counter on
3377208019Sthompsa		 * every FIFO stat request, so we know how many slots are left.
3378208019Sthompsa		 * We do this only in HOSTAP or multiple vap mode since FIFO stats
3379208019Sthompsa		 * are used only in those modes.
3380208019Sthompsa		 * We just drain stats. AMRR gets updated every 1 sec by
3381208019Sthompsa		 * run_ratectl_cb() via callout.
3382208019Sthompsa		 * Call it early. Otherwise overflow.
3383208019Sthompsa		 */
3384209917Sthompsa		if (sc->fifo_cnt++ == 10) {
3385208019Sthompsa			/*
3386208019Sthompsa			 * With multiple vaps or if_bridge, if_start() is called
3387208019Sthompsa			 * with a non-sleepable lock, tcpinp. So, need to defer.
3388208019Sthompsa			 */
3389208019Sthompsa			uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
3390208019Sthompsa			DPRINTFN(6, "cmdq_store=%d\n", i);
3391208019Sthompsa			sc->cmdq[i].func = run_drain_fifo;
3392208019Sthompsa			sc->cmdq[i].arg0 = sc;
3393208019Sthompsa			ieee80211_runtask(ic, &sc->cmdq_task);
3394208019Sthompsa		}
3395208019Sthompsa	}
3396208019Sthompsa
3397203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next);
3398203134Sthompsa
3399203134Sthompsa	usbd_transfer_start(sc->sc_xfer[qid]);
3400203134Sthompsa
3401258840Skevlo	DPRINTFN(8, "sending data frame len=%d rate=%d qid=%d\n",
3402259032Skevlo	    m->m_pkthdr.len + (int)(sizeof(struct rt2870_txd) +
3403259046Shselasky	    sizeof(struct rt2860_txwi)), rt2860_rates[ridx].rate, qid);
3404203134Sthompsa
3405203134Sthompsa	return (0);
3406203134Sthompsa}
3407203134Sthompsa
3408203134Sthompsastatic int
3409203134Sthompsarun_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
3410203134Sthompsa{
3411287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3412287552Skevlo	struct run_node *rn = RUN_NODE(ni);
3413203134Sthompsa	struct run_tx_data *data;
3414203134Sthompsa	struct ieee80211_frame *wh;
3415208019Sthompsa	struct rt2870_txd *txd;
3416208019Sthompsa	struct rt2860_txwi *txwi;
3417203134Sthompsa	uint16_t dur;
3418208019Sthompsa	uint8_t ridx = rn->mgt_ridx;
3419203134Sthompsa	uint8_t type;
3420203134Sthompsa	uint8_t xflags = 0;
3421208019Sthompsa	uint8_t wflags = 0;
3422203134Sthompsa
3423203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3424203134Sthompsa
3425203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3426203134Sthompsa
3427203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3428203134Sthompsa
3429208019Sthompsa	/* tell hardware to add timestamp for probe responses */
3430208019Sthompsa	if ((wh->i_fc[0] &
3431208019Sthompsa	    (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==
3432208019Sthompsa	    (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP))
3433208019Sthompsa		wflags |= RT2860_TX_TS;
3434208019Sthompsa	else if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3435203134Sthompsa		xflags |= RT2860_TX_ACK;
3436203134Sthompsa
3437208019Sthompsa		dur = ieee80211_ack_duration(ic->ic_rt, rt2860_rates[ridx].rate,
3438203134Sthompsa		    ic->ic_flags & IEEE80211_F_SHPREAMBLE);
3439258919Shselasky		USETW(wh->i_dur, dur);
3440203134Sthompsa	}
3441203134Sthompsa
3442287197Sglebius	if (sc->sc_epq[0].tx_nfree == 0)
3443203134Sthompsa		/* let caller free mbuf */
3444203134Sthompsa		return (EIO);
3445203134Sthompsa	data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3446203134Sthompsa	STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3447203134Sthompsa	sc->sc_epq[0].tx_nfree--;
3448203134Sthompsa
3449208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3450208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3451208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3452208019Sthompsa	txwi->wcid = 0xff;
3453208019Sthompsa	txwi->flags = wflags;
3454208019Sthompsa	txwi->xflags = xflags;
3455208019Sthompsa	txwi->txop = 0;	/* clear leftover garbage bits */
3456208019Sthompsa
3457203134Sthompsa	data->m = m;
3458203134Sthompsa	data->ni = ni;
3459203134Sthompsa	data->ridx = ridx;
3460203134Sthompsa
3461208019Sthompsa	run_set_tx_desc(sc, data);
3462203134Sthompsa
3463203134Sthompsa	DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m->m_pkthdr.len +
3464258840Skevlo	    (int)(sizeof(struct rt2870_txd) + sizeof(struct rt2860_txwi)),
3465208019Sthompsa	    rt2860_rates[ridx].rate);
3466203134Sthompsa
3467203134Sthompsa	STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3468203134Sthompsa
3469203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3470203134Sthompsa
3471203134Sthompsa	return (0);
3472203134Sthompsa}
3473203134Sthompsa
3474203134Sthompsastatic int
3475203134Sthompsarun_sendprot(struct run_softc *sc,
3476203134Sthompsa    const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate)
3477203134Sthompsa{
3478203134Sthompsa	struct ieee80211com *ic = ni->ni_ic;
3479203134Sthompsa	struct ieee80211_frame *wh;
3480203134Sthompsa	struct run_tx_data *data;
3481208019Sthompsa	struct rt2870_txd *txd;
3482208019Sthompsa	struct rt2860_txwi *txwi;
3483203134Sthompsa	struct mbuf *mprot;
3484203134Sthompsa	int ridx;
3485203134Sthompsa	int protrate;
3486203134Sthompsa	int ackrate;
3487203134Sthompsa	int pktlen;
3488203134Sthompsa	int isshort;
3489203134Sthompsa	uint16_t dur;
3490203134Sthompsa	uint8_t type;
3491208019Sthompsa	uint8_t wflags = 0;
3492208019Sthompsa	uint8_t xflags = 0;
3493203134Sthompsa
3494203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3495203134Sthompsa
3496203134Sthompsa	KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY,
3497203134Sthompsa	    ("protection %d", prot));
3498203134Sthompsa
3499203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3500203134Sthompsa	pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN;
3501203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3502203134Sthompsa
3503203134Sthompsa	protrate = ieee80211_ctl_rate(ic->ic_rt, rate);
3504203134Sthompsa	ackrate = ieee80211_ack_rate(ic->ic_rt, rate);
3505203134Sthompsa
3506203134Sthompsa	isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
3507209189Sjkim	dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort)
3508203134Sthompsa	    + ieee80211_ack_duration(ic->ic_rt, rate, isshort);
3509203134Sthompsa	wflags = RT2860_TX_FRAG;
3510203134Sthompsa
3511203134Sthompsa	/* check that there are free slots before allocating the mbuf */
3512287197Sglebius	if (sc->sc_epq[0].tx_nfree == 0)
3513203134Sthompsa		/* let caller free mbuf */
3514203134Sthompsa		return (ENOBUFS);
3515203134Sthompsa
3516203134Sthompsa	if (prot == IEEE80211_PROT_RTSCTS) {
3517203134Sthompsa		/* NB: CTS is the same size as an ACK */
3518203134Sthompsa		dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort);
3519208019Sthompsa		xflags |= RT2860_TX_ACK;
3520203134Sthompsa		mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur);
3521203134Sthompsa	} else {
3522203134Sthompsa		mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur);
3523203134Sthompsa	}
3524203134Sthompsa	if (mprot == NULL) {
3525287197Sglebius		if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1);
3526203134Sthompsa		DPRINTF("could not allocate mbuf\n");
3527203134Sthompsa		return (ENOBUFS);
3528203134Sthompsa	}
3529203134Sthompsa
3530203134Sthompsa        data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3531203134Sthompsa        STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3532203134Sthompsa        sc->sc_epq[0].tx_nfree--;
3533203134Sthompsa
3534208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3535208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3536208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3537208019Sthompsa	txwi->wcid = 0xff;
3538208019Sthompsa	txwi->flags = wflags;
3539208019Sthompsa	txwi->xflags = xflags;
3540208019Sthompsa	txwi->txop = 0;	/* clear leftover garbage bits */
3541208019Sthompsa
3542203134Sthompsa	data->m = mprot;
3543203134Sthompsa	data->ni = ieee80211_ref_node(ni);
3544203134Sthompsa
3545203134Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
3546203134Sthompsa		if (rt2860_rates[ridx].rate == protrate)
3547203134Sthompsa			break;
3548203134Sthompsa	data->ridx = ridx;
3549203134Sthompsa
3550208019Sthompsa	run_set_tx_desc(sc, data);
3551203134Sthompsa
3552203134Sthompsa        DPRINTFN(1, "sending prot len=%u rate=%u\n",
3553203134Sthompsa            m->m_pkthdr.len, rate);
3554203134Sthompsa
3555203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3556203134Sthompsa
3557203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3558203134Sthompsa
3559203134Sthompsa	return (0);
3560203134Sthompsa}
3561203134Sthompsa
3562203134Sthompsastatic int
3563203134Sthompsarun_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni,
3564203134Sthompsa    const struct ieee80211_bpf_params *params)
3565203134Sthompsa{
3566203134Sthompsa	struct ieee80211com *ic = ni->ni_ic;
3567203134Sthompsa	struct ieee80211_frame *wh;
3568203134Sthompsa	struct run_tx_data *data;
3569208019Sthompsa	struct rt2870_txd *txd;
3570208019Sthompsa	struct rt2860_txwi *txwi;
3571203134Sthompsa	uint8_t type;
3572208019Sthompsa	uint8_t ridx;
3573208019Sthompsa	uint8_t rate;
3574208019Sthompsa	uint8_t opflags = 0;
3575208019Sthompsa	uint8_t xflags = 0;
3576203134Sthompsa	int error;
3577203134Sthompsa
3578203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3579203134Sthompsa
3580203134Sthompsa	KASSERT(params != NULL, ("no raw xmit params"));
3581203134Sthompsa
3582203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3583203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3584203134Sthompsa
3585203134Sthompsa	rate = params->ibp_rate0;
3586203134Sthompsa	if (!ieee80211_isratevalid(ic->ic_rt, rate)) {
3587203134Sthompsa		/* let caller free mbuf */
3588203134Sthompsa		return (EINVAL);
3589203134Sthompsa	}
3590203134Sthompsa
3591203134Sthompsa	if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0)
3592208019Sthompsa		xflags |= RT2860_TX_ACK;
3593203134Sthompsa	if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) {
3594203134Sthompsa		error = run_sendprot(sc, m, ni,
3595203134Sthompsa		    params->ibp_flags & IEEE80211_BPF_RTS ?
3596203134Sthompsa			IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY,
3597203134Sthompsa		    rate);
3598203134Sthompsa		if (error) {
3599203134Sthompsa			/* let caller free mbuf */
3600209917Sthompsa			return error;
3601203134Sthompsa		}
3602203134Sthompsa		opflags |= /*XXX RT2573_TX_LONG_RETRY |*/ RT2860_TX_TXOP_SIFS;
3603203134Sthompsa	}
3604203134Sthompsa
3605203134Sthompsa	if (sc->sc_epq[0].tx_nfree == 0) {
3606203134Sthompsa		/* let caller free mbuf */
3607203134Sthompsa		DPRINTF("sending raw frame, but tx ring is full\n");
3608203134Sthompsa		return (EIO);
3609203134Sthompsa	}
3610203134Sthompsa        data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3611203134Sthompsa        STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3612203134Sthompsa        sc->sc_epq[0].tx_nfree--;
3613203134Sthompsa
3614208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3615208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3616208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3617208019Sthompsa	txwi->wcid = 0xff;
3618208019Sthompsa	txwi->xflags = xflags;
3619208019Sthompsa	txwi->txop = opflags;
3620208019Sthompsa	txwi->flags = 0;	/* clear leftover garbage bits */
3621208019Sthompsa
3622203134Sthompsa        data->m = m;
3623203134Sthompsa        data->ni = ni;
3624203134Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
3625203134Sthompsa		if (rt2860_rates[ridx].rate == rate)
3626203134Sthompsa			break;
3627203134Sthompsa	data->ridx = ridx;
3628203134Sthompsa
3629208019Sthompsa        run_set_tx_desc(sc, data);
3630203134Sthompsa
3631203134Sthompsa        DPRINTFN(10, "sending raw frame len=%u rate=%u\n",
3632203134Sthompsa            m->m_pkthdr.len, rate);
3633203134Sthompsa
3634203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3635203134Sthompsa
3636203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3637203134Sthompsa
3638209917Sthompsa        return (0);
3639203134Sthompsa}
3640203134Sthompsa
3641203134Sthompsastatic int
3642203134Sthompsarun_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
3643203134Sthompsa    const struct ieee80211_bpf_params *params)
3644203134Sthompsa{
3645286950Sadrian	struct run_softc *sc = ni->ni_ic->ic_softc;
3646208019Sthompsa	int error = 0;
3647208019Sthompsa
3648203134Sthompsa	RUN_LOCK(sc);
3649203134Sthompsa
3650203134Sthompsa	/* prevent management frames from being sent if we're not ready */
3651287197Sglebius	if (!(sc->sc_flags & RUN_RUNNING)) {
3652287197Sglebius		error = ENETDOWN;
3653208019Sthompsa		goto done;
3654203134Sthompsa	}
3655203134Sthompsa
3656203134Sthompsa	if (params == NULL) {
3657203134Sthompsa		/* tx mgt packet */
3658209917Sthompsa		if ((error = run_tx_mgt(sc, m, ni)) != 0) {
3659203134Sthompsa			DPRINTF("mgt tx failed\n");
3660208019Sthompsa			goto done;
3661203134Sthompsa		}
3662203134Sthompsa	} else {
3663203134Sthompsa		/* tx raw packet with param */
3664209917Sthompsa		if ((error = run_tx_param(sc, m, ni, params)) != 0) {
3665203134Sthompsa			DPRINTF("tx with param failed\n");
3666208019Sthompsa			goto done;
3667203134Sthompsa		}
3668203134Sthompsa	}
3669203134Sthompsa
3670208019Sthompsadone:
3671203134Sthompsa	RUN_UNLOCK(sc);
3672203134Sthompsa
3673209917Sthompsa	if (error != 0) {
3674208019Sthompsa		if(m != NULL)
3675208019Sthompsa			m_freem(m);
3676208019Sthompsa	}
3677203134Sthompsa
3678203134Sthompsa	return (error);
3679203134Sthompsa}
3680203134Sthompsa
3681287197Sglebiusstatic int
3682287197Sglebiusrun_transmit(struct ieee80211com *ic, struct mbuf *m)
3683287197Sglebius{
3684287197Sglebius	struct run_softc *sc = ic->ic_softc;
3685287197Sglebius	int error;
3686287197Sglebius
3687287197Sglebius	RUN_LOCK(sc);
3688287197Sglebius	if ((sc->sc_flags & RUN_RUNNING) == 0) {
3689287197Sglebius		RUN_UNLOCK(sc);
3690287197Sglebius		return (ENXIO);
3691287197Sglebius	}
3692287197Sglebius	error = mbufq_enqueue(&sc->sc_snd, m);
3693287197Sglebius	if (error) {
3694287197Sglebius		RUN_UNLOCK(sc);
3695287197Sglebius		return (error);
3696287197Sglebius	}
3697287197Sglebius	run_start(sc);
3698287197Sglebius	RUN_UNLOCK(sc);
3699287197Sglebius
3700287197Sglebius	return (0);
3701287197Sglebius}
3702287197Sglebius
3703203134Sthompsastatic void
3704287197Sglebiusrun_start(struct run_softc *sc)
3705203134Sthompsa{
3706203134Sthompsa	struct ieee80211_node *ni;
3707203134Sthompsa	struct mbuf *m;
3708203134Sthompsa
3709287197Sglebius	RUN_LOCK_ASSERT(sc, MA_OWNED);
3710203134Sthompsa
3711287197Sglebius	if ((sc->sc_flags & RUN_RUNNING) == 0)
3712203134Sthompsa		return;
3713203134Sthompsa
3714287197Sglebius	while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
3715203134Sthompsa		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
3716203134Sthompsa		if (run_tx(sc, m, ni) != 0) {
3717287197Sglebius			mbufq_prepend(&sc->sc_snd, m);
3718203134Sthompsa			break;
3719203134Sthompsa		}
3720203134Sthompsa	}
3721203134Sthompsa}
3722203134Sthompsa
3723287197Sglebiusstatic void
3724287197Sglebiusrun_parent(struct ieee80211com *ic)
3725203134Sthompsa{
3726286950Sadrian	struct run_softc *sc = ic->ic_softc;
3727208019Sthompsa	int startall = 0;
3728203134Sthompsa
3729246614Shselasky	RUN_LOCK(sc);
3730287197Sglebius	if (sc->sc_detached) {
3731203134Sthompsa		RUN_UNLOCK(sc);
3732287197Sglebius		return;
3733203134Sthompsa	}
3734203134Sthompsa
3735287197Sglebius	if (ic->ic_nrunning > 0) {
3736287197Sglebius		if (!(sc->sc_flags & RUN_RUNNING)) {
3737287197Sglebius			startall = 1;
3738287197Sglebius			run_init_locked(sc);
3739287197Sglebius		} else
3740287197Sglebius			run_update_promisc_locked(sc);
3741287197Sglebius	} else if ((sc->sc_flags & RUN_RUNNING) && sc->rvp_cnt <= 1)
3742287197Sglebius		run_stop(sc);
3743287197Sglebius	RUN_UNLOCK(sc);
3744287197Sglebius	if (startall)
3745287197Sglebius		ieee80211_start_all(ic);
3746203134Sthompsa}
3747203134Sthompsa
3748203134Sthompsastatic void
3749259544Skevlorun_iq_calib(struct run_softc *sc, u_int chan)
3750259544Skevlo{
3751259544Skevlo	uint16_t val;
3752259544Skevlo
3753259544Skevlo	/* Tx0 IQ gain. */
3754259544Skevlo	run_bbp_write(sc, 158, 0x2c);
3755259544Skevlo	if (chan <= 14)
3756259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX0_2GHZ, &val, 1);
3757259544Skevlo	else if (chan <= 64) {
3758259544Skevlo		run_efuse_read(sc,
3759259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH36_TO_CH64_5GHZ,
3760259544Skevlo		    &val, 1);
3761259544Skevlo	} else if (chan <= 138) {
3762259544Skevlo		run_efuse_read(sc,
3763259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH100_TO_CH138_5GHZ,
3764259544Skevlo		    &val, 1);
3765259544Skevlo	} else if (chan <= 165) {
3766259544Skevlo		run_efuse_read(sc,
3767259544Skevlo	    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH140_TO_CH165_5GHZ,
3768259544Skevlo		    &val, 1);
3769259544Skevlo	} else
3770259544Skevlo		val = 0;
3771259547Skevlo	run_bbp_write(sc, 159, val);
3772259544Skevlo
3773259544Skevlo	/* Tx0 IQ phase. */
3774259544Skevlo	run_bbp_write(sc, 158, 0x2d);
3775259544Skevlo	if (chan <= 14) {
3776259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX0_2GHZ,
3777259544Skevlo		    &val, 1);
3778259544Skevlo	} else if (chan <= 64) {
3779259544Skevlo		run_efuse_read(sc,
3780259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH36_TO_CH64_5GHZ,
3781259544Skevlo		    &val, 1);
3782259544Skevlo	} else if (chan <= 138) {
3783259544Skevlo		run_efuse_read(sc,
3784259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH100_TO_CH138_5GHZ,
3785259544Skevlo		    &val, 1);
3786259544Skevlo	} else if (chan <= 165) {
3787259544Skevlo		run_efuse_read(sc,
3788259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH140_TO_CH165_5GHZ,
3789259544Skevlo		    &val, 1);
3790259544Skevlo	} else
3791259544Skevlo		val = 0;
3792259547Skevlo	run_bbp_write(sc, 159, val);
3793259544Skevlo
3794259544Skevlo	/* Tx1 IQ gain. */
3795259544Skevlo	run_bbp_write(sc, 158, 0x4a);
3796259544Skevlo	if (chan <= 14) {
3797259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX1_2GHZ,
3798259544Skevlo		    &val, 1);
3799259544Skevlo	} else if (chan <= 64) {
3800259544Skevlo		run_efuse_read(sc,
3801259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH36_TO_CH64_5GHZ,
3802259544Skevlo		    &val, 1);
3803259544Skevlo	} else if (chan <= 138) {
3804259544Skevlo		run_efuse_read(sc,
3805259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH100_TO_CH138_5GHZ,
3806259544Skevlo		    &val, 1);
3807259544Skevlo	} else if (chan <= 165) {
3808259544Skevlo		run_efuse_read(sc,
3809259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH140_TO_CH165_5GHZ,
3810259544Skevlo		    &val, 1);
3811259544Skevlo	} else
3812259544Skevlo		val = 0;
3813259547Skevlo	run_bbp_write(sc, 159, val);
3814259544Skevlo
3815259544Skevlo	/* Tx1 IQ phase. */
3816259544Skevlo	run_bbp_write(sc, 158, 0x4b);
3817259544Skevlo	if (chan <= 14) {
3818259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX1_2GHZ,
3819259544Skevlo		    &val, 1);
3820259544Skevlo	} else if (chan <= 64) {
3821259544Skevlo		run_efuse_read(sc,
3822259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH36_TO_CH64_5GHZ,
3823259544Skevlo		    &val, 1);
3824259544Skevlo	} else if (chan <= 138) {
3825259544Skevlo		run_efuse_read(sc,
3826259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH100_TO_CH138_5GHZ,
3827259544Skevlo		    &val, 1);
3828259544Skevlo	} else if (chan <= 165) {
3829259544Skevlo		run_efuse_read(sc,
3830259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH140_TO_CH165_5GHZ,
3831259544Skevlo		    &val, 1);
3832259544Skevlo	} else
3833259544Skevlo		val = 0;
3834259547Skevlo	run_bbp_write(sc, 159, val);
3835259544Skevlo
3836259544Skevlo	/* RF IQ compensation control. */
3837259544Skevlo	run_bbp_write(sc, 158, 0x04);
3838259544Skevlo	run_efuse_read(sc, RT5390_EEPROM_RF_IQ_COMPENSATION_CTL,
3839259544Skevlo	    &val, 1);
3840259547Skevlo	run_bbp_write(sc, 159, val);
3841259544Skevlo
3842259544Skevlo	/* RF IQ imbalance compensation control. */
3843259544Skevlo	run_bbp_write(sc, 158, 0x03);
3844259544Skevlo	run_efuse_read(sc,
3845259544Skevlo	    RT5390_EEPROM_RF_IQ_IMBALANCE_COMPENSATION_CTL, &val, 1);
3846259547Skevlo	run_bbp_write(sc, 159, val);
3847259544Skevlo}
3848259544Skevlo
3849259544Skevlostatic void
3850205042Sthompsarun_set_agc(struct run_softc *sc, uint8_t agc)
3851205042Sthompsa{
3852205042Sthompsa	uint8_t bbp;
3853205042Sthompsa
3854205042Sthompsa	if (sc->mac_ver == 0x3572) {
3855205042Sthompsa		run_bbp_read(sc, 27, &bbp);
3856205042Sthompsa		bbp &= ~(0x3 << 5);
3857205042Sthompsa		run_bbp_write(sc, 27, bbp | 0 << 5);	/* select Rx0 */
3858205042Sthompsa		run_bbp_write(sc, 66, agc);
3859205042Sthompsa		run_bbp_write(sc, 27, bbp | 1 << 5);	/* select Rx1 */
3860205042Sthompsa		run_bbp_write(sc, 66, agc);
3861205042Sthompsa	} else
3862205042Sthompsa		run_bbp_write(sc, 66, agc);
3863205042Sthompsa}
3864205042Sthompsa
3865205042Sthompsastatic void
3866203134Sthompsarun_select_chan_group(struct run_softc *sc, int group)
3867203134Sthompsa{
3868203134Sthompsa	uint32_t tmp;
3869205042Sthompsa	uint8_t agc;
3870203134Sthompsa
3871203134Sthompsa	run_bbp_write(sc, 62, 0x37 - sc->lna[group]);
3872203134Sthompsa	run_bbp_write(sc, 63, 0x37 - sc->lna[group]);
3873203134Sthompsa	run_bbp_write(sc, 64, 0x37 - sc->lna[group]);
3874258082Skevlo	if (sc->mac_ver < 0x3572)
3875257955Skevlo		run_bbp_write(sc, 86, 0x00);
3876203134Sthompsa
3877260219Skevlo	if (sc->mac_ver == 0x3593) {
3878260219Skevlo		run_bbp_write(sc, 77, 0x98);
3879260219Skevlo		run_bbp_write(sc, 83, (group == 0) ? 0x8a : 0x9a);
3880260219Skevlo	}
3881260219Skevlo
3882203134Sthompsa	if (group == 0) {
3883203134Sthompsa		if (sc->ext_2ghz_lna) {
3884257955Skevlo			if (sc->mac_ver >= 0x5390)
3885257955Skevlo				run_bbp_write(sc, 75, 0x52);
3886257955Skevlo			else {
3887257955Skevlo				run_bbp_write(sc, 82, 0x62);
3888257955Skevlo				run_bbp_write(sc, 75, 0x46);
3889257955Skevlo			}
3890203134Sthompsa		} else {
3891259032Skevlo			if (sc->mac_ver == 0x5592) {
3892259032Skevlo				run_bbp_write(sc, 79, 0x1c);
3893259032Skevlo				run_bbp_write(sc, 80, 0x0e);
3894259032Skevlo				run_bbp_write(sc, 81, 0x3a);
3895259032Skevlo				run_bbp_write(sc, 82, 0x62);
3896259032Skevlo
3897259032Skevlo				run_bbp_write(sc, 195, 0x80);
3898259032Skevlo				run_bbp_write(sc, 196, 0xe0);
3899259032Skevlo				run_bbp_write(sc, 195, 0x81);
3900259032Skevlo				run_bbp_write(sc, 196, 0x1f);
3901259032Skevlo				run_bbp_write(sc, 195, 0x82);
3902259032Skevlo				run_bbp_write(sc, 196, 0x38);
3903259032Skevlo				run_bbp_write(sc, 195, 0x83);
3904259032Skevlo				run_bbp_write(sc, 196, 0x32);
3905259032Skevlo				run_bbp_write(sc, 195, 0x85);
3906259032Skevlo				run_bbp_write(sc, 196, 0x28);
3907259032Skevlo				run_bbp_write(sc, 195, 0x86);
3908259032Skevlo				run_bbp_write(sc, 196, 0x19);
3909259032Skevlo			} else if (sc->mac_ver >= 0x5390)
3910257955Skevlo				run_bbp_write(sc, 75, 0x50);
3911257955Skevlo			else {
3912260219Skevlo				run_bbp_write(sc, 82,
3913260219Skevlo				    (sc->mac_ver == 0x3593) ? 0x62 : 0x84);
3914257955Skevlo				run_bbp_write(sc, 75, 0x50);
3915257955Skevlo			}
3916203134Sthompsa		}
3917203134Sthompsa	} else {
3918259032Skevlo		if (sc->mac_ver == 0x5592) {
3919259032Skevlo			run_bbp_write(sc, 79, 0x18);
3920259032Skevlo			run_bbp_write(sc, 80, 0x08);
3921259032Skevlo			run_bbp_write(sc, 81, 0x38);
3922259032Skevlo			run_bbp_write(sc, 82, 0x92);
3923259032Skevlo
3924259032Skevlo			run_bbp_write(sc, 195, 0x80);
3925259032Skevlo			run_bbp_write(sc, 196, 0xf0);
3926259032Skevlo			run_bbp_write(sc, 195, 0x81);
3927259032Skevlo			run_bbp_write(sc, 196, 0x1e);
3928259032Skevlo			run_bbp_write(sc, 195, 0x82);
3929259032Skevlo			run_bbp_write(sc, 196, 0x28);
3930259032Skevlo			run_bbp_write(sc, 195, 0x83);
3931259032Skevlo			run_bbp_write(sc, 196, 0x20);
3932259032Skevlo			run_bbp_write(sc, 195, 0x85);
3933259032Skevlo			run_bbp_write(sc, 196, 0x7f);
3934259032Skevlo			run_bbp_write(sc, 195, 0x86);
3935259032Skevlo			run_bbp_write(sc, 196, 0x7f);
3936259032Skevlo		} else if (sc->mac_ver == 0x3572)
3937205042Sthompsa			run_bbp_write(sc, 82, 0x94);
3938205042Sthompsa		else
3939260219Skevlo			run_bbp_write(sc, 82,
3940260219Skevlo			    (sc->mac_ver == 0x3593) ? 0x82 : 0xf2);
3941205042Sthompsa		if (sc->ext_5ghz_lna)
3942203134Sthompsa			run_bbp_write(sc, 75, 0x46);
3943205042Sthompsa		else
3944203134Sthompsa			run_bbp_write(sc, 75, 0x50);
3945203134Sthompsa	}
3946203134Sthompsa
3947203134Sthompsa	run_read(sc, RT2860_TX_BAND_CFG, &tmp);
3948203134Sthompsa	tmp &= ~(RT2860_5G_BAND_SEL_N | RT2860_5G_BAND_SEL_P);
3949203134Sthompsa	tmp |= (group == 0) ? RT2860_5G_BAND_SEL_N : RT2860_5G_BAND_SEL_P;
3950203134Sthompsa	run_write(sc, RT2860_TX_BAND_CFG, tmp);
3951203134Sthompsa
3952203134Sthompsa	/* enable appropriate Power Amplifiers and Low Noise Amplifiers */
3953208019Sthompsa	tmp = RT2860_RFTR_EN | RT2860_TRSW_EN | RT2860_LNA_PE0_EN;
3954260219Skevlo	if (sc->mac_ver == 0x3593)
3955260219Skevlo		tmp |= 1 << 29 | 1 << 28;
3956208019Sthompsa	if (sc->nrxchains > 1)
3957208019Sthompsa		tmp |= RT2860_LNA_PE1_EN;
3958203134Sthompsa	if (group == 0) {	/* 2GHz */
3959208019Sthompsa		tmp |= RT2860_PA_PE_G0_EN;
3960203134Sthompsa		if (sc->ntxchains > 1)
3961203134Sthompsa			tmp |= RT2860_PA_PE_G1_EN;
3962260219Skevlo		if (sc->mac_ver == 0x3593) {
3963260219Skevlo			if (sc->ntxchains > 2)
3964260219Skevlo				tmp |= 1 << 25;
3965260219Skevlo		}
3966203134Sthompsa	} else {		/* 5GHz */
3967208019Sthompsa		tmp |= RT2860_PA_PE_A0_EN;
3968203134Sthompsa		if (sc->ntxchains > 1)
3969203134Sthompsa			tmp |= RT2860_PA_PE_A1_EN;
3970203134Sthompsa	}
3971205042Sthompsa	if (sc->mac_ver == 0x3572) {
3972205042Sthompsa		run_rt3070_rf_write(sc, 8, 0x00);
3973205042Sthompsa		run_write(sc, RT2860_TX_PIN_CFG, tmp);
3974205042Sthompsa		run_rt3070_rf_write(sc, 8, 0x80);
3975205042Sthompsa	} else
3976205042Sthompsa		run_write(sc, RT2860_TX_PIN_CFG, tmp);
3977203134Sthompsa
3978259032Skevlo	if (sc->mac_ver == 0x5592) {
3979259032Skevlo		run_bbp_write(sc, 195, 0x8d);
3980259032Skevlo		run_bbp_write(sc, 196, 0x1a);
3981259032Skevlo	}
3982259032Skevlo
3983260219Skevlo	if (sc->mac_ver == 0x3593) {
3984260219Skevlo		run_read(sc, RT2860_GPIO_CTRL, &tmp);
3985260219Skevlo		tmp &= ~0x01010000;
3986260219Skevlo		if (group == 0)
3987260219Skevlo			tmp |= 0x00010000;
3988260219Skevlo		tmp = (tmp & ~0x00009090) | 0x00000090;
3989260219Skevlo		run_write(sc, RT2860_GPIO_CTRL, tmp);
3990260219Skevlo	}
3991260219Skevlo
3992203134Sthompsa	/* set initial AGC value */
3993205042Sthompsa	if (group == 0) {	/* 2GHz band */
3994205042Sthompsa		if (sc->mac_ver >= 0x3070)
3995205042Sthompsa			agc = 0x1c + sc->lna[0] * 2;
3996205042Sthompsa		else
3997205042Sthompsa			agc = 0x2e + sc->lna[0];
3998205042Sthompsa	} else {		/* 5GHz band */
3999259032Skevlo		if (sc->mac_ver == 0x5592)
4000259032Skevlo			agc = 0x24 + sc->lna[group] * 2;
4001260219Skevlo		else if (sc->mac_ver == 0x3572 || sc->mac_ver == 0x3593)
4002205042Sthompsa			agc = 0x22 + (sc->lna[group] * 5) / 3;
4003205042Sthompsa		else
4004205042Sthompsa			agc = 0x32 + (sc->lna[group] * 5) / 3;
4005205042Sthompsa	}
4006205042Sthompsa	run_set_agc(sc, agc);
4007203134Sthompsa}
4008203134Sthompsa
4009203134Sthompsastatic void
4010257429Shselaskyrun_rt2870_set_chan(struct run_softc *sc, u_int chan)
4011203134Sthompsa{
4012203134Sthompsa	const struct rfprog *rfprog = rt2860_rf2850;
4013203134Sthompsa	uint32_t r2, r3, r4;
4014203134Sthompsa	int8_t txpow1, txpow2;
4015203134Sthompsa	int i;
4016203134Sthompsa
4017203134Sthompsa	/* find the settings for this channel (we know it exists) */
4018203134Sthompsa	for (i = 0; rfprog[i].chan != chan; i++);
4019203134Sthompsa
4020203134Sthompsa	r2 = rfprog[i].r2;
4021203134Sthompsa	if (sc->ntxchains == 1)
4022258732Skevlo		r2 |= 1 << 14;		/* 1T: disable Tx chain 2 */
4023203134Sthompsa	if (sc->nrxchains == 1)
4024258732Skevlo		r2 |= 1 << 17 | 1 << 6;	/* 1R: disable Rx chains 2 & 3 */
4025203134Sthompsa	else if (sc->nrxchains == 2)
4026258732Skevlo		r2 |= 1 << 6;		/* 2R: disable Rx chain 3 */
4027203134Sthompsa
4028203134Sthompsa	/* use Tx power values from EEPROM */
4029203134Sthompsa	txpow1 = sc->txpow1[i];
4030203134Sthompsa	txpow2 = sc->txpow2[i];
4031258732Skevlo
4032258732Skevlo	/* Initialize RF R3 and R4. */
4033258732Skevlo	r3 = rfprog[i].r3 & 0xffffc1ff;
4034258732Skevlo	r4 = (rfprog[i].r4 & ~(0x001f87c0)) | (sc->freq << 15);
4035203134Sthompsa	if (chan > 14) {
4036258732Skevlo		if (txpow1 >= 0) {
4037258732Skevlo			txpow1 = (txpow1 > 0xf) ? (0xf) : (txpow1);
4038258732Skevlo			r3 |= (txpow1 << 10) | (1 << 9);
4039258732Skevlo		} else {
4040258732Skevlo			txpow1 += 7;
4041258732Skevlo
4042258732Skevlo			/* txpow1 is not possible larger than 15. */
4043258732Skevlo			r3 |= (txpow1 << 10);
4044258732Skevlo		}
4045258732Skevlo		if (txpow2 >= 0) {
4046258732Skevlo			txpow2 = (txpow2 > 0xf) ? (0xf) : (txpow2);
4047258921Shselasky			r4 |= (txpow2 << 7) | (1 << 6);
4048258732Skevlo		} else {
4049258732Skevlo			txpow2 += 7;
4050258732Skevlo			r4 |= (txpow2 << 7);
4051258732Skevlo		}
4052258732Skevlo	} else {
4053258732Skevlo		/* Set Tx0 power. */
4054258732Skevlo		r3 |= (txpow1 << 9);
4055258732Skevlo
4056258732Skevlo		/* Set frequency offset and Tx1 power. */
4057258732Skevlo		r4 |= (txpow2 << 6);
4058203134Sthompsa	}
4059203134Sthompsa
4060258733Skevlo	run_rt2870_rf_write(sc, rfprog[i].r1);
4061258733Skevlo	run_rt2870_rf_write(sc, r2);
4062258733Skevlo	run_rt2870_rf_write(sc, r3 & ~(1 << 2));
4063258733Skevlo	run_rt2870_rf_write(sc, r4);
4064203134Sthompsa
4065203134Sthompsa	run_delay(sc, 10);
4066203134Sthompsa
4067258733Skevlo	run_rt2870_rf_write(sc, rfprog[i].r1);
4068258733Skevlo	run_rt2870_rf_write(sc, r2);
4069258733Skevlo	run_rt2870_rf_write(sc, r3 | (1 << 2));
4070258733Skevlo	run_rt2870_rf_write(sc, r4);
4071203134Sthompsa
4072203134Sthompsa	run_delay(sc, 10);
4073203134Sthompsa
4074258733Skevlo	run_rt2870_rf_write(sc, rfprog[i].r1);
4075258733Skevlo	run_rt2870_rf_write(sc, r2);
4076258733Skevlo	run_rt2870_rf_write(sc, r3 & ~(1 << 2));
4077258733Skevlo	run_rt2870_rf_write(sc, r4);
4078203134Sthompsa}
4079203134Sthompsa
4080203134Sthompsastatic void
4081257429Shselaskyrun_rt3070_set_chan(struct run_softc *sc, u_int chan)
4082203134Sthompsa{
4083203134Sthompsa	int8_t txpow1, txpow2;
4084203134Sthompsa	uint8_t rf;
4085205042Sthompsa	int i;
4086203134Sthompsa
4087205042Sthompsa	/* find the settings for this channel (we know it exists) */
4088205042Sthompsa	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4089205042Sthompsa
4090203134Sthompsa	/* use Tx power values from EEPROM */
4091205042Sthompsa	txpow1 = sc->txpow1[i];
4092205042Sthompsa	txpow2 = sc->txpow2[i];
4093203134Sthompsa
4094205042Sthompsa	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
4095256720Skevlo
4096256720Skevlo	/* RT3370/RT3390: RF R3 [7:4] is not reserved bits. */
4097256720Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4098256720Skevlo	rf = (rf & ~0x0f) | rt3070_freqs[i].k;
4099256720Skevlo	run_rt3070_rf_write(sc, 3, rf);
4100256720Skevlo
4101203134Sthompsa	run_rt3070_rf_read(sc, 6, &rf);
4102205042Sthompsa	rf = (rf & ~0x03) | rt3070_freqs[i].r;
4103203134Sthompsa	run_rt3070_rf_write(sc, 6, rf);
4104203134Sthompsa
4105203134Sthompsa	/* set Tx0 power */
4106203134Sthompsa	run_rt3070_rf_read(sc, 12, &rf);
4107203134Sthompsa	rf = (rf & ~0x1f) | txpow1;
4108203134Sthompsa	run_rt3070_rf_write(sc, 12, rf);
4109203134Sthompsa
4110203134Sthompsa	/* set Tx1 power */
4111203134Sthompsa	run_rt3070_rf_read(sc, 13, &rf);
4112203134Sthompsa	rf = (rf & ~0x1f) | txpow2;
4113203134Sthompsa	run_rt3070_rf_write(sc, 13, rf);
4114203134Sthompsa
4115203134Sthompsa	run_rt3070_rf_read(sc, 1, &rf);
4116203134Sthompsa	rf &= ~0xfc;
4117203134Sthompsa	if (sc->ntxchains == 1)
4118203134Sthompsa		rf |= 1 << 7 | 1 << 5;	/* 1T: disable Tx chains 2 & 3 */
4119203134Sthompsa	else if (sc->ntxchains == 2)
4120203134Sthompsa		rf |= 1 << 7;		/* 2T: disable Tx chain 3 */
4121203134Sthompsa	if (sc->nrxchains == 1)
4122203134Sthompsa		rf |= 1 << 6 | 1 << 4;	/* 1R: disable Rx chains 2 & 3 */
4123203134Sthompsa	else if (sc->nrxchains == 2)
4124203134Sthompsa		rf |= 1 << 6;		/* 2R: disable Rx chain 3 */
4125203134Sthompsa	run_rt3070_rf_write(sc, 1, rf);
4126203134Sthompsa
4127203134Sthompsa	/* set RF offset */
4128203134Sthompsa	run_rt3070_rf_read(sc, 23, &rf);
4129203134Sthompsa	rf = (rf & ~0x7f) | sc->freq;
4130203134Sthompsa	run_rt3070_rf_write(sc, 23, rf);
4131203134Sthompsa
4132203134Sthompsa	/* program RF filter */
4133205042Sthompsa	run_rt3070_rf_read(sc, 24, &rf);	/* Tx */
4134205042Sthompsa	rf = (rf & ~0x3f) | sc->rf24_20mhz;
4135205042Sthompsa	run_rt3070_rf_write(sc, 24, rf);
4136205042Sthompsa	run_rt3070_rf_read(sc, 31, &rf);	/* Rx */
4137205042Sthompsa	rf = (rf & ~0x3f) | sc->rf24_20mhz;
4138205042Sthompsa	run_rt3070_rf_write(sc, 31, rf);
4139203134Sthompsa
4140203134Sthompsa	/* enable RF tuning */
4141203134Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4142203134Sthompsa	run_rt3070_rf_write(sc, 7, rf | 0x01);
4143203134Sthompsa}
4144203134Sthompsa
4145203134Sthompsastatic void
4146205042Sthompsarun_rt3572_set_chan(struct run_softc *sc, u_int chan)
4147205042Sthompsa{
4148205042Sthompsa	int8_t txpow1, txpow2;
4149205042Sthompsa	uint32_t tmp;
4150205042Sthompsa	uint8_t rf;
4151205042Sthompsa	int i;
4152205042Sthompsa
4153205042Sthompsa	/* find the settings for this channel (we know it exists) */
4154205042Sthompsa	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4155205042Sthompsa
4156205042Sthompsa	/* use Tx power values from EEPROM */
4157205042Sthompsa	txpow1 = sc->txpow1[i];
4158205042Sthompsa	txpow2 = sc->txpow2[i];
4159205042Sthompsa
4160205042Sthompsa	if (chan <= 14) {
4161205042Sthompsa		run_bbp_write(sc, 25, sc->bbp25);
4162205042Sthompsa		run_bbp_write(sc, 26, sc->bbp26);
4163205042Sthompsa	} else {
4164205042Sthompsa		/* enable IQ phase correction */
4165205042Sthompsa		run_bbp_write(sc, 25, 0x09);
4166205042Sthompsa		run_bbp_write(sc, 26, 0xff);
4167205042Sthompsa	}
4168205042Sthompsa
4169205042Sthompsa	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
4170205042Sthompsa	run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k);
4171205042Sthompsa	run_rt3070_rf_read(sc, 6, &rf);
4172205042Sthompsa	rf  = (rf & ~0x0f) | rt3070_freqs[i].r;
4173205042Sthompsa	rf |= (chan <= 14) ? 0x08 : 0x04;
4174205042Sthompsa	run_rt3070_rf_write(sc, 6, rf);
4175205042Sthompsa
4176205042Sthompsa	/* set PLL mode */
4177205042Sthompsa	run_rt3070_rf_read(sc, 5, &rf);
4178205042Sthompsa	rf &= ~(0x08 | 0x04);
4179205042Sthompsa	rf |= (chan <= 14) ? 0x04 : 0x08;
4180205042Sthompsa	run_rt3070_rf_write(sc, 5, rf);
4181205042Sthompsa
4182205042Sthompsa	/* set Tx power for chain 0 */
4183205042Sthompsa	if (chan <= 14)
4184205042Sthompsa		rf = 0x60 | txpow1;
4185205042Sthompsa	else
4186205042Sthompsa		rf = 0xe0 | (txpow1 & 0xc) << 1 | (txpow1 & 0x3);
4187205042Sthompsa	run_rt3070_rf_write(sc, 12, rf);
4188205042Sthompsa
4189205042Sthompsa	/* set Tx power for chain 1 */
4190205042Sthompsa	if (chan <= 14)
4191205042Sthompsa		rf = 0x60 | txpow2;
4192205042Sthompsa	else
4193205042Sthompsa		rf = 0xe0 | (txpow2 & 0xc) << 1 | (txpow2 & 0x3);
4194205042Sthompsa	run_rt3070_rf_write(sc, 13, rf);
4195205042Sthompsa
4196205042Sthompsa	/* set Tx/Rx streams */
4197205042Sthompsa	run_rt3070_rf_read(sc, 1, &rf);
4198205042Sthompsa	rf &= ~0xfc;
4199205042Sthompsa	if (sc->ntxchains == 1)
4200205042Sthompsa		rf |= 1 << 7 | 1 << 5;  /* 1T: disable Tx chains 2 & 3 */
4201205042Sthompsa	else if (sc->ntxchains == 2)
4202205042Sthompsa		rf |= 1 << 7;           /* 2T: disable Tx chain 3 */
4203205042Sthompsa	if (sc->nrxchains == 1)
4204205042Sthompsa		rf |= 1 << 6 | 1 << 4;  /* 1R: disable Rx chains 2 & 3 */
4205205042Sthompsa	else if (sc->nrxchains == 2)
4206205042Sthompsa		rf |= 1 << 6;           /* 2R: disable Rx chain 3 */
4207205042Sthompsa	run_rt3070_rf_write(sc, 1, rf);
4208205042Sthompsa
4209205042Sthompsa	/* set RF offset */
4210205042Sthompsa	run_rt3070_rf_read(sc, 23, &rf);
4211205042Sthompsa	rf = (rf & ~0x7f) | sc->freq;
4212205042Sthompsa	run_rt3070_rf_write(sc, 23, rf);
4213205042Sthompsa
4214205042Sthompsa	/* program RF filter */
4215205042Sthompsa	rf = sc->rf24_20mhz;
4216205042Sthompsa	run_rt3070_rf_write(sc, 24, rf);	/* Tx */
4217205042Sthompsa	run_rt3070_rf_write(sc, 31, rf);	/* Rx */
4218205042Sthompsa
4219205042Sthompsa	/* enable RF tuning */
4220205042Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4221205042Sthompsa	rf = (chan <= 14) ? 0xd8 : ((rf & ~0xc8) | 0x14);
4222205042Sthompsa	run_rt3070_rf_write(sc, 7, rf);
4223205042Sthompsa
4224205042Sthompsa	/* TSSI */
4225205042Sthompsa	rf = (chan <= 14) ? 0xc3 : 0xc0;
4226205042Sthompsa	run_rt3070_rf_write(sc, 9, rf);
4227205042Sthompsa
4228205042Sthompsa	/* set loop filter 1 */
4229205042Sthompsa	run_rt3070_rf_write(sc, 10, 0xf1);
4230205042Sthompsa	/* set loop filter 2 */
4231205042Sthompsa	run_rt3070_rf_write(sc, 11, (chan <= 14) ? 0xb9 : 0x00);
4232205042Sthompsa
4233205042Sthompsa	/* set tx_mx2_ic */
4234205042Sthompsa	run_rt3070_rf_write(sc, 15, (chan <= 14) ? 0x53 : 0x43);
4235205042Sthompsa	/* set tx_mx1_ic */
4236205042Sthompsa	if (chan <= 14)
4237205042Sthompsa		rf = 0x48 | sc->txmixgain_2ghz;
4238205042Sthompsa	else
4239205042Sthompsa		rf = 0x78 | sc->txmixgain_5ghz;
4240205042Sthompsa	run_rt3070_rf_write(sc, 16, rf);
4241205042Sthompsa
4242205042Sthompsa	/* set tx_lo1 */
4243205042Sthompsa	run_rt3070_rf_write(sc, 17, 0x23);
4244205042Sthompsa	/* set tx_lo2 */
4245205042Sthompsa	if (chan <= 14)
4246205042Sthompsa		rf = 0x93;
4247205042Sthompsa	else if (chan <= 64)
4248205042Sthompsa		rf = 0xb7;
4249205042Sthompsa	else if (chan <= 128)
4250205042Sthompsa		rf = 0x74;
4251205042Sthompsa	else
4252205042Sthompsa		rf = 0x72;
4253205042Sthompsa	run_rt3070_rf_write(sc, 19, rf);
4254205042Sthompsa
4255205042Sthompsa	/* set rx_lo1 */
4256205042Sthompsa	if (chan <= 14)
4257205042Sthompsa		rf = 0xb3;
4258205042Sthompsa	else if (chan <= 64)
4259205042Sthompsa		rf = 0xf6;
4260205042Sthompsa	else if (chan <= 128)
4261205042Sthompsa		rf = 0xf4;
4262205042Sthompsa	else
4263205042Sthompsa		rf = 0xf3;
4264205042Sthompsa	run_rt3070_rf_write(sc, 20, rf);
4265205042Sthompsa
4266205042Sthompsa	/* set pfd_delay */
4267205042Sthompsa	if (chan <= 14)
4268205042Sthompsa		rf = 0x15;
4269205042Sthompsa	else if (chan <= 64)
4270205042Sthompsa		rf = 0x3d;
4271205042Sthompsa	else
4272205042Sthompsa		rf = 0x01;
4273205042Sthompsa	run_rt3070_rf_write(sc, 25, rf);
4274205042Sthompsa
4275205042Sthompsa	/* set rx_lo2 */
4276205042Sthompsa	run_rt3070_rf_write(sc, 26, (chan <= 14) ? 0x85 : 0x87);
4277205042Sthompsa	/* set ldo_rf_vc */
4278205042Sthompsa	run_rt3070_rf_write(sc, 27, (chan <= 14) ? 0x00 : 0x01);
4279205042Sthompsa	/* set drv_cc */
4280205042Sthompsa	run_rt3070_rf_write(sc, 29, (chan <= 14) ? 0x9b : 0x9f);
4281205042Sthompsa
4282205042Sthompsa	run_read(sc, RT2860_GPIO_CTRL, &tmp);
4283205042Sthompsa	tmp &= ~0x8080;
4284205042Sthompsa	if (chan <= 14)
4285205042Sthompsa		tmp |= 0x80;
4286205042Sthompsa	run_write(sc, RT2860_GPIO_CTRL, tmp);
4287205042Sthompsa
4288205042Sthompsa	/* enable RF tuning */
4289205042Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4290205042Sthompsa	run_rt3070_rf_write(sc, 7, rf | 0x01);
4291205042Sthompsa
4292205042Sthompsa	run_delay(sc, 2);
4293205042Sthompsa}
4294205042Sthompsa
4295205042Sthompsastatic void
4296260219Skevlorun_rt3593_set_chan(struct run_softc *sc, u_int chan)
4297260219Skevlo{
4298260219Skevlo	int8_t txpow1, txpow2, txpow3;
4299260219Skevlo	uint8_t h20mhz, rf;
4300260219Skevlo	int i;
4301260219Skevlo
4302260219Skevlo	/* find the settings for this channel (we know it exists) */
4303260219Skevlo	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4304260219Skevlo
4305260219Skevlo	/* use Tx power values from EEPROM */
4306260219Skevlo	txpow1 = sc->txpow1[i];
4307260219Skevlo	txpow2 = sc->txpow2[i];
4308260219Skevlo	txpow3 = (sc->ntxchains == 3) ? sc->txpow3[i] : 0;
4309260219Skevlo
4310260219Skevlo	if (chan <= 14) {
4311260219Skevlo		run_bbp_write(sc, 25, sc->bbp25);
4312260219Skevlo		run_bbp_write(sc, 26, sc->bbp26);
4313260219Skevlo	} else {
4314260219Skevlo		/* Enable IQ phase correction. */
4315260219Skevlo		run_bbp_write(sc, 25, 0x09);
4316260219Skevlo		run_bbp_write(sc, 26, 0xff);
4317260219Skevlo	}
4318260219Skevlo
4319260219Skevlo	run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n);
4320260219Skevlo	run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f);
4321260219Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4322260219Skevlo	rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03);
4323260219Skevlo	run_rt3070_rf_write(sc, 11, rf);
4324260219Skevlo
4325260219Skevlo	/* Set pll_idoh. */
4326260219Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4327260219Skevlo	rf &= ~0x4c;
4328260219Skevlo	rf |= (chan <= 14) ? 0x44 : 0x48;
4329260219Skevlo	run_rt3070_rf_write(sc, 11, rf);
4330260219Skevlo
4331260219Skevlo	if (chan <= 14)
4332260219Skevlo		rf = txpow1 & 0x1f;
4333260219Skevlo	else
4334260219Skevlo		rf = 0x40 | ((txpow1 & 0x18) << 1) | (txpow1 & 0x07);
4335260219Skevlo	run_rt3070_rf_write(sc, 53, rf);
4336260219Skevlo
4337260219Skevlo	if (chan <= 14)
4338260219Skevlo		rf = txpow2 & 0x1f;
4339260219Skevlo	else
4340260219Skevlo		rf = 0x40 | ((txpow2 & 0x18) << 1) | (txpow2 & 0x07);
4341260219Skevlo	run_rt3070_rf_write(sc, 55, rf);
4342260219Skevlo
4343260219Skevlo	if (chan <= 14)
4344260219Skevlo		rf = txpow3 & 0x1f;
4345260219Skevlo	else
4346260219Skevlo		rf = 0x40 | ((txpow3 & 0x18) << 1) | (txpow3 & 0x07);
4347260219Skevlo	run_rt3070_rf_write(sc, 54, rf);
4348260219Skevlo
4349260219Skevlo	rf = RT3070_RF_BLOCK | RT3070_PLL_PD;
4350260219Skevlo	if (sc->ntxchains == 3)
4351260219Skevlo		rf |= RT3070_TX0_PD | RT3070_TX1_PD | RT3070_TX2_PD;
4352260219Skevlo	else
4353260219Skevlo		rf |= RT3070_TX0_PD | RT3070_TX1_PD;
4354260219Skevlo	rf |= RT3070_RX0_PD | RT3070_RX1_PD | RT3070_RX2_PD;
4355260219Skevlo	run_rt3070_rf_write(sc, 1, rf);
4356260219Skevlo
4357260219Skevlo	run_adjust_freq_offset(sc);
4358260219Skevlo
4359260219Skevlo	run_rt3070_rf_write(sc, 31, (chan <= 14) ? 0xa0 : 0x80);
4360260219Skevlo
4361260219Skevlo	h20mhz = (sc->rf24_20mhz & 0x20) >> 5;
4362260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
4363260219Skevlo	rf = (rf & ~0x06) | (h20mhz << 1) | (h20mhz << 2);
4364260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
4365260219Skevlo
4366260219Skevlo	run_rt3070_rf_read(sc, 36, &rf);
4367260219Skevlo	if (chan <= 14)
4368260219Skevlo		rf |= 0x80;
4369260219Skevlo	else
4370260219Skevlo		rf &= ~0x80;
4371260219Skevlo	run_rt3070_rf_write(sc, 36, rf);
4372260219Skevlo
4373260219Skevlo	/* Set vcolo_bs. */
4374260219Skevlo	run_rt3070_rf_write(sc, 34, (chan <= 14) ? 0x3c : 0x20);
4375260219Skevlo	/* Set pfd_delay. */
4376260219Skevlo	run_rt3070_rf_write(sc, 12, (chan <= 14) ? 0x1a : 0x12);
4377260219Skevlo
4378260219Skevlo	/* Set vco bias current control. */
4379260219Skevlo	run_rt3070_rf_read(sc, 6, &rf);
4380260219Skevlo	rf &= ~0xc0;
4381260219Skevlo	if (chan <= 14)
4382260219Skevlo		rf |= 0x40;
4383260219Skevlo	else if (chan <= 128)
4384260219Skevlo		rf |= 0x80;
4385260219Skevlo	else
4386260219Skevlo		rf |= 0x40;
4387260219Skevlo	run_rt3070_rf_write(sc, 6, rf);
4388260219Skevlo
4389260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
4390260219Skevlo	rf = (rf & ~0x18) | 0x10;
4391260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
4392260219Skevlo
4393260219Skevlo	run_rt3070_rf_write(sc, 10, (chan <= 14) ? 0xd3 : 0xd8);
4394260219Skevlo	run_rt3070_rf_write(sc, 13, (chan <= 14) ? 0x12 : 0x23);
4395260219Skevlo
4396260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4397260219Skevlo	rf = (rf & ~0x03) | 0x01;
4398260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
4399260219Skevlo	/* Set tx_mx1_cc. */
4400260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4401260219Skevlo	rf &= ~0x1c;
4402260219Skevlo	rf |= (chan <= 14) ? 0x14 : 0x10;
4403260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
4404260219Skevlo	/* Set tx_mx1_ic. */
4405260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4406260219Skevlo	rf &= ~0xe0;
4407260219Skevlo	rf |= (chan <= 14) ? 0x60 : 0x40;
4408260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
4409260219Skevlo	/* Set tx_lo1_ic. */
4410260219Skevlo	run_rt3070_rf_read(sc, 49, &rf);
4411260219Skevlo	rf &= ~0x1c;
4412260219Skevlo	rf |= (chan <= 14) ? 0x0c : 0x08;
4413260219Skevlo	run_rt3070_rf_write(sc, 49, rf);
4414260219Skevlo	/* Set tx_lo1_en. */
4415260219Skevlo	run_rt3070_rf_read(sc, 50, &rf);
4416260219Skevlo	run_rt3070_rf_write(sc, 50, rf & ~0x20);
4417260219Skevlo	/* Set drv_cc. */
4418260219Skevlo	run_rt3070_rf_read(sc, 57, &rf);
4419260219Skevlo	rf &= ~0xfc;
4420260219Skevlo	rf |= (chan <= 14) ?  0x6c : 0x3c;
4421260219Skevlo	run_rt3070_rf_write(sc, 57, rf);
4422260219Skevlo	/* Set rx_mix1_ic, rxa_lnactr, lna_vc, lna_inbias_en and lna_en. */
4423260219Skevlo	run_rt3070_rf_write(sc, 44, (chan <= 14) ? 0x93 : 0x9b);
4424260219Skevlo	/* Set drv_gnd_a, tx_vga_cc_a and tx_mx2_gain. */
4425260219Skevlo	run_rt3070_rf_write(sc, 52, (chan <= 14) ? 0x45 : 0x05);
4426260219Skevlo	/* Enable VCO calibration. */
4427260219Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4428260219Skevlo	rf &= ~RT5390_VCOCAL;
4429260219Skevlo	rf |= (chan <= 14) ? RT5390_VCOCAL : 0xbe;
4430260219Skevlo	run_rt3070_rf_write(sc, 3, rf);
4431260219Skevlo
4432260219Skevlo	if (chan <= 14)
4433260219Skevlo		rf = 0x23;
4434260219Skevlo	else if (chan <= 64)
4435260219Skevlo		rf = 0x36;
4436260219Skevlo	else if (chan <= 128)
4437260219Skevlo		rf = 0x32;
4438260219Skevlo	else
4439260219Skevlo		rf = 0x30;
4440260219Skevlo	run_rt3070_rf_write(sc, 39, rf);
4441260219Skevlo	if (chan <= 14)
4442260219Skevlo		rf = 0xbb;
4443260219Skevlo	else if (chan <= 64)
4444260219Skevlo		rf = 0xeb;
4445260219Skevlo	else if (chan <= 128)
4446260219Skevlo		rf = 0xb3;
4447260219Skevlo	else
4448260219Skevlo		rf = 0x9b;
4449260219Skevlo	run_rt3070_rf_write(sc, 45, rf);
4450260219Skevlo
4451260219Skevlo	/* Set FEQ/AEQ control. */
4452260219Skevlo	run_bbp_write(sc, 105, 0x34);
4453260219Skevlo}
4454260219Skevlo
4455260219Skevlostatic void
4456257955Skevlorun_rt5390_set_chan(struct run_softc *sc, u_int chan)
4457257955Skevlo{
4458257955Skevlo	int8_t txpow1, txpow2;
4459257955Skevlo	uint8_t rf;
4460257955Skevlo	int i;
4461257955Skevlo
4462257955Skevlo	/* find the settings for this channel (we know it exists) */
4463257955Skevlo	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4464257955Skevlo
4465257955Skevlo	/* use Tx power values from EEPROM */
4466257955Skevlo	txpow1 = sc->txpow1[i];
4467257955Skevlo	txpow2 = sc->txpow2[i];
4468257955Skevlo
4469257955Skevlo	run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n);
4470257955Skevlo	run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f);
4471257955Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4472257955Skevlo	rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03);
4473257955Skevlo	run_rt3070_rf_write(sc, 11, rf);
4474257955Skevlo
4475257955Skevlo	run_rt3070_rf_read(sc, 49, &rf);
4476257955Skevlo	rf = (rf & ~0x3f) | (txpow1 & 0x3f);
4477257955Skevlo	/* The valid range of the RF R49 is 0x00 to 0x27. */
4478257955Skevlo	if ((rf & 0x3f) > 0x27)
4479257955Skevlo		rf = (rf & ~0x3f) | 0x27;
4480257955Skevlo	run_rt3070_rf_write(sc, 49, rf);
4481257955Skevlo
4482257955Skevlo	if (sc->mac_ver == 0x5392) {
4483257955Skevlo		run_rt3070_rf_read(sc, 50, &rf);
4484257955Skevlo		rf = (rf & ~0x3f) | (txpow2 & 0x3f);
4485257955Skevlo		/* The valid range of the RF R50 is 0x00 to 0x27. */
4486257955Skevlo		if ((rf & 0x3f) > 0x27)
4487257955Skevlo			rf = (rf & ~0x3f) | 0x27;
4488257955Skevlo		run_rt3070_rf_write(sc, 50, rf);
4489257955Skevlo	}
4490257955Skevlo
4491257955Skevlo	run_rt3070_rf_read(sc, 1, &rf);
4492257955Skevlo	rf |= RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD;
4493257955Skevlo	if (sc->mac_ver == 0x5392)
4494257955Skevlo		rf |= RT3070_RX1_PD | RT3070_TX1_PD;
4495257955Skevlo	run_rt3070_rf_write(sc, 1, rf);
4496257955Skevlo
4497257955Skevlo	if (sc->mac_ver != 0x5392) {
4498257955Skevlo		run_rt3070_rf_read(sc, 2, &rf);
4499257955Skevlo		rf |= 0x80;
4500257955Skevlo		run_rt3070_rf_write(sc, 2, rf);
4501257955Skevlo		run_delay(sc, 10);
4502257955Skevlo		rf &= 0x7f;
4503257955Skevlo		run_rt3070_rf_write(sc, 2, rf);
4504257955Skevlo	}
4505257955Skevlo
4506257955Skevlo	run_adjust_freq_offset(sc);
4507257955Skevlo
4508257955Skevlo	if (sc->mac_ver == 0x5392) {
4509257955Skevlo		/* Fix for RT5392C. */
4510257955Skevlo		if (sc->mac_rev >= 0x0223) {
4511259030Skevlo			if (chan <= 4)
4512257955Skevlo				rf = 0x0f;
4513259030Skevlo			else if (chan >= 5 && chan <= 7)
4514257955Skevlo				rf = 0x0e;
4515259030Skevlo			else
4516257955Skevlo				rf = 0x0d;
4517257955Skevlo			run_rt3070_rf_write(sc, 23, rf);
4518257955Skevlo
4519259030Skevlo			if (chan <= 4)
4520257955Skevlo				rf = 0x0c;
4521257955Skevlo			else if (chan == 5)
4522257955Skevlo				rf = 0x0b;
4523259030Skevlo			else if (chan >= 6 && chan <= 7)
4524257955Skevlo				rf = 0x0a;
4525259030Skevlo			else if (chan >= 8 && chan <= 10)
4526257955Skevlo				rf = 0x09;
4527259030Skevlo			else
4528257955Skevlo				rf = 0x08;
4529257955Skevlo			run_rt3070_rf_write(sc, 59, rf);
4530257955Skevlo		} else {
4531259030Skevlo			if (chan <= 11)
4532257955Skevlo				rf = 0x0f;
4533259030Skevlo			else
4534257955Skevlo				rf = 0x0b;
4535257955Skevlo			run_rt3070_rf_write(sc, 59, rf);
4536257955Skevlo		}
4537257955Skevlo	} else {
4538257955Skevlo		/* Fix for RT5390F. */
4539257955Skevlo		if (sc->mac_rev >= 0x0502) {
4540259030Skevlo			if (chan <= 11)
4541257955Skevlo				rf = 0x43;
4542259030Skevlo			else
4543257955Skevlo				rf = 0x23;
4544257955Skevlo			run_rt3070_rf_write(sc, 55, rf);
4545257955Skevlo
4546259030Skevlo			if (chan <= 11)
4547257955Skevlo				rf = 0x0f;
4548257955Skevlo			else if (chan == 12)
4549257955Skevlo				rf = 0x0d;
4550259030Skevlo			else
4551257955Skevlo				rf = 0x0b;
4552257955Skevlo			run_rt3070_rf_write(sc, 59, rf);
4553257955Skevlo		} else {
4554257955Skevlo			run_rt3070_rf_write(sc, 55, 0x44);
4555257955Skevlo			run_rt3070_rf_write(sc, 59, 0x8f);
4556257955Skevlo		}
4557257955Skevlo	}
4558257955Skevlo
4559257955Skevlo	/* Enable VCO calibration. */
4560257955Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4561257955Skevlo	rf |= RT5390_VCOCAL;
4562257955Skevlo	run_rt3070_rf_write(sc, 3, rf);
4563257955Skevlo}
4564257955Skevlo
4565257955Skevlostatic void
4566259032Skevlorun_rt5592_set_chan(struct run_softc *sc, u_int chan)
4567259032Skevlo{
4568259032Skevlo	const struct rt5592_freqs *freqs;
4569259032Skevlo	uint32_t tmp;
4570259032Skevlo	uint8_t reg, rf, txpow_bound;
4571259032Skevlo	int8_t txpow1, txpow2;
4572259032Skevlo	int i;
4573259032Skevlo
4574259032Skevlo	run_read(sc, RT5592_DEBUG_INDEX, &tmp);
4575259032Skevlo	freqs = (tmp & RT5592_SEL_XTAL) ?
4576259032Skevlo	    rt5592_freqs_40mhz : rt5592_freqs_20mhz;
4577259032Skevlo
4578259032Skevlo	/* find the settings for this channel (we know it exists) */
4579259032Skevlo	for (i = 0; rt2860_rf2850[i].chan != chan; i++, freqs++);
4580259032Skevlo
4581259032Skevlo	/* use Tx power values from EEPROM */
4582259032Skevlo	txpow1 = sc->txpow1[i];
4583259032Skevlo	txpow2 = sc->txpow2[i];
4584259032Skevlo
4585259032Skevlo	run_read(sc, RT3070_LDO_CFG0, &tmp);
4586259032Skevlo	tmp &= ~0x1c000000;
4587259032Skevlo	if (chan > 14)
4588259032Skevlo		tmp |= 0x14000000;
4589259032Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
4590259032Skevlo
4591259032Skevlo	/* N setting. */
4592259032Skevlo	run_rt3070_rf_write(sc, 8, freqs->n & 0xff);
4593259032Skevlo	run_rt3070_rf_read(sc, 9, &rf);
4594259032Skevlo	rf &= ~(1 << 4);
4595259032Skevlo	rf |= ((freqs->n & 0x0100) >> 8) << 4;
4596259032Skevlo	run_rt3070_rf_write(sc, 9, rf);
4597259032Skevlo
4598259032Skevlo	/* K setting. */
4599259032Skevlo	run_rt3070_rf_read(sc, 9, &rf);
4600259032Skevlo	rf &= ~0x0f;
4601259032Skevlo	rf |= (freqs->k & 0x0f);
4602259032Skevlo	run_rt3070_rf_write(sc, 9, rf);
4603259032Skevlo
4604259032Skevlo	/* Mode setting. */
4605259032Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4606259032Skevlo	rf &= ~0x0c;
4607259032Skevlo	rf |= ((freqs->m - 0x8) & 0x3) << 2;
4608259032Skevlo	run_rt3070_rf_write(sc, 11, rf);
4609259032Skevlo	run_rt3070_rf_read(sc, 9, &rf);
4610259032Skevlo	rf &= ~(1 << 7);
4611259032Skevlo	rf |= (((freqs->m - 0x8) & 0x4) >> 2) << 7;
4612259032Skevlo	run_rt3070_rf_write(sc, 9, rf);
4613259032Skevlo
4614259032Skevlo	/* R setting. */
4615259032Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4616259032Skevlo	rf &= ~0x03;
4617259032Skevlo	rf |= (freqs->r - 0x1);
4618259032Skevlo	run_rt3070_rf_write(sc, 11, rf);
4619259032Skevlo
4620259032Skevlo	if (chan <= 14) {
4621259032Skevlo		/* Initialize RF registers for 2GHZ. */
4622259032Skevlo		for (i = 0; i < nitems(rt5592_2ghz_def_rf); i++) {
4623259032Skevlo			run_rt3070_rf_write(sc, rt5592_2ghz_def_rf[i].reg,
4624259032Skevlo			    rt5592_2ghz_def_rf[i].val);
4625259032Skevlo		}
4626259032Skevlo
4627259032Skevlo		rf = (chan <= 10) ? 0x07 : 0x06;
4628259032Skevlo		run_rt3070_rf_write(sc, 23, rf);
4629259032Skevlo		run_rt3070_rf_write(sc, 59, rf);
4630259032Skevlo
4631259032Skevlo		run_rt3070_rf_write(sc, 55, 0x43);
4632259032Skevlo
4633259032Skevlo		/*
4634259032Skevlo		 * RF R49/R50 Tx power ALC code.
4635259032Skevlo		 * G-band bit<7:6>=1:0, bit<5:0> range from 0x0 ~ 0x27.
4636259032Skevlo		 */
4637259032Skevlo		reg = 2;
4638259032Skevlo		txpow_bound = 0x27;
4639259032Skevlo	} else {
4640259032Skevlo		/* Initialize RF registers for 5GHZ. */
4641259032Skevlo		for (i = 0; i < nitems(rt5592_5ghz_def_rf); i++) {
4642259032Skevlo			run_rt3070_rf_write(sc, rt5592_5ghz_def_rf[i].reg,
4643259032Skevlo			    rt5592_5ghz_def_rf[i].val);
4644259032Skevlo		}
4645259032Skevlo		for (i = 0; i < nitems(rt5592_chan_5ghz); i++) {
4646259032Skevlo			if (chan >= rt5592_chan_5ghz[i].firstchan &&
4647259032Skevlo			    chan <= rt5592_chan_5ghz[i].lastchan) {
4648259032Skevlo				run_rt3070_rf_write(sc, rt5592_chan_5ghz[i].reg,
4649259032Skevlo				    rt5592_chan_5ghz[i].val);
4650259032Skevlo			}
4651259032Skevlo		}
4652259032Skevlo
4653259032Skevlo		/*
4654259032Skevlo		 * RF R49/R50 Tx power ALC code.
4655259032Skevlo		 * A-band bit<7:6>=1:1, bit<5:0> range from 0x0 ~ 0x2b.
4656259032Skevlo		 */
4657259032Skevlo		reg = 3;
4658259032Skevlo		txpow_bound = 0x2b;
4659259032Skevlo	}
4660259032Skevlo
4661259032Skevlo	/* RF R49 ch0 Tx power ALC code. */
4662259032Skevlo	run_rt3070_rf_read(sc, 49, &rf);
4663259032Skevlo	rf &= ~0xc0;
4664259032Skevlo	rf |= (reg << 6);
4665259032Skevlo	rf = (rf & ~0x3f) | (txpow1 & 0x3f);
4666259032Skevlo	if ((rf & 0x3f) > txpow_bound)
4667259032Skevlo		rf = (rf & ~0x3f) | txpow_bound;
4668259032Skevlo	run_rt3070_rf_write(sc, 49, rf);
4669259032Skevlo
4670259032Skevlo	/* RF R50 ch1 Tx power ALC code. */
4671259032Skevlo	run_rt3070_rf_read(sc, 50, &rf);
4672259032Skevlo	rf &= ~(1 << 7 | 1 << 6);
4673259032Skevlo	rf |= (reg << 6);
4674259032Skevlo	rf = (rf & ~0x3f) | (txpow2 & 0x3f);
4675259032Skevlo	if ((rf & 0x3f) > txpow_bound)
4676259032Skevlo		rf = (rf & ~0x3f) | txpow_bound;
4677259032Skevlo	run_rt3070_rf_write(sc, 50, rf);
4678259032Skevlo
4679259032Skevlo	/* Enable RF_BLOCK, PLL_PD, RX0_PD, and TX0_PD. */
4680259032Skevlo	run_rt3070_rf_read(sc, 1, &rf);
4681259032Skevlo	rf |= (RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD);
4682259032Skevlo	if (sc->ntxchains > 1)
4683259032Skevlo		rf |= RT3070_TX1_PD;
4684259032Skevlo	if (sc->nrxchains > 1)
4685259032Skevlo		rf |= RT3070_RX1_PD;
4686259032Skevlo	run_rt3070_rf_write(sc, 1, rf);
4687259032Skevlo
4688259032Skevlo	run_rt3070_rf_write(sc, 6, 0xe4);
4689259032Skevlo
4690259032Skevlo	run_rt3070_rf_write(sc, 30, 0x10);
4691259032Skevlo	run_rt3070_rf_write(sc, 31, 0x80);
4692259032Skevlo	run_rt3070_rf_write(sc, 32, 0x80);
4693259032Skevlo
4694259032Skevlo	run_adjust_freq_offset(sc);
4695259032Skevlo
4696259032Skevlo	/* Enable VCO calibration. */
4697259032Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4698259032Skevlo	rf |= RT5390_VCOCAL;
4699259032Skevlo	run_rt3070_rf_write(sc, 3, rf);
4700259032Skevlo}
4701259032Skevlo
4702259032Skevlostatic void
4703203134Sthompsarun_set_rx_antenna(struct run_softc *sc, int aux)
4704203134Sthompsa{
4705203134Sthompsa	uint32_t tmp;
4706257955Skevlo	uint8_t bbp152;
4707203134Sthompsa
4708203134Sthompsa	if (aux) {
4709257955Skevlo		if (sc->rf_rev == RT5390_RF_5370) {
4710257955Skevlo			run_bbp_read(sc, 152, &bbp152);
4711257955Skevlo			run_bbp_write(sc, 152, bbp152 & ~0x80);
4712259030Skevlo		} else {
4713257955Skevlo			run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 0);
4714257955Skevlo			run_read(sc, RT2860_GPIO_CTRL, &tmp);
4715257955Skevlo			run_write(sc, RT2860_GPIO_CTRL, (tmp & ~0x0808) | 0x08);
4716257955Skevlo		}
4717203134Sthompsa	} else {
4718257955Skevlo		if (sc->rf_rev == RT5390_RF_5370) {
4719257955Skevlo			run_bbp_read(sc, 152, &bbp152);
4720257955Skevlo			run_bbp_write(sc, 152, bbp152 | 0x80);
4721259030Skevlo		} else {
4722257955Skevlo			run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 1);
4723257955Skevlo			run_read(sc, RT2860_GPIO_CTRL, &tmp);
4724257955Skevlo			run_write(sc, RT2860_GPIO_CTRL, tmp & ~0x0808);
4725257955Skevlo		}
4726203134Sthompsa	}
4727203134Sthompsa}
4728203134Sthompsa
4729203134Sthompsastatic int
4730203134Sthompsarun_set_chan(struct run_softc *sc, struct ieee80211_channel *c)
4731203134Sthompsa{
4732287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
4733257429Shselasky	u_int chan, group;
4734203134Sthompsa
4735203134Sthompsa	chan = ieee80211_chan2ieee(ic, c);
4736203134Sthompsa	if (chan == 0 || chan == IEEE80211_CHAN_ANY)
4737209917Sthompsa		return (EINVAL);
4738203134Sthompsa
4739259032Skevlo	if (sc->mac_ver == 0x5592)
4740259032Skevlo		run_rt5592_set_chan(sc, chan);
4741259032Skevlo	else if (sc->mac_ver >= 0x5390)
4742257955Skevlo		run_rt5390_set_chan(sc, chan);
4743260219Skevlo	else if (sc->mac_ver == 0x3593)
4744260219Skevlo		run_rt3593_set_chan(sc, chan);
4745257955Skevlo	else if (sc->mac_ver == 0x3572)
4746205042Sthompsa		run_rt3572_set_chan(sc, chan);
4747205042Sthompsa	else if (sc->mac_ver >= 0x3070)
4748203134Sthompsa		run_rt3070_set_chan(sc, chan);
4749203134Sthompsa	else
4750203134Sthompsa		run_rt2870_set_chan(sc, chan);
4751203134Sthompsa
4752203134Sthompsa	/* determine channel group */
4753203134Sthompsa	if (chan <= 14)
4754203134Sthompsa		group = 0;
4755203134Sthompsa	else if (chan <= 64)
4756203134Sthompsa		group = 1;
4757203134Sthompsa	else if (chan <= 128)
4758203134Sthompsa		group = 2;
4759203134Sthompsa	else
4760203134Sthompsa		group = 3;
4761203134Sthompsa
4762203134Sthompsa	/* XXX necessary only when group has changed! */
4763203134Sthompsa	run_select_chan_group(sc, group);
4764203134Sthompsa
4765203134Sthompsa	run_delay(sc, 10);
4766203134Sthompsa
4767259545Skevlo	/* Perform IQ calibration. */
4768259544Skevlo	if (sc->mac_ver >= 0x5392)
4769259544Skevlo		run_iq_calib(sc, chan);
4770259544Skevlo
4771209917Sthompsa	return (0);
4772203134Sthompsa}
4773203134Sthompsa
4774203134Sthompsastatic void
4775203134Sthompsarun_set_channel(struct ieee80211com *ic)
4776203134Sthompsa{
4777286950Sadrian	struct run_softc *sc = ic->ic_softc;
4778203134Sthompsa
4779203134Sthompsa	RUN_LOCK(sc);
4780203134Sthompsa	run_set_chan(sc, ic->ic_curchan);
4781203134Sthompsa	RUN_UNLOCK(sc);
4782203134Sthompsa
4783203134Sthompsa	return;
4784203134Sthompsa}
4785203134Sthompsa
4786203134Sthompsastatic void
4787203134Sthompsarun_scan_start(struct ieee80211com *ic)
4788203134Sthompsa{
4789286950Sadrian	struct run_softc *sc = ic->ic_softc;
4790203134Sthompsa	uint32_t tmp;
4791203134Sthompsa
4792203134Sthompsa	RUN_LOCK(sc);
4793203134Sthompsa
4794203134Sthompsa	/* abort TSF synchronization */
4795203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
4796203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG,
4797203134Sthompsa	    tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
4798203134Sthompsa	    RT2860_TBTT_TIMER_EN));
4799287197Sglebius	run_set_bssid(sc, ieee80211broadcastaddr);
4800203134Sthompsa
4801203134Sthompsa	RUN_UNLOCK(sc);
4802203134Sthompsa
4803203134Sthompsa	return;
4804203134Sthompsa}
4805203134Sthompsa
4806203134Sthompsastatic void
4807203134Sthompsarun_scan_end(struct ieee80211com *ic)
4808203134Sthompsa{
4809286950Sadrian	struct run_softc *sc = ic->ic_softc;
4810203134Sthompsa
4811203134Sthompsa	RUN_LOCK(sc);
4812203134Sthompsa
4813203134Sthompsa	run_enable_tsf_sync(sc);
4814203134Sthompsa	/* XXX keep local copy */
4815287197Sglebius	run_set_bssid(sc, ic->ic_macaddr);
4816203134Sthompsa
4817203134Sthompsa	RUN_UNLOCK(sc);
4818203134Sthompsa
4819203134Sthompsa	return;
4820203134Sthompsa}
4821203134Sthompsa
4822208019Sthompsa/*
4823208019Sthompsa * Could be called from ieee80211_node_timeout()
4824208019Sthompsa * (non-sleepable thread)
4825208019Sthompsa */
4826208019Sthompsastatic void
4827208019Sthompsarun_update_beacon(struct ieee80211vap *vap, int item)
4828203134Sthompsa{
4829208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
4830288095Sadrian	struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off;
4831288095Sadrian	struct ieee80211_node *ni = vap->iv_bss;
4832286950Sadrian	struct run_softc *sc = ic->ic_softc;
4833218492Sbschmidt	struct run_vap *rvp = RUN_VAP(vap);
4834218492Sbschmidt	int mcast = 0;
4835208019Sthompsa	uint32_t i;
4836208019Sthompsa
4837218492Sbschmidt	switch (item) {
4838218492Sbschmidt	case IEEE80211_BEACON_ERP:
4839283540Sglebius		run_updateslot(ic);
4840218492Sbschmidt		break;
4841218492Sbschmidt	case IEEE80211_BEACON_HTINFO:
4842218492Sbschmidt		run_updateprot(ic);
4843218492Sbschmidt		break;
4844218492Sbschmidt	case IEEE80211_BEACON_TIM:
4845218492Sbschmidt		mcast = 1;	/*TODO*/
4846218492Sbschmidt		break;
4847218492Sbschmidt	default:
4848218492Sbschmidt		break;
4849218492Sbschmidt	}
4850218492Sbschmidt
4851288095Sadrian	setbit(bo->bo_flags, item);
4852273448Skevlo	if (rvp->beacon_mbuf == NULL) {
4853288636Sadrian		rvp->beacon_mbuf = ieee80211_beacon_alloc(ni);
4854273448Skevlo		if (rvp->beacon_mbuf == NULL)
4855273448Skevlo			return;
4856273448Skevlo	}
4857288636Sadrian	ieee80211_beacon_update(ni, rvp->beacon_mbuf, mcast);
4858218492Sbschmidt
4859208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
4860208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
4861208019Sthompsa	sc->cmdq[i].func = run_update_beacon_cb;
4862208019Sthompsa	sc->cmdq[i].arg0 = vap;
4863208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
4864208019Sthompsa
4865208019Sthompsa	return;
4866203134Sthompsa}
4867203134Sthompsa
4868203134Sthompsastatic void
4869208019Sthompsarun_update_beacon_cb(void *arg)
4870203134Sthompsa{
4871208019Sthompsa	struct ieee80211vap *vap = arg;
4872288095Sadrian	struct ieee80211_node *ni = vap->iv_bss;
4873218492Sbschmidt	struct run_vap *rvp = RUN_VAP(vap);
4874203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
4875286950Sadrian	struct run_softc *sc = ic->ic_softc;
4876203134Sthompsa	struct rt2860_txwi txwi;
4877203134Sthompsa	struct mbuf *m;
4878259032Skevlo	uint16_t txwisize;
4879208019Sthompsa	uint8_t ridx;
4880203134Sthompsa
4881288095Sadrian	if (ni->ni_chan == IEEE80211_CHAN_ANYC)
4882208019Sthompsa		return;
4883236439Shselasky	if (ic->ic_bsschan == IEEE80211_CHAN_ANYC)
4884236439Shselasky		return;
4885208019Sthompsa
4886218492Sbschmidt	/*
4887218492Sbschmidt	 * No need to call ieee80211_beacon_update(), run_update_beacon()
4888218492Sbschmidt	 * is taking care of apropriate calls.
4889218492Sbschmidt	 */
4890218492Sbschmidt	if (rvp->beacon_mbuf == NULL) {
4891288636Sadrian		rvp->beacon_mbuf = ieee80211_beacon_alloc(ni);
4892218492Sbschmidt		if (rvp->beacon_mbuf == NULL)
4893218492Sbschmidt			return;
4894218492Sbschmidt	}
4895218492Sbschmidt	m = rvp->beacon_mbuf;
4896203134Sthompsa
4897259032Skevlo	memset(&txwi, 0, sizeof(txwi));
4898203134Sthompsa	txwi.wcid = 0xff;
4899203134Sthompsa	txwi.len = htole16(m->m_pkthdr.len);
4900259032Skevlo
4901203134Sthompsa	/* send beacons at the lowest available rate */
4902208019Sthompsa	ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
4903208019Sthompsa	    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
4904208019Sthompsa	txwi.phy = htole16(rt2860_rates[ridx].mcs);
4905208019Sthompsa	if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM)
4906259032Skevlo		txwi.phy |= htole16(RT2860_PHY_OFDM);
4907203134Sthompsa	txwi.txop = RT2860_TX_TXOP_HT;
4908203134Sthompsa	txwi.flags = RT2860_TX_TS;
4909209144Sthompsa	txwi.xflags = RT2860_TX_NSEQ;
4910203134Sthompsa
4911259032Skevlo	txwisize = (sc->mac_ver == 0x5592) ?
4912259032Skevlo	    sizeof(txwi) + sizeof(uint32_t) : sizeof(txwi);
4913259032Skevlo	run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id), (uint8_t *)&txwi,
4914259032Skevlo	    txwisize);
4915259032Skevlo	run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id) + txwisize,
4916259032Skevlo	    mtod(m, uint8_t *), (m->m_pkthdr.len + 1) & ~1);
4917203134Sthompsa}
4918203134Sthompsa
4919203134Sthompsastatic void
4920203134Sthompsarun_updateprot(struct ieee80211com *ic)
4921203134Sthompsa{
4922286950Sadrian	struct run_softc *sc = ic->ic_softc;
4923218492Sbschmidt	uint32_t i;
4924218492Sbschmidt
4925218492Sbschmidt	i = RUN_CMDQ_GET(&sc->cmdq_store);
4926218492Sbschmidt	DPRINTF("cmdq_store=%d\n", i);
4927218492Sbschmidt	sc->cmdq[i].func = run_updateprot_cb;
4928218492Sbschmidt	sc->cmdq[i].arg0 = ic;
4929218492Sbschmidt	ieee80211_runtask(ic, &sc->cmdq_task);
4930218492Sbschmidt}
4931218492Sbschmidt
4932218492Sbschmidtstatic void
4933218492Sbschmidtrun_updateprot_cb(void *arg)
4934218492Sbschmidt{
4935218492Sbschmidt	struct ieee80211com *ic = arg;
4936286950Sadrian	struct run_softc *sc = ic->ic_softc;
4937203134Sthompsa	uint32_t tmp;
4938203134Sthompsa
4939203134Sthompsa	tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL;
4940203134Sthompsa	/* setup protection frame rate (MCS code) */
4941203134Sthompsa	tmp |= (ic->ic_curmode == IEEE80211_MODE_11A) ?
4942270192Skevlo	    rt2860_rates[RT2860_RIDX_OFDM6].mcs | RT2860_PHY_OFDM :
4943203134Sthompsa	    rt2860_rates[RT2860_RIDX_CCK11].mcs;
4944203134Sthompsa
4945203134Sthompsa	/* CCK frames don't require protection */
4946203134Sthompsa	run_write(sc, RT2860_CCK_PROT_CFG, tmp);
4947203134Sthompsa	if (ic->ic_flags & IEEE80211_F_USEPROT) {
4948203134Sthompsa		if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
4949203134Sthompsa			tmp |= RT2860_PROT_CTRL_RTS_CTS;
4950203134Sthompsa		else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
4951203134Sthompsa			tmp |= RT2860_PROT_CTRL_CTS;
4952203134Sthompsa	}
4953203134Sthompsa	run_write(sc, RT2860_OFDM_PROT_CFG, tmp);
4954203134Sthompsa}
4955203134Sthompsa
4956203134Sthompsastatic void
4957208019Sthompsarun_usb_timeout_cb(void *arg)
4958203134Sthompsa{
4959208019Sthompsa	struct ieee80211vap *vap = arg;
4960286950Sadrian	struct run_softc *sc = vap->iv_ic->ic_softc;
4961203134Sthompsa
4962208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
4963203134Sthompsa
4964203134Sthompsa	if(vap->iv_state == IEEE80211_S_RUN &&
4965203134Sthompsa	    vap->iv_opmode != IEEE80211_M_STA)
4966203134Sthompsa		run_reset_livelock(sc);
4967209917Sthompsa	else if (vap->iv_state == IEEE80211_S_SCAN) {
4968203134Sthompsa		DPRINTF("timeout caused by scan\n");
4969203134Sthompsa		/* cancel bgscan */
4970203134Sthompsa		ieee80211_cancel_scan(vap);
4971203134Sthompsa	} else
4972203134Sthompsa		DPRINTF("timeout by unknown cause\n");
4973203134Sthompsa}
4974203134Sthompsa
4975203134Sthompsastatic void
4976203134Sthompsarun_reset_livelock(struct run_softc *sc)
4977203134Sthompsa{
4978203134Sthompsa	uint32_t tmp;
4979203134Sthompsa
4980208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
4981208019Sthompsa
4982203134Sthompsa	/*
4983203134Sthompsa	 * In IBSS or HostAP modes (when the hardware sends beacons), the MAC
4984203134Sthompsa	 * can run into a livelock and start sending CTS-to-self frames like
4985203134Sthompsa	 * crazy if protection is enabled.  Reset MAC/BBP for a while
4986203134Sthompsa	 */
4987203134Sthompsa	run_read(sc, RT2860_DEBUG, &tmp);
4988208019Sthompsa	DPRINTFN(3, "debug reg %08x\n", tmp);
4989209917Sthompsa	if ((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))) {
4990203134Sthompsa		DPRINTF("CTS-to-self livelock detected\n");
4991203134Sthompsa		run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST);
4992203134Sthompsa		run_delay(sc, 1);
4993203134Sthompsa		run_write(sc, RT2860_MAC_SYS_CTRL,
4994203134Sthompsa		    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
4995203134Sthompsa	}
4996203134Sthompsa}
4997203134Sthompsa
4998203134Sthompsastatic void
4999283540Sglebiusrun_update_promisc_locked(struct run_softc *sc)
5000203134Sthompsa{
5001203134Sthompsa        uint32_t tmp;
5002203134Sthompsa
5003203134Sthompsa	run_read(sc, RT2860_RX_FILTR_CFG, &tmp);
5004203134Sthompsa
5005203134Sthompsa	tmp |= RT2860_DROP_UC_NOME;
5006287197Sglebius        if (sc->sc_ic.ic_promisc > 0)
5007203134Sthompsa		tmp &= ~RT2860_DROP_UC_NOME;
5008203134Sthompsa
5009203134Sthompsa	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
5010203134Sthompsa
5011287197Sglebius        DPRINTF("%s promiscuous mode\n", (sc->sc_ic.ic_promisc > 0) ?
5012203134Sthompsa            "entering" : "leaving");
5013203134Sthompsa}
5014203134Sthompsa
5015203134Sthompsastatic void
5016283540Sglebiusrun_update_promisc(struct ieee80211com *ic)
5017203134Sthompsa{
5018283540Sglebius	struct run_softc *sc = ic->ic_softc;
5019203134Sthompsa
5020287197Sglebius	if ((sc->sc_flags & RUN_RUNNING) == 0)
5021203134Sthompsa		return;
5022203134Sthompsa
5023203134Sthompsa	RUN_LOCK(sc);
5024283540Sglebius	run_update_promisc_locked(sc);
5025203134Sthompsa	RUN_UNLOCK(sc);
5026203134Sthompsa}
5027203134Sthompsa
5028203134Sthompsastatic void
5029203134Sthompsarun_enable_tsf_sync(struct run_softc *sc)
5030203134Sthompsa{
5031287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5032203134Sthompsa	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
5033203134Sthompsa	uint32_t tmp;
5034203134Sthompsa
5035257955Skevlo	DPRINTF("rvp_id=%d ic_opmode=%d\n", RUN_VAP(vap)->rvp_id,
5036257955Skevlo	    ic->ic_opmode);
5037208019Sthompsa
5038203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
5039203134Sthompsa	tmp &= ~0x1fffff;
5040203134Sthompsa	tmp |= vap->iv_bss->ni_intval * 16;
5041203134Sthompsa	tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN;
5042203134Sthompsa
5043208019Sthompsa	if (ic->ic_opmode == IEEE80211_M_STA) {
5044203134Sthompsa		/*
5045203134Sthompsa		 * Local TSF is always updated with remote TSF on beacon
5046203134Sthompsa		 * reception.
5047203134Sthompsa		 */
5048203134Sthompsa		tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT;
5049208019Sthompsa	} else if (ic->ic_opmode == IEEE80211_M_IBSS) {
5050203134Sthompsa	        tmp |= RT2860_BCN_TX_EN;
5051203134Sthompsa	        /*
5052203134Sthompsa	         * Local TSF is updated with remote TSF on beacon reception
5053203134Sthompsa	         * only if the remote TSF is greater than local TSF.
5054203134Sthompsa	         */
5055203134Sthompsa	        tmp |= 2 << RT2860_TSF_SYNC_MODE_SHIFT;
5056208019Sthompsa	} else if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
5057208019Sthompsa		    ic->ic_opmode == IEEE80211_M_MBSS) {
5058203134Sthompsa	        tmp |= RT2860_BCN_TX_EN;
5059203134Sthompsa	        /* SYNC with nobody */
5060203134Sthompsa	        tmp |= 3 << RT2860_TSF_SYNC_MODE_SHIFT;
5061208019Sthompsa	} else {
5062203134Sthompsa		DPRINTF("Enabling TSF failed. undefined opmode\n");
5063208019Sthompsa		return;
5064208019Sthompsa	}
5065203134Sthompsa
5066203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
5067203134Sthompsa}
5068203134Sthompsa
5069203134Sthompsastatic void
5070287555Skevlorun_enable_tsf(struct run_softc *sc)
5071287555Skevlo{
5072287555Skevlo	uint32_t tmp;
5073287555Skevlo
5074287555Skevlo	if (run_read(sc, RT2860_BCN_TIME_CFG, &tmp) == 0) {
5075287555Skevlo		tmp &= ~(RT2860_BCN_TX_EN | RT2860_TBTT_TIMER_EN);
5076287555Skevlo		tmp |= RT2860_TSF_TIMER_EN;
5077287555Skevlo		run_write(sc, RT2860_BCN_TIME_CFG, tmp);
5078287555Skevlo	}
5079287555Skevlo}
5080287555Skevlo
5081287555Skevlostatic void
5082287554Skevlorun_get_tsf(struct run_softc *sc, uint64_t *buf)
5083287554Skevlo{
5084287554Skevlo	run_read_region_1(sc, RT2860_TSF_TIMER_DW0, (uint8_t *)buf,
5085287554Skevlo	    sizeof(*buf));
5086287554Skevlo}
5087287554Skevlo
5088287554Skevlostatic void
5089203134Sthompsarun_enable_mrr(struct run_softc *sc)
5090203134Sthompsa{
5091259546Skevlo#define	CCK(mcs)	(mcs)
5092259546Skevlo#define	OFDM(mcs)	(1 << 3 | (mcs))
5093203134Sthompsa	run_write(sc, RT2860_LG_FBK_CFG0,
5094203134Sthompsa	    OFDM(6) << 28 |	/* 54->48 */
5095203134Sthompsa	    OFDM(5) << 24 |	/* 48->36 */
5096203134Sthompsa	    OFDM(4) << 20 |	/* 36->24 */
5097203134Sthompsa	    OFDM(3) << 16 |	/* 24->18 */
5098203134Sthompsa	    OFDM(2) << 12 |	/* 18->12 */
5099203134Sthompsa	    OFDM(1) <<  8 |	/* 12-> 9 */
5100203134Sthompsa	    OFDM(0) <<  4 |	/*  9-> 6 */
5101203134Sthompsa	    OFDM(0));		/*  6-> 6 */
5102203134Sthompsa
5103203134Sthompsa	run_write(sc, RT2860_LG_FBK_CFG1,
5104203134Sthompsa	    CCK(2) << 12 |	/* 11->5.5 */
5105203134Sthompsa	    CCK(1) <<  8 |	/* 5.5-> 2 */
5106203134Sthompsa	    CCK(0) <<  4 |	/*   2-> 1 */
5107203134Sthompsa	    CCK(0));		/*   1-> 1 */
5108203134Sthompsa#undef OFDM
5109203134Sthompsa#undef CCK
5110203134Sthompsa}
5111203134Sthompsa
5112203134Sthompsastatic void
5113203134Sthompsarun_set_txpreamble(struct run_softc *sc)
5114203134Sthompsa{
5115287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5116203134Sthompsa	uint32_t tmp;
5117203134Sthompsa
5118203134Sthompsa	run_read(sc, RT2860_AUTO_RSP_CFG, &tmp);
5119203134Sthompsa	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
5120203134Sthompsa		tmp |= RT2860_CCK_SHORT_EN;
5121203134Sthompsa	else
5122203134Sthompsa		tmp &= ~RT2860_CCK_SHORT_EN;
5123203134Sthompsa	run_write(sc, RT2860_AUTO_RSP_CFG, tmp);
5124203134Sthompsa}
5125203134Sthompsa
5126203134Sthompsastatic void
5127203134Sthompsarun_set_basicrates(struct run_softc *sc)
5128203134Sthompsa{
5129287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5130203134Sthompsa
5131203134Sthompsa	/* set basic rates mask */
5132203134Sthompsa	if (ic->ic_curmode == IEEE80211_MODE_11B)
5133203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x003);
5134203134Sthompsa	else if (ic->ic_curmode == IEEE80211_MODE_11A)
5135203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x150);
5136203134Sthompsa	else	/* 11g */
5137203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x15f);
5138203134Sthompsa}
5139203134Sthompsa
5140203134Sthompsastatic void
5141203134Sthompsarun_set_leds(struct run_softc *sc, uint16_t which)
5142203134Sthompsa{
5143203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LEDS,
5144203134Sthompsa	    which | (sc->leds & 0x7f));
5145203134Sthompsa}
5146203134Sthompsa
5147203134Sthompsastatic void
5148203134Sthompsarun_set_bssid(struct run_softc *sc, const uint8_t *bssid)
5149203134Sthompsa{
5150203134Sthompsa	run_write(sc, RT2860_MAC_BSSID_DW0,
5151203134Sthompsa	    bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24);
5152203134Sthompsa	run_write(sc, RT2860_MAC_BSSID_DW1,
5153203134Sthompsa	    bssid[4] | bssid[5] << 8);
5154203134Sthompsa}
5155203134Sthompsa
5156203134Sthompsastatic void
5157203134Sthompsarun_set_macaddr(struct run_softc *sc, const uint8_t *addr)
5158203134Sthompsa{
5159203134Sthompsa	run_write(sc, RT2860_MAC_ADDR_DW0,
5160203134Sthompsa	    addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24);
5161203134Sthompsa	run_write(sc, RT2860_MAC_ADDR_DW1,
5162203134Sthompsa	    addr[4] | addr[5] << 8 | 0xff << 16);
5163203134Sthompsa}
5164203134Sthompsa
5165203134Sthompsastatic void
5166283540Sglebiusrun_updateslot(struct ieee80211com *ic)
5167203134Sthompsa{
5168283540Sglebius	struct run_softc *sc = ic->ic_softc;
5169218492Sbschmidt	uint32_t i;
5170218492Sbschmidt
5171218492Sbschmidt	i = RUN_CMDQ_GET(&sc->cmdq_store);
5172218492Sbschmidt	DPRINTF("cmdq_store=%d\n", i);
5173218492Sbschmidt	sc->cmdq[i].func = run_updateslot_cb;
5174287197Sglebius	sc->cmdq[i].arg0 = ic;
5175218492Sbschmidt	ieee80211_runtask(ic, &sc->cmdq_task);
5176218492Sbschmidt
5177218492Sbschmidt	return;
5178218492Sbschmidt}
5179218492Sbschmidt
5180218492Sbschmidt/* ARGSUSED */
5181218492Sbschmidtstatic void
5182218492Sbschmidtrun_updateslot_cb(void *arg)
5183218492Sbschmidt{
5184287197Sglebius	struct ieee80211com *ic = arg;
5185286950Sadrian	struct run_softc *sc = ic->ic_softc;
5186203134Sthompsa	uint32_t tmp;
5187203134Sthompsa
5188203134Sthompsa	run_read(sc, RT2860_BKOFF_SLOT_CFG, &tmp);
5189203134Sthompsa	tmp &= ~0xff;
5190292165Savos	tmp |= IEEE80211_GET_SLOTTIME(ic);
5191203134Sthompsa	run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp);
5192203134Sthompsa}
5193203134Sthompsa
5194208019Sthompsastatic void
5195283540Sglebiusrun_update_mcast(struct ieee80211com *ic)
5196208019Sthompsa{
5197208019Sthompsa}
5198208019Sthompsa
5199203134Sthompsastatic int8_t
5200203134Sthompsarun_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain)
5201203134Sthompsa{
5202287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5203203134Sthompsa	struct ieee80211_channel *c = ic->ic_curchan;
5204203134Sthompsa	int delta;
5205203134Sthompsa
5206203134Sthompsa	if (IEEE80211_IS_CHAN_5GHZ(c)) {
5207257429Shselasky		u_int chan = ieee80211_chan2ieee(ic, c);
5208203134Sthompsa		delta = sc->rssi_5ghz[rxchain];
5209203134Sthompsa
5210203134Sthompsa		/* determine channel group */
5211203134Sthompsa		if (chan <= 64)
5212203134Sthompsa			delta -= sc->lna[1];
5213203134Sthompsa		else if (chan <= 128)
5214203134Sthompsa			delta -= sc->lna[2];
5215203134Sthompsa		else
5216203134Sthompsa			delta -= sc->lna[3];
5217203134Sthompsa	} else
5218203134Sthompsa		delta = sc->rssi_2ghz[rxchain] - sc->lna[0];
5219203134Sthompsa
5220209917Sthompsa	return (-12 - delta - rssi);
5221203134Sthompsa}
5222203134Sthompsa
5223257955Skevlostatic void
5224257955Skevlorun_rt5390_bbp_init(struct run_softc *sc)
5225257955Skevlo{
5226257955Skevlo	int i;
5227259032Skevlo	uint8_t bbp;
5228257955Skevlo
5229259032Skevlo	/* Apply maximum likelihood detection for 2 stream case. */
5230259032Skevlo	run_bbp_read(sc, 105, &bbp);
5231259032Skevlo	if (sc->nrxchains > 1)
5232259032Skevlo		run_bbp_write(sc, 105, bbp | RT5390_MLD);
5233259032Skevlo
5234257955Skevlo	/* Avoid data lost and CRC error. */
5235259032Skevlo	run_bbp_read(sc, 4, &bbp);
5236259031Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5237257955Skevlo
5238259032Skevlo	if (sc->mac_ver == 0x5592) {
5239259032Skevlo		for (i = 0; i < nitems(rt5592_def_bbp); i++) {
5240259032Skevlo			run_bbp_write(sc, rt5592_def_bbp[i].reg,
5241259032Skevlo			    rt5592_def_bbp[i].val);
5242259032Skevlo		}
5243259032Skevlo		for (i = 0; i < nitems(rt5592_bbp_r196); i++) {
5244259032Skevlo			run_bbp_write(sc, 195, i + 0x80);
5245259032Skevlo			run_bbp_write(sc, 196, rt5592_bbp_r196[i]);
5246259032Skevlo		}
5247259032Skevlo	} else {
5248259032Skevlo		for (i = 0; i < nitems(rt5390_def_bbp); i++) {
5249259032Skevlo			run_bbp_write(sc, rt5390_def_bbp[i].reg,
5250259032Skevlo			    rt5390_def_bbp[i].val);
5251259032Skevlo		}
5252257955Skevlo	}
5253257955Skevlo	if (sc->mac_ver == 0x5392) {
5254257955Skevlo		run_bbp_write(sc, 88, 0x90);
5255257955Skevlo		run_bbp_write(sc, 95, 0x9a);
5256257955Skevlo		run_bbp_write(sc, 98, 0x12);
5257257955Skevlo		run_bbp_write(sc, 106, 0x12);
5258257955Skevlo		run_bbp_write(sc, 134, 0xd0);
5259257955Skevlo		run_bbp_write(sc, 135, 0xf6);
5260257955Skevlo		run_bbp_write(sc, 148, 0x84);
5261257955Skevlo	}
5262257955Skevlo
5263259032Skevlo	run_bbp_read(sc, 152, &bbp);
5264259032Skevlo	run_bbp_write(sc, 152, bbp | 0x80);
5265259032Skevlo
5266259032Skevlo	/* Fix BBP254 for RT5592C. */
5267259032Skevlo	if (sc->mac_ver == 0x5592 && sc->mac_rev >= 0x0221) {
5268259032Skevlo		run_bbp_read(sc, 254, &bbp);
5269259032Skevlo		run_bbp_write(sc, 254, bbp | 0x80);
5270259032Skevlo	}
5271259032Skevlo
5272257955Skevlo	/* Disable hardware antenna diversity. */
5273257955Skevlo	if (sc->mac_ver == 0x5390)
5274257955Skevlo		run_bbp_write(sc, 154, 0);
5275259032Skevlo
5276259032Skevlo	/* Initialize Rx CCK/OFDM frequency offset report. */
5277259032Skevlo	run_bbp_write(sc, 142, 1);
5278259032Skevlo	run_bbp_write(sc, 143, 57);
5279257955Skevlo}
5280257955Skevlo
5281203134Sthompsastatic int
5282203134Sthompsarun_bbp_init(struct run_softc *sc)
5283203134Sthompsa{
5284203134Sthompsa	int i, error, ntries;
5285203134Sthompsa	uint8_t bbp0;
5286203134Sthompsa
5287203134Sthompsa	/* wait for BBP to wake up */
5288203134Sthompsa	for (ntries = 0; ntries < 20; ntries++) {
5289203134Sthompsa		if ((error = run_bbp_read(sc, 0, &bbp0)) != 0)
5290203134Sthompsa			return error;
5291203134Sthompsa		if (bbp0 != 0 && bbp0 != 0xff)
5292203134Sthompsa			break;
5293203134Sthompsa	}
5294203134Sthompsa	if (ntries == 20)
5295209917Sthompsa		return (ETIMEDOUT);
5296203134Sthompsa
5297203134Sthompsa	/* initialize BBP registers to default values */
5298257955Skevlo	if (sc->mac_ver >= 0x5390)
5299257955Skevlo		run_rt5390_bbp_init(sc);
5300257955Skevlo	else {
5301257955Skevlo		for (i = 0; i < nitems(rt2860_def_bbp); i++) {
5302257955Skevlo			run_bbp_write(sc, rt2860_def_bbp[i].reg,
5303257955Skevlo			    rt2860_def_bbp[i].val);
5304257955Skevlo		}
5305203134Sthompsa	}
5306203134Sthompsa
5307260219Skevlo	if (sc->mac_ver == 0x3593) {
5308260219Skevlo		run_bbp_write(sc, 79, 0x13);
5309260219Skevlo		run_bbp_write(sc, 80, 0x05);
5310260219Skevlo		run_bbp_write(sc, 81, 0x33);
5311260219Skevlo		run_bbp_write(sc, 86, 0x46);
5312260219Skevlo		run_bbp_write(sc, 137, 0x0f);
5313260219Skevlo	}
5314260219Skevlo
5315203134Sthompsa	/* fix BBP84 for RT2860E */
5316205042Sthompsa	if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0101)
5317205042Sthompsa		run_bbp_write(sc, 84, 0x19);
5318203134Sthompsa
5319260219Skevlo	if (sc->mac_ver >= 0x3070 && (sc->mac_ver != 0x3593 &&
5320260219Skevlo	    sc->mac_ver != 0x5592)) {
5321203134Sthompsa		run_bbp_write(sc, 79, 0x13);
5322203134Sthompsa		run_bbp_write(sc, 80, 0x05);
5323203134Sthompsa		run_bbp_write(sc, 81, 0x33);
5324205042Sthompsa	} else if (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) {
5325203134Sthompsa		run_bbp_write(sc, 69, 0x16);
5326203134Sthompsa		run_bbp_write(sc, 73, 0x12);
5327203134Sthompsa	}
5328209917Sthompsa	return (0);
5329203134Sthompsa}
5330203134Sthompsa
5331203134Sthompsastatic int
5332203134Sthompsarun_rt3070_rf_init(struct run_softc *sc)
5333203134Sthompsa{
5334203134Sthompsa	uint32_t tmp;
5335256722Skevlo	uint8_t bbp4, mingain, rf, target;
5336203134Sthompsa	int i;
5337203134Sthompsa
5338203134Sthompsa	run_rt3070_rf_read(sc, 30, &rf);
5339203134Sthompsa	/* toggle RF R30 bit 7 */
5340203134Sthompsa	run_rt3070_rf_write(sc, 30, rf | 0x80);
5341203134Sthompsa	run_delay(sc, 10);
5342203134Sthompsa	run_rt3070_rf_write(sc, 30, rf & ~0x80);
5343203134Sthompsa
5344203134Sthompsa	/* initialize RF registers to default value */
5345205042Sthompsa	if (sc->mac_ver == 0x3572) {
5346257955Skevlo		for (i = 0; i < nitems(rt3572_def_rf); i++) {
5347205042Sthompsa			run_rt3070_rf_write(sc, rt3572_def_rf[i].reg,
5348205042Sthompsa			    rt3572_def_rf[i].val);
5349205042Sthompsa		}
5350205042Sthompsa	} else {
5351257955Skevlo		for (i = 0; i < nitems(rt3070_def_rf); i++) {
5352205042Sthompsa			run_rt3070_rf_write(sc, rt3070_def_rf[i].reg,
5353205042Sthompsa			    rt3070_def_rf[i].val);
5354205042Sthompsa		}
5355203134Sthompsa	}
5356205042Sthompsa
5357256721Skevlo	if (sc->mac_ver == 0x3070 && sc->mac_rev < 0x0201) {
5358256721Skevlo		/*
5359256721Skevlo		 * Change voltage from 1.2V to 1.35V for RT3070.
5360256721Skevlo		 * The DAC issue (RT3070_LDO_CFG0) has been fixed
5361256721Skevlo		 * in RT3070(F).
5362256721Skevlo		 */
5363203134Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5364203134Sthompsa		tmp = (tmp & ~0x0f000000) | 0x0d000000;
5365203134Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5366203134Sthompsa
5367205042Sthompsa	} else if (sc->mac_ver == 0x3071) {
5368203134Sthompsa		run_rt3070_rf_read(sc, 6, &rf);
5369203134Sthompsa		run_rt3070_rf_write(sc, 6, rf | 0x40);
5370203134Sthompsa		run_rt3070_rf_write(sc, 31, 0x14);
5371203134Sthompsa
5372203134Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5373203134Sthompsa		tmp &= ~0x1f000000;
5374205042Sthompsa		if (sc->mac_rev < 0x0211)
5375205042Sthompsa			tmp |= 0x0d000000;	/* 1.3V */
5376203134Sthompsa		else
5377205042Sthompsa			tmp |= 0x01000000;	/* 1.2V */
5378203134Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5379203134Sthompsa
5380203134Sthompsa		/* patch LNA_PE_G1 */
5381203134Sthompsa		run_read(sc, RT3070_GPIO_SWITCH, &tmp);
5382203134Sthompsa		run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20);
5383208019Sthompsa
5384209917Sthompsa	} else if (sc->mac_ver == 0x3572) {
5385205042Sthompsa		run_rt3070_rf_read(sc, 6, &rf);
5386205042Sthompsa		run_rt3070_rf_write(sc, 6, rf | 0x40);
5387205042Sthompsa
5388208019Sthompsa		/* increase voltage from 1.2V to 1.35V */
5389208019Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5390208019Sthompsa		tmp = (tmp & ~0x1f000000) | 0x0d000000;
5391208019Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5392203134Sthompsa
5393209917Sthompsa		if (sc->mac_rev < 0x0211 || !sc->patch_dac) {
5394203134Sthompsa			run_delay(sc, 1);	/* wait for 1msec */
5395205042Sthompsa			/* decrease voltage back to 1.2V */
5396203134Sthompsa			tmp = (tmp & ~0x1f000000) | 0x01000000;
5397203134Sthompsa			run_write(sc, RT3070_LDO_CFG0, tmp);
5398203134Sthompsa		}
5399203134Sthompsa	}
5400203134Sthompsa
5401203134Sthompsa	/* select 20MHz bandwidth */
5402203134Sthompsa	run_rt3070_rf_read(sc, 31, &rf);
5403203134Sthompsa	run_rt3070_rf_write(sc, 31, rf & ~0x20);
5404203134Sthompsa
5405203134Sthompsa	/* calibrate filter for 20MHz bandwidth */
5406203134Sthompsa	sc->rf24_20mhz = 0x1f;	/* default value */
5407205042Sthompsa	target = (sc->mac_ver < 0x3071) ? 0x16 : 0x13;
5408205042Sthompsa	run_rt3070_filter_calib(sc, 0x07, target, &sc->rf24_20mhz);
5409203134Sthompsa
5410203134Sthompsa	/* select 40MHz bandwidth */
5411203134Sthompsa	run_bbp_read(sc, 4, &bbp4);
5412256721Skevlo	run_bbp_write(sc, 4, (bbp4 & ~0x18) | 0x10);
5413205042Sthompsa	run_rt3070_rf_read(sc, 31, &rf);
5414205042Sthompsa	run_rt3070_rf_write(sc, 31, rf | 0x20);
5415203134Sthompsa
5416203134Sthompsa	/* calibrate filter for 40MHz bandwidth */
5417203134Sthompsa	sc->rf24_40mhz = 0x2f;	/* default value */
5418205042Sthompsa	target = (sc->mac_ver < 0x3071) ? 0x19 : 0x15;
5419205042Sthompsa	run_rt3070_filter_calib(sc, 0x27, target, &sc->rf24_40mhz);
5420203134Sthompsa
5421203134Sthompsa	/* go back to 20MHz bandwidth */
5422203134Sthompsa	run_bbp_read(sc, 4, &bbp4);
5423203134Sthompsa	run_bbp_write(sc, 4, bbp4 & ~0x18);
5424203134Sthompsa
5425205042Sthompsa	if (sc->mac_ver == 0x3572) {
5426205042Sthompsa		/* save default BBP registers 25 and 26 values */
5427205042Sthompsa		run_bbp_read(sc, 25, &sc->bbp25);
5428205042Sthompsa		run_bbp_read(sc, 26, &sc->bbp26);
5429256721Skevlo	} else if (sc->mac_rev < 0x0201 || sc->mac_rev < 0x0211)
5430203134Sthompsa		run_rt3070_rf_write(sc, 27, 0x03);
5431203134Sthompsa
5432203134Sthompsa	run_read(sc, RT3070_OPT_14, &tmp);
5433203134Sthompsa	run_write(sc, RT3070_OPT_14, tmp | 1);
5434203134Sthompsa
5435205042Sthompsa	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
5436205042Sthompsa		run_rt3070_rf_read(sc, 17, &rf);
5437205042Sthompsa		rf &= ~RT3070_TX_LO1;
5438205042Sthompsa		if ((sc->mac_ver == 0x3070 ||
5439205042Sthompsa		     (sc->mac_ver == 0x3071 && sc->mac_rev >= 0x0211)) &&
5440205042Sthompsa		    !sc->ext_2ghz_lna)
5441205042Sthompsa			rf |= 0x20;	/* fix for long range Rx issue */
5442256722Skevlo		mingain = (sc->mac_ver == 0x3070) ? 1 : 2;
5443256722Skevlo		if (sc->txmixgain_2ghz >= mingain)
5444205042Sthompsa			rf = (rf & ~0x7) | sc->txmixgain_2ghz;
5445205042Sthompsa		run_rt3070_rf_write(sc, 17, rf);
5446205042Sthompsa	}
5447205042Sthompsa
5448270643Skevlo	if (sc->mac_ver == 0x3071) {
5449203134Sthompsa		run_rt3070_rf_read(sc, 1, &rf);
5450203134Sthompsa		rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD);
5451203134Sthompsa		rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD;
5452203134Sthompsa		run_rt3070_rf_write(sc, 1, rf);
5453203134Sthompsa
5454203134Sthompsa		run_rt3070_rf_read(sc, 15, &rf);
5455203134Sthompsa		run_rt3070_rf_write(sc, 15, rf & ~RT3070_TX_LO2);
5456203134Sthompsa
5457203134Sthompsa		run_rt3070_rf_read(sc, 20, &rf);
5458203134Sthompsa		run_rt3070_rf_write(sc, 20, rf & ~RT3070_RX_LO1);
5459203134Sthompsa
5460203134Sthompsa		run_rt3070_rf_read(sc, 21, &rf);
5461203134Sthompsa		run_rt3070_rf_write(sc, 21, rf & ~RT3070_RX_LO2);
5462205042Sthompsa	}
5463203134Sthompsa
5464205042Sthompsa	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
5465205042Sthompsa		/* fix Tx to Rx IQ glitch by raising RF voltage */
5466203134Sthompsa		run_rt3070_rf_read(sc, 27, &rf);
5467203134Sthompsa		rf &= ~0x77;
5468205042Sthompsa		if (sc->mac_rev < 0x0211)
5469203134Sthompsa			rf |= 0x03;
5470203134Sthompsa		run_rt3070_rf_write(sc, 27, rf);
5471203134Sthompsa	}
5472209917Sthompsa	return (0);
5473203134Sthompsa}
5474203134Sthompsa
5475257955Skevlostatic void
5476260219Skevlorun_rt3593_rf_init(struct run_softc *sc)
5477260219Skevlo{
5478260219Skevlo	uint32_t tmp;
5479260219Skevlo	uint8_t rf;
5480260219Skevlo	int i;
5481260219Skevlo
5482260219Skevlo	/* Disable the GPIO bits 4 and 7 for LNA PE control. */
5483260219Skevlo	run_read(sc, RT3070_GPIO_SWITCH, &tmp);
5484260219Skevlo	tmp &= ~(1 << 4 | 1 << 7);
5485260219Skevlo	run_write(sc, RT3070_GPIO_SWITCH, tmp);
5486260219Skevlo
5487260219Skevlo	/* Initialize RF registers to default value. */
5488260219Skevlo	for (i = 0; i < nitems(rt3593_def_rf); i++) {
5489260219Skevlo		run_rt3070_rf_write(sc, rt3593_def_rf[i].reg,
5490260219Skevlo		    rt3593_def_rf[i].val);
5491260219Skevlo	}
5492260219Skevlo
5493260219Skevlo	/* Toggle RF R2 to initiate calibration. */
5494260219Skevlo	run_rt3070_rf_write(sc, 2, RT5390_RESCAL);
5495260219Skevlo
5496260219Skevlo	/* Initialize RF frequency offset. */
5497260219Skevlo	run_adjust_freq_offset(sc);
5498260219Skevlo
5499260219Skevlo	run_rt3070_rf_read(sc, 18, &rf);
5500260219Skevlo	run_rt3070_rf_write(sc, 18, rf | RT3593_AUTOTUNE_BYPASS);
5501260219Skevlo
5502260219Skevlo	/*
5503260219Skevlo	 * Increase voltage from 1.2V to 1.35V, wait for 1 msec to
5504260219Skevlo	 * decrease voltage back to 1.2V.
5505260219Skevlo	 */
5506260219Skevlo	run_read(sc, RT3070_LDO_CFG0, &tmp);
5507260219Skevlo	tmp = (tmp & ~0x1f000000) | 0x0d000000;
5508260219Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
5509260219Skevlo	run_delay(sc, 1);
5510260219Skevlo	tmp = (tmp & ~0x1f000000) | 0x01000000;
5511260219Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
5512260219Skevlo
5513260219Skevlo	sc->rf24_20mhz = 0x1f;
5514260219Skevlo	sc->rf24_40mhz = 0x2f;
5515260219Skevlo
5516260219Skevlo	/* Save default BBP registers 25 and 26 values. */
5517260219Skevlo	run_bbp_read(sc, 25, &sc->bbp25);
5518260219Skevlo	run_bbp_read(sc, 26, &sc->bbp26);
5519260219Skevlo
5520260219Skevlo	run_read(sc, RT3070_OPT_14, &tmp);
5521260219Skevlo	run_write(sc, RT3070_OPT_14, tmp | 1);
5522260219Skevlo}
5523260219Skevlo
5524260219Skevlostatic void
5525257955Skevlorun_rt5390_rf_init(struct run_softc *sc)
5526257955Skevlo{
5527257955Skevlo	uint32_t tmp;
5528257955Skevlo	uint8_t rf;
5529257955Skevlo	int i;
5530257955Skevlo
5531259030Skevlo	/* Toggle RF R2 to initiate calibration. */
5532259030Skevlo	if (sc->mac_ver == 0x5390) {
5533257955Skevlo		run_rt3070_rf_read(sc, 2, &rf);
5534259031Skevlo		run_rt3070_rf_write(sc, 2, rf | RT5390_RESCAL);
5535257955Skevlo		run_delay(sc, 10);
5536259031Skevlo		run_rt3070_rf_write(sc, 2, rf & ~RT5390_RESCAL);
5537259030Skevlo	} else {
5538259031Skevlo		run_rt3070_rf_write(sc, 2, RT5390_RESCAL);
5539259030Skevlo		run_delay(sc, 10);
5540257955Skevlo	}
5541257955Skevlo
5542257955Skevlo	/* Initialize RF registers to default value. */
5543259032Skevlo	if (sc->mac_ver == 0x5592) {
5544259032Skevlo		for (i = 0; i < nitems(rt5592_def_rf); i++) {
5545259032Skevlo			run_rt3070_rf_write(sc, rt5592_def_rf[i].reg,
5546259032Skevlo			    rt5592_def_rf[i].val);
5547259032Skevlo		}
5548259032Skevlo		/* Initialize RF frequency offset. */
5549259032Skevlo		run_adjust_freq_offset(sc);
5550259032Skevlo	} else if (sc->mac_ver == 0x5392) {
5551257955Skevlo		for (i = 0; i < nitems(rt5392_def_rf); i++) {
5552257955Skevlo			run_rt3070_rf_write(sc, rt5392_def_rf[i].reg,
5553257955Skevlo			    rt5392_def_rf[i].val);
5554257955Skevlo		}
5555257955Skevlo		if (sc->mac_rev >= 0x0223) {
5556257955Skevlo			run_rt3070_rf_write(sc, 23, 0x0f);
5557257955Skevlo			run_rt3070_rf_write(sc, 24, 0x3e);
5558257955Skevlo			run_rt3070_rf_write(sc, 51, 0x32);
5559257955Skevlo			run_rt3070_rf_write(sc, 53, 0x22);
5560257955Skevlo			run_rt3070_rf_write(sc, 56, 0xc1);
5561257955Skevlo			run_rt3070_rf_write(sc, 59, 0x0f);
5562257955Skevlo		}
5563257955Skevlo	} else {
5564257955Skevlo		for (i = 0; i < nitems(rt5390_def_rf); i++) {
5565257955Skevlo			run_rt3070_rf_write(sc, rt5390_def_rf[i].reg,
5566257955Skevlo			    rt5390_def_rf[i].val);
5567257955Skevlo		}
5568257955Skevlo		if (sc->mac_rev >= 0x0502) {
5569257955Skevlo			run_rt3070_rf_write(sc, 6, 0xe0);
5570257955Skevlo			run_rt3070_rf_write(sc, 25, 0x80);
5571257955Skevlo			run_rt3070_rf_write(sc, 46, 0x73);
5572257955Skevlo			run_rt3070_rf_write(sc, 53, 0x00);
5573257955Skevlo			run_rt3070_rf_write(sc, 56, 0x42);
5574257955Skevlo			run_rt3070_rf_write(sc, 61, 0xd1);
5575257955Skevlo		}
5576257955Skevlo	}
5577257955Skevlo
5578257955Skevlo	sc->rf24_20mhz = 0x1f;	/* default value */
5579259032Skevlo	sc->rf24_40mhz = (sc->mac_ver == 0x5592) ? 0 : 0x2f;
5580257955Skevlo
5581257955Skevlo	if (sc->mac_rev < 0x0211)
5582257955Skevlo		run_rt3070_rf_write(sc, 27, 0x3);
5583257955Skevlo
5584257955Skevlo	run_read(sc, RT3070_OPT_14, &tmp);
5585257955Skevlo	run_write(sc, RT3070_OPT_14, tmp | 1);
5586257955Skevlo}
5587257955Skevlo
5588203134Sthompsastatic int
5589203134Sthompsarun_rt3070_filter_calib(struct run_softc *sc, uint8_t init, uint8_t target,
5590203134Sthompsa    uint8_t *val)
5591203134Sthompsa{
5592203134Sthompsa	uint8_t rf22, rf24;
5593203134Sthompsa	uint8_t bbp55_pb, bbp55_sb, delta;
5594203134Sthompsa	int ntries;
5595203134Sthompsa
5596203134Sthompsa	/* program filter */
5597205042Sthompsa	run_rt3070_rf_read(sc, 24, &rf24);
5598205042Sthompsa	rf24 = (rf24 & 0xc0) | init;	/* initial filter value */
5599203134Sthompsa	run_rt3070_rf_write(sc, 24, rf24);
5600203134Sthompsa
5601203134Sthompsa	/* enable baseband loopback mode */
5602203134Sthompsa	run_rt3070_rf_read(sc, 22, &rf22);
5603203134Sthompsa	run_rt3070_rf_write(sc, 22, rf22 | 0x01);
5604203134Sthompsa
5605203134Sthompsa	/* set power and frequency of passband test tone */
5606203134Sthompsa	run_bbp_write(sc, 24, 0x00);
5607203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5608203134Sthompsa		/* transmit test tone */
5609203134Sthompsa		run_bbp_write(sc, 25, 0x90);
5610203134Sthompsa		run_delay(sc, 10);
5611203134Sthompsa		/* read received power */
5612203134Sthompsa		run_bbp_read(sc, 55, &bbp55_pb);
5613203134Sthompsa		if (bbp55_pb != 0)
5614203134Sthompsa			break;
5615203134Sthompsa	}
5616203134Sthompsa	if (ntries == 100)
5617257955Skevlo		return (ETIMEDOUT);
5618203134Sthompsa
5619203134Sthompsa	/* set power and frequency of stopband test tone */
5620203134Sthompsa	run_bbp_write(sc, 24, 0x06);
5621203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5622203134Sthompsa		/* transmit test tone */
5623203134Sthompsa		run_bbp_write(sc, 25, 0x90);
5624203134Sthompsa		run_delay(sc, 10);
5625203134Sthompsa		/* read received power */
5626203134Sthompsa		run_bbp_read(sc, 55, &bbp55_sb);
5627203134Sthompsa
5628203134Sthompsa		delta = bbp55_pb - bbp55_sb;
5629203134Sthompsa		if (delta > target)
5630203134Sthompsa			break;
5631203134Sthompsa
5632203134Sthompsa		/* reprogram filter */
5633203134Sthompsa		rf24++;
5634203134Sthompsa		run_rt3070_rf_write(sc, 24, rf24);
5635203134Sthompsa	}
5636203134Sthompsa	if (ntries < 100) {
5637203134Sthompsa		if (rf24 != init)
5638203134Sthompsa			rf24--;	/* backtrack */
5639203134Sthompsa		*val = rf24;
5640203134Sthompsa		run_rt3070_rf_write(sc, 24, rf24);
5641203134Sthompsa	}
5642203134Sthompsa
5643203134Sthompsa	/* restore initial state */
5644203134Sthompsa	run_bbp_write(sc, 24, 0x00);
5645203134Sthompsa
5646203134Sthompsa	/* disable baseband loopback mode */
5647203134Sthompsa	run_rt3070_rf_read(sc, 22, &rf22);
5648203134Sthompsa	run_rt3070_rf_write(sc, 22, rf22 & ~0x01);
5649203134Sthompsa
5650209917Sthompsa	return (0);
5651203134Sthompsa}
5652203134Sthompsa
5653205042Sthompsastatic void
5654205042Sthompsarun_rt3070_rf_setup(struct run_softc *sc)
5655205042Sthompsa{
5656205042Sthompsa	uint8_t bbp, rf;
5657205042Sthompsa	int i;
5658205042Sthompsa
5659260219Skevlo	if (sc->mac_ver == 0x3572) {
5660205042Sthompsa		/* enable DC filter */
5661205042Sthompsa		if (sc->mac_rev >= 0x0201)
5662205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5663205042Sthompsa
5664205042Sthompsa		run_bbp_read(sc, 138, &bbp);
5665205042Sthompsa		if (sc->ntxchains == 1)
5666205042Sthompsa			bbp |= 0x20;	/* turn off DAC1 */
5667205042Sthompsa		if (sc->nrxchains == 1)
5668205042Sthompsa			bbp &= ~0x02;	/* turn off ADC1 */
5669205042Sthompsa		run_bbp_write(sc, 138, bbp);
5670205042Sthompsa
5671205042Sthompsa		if (sc->mac_rev >= 0x0211) {
5672205042Sthompsa			/* improve power consumption */
5673205042Sthompsa			run_bbp_read(sc, 31, &bbp);
5674205042Sthompsa			run_bbp_write(sc, 31, bbp & ~0x03);
5675205042Sthompsa		}
5676205042Sthompsa
5677205042Sthompsa		run_rt3070_rf_read(sc, 16, &rf);
5678205042Sthompsa		rf = (rf & ~0x07) | sc->txmixgain_2ghz;
5679205042Sthompsa		run_rt3070_rf_write(sc, 16, rf);
5680205042Sthompsa
5681205042Sthompsa	} else if (sc->mac_ver == 0x3071) {
5682257409Skevlo		if (sc->mac_rev >= 0x0211) {
5683257409Skevlo			/* enable DC filter */
5684205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5685205042Sthompsa
5686257409Skevlo			/* improve power consumption */
5687257409Skevlo			run_bbp_read(sc, 31, &bbp);
5688257409Skevlo			run_bbp_write(sc, 31, bbp & ~0x03);
5689257409Skevlo		}
5690257409Skevlo
5691205042Sthompsa		run_bbp_read(sc, 138, &bbp);
5692205042Sthompsa		if (sc->ntxchains == 1)
5693205042Sthompsa			bbp |= 0x20;	/* turn off DAC1 */
5694205042Sthompsa		if (sc->nrxchains == 1)
5695205042Sthompsa			bbp &= ~0x02;	/* turn off ADC1 */
5696205042Sthompsa		run_bbp_write(sc, 138, bbp);
5697205042Sthompsa
5698205042Sthompsa		run_write(sc, RT2860_TX_SW_CFG1, 0);
5699205042Sthompsa		if (sc->mac_rev < 0x0211) {
5700205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2,
5701205042Sthompsa			    sc->patch_dac ? 0x2c : 0x0f);
5702205042Sthompsa		} else
5703205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0);
5704205042Sthompsa
5705205042Sthompsa	} else if (sc->mac_ver == 0x3070) {
5706205042Sthompsa		if (sc->mac_rev >= 0x0201) {
5707205042Sthompsa			/* enable DC filter */
5708205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5709205042Sthompsa
5710205042Sthompsa			/* improve power consumption */
5711205042Sthompsa			run_bbp_read(sc, 31, &bbp);
5712205042Sthompsa			run_bbp_write(sc, 31, bbp & ~0x03);
5713205042Sthompsa		}
5714205042Sthompsa
5715256955Skevlo		if (sc->mac_rev < 0x0201) {
5716205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG1, 0);
5717205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0x2c);
5718205042Sthompsa		} else
5719205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0);
5720205042Sthompsa	}
5721205042Sthompsa
5722205042Sthompsa	/* initialize RF registers from ROM for >=RT3071*/
5723260219Skevlo	if (sc->mac_ver >= 0x3071) {
5724205042Sthompsa		for (i = 0; i < 10; i++) {
5725205042Sthompsa			if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff)
5726205042Sthompsa				continue;
5727205042Sthompsa			run_rt3070_rf_write(sc, sc->rf[i].reg, sc->rf[i].val);
5728205042Sthompsa		}
5729205042Sthompsa	}
5730205042Sthompsa}
5731205042Sthompsa
5732260219Skevlostatic void
5733260219Skevlorun_rt3593_rf_setup(struct run_softc *sc)
5734260219Skevlo{
5735260219Skevlo	uint8_t bbp, rf;
5736260219Skevlo
5737260219Skevlo	if (sc->mac_rev >= 0x0211) {
5738260219Skevlo		/* Enable DC filter. */
5739260219Skevlo		run_bbp_write(sc, 103, 0xc0);
5740260219Skevlo	}
5741260219Skevlo	run_write(sc, RT2860_TX_SW_CFG1, 0);
5742260219Skevlo	if (sc->mac_rev < 0x0211) {
5743260219Skevlo		run_write(sc, RT2860_TX_SW_CFG2,
5744260219Skevlo		    sc->patch_dac ? 0x2c : 0x0f);
5745260219Skevlo	} else
5746260219Skevlo		run_write(sc, RT2860_TX_SW_CFG2, 0);
5747260219Skevlo
5748260219Skevlo	run_rt3070_rf_read(sc, 50, &rf);
5749260219Skevlo	run_rt3070_rf_write(sc, 50, rf & ~RT3593_TX_LO2);
5750260219Skevlo
5751260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
5752260219Skevlo	rf = (rf & ~(RT3593_TX_LO1 | 0x0c)) |
5753260219Skevlo	    ((sc->txmixgain_2ghz & 0x07) << 2);
5754260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
5755260219Skevlo
5756260219Skevlo	run_rt3070_rf_read(sc, 38, &rf);
5757260219Skevlo	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
5758260219Skevlo
5759260219Skevlo	run_rt3070_rf_read(sc, 39, &rf);
5760260219Skevlo	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
5761260219Skevlo
5762260219Skevlo	run_rt3070_rf_read(sc, 1, &rf);
5763260219Skevlo	run_rt3070_rf_write(sc, 1, rf & ~(RT3070_RF_BLOCK | RT3070_PLL_PD));
5764260219Skevlo
5765260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
5766260219Skevlo	rf = (rf & ~0x18) | 0x10;
5767260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
5768260219Skevlo
5769260219Skevlo	/* Apply maximum likelihood detection for 2 stream case. */
5770260219Skevlo	run_bbp_read(sc, 105, &bbp);
5771260219Skevlo	if (sc->nrxchains > 1)
5772260219Skevlo		run_bbp_write(sc, 105, bbp | RT5390_MLD);
5773260219Skevlo
5774260219Skevlo	/* Avoid data lost and CRC error. */
5775260219Skevlo	run_bbp_read(sc, 4, &bbp);
5776260219Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5777260219Skevlo
5778260219Skevlo	run_bbp_write(sc, 92, 0x02);
5779260219Skevlo	run_bbp_write(sc, 82, 0x82);
5780260219Skevlo	run_bbp_write(sc, 106, 0x05);
5781260219Skevlo	run_bbp_write(sc, 104, 0x92);
5782260219Skevlo	run_bbp_write(sc, 88, 0x90);
5783260219Skevlo	run_bbp_write(sc, 148, 0xc8);
5784260219Skevlo	run_bbp_write(sc, 47, 0x48);
5785260219Skevlo	run_bbp_write(sc, 120, 0x50);
5786260219Skevlo
5787260219Skevlo	run_bbp_write(sc, 163, 0x9d);
5788260219Skevlo
5789260219Skevlo	/* SNR mapping. */
5790260219Skevlo	run_bbp_write(sc, 142, 0x06);
5791260219Skevlo	run_bbp_write(sc, 143, 0xa0);
5792260219Skevlo	run_bbp_write(sc, 142, 0x07);
5793260219Skevlo	run_bbp_write(sc, 143, 0xa1);
5794260219Skevlo	run_bbp_write(sc, 142, 0x08);
5795260219Skevlo	run_bbp_write(sc, 143, 0xa2);
5796260219Skevlo
5797260219Skevlo	run_bbp_write(sc, 31, 0x08);
5798260219Skevlo	run_bbp_write(sc, 68, 0x0b);
5799260219Skevlo	run_bbp_write(sc, 105, 0x04);
5800260219Skevlo}
5801260219Skevlo
5802260219Skevlostatic void
5803260219Skevlorun_rt5390_rf_setup(struct run_softc *sc)
5804260219Skevlo{
5805260219Skevlo	uint8_t bbp, rf;
5806260219Skevlo
5807260219Skevlo	if (sc->mac_rev >= 0x0211) {
5808260219Skevlo		/* Enable DC filter. */
5809260219Skevlo		run_bbp_write(sc, 103, 0xc0);
5810260219Skevlo
5811260219Skevlo		if (sc->mac_ver != 0x5592) {
5812260219Skevlo			/* Improve power consumption. */
5813260219Skevlo			run_bbp_read(sc, 31, &bbp);
5814260219Skevlo			run_bbp_write(sc, 31, bbp & ~0x03);
5815260219Skevlo		}
5816260219Skevlo	}
5817260219Skevlo
5818260219Skevlo	run_bbp_read(sc, 138, &bbp);
5819260219Skevlo	if (sc->ntxchains == 1)
5820260219Skevlo		bbp |= 0x20;	/* turn off DAC1 */
5821260219Skevlo	if (sc->nrxchains == 1)
5822260219Skevlo		bbp &= ~0x02;	/* turn off ADC1 */
5823260219Skevlo	run_bbp_write(sc, 138, bbp);
5824260219Skevlo
5825260219Skevlo	run_rt3070_rf_read(sc, 38, &rf);
5826260219Skevlo	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
5827260219Skevlo
5828260219Skevlo	run_rt3070_rf_read(sc, 39, &rf);
5829260219Skevlo	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
5830260219Skevlo
5831260219Skevlo	/* Avoid data lost and CRC error. */
5832260219Skevlo	run_bbp_read(sc, 4, &bbp);
5833260219Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5834260219Skevlo
5835260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
5836260219Skevlo	rf = (rf & ~0x18) | 0x10;
5837260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
5838260219Skevlo
5839260219Skevlo	if (sc->mac_ver != 0x5592) {
5840260219Skevlo		run_write(sc, RT2860_TX_SW_CFG1, 0);
5841260219Skevlo		if (sc->mac_rev < 0x0211) {
5842260219Skevlo			run_write(sc, RT2860_TX_SW_CFG2,
5843260219Skevlo			    sc->patch_dac ? 0x2c : 0x0f);
5844260219Skevlo		} else
5845260219Skevlo			run_write(sc, RT2860_TX_SW_CFG2, 0);
5846260219Skevlo	}
5847260219Skevlo}
5848260219Skevlo
5849203134Sthompsastatic int
5850203134Sthompsarun_txrx_enable(struct run_softc *sc)
5851203134Sthompsa{
5852287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5853203134Sthompsa	uint32_t tmp;
5854203134Sthompsa	int error, ntries;
5855203134Sthompsa
5856203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_TX_EN);
5857203134Sthompsa	for (ntries = 0; ntries < 200; ntries++) {
5858203134Sthompsa		if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0)
5859257955Skevlo			return (error);
5860203134Sthompsa		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
5861203134Sthompsa			break;
5862203134Sthompsa		run_delay(sc, 50);
5863203134Sthompsa	}
5864203134Sthompsa	if (ntries == 200)
5865257955Skevlo		return (ETIMEDOUT);
5866203134Sthompsa
5867203134Sthompsa	run_delay(sc, 50);
5868203134Sthompsa
5869203134Sthompsa	tmp |= RT2860_RX_DMA_EN | RT2860_TX_DMA_EN | RT2860_TX_WB_DDONE;
5870203134Sthompsa	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
5871203134Sthompsa
5872203134Sthompsa	/* enable Rx bulk aggregation (set timeout and limit) */
5873203134Sthompsa	tmp = RT2860_USB_TX_EN | RT2860_USB_RX_EN | RT2860_USB_RX_AGG_EN |
5874203134Sthompsa	    RT2860_USB_RX_AGG_TO(128) | RT2860_USB_RX_AGG_LMT(2);
5875203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, tmp);
5876203134Sthompsa
5877203134Sthompsa	/* set Rx filter */
5878203134Sthompsa	tmp = RT2860_DROP_CRC_ERR | RT2860_DROP_PHY_ERR;
5879203134Sthompsa	if (ic->ic_opmode != IEEE80211_M_MONITOR) {
5880203134Sthompsa		tmp |= RT2860_DROP_UC_NOME | RT2860_DROP_DUPL |
5881203134Sthompsa		    RT2860_DROP_CTS | RT2860_DROP_BA | RT2860_DROP_ACK |
5882203134Sthompsa		    RT2860_DROP_VER_ERR | RT2860_DROP_CTRL_RSV |
5883203134Sthompsa		    RT2860_DROP_CFACK | RT2860_DROP_CFEND;
5884203134Sthompsa		if (ic->ic_opmode == IEEE80211_M_STA)
5885203134Sthompsa			tmp |= RT2860_DROP_RTS | RT2860_DROP_PSPOLL;
5886203134Sthompsa	}
5887203134Sthompsa	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
5888203134Sthompsa
5889203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL,
5890203134Sthompsa	    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
5891203134Sthompsa
5892209917Sthompsa	return (0);
5893203134Sthompsa}
5894203134Sthompsa
5895203134Sthompsastatic void
5896259030Skevlorun_adjust_freq_offset(struct run_softc *sc)
5897257955Skevlo{
5898257955Skevlo	uint8_t rf, tmp;
5899257955Skevlo
5900257955Skevlo	run_rt3070_rf_read(sc, 17, &rf);
5901257955Skevlo	tmp = rf;
5902257955Skevlo	rf = (rf & ~0x7f) | (sc->freq & 0x7f);
5903257955Skevlo	rf = MIN(rf, 0x5f);
5904257955Skevlo
5905257955Skevlo	if (tmp != rf)
5906257955Skevlo		run_mcu_cmd(sc, 0x74, (tmp << 8 ) | rf);
5907257955Skevlo}
5908257955Skevlo
5909257955Skevlostatic void
5910203134Sthompsarun_init_locked(struct run_softc *sc)
5911203134Sthompsa{
5912287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5913287197Sglebius	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
5914203134Sthompsa	uint32_t tmp;
5915203134Sthompsa	uint8_t bbp1, bbp3;
5916203134Sthompsa	int i;
5917203134Sthompsa	int ridx;
5918203134Sthompsa	int ntries;
5919203134Sthompsa
5920209917Sthompsa	if (ic->ic_nrunning > 1)
5921208019Sthompsa		return;
5922208019Sthompsa
5923203134Sthompsa	run_stop(sc);
5924203134Sthompsa
5925233283Sbschmidt	if (run_load_microcode(sc) != 0) {
5926233283Sbschmidt		device_printf(sc->sc_dev, "could not load 8051 microcode\n");
5927233283Sbschmidt		goto fail;
5928233283Sbschmidt	}
5929233283Sbschmidt
5930203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5931203134Sthompsa		if (run_read(sc, RT2860_ASIC_VER_ID, &tmp) != 0)
5932203134Sthompsa			goto fail;
5933203134Sthompsa		if (tmp != 0 && tmp != 0xffffffff)
5934203134Sthompsa			break;
5935203134Sthompsa		run_delay(sc, 10);
5936203134Sthompsa	}
5937203134Sthompsa	if (ntries == 100)
5938203134Sthompsa		goto fail;
5939203134Sthompsa
5940203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
5941203134Sthompsa		run_setup_tx_list(sc, &sc->sc_epq[i]);
5942203134Sthompsa
5943287197Sglebius	run_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr);
5944203134Sthompsa
5945203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5946203134Sthompsa		if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
5947203134Sthompsa			goto fail;
5948203134Sthompsa		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
5949203134Sthompsa			break;
5950203134Sthompsa		run_delay(sc, 10);
5951203134Sthompsa	}
5952203134Sthompsa	if (ntries == 100) {
5953203138Sthompsa		device_printf(sc->sc_dev, "timeout waiting for DMA engine\n");
5954203134Sthompsa		goto fail;
5955203134Sthompsa	}
5956203134Sthompsa	tmp &= 0xff0;
5957203134Sthompsa	tmp |= RT2860_TX_WB_DDONE;
5958203134Sthompsa	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
5959203134Sthompsa
5960203134Sthompsa	/* turn off PME_OEN to solve high-current issue */
5961203134Sthompsa	run_read(sc, RT2860_SYS_CTRL, &tmp);
5962203134Sthompsa	run_write(sc, RT2860_SYS_CTRL, tmp & ~RT2860_PME_OEN);
5963203134Sthompsa
5964203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL,
5965203134Sthompsa	    RT2860_BBP_HRST | RT2860_MAC_SRST);
5966203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, 0);
5967203134Sthompsa
5968203134Sthompsa	if (run_reset(sc) != 0) {
5969203138Sthompsa		device_printf(sc->sc_dev, "could not reset chipset\n");
5970203134Sthompsa		goto fail;
5971203134Sthompsa	}
5972203134Sthompsa
5973203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
5974203134Sthompsa
5975203134Sthompsa	/* init Tx power for all Tx rates (from EEPROM) */
5976203134Sthompsa	for (ridx = 0; ridx < 5; ridx++) {
5977203134Sthompsa		if (sc->txpow20mhz[ridx] == 0xffffffff)
5978203134Sthompsa			continue;
5979203134Sthompsa		run_write(sc, RT2860_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]);
5980203134Sthompsa	}
5981203134Sthompsa
5982257955Skevlo	for (i = 0; i < nitems(rt2870_def_mac); i++)
5983203134Sthompsa		run_write(sc, rt2870_def_mac[i].reg, rt2870_def_mac[i].val);
5984203134Sthompsa	run_write(sc, RT2860_WMM_AIFSN_CFG, 0x00002273);
5985203134Sthompsa	run_write(sc, RT2860_WMM_CWMIN_CFG, 0x00002344);
5986203134Sthompsa	run_write(sc, RT2860_WMM_CWMAX_CFG, 0x000034aa);
5987203134Sthompsa
5988259030Skevlo	if (sc->mac_ver >= 0x5390) {
5989259030Skevlo		run_write(sc, RT2860_TX_SW_CFG0,
5990259030Skevlo		    4 << RT2860_DLY_PAPE_EN_SHIFT | 4);
5991259030Skevlo		if (sc->mac_ver >= 0x5392) {
5992259030Skevlo			run_write(sc, RT2860_MAX_LEN_CFG, 0x00002fff);
5993259032Skevlo			if (sc->mac_ver == 0x5592) {
5994259032Skevlo				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcba980);
5995259032Skevlo				run_write(sc, RT2860_TXOP_HLDR_ET, 0x00000082);
5996259032Skevlo			} else {
5997259032Skevlo				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcb4980);
5998259032Skevlo				run_write(sc, RT2860_LG_FBK_CFG0, 0xedcba322);
5999259032Skevlo			}
6000259030Skevlo		}
6001260219Skevlo	} else if (sc->mac_ver == 0x3593) {
6002260219Skevlo		run_write(sc, RT2860_TX_SW_CFG0,
6003260219Skevlo		    4 << RT2860_DLY_PAPE_EN_SHIFT | 2);
6004257955Skevlo	} else if (sc->mac_ver >= 0x3070) {
6005203134Sthompsa		/* set delay of PA_PE assertion to 1us (unit of 0.25us) */
6006203134Sthompsa		run_write(sc, RT2860_TX_SW_CFG0,
6007203134Sthompsa		    4 << RT2860_DLY_PAPE_EN_SHIFT);
6008203134Sthompsa	}
6009203134Sthompsa
6010203134Sthompsa	/* wait while MAC is busy */
6011203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
6012203134Sthompsa		if (run_read(sc, RT2860_MAC_STATUS_REG, &tmp) != 0)
6013203134Sthompsa			goto fail;
6014203134Sthompsa		if (!(tmp & (RT2860_RX_STATUS_BUSY | RT2860_TX_STATUS_BUSY)))
6015203134Sthompsa			break;
6016203134Sthompsa		run_delay(sc, 10);
6017203134Sthompsa	}
6018203134Sthompsa	if (ntries == 100)
6019203134Sthompsa		goto fail;
6020203134Sthompsa
6021203134Sthompsa	/* clear Host to MCU mailbox */
6022203134Sthompsa	run_write(sc, RT2860_H2M_BBPAGENT, 0);
6023203134Sthompsa	run_write(sc, RT2860_H2M_MAILBOX, 0);
6024203134Sthompsa	run_delay(sc, 10);
6025203134Sthompsa
6026203134Sthompsa	if (run_bbp_init(sc) != 0) {
6027203138Sthompsa		device_printf(sc->sc_dev, "could not initialize BBP\n");
6028203134Sthompsa		goto fail;
6029203134Sthompsa	}
6030203134Sthompsa
6031203134Sthompsa	/* abort TSF synchronization */
6032203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
6033203134Sthompsa	tmp &= ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
6034203134Sthompsa	    RT2860_TBTT_TIMER_EN);
6035203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
6036203134Sthompsa
6037203134Sthompsa	/* clear RX WCID search table */
6038203134Sthompsa	run_set_region_4(sc, RT2860_WCID_ENTRY(0), 0, 512);
6039203134Sthompsa	/* clear WCID attribute table */
6040203134Sthompsa	run_set_region_4(sc, RT2860_WCID_ATTR(0), 0, 8 * 32);
6041203134Sthompsa
6042209144Sthompsa	/* hostapd sets a key before init. So, don't clear it. */
6043209917Sthompsa	if (sc->cmdq_key_set != RUN_CMDQ_GO) {
6044209144Sthompsa		/* clear shared key table */
6045209144Sthompsa		run_set_region_4(sc, RT2860_SKEY(0, 0), 0, 8 * 32);
6046209144Sthompsa		/* clear shared key mode */
6047209144Sthompsa		run_set_region_4(sc, RT2860_SKEY_MODE_0_7, 0, 4);
6048209144Sthompsa	}
6049209144Sthompsa
6050203134Sthompsa	run_read(sc, RT2860_US_CYC_CNT, &tmp);
6051203134Sthompsa	tmp = (tmp & ~0xff) | 0x1e;
6052203134Sthompsa	run_write(sc, RT2860_US_CYC_CNT, tmp);
6053203134Sthompsa
6054205042Sthompsa	if (sc->mac_rev != 0x0101)
6055203134Sthompsa		run_write(sc, RT2860_TXOP_CTRL_CFG, 0x0000583f);
6056203134Sthompsa
6057203134Sthompsa	run_write(sc, RT2860_WMM_TXOP0_CFG, 0);
6058203134Sthompsa	run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96);
6059203134Sthompsa
6060203134Sthompsa	/* write vendor-specific BBP values (from EEPROM) */
6061260219Skevlo	if (sc->mac_ver < 0x3593) {
6062257955Skevlo		for (i = 0; i < 10; i++) {
6063257955Skevlo			if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff)
6064257955Skevlo				continue;
6065257955Skevlo			run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val);
6066257955Skevlo		}
6067203134Sthompsa	}
6068203134Sthompsa
6069203134Sthompsa	/* select Main antenna for 1T1R devices */
6070257955Skevlo	if (sc->rf_rev == RT3070_RF_3020 || sc->rf_rev == RT5390_RF_5370)
6071203134Sthompsa		run_set_rx_antenna(sc, 0);
6072203134Sthompsa
6073203134Sthompsa	/* send LEDs operating mode to microcontroller */
6074203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0]);
6075203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1]);
6076203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2]);
6077203134Sthompsa
6078257955Skevlo	if (sc->mac_ver >= 0x5390)
6079257955Skevlo		run_rt5390_rf_init(sc);
6080260219Skevlo	else if (sc->mac_ver == 0x3593)
6081260219Skevlo		run_rt3593_rf_init(sc);
6082257955Skevlo	else if (sc->mac_ver >= 0x3070)
6083205042Sthompsa		run_rt3070_rf_init(sc);
6084205042Sthompsa
6085203134Sthompsa	/* disable non-existing Rx chains */
6086203134Sthompsa	run_bbp_read(sc, 3, &bbp3);
6087203134Sthompsa	bbp3 &= ~(1 << 3 | 1 << 4);
6088203134Sthompsa	if (sc->nrxchains == 2)
6089203134Sthompsa		bbp3 |= 1 << 3;
6090203134Sthompsa	else if (sc->nrxchains == 3)
6091203134Sthompsa		bbp3 |= 1 << 4;
6092203134Sthompsa	run_bbp_write(sc, 3, bbp3);
6093203134Sthompsa
6094203134Sthompsa	/* disable non-existing Tx chains */
6095203134Sthompsa	run_bbp_read(sc, 1, &bbp1);
6096203134Sthompsa	if (sc->ntxchains == 1)
6097203134Sthompsa		bbp1 &= ~(1 << 3 | 1 << 4);
6098203134Sthompsa	run_bbp_write(sc, 1, bbp1);
6099203134Sthompsa
6100260219Skevlo	if (sc->mac_ver >= 0x5390)
6101260219Skevlo		run_rt5390_rf_setup(sc);
6102260219Skevlo	else if (sc->mac_ver == 0x3593)
6103260219Skevlo		run_rt3593_rf_setup(sc);
6104260219Skevlo	else if (sc->mac_ver >= 0x3070)
6105205042Sthompsa		run_rt3070_rf_setup(sc);
6106203134Sthompsa
6107203134Sthompsa	/* select default channel */
6108203134Sthompsa	run_set_chan(sc, ic->ic_curchan);
6109203134Sthompsa
6110203134Sthompsa	/* setup initial protection mode */
6111218492Sbschmidt	run_updateprot_cb(ic);
6112203134Sthompsa
6113203134Sthompsa	/* turn radio LED on */
6114203134Sthompsa	run_set_leds(sc, RT2860_LED_RADIO);
6115203134Sthompsa
6116287197Sglebius	sc->sc_flags |= RUN_RUNNING;
6117208019Sthompsa	sc->cmdq_run = RUN_CMDQ_GO;
6118203134Sthompsa
6119209917Sthompsa	for (i = 0; i != RUN_N_XFER; i++)
6120203134Sthompsa		usbd_xfer_set_stall(sc->sc_xfer[i]);
6121203134Sthompsa
6122203134Sthompsa	usbd_transfer_start(sc->sc_xfer[RUN_BULK_RX]);
6123203134Sthompsa
6124203134Sthompsa	if (run_txrx_enable(sc) != 0)
6125203134Sthompsa		goto fail;
6126203134Sthompsa
6127203134Sthompsa	return;
6128203134Sthompsa
6129203134Sthompsafail:
6130203134Sthompsa	run_stop(sc);
6131203134Sthompsa}
6132203134Sthompsa
6133203134Sthompsastatic void
6134203134Sthompsarun_stop(void *arg)
6135203134Sthompsa{
6136203134Sthompsa	struct run_softc *sc = (struct run_softc *)arg;
6137203134Sthompsa	uint32_t tmp;
6138203134Sthompsa	int i;
6139203134Sthompsa	int ntries;
6140203134Sthompsa
6141203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
6142203134Sthompsa
6143287197Sglebius	if (sc->sc_flags & RUN_RUNNING)
6144203134Sthompsa		run_set_leds(sc, 0);	/* turn all LEDs off */
6145203134Sthompsa
6146287197Sglebius	sc->sc_flags &= ~RUN_RUNNING;
6147203134Sthompsa
6148208019Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
6149209144Sthompsa	sc->cmdq_run = sc->cmdq_key_set;
6150208019Sthompsa
6151203134Sthompsa	RUN_UNLOCK(sc);
6152203134Sthompsa
6153203134Sthompsa	for(i = 0; i < RUN_N_XFER; i++)
6154203134Sthompsa		usbd_transfer_drain(sc->sc_xfer[i]);
6155203134Sthompsa
6156203134Sthompsa	RUN_LOCK(sc);
6157203134Sthompsa
6158288649Sadrian	run_drain_mbufq(sc);
6159288649Sadrian
6160209917Sthompsa	if (sc->rx_m != NULL) {
6161203134Sthompsa		m_free(sc->rx_m);
6162203134Sthompsa		sc->rx_m = NULL;
6163203134Sthompsa	}
6164203134Sthompsa
6165257955Skevlo	/* Disable Tx/Rx DMA. */
6166257955Skevlo	if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
6167257955Skevlo		return;
6168257955Skevlo	tmp &= ~(RT2860_RX_DMA_EN | RT2860_TX_DMA_EN);
6169257955Skevlo	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
6170257955Skevlo
6171258643Shselasky	for (ntries = 0; ntries < 100; ntries++) {
6172257955Skevlo		if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
6173257955Skevlo			return;
6174257955Skevlo		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
6175257955Skevlo				break;
6176257955Skevlo		run_delay(sc, 10);
6177257955Skevlo	}
6178257955Skevlo	if (ntries == 100) {
6179257955Skevlo		device_printf(sc->sc_dev, "timeout waiting for DMA engine\n");
6180257955Skevlo		return;
6181257955Skevlo	}
6182257955Skevlo
6183203134Sthompsa	/* disable Tx/Rx */
6184203134Sthompsa	run_read(sc, RT2860_MAC_SYS_CTRL, &tmp);
6185203134Sthompsa	tmp &= ~(RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
6186203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, tmp);
6187203134Sthompsa
6188203134Sthompsa	/* wait for pending Tx to complete */
6189203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
6190209917Sthompsa		if (run_read(sc, RT2860_TXRXQ_PCNT, &tmp) != 0) {
6191203134Sthompsa			DPRINTF("Cannot read Tx queue count\n");
6192203134Sthompsa			break;
6193203134Sthompsa		}
6194209917Sthompsa		if ((tmp & RT2860_TX2Q_PCNT_MASK) == 0) {
6195203134Sthompsa			DPRINTF("All Tx cleared\n");
6196203134Sthompsa			break;
6197203134Sthompsa		}
6198203134Sthompsa		run_delay(sc, 10);
6199203134Sthompsa	}
6200209917Sthompsa	if (ntries >= 100)
6201203134Sthompsa		DPRINTF("There are still pending Tx\n");
6202203134Sthompsa	run_delay(sc, 10);
6203203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, 0);
6204203134Sthompsa
6205203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST);
6206203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
6207203134Sthompsa
6208203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
6209203134Sthompsa		run_unsetup_tx_list(sc, &sc->sc_epq[i]);
6210203134Sthompsa}
6211203134Sthompsa
6212203134Sthompsastatic void
6213257429Shselaskyrun_delay(struct run_softc *sc, u_int ms)
6214203134Sthompsa{
6215203134Sthompsa	usb_pause_mtx(mtx_owned(&sc->sc_mtx) ?
6216203134Sthompsa	    &sc->sc_mtx : NULL, USB_MS_TO_TICKS(ms));
6217203134Sthompsa}
6218203134Sthompsa
6219203134Sthompsastatic device_method_t run_methods[] = {
6220203134Sthompsa	/* Device interface */
6221203134Sthompsa	DEVMETHOD(device_probe,		run_match),
6222203134Sthompsa	DEVMETHOD(device_attach,	run_attach),
6223203134Sthompsa	DEVMETHOD(device_detach,	run_detach),
6224246614Shselasky	DEVMETHOD_END
6225203134Sthompsa};
6226203134Sthompsa
6227203134Sthompsastatic driver_t run_driver = {
6228233774Shselasky	.name = "run",
6229233774Shselasky	.methods = run_methods,
6230233774Shselasky	.size = sizeof(struct run_softc)
6231203134Sthompsa};
6232203134Sthompsa
6233203134Sthompsastatic devclass_t run_devclass;
6234203134Sthompsa
6235259812SkevloDRIVER_MODULE(run, uhub, run_driver, run_devclass, run_driver_loaded, NULL);
6236212122SthompsaMODULE_DEPEND(run, wlan, 1, 1, 1);
6237212122SthompsaMODULE_DEPEND(run, usb, 1, 1, 1);
6238212122SthompsaMODULE_DEPEND(run, firmware, 1, 1, 1);
6239212122SthompsaMODULE_VERSION(run, 1);
6240292080SimpUSB_PNP_HOST_INFO(run_devs);
6241