if_run.c revision 301302
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 301302 2016-06-04 07:18:39Z adrian $");
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 *);
426300748Savosstatic void	run_getradiocaps(struct ieee80211com *, int, int *,
427300748Savos		    struct ieee80211_channel[]);
428203134Sthompsastatic void	run_scan_start(struct ieee80211com *);
429203134Sthompsastatic void	run_scan_end(struct ieee80211com *);
430203134Sthompsastatic void	run_update_beacon(struct ieee80211vap *, int);
431208019Sthompsastatic void	run_update_beacon_cb(void *);
432203134Sthompsastatic void	run_updateprot(struct ieee80211com *);
433218492Sbschmidtstatic void	run_updateprot_cb(void *);
434208019Sthompsastatic void	run_usb_timeout_cb(void *);
435203134Sthompsastatic void	run_reset_livelock(struct run_softc *);
436203134Sthompsastatic void	run_enable_tsf_sync(struct run_softc *);
437287555Skevlostatic void	run_enable_tsf(struct run_softc *);
438287554Skevlostatic void	run_get_tsf(struct run_softc *, uint64_t *);
439203134Sthompsastatic void	run_enable_mrr(struct run_softc *);
440203134Sthompsastatic void	run_set_txpreamble(struct run_softc *);
441203134Sthompsastatic void	run_set_basicrates(struct run_softc *);
442203134Sthompsastatic void	run_set_leds(struct run_softc *, uint16_t);
443203134Sthompsastatic void	run_set_bssid(struct run_softc *, const uint8_t *);
444203134Sthompsastatic void	run_set_macaddr(struct run_softc *, const uint8_t *);
445283540Sglebiusstatic void	run_updateslot(struct ieee80211com *);
446218492Sbschmidtstatic void	run_updateslot_cb(void *);
447283540Sglebiusstatic void	run_update_mcast(struct ieee80211com *);
448203134Sthompsastatic int8_t	run_rssi2dbm(struct run_softc *, uint8_t, uint8_t);
449283540Sglebiusstatic void	run_update_promisc_locked(struct run_softc *);
450283540Sglebiusstatic void	run_update_promisc(struct ieee80211com *);
451257955Skevlostatic void	run_rt5390_bbp_init(struct run_softc *);
452203134Sthompsastatic int	run_bbp_init(struct run_softc *);
453203134Sthompsastatic int	run_rt3070_rf_init(struct run_softc *);
454260219Skevlostatic void	run_rt3593_rf_init(struct run_softc *);
455257955Skevlostatic void	run_rt5390_rf_init(struct run_softc *);
456203134Sthompsastatic int	run_rt3070_filter_calib(struct run_softc *, uint8_t, uint8_t,
457203134Sthompsa		    uint8_t *);
458205042Sthompsastatic void	run_rt3070_rf_setup(struct run_softc *);
459260219Skevlostatic void	run_rt3593_rf_setup(struct run_softc *);
460260219Skevlostatic void	run_rt5390_rf_setup(struct run_softc *);
461203134Sthompsastatic int	run_txrx_enable(struct run_softc *);
462257955Skevlostatic void	run_adjust_freq_offset(struct run_softc *);
463203134Sthompsastatic void	run_init_locked(struct run_softc *);
464203134Sthompsastatic void	run_stop(void *);
465257429Shselaskystatic void	run_delay(struct run_softc *, u_int);
466203134Sthompsa
467259812Skevlostatic eventhandler_tag run_etag;
468259812Skevlo
469259544Skevlostatic const struct rt2860_rate {
470259544Skevlo	uint8_t		rate;
471259544Skevlo	uint8_t		mcs;
472259544Skevlo	enum		ieee80211_phytype phy;
473259544Skevlo	uint8_t		ctl_ridx;
474259544Skevlo	uint16_t	sp_ack_dur;
475259544Skevlo	uint16_t	lp_ack_dur;
476259544Skevlo} rt2860_rates[] = {
477259544Skevlo	{   2, 0, IEEE80211_T_DS,   0, 314, 314 },
478259544Skevlo	{   4, 1, IEEE80211_T_DS,   1, 258, 162 },
479259544Skevlo	{  11, 2, IEEE80211_T_DS,   2, 223, 127 },
480259544Skevlo	{  22, 3, IEEE80211_T_DS,   3, 213, 117 },
481259544Skevlo	{  12, 0, IEEE80211_T_OFDM, 4,  60,  60 },
482259544Skevlo	{  18, 1, IEEE80211_T_OFDM, 4,  52,  52 },
483259544Skevlo	{  24, 2, IEEE80211_T_OFDM, 6,  48,  48 },
484259544Skevlo	{  36, 3, IEEE80211_T_OFDM, 6,  44,  44 },
485259544Skevlo	{  48, 4, IEEE80211_T_OFDM, 8,  44,  44 },
486259544Skevlo	{  72, 5, IEEE80211_T_OFDM, 8,  40,  40 },
487259544Skevlo	{  96, 6, IEEE80211_T_OFDM, 8,  40,  40 },
488259544Skevlo	{ 108, 7, IEEE80211_T_OFDM, 8,  40,  40 }
489259544Skevlo};
490259544Skevlo
491203134Sthompsastatic const struct {
492208019Sthompsa	uint16_t	reg;
493203134Sthompsa	uint32_t	val;
494203134Sthompsa} rt2870_def_mac[] = {
495203134Sthompsa	RT2870_DEF_MAC
496203134Sthompsa};
497203134Sthompsa
498203134Sthompsastatic const struct {
499203134Sthompsa	uint8_t	reg;
500203134Sthompsa	uint8_t	val;
501203134Sthompsa} rt2860_def_bbp[] = {
502203134Sthompsa	RT2860_DEF_BBP
503257955Skevlo},rt5390_def_bbp[] = {
504257955Skevlo	RT5390_DEF_BBP
505259032Skevlo},rt5592_def_bbp[] = {
506259032Skevlo	RT5592_DEF_BBP
507203134Sthompsa};
508203134Sthompsa
509259032Skevlo/*
510259032Skevlo * Default values for BBP register R196 for RT5592.
511259032Skevlo */
512259032Skevlostatic const uint8_t rt5592_bbp_r196[] = {
513259032Skevlo	0xe0, 0x1f, 0x38, 0x32, 0x08, 0x28, 0x19, 0x0a, 0xff, 0x00,
514259032Skevlo	0x16, 0x10, 0x10, 0x0b, 0x36, 0x2c, 0x26, 0x24, 0x42, 0x36,
515259032Skevlo	0x30, 0x2d, 0x4c, 0x46, 0x3d, 0x40, 0x3e, 0x42, 0x3d, 0x40,
516259032Skevlo	0x3c, 0x34, 0x2c, 0x2f, 0x3c, 0x35, 0x2e, 0x2a, 0x49, 0x41,
517259032Skevlo	0x36, 0x31, 0x30, 0x30, 0x0e, 0x0d, 0x28, 0x21, 0x1c, 0x16,
518259032Skevlo	0x50, 0x4a, 0x43, 0x40, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00,
519259032Skevlo	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
520259032Skevlo	0x00, 0x00, 0x7d, 0x14, 0x32, 0x2c, 0x36, 0x4c, 0x43, 0x2c,
521259032Skevlo	0x2e, 0x36, 0x30, 0x6e
522259032Skevlo};
523259032Skevlo
524203134Sthompsastatic const struct rfprog {
525203134Sthompsa	uint8_t		chan;
526203134Sthompsa	uint32_t	r1, r2, r3, r4;
527203134Sthompsa} rt2860_rf2850[] = {
528203134Sthompsa	RT2860_RF2850
529203134Sthompsa};
530203134Sthompsa
531203134Sthompsastruct {
532203134Sthompsa	uint8_t	n, r, k;
533205042Sthompsa} rt3070_freqs[] = {
534205042Sthompsa	RT3070_RF3052
535203134Sthompsa};
536203134Sthompsa
537259032Skevlostatic const struct rt5592_freqs {
538259032Skevlo	uint16_t	n;
539259032Skevlo	uint8_t		k, m, r;
540259032Skevlo} rt5592_freqs_20mhz[] = {
541259032Skevlo	RT5592_RF5592_20MHZ
542259032Skevlo},rt5592_freqs_40mhz[] = {
543259032Skevlo	RT5592_RF5592_40MHZ
544259032Skevlo};
545259032Skevlo
546203134Sthompsastatic const struct {
547203134Sthompsa	uint8_t	reg;
548203134Sthompsa	uint8_t	val;
549203134Sthompsa} rt3070_def_rf[] = {
550203134Sthompsa	RT3070_DEF_RF
551205042Sthompsa},rt3572_def_rf[] = {
552205042Sthompsa	RT3572_DEF_RF
553260219Skevlo},rt3593_def_rf[] = {
554260219Skevlo	RT3593_DEF_RF
555257955Skevlo},rt5390_def_rf[] = {
556257955Skevlo	RT5390_DEF_RF
557257955Skevlo},rt5392_def_rf[] = {
558257955Skevlo	RT5392_DEF_RF
559259032Skevlo},rt5592_def_rf[] = {
560259032Skevlo	RT5592_DEF_RF
561259032Skevlo},rt5592_2ghz_def_rf[] = {
562259032Skevlo	RT5592_2GHZ_DEF_RF
563259032Skevlo},rt5592_5ghz_def_rf[] = {
564259032Skevlo	RT5592_5GHZ_DEF_RF
565203134Sthompsa};
566203134Sthompsa
567259032Skevlostatic const struct {
568259032Skevlo	u_int	firstchan;
569259032Skevlo	u_int	lastchan;
570259032Skevlo	uint8_t	reg;
571259032Skevlo	uint8_t	val;
572259032Skevlo} rt5592_chan_5ghz[] = {
573259032Skevlo	RT5592_CHAN_5GHZ
574259032Skevlo};
575259032Skevlo
576203134Sthompsastatic const struct usb_config run_config[RUN_N_XFER] = {
577203134Sthompsa    [RUN_BULK_TX_BE] = {
578203134Sthompsa	.type = UE_BULK,
579203134Sthompsa	.endpoint = UE_ADDR_ANY,
580203134Sthompsa	.ep_index = 0,
581203134Sthompsa	.direction = UE_DIR_OUT,
582203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
583203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
584203134Sthompsa	.callback = run_bulk_tx_callback0,
585203134Sthompsa	.timeout = 5000,	/* ms */
586203134Sthompsa    },
587203134Sthompsa    [RUN_BULK_TX_BK] = {
588203134Sthompsa	.type = UE_BULK,
589203134Sthompsa	.endpoint = UE_ADDR_ANY,
590203134Sthompsa	.direction = UE_DIR_OUT,
591203134Sthompsa	.ep_index = 1,
592203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
593203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
594203134Sthompsa	.callback = run_bulk_tx_callback1,
595203134Sthompsa	.timeout = 5000,	/* ms */
596203134Sthompsa    },
597203134Sthompsa    [RUN_BULK_TX_VI] = {
598203134Sthompsa	.type = UE_BULK,
599203134Sthompsa	.endpoint = UE_ADDR_ANY,
600203134Sthompsa	.direction = UE_DIR_OUT,
601203134Sthompsa	.ep_index = 2,
602203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
603203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
604203134Sthompsa	.callback = run_bulk_tx_callback2,
605203134Sthompsa	.timeout = 5000,	/* ms */
606203134Sthompsa    },
607203134Sthompsa    [RUN_BULK_TX_VO] = {
608203134Sthompsa	.type = UE_BULK,
609203134Sthompsa	.endpoint = UE_ADDR_ANY,
610203134Sthompsa	.direction = UE_DIR_OUT,
611203134Sthompsa	.ep_index = 3,
612203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
613203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
614203134Sthompsa	.callback = run_bulk_tx_callback3,
615203134Sthompsa	.timeout = 5000,	/* ms */
616203134Sthompsa    },
617203134Sthompsa    [RUN_BULK_TX_HCCA] = {
618203134Sthompsa	.type = UE_BULK,
619203134Sthompsa	.endpoint = UE_ADDR_ANY,
620203134Sthompsa	.direction = UE_DIR_OUT,
621203134Sthompsa	.ep_index = 4,
622203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
623203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
624203134Sthompsa	.callback = run_bulk_tx_callback4,
625203134Sthompsa	.timeout = 5000,	/* ms */
626203134Sthompsa    },
627203134Sthompsa    [RUN_BULK_TX_PRIO] = {
628203134Sthompsa	.type = UE_BULK,
629203134Sthompsa	.endpoint = UE_ADDR_ANY,
630203134Sthompsa	.direction = UE_DIR_OUT,
631203134Sthompsa	.ep_index = 5,
632203134Sthompsa	.bufsize = RUN_MAX_TXSZ,
633203134Sthompsa	.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
634203134Sthompsa	.callback = run_bulk_tx_callback5,
635203134Sthompsa	.timeout = 5000,	/* ms */
636203134Sthompsa    },
637203134Sthompsa    [RUN_BULK_RX] = {
638203134Sthompsa	.type = UE_BULK,
639203134Sthompsa	.endpoint = UE_ADDR_ANY,
640203134Sthompsa	.direction = UE_DIR_IN,
641203134Sthompsa	.bufsize = RUN_MAX_RXSZ,
642203134Sthompsa	.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
643203134Sthompsa	.callback = run_bulk_rx_callback,
644203134Sthompsa    }
645203134Sthompsa};
646203134Sthompsa
647259812Skevlostatic void
648259812Skevlorun_autoinst(void *arg, struct usb_device *udev,
649259812Skevlo    struct usb_attach_arg *uaa)
650259812Skevlo{
651259812Skevlo	struct usb_interface *iface;
652259812Skevlo	struct usb_interface_descriptor *id;
653259812Skevlo
654259812Skevlo	if (uaa->dev_state != UAA_DEV_READY)
655259812Skevlo		return;
656259812Skevlo
657259812Skevlo	iface = usbd_get_iface(udev, 0);
658259812Skevlo	if (iface == NULL)
659259812Skevlo		return;
660259812Skevlo	id = iface->idesc;
661259812Skevlo	if (id == NULL || id->bInterfaceClass != UICLASS_MASS)
662259812Skevlo		return;
663259812Skevlo	if (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa))
664259812Skevlo		return;
665259812Skevlo
666259812Skevlo	if (usb_msc_eject(udev, 0, MSC_EJECT_STOPUNIT) == 0)
667259812Skevlo		uaa->dev_state = UAA_DEV_EJECTING;
668259812Skevlo}
669259812Skevlo
670220235Skevlostatic int
671259812Skevlorun_driver_loaded(struct module *mod, int what, void *arg)
672259812Skevlo{
673259812Skevlo	switch (what) {
674259812Skevlo	case MOD_LOAD:
675259812Skevlo		run_etag = EVENTHANDLER_REGISTER(usb_dev_configured,
676259812Skevlo		    run_autoinst, NULL, EVENTHANDLER_PRI_ANY);
677259812Skevlo		break;
678259812Skevlo	case MOD_UNLOAD:
679259812Skevlo		EVENTHANDLER_DEREGISTER(usb_dev_configured, run_etag);
680259812Skevlo		break;
681259812Skevlo	default:
682259812Skevlo		return (EOPNOTSUPP);
683259812Skevlo	}
684259812Skevlo	return (0);
685259812Skevlo}
686259812Skevlo
687259812Skevlostatic int
688203134Sthompsarun_match(device_t self)
689203134Sthompsa{
690203134Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(self);
691203134Sthompsa
692203134Sthompsa	if (uaa->usb_mode != USB_MODE_HOST)
693203134Sthompsa		return (ENXIO);
694203134Sthompsa	if (uaa->info.bConfigIndex != 0)
695203134Sthompsa		return (ENXIO);
696203134Sthompsa	if (uaa->info.bIfaceIndex != RT2860_IFACE_INDEX)
697203134Sthompsa		return (ENXIO);
698203134Sthompsa
699203134Sthompsa	return (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa));
700203134Sthompsa}
701203134Sthompsa
702203134Sthompsastatic int
703203134Sthompsarun_attach(device_t self)
704203134Sthompsa{
705203134Sthompsa	struct run_softc *sc = device_get_softc(self);
706203134Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(self);
707287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
708205042Sthompsa	uint32_t ver;
709293339Savos	uint8_t iface_index;
710258082Skevlo	int ntries, error;
711203134Sthompsa
712203134Sthompsa	device_set_usb_desc(self);
713203134Sthompsa	sc->sc_udev = uaa->device;
714203134Sthompsa	sc->sc_dev = self;
715262465Skevlo	if (USB_GET_DRIVER_INFO(uaa) != RUN_EJECT)
716262465Skevlo		sc->sc_flags |= RUN_FLAG_FWLOAD_NEEDED;
717203134Sthompsa
718203134Sthompsa	mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev),
719203134Sthompsa	    MTX_NETWORK_LOCK, MTX_DEF);
720287197Sglebius	mbufq_init(&sc->sc_snd, ifqmaxlen);
721203134Sthompsa
722203134Sthompsa	iface_index = RT2860_IFACE_INDEX;
723208019Sthompsa
724203134Sthompsa	error = usbd_transfer_setup(uaa->device, &iface_index,
725203134Sthompsa	    sc->sc_xfer, run_config, RUN_N_XFER, sc, &sc->sc_mtx);
726203134Sthompsa	if (error) {
727205042Sthompsa		device_printf(self, "could not allocate USB transfers, "
728203134Sthompsa		    "err=%s\n", usbd_errstr(error));
729203134Sthompsa		goto detach;
730203134Sthompsa	}
731203134Sthompsa
732203134Sthompsa	RUN_LOCK(sc);
733203134Sthompsa
734203134Sthompsa	/* wait for the chip to settle */
735203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
736209917Sthompsa		if (run_read(sc, RT2860_ASIC_VER_ID, &ver) != 0) {
737203134Sthompsa			RUN_UNLOCK(sc);
738203134Sthompsa			goto detach;
739203134Sthompsa		}
740205042Sthompsa		if (ver != 0 && ver != 0xffffffff)
741203134Sthompsa			break;
742203134Sthompsa		run_delay(sc, 10);
743203134Sthompsa	}
744203134Sthompsa	if (ntries == 100) {
745203138Sthompsa		device_printf(sc->sc_dev,
746203138Sthompsa		    "timeout waiting for NIC to initialize\n");
747203134Sthompsa		RUN_UNLOCK(sc);
748203134Sthompsa		goto detach;
749203134Sthompsa	}
750205042Sthompsa	sc->mac_ver = ver >> 16;
751205042Sthompsa	sc->mac_rev = ver & 0xffff;
752203134Sthompsa
753203134Sthompsa	/* retrieve RF rev. no and various other things from EEPROM */
754203134Sthompsa	run_read_eeprom(sc);
755203134Sthompsa
756203138Sthompsa	device_printf(sc->sc_dev,
757203138Sthompsa	    "MAC/BBP RT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), address %s\n",
758205042Sthompsa	    sc->mac_ver, sc->mac_rev, run_get_rf(sc->rf_rev),
759287197Sglebius	    sc->ntxchains, sc->nrxchains, ether_sprintf(ic->ic_macaddr));
760203134Sthompsa
761203134Sthompsa	RUN_UNLOCK(sc);
762203134Sthompsa
763283537Sglebius	ic->ic_softc = sc;
764283527Sglebius	ic->ic_name = device_get_nameunit(self);
765203134Sthompsa	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
766203134Sthompsa	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
767208019Sthompsa
768203134Sthompsa	/* set device capabilities */
769203134Sthompsa	ic->ic_caps =
770203134Sthompsa	    IEEE80211_C_STA |		/* station mode supported */
771203134Sthompsa	    IEEE80211_C_MONITOR |	/* monitor mode supported */
772203134Sthompsa	    IEEE80211_C_IBSS |
773203134Sthompsa	    IEEE80211_C_HOSTAP |
774208019Sthompsa	    IEEE80211_C_WDS |		/* 4-address traffic works */
775208019Sthompsa	    IEEE80211_C_MBSS |
776203134Sthompsa	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
777203134Sthompsa	    IEEE80211_C_SHSLOT |	/* short slot time supported */
778203134Sthompsa	    IEEE80211_C_WME |		/* WME */
779214894Sbschmidt	    IEEE80211_C_WPA;		/* WPA1|WPA2(RSN) */
780203134Sthompsa
781203134Sthompsa	ic->ic_cryptocaps =
782203134Sthompsa	    IEEE80211_CRYPTO_WEP |
783203134Sthompsa	    IEEE80211_CRYPTO_AES_CCM |
784203134Sthompsa	    IEEE80211_CRYPTO_TKIPMIC |
785203134Sthompsa	    IEEE80211_CRYPTO_TKIP;
786203134Sthompsa
787203134Sthompsa	ic->ic_flags |= IEEE80211_F_DATAPAD;
788203134Sthompsa	ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;
789203134Sthompsa
790300748Savos	run_getradiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans,
791300748Savos	    ic->ic_channels);
792203134Sthompsa
793287197Sglebius	ieee80211_ifattach(ic);
794203134Sthompsa
795203134Sthompsa	ic->ic_scan_start = run_scan_start;
796203134Sthompsa	ic->ic_scan_end = run_scan_end;
797203134Sthompsa	ic->ic_set_channel = run_set_channel;
798300748Savos	ic->ic_getradiocaps = run_getradiocaps;
799203134Sthompsa	ic->ic_node_alloc = run_node_alloc;
800203134Sthompsa	ic->ic_newassoc = run_newassoc;
801218492Sbschmidt	ic->ic_updateslot = run_updateslot;
802208019Sthompsa	ic->ic_update_mcast = run_update_mcast;
803203134Sthompsa	ic->ic_wme.wme_update = run_wme_update;
804203134Sthompsa	ic->ic_raw_xmit = run_raw_xmit;
805203134Sthompsa	ic->ic_update_promisc = run_update_promisc;
806203134Sthompsa	ic->ic_vap_create = run_vap_create;
807203134Sthompsa	ic->ic_vap_delete = run_vap_delete;
808287197Sglebius	ic->ic_transmit = run_transmit;
809287197Sglebius	ic->ic_parent = run_parent;
810203134Sthompsa
811203134Sthompsa	ieee80211_radiotap_attach(ic,
812203134Sthompsa	    &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap),
813203134Sthompsa		RUN_TX_RADIOTAP_PRESENT,
814203134Sthompsa	    &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap),
815203134Sthompsa		RUN_RX_RADIOTAP_PRESENT);
816203134Sthompsa
817208019Sthompsa	TASK_INIT(&sc->cmdq_task, 0, run_cmdq_cb, sc);
818208019Sthompsa	TASK_INIT(&sc->ratectl_task, 0, run_ratectl_cb, sc);
819257712Shselasky	usb_callout_init_mtx(&sc->ratectl_ch, &sc->sc_mtx, 0);
820208019Sthompsa
821203134Sthompsa	if (bootverbose)
822203134Sthompsa		ieee80211_announce(ic);
823203134Sthompsa
824209917Sthompsa	return (0);
825203134Sthompsa
826203134Sthompsadetach:
827203134Sthompsa	run_detach(self);
828209917Sthompsa	return (ENXIO);
829203134Sthompsa}
830203134Sthompsa
831288649Sadrianstatic void
832288649Sadrianrun_drain_mbufq(struct run_softc *sc)
833288649Sadrian{
834288649Sadrian	struct mbuf *m;
835288649Sadrian	struct ieee80211_node *ni;
836288649Sadrian
837288649Sadrian	RUN_LOCK_ASSERT(sc, MA_OWNED);
838288649Sadrian	while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
839288649Sadrian		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
840288649Sadrian		m->m_pkthdr.rcvif = NULL;
841288649Sadrian		ieee80211_free_node(ni);
842288649Sadrian		m_freem(m);
843288649Sadrian	}
844288649Sadrian}
845288649Sadrian
846203134Sthompsastatic int
847203134Sthompsarun_detach(device_t self)
848203134Sthompsa{
849203134Sthompsa	struct run_softc *sc = device_get_softc(self);
850287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
851203134Sthompsa	int i;
852203134Sthompsa
853246614Shselasky	RUN_LOCK(sc);
854246614Shselasky	sc->sc_detached = 1;
855246614Shselasky	RUN_UNLOCK(sc);
856246614Shselasky
857203134Sthompsa	/* stop all USB transfers */
858203134Sthompsa	usbd_transfer_unsetup(sc->sc_xfer, RUN_N_XFER);
859203134Sthompsa
860203134Sthompsa	RUN_LOCK(sc);
861209144Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
862209144Sthompsa	sc->cmdq_run = sc->cmdq_key_set = RUN_CMDQ_ABORT;
863209144Sthompsa
864203134Sthompsa	/* free TX list, if any */
865203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
866203134Sthompsa		run_unsetup_tx_list(sc, &sc->sc_epq[i]);
867288649Sadrian
868288649Sadrian	/* Free TX queue */
869288649Sadrian	run_drain_mbufq(sc);
870203134Sthompsa	RUN_UNLOCK(sc);
871203134Sthompsa
872287197Sglebius	if (sc->sc_ic.ic_softc == sc) {
873208019Sthompsa		/* drain tasks */
874208019Sthompsa		usb_callout_drain(&sc->ratectl_ch);
875208019Sthompsa		ieee80211_draintask(ic, &sc->cmdq_task);
876208019Sthompsa		ieee80211_draintask(ic, &sc->ratectl_task);
877203134Sthompsa		ieee80211_ifdetach(ic);
878203134Sthompsa	}
879203134Sthompsa
880203134Sthompsa	mtx_destroy(&sc->sc_mtx);
881203134Sthompsa
882203134Sthompsa	return (0);
883203134Sthompsa}
884203134Sthompsa
885203134Sthompsastatic struct ieee80211vap *
886228621Sbschmidtrun_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
887228621Sbschmidt    enum ieee80211_opmode opmode, int flags,
888203134Sthompsa    const uint8_t bssid[IEEE80211_ADDR_LEN],
889203134Sthompsa    const uint8_t mac[IEEE80211_ADDR_LEN])
890203134Sthompsa{
891286950Sadrian	struct run_softc *sc = ic->ic_softc;
892203134Sthompsa	struct run_vap *rvp;
893203134Sthompsa	struct ieee80211vap *vap;
894208019Sthompsa	int i;
895203134Sthompsa
896209917Sthompsa	if (sc->rvp_cnt >= RUN_VAP_MAX) {
897287197Sglebius		device_printf(sc->sc_dev, "number of VAPs maxed out\n");
898209917Sthompsa		return (NULL);
899208019Sthompsa	}
900208019Sthompsa
901208019Sthompsa	switch (opmode) {
902208019Sthompsa	case IEEE80211_M_STA:
903208019Sthompsa		/* enable s/w bmiss handling for sta mode */
904208019Sthompsa		flags |= IEEE80211_CLONE_NOBEACONS;
905208019Sthompsa		/* fall though */
906208019Sthompsa	case IEEE80211_M_IBSS:
907208019Sthompsa	case IEEE80211_M_MONITOR:
908208019Sthompsa	case IEEE80211_M_HOSTAP:
909208019Sthompsa	case IEEE80211_M_MBSS:
910208019Sthompsa		/* other than WDS vaps, only one at a time */
911208019Sthompsa		if (!TAILQ_EMPTY(&ic->ic_vaps))
912209917Sthompsa			return (NULL);
913208019Sthompsa		break;
914208019Sthompsa	case IEEE80211_M_WDS:
915208019Sthompsa		TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next){
916208019Sthompsa			if(vap->iv_opmode != IEEE80211_M_HOSTAP)
917208019Sthompsa				continue;
918208019Sthompsa			/* WDS vap's always share the local mac address. */
919208019Sthompsa			flags &= ~IEEE80211_CLONE_BSSID;
920208019Sthompsa			break;
921208019Sthompsa		}
922209917Sthompsa		if (vap == NULL) {
923287197Sglebius			device_printf(sc->sc_dev,
924287197Sglebius			    "wds only supported in ap mode\n");
925209917Sthompsa			return (NULL);
926208019Sthompsa		}
927208019Sthompsa		break;
928208019Sthompsa	default:
929287197Sglebius		device_printf(sc->sc_dev, "unknown opmode %d\n", opmode);
930209917Sthompsa		return (NULL);
931208019Sthompsa	}
932208019Sthompsa
933287197Sglebius	rvp = malloc(sizeof(struct run_vap), M_80211_VAP, M_WAITOK | M_ZERO);
934203134Sthompsa	vap = &rvp->vap;
935203134Sthompsa
936287197Sglebius	if (ieee80211_vap_setup(ic, vap, name, unit, opmode, flags,
937287197Sglebius	    bssid) != 0) {
938257743Shselasky		/* out of memory */
939257743Shselasky		free(rvp, M_80211_VAP);
940257743Shselasky		return (NULL);
941257743Shselasky	}
942257743Shselasky
943203134Sthompsa	vap->iv_update_beacon = run_update_beacon;
944208019Sthompsa	vap->iv_max_aid = RT2870_WCID_MAX;
945208019Sthompsa	/*
946208019Sthompsa	 * To delete the right key from h/w, we need wcid.
947208019Sthompsa	 * Luckily, there is unused space in ieee80211_key{}, wk_pad,
948208019Sthompsa	 * and matching wcid will be written into there. So, cast
949208019Sthompsa	 * some spells to remove 'const' from ieee80211_key{}
950208019Sthompsa	 */
951208019Sthompsa	vap->iv_key_delete = (void *)run_key_delete;
952208019Sthompsa	vap->iv_key_set = (void *)run_key_set;
953203134Sthompsa
954203134Sthompsa	/* override state transition machine */
955203134Sthompsa	rvp->newstate = vap->iv_newstate;
956203134Sthompsa	vap->iv_newstate = run_newstate;
957288603Sadrian	if (opmode == IEEE80211_M_IBSS) {
958288603Sadrian		rvp->recv_mgmt = vap->iv_recv_mgmt;
959288603Sadrian		vap->iv_recv_mgmt = run_recv_mgmt;
960288603Sadrian	}
961203134Sthompsa
962206358Srpaulo	ieee80211_ratectl_init(vap);
963206358Srpaulo	ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */);
964203134Sthompsa
965203134Sthompsa	/* complete setup */
966287197Sglebius	ieee80211_vap_attach(vap, run_media_change, ieee80211_media_status,
967287197Sglebius	    mac);
968208019Sthompsa
969208019Sthompsa	/* make sure id is always unique */
970209917Sthompsa	for (i = 0; i < RUN_VAP_MAX; i++) {
971208019Sthompsa		if((sc->rvp_bmap & 1 << i) == 0){
972208019Sthompsa			sc->rvp_bmap |= 1 << i;
973208019Sthompsa			rvp->rvp_id = i;
974208019Sthompsa			break;
975208019Sthompsa		}
976208019Sthompsa	}
977209917Sthompsa	if (sc->rvp_cnt++ == 0)
978208019Sthompsa		ic->ic_opmode = opmode;
979208019Sthompsa
980209917Sthompsa	if (opmode == IEEE80211_M_HOSTAP)
981209144Sthompsa		sc->cmdq_run = RUN_CMDQ_GO;
982209144Sthompsa
983208019Sthompsa	DPRINTF("rvp_id=%d bmap=%x rvp_cnt=%d\n",
984208019Sthompsa	    rvp->rvp_id, sc->rvp_bmap, sc->rvp_cnt);
985208019Sthompsa
986209917Sthompsa	return (vap);
987203134Sthompsa}
988203134Sthompsa
989203134Sthompsastatic void
990203134Sthompsarun_vap_delete(struct ieee80211vap *vap)
991203134Sthompsa{
992203134Sthompsa	struct run_vap *rvp = RUN_VAP(vap);
993203134Sthompsa	struct ieee80211com *ic;
994203134Sthompsa	struct run_softc *sc;
995208019Sthompsa	uint8_t rvp_id;
996203134Sthompsa
997209917Sthompsa	if (vap == NULL)
998203134Sthompsa		return;
999203134Sthompsa
1000203134Sthompsa	ic = vap->iv_ic;
1001286950Sadrian	sc = ic->ic_softc;
1002203134Sthompsa
1003205042Sthompsa	RUN_LOCK(sc);
1004208019Sthompsa
1005218492Sbschmidt	m_freem(rvp->beacon_mbuf);
1006218492Sbschmidt	rvp->beacon_mbuf = NULL;
1007218492Sbschmidt
1008208019Sthompsa	rvp_id = rvp->rvp_id;
1009208019Sthompsa	sc->ratectl_run &= ~(1 << rvp_id);
1010208019Sthompsa	sc->rvp_bmap &= ~(1 << rvp_id);
1011208019Sthompsa	run_set_region_4(sc, RT2860_SKEY(rvp_id, 0), 0, 128);
1012208019Sthompsa	run_set_region_4(sc, RT2860_BCN_BASE(rvp_id), 0, 512);
1013208019Sthompsa	--sc->rvp_cnt;
1014208019Sthompsa
1015208019Sthompsa	DPRINTF("vap=%p rvp_id=%d bmap=%x rvp_cnt=%d\n",
1016208019Sthompsa	    vap, rvp_id, sc->rvp_bmap, sc->rvp_cnt);
1017208019Sthompsa
1018205042Sthompsa	RUN_UNLOCK(sc);
1019203134Sthompsa
1020206358Srpaulo	ieee80211_ratectl_deinit(vap);
1021203134Sthompsa	ieee80211_vap_detach(vap);
1022203134Sthompsa	free(rvp, M_80211_VAP);
1023203134Sthompsa}
1024203134Sthompsa
1025208019Sthompsa/*
1026208019Sthompsa * There are numbers of functions need to be called in context thread.
1027208019Sthompsa * Rather than creating taskqueue event for each of those functions,
1028208019Sthompsa * here is all-for-one taskqueue callback function. This function
1029298932Spfg * guarantees deferred functions are executed in the same order they
1030208019Sthompsa * were enqueued.
1031208019Sthompsa * '& RUN_CMDQ_MASQ' is to loop cmdq[].
1032208019Sthompsa */
1033203134Sthompsastatic void
1034208019Sthompsarun_cmdq_cb(void *arg, int pending)
1035208019Sthompsa{
1036208019Sthompsa	struct run_softc *sc = arg;
1037208019Sthompsa	uint8_t i;
1038208019Sthompsa
1039208019Sthompsa	/* call cmdq[].func locked */
1040208019Sthompsa	RUN_LOCK(sc);
1041209917Sthompsa	for (i = sc->cmdq_exec; sc->cmdq[i].func && pending;
1042209917Sthompsa	    i = sc->cmdq_exec, pending--) {
1043208019Sthompsa		DPRINTFN(6, "cmdq_exec=%d pending=%d\n", i, pending);
1044209917Sthompsa		if (sc->cmdq_run == RUN_CMDQ_GO) {
1045208019Sthompsa			/*
1046208019Sthompsa			 * If arg0 is NULL, callback func needs more
1047208019Sthompsa			 * than one arg. So, pass ptr to cmdq struct.
1048208019Sthompsa			 */
1049209917Sthompsa			if (sc->cmdq[i].arg0)
1050208019Sthompsa				sc->cmdq[i].func(sc->cmdq[i].arg0);
1051208019Sthompsa			else
1052208019Sthompsa				sc->cmdq[i].func(&sc->cmdq[i]);
1053208019Sthompsa		}
1054208019Sthompsa		sc->cmdq[i].arg0 = NULL;
1055208019Sthompsa		sc->cmdq[i].func = NULL;
1056208019Sthompsa		sc->cmdq_exec++;
1057208019Sthompsa		sc->cmdq_exec &= RUN_CMDQ_MASQ;
1058208019Sthompsa	}
1059208019Sthompsa	RUN_UNLOCK(sc);
1060208019Sthompsa}
1061208019Sthompsa
1062208019Sthompsastatic void
1063203134Sthompsarun_setup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
1064203134Sthompsa{
1065203134Sthompsa	struct run_tx_data *data;
1066203134Sthompsa
1067203134Sthompsa	memset(pq, 0, sizeof(*pq));
1068203134Sthompsa
1069203134Sthompsa	STAILQ_INIT(&pq->tx_qh);
1070203134Sthompsa	STAILQ_INIT(&pq->tx_fh);
1071203134Sthompsa
1072203134Sthompsa	for (data = &pq->tx_data[0];
1073203134Sthompsa	    data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) {
1074203134Sthompsa		data->sc = sc;
1075203134Sthompsa		STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
1076203134Sthompsa	}
1077203134Sthompsa	pq->tx_nfree = RUN_TX_RING_COUNT;
1078203134Sthompsa}
1079203134Sthompsa
1080203134Sthompsastatic void
1081203134Sthompsarun_unsetup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
1082203134Sthompsa{
1083203134Sthompsa	struct run_tx_data *data;
1084203134Sthompsa
1085203134Sthompsa	/* make sure any subsequent use of the queues will fail */
1086203134Sthompsa	pq->tx_nfree = 0;
1087203134Sthompsa	STAILQ_INIT(&pq->tx_fh);
1088203134Sthompsa	STAILQ_INIT(&pq->tx_qh);
1089203134Sthompsa
1090203134Sthompsa	/* free up all node references and mbufs */
1091203134Sthompsa	for (data = &pq->tx_data[0];
1092209917Sthompsa	    data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) {
1093203134Sthompsa		if (data->m != NULL) {
1094203134Sthompsa			m_freem(data->m);
1095203134Sthompsa			data->m = NULL;
1096203134Sthompsa		}
1097203134Sthompsa		if (data->ni != NULL) {
1098203134Sthompsa			ieee80211_free_node(data->ni);
1099203134Sthompsa			data->ni = NULL;
1100203134Sthompsa		}
1101203134Sthompsa	}
1102203134Sthompsa}
1103203134Sthompsa
1104220235Skevlostatic int
1105203134Sthompsarun_load_microcode(struct run_softc *sc)
1106203134Sthompsa{
1107203134Sthompsa	usb_device_request_t req;
1108203137Sthompsa	const struct firmware *fw;
1109203134Sthompsa	const u_char *base;
1110203134Sthompsa	uint32_t tmp;
1111203134Sthompsa	int ntries, error;
1112203134Sthompsa	const uint64_t *temp;
1113203134Sthompsa	uint64_t bytes;
1114203134Sthompsa
1115205042Sthompsa	RUN_UNLOCK(sc);
1116203137Sthompsa	fw = firmware_get("runfw");
1117205042Sthompsa	RUN_LOCK(sc);
1118209917Sthompsa	if (fw == NULL) {
1119203138Sthompsa		device_printf(sc->sc_dev,
1120203138Sthompsa		    "failed loadfirmware of file %s\n", "runfw");
1121203134Sthompsa		return ENOENT;
1122203134Sthompsa	}
1123203134Sthompsa
1124203137Sthompsa	if (fw->datasize != 8192) {
1125203138Sthompsa		device_printf(sc->sc_dev,
1126203138Sthompsa		    "invalid firmware size (should be 8KB)\n");
1127203137Sthompsa		error = EINVAL;
1128203137Sthompsa		goto fail;
1129203134Sthompsa	}
1130203134Sthompsa
1131203134Sthompsa	/*
1132203134Sthompsa	 * RT3071/RT3072 use a different firmware
1133203134Sthompsa	 * run-rt2870 (8KB) contains both,
1134203134Sthompsa	 * first half (4KB) is for rt2870,
1135203134Sthompsa	 * last half is for rt3071.
1136203134Sthompsa	 */
1137203137Sthompsa	base = fw->data;
1138205042Sthompsa	if ((sc->mac_ver) != 0x2860 &&
1139205042Sthompsa	    (sc->mac_ver) != 0x2872 &&
1140209917Sthompsa	    (sc->mac_ver) != 0x3070) {
1141203134Sthompsa		base += 4096;
1142205042Sthompsa	}
1143203134Sthompsa
1144203134Sthompsa	/* cheap sanity check */
1145203137Sthompsa	temp = fw->data;
1146203134Sthompsa	bytes = *temp;
1147257712Shselasky	if (bytes != be64toh(0xffffff0210280210ULL)) {
1148203138Sthompsa		device_printf(sc->sc_dev, "firmware checksum failed\n");
1149203137Sthompsa		error = EINVAL;
1150203137Sthompsa		goto fail;
1151203137Sthompsa	}
1152203134Sthompsa
1153203134Sthompsa	/* write microcode image */
1154262465Skevlo	if (sc->sc_flags & RUN_FLAG_FWLOAD_NEEDED) {
1155260219Skevlo		run_write_region_1(sc, RT2870_FW_BASE, base, 4096);
1156260219Skevlo		run_write(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff);
1157260219Skevlo		run_write(sc, RT2860_H2M_MAILBOX_STATUS, 0xffffffff);
1158260219Skevlo	}
1159203134Sthompsa
1160203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1161203134Sthompsa	req.bRequest = RT2870_RESET;
1162203134Sthompsa	USETW(req.wValue, 8);
1163203134Sthompsa	USETW(req.wIndex, 0);
1164203134Sthompsa	USETW(req.wLength, 0);
1165220235Skevlo	if ((error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL))
1166220235Skevlo	    != 0) {
1167203138Sthompsa		device_printf(sc->sc_dev, "firmware reset failed\n");
1168203137Sthompsa		goto fail;
1169203137Sthompsa	}
1170203134Sthompsa
1171203134Sthompsa	run_delay(sc, 10);
1172203134Sthompsa
1173260219Skevlo	run_write(sc, RT2860_H2M_BBPAGENT, 0);
1174203134Sthompsa	run_write(sc, RT2860_H2M_MAILBOX, 0);
1175260219Skevlo	run_write(sc, RT2860_H2M_INTSRC, 0);
1176205042Sthompsa	if ((error = run_mcu_cmd(sc, RT2860_MCU_CMD_RFRESET, 0)) != 0)
1177203137Sthompsa		goto fail;
1178203134Sthompsa
1179203134Sthompsa	/* wait until microcontroller is ready */
1180203134Sthompsa	for (ntries = 0; ntries < 1000; ntries++) {
1181260219Skevlo		if ((error = run_read(sc, RT2860_SYS_CTRL, &tmp)) != 0)
1182203137Sthompsa			goto fail;
1183203134Sthompsa		if (tmp & RT2860_MCU_READY)
1184203134Sthompsa			break;
1185203134Sthompsa		run_delay(sc, 10);
1186203134Sthompsa	}
1187203134Sthompsa	if (ntries == 1000) {
1188203138Sthompsa		device_printf(sc->sc_dev,
1189203138Sthompsa		    "timeout waiting for MCU to initialize\n");
1190203137Sthompsa		error = ETIMEDOUT;
1191203137Sthompsa		goto fail;
1192203134Sthompsa	}
1193233283Sbschmidt	device_printf(sc->sc_dev, "firmware %s ver. %u.%u loaded\n",
1194233283Sbschmidt	    (base == fw->data) ? "RT2870" : "RT3071",
1195233283Sbschmidt	    *(base + 4092), *(base + 4093));
1196203134Sthompsa
1197203137Sthompsafail:
1198203137Sthompsa	firmware_put(fw, FIRMWARE_UNLOAD);
1199203137Sthompsa	return (error);
1200203134Sthompsa}
1201203134Sthompsa
1202258641Shselaskystatic int
1203203134Sthompsarun_reset(struct run_softc *sc)
1204203134Sthompsa{
1205203134Sthompsa	usb_device_request_t req;
1206203134Sthompsa
1207203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1208203134Sthompsa	req.bRequest = RT2870_RESET;
1209203134Sthompsa	USETW(req.wValue, 1);
1210203134Sthompsa	USETW(req.wIndex, 0);
1211203134Sthompsa	USETW(req.wLength, 0);
1212209917Sthompsa	return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL));
1213203134Sthompsa}
1214203134Sthompsa
1215203134Sthompsastatic usb_error_t
1216203134Sthompsarun_do_request(struct run_softc *sc,
1217203134Sthompsa    struct usb_device_request *req, void *data)
1218203134Sthompsa{
1219203134Sthompsa	usb_error_t err;
1220203134Sthompsa	int ntries = 10;
1221203134Sthompsa
1222203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
1223203134Sthompsa
1224203134Sthompsa	while (ntries--) {
1225203134Sthompsa		err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx,
1226203134Sthompsa		    req, data, 0, NULL, 250 /* ms */);
1227203134Sthompsa		if (err == 0)
1228203134Sthompsa			break;
1229203134Sthompsa		DPRINTFN(1, "Control request failed, %s (retrying)\n",
1230203134Sthompsa		    usbd_errstr(err));
1231203134Sthompsa		run_delay(sc, 10);
1232203134Sthompsa	}
1233203134Sthompsa	return (err);
1234203134Sthompsa}
1235203134Sthompsa
1236203134Sthompsastatic int
1237203134Sthompsarun_read(struct run_softc *sc, uint16_t reg, uint32_t *val)
1238203134Sthompsa{
1239203134Sthompsa	uint32_t tmp;
1240203134Sthompsa	int error;
1241203134Sthompsa
1242203134Sthompsa	error = run_read_region_1(sc, reg, (uint8_t *)&tmp, sizeof tmp);
1243203134Sthompsa	if (error == 0)
1244203134Sthompsa		*val = le32toh(tmp);
1245203134Sthompsa	else
1246203134Sthompsa		*val = 0xffffffff;
1247209917Sthompsa	return (error);
1248203134Sthompsa}
1249203134Sthompsa
1250203134Sthompsastatic int
1251203134Sthompsarun_read_region_1(struct run_softc *sc, uint16_t reg, uint8_t *buf, int len)
1252203134Sthompsa{
1253203134Sthompsa	usb_device_request_t req;
1254203134Sthompsa
1255203134Sthompsa	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1256203134Sthompsa	req.bRequest = RT2870_READ_REGION_1;
1257203134Sthompsa	USETW(req.wValue, 0);
1258203134Sthompsa	USETW(req.wIndex, reg);
1259203134Sthompsa	USETW(req.wLength, len);
1260203134Sthompsa
1261209917Sthompsa	return (run_do_request(sc, &req, buf));
1262203134Sthompsa}
1263203134Sthompsa
1264203134Sthompsastatic int
1265203134Sthompsarun_write_2(struct run_softc *sc, uint16_t reg, uint16_t val)
1266203134Sthompsa{
1267203134Sthompsa	usb_device_request_t req;
1268203134Sthompsa
1269203134Sthompsa	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1270203134Sthompsa	req.bRequest = RT2870_WRITE_2;
1271203134Sthompsa	USETW(req.wValue, val);
1272203134Sthompsa	USETW(req.wIndex, reg);
1273203134Sthompsa	USETW(req.wLength, 0);
1274203134Sthompsa
1275209917Sthompsa	return (run_do_request(sc, &req, NULL));
1276203134Sthompsa}
1277203134Sthompsa
1278203134Sthompsastatic int
1279203134Sthompsarun_write(struct run_softc *sc, uint16_t reg, uint32_t val)
1280203134Sthompsa{
1281203134Sthompsa	int error;
1282203134Sthompsa
1283203134Sthompsa	if ((error = run_write_2(sc, reg, val & 0xffff)) == 0)
1284203134Sthompsa		error = run_write_2(sc, reg + 2, val >> 16);
1285209917Sthompsa	return (error);
1286203134Sthompsa}
1287203134Sthompsa
1288203134Sthompsastatic int
1289203134Sthompsarun_write_region_1(struct run_softc *sc, uint16_t reg, const uint8_t *buf,
1290203134Sthompsa    int len)
1291203134Sthompsa{
1292203134Sthompsa#if 1
1293203134Sthompsa	int i, error = 0;
1294203134Sthompsa	/*
1295203134Sthompsa	 * NB: the WRITE_REGION_1 command is not stable on RT2860.
1296203134Sthompsa	 * We thus issue multiple WRITE_2 commands instead.
1297203134Sthompsa	 */
1298203134Sthompsa	KASSERT((len & 1) == 0, ("run_write_region_1: Data too long.\n"));
1299203134Sthompsa	for (i = 0; i < len && error == 0; i += 2)
1300203134Sthompsa		error = run_write_2(sc, reg + i, buf[i] | buf[i + 1] << 8);
1301209917Sthompsa	return (error);
1302203134Sthompsa#else
1303203134Sthompsa	usb_device_request_t req;
1304257958Skevlo	int error = 0;
1305203134Sthompsa
1306257958Skevlo	/*
1307257958Skevlo	 * NOTE: It appears the WRITE_REGION_1 command cannot be
1308257958Skevlo	 * passed a huge amount of data, which will crash the
1309257958Skevlo	 * firmware. Limit amount of data passed to 64-bytes at a
1310257958Skevlo	 * time.
1311257958Skevlo	 */
1312257958Skevlo	while (len > 0) {
1313257958Skevlo		int delta = 64;
1314257958Skevlo		if (delta > len)
1315257958Skevlo			delta = len;
1316257958Skevlo
1317257958Skevlo		req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1318257958Skevlo		req.bRequest = RT2870_WRITE_REGION_1;
1319257958Skevlo		USETW(req.wValue, 0);
1320257958Skevlo		USETW(req.wIndex, reg);
1321257958Skevlo		USETW(req.wLength, delta);
1322257958Skevlo		error = run_do_request(sc, &req, __DECONST(uint8_t *, buf));
1323257958Skevlo		if (error != 0)
1324257958Skevlo			break;
1325257958Skevlo		reg += delta;
1326257958Skevlo		buf += delta;
1327257958Skevlo		len -= delta;
1328257958Skevlo	}
1329257958Skevlo	return (error);
1330203134Sthompsa#endif
1331203134Sthompsa}
1332203134Sthompsa
1333203134Sthompsastatic int
1334203134Sthompsarun_set_region_4(struct run_softc *sc, uint16_t reg, uint32_t val, int len)
1335203134Sthompsa{
1336203134Sthompsa	int i, error = 0;
1337203134Sthompsa
1338203134Sthompsa	KASSERT((len & 3) == 0, ("run_set_region_4: Invalid data length.\n"));
1339203134Sthompsa	for (i = 0; i < len && error == 0; i += 4)
1340203134Sthompsa		error = run_write(sc, reg + i, val);
1341209917Sthompsa	return (error);
1342203134Sthompsa}
1343203134Sthompsa
1344203134Sthompsastatic int
1345259544Skevlorun_efuse_read(struct run_softc *sc, uint16_t addr, uint16_t *val, int count)
1346203134Sthompsa{
1347203134Sthompsa	uint32_t tmp;
1348203134Sthompsa	uint16_t reg;
1349203134Sthompsa	int error, ntries;
1350203134Sthompsa
1351203134Sthompsa	if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
1352209917Sthompsa		return (error);
1353203134Sthompsa
1354261076Shselasky	if (count == 2)
1355261076Shselasky		addr *= 2;
1356203134Sthompsa	/*-
1357203134Sthompsa	 * Read one 16-byte block into registers EFUSE_DATA[0-3]:
1358203134Sthompsa	 * DATA0: F E D C
1359203134Sthompsa	 * DATA1: B A 9 8
1360203134Sthompsa	 * DATA2: 7 6 5 4
1361203134Sthompsa	 * DATA3: 3 2 1 0
1362203134Sthompsa	 */
1363203134Sthompsa	tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK);
1364203134Sthompsa	tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK;
1365203134Sthompsa	run_write(sc, RT3070_EFUSE_CTRL, tmp);
1366203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1367203134Sthompsa		if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
1368209917Sthompsa			return (error);
1369203134Sthompsa		if (!(tmp & RT3070_EFSROM_KICK))
1370203134Sthompsa			break;
1371203134Sthompsa		run_delay(sc, 2);
1372203134Sthompsa	}
1373203134Sthompsa	if (ntries == 100)
1374209917Sthompsa		return (ETIMEDOUT);
1375203134Sthompsa
1376261076Shselasky	if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK) {
1377261076Shselasky		*val = 0xffff;	/* address not found */
1378209917Sthompsa		return (0);
1379261076Shselasky	}
1380203134Sthompsa	/* determine to which 32-bit register our 16-bit word belongs */
1381203134Sthompsa	reg = RT3070_EFUSE_DATA3 - (addr & 0xc);
1382203134Sthompsa	if ((error = run_read(sc, reg, &tmp)) != 0)
1383209917Sthompsa		return (error);
1384203134Sthompsa
1385261118Skevlo	tmp >>= (8 * (addr & 0x3));
1386261118Skevlo	*val = (addr & 1) ? tmp >> 16 : tmp & 0xffff;
1387261118Skevlo
1388209917Sthompsa	return (0);
1389203134Sthompsa}
1390203134Sthompsa
1391261124Skevlo/* Read 16-bit from eFUSE ROM for RT3xxx. */
1392203134Sthompsastatic int
1393259544Skevlorun_efuse_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
1394259544Skevlo{
1395259544Skevlo	return (run_efuse_read(sc, addr, val, 2));
1396259544Skevlo}
1397259544Skevlo
1398259544Skevlostatic int
1399203134Sthompsarun_eeprom_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
1400203134Sthompsa{
1401203134Sthompsa	usb_device_request_t req;
1402203134Sthompsa	uint16_t tmp;
1403203134Sthompsa	int error;
1404203134Sthompsa
1405203134Sthompsa	addr *= 2;
1406203134Sthompsa	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1407203134Sthompsa	req.bRequest = RT2870_EEPROM_READ;
1408203134Sthompsa	USETW(req.wValue, 0);
1409203134Sthompsa	USETW(req.wIndex, addr);
1410260219Skevlo	USETW(req.wLength, sizeof(tmp));
1411203134Sthompsa
1412203134Sthompsa	error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, &tmp);
1413203134Sthompsa	if (error == 0)
1414203134Sthompsa		*val = le16toh(tmp);
1415203134Sthompsa	else
1416203134Sthompsa		*val = 0xffff;
1417209917Sthompsa	return (error);
1418203134Sthompsa}
1419203134Sthompsa
1420203134Sthompsastatic __inline int
1421203134Sthompsarun_srom_read(struct run_softc *sc, uint16_t addr, uint16_t *val)
1422203134Sthompsa{
1423203134Sthompsa	/* either eFUSE ROM or EEPROM */
1424203134Sthompsa	return sc->sc_srom_read(sc, addr, val);
1425203134Sthompsa}
1426203134Sthompsa
1427203134Sthompsastatic int
1428258733Skevlorun_rt2870_rf_write(struct run_softc *sc, uint32_t val)
1429203134Sthompsa{
1430203134Sthompsa	uint32_t tmp;
1431203134Sthompsa	int error, ntries;
1432203134Sthompsa
1433203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1434203134Sthompsa		if ((error = run_read(sc, RT2860_RF_CSR_CFG0, &tmp)) != 0)
1435209917Sthompsa			return (error);
1436203134Sthompsa		if (!(tmp & RT2860_RF_REG_CTRL))
1437203134Sthompsa			break;
1438203134Sthompsa	}
1439203134Sthompsa	if (ntries == 10)
1440209917Sthompsa		return (ETIMEDOUT);
1441203134Sthompsa
1442258732Skevlo	return (run_write(sc, RT2860_RF_CSR_CFG0, val));
1443203134Sthompsa}
1444203134Sthompsa
1445203134Sthompsastatic int
1446203134Sthompsarun_rt3070_rf_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
1447203134Sthompsa{
1448203134Sthompsa	uint32_t tmp;
1449203134Sthompsa	int error, ntries;
1450203134Sthompsa
1451203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1452203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1453209917Sthompsa			return (error);
1454203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1455203134Sthompsa			break;
1456203134Sthompsa	}
1457203134Sthompsa	if (ntries == 100)
1458209917Sthompsa		return (ETIMEDOUT);
1459203134Sthompsa
1460203134Sthompsa	tmp = RT3070_RF_KICK | reg << 8;
1461203134Sthompsa	if ((error = run_write(sc, RT3070_RF_CSR_CFG, tmp)) != 0)
1462209917Sthompsa		return (error);
1463203134Sthompsa
1464203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1465203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1466209917Sthompsa			return (error);
1467203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1468203134Sthompsa			break;
1469203134Sthompsa	}
1470203134Sthompsa	if (ntries == 100)
1471209917Sthompsa		return (ETIMEDOUT);
1472203134Sthompsa
1473203134Sthompsa	*val = tmp & 0xff;
1474209917Sthompsa	return (0);
1475203134Sthompsa}
1476203134Sthompsa
1477203134Sthompsastatic int
1478203134Sthompsarun_rt3070_rf_write(struct run_softc *sc, uint8_t reg, uint8_t val)
1479203134Sthompsa{
1480203134Sthompsa	uint32_t tmp;
1481203134Sthompsa	int error, ntries;
1482203134Sthompsa
1483203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1484203134Sthompsa		if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
1485209917Sthompsa			return (error);
1486203134Sthompsa		if (!(tmp & RT3070_RF_KICK))
1487203134Sthompsa			break;
1488203134Sthompsa	}
1489203134Sthompsa	if (ntries == 10)
1490209917Sthompsa		return (ETIMEDOUT);
1491203134Sthompsa
1492203134Sthompsa	tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val;
1493209917Sthompsa	return (run_write(sc, RT3070_RF_CSR_CFG, tmp));
1494203134Sthompsa}
1495203134Sthompsa
1496203134Sthompsastatic int
1497203134Sthompsarun_bbp_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
1498203134Sthompsa{
1499203134Sthompsa	uint32_t tmp;
1500203134Sthompsa	int ntries, error;
1501203134Sthompsa
1502203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1503203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1504209917Sthompsa			return (error);
1505203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1506203134Sthompsa			break;
1507203134Sthompsa	}
1508203134Sthompsa	if (ntries == 10)
1509209917Sthompsa		return (ETIMEDOUT);
1510203134Sthompsa
1511203134Sthompsa	tmp = RT2860_BBP_CSR_READ | RT2860_BBP_CSR_KICK | reg << 8;
1512203134Sthompsa	if ((error = run_write(sc, RT2860_BBP_CSR_CFG, tmp)) != 0)
1513209917Sthompsa		return (error);
1514203134Sthompsa
1515203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1516203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1517209917Sthompsa			return (error);
1518203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1519203134Sthompsa			break;
1520203134Sthompsa	}
1521203134Sthompsa	if (ntries == 10)
1522209917Sthompsa		return (ETIMEDOUT);
1523203134Sthompsa
1524203134Sthompsa	*val = tmp & 0xff;
1525209917Sthompsa	return (0);
1526203134Sthompsa}
1527203134Sthompsa
1528203134Sthompsastatic int
1529203134Sthompsarun_bbp_write(struct run_softc *sc, uint8_t reg, uint8_t val)
1530203134Sthompsa{
1531203134Sthompsa	uint32_t tmp;
1532203134Sthompsa	int ntries, error;
1533203134Sthompsa
1534203134Sthompsa	for (ntries = 0; ntries < 10; ntries++) {
1535203134Sthompsa		if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
1536209917Sthompsa			return (error);
1537203134Sthompsa		if (!(tmp & RT2860_BBP_CSR_KICK))
1538203134Sthompsa			break;
1539203134Sthompsa	}
1540203134Sthompsa	if (ntries == 10)
1541209917Sthompsa		return (ETIMEDOUT);
1542203134Sthompsa
1543203134Sthompsa	tmp = RT2860_BBP_CSR_KICK | reg << 8 | val;
1544209917Sthompsa	return (run_write(sc, RT2860_BBP_CSR_CFG, tmp));
1545203134Sthompsa}
1546203134Sthompsa
1547203134Sthompsa/*
1548203134Sthompsa * Send a command to the 8051 microcontroller unit.
1549203134Sthompsa */
1550203134Sthompsastatic int
1551203134Sthompsarun_mcu_cmd(struct run_softc *sc, uint8_t cmd, uint16_t arg)
1552203134Sthompsa{
1553203134Sthompsa	uint32_t tmp;
1554203134Sthompsa	int error, ntries;
1555203134Sthompsa
1556203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
1557203134Sthompsa		if ((error = run_read(sc, RT2860_H2M_MAILBOX, &tmp)) != 0)
1558203134Sthompsa			return error;
1559203134Sthompsa		if (!(tmp & RT2860_H2M_BUSY))
1560203134Sthompsa			break;
1561203134Sthompsa	}
1562203134Sthompsa	if (ntries == 100)
1563203134Sthompsa		return ETIMEDOUT;
1564203134Sthompsa
1565203134Sthompsa	tmp = RT2860_H2M_BUSY | RT2860_TOKEN_NO_INTR << 16 | arg;
1566203134Sthompsa	if ((error = run_write(sc, RT2860_H2M_MAILBOX, tmp)) == 0)
1567203134Sthompsa		error = run_write(sc, RT2860_HOST_CMD, cmd);
1568209917Sthompsa	return (error);
1569203134Sthompsa}
1570203134Sthompsa
1571203134Sthompsa/*
1572203134Sthompsa * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word.
1573203134Sthompsa * Used to adjust per-rate Tx power registers.
1574203134Sthompsa */
1575203134Sthompsastatic __inline uint32_t
1576203134Sthompsab4inc(uint32_t b32, int8_t delta)
1577203134Sthompsa{
1578203134Sthompsa	int8_t i, b4;
1579203134Sthompsa
1580203134Sthompsa	for (i = 0; i < 8; i++) {
1581203134Sthompsa		b4 = b32 & 0xf;
1582203134Sthompsa		b4 += delta;
1583203134Sthompsa		if (b4 < 0)
1584203134Sthompsa			b4 = 0;
1585203134Sthompsa		else if (b4 > 0xf)
1586203134Sthompsa			b4 = 0xf;
1587203134Sthompsa		b32 = b32 >> 4 | b4 << 28;
1588203134Sthompsa	}
1589209917Sthompsa	return (b32);
1590203134Sthompsa}
1591203134Sthompsa
1592203134Sthompsastatic const char *
1593257955Skevlorun_get_rf(uint16_t rev)
1594203134Sthompsa{
1595203134Sthompsa	switch (rev) {
1596203134Sthompsa	case RT2860_RF_2820:	return "RT2820";
1597203134Sthompsa	case RT2860_RF_2850:	return "RT2850";
1598203134Sthompsa	case RT2860_RF_2720:	return "RT2720";
1599203134Sthompsa	case RT2860_RF_2750:	return "RT2750";
1600203134Sthompsa	case RT3070_RF_3020:	return "RT3020";
1601203134Sthompsa	case RT3070_RF_2020:	return "RT2020";
1602203134Sthompsa	case RT3070_RF_3021:	return "RT3021";
1603203134Sthompsa	case RT3070_RF_3022:	return "RT3022";
1604203134Sthompsa	case RT3070_RF_3052:	return "RT3052";
1605260219Skevlo	case RT3593_RF_3053:	return "RT3053";
1606259032Skevlo	case RT5592_RF_5592:	return "RT5592";
1607257955Skevlo	case RT5390_RF_5370:	return "RT5370";
1608257955Skevlo	case RT5390_RF_5372:	return "RT5372";
1609203134Sthompsa	}
1610209917Sthompsa	return ("unknown");
1611203134Sthompsa}
1612203134Sthompsa
1613260219Skevlostatic void
1614260219Skevlorun_rt3593_get_txpower(struct run_softc *sc)
1615260219Skevlo{
1616260219Skevlo	uint16_t addr, val;
1617260219Skevlo	int i;
1618260219Skevlo
1619260219Skevlo	/* Read power settings for 2GHz channels. */
1620260219Skevlo	for (i = 0; i < 14; i += 2) {
1621260219Skevlo		addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE1 :
1622260219Skevlo		    RT2860_EEPROM_PWR2GHZ_BASE1;
1623260219Skevlo		run_srom_read(sc, addr + i / 2, &val);
1624260219Skevlo		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
1625260219Skevlo		sc->txpow1[i + 1] = (int8_t)(val >> 8);
1626260219Skevlo
1627260219Skevlo		addr = (sc->ntxchains == 3) ? RT3593_EEPROM_PWR2GHZ_BASE2 :
1628260219Skevlo		    RT2860_EEPROM_PWR2GHZ_BASE2;
1629260219Skevlo		run_srom_read(sc, addr + i / 2, &val);
1630260219Skevlo		sc->txpow2[i + 0] = (int8_t)(val & 0xff);
1631260219Skevlo		sc->txpow2[i + 1] = (int8_t)(val >> 8);
1632260219Skevlo
1633260219Skevlo		if (sc->ntxchains == 3) {
1634260219Skevlo			run_srom_read(sc, RT3593_EEPROM_PWR2GHZ_BASE3 + i / 2,
1635260219Skevlo			    &val);
1636260219Skevlo			sc->txpow3[i + 0] = (int8_t)(val & 0xff);
1637260219Skevlo			sc->txpow3[i + 1] = (int8_t)(val >> 8);
1638260219Skevlo		}
1639260219Skevlo	}
1640260219Skevlo	/* Fix broken Tx power entries. */
1641260219Skevlo	for (i = 0; i < 14; i++) {
1642260542Skevlo		if (sc->txpow1[i] > 31)
1643260219Skevlo			sc->txpow1[i] = 5;
1644260542Skevlo		if (sc->txpow2[i] > 31)
1645260219Skevlo			sc->txpow2[i] = 5;
1646260219Skevlo		if (sc->ntxchains == 3) {
1647260542Skevlo			if (sc->txpow3[i] > 31)
1648260219Skevlo				sc->txpow3[i] = 5;
1649260219Skevlo		}
1650260219Skevlo	}
1651260219Skevlo	/* Read power settings for 5GHz channels. */
1652260219Skevlo	for (i = 0; i < 40; i += 2) {
1653260219Skevlo		run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
1654260219Skevlo		sc->txpow1[i + 14] = (int8_t)(val & 0xff);
1655260219Skevlo		sc->txpow1[i + 15] = (int8_t)(val >> 8);
1656260219Skevlo
1657260219Skevlo		run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
1658260219Skevlo		sc->txpow2[i + 14] = (int8_t)(val & 0xff);
1659260219Skevlo		sc->txpow2[i + 15] = (int8_t)(val >> 8);
1660260219Skevlo
1661260219Skevlo		if (sc->ntxchains == 3) {
1662260219Skevlo			run_srom_read(sc, RT3593_EEPROM_PWR5GHZ_BASE3 + i / 2,
1663260219Skevlo			    &val);
1664260219Skevlo			sc->txpow3[i + 14] = (int8_t)(val & 0xff);
1665260219Skevlo			sc->txpow3[i + 15] = (int8_t)(val >> 8);
1666260219Skevlo		}
1667260219Skevlo	}
1668260219Skevlo}
1669260219Skevlo
1670260219Skevlostatic void
1671260219Skevlorun_get_txpower(struct run_softc *sc)
1672260219Skevlo{
1673260219Skevlo	uint16_t val;
1674260219Skevlo	int i;
1675260219Skevlo
1676260219Skevlo	/* Read power settings for 2GHz channels. */
1677260219Skevlo	for (i = 0; i < 14; i += 2) {
1678260219Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE1 + i / 2, &val);
1679260219Skevlo		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
1680260219Skevlo		sc->txpow1[i + 1] = (int8_t)(val >> 8);
1681260219Skevlo
1682260219Skevlo		if (sc->mac_ver != 0x5390) {
1683260219Skevlo			run_srom_read(sc,
1684260219Skevlo			    RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2, &val);
1685260219Skevlo			sc->txpow2[i + 0] = (int8_t)(val & 0xff);
1686260219Skevlo			sc->txpow2[i + 1] = (int8_t)(val >> 8);
1687260219Skevlo		}
1688260219Skevlo	}
1689260219Skevlo	/* Fix broken Tx power entries. */
1690260219Skevlo	for (i = 0; i < 14; i++) {
1691260219Skevlo		if (sc->mac_ver >= 0x5390) {
1692288666Skevlo			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 39)
1693260219Skevlo				sc->txpow1[i] = 5;
1694260219Skevlo		} else {
1695260219Skevlo			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31)
1696260219Skevlo				sc->txpow1[i] = 5;
1697260219Skevlo		}
1698260219Skevlo		if (sc->mac_ver > 0x5390) {
1699288666Skevlo			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 39)
1700260219Skevlo				sc->txpow2[i] = 5;
1701260219Skevlo		} else if (sc->mac_ver < 0x5390) {
1702260219Skevlo			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31)
1703260219Skevlo				sc->txpow2[i] = 5;
1704260219Skevlo		}
1705260219Skevlo		DPRINTF("chan %d: power1=%d, power2=%d\n",
1706260219Skevlo		    rt2860_rf2850[i].chan, sc->txpow1[i], sc->txpow2[i]);
1707260219Skevlo	}
1708260219Skevlo	/* Read power settings for 5GHz channels. */
1709260219Skevlo	for (i = 0; i < 40; i += 2) {
1710260219Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
1711260219Skevlo		sc->txpow1[i + 14] = (int8_t)(val & 0xff);
1712260219Skevlo		sc->txpow1[i + 15] = (int8_t)(val >> 8);
1713260219Skevlo
1714260219Skevlo		run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
1715260219Skevlo		sc->txpow2[i + 14] = (int8_t)(val & 0xff);
1716260219Skevlo		sc->txpow2[i + 15] = (int8_t)(val >> 8);
1717260219Skevlo	}
1718260219Skevlo	/* Fix broken Tx power entries. */
1719260219Skevlo	for (i = 0; i < 40; i++ ) {
1720260219Skevlo		if (sc->mac_ver != 0x5592) {
1721260219Skevlo			if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15)
1722260219Skevlo				sc->txpow1[14 + i] = 5;
1723260219Skevlo			if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15)
1724260219Skevlo				sc->txpow2[14 + i] = 5;
1725260219Skevlo		}
1726260219Skevlo		DPRINTF("chan %d: power1=%d, power2=%d\n",
1727260219Skevlo		    rt2860_rf2850[14 + i].chan, sc->txpow1[14 + i],
1728260219Skevlo		    sc->txpow2[14 + i]);
1729260219Skevlo	}
1730260219Skevlo}
1731260219Skevlo
1732258641Shselaskystatic int
1733203134Sthompsarun_read_eeprom(struct run_softc *sc)
1734203134Sthompsa{
1735287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
1736203134Sthompsa	int8_t delta_2ghz, delta_5ghz;
1737203134Sthompsa	uint32_t tmp;
1738203134Sthompsa	uint16_t val;
1739203134Sthompsa	int ridx, ant, i;
1740203134Sthompsa
1741203134Sthompsa	/* check whether the ROM is eFUSE ROM or EEPROM */
1742203134Sthompsa	sc->sc_srom_read = run_eeprom_read_2;
1743205042Sthompsa	if (sc->mac_ver >= 0x3070) {
1744203134Sthompsa		run_read(sc, RT3070_EFUSE_CTRL, &tmp);
1745203134Sthompsa		DPRINTF("EFUSE_CTRL=0x%08x\n", tmp);
1746261118Skevlo		if ((tmp & RT3070_SEL_EFUSE) || sc->mac_ver == 0x3593)
1747203134Sthompsa			sc->sc_srom_read = run_efuse_read_2;
1748203134Sthompsa	}
1749203134Sthompsa
1750203134Sthompsa	/* read ROM version */
1751203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_VERSION, &val);
1752287853Skevlo	DPRINTF("EEPROM rev=%d, FAE=%d\n", val >> 8, val & 0xff);
1753203134Sthompsa
1754203134Sthompsa	/* read MAC address */
1755203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC01, &val);
1756287197Sglebius	ic->ic_macaddr[0] = val & 0xff;
1757287197Sglebius	ic->ic_macaddr[1] = val >> 8;
1758203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC23, &val);
1759287197Sglebius	ic->ic_macaddr[2] = val & 0xff;
1760287197Sglebius	ic->ic_macaddr[3] = val >> 8;
1761203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_MAC45, &val);
1762287197Sglebius	ic->ic_macaddr[4] = val & 0xff;
1763287197Sglebius	ic->ic_macaddr[5] = val >> 8;
1764203134Sthompsa
1765260219Skevlo	if (sc->mac_ver < 0x3593) {
1766257955Skevlo		/* read vender BBP settings */
1767205042Sthompsa		for (i = 0; i < 10; i++) {
1768257955Skevlo			run_srom_read(sc, RT2860_EEPROM_BBP_BASE + i, &val);
1769257955Skevlo			sc->bbp[i].val = val & 0xff;
1770257955Skevlo			sc->bbp[i].reg = val >> 8;
1771257955Skevlo			DPRINTF("BBP%d=0x%02x\n", sc->bbp[i].reg,
1772257955Skevlo			    sc->bbp[i].val);
1773205042Sthompsa		}
1774257955Skevlo		if (sc->mac_ver >= 0x3071) {
1775257955Skevlo			/* read vendor RF settings */
1776257955Skevlo			for (i = 0; i < 10; i++) {
1777257955Skevlo				run_srom_read(sc, RT3071_EEPROM_RF_BASE + i,
1778257955Skevlo				   &val);
1779257955Skevlo				sc->rf[i].val = val & 0xff;
1780257955Skevlo				sc->rf[i].reg = val >> 8;
1781257955Skevlo				DPRINTF("RF%d=0x%02x\n", sc->rf[i].reg,
1782257955Skevlo				    sc->rf[i].val);
1783257955Skevlo			}
1784257955Skevlo		}
1785205042Sthompsa	}
1786203134Sthompsa
1787203134Sthompsa	/* read RF frequency offset from EEPROM */
1788260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS :
1789260219Skevlo	    RT3593_EEPROM_FREQ, &val);
1790203134Sthompsa	sc->freq = ((val & 0xff) != 0xff) ? val & 0xff : 0;
1791203134Sthompsa	DPRINTF("EEPROM freq offset %d\n", sc->freq & 0xff);
1792203134Sthompsa
1793260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_FREQ_LEDS :
1794260219Skevlo	    RT3593_EEPROM_FREQ_LEDS, &val);
1795205042Sthompsa	if (val >> 8 != 0xff) {
1796203134Sthompsa		/* read LEDs operating mode */
1797205042Sthompsa		sc->leds = val >> 8;
1798260219Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED1 :
1799260219Skevlo		    RT3593_EEPROM_LED1, &sc->led[0]);
1800260219Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED2 :
1801260219Skevlo		    RT3593_EEPROM_LED2, &sc->led[1]);
1802260219Skevlo		run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LED3 :
1803260219Skevlo		    RT3593_EEPROM_LED3, &sc->led[2]);
1804203134Sthompsa	} else {
1805203134Sthompsa		/* broken EEPROM, use default settings */
1806203134Sthompsa		sc->leds = 0x01;
1807203134Sthompsa		sc->led[0] = 0x5555;
1808203134Sthompsa		sc->led[1] = 0x2221;
1809203134Sthompsa		sc->led[2] = 0x5627;	/* differs from RT2860 */
1810203134Sthompsa	}
1811203134Sthompsa	DPRINTF("EEPROM LED mode=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n",
1812203134Sthompsa	    sc->leds, sc->led[0], sc->led[1], sc->led[2]);
1813203134Sthompsa
1814203134Sthompsa	/* read RF information */
1815259032Skevlo	if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392)
1816257955Skevlo		run_srom_read(sc, 0x00, &val);
1817257955Skevlo	else
1818257955Skevlo		run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
1819257955Skevlo
1820203134Sthompsa	if (val == 0xffff) {
1821260219Skevlo		device_printf(sc->sc_dev,
1822260219Skevlo		    "invalid EEPROM antenna info, using default\n");
1823203134Sthompsa		DPRINTF("invalid EEPROM antenna info, using default\n");
1824205042Sthompsa		if (sc->mac_ver == 0x3572) {
1825205042Sthompsa			/* default to RF3052 2T2R */
1826205042Sthompsa			sc->rf_rev = RT3070_RF_3052;
1827205042Sthompsa			sc->ntxchains = 2;
1828205042Sthompsa			sc->nrxchains = 2;
1829205042Sthompsa		} else if (sc->mac_ver >= 0x3070) {
1830203134Sthompsa			/* default to RF3020 1T1R */
1831203134Sthompsa			sc->rf_rev = RT3070_RF_3020;
1832203134Sthompsa			sc->ntxchains = 1;
1833203134Sthompsa			sc->nrxchains = 1;
1834203134Sthompsa		} else {
1835203134Sthompsa			/* default to RF2820 1T2R */
1836203134Sthompsa			sc->rf_rev = RT2860_RF_2820;
1837203134Sthompsa			sc->ntxchains = 1;
1838203134Sthompsa			sc->nrxchains = 2;
1839203134Sthompsa		}
1840203134Sthompsa	} else {
1841259032Skevlo		if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392) {
1842257955Skevlo			sc->rf_rev = val;
1843257955Skevlo			run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
1844257955Skevlo		} else
1845257955Skevlo			sc->rf_rev = (val >> 8) & 0xf;
1846203134Sthompsa		sc->ntxchains = (val >> 4) & 0xf;
1847203134Sthompsa		sc->nrxchains = val & 0xf;
1848203134Sthompsa	}
1849257955Skevlo	DPRINTF("EEPROM RF rev=0x%04x chains=%dT%dR\n",
1850203134Sthompsa	    sc->rf_rev, sc->ntxchains, sc->nrxchains);
1851203134Sthompsa
1852208019Sthompsa	/* check if RF supports automatic Tx access gain control */
1853203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_CONFIG, &val);
1854203134Sthompsa	DPRINTF("EEPROM CFG 0x%04x\n", val);
1855205042Sthompsa	/* check if driver should patch the DAC issue */
1856205042Sthompsa	if ((val >> 8) != 0xff)
1857205042Sthompsa		sc->patch_dac = (val >> 15) & 1;
1858203134Sthompsa	if ((val & 0xff) != 0xff) {
1859203134Sthompsa		sc->ext_5ghz_lna = (val >> 3) & 1;
1860203134Sthompsa		sc->ext_2ghz_lna = (val >> 2) & 1;
1861205042Sthompsa		/* check if RF supports automatic Tx access gain control */
1862203134Sthompsa		sc->calib_2ghz = sc->calib_5ghz = (val >> 1) & 1;
1863205042Sthompsa		/* check if we have a hardware radio switch */
1864205042Sthompsa		sc->rfswitch = val & 1;
1865203134Sthompsa	}
1866203134Sthompsa
1867260219Skevlo	/* Read Tx power settings. */
1868260219Skevlo	if (sc->mac_ver == 0x3593)
1869260219Skevlo		run_rt3593_get_txpower(sc);
1870260219Skevlo	else
1871260219Skevlo		run_get_txpower(sc);
1872203134Sthompsa
1873203134Sthompsa	/* read Tx power compensation for each Tx rate */
1874203134Sthompsa	run_srom_read(sc, RT2860_EEPROM_DELTAPWR, &val);
1875203134Sthompsa	delta_2ghz = delta_5ghz = 0;
1876203134Sthompsa	if ((val & 0xff) != 0xff && (val & 0x80)) {
1877203134Sthompsa		delta_2ghz = val & 0xf;
1878203134Sthompsa		if (!(val & 0x40))	/* negative number */
1879203134Sthompsa			delta_2ghz = -delta_2ghz;
1880203134Sthompsa	}
1881203134Sthompsa	val >>= 8;
1882203134Sthompsa	if ((val & 0xff) != 0xff && (val & 0x80)) {
1883203134Sthompsa		delta_5ghz = val & 0xf;
1884203134Sthompsa		if (!(val & 0x40))	/* negative number */
1885203134Sthompsa			delta_5ghz = -delta_5ghz;
1886203134Sthompsa	}
1887203134Sthompsa	DPRINTF("power compensation=%d (2GHz), %d (5GHz)\n",
1888203134Sthompsa	    delta_2ghz, delta_5ghz);
1889203134Sthompsa
1890203134Sthompsa	for (ridx = 0; ridx < 5; ridx++) {
1891203134Sthompsa		uint32_t reg;
1892203134Sthompsa
1893208019Sthompsa		run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2, &val);
1894208019Sthompsa		reg = val;
1895208019Sthompsa		run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2 + 1, &val);
1896208019Sthompsa		reg |= (uint32_t)val << 16;
1897203134Sthompsa
1898203134Sthompsa		sc->txpow20mhz[ridx] = reg;
1899203134Sthompsa		sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz);
1900203134Sthompsa		sc->txpow40mhz_5ghz[ridx] = b4inc(reg, delta_5ghz);
1901203134Sthompsa
1902203134Sthompsa		DPRINTF("ridx %d: power 20MHz=0x%08x, 40MHz/2GHz=0x%08x, "
1903203134Sthompsa		    "40MHz/5GHz=0x%08x\n", ridx, sc->txpow20mhz[ridx],
1904203134Sthompsa		    sc->txpow40mhz_2ghz[ridx], sc->txpow40mhz_5ghz[ridx]);
1905203134Sthompsa	}
1906203134Sthompsa
1907260219Skevlo	/* Read RSSI offsets and LNA gains from EEPROM. */
1908260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_2GHZ :
1909260219Skevlo	    RT3593_EEPROM_RSSI1_2GHZ, &val);
1910203134Sthompsa	sc->rssi_2ghz[0] = val & 0xff;	/* Ant A */
1911203134Sthompsa	sc->rssi_2ghz[1] = val >> 8;	/* Ant B */
1912260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_2GHZ :
1913260219Skevlo	    RT3593_EEPROM_RSSI2_2GHZ, &val);
1914205042Sthompsa	if (sc->mac_ver >= 0x3070) {
1915260219Skevlo		if (sc->mac_ver == 0x3593) {
1916260219Skevlo			sc->txmixgain_2ghz = 0;
1917260219Skevlo			sc->rssi_2ghz[2] = val & 0xff;	/* Ant C */
1918260219Skevlo		} else {
1919260219Skevlo			/*
1920260219Skevlo			 * On RT3070 chips (limited to 2 Rx chains), this ROM
1921260219Skevlo			 * field contains the Tx mixer gain for the 2GHz band.
1922260219Skevlo			 */
1923260219Skevlo			if ((val & 0xff) != 0xff)
1924260219Skevlo				sc->txmixgain_2ghz = val & 0x7;
1925260219Skevlo		}
1926205042Sthompsa		DPRINTF("tx mixer gain=%u (2GHz)\n", sc->txmixgain_2ghz);
1927205042Sthompsa	} else
1928205042Sthompsa		sc->rssi_2ghz[2] = val & 0xff;	/* Ant C */
1929260219Skevlo	if (sc->mac_ver == 0x3593)
1930260219Skevlo		run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val);
1931203134Sthompsa	sc->lna[2] = val >> 8;		/* channel group 2 */
1932203134Sthompsa
1933260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI1_5GHZ :
1934260219Skevlo	    RT3593_EEPROM_RSSI1_5GHZ, &val);
1935203134Sthompsa	sc->rssi_5ghz[0] = val & 0xff;	/* Ant A */
1936203134Sthompsa	sc->rssi_5ghz[1] = val >> 8;	/* Ant B */
1937260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_RSSI2_5GHZ :
1938260219Skevlo	    RT3593_EEPROM_RSSI2_5GHZ, &val);
1939205042Sthompsa	if (sc->mac_ver == 0x3572) {
1940205042Sthompsa		/*
1941205042Sthompsa		 * On RT3572 chips (limited to 2 Rx chains), this ROM
1942205042Sthompsa		 * field contains the Tx mixer gain for the 5GHz band.
1943205042Sthompsa		 */
1944205042Sthompsa		if ((val & 0xff) != 0xff)
1945205042Sthompsa			sc->txmixgain_5ghz = val & 0x7;
1946205042Sthompsa		DPRINTF("tx mixer gain=%u (5GHz)\n", sc->txmixgain_5ghz);
1947205042Sthompsa	} else
1948205042Sthompsa		sc->rssi_5ghz[2] = val & 0xff;	/* Ant C */
1949260219Skevlo	if (sc->mac_ver == 0x3593) {
1950260219Skevlo		sc->txmixgain_5ghz = 0;
1951260219Skevlo		run_srom_read(sc, RT3593_EEPROM_LNA_5GHZ, &val);
1952260219Skevlo	}
1953203134Sthompsa	sc->lna[3] = val >> 8;		/* channel group 3 */
1954203134Sthompsa
1955260219Skevlo	run_srom_read(sc, (sc->mac_ver != 0x3593) ? RT2860_EEPROM_LNA :
1956260219Skevlo	    RT3593_EEPROM_LNA, &val);
1957203134Sthompsa	sc->lna[0] = val & 0xff;	/* channel group 0 */
1958203134Sthompsa	sc->lna[1] = val >> 8;		/* channel group 1 */
1959203134Sthompsa
1960203134Sthompsa	/* fix broken 5GHz LNA entries */
1961203134Sthompsa	if (sc->lna[2] == 0 || sc->lna[2] == 0xff) {
1962203134Sthompsa		DPRINTF("invalid LNA for channel group %d\n", 2);
1963203134Sthompsa		sc->lna[2] = sc->lna[1];
1964203134Sthompsa	}
1965203134Sthompsa	if (sc->lna[3] == 0 || sc->lna[3] == 0xff) {
1966203134Sthompsa		DPRINTF("invalid LNA for channel group %d\n", 3);
1967203134Sthompsa		sc->lna[3] = sc->lna[1];
1968203134Sthompsa	}
1969203134Sthompsa
1970203134Sthompsa	/* fix broken RSSI offset entries */
1971203134Sthompsa	for (ant = 0; ant < 3; ant++) {
1972203134Sthompsa		if (sc->rssi_2ghz[ant] < -10 || sc->rssi_2ghz[ant] > 10) {
1973203134Sthompsa			DPRINTF("invalid RSSI%d offset: %d (2GHz)\n",
1974203134Sthompsa			    ant + 1, sc->rssi_2ghz[ant]);
1975203134Sthompsa			sc->rssi_2ghz[ant] = 0;
1976203134Sthompsa		}
1977203134Sthompsa		if (sc->rssi_5ghz[ant] < -10 || sc->rssi_5ghz[ant] > 10) {
1978203134Sthompsa			DPRINTF("invalid RSSI%d offset: %d (5GHz)\n",
1979203134Sthompsa			    ant + 1, sc->rssi_5ghz[ant]);
1980203134Sthompsa			sc->rssi_5ghz[ant] = 0;
1981203134Sthompsa		}
1982203134Sthompsa	}
1983209917Sthompsa	return (0);
1984203134Sthompsa}
1985203134Sthompsa
1986218676Shselaskystatic struct ieee80211_node *
1987203134Sthompsarun_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
1988203134Sthompsa{
1989203134Sthompsa	return malloc(sizeof (struct run_node), M_DEVBUF, M_NOWAIT | M_ZERO);
1990203134Sthompsa}
1991203134Sthompsa
1992203134Sthompsastatic int
1993203134Sthompsarun_media_change(struct ifnet *ifp)
1994203134Sthompsa{
1995208019Sthompsa	struct ieee80211vap *vap = ifp->if_softc;
1996208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
1997203134Sthompsa	const struct ieee80211_txparam *tp;
1998286950Sadrian	struct run_softc *sc = ic->ic_softc;
1999203134Sthompsa	uint8_t rate, ridx;
2000203134Sthompsa	int error;
2001203134Sthompsa
2002203134Sthompsa	RUN_LOCK(sc);
2003203134Sthompsa
2004203134Sthompsa	error = ieee80211_media_change(ifp);
2005209917Sthompsa	if (error != ENETRESET) {
2006203134Sthompsa		RUN_UNLOCK(sc);
2007209917Sthompsa		return (error);
2008208019Sthompsa	}
2009203134Sthompsa
2010203134Sthompsa	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
2011203134Sthompsa	if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
2012212127Sthompsa		struct ieee80211_node *ni;
2013212127Sthompsa		struct run_node	*rn;
2014212127Sthompsa
2015203134Sthompsa		rate = ic->ic_sup_rates[ic->ic_curmode].
2016203134Sthompsa		    rs_rates[tp->ucastrate] & IEEE80211_RATE_VAL;
2017203134Sthompsa		for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2018203134Sthompsa			if (rt2860_rates[ridx].rate == rate)
2019203134Sthompsa				break;
2020212127Sthompsa		ni = ieee80211_ref_node(vap->iv_bss);
2021287552Skevlo		rn = RUN_NODE(ni);
2022208019Sthompsa		rn->fix_ridx = ridx;
2023208019Sthompsa		DPRINTF("rate=%d, fix_ridx=%d\n", rate, rn->fix_ridx);
2024212127Sthompsa		ieee80211_free_node(ni);
2025203134Sthompsa	}
2026203134Sthompsa
2027208019Sthompsa#if 0
2028203134Sthompsa	if ((ifp->if_flags & IFF_UP) &&
2029287197Sglebius	    (ifp->if_drv_flags &  RUN_RUNNING)){
2030203134Sthompsa		run_init_locked(sc);
2031203134Sthompsa	}
2032208019Sthompsa#endif
2033203134Sthompsa
2034203134Sthompsa	RUN_UNLOCK(sc);
2035203134Sthompsa
2036209917Sthompsa	return (0);
2037203134Sthompsa}
2038203134Sthompsa
2039203134Sthompsastatic int
2040203134Sthompsarun_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
2041203134Sthompsa{
2042203134Sthompsa	const struct ieee80211_txparam *tp;
2043203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2044286950Sadrian	struct run_softc *sc = ic->ic_softc;
2045203134Sthompsa	struct run_vap *rvp = RUN_VAP(vap);
2046203134Sthompsa	enum ieee80211_state ostate;
2047208019Sthompsa	uint32_t sta[3];
2048203134Sthompsa	uint32_t tmp;
2049208019Sthompsa	uint8_t ratectl;
2050208019Sthompsa	uint8_t restart_ratectl = 0;
2051208019Sthompsa	uint8_t bid = 1 << rvp->rvp_id;
2052203134Sthompsa
2053203134Sthompsa	ostate = vap->iv_state;
2054203134Sthompsa	DPRINTF("%s -> %s\n",
2055203134Sthompsa		ieee80211_state_name[ostate],
2056203134Sthompsa		ieee80211_state_name[nstate]);
2057203134Sthompsa
2058203134Sthompsa	IEEE80211_UNLOCK(ic);
2059203134Sthompsa	RUN_LOCK(sc);
2060203134Sthompsa
2061208019Sthompsa	ratectl = sc->ratectl_run; /* remember current state */
2062208019Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
2063208019Sthompsa	usb_callout_stop(&sc->ratectl_ch);
2064203134Sthompsa
2065203134Sthompsa	if (ostate == IEEE80211_S_RUN) {
2066203134Sthompsa		/* turn link LED off */
2067203134Sthompsa		run_set_leds(sc, RT2860_LED_RADIO);
2068203134Sthompsa	}
2069203134Sthompsa
2070203134Sthompsa	switch (nstate) {
2071203134Sthompsa	case IEEE80211_S_INIT:
2072208019Sthompsa		restart_ratectl = 1;
2073208019Sthompsa
2074208019Sthompsa		if (ostate != IEEE80211_S_RUN)
2075208019Sthompsa			break;
2076208019Sthompsa
2077208019Sthompsa		ratectl &= ~bid;
2078208019Sthompsa		sc->runbmap &= ~bid;
2079208019Sthompsa
2080208019Sthompsa		/* abort TSF synchronization if there is no vap running */
2081209917Sthompsa		if (--sc->running == 0) {
2082203134Sthompsa			run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
2083203134Sthompsa			run_write(sc, RT2860_BCN_TIME_CFG,
2084203134Sthompsa			    tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
2085203134Sthompsa			    RT2860_TBTT_TIMER_EN));
2086203134Sthompsa		}
2087203134Sthompsa		break;
2088203134Sthompsa
2089203134Sthompsa	case IEEE80211_S_RUN:
2090209917Sthompsa		if (!(sc->runbmap & bid)) {
2091208019Sthompsa			if(sc->running++)
2092208019Sthompsa				restart_ratectl = 1;
2093208019Sthompsa			sc->runbmap |= bid;
2094208019Sthompsa		}
2095203134Sthompsa
2096218492Sbschmidt		m_freem(rvp->beacon_mbuf);
2097218492Sbschmidt		rvp->beacon_mbuf = NULL;
2098218492Sbschmidt
2099209917Sthompsa		switch (vap->iv_opmode) {
2100208019Sthompsa		case IEEE80211_M_HOSTAP:
2101208019Sthompsa		case IEEE80211_M_MBSS:
2102208019Sthompsa			sc->ap_running |= bid;
2103208019Sthompsa			ic->ic_opmode = vap->iv_opmode;
2104208019Sthompsa			run_update_beacon_cb(vap);
2105208019Sthompsa			break;
2106208019Sthompsa		case IEEE80211_M_IBSS:
2107208019Sthompsa			sc->adhoc_running |= bid;
2108209917Sthompsa			if (!sc->ap_running)
2109208019Sthompsa				ic->ic_opmode = vap->iv_opmode;
2110208019Sthompsa			run_update_beacon_cb(vap);
2111208019Sthompsa			break;
2112208019Sthompsa		case IEEE80211_M_STA:
2113208019Sthompsa			sc->sta_running |= bid;
2114209917Sthompsa			if (!sc->ap_running && !sc->adhoc_running)
2115208019Sthompsa				ic->ic_opmode = vap->iv_opmode;
2116208019Sthompsa
2117208019Sthompsa			/* read statistic counters (clear on read) */
2118208019Sthompsa			run_read_region_1(sc, RT2860_TX_STA_CNT0,
2119208019Sthompsa			    (uint8_t *)sta, sizeof sta);
2120208019Sthompsa
2121208019Sthompsa			break;
2122208019Sthompsa		default:
2123208019Sthompsa			ic->ic_opmode = vap->iv_opmode;
2124208019Sthompsa			break;
2125208019Sthompsa		}
2126208019Sthompsa
2127203134Sthompsa		if (vap->iv_opmode != IEEE80211_M_MONITOR) {
2128212127Sthompsa			struct ieee80211_node *ni;
2129212127Sthompsa
2130236439Shselasky			if (ic->ic_bsschan == IEEE80211_CHAN_ANYC) {
2131236439Shselasky				RUN_UNLOCK(sc);
2132236439Shselasky				IEEE80211_LOCK(ic);
2133236439Shselasky				return (-1);
2134236439Shselasky			}
2135283540Sglebius			run_updateslot(ic);
2136203134Sthompsa			run_enable_mrr(sc);
2137203134Sthompsa			run_set_txpreamble(sc);
2138203134Sthompsa			run_set_basicrates(sc);
2139212127Sthompsa			ni = ieee80211_ref_node(vap->iv_bss);
2140296356Savos			IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid);
2141296356Savos			run_set_bssid(sc, sc->sc_bssid);
2142212127Sthompsa			ieee80211_free_node(ni);
2143208019Sthompsa			run_enable_tsf_sync(sc);
2144203134Sthompsa
2145208019Sthompsa			/* enable automatic rate adaptation */
2146208019Sthompsa			tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
2147208019Sthompsa			if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
2148208019Sthompsa				ratectl |= bid;
2149287555Skevlo		} else
2150287555Skevlo			run_enable_tsf(sc);
2151203134Sthompsa
2152203134Sthompsa		/* turn link LED on */
2153203134Sthompsa		run_set_leds(sc, RT2860_LED_RADIO |
2154208019Sthompsa		    (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ?
2155203134Sthompsa		     RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ));
2156203134Sthompsa
2157203134Sthompsa		break;
2158203134Sthompsa	default:
2159203134Sthompsa		DPRINTFN(6, "undefined case\n");
2160203134Sthompsa		break;
2161203134Sthompsa	}
2162203134Sthompsa
2163208019Sthompsa	/* restart amrr for running VAPs */
2164209917Sthompsa	if ((sc->ratectl_run = ratectl) && restart_ratectl)
2165208019Sthompsa		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2166208019Sthompsa
2167203134Sthompsa	RUN_UNLOCK(sc);
2168203134Sthompsa	IEEE80211_LOCK(ic);
2169203134Sthompsa
2170203134Sthompsa	return(rvp->newstate(vap, nstate, arg));
2171203134Sthompsa}
2172203134Sthompsa
2173290407Savosstatic int
2174290407Savosrun_wme_update(struct ieee80211com *ic)
2175203134Sthompsa{
2176286950Sadrian	struct run_softc *sc = ic->ic_softc;
2177288646Sadrian	const struct wmeParams *ac =
2178288646Sadrian	    ic->ic_wme.wme_chanParams.cap_wmeParams;
2179203134Sthompsa	int aci, error = 0;
2180203134Sthompsa
2181203134Sthompsa	/* update MAC TX configuration registers */
2182290407Savos	RUN_LOCK(sc);
2183203134Sthompsa	for (aci = 0; aci < WME_NUM_AC; aci++) {
2184203134Sthompsa		error = run_write(sc, RT2860_EDCA_AC_CFG(aci),
2185288646Sadrian		    ac[aci].wmep_logcwmax << 16 |
2186288646Sadrian		    ac[aci].wmep_logcwmin << 12 |
2187288646Sadrian		    ac[aci].wmep_aifsn    <<  8 |
2188288646Sadrian		    ac[aci].wmep_txopLimit);
2189209917Sthompsa		if (error) goto err;
2190203134Sthompsa	}
2191203134Sthompsa
2192203134Sthompsa	/* update SCH/DMA registers too */
2193203134Sthompsa	error = run_write(sc, RT2860_WMM_AIFSN_CFG,
2194288646Sadrian	    ac[WME_AC_VO].wmep_aifsn  << 12 |
2195288646Sadrian	    ac[WME_AC_VI].wmep_aifsn  <<  8 |
2196288646Sadrian	    ac[WME_AC_BK].wmep_aifsn  <<  4 |
2197288646Sadrian	    ac[WME_AC_BE].wmep_aifsn);
2198209917Sthompsa	if (error) goto err;
2199203134Sthompsa	error = run_write(sc, RT2860_WMM_CWMIN_CFG,
2200288646Sadrian	    ac[WME_AC_VO].wmep_logcwmin << 12 |
2201288646Sadrian	    ac[WME_AC_VI].wmep_logcwmin <<  8 |
2202288646Sadrian	    ac[WME_AC_BK].wmep_logcwmin <<  4 |
2203288646Sadrian	    ac[WME_AC_BE].wmep_logcwmin);
2204209917Sthompsa	if (error) goto err;
2205203134Sthompsa	error = run_write(sc, RT2860_WMM_CWMAX_CFG,
2206288646Sadrian	    ac[WME_AC_VO].wmep_logcwmax << 12 |
2207288646Sadrian	    ac[WME_AC_VI].wmep_logcwmax <<  8 |
2208288646Sadrian	    ac[WME_AC_BK].wmep_logcwmax <<  4 |
2209288646Sadrian	    ac[WME_AC_BE].wmep_logcwmax);
2210209917Sthompsa	if (error) goto err;
2211203134Sthompsa	error = run_write(sc, RT2860_WMM_TXOP0_CFG,
2212288646Sadrian	    ac[WME_AC_BK].wmep_txopLimit << 16 |
2213288646Sadrian	    ac[WME_AC_BE].wmep_txopLimit);
2214209917Sthompsa	if (error) goto err;
2215203134Sthompsa	error = run_write(sc, RT2860_WMM_TXOP1_CFG,
2216288646Sadrian	    ac[WME_AC_VO].wmep_txopLimit << 16 |
2217288646Sadrian	    ac[WME_AC_VI].wmep_txopLimit);
2218203134Sthompsa
2219203134Sthompsaerr:
2220290407Savos	RUN_UNLOCK(sc);
2221209917Sthompsa	if (error)
2222203134Sthompsa		DPRINTF("WME update failed\n");
2223203134Sthompsa
2224290407Savos	return (error);
2225203134Sthompsa}
2226203134Sthompsa
2227203134Sthompsastatic void
2228208019Sthompsarun_key_set_cb(void *arg)
2229203134Sthompsa{
2230208019Sthompsa	struct run_cmdq *cmdq = arg;
2231208019Sthompsa	struct ieee80211vap *vap = cmdq->arg1;
2232208019Sthompsa	struct ieee80211_key *k = cmdq->k;
2233203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2234286950Sadrian	struct run_softc *sc = ic->ic_softc;
2235203134Sthompsa	struct ieee80211_node *ni;
2236287553Skevlo	u_int cipher = k->wk_cipher->ic_cipher;
2237203134Sthompsa	uint32_t attr;
2238203134Sthompsa	uint16_t base, associd;
2239209144Sthompsa	uint8_t mode, wcid, iv[8];
2240203134Sthompsa
2241208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2242203134Sthompsa
2243209917Sthompsa	if (vap->iv_opmode == IEEE80211_M_HOSTAP)
2244208019Sthompsa		ni = ieee80211_find_vap_node(&ic->ic_sta, vap, cmdq->mac);
2245209144Sthompsa	else
2246203134Sthompsa		ni = vap->iv_bss;
2247208019Sthompsa	associd = (ni != NULL) ? ni->ni_associd : 0;
2248203134Sthompsa
2249203134Sthompsa	/* map net80211 cipher to RT2860 security mode */
2250287553Skevlo	switch (cipher) {
2251203134Sthompsa	case IEEE80211_CIPHER_WEP:
2252203134Sthompsa		if(k->wk_keylen < 8)
2253203134Sthompsa			mode = RT2860_MODE_WEP40;
2254203134Sthompsa		else
2255203134Sthompsa			mode = RT2860_MODE_WEP104;
2256203134Sthompsa		break;
2257203134Sthompsa	case IEEE80211_CIPHER_TKIP:
2258203134Sthompsa		mode = RT2860_MODE_TKIP;
2259203134Sthompsa		break;
2260203134Sthompsa	case IEEE80211_CIPHER_AES_CCM:
2261203134Sthompsa		mode = RT2860_MODE_AES_CCMP;
2262203134Sthompsa		break;
2263203134Sthompsa	default:
2264203134Sthompsa		DPRINTF("undefined case\n");
2265208019Sthompsa		return;
2266203134Sthompsa	}
2267203134Sthompsa
2268208019Sthompsa	DPRINTFN(1, "associd=%x, keyix=%d, mode=%x, type=%s, tx=%s, rx=%s\n",
2269203134Sthompsa	    associd, k->wk_keyix, mode,
2270208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_GROUP) ? "group" : "pairwise",
2271208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_XMIT) ? "on" : "off",
2272208019Sthompsa	    (k->wk_flags & IEEE80211_KEY_RECV) ? "on" : "off");
2273203134Sthompsa
2274203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2275203134Sthompsa		wcid = 0;	/* NB: update WCID0 for group keys */
2276208019Sthompsa		base = RT2860_SKEY(RUN_VAP(vap)->rvp_id, k->wk_keyix);
2277203134Sthompsa	} else {
2278245047Shselasky		wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
2279245047Shselasky		    1 : RUN_AID2WCID(associd);
2280203134Sthompsa		base = RT2860_PKEY(wcid);
2281203134Sthompsa	}
2282203134Sthompsa
2283287553Skevlo	if (cipher == IEEE80211_CIPHER_TKIP) {
2284203134Sthompsa		if(run_write_region_1(sc, base, k->wk_key, 16))
2285208019Sthompsa			return;
2286209144Sthompsa		if(run_write_region_1(sc, base + 16, &k->wk_key[16], 8))	/* wk_txmic */
2287208019Sthompsa			return;
2288209144Sthompsa		if(run_write_region_1(sc, base + 24, &k->wk_key[24], 8))	/* wk_rxmic */
2289208019Sthompsa			return;
2290203134Sthompsa	} else {
2291203134Sthompsa		/* roundup len to 16-bit: XXX fix write_region_1() instead */
2292203134Sthompsa		if(run_write_region_1(sc, base, k->wk_key, (k->wk_keylen + 1) & ~1))
2293208019Sthompsa			return;
2294203134Sthompsa	}
2295203134Sthompsa
2296203134Sthompsa	if (!(k->wk_flags & IEEE80211_KEY_GROUP) ||
2297203134Sthompsa	    (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))) {
2298203134Sthompsa		/* set initial packet number in IV+EIV */
2299287553Skevlo		if (cipher == IEEE80211_CIPHER_WEP) {
2300203134Sthompsa			memset(iv, 0, sizeof iv);
2301208019Sthompsa			iv[3] = vap->iv_def_txkey << 6;
2302203134Sthompsa		} else {
2303287553Skevlo			if (cipher == IEEE80211_CIPHER_TKIP) {
2304203134Sthompsa				iv[0] = k->wk_keytsc >> 8;
2305203134Sthompsa				iv[1] = (iv[0] | 0x20) & 0x7f;
2306203134Sthompsa				iv[2] = k->wk_keytsc;
2307203134Sthompsa			} else /* CCMP */ {
2308203134Sthompsa				iv[0] = k->wk_keytsc;
2309203134Sthompsa				iv[1] = k->wk_keytsc >> 8;
2310203134Sthompsa				iv[2] = 0;
2311203134Sthompsa			}
2312203134Sthompsa			iv[3] = k->wk_keyix << 6 | IEEE80211_WEP_EXTIV;
2313203134Sthompsa			iv[4] = k->wk_keytsc >> 16;
2314203134Sthompsa			iv[5] = k->wk_keytsc >> 24;
2315203134Sthompsa			iv[6] = k->wk_keytsc >> 32;
2316203134Sthompsa			iv[7] = k->wk_keytsc >> 40;
2317203134Sthompsa		}
2318209917Sthompsa		if (run_write_region_1(sc, RT2860_IVEIV(wcid), iv, 8))
2319208019Sthompsa			return;
2320203134Sthompsa	}
2321203134Sthompsa
2322203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2323203134Sthompsa		/* install group key */
2324209917Sthompsa		if (run_read(sc, RT2860_SKEY_MODE_0_7, &attr))
2325208019Sthompsa			return;
2326203134Sthompsa		attr &= ~(0xf << (k->wk_keyix * 4));
2327203134Sthompsa		attr |= mode << (k->wk_keyix * 4);
2328209917Sthompsa		if (run_write(sc, RT2860_SKEY_MODE_0_7, attr))
2329208019Sthompsa			return;
2330203134Sthompsa	} else {
2331203134Sthompsa		/* install pairwise key */
2332209917Sthompsa		if (run_read(sc, RT2860_WCID_ATTR(wcid), &attr))
2333208019Sthompsa			return;
2334203134Sthompsa		attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN;
2335209917Sthompsa		if (run_write(sc, RT2860_WCID_ATTR(wcid), attr))
2336208019Sthompsa			return;
2337203134Sthompsa	}
2338203134Sthompsa
2339203134Sthompsa	/* TODO create a pass-thru key entry? */
2340203134Sthompsa
2341208019Sthompsa	/* need wcid to delete the right key later */
2342208019Sthompsa	k->wk_pad = wcid;
2343203134Sthompsa}
2344203134Sthompsa
2345203134Sthompsa/*
2346208019Sthompsa * Don't have to be deferred, but in order to keep order of
2347208019Sthompsa * execution, i.e. with run_key_delete(), defer this and let
2348208019Sthompsa * run_cmdq_cb() maintain the order.
2349208019Sthompsa *
2350203134Sthompsa * return 0 on error
2351203134Sthompsa */
2352203134Sthompsastatic int
2353288635Sadrianrun_key_set(struct ieee80211vap *vap, struct ieee80211_key *k)
2354203134Sthompsa{
2355203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2356286950Sadrian	struct run_softc *sc = ic->ic_softc;
2357208019Sthompsa	uint32_t i;
2358208019Sthompsa
2359208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
2360208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
2361208019Sthompsa	sc->cmdq[i].func = run_key_set_cb;
2362208019Sthompsa	sc->cmdq[i].arg0 = NULL;
2363208019Sthompsa	sc->cmdq[i].arg1 = vap;
2364208019Sthompsa	sc->cmdq[i].k = k;
2365288635Sadrian	IEEE80211_ADDR_COPY(sc->cmdq[i].mac, k->wk_macaddr);
2366208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
2367208019Sthompsa
2368209144Sthompsa	/*
2369209144Sthompsa	 * To make sure key will be set when hostapd
2370209144Sthompsa	 * calls iv_key_set() before if_init().
2371209144Sthompsa	 */
2372209917Sthompsa	if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
2373209144Sthompsa		RUN_LOCK(sc);
2374209144Sthompsa		sc->cmdq_key_set = RUN_CMDQ_GO;
2375209144Sthompsa		RUN_UNLOCK(sc);
2376209144Sthompsa	}
2377209144Sthompsa
2378209917Sthompsa	return (1);
2379208019Sthompsa}
2380208019Sthompsa
2381208019Sthompsa/*
2382208019Sthompsa * If wlan is destroyed without being brought down i.e. without
2383208019Sthompsa * wlan down or wpa_cli terminate, this function is called after
2384208019Sthompsa * vap is gone. Don't refer it.
2385208019Sthompsa */
2386208019Sthompsastatic void
2387208019Sthompsarun_key_delete_cb(void *arg)
2388208019Sthompsa{
2389208019Sthompsa	struct run_cmdq *cmdq = arg;
2390208019Sthompsa	struct run_softc *sc = cmdq->arg1;
2391208019Sthompsa	struct ieee80211_key *k = &cmdq->key;
2392203134Sthompsa	uint32_t attr;
2393203134Sthompsa	uint8_t wcid;
2394203134Sthompsa
2395208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2396203134Sthompsa
2397203134Sthompsa	if (k->wk_flags & IEEE80211_KEY_GROUP) {
2398203134Sthompsa		/* remove group key */
2399208019Sthompsa		DPRINTF("removing group key\n");
2400208019Sthompsa		run_read(sc, RT2860_SKEY_MODE_0_7, &attr);
2401203134Sthompsa		attr &= ~(0xf << (k->wk_keyix * 4));
2402208019Sthompsa		run_write(sc, RT2860_SKEY_MODE_0_7, attr);
2403203134Sthompsa	} else {
2404203134Sthompsa		/* remove pairwise key */
2405208019Sthompsa		DPRINTF("removing key for wcid %x\n", k->wk_pad);
2406208019Sthompsa		/* matching wcid was written to wk_pad in run_key_set() */
2407208019Sthompsa		wcid = k->wk_pad;
2408208019Sthompsa		run_read(sc, RT2860_WCID_ATTR(wcid), &attr);
2409203134Sthompsa		attr &= ~0xf;
2410208019Sthompsa		run_write(sc, RT2860_WCID_ATTR(wcid), attr);
2411208019Sthompsa		run_set_region_4(sc, RT2860_WCID_ENTRY(wcid), 0, 8);
2412203134Sthompsa	}
2413203134Sthompsa
2414208019Sthompsa	k->wk_pad = 0;
2415203134Sthompsa}
2416203134Sthompsa
2417208019Sthompsa/*
2418208019Sthompsa * return 0 on error
2419208019Sthompsa */
2420208019Sthompsastatic int
2421208019Sthompsarun_key_delete(struct ieee80211vap *vap, struct ieee80211_key *k)
2422203134Sthompsa{
2423208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2424286950Sadrian	struct run_softc *sc = ic->ic_softc;
2425208019Sthompsa	struct ieee80211_key *k0;
2426208019Sthompsa	uint32_t i;
2427203134Sthompsa
2428208019Sthompsa	/*
2429208019Sthompsa	 * When called back, key might be gone. So, make a copy
2430208019Sthompsa	 * of some values need to delete keys before deferring.
2431208019Sthompsa	 * But, because of LOR with node lock, cannot use lock here.
2432208019Sthompsa	 * So, use atomic instead.
2433208019Sthompsa	 */
2434208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
2435208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
2436208019Sthompsa	sc->cmdq[i].func = run_key_delete_cb;
2437208019Sthompsa	sc->cmdq[i].arg0 = NULL;
2438208019Sthompsa	sc->cmdq[i].arg1 = sc;
2439208019Sthompsa	k0 = &sc->cmdq[i].key;
2440208019Sthompsa	k0->wk_flags = k->wk_flags;
2441208019Sthompsa	k0->wk_keyix = k->wk_keyix;
2442208019Sthompsa	/* matching wcid was written to wk_pad in run_key_set() */
2443208019Sthompsa	k0->wk_pad = k->wk_pad;
2444208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
2445208019Sthompsa	return (1);	/* return fake success */
2446203134Sthompsa
2447203134Sthompsa}
2448203134Sthompsa
2449203134Sthompsastatic void
2450206358Srpaulorun_ratectl_to(void *arg)
2451203134Sthompsa{
2452208019Sthompsa	struct run_softc *sc = arg;
2453203134Sthompsa
2454203134Sthompsa	/* do it in a process context, so it can go sleep */
2455287197Sglebius	ieee80211_runtask(&sc->sc_ic, &sc->ratectl_task);
2456203134Sthompsa	/* next timeout will be rescheduled in the callback task */
2457203134Sthompsa}
2458203134Sthompsa
2459203134Sthompsa/* ARGSUSED */
2460203134Sthompsastatic void
2461206358Srpaulorun_ratectl_cb(void *arg, int pending)
2462203134Sthompsa{
2463208019Sthompsa	struct run_softc *sc = arg;
2464287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
2465208019Sthompsa	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
2466203134Sthompsa
2467209917Sthompsa	if (vap == NULL)
2468208019Sthompsa		return;
2469208019Sthompsa
2470262795Shselasky	if (sc->rvp_cnt > 1 || vap->iv_opmode != IEEE80211_M_STA) {
2471203134Sthompsa		/*
2472203134Sthompsa		 * run_reset_livelock() doesn't do anything with AMRR,
2473203134Sthompsa		 * but Ralink wants us to call it every 1 sec. So, we
2474203134Sthompsa		 * piggyback here rather than creating another callout.
2475203134Sthompsa		 * Livelock may occur only in HOSTAP or IBSS mode
2476203134Sthompsa		 * (when h/w is sending beacons).
2477203134Sthompsa		 */
2478203134Sthompsa		RUN_LOCK(sc);
2479203134Sthompsa		run_reset_livelock(sc);
2480208019Sthompsa		/* just in case, there are some stats to drain */
2481208019Sthompsa		run_drain_fifo(sc);
2482203134Sthompsa		RUN_UNLOCK(sc);
2483203134Sthompsa	}
2484203134Sthompsa
2485262795Shselasky	ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, sc);
2486262795Shselasky
2487257712Shselasky	RUN_LOCK(sc);
2488208019Sthompsa	if(sc->ratectl_run != RUN_RATECTL_OFF)
2489208019Sthompsa		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2490257712Shselasky	RUN_UNLOCK(sc);
2491203134Sthompsa}
2492203134Sthompsa
2493203134Sthompsastatic void
2494208019Sthompsarun_drain_fifo(void *arg)
2495203134Sthompsa{
2496208019Sthompsa	struct run_softc *sc = arg;
2497208019Sthompsa	uint32_t stat;
2498218676Shselasky	uint16_t (*wstat)[3];
2499203134Sthompsa	uint8_t wcid, mcs, pid;
2500218676Shselasky	int8_t retry;
2501203134Sthompsa
2502208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2503203134Sthompsa
2504208019Sthompsa	for (;;) {
2505203134Sthompsa		/* drain Tx status FIFO (maxsize = 16) */
2506203134Sthompsa		run_read(sc, RT2860_TX_STAT_FIFO, &stat);
2507208019Sthompsa		DPRINTFN(4, "tx stat 0x%08x\n", stat);
2508209917Sthompsa		if (!(stat & RT2860_TXQ_VLD))
2509208019Sthompsa			break;
2510203134Sthompsa
2511208019Sthompsa		wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff;
2512203134Sthompsa
2513208019Sthompsa		/* if no ACK was requested, no feedback is available */
2514208019Sthompsa		if (!(stat & RT2860_TXQ_ACKREQ) || wcid > RT2870_WCID_MAX ||
2515208019Sthompsa		    wcid == 0)
2516208019Sthompsa			continue;
2517203134Sthompsa
2518218676Shselasky		/*
2519218676Shselasky		 * Even though each stat is Tx-complete-status like format,
2520218676Shselasky		 * the device can poll stats. Because there is no guarantee
2521218676Shselasky		 * that the referring node is still around when read the stats.
2522218676Shselasky		 * So that, if we use ieee80211_ratectl_tx_update(), we will
2523218676Shselasky		 * have hard time not to refer already freed node.
2524218676Shselasky		 *
2525218676Shselasky		 * To eliminate such page faults, we poll stats in softc.
2526218676Shselasky		 * Then, update the rates later with ieee80211_ratectl_tx_update().
2527218676Shselasky		 */
2528218676Shselasky		wstat = &(sc->wcid_stats[wcid]);
2529218676Shselasky		(*wstat)[RUN_TXCNT]++;
2530218676Shselasky		if (stat & RT2860_TXQ_OK)
2531218676Shselasky			(*wstat)[RUN_SUCCESS]++;
2532218676Shselasky		else
2533287197Sglebius			counter_u64_add(sc->sc_ic.ic_oerrors, 1);
2534218676Shselasky		/*
2535218676Shselasky		 * Check if there were retries, ie if the Tx success rate is
2536218676Shselasky		 * different from the requested rate. Note that it works only
2537218676Shselasky		 * because we do not allow rate fallback from OFDM to CCK.
2538218676Shselasky		 */
2539218676Shselasky		mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f;
2540218676Shselasky		pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf;
2541218676Shselasky		if ((retry = pid -1 - mcs) > 0) {
2542218676Shselasky			(*wstat)[RUN_TXCNT] += retry;
2543218676Shselasky			(*wstat)[RUN_RETRY] += retry;
2544203134Sthompsa		}
2545208019Sthompsa	}
2546208019Sthompsa	DPRINTFN(3, "count=%d\n", sc->fifo_cnt);
2547208019Sthompsa
2548208019Sthompsa	sc->fifo_cnt = 0;
2549208019Sthompsa}
2550208019Sthompsa
2551208019Sthompsastatic void
2552208019Sthompsarun_iter_func(void *arg, struct ieee80211_node *ni)
2553208019Sthompsa{
2554208019Sthompsa	struct run_softc *sc = arg;
2555208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
2556287552Skevlo	struct run_node *rn = RUN_NODE(ni);
2557218676Shselasky	union run_stats sta[2];
2558218676Shselasky	uint16_t (*wstat)[3];
2559218676Shselasky	int txcnt, success, retrycnt, error;
2560208019Sthompsa
2561218676Shselasky	RUN_LOCK(sc);
2562218676Shselasky
2563262795Shselasky	/* Check for special case */
2564262795Shselasky	if (sc->rvp_cnt <= 1 && vap->iv_opmode == IEEE80211_M_STA &&
2565262795Shselasky	    ni != vap->iv_bss)
2566262795Shselasky		goto fail;
2567262795Shselasky
2568209917Sthompsa	if (sc->rvp_cnt <= 1 && (vap->iv_opmode == IEEE80211_M_IBSS ||
2569209917Sthompsa	    vap->iv_opmode == IEEE80211_M_STA)) {
2570203134Sthompsa		/* read statistic counters (clear on read) and update AMRR state */
2571203134Sthompsa		error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta,
2572203134Sthompsa		    sizeof sta);
2573203134Sthompsa		if (error != 0)
2574218676Shselasky			goto fail;
2575203134Sthompsa
2576203134Sthompsa		/* count failed TX as errors */
2577287197Sglebius		if_inc_counter(vap->iv_ifp, IFCOUNTER_OERRORS,
2578287197Sglebius		    le16toh(sta[0].error.fail));
2579203134Sthompsa
2580218676Shselasky		retrycnt = le16toh(sta[1].tx.retry);
2581218676Shselasky		success = le16toh(sta[1].tx.success);
2582218676Shselasky		txcnt = retrycnt + success + le16toh(sta[0].error.fail);
2583203134Sthompsa
2584218676Shselasky		DPRINTFN(3, "retrycnt=%d success=%d failcnt=%d\n",
2585218676Shselasky			retrycnt, success, le16toh(sta[0].error.fail));
2586218676Shselasky	} else {
2587218676Shselasky		wstat = &(sc->wcid_stats[RUN_AID2WCID(ni->ni_associd)]);
2588203134Sthompsa
2589218676Shselasky		if (wstat == &(sc->wcid_stats[0]) ||
2590218676Shselasky		    wstat > &(sc->wcid_stats[RT2870_WCID_MAX]))
2591218676Shselasky			goto fail;
2592208019Sthompsa
2593218676Shselasky		txcnt = (*wstat)[RUN_TXCNT];
2594218676Shselasky		success = (*wstat)[RUN_SUCCESS];
2595218676Shselasky		retrycnt = (*wstat)[RUN_RETRY];
2596218676Shselasky		DPRINTFN(3, "retrycnt=%d txcnt=%d success=%d\n",
2597218676Shselasky		    retrycnt, txcnt, success);
2598208019Sthompsa
2599218676Shselasky		memset(wstat, 0, sizeof(*wstat));
2600203134Sthompsa	}
2601203134Sthompsa
2602218676Shselasky	ieee80211_ratectl_tx_update(vap, ni, &txcnt, &success, &retrycnt);
2603208019Sthompsa	rn->amrr_ridx = ieee80211_ratectl_rate(ni, NULL, 0);
2604218676Shselasky
2605218676Shselaskyfail:
2606218676Shselasky	RUN_UNLOCK(sc);
2607218676Shselasky
2608208019Sthompsa	DPRINTFN(3, "ridx=%d\n", rn->amrr_ridx);
2609208019Sthompsa}
2610203134Sthompsa
2611208019Sthompsastatic void
2612208019Sthompsarun_newassoc_cb(void *arg)
2613208019Sthompsa{
2614208019Sthompsa	struct run_cmdq *cmdq = arg;
2615208019Sthompsa	struct ieee80211_node *ni = cmdq->arg1;
2616286950Sadrian	struct run_softc *sc = ni->ni_vap->iv_ic->ic_softc;
2617208019Sthompsa	uint8_t wcid = cmdq->wcid;
2618203134Sthompsa
2619208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
2620208019Sthompsa
2621208019Sthompsa	run_write_region_1(sc, RT2860_WCID_ENTRY(wcid),
2622208019Sthompsa	    ni->ni_macaddr, IEEE80211_ADDR_LEN);
2623218676Shselasky
2624218676Shselasky	memset(&(sc->wcid_stats[wcid]), 0, sizeof(sc->wcid_stats[wcid]));
2625203134Sthompsa}
2626203134Sthompsa
2627203134Sthompsastatic void
2628203134Sthompsarun_newassoc(struct ieee80211_node *ni, int isnew)
2629203134Sthompsa{
2630287552Skevlo	struct run_node *rn = RUN_NODE(ni);
2631203134Sthompsa	struct ieee80211_rateset *rs = &ni->ni_rates;
2632208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
2633208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
2634286950Sadrian	struct run_softc *sc = ic->ic_softc;
2635203134Sthompsa	uint8_t rate;
2636208019Sthompsa	uint8_t ridx;
2637245047Shselasky	uint8_t wcid;
2638208019Sthompsa	int i, j;
2639203134Sthompsa
2640245047Shselasky	wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
2641245047Shselasky	    1 : RUN_AID2WCID(ni->ni_associd);
2642245047Shselasky
2643209917Sthompsa	if (wcid > RT2870_WCID_MAX) {
2644208019Sthompsa		device_printf(sc->sc_dev, "wcid=%d out of range\n", wcid);
2645208019Sthompsa		return;
2646208019Sthompsa	}
2647203134Sthompsa
2648208019Sthompsa	/* only interested in true associations */
2649209917Sthompsa	if (isnew && ni->ni_associd != 0) {
2650208019Sthompsa
2651208019Sthompsa		/*
2652208019Sthompsa		 * This function could is called though timeout function.
2653208019Sthompsa		 * Need to defer.
2654208019Sthompsa		 */
2655208019Sthompsa		uint32_t cnt = RUN_CMDQ_GET(&sc->cmdq_store);
2656208019Sthompsa		DPRINTF("cmdq_store=%d\n", cnt);
2657208019Sthompsa		sc->cmdq[cnt].func = run_newassoc_cb;
2658208019Sthompsa		sc->cmdq[cnt].arg0 = NULL;
2659208019Sthompsa		sc->cmdq[cnt].arg1 = ni;
2660208019Sthompsa		sc->cmdq[cnt].wcid = wcid;
2661208019Sthompsa		ieee80211_runtask(ic, &sc->cmdq_task);
2662208019Sthompsa	}
2663208019Sthompsa
2664208019Sthompsa	DPRINTF("new assoc isnew=%d associd=%x addr=%s\n",
2665208019Sthompsa	    isnew, ni->ni_associd, ether_sprintf(ni->ni_macaddr));
2666208019Sthompsa
2667203134Sthompsa	for (i = 0; i < rs->rs_nrates; i++) {
2668203134Sthompsa		rate = rs->rs_rates[i] & IEEE80211_RATE_VAL;
2669203134Sthompsa		/* convert 802.11 rate to hardware rate index */
2670203134Sthompsa		for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2671203134Sthompsa			if (rt2860_rates[ridx].rate == rate)
2672203134Sthompsa				break;
2673203134Sthompsa		rn->ridx[i] = ridx;
2674203134Sthompsa		/* determine rate of control response frames */
2675203134Sthompsa		for (j = i; j >= 0; j--) {
2676203134Sthompsa			if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) &&
2677203134Sthompsa			    rt2860_rates[rn->ridx[i]].phy ==
2678203134Sthompsa			    rt2860_rates[rn->ridx[j]].phy)
2679203134Sthompsa				break;
2680203134Sthompsa		}
2681203134Sthompsa		if (j >= 0) {
2682203134Sthompsa			rn->ctl_ridx[i] = rn->ridx[j];
2683203134Sthompsa		} else {
2684203134Sthompsa			/* no basic rate found, use mandatory one */
2685203134Sthompsa			rn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx;
2686203134Sthompsa		}
2687203134Sthompsa		DPRINTF("rate=0x%02x ridx=%d ctl_ridx=%d\n",
2688203134Sthompsa		    rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]);
2689203134Sthompsa	}
2690208019Sthompsa	rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate;
2691208019Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
2692208019Sthompsa		if (rt2860_rates[ridx].rate == rate)
2693208019Sthompsa			break;
2694208019Sthompsa	rn->mgt_ridx = ridx;
2695208019Sthompsa	DPRINTF("rate=%d, mgmt_ridx=%d\n", rate, rn->mgt_ridx);
2696208019Sthompsa
2697262795Shselasky	RUN_LOCK(sc);
2698262795Shselasky	if(sc->ratectl_run != RUN_RATECTL_OFF)
2699262795Shselasky		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
2700262795Shselasky	RUN_UNLOCK(sc);
2701203134Sthompsa}
2702203134Sthompsa
2703203134Sthompsa/*
2704203134Sthompsa * Return the Rx chain with the highest RSSI for a given frame.
2705203134Sthompsa */
2706203134Sthompsastatic __inline uint8_t
2707203134Sthompsarun_maxrssi_chain(struct run_softc *sc, const struct rt2860_rxwi *rxwi)
2708203134Sthompsa{
2709203134Sthompsa	uint8_t rxchain = 0;
2710203134Sthompsa
2711203134Sthompsa	if (sc->nrxchains > 1) {
2712203134Sthompsa		if (rxwi->rssi[1] > rxwi->rssi[rxchain])
2713203134Sthompsa			rxchain = 1;
2714203134Sthompsa		if (sc->nrxchains > 2)
2715203134Sthompsa			if (rxwi->rssi[2] > rxwi->rssi[rxchain])
2716203134Sthompsa				rxchain = 2;
2717203134Sthompsa	}
2718209917Sthompsa	return (rxchain);
2719203134Sthompsa}
2720203134Sthompsa
2721203134Sthompsastatic void
2722288603Sadrianrun_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype,
2723288603Sadrian    const struct ieee80211_rx_stats *rxs, int rssi, int nf)
2724288603Sadrian{
2725288603Sadrian	struct ieee80211vap *vap = ni->ni_vap;
2726288603Sadrian	struct run_softc *sc = vap->iv_ic->ic_softc;
2727288603Sadrian	struct run_vap *rvp = RUN_VAP(vap);
2728288603Sadrian	uint64_t ni_tstamp, rx_tstamp;
2729288603Sadrian
2730288603Sadrian	rvp->recv_mgmt(ni, m, subtype, rxs, rssi, nf);
2731288603Sadrian
2732288603Sadrian	if (vap->iv_state == IEEE80211_S_RUN &&
2733288603Sadrian	    (subtype == IEEE80211_FC0_SUBTYPE_BEACON ||
2734288603Sadrian	    subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) {
2735288603Sadrian		ni_tstamp = le64toh(ni->ni_tstamp.tsf);
2736288603Sadrian		RUN_LOCK(sc);
2737288603Sadrian		run_get_tsf(sc, &rx_tstamp);
2738288603Sadrian		RUN_UNLOCK(sc);
2739288603Sadrian		rx_tstamp = le64toh(rx_tstamp);
2740288603Sadrian
2741288603Sadrian		if (ni_tstamp >= rx_tstamp) {
2742288603Sadrian			DPRINTF("ibss merge, tsf %ju tstamp %ju\n",
2743288603Sadrian			    (uintmax_t)rx_tstamp, (uintmax_t)ni_tstamp);
2744288603Sadrian			(void) ieee80211_ibss_merge(ni);
2745288603Sadrian		}
2746288603Sadrian	}
2747288603Sadrian}
2748288603Sadrian
2749288603Sadrianstatic void
2750203134Sthompsarun_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen)
2751203134Sthompsa{
2752287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
2753203134Sthompsa	struct ieee80211_frame *wh;
2754203134Sthompsa	struct ieee80211_node *ni;
2755203134Sthompsa	struct rt2870_rxd *rxd;
2756203134Sthompsa	struct rt2860_rxwi *rxwi;
2757203134Sthompsa	uint32_t flags;
2758259032Skevlo	uint16_t len, rxwisize;
2759203134Sthompsa	uint8_t ant, rssi;
2760203134Sthompsa	int8_t nf;
2761203134Sthompsa
2762203134Sthompsa	rxwi = mtod(m, struct rt2860_rxwi *);
2763203134Sthompsa	len = le16toh(rxwi->len) & 0xfff;
2764260219Skevlo	rxwisize = sizeof(struct rt2860_rxwi);
2765260219Skevlo	if (sc->mac_ver == 0x5592)
2766260219Skevlo		rxwisize += sizeof(uint64_t);
2767260219Skevlo	else if (sc->mac_ver == 0x3593)
2768260219Skevlo		rxwisize += sizeof(uint32_t);
2769203134Sthompsa	if (__predict_false(len > dmalen)) {
2770203134Sthompsa		m_freem(m);
2771287197Sglebius		counter_u64_add(ic->ic_ierrors, 1);
2772203134Sthompsa		DPRINTF("bad RXWI length %u > %u\n", len, dmalen);
2773203134Sthompsa		return;
2774203134Sthompsa	}
2775203134Sthompsa	/* Rx descriptor is located at the end */
2776203134Sthompsa	rxd = (struct rt2870_rxd *)(mtod(m, caddr_t) + dmalen);
2777203134Sthompsa	flags = le32toh(rxd->flags);
2778203134Sthompsa
2779203134Sthompsa	if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) {
2780203134Sthompsa		m_freem(m);
2781287197Sglebius		counter_u64_add(ic->ic_ierrors, 1);
2782203134Sthompsa		DPRINTF("%s error.\n", (flags & RT2860_RX_CRCERR)?"CRC":"ICV");
2783203134Sthompsa		return;
2784203134Sthompsa	}
2785203134Sthompsa
2786259032Skevlo	m->m_data += rxwisize;
2787259032Skevlo	m->m_pkthdr.len = m->m_len -= rxwisize;
2788203134Sthompsa
2789203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
2790203134Sthompsa
2791260444Skevlo	if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
2792260444Skevlo		wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
2793203134Sthompsa		m->m_flags |= M_WEP;
2794203134Sthompsa	}
2795203134Sthompsa
2796209917Sthompsa	if (flags & RT2860_RX_L2PAD) {
2797203134Sthompsa		DPRINTFN(8, "received RT2860_RX_L2PAD frame\n");
2798203134Sthompsa		len += 2;
2799203134Sthompsa	}
2800203134Sthompsa
2801208019Sthompsa	ni = ieee80211_find_rxnode(ic,
2802208019Sthompsa	    mtod(m, struct ieee80211_frame_min *));
2803208019Sthompsa
2804203134Sthompsa	if (__predict_false(flags & RT2860_RX_MICERR)) {
2805203134Sthompsa		/* report MIC failures to net80211 for TKIP */
2806209917Sthompsa		if (ni != NULL)
2807259032Skevlo			ieee80211_notify_michael_failure(ni->ni_vap, wh,
2808259032Skevlo			    rxwi->keyidx);
2809203134Sthompsa		m_freem(m);
2810287197Sglebius		counter_u64_add(ic->ic_ierrors, 1);
2811203134Sthompsa		DPRINTF("MIC error. Someone is lying.\n");
2812203134Sthompsa		return;
2813203134Sthompsa	}
2814203134Sthompsa
2815203134Sthompsa	ant = run_maxrssi_chain(sc, rxwi);
2816203134Sthompsa	rssi = rxwi->rssi[ant];
2817203134Sthompsa	nf = run_rssi2dbm(sc, rssi, ant);
2818203134Sthompsa
2819203134Sthompsa	m->m_pkthdr.len = m->m_len = len;
2820203134Sthompsa
2821209917Sthompsa	if (__predict_false(ieee80211_radiotap_active(ic))) {
2822203134Sthompsa		struct run_rx_radiotap_header *tap = &sc->sc_rxtap;
2823258643Shselasky		uint16_t phy;
2824203134Sthompsa
2825203134Sthompsa		tap->wr_flags = 0;
2826236439Shselasky		tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
2827236439Shselasky		tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
2828203134Sthompsa		tap->wr_antsignal = rssi;
2829203134Sthompsa		tap->wr_antenna = ant;
2830203134Sthompsa		tap->wr_dbm_antsignal = run_rssi2dbm(sc, rssi, ant);
2831203134Sthompsa		tap->wr_rate = 2;	/* in case it can't be found below */
2832301302Sadrian		RUN_LOCK(sc);
2833287554Skevlo		run_get_tsf(sc, &tap->wr_tsf);
2834301302Sadrian		RUN_UNLOCK(sc);
2835203134Sthompsa		phy = le16toh(rxwi->phy);
2836203134Sthompsa		switch (phy & RT2860_PHY_MODE) {
2837203134Sthompsa		case RT2860_PHY_CCK:
2838203134Sthompsa			switch ((phy & RT2860_PHY_MCS) & ~RT2860_PHY_SHPRE) {
2839203134Sthompsa			case 0:	tap->wr_rate =   2; break;
2840203134Sthompsa			case 1:	tap->wr_rate =   4; break;
2841203134Sthompsa			case 2:	tap->wr_rate =  11; break;
2842203134Sthompsa			case 3:	tap->wr_rate =  22; break;
2843203134Sthompsa			}
2844203134Sthompsa			if (phy & RT2860_PHY_SHPRE)
2845203134Sthompsa				tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
2846203134Sthompsa			break;
2847203134Sthompsa		case RT2860_PHY_OFDM:
2848203134Sthompsa			switch (phy & RT2860_PHY_MCS) {
2849203134Sthompsa			case 0:	tap->wr_rate =  12; break;
2850203134Sthompsa			case 1:	tap->wr_rate =  18; break;
2851203134Sthompsa			case 2:	tap->wr_rate =  24; break;
2852203134Sthompsa			case 3:	tap->wr_rate =  36; break;
2853203134Sthompsa			case 4:	tap->wr_rate =  48; break;
2854203134Sthompsa			case 5:	tap->wr_rate =  72; break;
2855203134Sthompsa			case 6:	tap->wr_rate =  96; break;
2856203134Sthompsa			case 7:	tap->wr_rate = 108; break;
2857203134Sthompsa			}
2858203134Sthompsa			break;
2859203134Sthompsa		}
2860203134Sthompsa	}
2861289753Savos
2862289753Savos	if (ni != NULL) {
2863289753Savos		(void)ieee80211_input(ni, m, rssi, nf);
2864289753Savos		ieee80211_free_node(ni);
2865289753Savos	} else {
2866289753Savos		(void)ieee80211_input_all(ic, m, rssi, nf);
2867289753Savos	}
2868203134Sthompsa}
2869203134Sthompsa
2870203134Sthompsastatic void
2871203134Sthompsarun_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error)
2872203134Sthompsa{
2873203134Sthompsa	struct run_softc *sc = usbd_xfer_softc(xfer);
2874287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
2875203134Sthompsa	struct mbuf *m = NULL;
2876203134Sthompsa	struct mbuf *m0;
2877203134Sthompsa	uint32_t dmalen;
2878259032Skevlo	uint16_t rxwisize;
2879203134Sthompsa	int xferlen;
2880203134Sthompsa
2881260219Skevlo	rxwisize = sizeof(struct rt2860_rxwi);
2882260219Skevlo	if (sc->mac_ver == 0x5592)
2883260219Skevlo		rxwisize += sizeof(uint64_t);
2884260219Skevlo	else if (sc->mac_ver == 0x3593)
2885260219Skevlo		rxwisize += sizeof(uint32_t);
2886259032Skevlo
2887203134Sthompsa	usbd_xfer_status(xfer, &xferlen, NULL, NULL, NULL);
2888203134Sthompsa
2889203134Sthompsa	switch (USB_GET_STATE(xfer)) {
2890203134Sthompsa	case USB_ST_TRANSFERRED:
2891203134Sthompsa
2892203134Sthompsa		DPRINTFN(15, "rx done, actlen=%d\n", xferlen);
2893203134Sthompsa
2894259032Skevlo		if (xferlen < (int)(sizeof(uint32_t) + rxwisize +
2895259032Skevlo		    sizeof(struct rt2870_rxd))) {
2896203134Sthompsa			DPRINTF("xfer too short %d\n", xferlen);
2897203134Sthompsa			goto tr_setup;
2898203134Sthompsa		}
2899203134Sthompsa
2900203134Sthompsa		m = sc->rx_m;
2901203134Sthompsa		sc->rx_m = NULL;
2902203134Sthompsa
2903203134Sthompsa		/* FALLTHROUGH */
2904203134Sthompsa	case USB_ST_SETUP:
2905203134Sthompsatr_setup:
2906203134Sthompsa		if (sc->rx_m == NULL) {
2907243857Sglebius			sc->rx_m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR,
2908203134Sthompsa			    MJUMPAGESIZE /* xfer can be bigger than MCLBYTES */);
2909203134Sthompsa		}
2910203134Sthompsa		if (sc->rx_m == NULL) {
2911203134Sthompsa			DPRINTF("could not allocate mbuf - idle with stall\n");
2912287197Sglebius			counter_u64_add(ic->ic_ierrors, 1);
2913203134Sthompsa			usbd_xfer_set_stall(xfer);
2914203134Sthompsa			usbd_xfer_set_frames(xfer, 0);
2915203134Sthompsa		} else {
2916203134Sthompsa			/*
2917203134Sthompsa			 * Directly loading a mbuf cluster into DMA to
2918203134Sthompsa			 * save some data copying. This works because
2919203134Sthompsa			 * there is only one cluster.
2920203134Sthompsa			 */
2921203134Sthompsa			usbd_xfer_set_frame_data(xfer, 0,
2922203134Sthompsa			    mtod(sc->rx_m, caddr_t), RUN_MAX_RXSZ);
2923203134Sthompsa			usbd_xfer_set_frames(xfer, 1);
2924203134Sthompsa		}
2925203134Sthompsa		usbd_transfer_submit(xfer);
2926203134Sthompsa		break;
2927203134Sthompsa
2928203134Sthompsa	default:	/* Error */
2929203134Sthompsa		if (error != USB_ERR_CANCELLED) {
2930203134Sthompsa			/* try to clear stall first */
2931203134Sthompsa			usbd_xfer_set_stall(xfer);
2932203134Sthompsa			if (error == USB_ERR_TIMEOUT)
2933203134Sthompsa				device_printf(sc->sc_dev, "device timeout\n");
2934287197Sglebius			counter_u64_add(ic->ic_ierrors, 1);
2935203134Sthompsa			goto tr_setup;
2936203134Sthompsa		}
2937209917Sthompsa		if (sc->rx_m != NULL) {
2938203134Sthompsa			m_freem(sc->rx_m);
2939203134Sthompsa			sc->rx_m = NULL;
2940203134Sthompsa		}
2941203134Sthompsa		break;
2942203134Sthompsa	}
2943203134Sthompsa
2944203134Sthompsa	if (m == NULL)
2945203134Sthompsa		return;
2946203134Sthompsa
2947203134Sthompsa	/* inputting all the frames must be last */
2948203134Sthompsa
2949203134Sthompsa	RUN_UNLOCK(sc);
2950203134Sthompsa
2951203134Sthompsa	m->m_pkthdr.len = m->m_len = xferlen;
2952203134Sthompsa
2953203134Sthompsa	/* HW can aggregate multiple 802.11 frames in a single USB xfer */
2954203134Sthompsa	for(;;) {
2955203134Sthompsa		dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff;
2956203134Sthompsa
2957233774Shselasky		if ((dmalen >= (uint32_t)-8) || (dmalen == 0) ||
2958233774Shselasky		    ((dmalen & 3) != 0)) {
2959203134Sthompsa			DPRINTF("bad DMA length %u\n", dmalen);
2960203134Sthompsa			break;
2961203134Sthompsa		}
2962233774Shselasky		if ((dmalen + 8) > (uint32_t)xferlen) {
2963203134Sthompsa			DPRINTF("bad DMA length %u > %d\n",
2964203134Sthompsa			dmalen + 8, xferlen);
2965203134Sthompsa			break;
2966203134Sthompsa		}
2967203134Sthompsa
2968203134Sthompsa		/* If it is the last one or a single frame, we won't copy. */
2969209917Sthompsa		if ((xferlen -= dmalen + 8) <= 8) {
2970203134Sthompsa			/* trim 32-bit DMA-len header */
2971203134Sthompsa			m->m_data += 4;
2972203134Sthompsa			m->m_pkthdr.len = m->m_len -= 4;
2973203134Sthompsa			run_rx_frame(sc, m, dmalen);
2974257435Shselasky			m = NULL;	/* don't free source buffer */
2975203134Sthompsa			break;
2976203134Sthompsa		}
2977203134Sthompsa
2978203134Sthompsa		/* copy aggregated frames to another mbuf */
2979243857Sglebius		m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
2980203134Sthompsa		if (__predict_false(m0 == NULL)) {
2981203134Sthompsa			DPRINTF("could not allocate mbuf\n");
2982287197Sglebius			counter_u64_add(ic->ic_ierrors, 1);
2983203134Sthompsa			break;
2984203134Sthompsa		}
2985203134Sthompsa		m_copydata(m, 4 /* skip 32-bit DMA-len header */,
2986203134Sthompsa		    dmalen + sizeof(struct rt2870_rxd), mtod(m0, caddr_t));
2987203134Sthompsa		m0->m_pkthdr.len = m0->m_len =
2988203134Sthompsa		    dmalen + sizeof(struct rt2870_rxd);
2989203134Sthompsa		run_rx_frame(sc, m0, dmalen);
2990203134Sthompsa
2991203134Sthompsa		/* update data ptr */
2992203134Sthompsa		m->m_data += dmalen + 8;
2993203134Sthompsa		m->m_pkthdr.len = m->m_len -= dmalen + 8;
2994203134Sthompsa	}
2995203134Sthompsa
2996257435Shselasky	/* make sure we free the source buffer, if any */
2997257435Shselasky	m_freem(m);
2998257435Shselasky
2999203134Sthompsa	RUN_LOCK(sc);
3000203134Sthompsa}
3001203134Sthompsa
3002203134Sthompsastatic void
3003203134Sthompsarun_tx_free(struct run_endpoint_queue *pq,
3004203134Sthompsa    struct run_tx_data *data, int txerr)
3005203134Sthompsa{
3006203134Sthompsa
3007289841Savos	ieee80211_tx_complete(data->ni, data->m, txerr);
3008203134Sthompsa
3009289841Savos	data->m = NULL;
3010289841Savos	data->ni = NULL;
3011289841Savos
3012203134Sthompsa	STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
3013203134Sthompsa	pq->tx_nfree++;
3014203134Sthompsa}
3015203134Sthompsa
3016203134Sthompsastatic void
3017257429Shselaskyrun_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, u_int index)
3018203134Sthompsa{
3019203134Sthompsa	struct run_softc *sc = usbd_xfer_softc(xfer);
3020287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3021203134Sthompsa	struct run_tx_data *data;
3022203134Sthompsa	struct ieee80211vap *vap = NULL;
3023203134Sthompsa	struct usb_page_cache *pc;
3024203134Sthompsa	struct run_endpoint_queue *pq = &sc->sc_epq[index];
3025203134Sthompsa	struct mbuf *m;
3026203134Sthompsa	usb_frlength_t size;
3027203134Sthompsa	int actlen;
3028203134Sthompsa	int sumlen;
3029203134Sthompsa
3030203134Sthompsa	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
3031203134Sthompsa
3032209917Sthompsa	switch (USB_GET_STATE(xfer)) {
3033203134Sthompsa	case USB_ST_TRANSFERRED:
3034203134Sthompsa		DPRINTFN(11, "transfer complete: %d "
3035203134Sthompsa		    "bytes @ index %d\n", actlen, index);
3036203134Sthompsa
3037203134Sthompsa		data = usbd_xfer_get_priv(xfer);
3038203134Sthompsa		run_tx_free(pq, data, 0);
3039203134Sthompsa		usbd_xfer_set_priv(xfer, NULL);
3040203134Sthompsa
3041203134Sthompsa		/* FALLTHROUGH */
3042203134Sthompsa	case USB_ST_SETUP:
3043203134Sthompsatr_setup:
3044203134Sthompsa		data = STAILQ_FIRST(&pq->tx_qh);
3045209917Sthompsa		if (data == NULL)
3046203134Sthompsa			break;
3047203134Sthompsa
3048203134Sthompsa		STAILQ_REMOVE_HEAD(&pq->tx_qh, next);
3049203134Sthompsa
3050203134Sthompsa		m = data->m;
3051261330Shselasky		size = (sc->mac_ver == 0x5592) ?
3052261330Shselasky		    sizeof(data->desc) + sizeof(uint32_t) : sizeof(data->desc);
3053261076Shselasky		if ((m->m_pkthdr.len +
3054261330Shselasky		    size + 3 + 8) > RUN_MAX_TXSZ) {
3055203134Sthompsa			DPRINTF("data overflow, %u bytes\n",
3056203134Sthompsa			    m->m_pkthdr.len);
3057203134Sthompsa			run_tx_free(pq, data, 1);
3058203134Sthompsa			goto tr_setup;
3059203134Sthompsa		}
3060203134Sthompsa
3061203134Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
3062203134Sthompsa		usbd_copy_in(pc, 0, &data->desc, size);
3063203134Sthompsa		usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len);
3064228508Shselasky		size += m->m_pkthdr.len;
3065228508Shselasky		/*
3066228508Shselasky		 * Align end on a 4-byte boundary, pad 8 bytes (CRC +
3067228508Shselasky		 * 4-byte padding), and be sure to zero those trailing
3068228508Shselasky		 * bytes:
3069228508Shselasky		 */
3070228508Shselasky		usbd_frame_zero(pc, size, ((-size) & 3) + 8);
3071228508Shselasky		size += ((-size) & 3) + 8;
3072203134Sthompsa
3073203134Sthompsa		vap = data->ni->ni_vap;
3074203134Sthompsa		if (ieee80211_radiotap_active_vap(vap)) {
3075203134Sthompsa			struct run_tx_radiotap_header *tap = &sc->sc_txtap;
3076259032Skevlo			struct rt2860_txwi *txwi =
3077208019Sthompsa			    (struct rt2860_txwi *)(&data->desc + sizeof(struct rt2870_txd));
3078203134Sthompsa			tap->wt_flags = 0;
3079203134Sthompsa			tap->wt_rate = rt2860_rates[data->ridx].rate;
3080287554Skevlo			run_get_tsf(sc, &tap->wt_tsf);
3081236439Shselasky			tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
3082236439Shselasky			tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
3083203134Sthompsa			tap->wt_hwqueue = index;
3084208019Sthompsa			if (le16toh(txwi->phy) & RT2860_PHY_SHPRE)
3085203134Sthompsa				tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
3086203134Sthompsa
3087203134Sthompsa			ieee80211_radiotap_tx(vap, m);
3088203134Sthompsa		}
3089203134Sthompsa
3090228508Shselasky		DPRINTFN(11, "sending frame len=%u/%u  @ index %d\n",
3091228508Shselasky		    m->m_pkthdr.len, size, index);
3092203134Sthompsa
3093228508Shselasky		usbd_xfer_set_frame_len(xfer, 0, size);
3094203134Sthompsa		usbd_xfer_set_priv(xfer, data);
3095203134Sthompsa		usbd_transfer_submit(xfer);
3096287197Sglebius		run_start(sc);
3097203134Sthompsa
3098203134Sthompsa		break;
3099203134Sthompsa
3100203134Sthompsa	default:
3101203134Sthompsa		DPRINTF("USB transfer error, %s\n",
3102203134Sthompsa		    usbd_errstr(error));
3103203134Sthompsa
3104203134Sthompsa		data = usbd_xfer_get_priv(xfer);
3105203134Sthompsa
3106203134Sthompsa		if (data != NULL) {
3107208019Sthompsa			if(data->ni != NULL)
3108208019Sthompsa				vap = data->ni->ni_vap;
3109203134Sthompsa			run_tx_free(pq, data, error);
3110203134Sthompsa			usbd_xfer_set_priv(xfer, NULL);
3111203134Sthompsa		}
3112287197Sglebius
3113209917Sthompsa		if (vap == NULL)
3114208019Sthompsa			vap = TAILQ_FIRST(&ic->ic_vaps);
3115203134Sthompsa
3116203134Sthompsa		if (error != USB_ERR_CANCELLED) {
3117203134Sthompsa			if (error == USB_ERR_TIMEOUT) {
3118203134Sthompsa				device_printf(sc->sc_dev, "device timeout\n");
3119208019Sthompsa				uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
3120208019Sthompsa				DPRINTF("cmdq_store=%d\n", i);
3121208019Sthompsa				sc->cmdq[i].func = run_usb_timeout_cb;
3122208019Sthompsa				sc->cmdq[i].arg0 = vap;
3123208019Sthompsa				ieee80211_runtask(ic, &sc->cmdq_task);
3124203134Sthompsa			}
3125203134Sthompsa
3126203134Sthompsa			/*
3127203134Sthompsa			 * Try to clear stall first, also if other
3128203134Sthompsa			 * errors occur, hence clearing stall
3129203134Sthompsa			 * introduces a 50 ms delay:
3130203134Sthompsa			 */
3131203134Sthompsa			usbd_xfer_set_stall(xfer);
3132203134Sthompsa			goto tr_setup;
3133203134Sthompsa		}
3134203134Sthompsa		break;
3135203134Sthompsa	}
3136203134Sthompsa}
3137203134Sthompsa
3138203134Sthompsastatic void
3139203134Sthompsarun_bulk_tx_callback0(struct usb_xfer *xfer, usb_error_t error)
3140203134Sthompsa{
3141203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 0);
3142203134Sthompsa}
3143203134Sthompsa
3144203134Sthompsastatic void
3145203134Sthompsarun_bulk_tx_callback1(struct usb_xfer *xfer, usb_error_t error)
3146203134Sthompsa{
3147203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 1);
3148203134Sthompsa}
3149203134Sthompsa
3150203134Sthompsastatic void
3151203134Sthompsarun_bulk_tx_callback2(struct usb_xfer *xfer, usb_error_t error)
3152203134Sthompsa{
3153203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 2);
3154203134Sthompsa}
3155203134Sthompsa
3156203134Sthompsastatic void
3157203134Sthompsarun_bulk_tx_callback3(struct usb_xfer *xfer, usb_error_t error)
3158203134Sthompsa{
3159203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 3);
3160203134Sthompsa}
3161203134Sthompsa
3162203134Sthompsastatic void
3163203134Sthompsarun_bulk_tx_callback4(struct usb_xfer *xfer, usb_error_t error)
3164203134Sthompsa{
3165203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 4);
3166203134Sthompsa}
3167203134Sthompsa
3168203134Sthompsastatic void
3169203134Sthompsarun_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error)
3170203134Sthompsa{
3171203134Sthompsa	run_bulk_tx_callbackN(xfer, error, 5);
3172203134Sthompsa}
3173203134Sthompsa
3174203134Sthompsastatic void
3175208019Sthompsarun_set_tx_desc(struct run_softc *sc, struct run_tx_data *data)
3176203134Sthompsa{
3177203134Sthompsa	struct mbuf *m = data->m;
3178287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3179208019Sthompsa	struct ieee80211vap *vap = data->ni->ni_vap;
3180203134Sthompsa	struct ieee80211_frame *wh;
3181203134Sthompsa	struct rt2870_txd *txd;
3182203134Sthompsa	struct rt2860_txwi *txwi;
3183259032Skevlo	uint16_t xferlen, txwisize;
3184208019Sthompsa	uint16_t mcs;
3185203134Sthompsa	uint8_t ridx = data->ridx;
3186208019Sthompsa	uint8_t pad;
3187203134Sthompsa
3188203134Sthompsa	/* get MCS code from rate index */
3189208019Sthompsa	mcs = rt2860_rates[ridx].mcs;
3190203134Sthompsa
3191259032Skevlo	txwisize = (sc->mac_ver == 0x5592) ?
3192259032Skevlo	    sizeof(*txwi) + sizeof(uint32_t) : sizeof(*txwi);
3193259032Skevlo	xferlen = txwisize + m->m_pkthdr.len;
3194203134Sthompsa
3195203134Sthompsa	/* roundup to 32-bit alignment */
3196203134Sthompsa	xferlen = (xferlen + 3) & ~3;
3197203134Sthompsa
3198203134Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3199203134Sthompsa	txd->len = htole16(xferlen);
3200203134Sthompsa
3201208019Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3202208019Sthompsa
3203208019Sthompsa	/*
3204208019Sthompsa	 * Ether both are true or both are false, the header
3205208019Sthompsa	 * are nicely aligned to 32-bit. So, no L2 padding.
3206208019Sthompsa	 */
3207208019Sthompsa	if(IEEE80211_HAS_ADDR4(wh) == IEEE80211_QOS_HAS_SEQ(wh))
3208208019Sthompsa		pad = 0;
3209208019Sthompsa	else
3210208019Sthompsa		pad = 2;
3211208019Sthompsa
3212203134Sthompsa	/* setup TX Wireless Information */
3213203134Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3214203134Sthompsa	txwi->len = htole16(m->m_pkthdr.len - pad);
3215203134Sthompsa	if (rt2860_rates[ridx].phy == IEEE80211_T_DS) {
3216270192Skevlo		mcs |= RT2860_PHY_CCK;
3217203134Sthompsa		if (ridx != RT2860_RIDX_CCK1 &&
3218203134Sthompsa		    (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
3219203134Sthompsa			mcs |= RT2860_PHY_SHPRE;
3220203134Sthompsa	} else
3221270192Skevlo		mcs |= RT2860_PHY_OFDM;
3222270192Skevlo	txwi->phy = htole16(mcs);
3223203134Sthompsa
3224203134Sthompsa	/* check if RTS/CTS or CTS-to-self protection is required */
3225203134Sthompsa	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
3226203134Sthompsa	    (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold ||
3227203134Sthompsa	     ((ic->ic_flags & IEEE80211_F_USEPROT) &&
3228203134Sthompsa	      rt2860_rates[ridx].phy == IEEE80211_T_OFDM)))
3229208019Sthompsa		txwi->txop |= RT2860_TX_TXOP_HT;
3230203134Sthompsa	else
3231208019Sthompsa		txwi->txop |= RT2860_TX_TXOP_BACKOFF;
3232209144Sthompsa
3233209917Sthompsa	if (vap->iv_opmode != IEEE80211_M_STA && !IEEE80211_QOS_HAS_SEQ(wh))
3234209144Sthompsa		txwi->xflags |= RT2860_TX_NSEQ;
3235203134Sthompsa}
3236203134Sthompsa
3237203134Sthompsa/* This function must be called locked */
3238203134Sthompsastatic int
3239203134Sthompsarun_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
3240203134Sthompsa{
3241287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3242208019Sthompsa	struct ieee80211vap *vap = ni->ni_vap;
3243203134Sthompsa	struct ieee80211_frame *wh;
3244208019Sthompsa	struct ieee80211_channel *chan;
3245203134Sthompsa	const struct ieee80211_txparam *tp;
3246287552Skevlo	struct run_node *rn = RUN_NODE(ni);
3247203134Sthompsa	struct run_tx_data *data;
3248208019Sthompsa	struct rt2870_txd *txd;
3249208019Sthompsa	struct rt2860_txwi *txwi;
3250203134Sthompsa	uint16_t qos;
3251203134Sthompsa	uint16_t dur;
3252208019Sthompsa	uint16_t qid;
3253203134Sthompsa	uint8_t type;
3254203134Sthompsa	uint8_t tid;
3255208019Sthompsa	uint8_t ridx;
3256208019Sthompsa	uint8_t ctl_ridx;
3257203134Sthompsa	uint8_t qflags;
3258203134Sthompsa	uint8_t xflags = 0;
3259203134Sthompsa	int hasqos;
3260203134Sthompsa
3261203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3262203134Sthompsa
3263203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3264203134Sthompsa
3265203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3266203134Sthompsa
3267203134Sthompsa	/*
3268203134Sthompsa	 * There are 7 bulk endpoints: 1 for RX
3269203134Sthompsa	 * and 6 for TX (4 EDCAs + HCCA + Prio).
3270203134Sthompsa	 * Update 03-14-2009:  some devices like the Planex GW-US300MiniS
3271203134Sthompsa	 * seem to have only 4 TX bulk endpoints (Fukaumi Naoki).
3272203134Sthompsa	 */
3273203134Sthompsa	if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) {
3274203134Sthompsa		uint8_t *frm;
3275203134Sthompsa
3276203134Sthompsa		if(IEEE80211_HAS_ADDR4(wh))
3277203134Sthompsa			frm = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos;
3278203134Sthompsa		else
3279203134Sthompsa			frm =((struct ieee80211_qosframe *)wh)->i_qos;
3280203134Sthompsa
3281203134Sthompsa		qos = le16toh(*(const uint16_t *)frm);
3282203134Sthompsa		tid = qos & IEEE80211_QOS_TID;
3283203134Sthompsa		qid = TID_TO_WME_AC(tid);
3284203134Sthompsa	} else {
3285203134Sthompsa		qos = 0;
3286203134Sthompsa		tid = 0;
3287203134Sthompsa		qid = WME_AC_BE;
3288203134Sthompsa	}
3289203134Sthompsa	qflags = (qid < 4) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA;
3290203134Sthompsa
3291203134Sthompsa	DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n",
3292203134Sthompsa	    qos, qid, tid, qflags);
3293203134Sthompsa
3294208019Sthompsa	chan = (ni->ni_chan != IEEE80211_CHAN_ANYC)?ni->ni_chan:ic->ic_curchan;
3295208019Sthompsa	tp = &vap->iv_txparms[ieee80211_chan2mode(chan)];
3296203134Sthompsa
3297203134Sthompsa	/* pickup a rate index */
3298203134Sthompsa	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
3299270192Skevlo	    type != IEEE80211_FC0_TYPE_DATA || m->m_flags & M_EAPOL) {
3300203134Sthompsa		ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
3301203134Sthompsa		    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
3302203134Sthompsa		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
3303203134Sthompsa	} else {
3304208019Sthompsa		if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
3305208019Sthompsa			ridx = rn->fix_ridx;
3306208019Sthompsa		else
3307208019Sthompsa			ridx = rn->amrr_ridx;
3308203134Sthompsa		ctl_ridx = rt2860_rates[ridx].ctl_ridx;
3309203134Sthompsa	}
3310203134Sthompsa
3311203134Sthompsa	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
3312203134Sthompsa	    (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) !=
3313203134Sthompsa	     IEEE80211_QOS_ACKPOLICY_NOACK)) {
3314209144Sthompsa		xflags |= RT2860_TX_ACK;
3315203134Sthompsa		if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
3316208019Sthompsa			dur = rt2860_rates[ctl_ridx].sp_ack_dur;
3317203134Sthompsa		else
3318208019Sthompsa			dur = rt2860_rates[ctl_ridx].lp_ack_dur;
3319258919Shselasky		USETW(wh->i_dur, dur);
3320203134Sthompsa	}
3321203134Sthompsa
3322203134Sthompsa	/* reserve slots for mgmt packets, just in case */
3323203134Sthompsa	if (sc->sc_epq[qid].tx_nfree < 3) {
3324203134Sthompsa		DPRINTFN(10, "tx ring %d is full\n", qid);
3325203134Sthompsa		return (-1);
3326203134Sthompsa	}
3327203134Sthompsa
3328203134Sthompsa	data = STAILQ_FIRST(&sc->sc_epq[qid].tx_fh);
3329203134Sthompsa	STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next);
3330203134Sthompsa	sc->sc_epq[qid].tx_nfree--;
3331203134Sthompsa
3332208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3333208019Sthompsa	txd->flags = qflags;
3334208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3335208019Sthompsa	txwi->xflags = xflags;
3336259032Skevlo	if (IEEE80211_IS_MULTICAST(wh->i_addr1))
3337245047Shselasky		txwi->wcid = 0;
3338259032Skevlo	else
3339245047Shselasky		txwi->wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
3340245047Shselasky		    1 : RUN_AID2WCID(ni->ni_associd);
3341259032Skevlo
3342208019Sthompsa	/* clear leftover garbage bits */
3343208019Sthompsa	txwi->flags = 0;
3344208019Sthompsa	txwi->txop = 0;
3345208019Sthompsa
3346203134Sthompsa	data->m = m;
3347203134Sthompsa	data->ni = ni;
3348203134Sthompsa	data->ridx = ridx;
3349203134Sthompsa
3350208019Sthompsa	run_set_tx_desc(sc, data);
3351203134Sthompsa
3352208019Sthompsa	/*
3353208019Sthompsa	 * The chip keeps track of 2 kind of Tx stats,
3354208019Sthompsa	 *  * TX_STAT_FIFO, for per WCID stats, and
3355208019Sthompsa	 *  * TX_STA_CNT0 for all-TX-in-one stats.
3356208019Sthompsa	 *
3357208019Sthompsa	 * To use FIFO stats, we need to store MCS into the driver-private
3358208019Sthompsa 	 * PacketID field. So that, we can tell whose stats when we read them.
3359208019Sthompsa 	 * We add 1 to the MCS because setting the PacketID field to 0 means
3360208019Sthompsa 	 * that we don't want feedback in TX_STAT_FIFO.
3361208019Sthompsa 	 * And, that's what we want for STA mode, since TX_STA_CNT0 does the job.
3362208019Sthompsa 	 *
3363208019Sthompsa 	 * FIFO stats doesn't count Tx with WCID 0xff, so we do this in run_tx().
3364208019Sthompsa 	 */
3365209917Sthompsa	if (sc->rvp_cnt > 1 || vap->iv_opmode == IEEE80211_M_HOSTAP ||
3366209917Sthompsa	    vap->iv_opmode == IEEE80211_M_MBSS) {
3367208019Sthompsa		uint16_t pid = (rt2860_rates[ridx].mcs + 1) & 0xf;
3368208019Sthompsa		txwi->len |= htole16(pid << RT2860_TX_PID_SHIFT);
3369208019Sthompsa
3370208019Sthompsa		/*
3371208019Sthompsa		 * Unlike PCI based devices, we don't get any interrupt from
3372208019Sthompsa		 * USB devices, so we simulate FIFO-is-full interrupt here.
3373298932Spfg		 * Ralink recommends to drain FIFO stats every 100 ms, but 16 slots
3374208019Sthompsa		 * quickly get fulled. To prevent overflow, increment a counter on
3375208019Sthompsa		 * every FIFO stat request, so we know how many slots are left.
3376208019Sthompsa		 * We do this only in HOSTAP or multiple vap mode since FIFO stats
3377208019Sthompsa		 * are used only in those modes.
3378208019Sthompsa		 * We just drain stats. AMRR gets updated every 1 sec by
3379208019Sthompsa		 * run_ratectl_cb() via callout.
3380208019Sthompsa		 * Call it early. Otherwise overflow.
3381208019Sthompsa		 */
3382209917Sthompsa		if (sc->fifo_cnt++ == 10) {
3383208019Sthompsa			/*
3384208019Sthompsa			 * With multiple vaps or if_bridge, if_start() is called
3385208019Sthompsa			 * with a non-sleepable lock, tcpinp. So, need to defer.
3386208019Sthompsa			 */
3387208019Sthompsa			uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store);
3388208019Sthompsa			DPRINTFN(6, "cmdq_store=%d\n", i);
3389208019Sthompsa			sc->cmdq[i].func = run_drain_fifo;
3390208019Sthompsa			sc->cmdq[i].arg0 = sc;
3391208019Sthompsa			ieee80211_runtask(ic, &sc->cmdq_task);
3392208019Sthompsa		}
3393208019Sthompsa	}
3394208019Sthompsa
3395203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next);
3396203134Sthompsa
3397203134Sthompsa	usbd_transfer_start(sc->sc_xfer[qid]);
3398203134Sthompsa
3399258840Skevlo	DPRINTFN(8, "sending data frame len=%d rate=%d qid=%d\n",
3400259032Skevlo	    m->m_pkthdr.len + (int)(sizeof(struct rt2870_txd) +
3401259046Shselasky	    sizeof(struct rt2860_txwi)), rt2860_rates[ridx].rate, qid);
3402203134Sthompsa
3403203134Sthompsa	return (0);
3404203134Sthompsa}
3405203134Sthompsa
3406203134Sthompsastatic int
3407203134Sthompsarun_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
3408203134Sthompsa{
3409287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
3410287552Skevlo	struct run_node *rn = RUN_NODE(ni);
3411203134Sthompsa	struct run_tx_data *data;
3412203134Sthompsa	struct ieee80211_frame *wh;
3413208019Sthompsa	struct rt2870_txd *txd;
3414208019Sthompsa	struct rt2860_txwi *txwi;
3415203134Sthompsa	uint16_t dur;
3416208019Sthompsa	uint8_t ridx = rn->mgt_ridx;
3417203134Sthompsa	uint8_t type;
3418203134Sthompsa	uint8_t xflags = 0;
3419208019Sthompsa	uint8_t wflags = 0;
3420203134Sthompsa
3421203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3422203134Sthompsa
3423203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3424203134Sthompsa
3425203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3426203134Sthompsa
3427208019Sthompsa	/* tell hardware to add timestamp for probe responses */
3428208019Sthompsa	if ((wh->i_fc[0] &
3429208019Sthompsa	    (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==
3430208019Sthompsa	    (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP))
3431208019Sthompsa		wflags |= RT2860_TX_TS;
3432208019Sthompsa	else if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3433203134Sthompsa		xflags |= RT2860_TX_ACK;
3434203134Sthompsa
3435208019Sthompsa		dur = ieee80211_ack_duration(ic->ic_rt, rt2860_rates[ridx].rate,
3436203134Sthompsa		    ic->ic_flags & IEEE80211_F_SHPREAMBLE);
3437258919Shselasky		USETW(wh->i_dur, dur);
3438203134Sthompsa	}
3439203134Sthompsa
3440287197Sglebius	if (sc->sc_epq[0].tx_nfree == 0)
3441203134Sthompsa		/* let caller free mbuf */
3442203134Sthompsa		return (EIO);
3443203134Sthompsa	data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3444203134Sthompsa	STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3445203134Sthompsa	sc->sc_epq[0].tx_nfree--;
3446203134Sthompsa
3447208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3448208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3449208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3450208019Sthompsa	txwi->wcid = 0xff;
3451208019Sthompsa	txwi->flags = wflags;
3452208019Sthompsa	txwi->xflags = xflags;
3453208019Sthompsa	txwi->txop = 0;	/* clear leftover garbage bits */
3454208019Sthompsa
3455203134Sthompsa	data->m = m;
3456203134Sthompsa	data->ni = ni;
3457203134Sthompsa	data->ridx = ridx;
3458203134Sthompsa
3459208019Sthompsa	run_set_tx_desc(sc, data);
3460203134Sthompsa
3461203134Sthompsa	DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m->m_pkthdr.len +
3462258840Skevlo	    (int)(sizeof(struct rt2870_txd) + sizeof(struct rt2860_txwi)),
3463208019Sthompsa	    rt2860_rates[ridx].rate);
3464203134Sthompsa
3465203134Sthompsa	STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3466203134Sthompsa
3467203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3468203134Sthompsa
3469203134Sthompsa	return (0);
3470203134Sthompsa}
3471203134Sthompsa
3472203134Sthompsastatic int
3473203134Sthompsarun_sendprot(struct run_softc *sc,
3474203134Sthompsa    const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate)
3475203134Sthompsa{
3476203134Sthompsa	struct ieee80211com *ic = ni->ni_ic;
3477203134Sthompsa	struct ieee80211_frame *wh;
3478203134Sthompsa	struct run_tx_data *data;
3479208019Sthompsa	struct rt2870_txd *txd;
3480208019Sthompsa	struct rt2860_txwi *txwi;
3481203134Sthompsa	struct mbuf *mprot;
3482203134Sthompsa	int ridx;
3483203134Sthompsa	int protrate;
3484203134Sthompsa	int ackrate;
3485203134Sthompsa	int pktlen;
3486203134Sthompsa	int isshort;
3487203134Sthompsa	uint16_t dur;
3488203134Sthompsa	uint8_t type;
3489208019Sthompsa	uint8_t wflags = 0;
3490208019Sthompsa	uint8_t xflags = 0;
3491203134Sthompsa
3492203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3493203134Sthompsa
3494203134Sthompsa	KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY,
3495203134Sthompsa	    ("protection %d", prot));
3496203134Sthompsa
3497203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3498203134Sthompsa	pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN;
3499203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3500203134Sthompsa
3501203134Sthompsa	protrate = ieee80211_ctl_rate(ic->ic_rt, rate);
3502203134Sthompsa	ackrate = ieee80211_ack_rate(ic->ic_rt, rate);
3503203134Sthompsa
3504203134Sthompsa	isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
3505209189Sjkim	dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort)
3506203134Sthompsa	    + ieee80211_ack_duration(ic->ic_rt, rate, isshort);
3507203134Sthompsa	wflags = RT2860_TX_FRAG;
3508203134Sthompsa
3509203134Sthompsa	/* check that there are free slots before allocating the mbuf */
3510287197Sglebius	if (sc->sc_epq[0].tx_nfree == 0)
3511203134Sthompsa		/* let caller free mbuf */
3512203134Sthompsa		return (ENOBUFS);
3513203134Sthompsa
3514203134Sthompsa	if (prot == IEEE80211_PROT_RTSCTS) {
3515203134Sthompsa		/* NB: CTS is the same size as an ACK */
3516203134Sthompsa		dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort);
3517208019Sthompsa		xflags |= RT2860_TX_ACK;
3518203134Sthompsa		mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur);
3519203134Sthompsa	} else {
3520203134Sthompsa		mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur);
3521203134Sthompsa	}
3522203134Sthompsa	if (mprot == NULL) {
3523287197Sglebius		if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1);
3524203134Sthompsa		DPRINTF("could not allocate mbuf\n");
3525203134Sthompsa		return (ENOBUFS);
3526203134Sthompsa	}
3527203134Sthompsa
3528203134Sthompsa        data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3529203134Sthompsa        STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3530203134Sthompsa        sc->sc_epq[0].tx_nfree--;
3531203134Sthompsa
3532208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3533208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3534208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3535208019Sthompsa	txwi->wcid = 0xff;
3536208019Sthompsa	txwi->flags = wflags;
3537208019Sthompsa	txwi->xflags = xflags;
3538208019Sthompsa	txwi->txop = 0;	/* clear leftover garbage bits */
3539208019Sthompsa
3540203134Sthompsa	data->m = mprot;
3541203134Sthompsa	data->ni = ieee80211_ref_node(ni);
3542203134Sthompsa
3543203134Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
3544203134Sthompsa		if (rt2860_rates[ridx].rate == protrate)
3545203134Sthompsa			break;
3546203134Sthompsa	data->ridx = ridx;
3547203134Sthompsa
3548208019Sthompsa	run_set_tx_desc(sc, data);
3549203134Sthompsa
3550203134Sthompsa        DPRINTFN(1, "sending prot len=%u rate=%u\n",
3551203134Sthompsa            m->m_pkthdr.len, rate);
3552203134Sthompsa
3553203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3554203134Sthompsa
3555203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3556203134Sthompsa
3557203134Sthompsa	return (0);
3558203134Sthompsa}
3559203134Sthompsa
3560203134Sthompsastatic int
3561203134Sthompsarun_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni,
3562203134Sthompsa    const struct ieee80211_bpf_params *params)
3563203134Sthompsa{
3564203134Sthompsa	struct ieee80211com *ic = ni->ni_ic;
3565203134Sthompsa	struct ieee80211_frame *wh;
3566203134Sthompsa	struct run_tx_data *data;
3567208019Sthompsa	struct rt2870_txd *txd;
3568208019Sthompsa	struct rt2860_txwi *txwi;
3569203134Sthompsa	uint8_t type;
3570208019Sthompsa	uint8_t ridx;
3571208019Sthompsa	uint8_t rate;
3572208019Sthompsa	uint8_t opflags = 0;
3573208019Sthompsa	uint8_t xflags = 0;
3574203134Sthompsa	int error;
3575203134Sthompsa
3576203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
3577203134Sthompsa
3578203134Sthompsa	KASSERT(params != NULL, ("no raw xmit params"));
3579203134Sthompsa
3580203134Sthompsa	wh = mtod(m, struct ieee80211_frame *);
3581203134Sthompsa	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3582203134Sthompsa
3583203134Sthompsa	rate = params->ibp_rate0;
3584203134Sthompsa	if (!ieee80211_isratevalid(ic->ic_rt, rate)) {
3585203134Sthompsa		/* let caller free mbuf */
3586203134Sthompsa		return (EINVAL);
3587203134Sthompsa	}
3588203134Sthompsa
3589203134Sthompsa	if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0)
3590208019Sthompsa		xflags |= RT2860_TX_ACK;
3591203134Sthompsa	if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) {
3592203134Sthompsa		error = run_sendprot(sc, m, ni,
3593203134Sthompsa		    params->ibp_flags & IEEE80211_BPF_RTS ?
3594203134Sthompsa			IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY,
3595203134Sthompsa		    rate);
3596203134Sthompsa		if (error) {
3597203134Sthompsa			/* let caller free mbuf */
3598209917Sthompsa			return error;
3599203134Sthompsa		}
3600203134Sthompsa		opflags |= /*XXX RT2573_TX_LONG_RETRY |*/ RT2860_TX_TXOP_SIFS;
3601203134Sthompsa	}
3602203134Sthompsa
3603203134Sthompsa	if (sc->sc_epq[0].tx_nfree == 0) {
3604203134Sthompsa		/* let caller free mbuf */
3605203134Sthompsa		DPRINTF("sending raw frame, but tx ring is full\n");
3606203134Sthompsa		return (EIO);
3607203134Sthompsa	}
3608203134Sthompsa        data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
3609203134Sthompsa        STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
3610203134Sthompsa        sc->sc_epq[0].tx_nfree--;
3611203134Sthompsa
3612208019Sthompsa	txd = (struct rt2870_txd *)&data->desc;
3613208019Sthompsa	txd->flags = RT2860_TX_QSEL_EDCA;
3614208019Sthompsa	txwi = (struct rt2860_txwi *)(txd + 1);
3615208019Sthompsa	txwi->wcid = 0xff;
3616208019Sthompsa	txwi->xflags = xflags;
3617208019Sthompsa	txwi->txop = opflags;
3618208019Sthompsa	txwi->flags = 0;	/* clear leftover garbage bits */
3619208019Sthompsa
3620203134Sthompsa        data->m = m;
3621203134Sthompsa        data->ni = ni;
3622203134Sthompsa	for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
3623203134Sthompsa		if (rt2860_rates[ridx].rate == rate)
3624203134Sthompsa			break;
3625203134Sthompsa	data->ridx = ridx;
3626203134Sthompsa
3627208019Sthompsa        run_set_tx_desc(sc, data);
3628203134Sthompsa
3629203134Sthompsa        DPRINTFN(10, "sending raw frame len=%u rate=%u\n",
3630203134Sthompsa            m->m_pkthdr.len, rate);
3631203134Sthompsa
3632203134Sthompsa        STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
3633203134Sthompsa
3634203134Sthompsa	usbd_transfer_start(sc->sc_xfer[0]);
3635203134Sthompsa
3636209917Sthompsa        return (0);
3637203134Sthompsa}
3638203134Sthompsa
3639203134Sthompsastatic int
3640203134Sthompsarun_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
3641203134Sthompsa    const struct ieee80211_bpf_params *params)
3642203134Sthompsa{
3643286950Sadrian	struct run_softc *sc = ni->ni_ic->ic_softc;
3644208019Sthompsa	int error = 0;
3645208019Sthompsa
3646203134Sthompsa	RUN_LOCK(sc);
3647203134Sthompsa
3648203134Sthompsa	/* prevent management frames from being sent if we're not ready */
3649287197Sglebius	if (!(sc->sc_flags & RUN_RUNNING)) {
3650287197Sglebius		error = ENETDOWN;
3651208019Sthompsa		goto done;
3652203134Sthompsa	}
3653203134Sthompsa
3654203134Sthompsa	if (params == NULL) {
3655203134Sthompsa		/* tx mgt packet */
3656209917Sthompsa		if ((error = run_tx_mgt(sc, m, ni)) != 0) {
3657203134Sthompsa			DPRINTF("mgt tx failed\n");
3658208019Sthompsa			goto done;
3659203134Sthompsa		}
3660203134Sthompsa	} else {
3661203134Sthompsa		/* tx raw packet with param */
3662209917Sthompsa		if ((error = run_tx_param(sc, m, ni, params)) != 0) {
3663203134Sthompsa			DPRINTF("tx with param failed\n");
3664208019Sthompsa			goto done;
3665203134Sthompsa		}
3666203134Sthompsa	}
3667203134Sthompsa
3668208019Sthompsadone:
3669203134Sthompsa	RUN_UNLOCK(sc);
3670203134Sthompsa
3671209917Sthompsa	if (error != 0) {
3672208019Sthompsa		if(m != NULL)
3673208019Sthompsa			m_freem(m);
3674208019Sthompsa	}
3675203134Sthompsa
3676203134Sthompsa	return (error);
3677203134Sthompsa}
3678203134Sthompsa
3679287197Sglebiusstatic int
3680287197Sglebiusrun_transmit(struct ieee80211com *ic, struct mbuf *m)
3681287197Sglebius{
3682287197Sglebius	struct run_softc *sc = ic->ic_softc;
3683287197Sglebius	int error;
3684287197Sglebius
3685287197Sglebius	RUN_LOCK(sc);
3686287197Sglebius	if ((sc->sc_flags & RUN_RUNNING) == 0) {
3687287197Sglebius		RUN_UNLOCK(sc);
3688287197Sglebius		return (ENXIO);
3689287197Sglebius	}
3690287197Sglebius	error = mbufq_enqueue(&sc->sc_snd, m);
3691287197Sglebius	if (error) {
3692287197Sglebius		RUN_UNLOCK(sc);
3693287197Sglebius		return (error);
3694287197Sglebius	}
3695287197Sglebius	run_start(sc);
3696287197Sglebius	RUN_UNLOCK(sc);
3697287197Sglebius
3698287197Sglebius	return (0);
3699287197Sglebius}
3700287197Sglebius
3701203134Sthompsastatic void
3702287197Sglebiusrun_start(struct run_softc *sc)
3703203134Sthompsa{
3704203134Sthompsa	struct ieee80211_node *ni;
3705203134Sthompsa	struct mbuf *m;
3706203134Sthompsa
3707287197Sglebius	RUN_LOCK_ASSERT(sc, MA_OWNED);
3708203134Sthompsa
3709287197Sglebius	if ((sc->sc_flags & RUN_RUNNING) == 0)
3710203134Sthompsa		return;
3711203134Sthompsa
3712287197Sglebius	while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
3713203134Sthompsa		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
3714203134Sthompsa		if (run_tx(sc, m, ni) != 0) {
3715287197Sglebius			mbufq_prepend(&sc->sc_snd, m);
3716203134Sthompsa			break;
3717203134Sthompsa		}
3718203134Sthompsa	}
3719203134Sthompsa}
3720203134Sthompsa
3721287197Sglebiusstatic void
3722287197Sglebiusrun_parent(struct ieee80211com *ic)
3723203134Sthompsa{
3724286950Sadrian	struct run_softc *sc = ic->ic_softc;
3725208019Sthompsa	int startall = 0;
3726203134Sthompsa
3727246614Shselasky	RUN_LOCK(sc);
3728287197Sglebius	if (sc->sc_detached) {
3729203134Sthompsa		RUN_UNLOCK(sc);
3730287197Sglebius		return;
3731203134Sthompsa	}
3732203134Sthompsa
3733287197Sglebius	if (ic->ic_nrunning > 0) {
3734287197Sglebius		if (!(sc->sc_flags & RUN_RUNNING)) {
3735287197Sglebius			startall = 1;
3736287197Sglebius			run_init_locked(sc);
3737287197Sglebius		} else
3738287197Sglebius			run_update_promisc_locked(sc);
3739287197Sglebius	} else if ((sc->sc_flags & RUN_RUNNING) && sc->rvp_cnt <= 1)
3740287197Sglebius		run_stop(sc);
3741287197Sglebius	RUN_UNLOCK(sc);
3742287197Sglebius	if (startall)
3743287197Sglebius		ieee80211_start_all(ic);
3744203134Sthompsa}
3745203134Sthompsa
3746203134Sthompsastatic void
3747259544Skevlorun_iq_calib(struct run_softc *sc, u_int chan)
3748259544Skevlo{
3749259544Skevlo	uint16_t val;
3750259544Skevlo
3751259544Skevlo	/* Tx0 IQ gain. */
3752259544Skevlo	run_bbp_write(sc, 158, 0x2c);
3753259544Skevlo	if (chan <= 14)
3754259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX0_2GHZ, &val, 1);
3755259544Skevlo	else if (chan <= 64) {
3756259544Skevlo		run_efuse_read(sc,
3757259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH36_TO_CH64_5GHZ,
3758259544Skevlo		    &val, 1);
3759259544Skevlo	} else if (chan <= 138) {
3760259544Skevlo		run_efuse_read(sc,
3761259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH100_TO_CH138_5GHZ,
3762259544Skevlo		    &val, 1);
3763259544Skevlo	} else if (chan <= 165) {
3764259544Skevlo		run_efuse_read(sc,
3765259544Skevlo	    RT5390_EEPROM_IQ_GAIN_CAL_TX0_CH140_TO_CH165_5GHZ,
3766259544Skevlo		    &val, 1);
3767259544Skevlo	} else
3768259544Skevlo		val = 0;
3769259547Skevlo	run_bbp_write(sc, 159, val);
3770259544Skevlo
3771259544Skevlo	/* Tx0 IQ phase. */
3772259544Skevlo	run_bbp_write(sc, 158, 0x2d);
3773259544Skevlo	if (chan <= 14) {
3774259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX0_2GHZ,
3775259544Skevlo		    &val, 1);
3776259544Skevlo	} else if (chan <= 64) {
3777259544Skevlo		run_efuse_read(sc,
3778259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH36_TO_CH64_5GHZ,
3779259544Skevlo		    &val, 1);
3780259544Skevlo	} else if (chan <= 138) {
3781259544Skevlo		run_efuse_read(sc,
3782259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH100_TO_CH138_5GHZ,
3783259544Skevlo		    &val, 1);
3784259544Skevlo	} else if (chan <= 165) {
3785259544Skevlo		run_efuse_read(sc,
3786259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX0_CH140_TO_CH165_5GHZ,
3787259544Skevlo		    &val, 1);
3788259544Skevlo	} else
3789259544Skevlo		val = 0;
3790259547Skevlo	run_bbp_write(sc, 159, val);
3791259544Skevlo
3792259544Skevlo	/* Tx1 IQ gain. */
3793259544Skevlo	run_bbp_write(sc, 158, 0x4a);
3794259544Skevlo	if (chan <= 14) {
3795259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_GAIN_CAL_TX1_2GHZ,
3796259544Skevlo		    &val, 1);
3797259544Skevlo	} else if (chan <= 64) {
3798259544Skevlo		run_efuse_read(sc,
3799259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH36_TO_CH64_5GHZ,
3800259544Skevlo		    &val, 1);
3801259544Skevlo	} else if (chan <= 138) {
3802259544Skevlo		run_efuse_read(sc,
3803259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH100_TO_CH138_5GHZ,
3804259544Skevlo		    &val, 1);
3805259544Skevlo	} else if (chan <= 165) {
3806259544Skevlo		run_efuse_read(sc,
3807259544Skevlo		    RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH140_TO_CH165_5GHZ,
3808259544Skevlo		    &val, 1);
3809259544Skevlo	} else
3810259544Skevlo		val = 0;
3811259547Skevlo	run_bbp_write(sc, 159, val);
3812259544Skevlo
3813259544Skevlo	/* Tx1 IQ phase. */
3814259544Skevlo	run_bbp_write(sc, 158, 0x4b);
3815259544Skevlo	if (chan <= 14) {
3816259544Skevlo		run_efuse_read(sc, RT5390_EEPROM_IQ_PHASE_CAL_TX1_2GHZ,
3817259544Skevlo		    &val, 1);
3818259544Skevlo	} else if (chan <= 64) {
3819259544Skevlo		run_efuse_read(sc,
3820259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH36_TO_CH64_5GHZ,
3821259544Skevlo		    &val, 1);
3822259544Skevlo	} else if (chan <= 138) {
3823259544Skevlo		run_efuse_read(sc,
3824259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH100_TO_CH138_5GHZ,
3825259544Skevlo		    &val, 1);
3826259544Skevlo	} else if (chan <= 165) {
3827259544Skevlo		run_efuse_read(sc,
3828259544Skevlo		    RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH140_TO_CH165_5GHZ,
3829259544Skevlo		    &val, 1);
3830259544Skevlo	} else
3831259544Skevlo		val = 0;
3832259547Skevlo	run_bbp_write(sc, 159, val);
3833259544Skevlo
3834259544Skevlo	/* RF IQ compensation control. */
3835259544Skevlo	run_bbp_write(sc, 158, 0x04);
3836259544Skevlo	run_efuse_read(sc, RT5390_EEPROM_RF_IQ_COMPENSATION_CTL,
3837259544Skevlo	    &val, 1);
3838259547Skevlo	run_bbp_write(sc, 159, val);
3839259544Skevlo
3840259544Skevlo	/* RF IQ imbalance compensation control. */
3841259544Skevlo	run_bbp_write(sc, 158, 0x03);
3842259544Skevlo	run_efuse_read(sc,
3843259544Skevlo	    RT5390_EEPROM_RF_IQ_IMBALANCE_COMPENSATION_CTL, &val, 1);
3844259547Skevlo	run_bbp_write(sc, 159, val);
3845259544Skevlo}
3846259544Skevlo
3847259544Skevlostatic void
3848205042Sthompsarun_set_agc(struct run_softc *sc, uint8_t agc)
3849205042Sthompsa{
3850205042Sthompsa	uint8_t bbp;
3851205042Sthompsa
3852205042Sthompsa	if (sc->mac_ver == 0x3572) {
3853205042Sthompsa		run_bbp_read(sc, 27, &bbp);
3854205042Sthompsa		bbp &= ~(0x3 << 5);
3855205042Sthompsa		run_bbp_write(sc, 27, bbp | 0 << 5);	/* select Rx0 */
3856205042Sthompsa		run_bbp_write(sc, 66, agc);
3857205042Sthompsa		run_bbp_write(sc, 27, bbp | 1 << 5);	/* select Rx1 */
3858205042Sthompsa		run_bbp_write(sc, 66, agc);
3859205042Sthompsa	} else
3860205042Sthompsa		run_bbp_write(sc, 66, agc);
3861205042Sthompsa}
3862205042Sthompsa
3863205042Sthompsastatic void
3864203134Sthompsarun_select_chan_group(struct run_softc *sc, int group)
3865203134Sthompsa{
3866203134Sthompsa	uint32_t tmp;
3867205042Sthompsa	uint8_t agc;
3868203134Sthompsa
3869203134Sthompsa	run_bbp_write(sc, 62, 0x37 - sc->lna[group]);
3870203134Sthompsa	run_bbp_write(sc, 63, 0x37 - sc->lna[group]);
3871203134Sthompsa	run_bbp_write(sc, 64, 0x37 - sc->lna[group]);
3872258082Skevlo	if (sc->mac_ver < 0x3572)
3873257955Skevlo		run_bbp_write(sc, 86, 0x00);
3874203134Sthompsa
3875260219Skevlo	if (sc->mac_ver == 0x3593) {
3876260219Skevlo		run_bbp_write(sc, 77, 0x98);
3877260219Skevlo		run_bbp_write(sc, 83, (group == 0) ? 0x8a : 0x9a);
3878260219Skevlo	}
3879260219Skevlo
3880203134Sthompsa	if (group == 0) {
3881203134Sthompsa		if (sc->ext_2ghz_lna) {
3882257955Skevlo			if (sc->mac_ver >= 0x5390)
3883257955Skevlo				run_bbp_write(sc, 75, 0x52);
3884257955Skevlo			else {
3885257955Skevlo				run_bbp_write(sc, 82, 0x62);
3886257955Skevlo				run_bbp_write(sc, 75, 0x46);
3887257955Skevlo			}
3888203134Sthompsa		} else {
3889259032Skevlo			if (sc->mac_ver == 0x5592) {
3890259032Skevlo				run_bbp_write(sc, 79, 0x1c);
3891259032Skevlo				run_bbp_write(sc, 80, 0x0e);
3892259032Skevlo				run_bbp_write(sc, 81, 0x3a);
3893259032Skevlo				run_bbp_write(sc, 82, 0x62);
3894259032Skevlo
3895259032Skevlo				run_bbp_write(sc, 195, 0x80);
3896259032Skevlo				run_bbp_write(sc, 196, 0xe0);
3897259032Skevlo				run_bbp_write(sc, 195, 0x81);
3898259032Skevlo				run_bbp_write(sc, 196, 0x1f);
3899259032Skevlo				run_bbp_write(sc, 195, 0x82);
3900259032Skevlo				run_bbp_write(sc, 196, 0x38);
3901259032Skevlo				run_bbp_write(sc, 195, 0x83);
3902259032Skevlo				run_bbp_write(sc, 196, 0x32);
3903259032Skevlo				run_bbp_write(sc, 195, 0x85);
3904259032Skevlo				run_bbp_write(sc, 196, 0x28);
3905259032Skevlo				run_bbp_write(sc, 195, 0x86);
3906259032Skevlo				run_bbp_write(sc, 196, 0x19);
3907259032Skevlo			} else if (sc->mac_ver >= 0x5390)
3908257955Skevlo				run_bbp_write(sc, 75, 0x50);
3909257955Skevlo			else {
3910260219Skevlo				run_bbp_write(sc, 82,
3911260219Skevlo				    (sc->mac_ver == 0x3593) ? 0x62 : 0x84);
3912257955Skevlo				run_bbp_write(sc, 75, 0x50);
3913257955Skevlo			}
3914203134Sthompsa		}
3915203134Sthompsa	} else {
3916259032Skevlo		if (sc->mac_ver == 0x5592) {
3917259032Skevlo			run_bbp_write(sc, 79, 0x18);
3918259032Skevlo			run_bbp_write(sc, 80, 0x08);
3919259032Skevlo			run_bbp_write(sc, 81, 0x38);
3920259032Skevlo			run_bbp_write(sc, 82, 0x92);
3921259032Skevlo
3922259032Skevlo			run_bbp_write(sc, 195, 0x80);
3923259032Skevlo			run_bbp_write(sc, 196, 0xf0);
3924259032Skevlo			run_bbp_write(sc, 195, 0x81);
3925259032Skevlo			run_bbp_write(sc, 196, 0x1e);
3926259032Skevlo			run_bbp_write(sc, 195, 0x82);
3927259032Skevlo			run_bbp_write(sc, 196, 0x28);
3928259032Skevlo			run_bbp_write(sc, 195, 0x83);
3929259032Skevlo			run_bbp_write(sc, 196, 0x20);
3930259032Skevlo			run_bbp_write(sc, 195, 0x85);
3931259032Skevlo			run_bbp_write(sc, 196, 0x7f);
3932259032Skevlo			run_bbp_write(sc, 195, 0x86);
3933259032Skevlo			run_bbp_write(sc, 196, 0x7f);
3934259032Skevlo		} else if (sc->mac_ver == 0x3572)
3935205042Sthompsa			run_bbp_write(sc, 82, 0x94);
3936205042Sthompsa		else
3937260219Skevlo			run_bbp_write(sc, 82,
3938260219Skevlo			    (sc->mac_ver == 0x3593) ? 0x82 : 0xf2);
3939205042Sthompsa		if (sc->ext_5ghz_lna)
3940203134Sthompsa			run_bbp_write(sc, 75, 0x46);
3941205042Sthompsa		else
3942203134Sthompsa			run_bbp_write(sc, 75, 0x50);
3943203134Sthompsa	}
3944203134Sthompsa
3945203134Sthompsa	run_read(sc, RT2860_TX_BAND_CFG, &tmp);
3946203134Sthompsa	tmp &= ~(RT2860_5G_BAND_SEL_N | RT2860_5G_BAND_SEL_P);
3947203134Sthompsa	tmp |= (group == 0) ? RT2860_5G_BAND_SEL_N : RT2860_5G_BAND_SEL_P;
3948203134Sthompsa	run_write(sc, RT2860_TX_BAND_CFG, tmp);
3949203134Sthompsa
3950203134Sthompsa	/* enable appropriate Power Amplifiers and Low Noise Amplifiers */
3951208019Sthompsa	tmp = RT2860_RFTR_EN | RT2860_TRSW_EN | RT2860_LNA_PE0_EN;
3952260219Skevlo	if (sc->mac_ver == 0x3593)
3953260219Skevlo		tmp |= 1 << 29 | 1 << 28;
3954208019Sthompsa	if (sc->nrxchains > 1)
3955208019Sthompsa		tmp |= RT2860_LNA_PE1_EN;
3956203134Sthompsa	if (group == 0) {	/* 2GHz */
3957208019Sthompsa		tmp |= RT2860_PA_PE_G0_EN;
3958203134Sthompsa		if (sc->ntxchains > 1)
3959203134Sthompsa			tmp |= RT2860_PA_PE_G1_EN;
3960260219Skevlo		if (sc->mac_ver == 0x3593) {
3961260219Skevlo			if (sc->ntxchains > 2)
3962260219Skevlo				tmp |= 1 << 25;
3963260219Skevlo		}
3964203134Sthompsa	} else {		/* 5GHz */
3965208019Sthompsa		tmp |= RT2860_PA_PE_A0_EN;
3966203134Sthompsa		if (sc->ntxchains > 1)
3967203134Sthompsa			tmp |= RT2860_PA_PE_A1_EN;
3968203134Sthompsa	}
3969205042Sthompsa	if (sc->mac_ver == 0x3572) {
3970205042Sthompsa		run_rt3070_rf_write(sc, 8, 0x00);
3971205042Sthompsa		run_write(sc, RT2860_TX_PIN_CFG, tmp);
3972205042Sthompsa		run_rt3070_rf_write(sc, 8, 0x80);
3973205042Sthompsa	} else
3974205042Sthompsa		run_write(sc, RT2860_TX_PIN_CFG, tmp);
3975203134Sthompsa
3976259032Skevlo	if (sc->mac_ver == 0x5592) {
3977259032Skevlo		run_bbp_write(sc, 195, 0x8d);
3978259032Skevlo		run_bbp_write(sc, 196, 0x1a);
3979259032Skevlo	}
3980259032Skevlo
3981260219Skevlo	if (sc->mac_ver == 0x3593) {
3982260219Skevlo		run_read(sc, RT2860_GPIO_CTRL, &tmp);
3983260219Skevlo		tmp &= ~0x01010000;
3984260219Skevlo		if (group == 0)
3985260219Skevlo			tmp |= 0x00010000;
3986260219Skevlo		tmp = (tmp & ~0x00009090) | 0x00000090;
3987260219Skevlo		run_write(sc, RT2860_GPIO_CTRL, tmp);
3988260219Skevlo	}
3989260219Skevlo
3990203134Sthompsa	/* set initial AGC value */
3991205042Sthompsa	if (group == 0) {	/* 2GHz band */
3992205042Sthompsa		if (sc->mac_ver >= 0x3070)
3993205042Sthompsa			agc = 0x1c + sc->lna[0] * 2;
3994205042Sthompsa		else
3995205042Sthompsa			agc = 0x2e + sc->lna[0];
3996205042Sthompsa	} else {		/* 5GHz band */
3997259032Skevlo		if (sc->mac_ver == 0x5592)
3998259032Skevlo			agc = 0x24 + sc->lna[group] * 2;
3999260219Skevlo		else if (sc->mac_ver == 0x3572 || sc->mac_ver == 0x3593)
4000205042Sthompsa			agc = 0x22 + (sc->lna[group] * 5) / 3;
4001205042Sthompsa		else
4002205042Sthompsa			agc = 0x32 + (sc->lna[group] * 5) / 3;
4003205042Sthompsa	}
4004205042Sthompsa	run_set_agc(sc, agc);
4005203134Sthompsa}
4006203134Sthompsa
4007203134Sthompsastatic void
4008257429Shselaskyrun_rt2870_set_chan(struct run_softc *sc, u_int chan)
4009203134Sthompsa{
4010203134Sthompsa	const struct rfprog *rfprog = rt2860_rf2850;
4011203134Sthompsa	uint32_t r2, r3, r4;
4012203134Sthompsa	int8_t txpow1, txpow2;
4013203134Sthompsa	int i;
4014203134Sthompsa
4015203134Sthompsa	/* find the settings for this channel (we know it exists) */
4016203134Sthompsa	for (i = 0; rfprog[i].chan != chan; i++);
4017203134Sthompsa
4018203134Sthompsa	r2 = rfprog[i].r2;
4019203134Sthompsa	if (sc->ntxchains == 1)
4020258732Skevlo		r2 |= 1 << 14;		/* 1T: disable Tx chain 2 */
4021203134Sthompsa	if (sc->nrxchains == 1)
4022258732Skevlo		r2 |= 1 << 17 | 1 << 6;	/* 1R: disable Rx chains 2 & 3 */
4023203134Sthompsa	else if (sc->nrxchains == 2)
4024258732Skevlo		r2 |= 1 << 6;		/* 2R: disable Rx chain 3 */
4025203134Sthompsa
4026203134Sthompsa	/* use Tx power values from EEPROM */
4027203134Sthompsa	txpow1 = sc->txpow1[i];
4028203134Sthompsa	txpow2 = sc->txpow2[i];
4029258732Skevlo
4030258732Skevlo	/* Initialize RF R3 and R4. */
4031258732Skevlo	r3 = rfprog[i].r3 & 0xffffc1ff;
4032258732Skevlo	r4 = (rfprog[i].r4 & ~(0x001f87c0)) | (sc->freq << 15);
4033203134Sthompsa	if (chan > 14) {
4034258732Skevlo		if (txpow1 >= 0) {
4035258732Skevlo			txpow1 = (txpow1 > 0xf) ? (0xf) : (txpow1);
4036258732Skevlo			r3 |= (txpow1 << 10) | (1 << 9);
4037258732Skevlo		} else {
4038258732Skevlo			txpow1 += 7;
4039258732Skevlo
4040258732Skevlo			/* txpow1 is not possible larger than 15. */
4041258732Skevlo			r3 |= (txpow1 << 10);
4042258732Skevlo		}
4043258732Skevlo		if (txpow2 >= 0) {
4044258732Skevlo			txpow2 = (txpow2 > 0xf) ? (0xf) : (txpow2);
4045258921Shselasky			r4 |= (txpow2 << 7) | (1 << 6);
4046258732Skevlo		} else {
4047258732Skevlo			txpow2 += 7;
4048258732Skevlo			r4 |= (txpow2 << 7);
4049258732Skevlo		}
4050258732Skevlo	} else {
4051258732Skevlo		/* Set Tx0 power. */
4052258732Skevlo		r3 |= (txpow1 << 9);
4053258732Skevlo
4054258732Skevlo		/* Set frequency offset and Tx1 power. */
4055258732Skevlo		r4 |= (txpow2 << 6);
4056203134Sthompsa	}
4057203134Sthompsa
4058258733Skevlo	run_rt2870_rf_write(sc, rfprog[i].r1);
4059258733Skevlo	run_rt2870_rf_write(sc, r2);
4060258733Skevlo	run_rt2870_rf_write(sc, r3 & ~(1 << 2));
4061258733Skevlo	run_rt2870_rf_write(sc, r4);
4062203134Sthompsa
4063203134Sthompsa	run_delay(sc, 10);
4064203134Sthompsa
4065258733Skevlo	run_rt2870_rf_write(sc, rfprog[i].r1);
4066258733Skevlo	run_rt2870_rf_write(sc, r2);
4067258733Skevlo	run_rt2870_rf_write(sc, r3 | (1 << 2));
4068258733Skevlo	run_rt2870_rf_write(sc, r4);
4069203134Sthompsa
4070203134Sthompsa	run_delay(sc, 10);
4071203134Sthompsa
4072258733Skevlo	run_rt2870_rf_write(sc, rfprog[i].r1);
4073258733Skevlo	run_rt2870_rf_write(sc, r2);
4074258733Skevlo	run_rt2870_rf_write(sc, r3 & ~(1 << 2));
4075258733Skevlo	run_rt2870_rf_write(sc, r4);
4076203134Sthompsa}
4077203134Sthompsa
4078203134Sthompsastatic void
4079257429Shselaskyrun_rt3070_set_chan(struct run_softc *sc, u_int chan)
4080203134Sthompsa{
4081203134Sthompsa	int8_t txpow1, txpow2;
4082203134Sthompsa	uint8_t rf;
4083205042Sthompsa	int i;
4084203134Sthompsa
4085205042Sthompsa	/* find the settings for this channel (we know it exists) */
4086205042Sthompsa	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4087205042Sthompsa
4088203134Sthompsa	/* use Tx power values from EEPROM */
4089205042Sthompsa	txpow1 = sc->txpow1[i];
4090205042Sthompsa	txpow2 = sc->txpow2[i];
4091203134Sthompsa
4092205042Sthompsa	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
4093256720Skevlo
4094256720Skevlo	/* RT3370/RT3390: RF R3 [7:4] is not reserved bits. */
4095256720Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4096256720Skevlo	rf = (rf & ~0x0f) | rt3070_freqs[i].k;
4097256720Skevlo	run_rt3070_rf_write(sc, 3, rf);
4098256720Skevlo
4099203134Sthompsa	run_rt3070_rf_read(sc, 6, &rf);
4100205042Sthompsa	rf = (rf & ~0x03) | rt3070_freqs[i].r;
4101203134Sthompsa	run_rt3070_rf_write(sc, 6, rf);
4102203134Sthompsa
4103203134Sthompsa	/* set Tx0 power */
4104203134Sthompsa	run_rt3070_rf_read(sc, 12, &rf);
4105203134Sthompsa	rf = (rf & ~0x1f) | txpow1;
4106203134Sthompsa	run_rt3070_rf_write(sc, 12, rf);
4107203134Sthompsa
4108203134Sthompsa	/* set Tx1 power */
4109203134Sthompsa	run_rt3070_rf_read(sc, 13, &rf);
4110203134Sthompsa	rf = (rf & ~0x1f) | txpow2;
4111203134Sthompsa	run_rt3070_rf_write(sc, 13, rf);
4112203134Sthompsa
4113203134Sthompsa	run_rt3070_rf_read(sc, 1, &rf);
4114203134Sthompsa	rf &= ~0xfc;
4115203134Sthompsa	if (sc->ntxchains == 1)
4116203134Sthompsa		rf |= 1 << 7 | 1 << 5;	/* 1T: disable Tx chains 2 & 3 */
4117203134Sthompsa	else if (sc->ntxchains == 2)
4118203134Sthompsa		rf |= 1 << 7;		/* 2T: disable Tx chain 3 */
4119203134Sthompsa	if (sc->nrxchains == 1)
4120203134Sthompsa		rf |= 1 << 6 | 1 << 4;	/* 1R: disable Rx chains 2 & 3 */
4121203134Sthompsa	else if (sc->nrxchains == 2)
4122203134Sthompsa		rf |= 1 << 6;		/* 2R: disable Rx chain 3 */
4123203134Sthompsa	run_rt3070_rf_write(sc, 1, rf);
4124203134Sthompsa
4125203134Sthompsa	/* set RF offset */
4126203134Sthompsa	run_rt3070_rf_read(sc, 23, &rf);
4127203134Sthompsa	rf = (rf & ~0x7f) | sc->freq;
4128203134Sthompsa	run_rt3070_rf_write(sc, 23, rf);
4129203134Sthompsa
4130203134Sthompsa	/* program RF filter */
4131205042Sthompsa	run_rt3070_rf_read(sc, 24, &rf);	/* Tx */
4132205042Sthompsa	rf = (rf & ~0x3f) | sc->rf24_20mhz;
4133205042Sthompsa	run_rt3070_rf_write(sc, 24, rf);
4134205042Sthompsa	run_rt3070_rf_read(sc, 31, &rf);	/* Rx */
4135205042Sthompsa	rf = (rf & ~0x3f) | sc->rf24_20mhz;
4136205042Sthompsa	run_rt3070_rf_write(sc, 31, rf);
4137203134Sthompsa
4138203134Sthompsa	/* enable RF tuning */
4139203134Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4140203134Sthompsa	run_rt3070_rf_write(sc, 7, rf | 0x01);
4141203134Sthompsa}
4142203134Sthompsa
4143203134Sthompsastatic void
4144205042Sthompsarun_rt3572_set_chan(struct run_softc *sc, u_int chan)
4145205042Sthompsa{
4146205042Sthompsa	int8_t txpow1, txpow2;
4147205042Sthompsa	uint32_t tmp;
4148205042Sthompsa	uint8_t rf;
4149205042Sthompsa	int i;
4150205042Sthompsa
4151205042Sthompsa	/* find the settings for this channel (we know it exists) */
4152205042Sthompsa	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4153205042Sthompsa
4154205042Sthompsa	/* use Tx power values from EEPROM */
4155205042Sthompsa	txpow1 = sc->txpow1[i];
4156205042Sthompsa	txpow2 = sc->txpow2[i];
4157205042Sthompsa
4158205042Sthompsa	if (chan <= 14) {
4159205042Sthompsa		run_bbp_write(sc, 25, sc->bbp25);
4160205042Sthompsa		run_bbp_write(sc, 26, sc->bbp26);
4161205042Sthompsa	} else {
4162205042Sthompsa		/* enable IQ phase correction */
4163205042Sthompsa		run_bbp_write(sc, 25, 0x09);
4164205042Sthompsa		run_bbp_write(sc, 26, 0xff);
4165205042Sthompsa	}
4166205042Sthompsa
4167205042Sthompsa	run_rt3070_rf_write(sc, 2, rt3070_freqs[i].n);
4168205042Sthompsa	run_rt3070_rf_write(sc, 3, rt3070_freqs[i].k);
4169205042Sthompsa	run_rt3070_rf_read(sc, 6, &rf);
4170205042Sthompsa	rf  = (rf & ~0x0f) | rt3070_freqs[i].r;
4171205042Sthompsa	rf |= (chan <= 14) ? 0x08 : 0x04;
4172205042Sthompsa	run_rt3070_rf_write(sc, 6, rf);
4173205042Sthompsa
4174205042Sthompsa	/* set PLL mode */
4175205042Sthompsa	run_rt3070_rf_read(sc, 5, &rf);
4176205042Sthompsa	rf &= ~(0x08 | 0x04);
4177205042Sthompsa	rf |= (chan <= 14) ? 0x04 : 0x08;
4178205042Sthompsa	run_rt3070_rf_write(sc, 5, rf);
4179205042Sthompsa
4180205042Sthompsa	/* set Tx power for chain 0 */
4181205042Sthompsa	if (chan <= 14)
4182205042Sthompsa		rf = 0x60 | txpow1;
4183205042Sthompsa	else
4184205042Sthompsa		rf = 0xe0 | (txpow1 & 0xc) << 1 | (txpow1 & 0x3);
4185205042Sthompsa	run_rt3070_rf_write(sc, 12, rf);
4186205042Sthompsa
4187205042Sthompsa	/* set Tx power for chain 1 */
4188205042Sthompsa	if (chan <= 14)
4189205042Sthompsa		rf = 0x60 | txpow2;
4190205042Sthompsa	else
4191205042Sthompsa		rf = 0xe0 | (txpow2 & 0xc) << 1 | (txpow2 & 0x3);
4192205042Sthompsa	run_rt3070_rf_write(sc, 13, rf);
4193205042Sthompsa
4194205042Sthompsa	/* set Tx/Rx streams */
4195205042Sthompsa	run_rt3070_rf_read(sc, 1, &rf);
4196205042Sthompsa	rf &= ~0xfc;
4197205042Sthompsa	if (sc->ntxchains == 1)
4198205042Sthompsa		rf |= 1 << 7 | 1 << 5;  /* 1T: disable Tx chains 2 & 3 */
4199205042Sthompsa	else if (sc->ntxchains == 2)
4200205042Sthompsa		rf |= 1 << 7;           /* 2T: disable Tx chain 3 */
4201205042Sthompsa	if (sc->nrxchains == 1)
4202205042Sthompsa		rf |= 1 << 6 | 1 << 4;  /* 1R: disable Rx chains 2 & 3 */
4203205042Sthompsa	else if (sc->nrxchains == 2)
4204205042Sthompsa		rf |= 1 << 6;           /* 2R: disable Rx chain 3 */
4205205042Sthompsa	run_rt3070_rf_write(sc, 1, rf);
4206205042Sthompsa
4207205042Sthompsa	/* set RF offset */
4208205042Sthompsa	run_rt3070_rf_read(sc, 23, &rf);
4209205042Sthompsa	rf = (rf & ~0x7f) | sc->freq;
4210205042Sthompsa	run_rt3070_rf_write(sc, 23, rf);
4211205042Sthompsa
4212205042Sthompsa	/* program RF filter */
4213205042Sthompsa	rf = sc->rf24_20mhz;
4214205042Sthompsa	run_rt3070_rf_write(sc, 24, rf);	/* Tx */
4215205042Sthompsa	run_rt3070_rf_write(sc, 31, rf);	/* Rx */
4216205042Sthompsa
4217205042Sthompsa	/* enable RF tuning */
4218205042Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4219205042Sthompsa	rf = (chan <= 14) ? 0xd8 : ((rf & ~0xc8) | 0x14);
4220205042Sthompsa	run_rt3070_rf_write(sc, 7, rf);
4221205042Sthompsa
4222205042Sthompsa	/* TSSI */
4223205042Sthompsa	rf = (chan <= 14) ? 0xc3 : 0xc0;
4224205042Sthompsa	run_rt3070_rf_write(sc, 9, rf);
4225205042Sthompsa
4226205042Sthompsa	/* set loop filter 1 */
4227205042Sthompsa	run_rt3070_rf_write(sc, 10, 0xf1);
4228205042Sthompsa	/* set loop filter 2 */
4229205042Sthompsa	run_rt3070_rf_write(sc, 11, (chan <= 14) ? 0xb9 : 0x00);
4230205042Sthompsa
4231205042Sthompsa	/* set tx_mx2_ic */
4232205042Sthompsa	run_rt3070_rf_write(sc, 15, (chan <= 14) ? 0x53 : 0x43);
4233205042Sthompsa	/* set tx_mx1_ic */
4234205042Sthompsa	if (chan <= 14)
4235205042Sthompsa		rf = 0x48 | sc->txmixgain_2ghz;
4236205042Sthompsa	else
4237205042Sthompsa		rf = 0x78 | sc->txmixgain_5ghz;
4238205042Sthompsa	run_rt3070_rf_write(sc, 16, rf);
4239205042Sthompsa
4240205042Sthompsa	/* set tx_lo1 */
4241205042Sthompsa	run_rt3070_rf_write(sc, 17, 0x23);
4242205042Sthompsa	/* set tx_lo2 */
4243205042Sthompsa	if (chan <= 14)
4244205042Sthompsa		rf = 0x93;
4245205042Sthompsa	else if (chan <= 64)
4246205042Sthompsa		rf = 0xb7;
4247205042Sthompsa	else if (chan <= 128)
4248205042Sthompsa		rf = 0x74;
4249205042Sthompsa	else
4250205042Sthompsa		rf = 0x72;
4251205042Sthompsa	run_rt3070_rf_write(sc, 19, rf);
4252205042Sthompsa
4253205042Sthompsa	/* set rx_lo1 */
4254205042Sthompsa	if (chan <= 14)
4255205042Sthompsa		rf = 0xb3;
4256205042Sthompsa	else if (chan <= 64)
4257205042Sthompsa		rf = 0xf6;
4258205042Sthompsa	else if (chan <= 128)
4259205042Sthompsa		rf = 0xf4;
4260205042Sthompsa	else
4261205042Sthompsa		rf = 0xf3;
4262205042Sthompsa	run_rt3070_rf_write(sc, 20, rf);
4263205042Sthompsa
4264205042Sthompsa	/* set pfd_delay */
4265205042Sthompsa	if (chan <= 14)
4266205042Sthompsa		rf = 0x15;
4267205042Sthompsa	else if (chan <= 64)
4268205042Sthompsa		rf = 0x3d;
4269205042Sthompsa	else
4270205042Sthompsa		rf = 0x01;
4271205042Sthompsa	run_rt3070_rf_write(sc, 25, rf);
4272205042Sthompsa
4273205042Sthompsa	/* set rx_lo2 */
4274205042Sthompsa	run_rt3070_rf_write(sc, 26, (chan <= 14) ? 0x85 : 0x87);
4275205042Sthompsa	/* set ldo_rf_vc */
4276205042Sthompsa	run_rt3070_rf_write(sc, 27, (chan <= 14) ? 0x00 : 0x01);
4277205042Sthompsa	/* set drv_cc */
4278205042Sthompsa	run_rt3070_rf_write(sc, 29, (chan <= 14) ? 0x9b : 0x9f);
4279205042Sthompsa
4280205042Sthompsa	run_read(sc, RT2860_GPIO_CTRL, &tmp);
4281205042Sthompsa	tmp &= ~0x8080;
4282205042Sthompsa	if (chan <= 14)
4283205042Sthompsa		tmp |= 0x80;
4284205042Sthompsa	run_write(sc, RT2860_GPIO_CTRL, tmp);
4285205042Sthompsa
4286205042Sthompsa	/* enable RF tuning */
4287205042Sthompsa	run_rt3070_rf_read(sc, 7, &rf);
4288205042Sthompsa	run_rt3070_rf_write(sc, 7, rf | 0x01);
4289205042Sthompsa
4290205042Sthompsa	run_delay(sc, 2);
4291205042Sthompsa}
4292205042Sthompsa
4293205042Sthompsastatic void
4294260219Skevlorun_rt3593_set_chan(struct run_softc *sc, u_int chan)
4295260219Skevlo{
4296260219Skevlo	int8_t txpow1, txpow2, txpow3;
4297260219Skevlo	uint8_t h20mhz, rf;
4298260219Skevlo	int i;
4299260219Skevlo
4300260219Skevlo	/* find the settings for this channel (we know it exists) */
4301260219Skevlo	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4302260219Skevlo
4303260219Skevlo	/* use Tx power values from EEPROM */
4304260219Skevlo	txpow1 = sc->txpow1[i];
4305260219Skevlo	txpow2 = sc->txpow2[i];
4306260219Skevlo	txpow3 = (sc->ntxchains == 3) ? sc->txpow3[i] : 0;
4307260219Skevlo
4308260219Skevlo	if (chan <= 14) {
4309260219Skevlo		run_bbp_write(sc, 25, sc->bbp25);
4310260219Skevlo		run_bbp_write(sc, 26, sc->bbp26);
4311260219Skevlo	} else {
4312260219Skevlo		/* Enable IQ phase correction. */
4313260219Skevlo		run_bbp_write(sc, 25, 0x09);
4314260219Skevlo		run_bbp_write(sc, 26, 0xff);
4315260219Skevlo	}
4316260219Skevlo
4317260219Skevlo	run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n);
4318260219Skevlo	run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f);
4319260219Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4320260219Skevlo	rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03);
4321260219Skevlo	run_rt3070_rf_write(sc, 11, rf);
4322260219Skevlo
4323260219Skevlo	/* Set pll_idoh. */
4324260219Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4325260219Skevlo	rf &= ~0x4c;
4326260219Skevlo	rf |= (chan <= 14) ? 0x44 : 0x48;
4327260219Skevlo	run_rt3070_rf_write(sc, 11, rf);
4328260219Skevlo
4329260219Skevlo	if (chan <= 14)
4330260219Skevlo		rf = txpow1 & 0x1f;
4331260219Skevlo	else
4332260219Skevlo		rf = 0x40 | ((txpow1 & 0x18) << 1) | (txpow1 & 0x07);
4333260219Skevlo	run_rt3070_rf_write(sc, 53, rf);
4334260219Skevlo
4335260219Skevlo	if (chan <= 14)
4336260219Skevlo		rf = txpow2 & 0x1f;
4337260219Skevlo	else
4338260219Skevlo		rf = 0x40 | ((txpow2 & 0x18) << 1) | (txpow2 & 0x07);
4339260219Skevlo	run_rt3070_rf_write(sc, 55, rf);
4340260219Skevlo
4341260219Skevlo	if (chan <= 14)
4342260219Skevlo		rf = txpow3 & 0x1f;
4343260219Skevlo	else
4344260219Skevlo		rf = 0x40 | ((txpow3 & 0x18) << 1) | (txpow3 & 0x07);
4345260219Skevlo	run_rt3070_rf_write(sc, 54, rf);
4346260219Skevlo
4347260219Skevlo	rf = RT3070_RF_BLOCK | RT3070_PLL_PD;
4348260219Skevlo	if (sc->ntxchains == 3)
4349260219Skevlo		rf |= RT3070_TX0_PD | RT3070_TX1_PD | RT3070_TX2_PD;
4350260219Skevlo	else
4351260219Skevlo		rf |= RT3070_TX0_PD | RT3070_TX1_PD;
4352260219Skevlo	rf |= RT3070_RX0_PD | RT3070_RX1_PD | RT3070_RX2_PD;
4353260219Skevlo	run_rt3070_rf_write(sc, 1, rf);
4354260219Skevlo
4355260219Skevlo	run_adjust_freq_offset(sc);
4356260219Skevlo
4357260219Skevlo	run_rt3070_rf_write(sc, 31, (chan <= 14) ? 0xa0 : 0x80);
4358260219Skevlo
4359260219Skevlo	h20mhz = (sc->rf24_20mhz & 0x20) >> 5;
4360260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
4361260219Skevlo	rf = (rf & ~0x06) | (h20mhz << 1) | (h20mhz << 2);
4362260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
4363260219Skevlo
4364260219Skevlo	run_rt3070_rf_read(sc, 36, &rf);
4365260219Skevlo	if (chan <= 14)
4366260219Skevlo		rf |= 0x80;
4367260219Skevlo	else
4368260219Skevlo		rf &= ~0x80;
4369260219Skevlo	run_rt3070_rf_write(sc, 36, rf);
4370260219Skevlo
4371260219Skevlo	/* Set vcolo_bs. */
4372260219Skevlo	run_rt3070_rf_write(sc, 34, (chan <= 14) ? 0x3c : 0x20);
4373260219Skevlo	/* Set pfd_delay. */
4374260219Skevlo	run_rt3070_rf_write(sc, 12, (chan <= 14) ? 0x1a : 0x12);
4375260219Skevlo
4376260219Skevlo	/* Set vco bias current control. */
4377260219Skevlo	run_rt3070_rf_read(sc, 6, &rf);
4378260219Skevlo	rf &= ~0xc0;
4379260219Skevlo	if (chan <= 14)
4380260219Skevlo		rf |= 0x40;
4381260219Skevlo	else if (chan <= 128)
4382260219Skevlo		rf |= 0x80;
4383260219Skevlo	else
4384260219Skevlo		rf |= 0x40;
4385260219Skevlo	run_rt3070_rf_write(sc, 6, rf);
4386260219Skevlo
4387260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
4388260219Skevlo	rf = (rf & ~0x18) | 0x10;
4389260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
4390260219Skevlo
4391260219Skevlo	run_rt3070_rf_write(sc, 10, (chan <= 14) ? 0xd3 : 0xd8);
4392260219Skevlo	run_rt3070_rf_write(sc, 13, (chan <= 14) ? 0x12 : 0x23);
4393260219Skevlo
4394260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4395260219Skevlo	rf = (rf & ~0x03) | 0x01;
4396260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
4397260219Skevlo	/* Set tx_mx1_cc. */
4398260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4399260219Skevlo	rf &= ~0x1c;
4400260219Skevlo	rf |= (chan <= 14) ? 0x14 : 0x10;
4401260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
4402260219Skevlo	/* Set tx_mx1_ic. */
4403260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
4404260219Skevlo	rf &= ~0xe0;
4405260219Skevlo	rf |= (chan <= 14) ? 0x60 : 0x40;
4406260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
4407260219Skevlo	/* Set tx_lo1_ic. */
4408260219Skevlo	run_rt3070_rf_read(sc, 49, &rf);
4409260219Skevlo	rf &= ~0x1c;
4410260219Skevlo	rf |= (chan <= 14) ? 0x0c : 0x08;
4411260219Skevlo	run_rt3070_rf_write(sc, 49, rf);
4412260219Skevlo	/* Set tx_lo1_en. */
4413260219Skevlo	run_rt3070_rf_read(sc, 50, &rf);
4414260219Skevlo	run_rt3070_rf_write(sc, 50, rf & ~0x20);
4415260219Skevlo	/* Set drv_cc. */
4416260219Skevlo	run_rt3070_rf_read(sc, 57, &rf);
4417260219Skevlo	rf &= ~0xfc;
4418260219Skevlo	rf |= (chan <= 14) ?  0x6c : 0x3c;
4419260219Skevlo	run_rt3070_rf_write(sc, 57, rf);
4420260219Skevlo	/* Set rx_mix1_ic, rxa_lnactr, lna_vc, lna_inbias_en and lna_en. */
4421260219Skevlo	run_rt3070_rf_write(sc, 44, (chan <= 14) ? 0x93 : 0x9b);
4422260219Skevlo	/* Set drv_gnd_a, tx_vga_cc_a and tx_mx2_gain. */
4423260219Skevlo	run_rt3070_rf_write(sc, 52, (chan <= 14) ? 0x45 : 0x05);
4424260219Skevlo	/* Enable VCO calibration. */
4425260219Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4426260219Skevlo	rf &= ~RT5390_VCOCAL;
4427260219Skevlo	rf |= (chan <= 14) ? RT5390_VCOCAL : 0xbe;
4428260219Skevlo	run_rt3070_rf_write(sc, 3, rf);
4429260219Skevlo
4430260219Skevlo	if (chan <= 14)
4431260219Skevlo		rf = 0x23;
4432260219Skevlo	else if (chan <= 64)
4433260219Skevlo		rf = 0x36;
4434260219Skevlo	else if (chan <= 128)
4435260219Skevlo		rf = 0x32;
4436260219Skevlo	else
4437260219Skevlo		rf = 0x30;
4438260219Skevlo	run_rt3070_rf_write(sc, 39, rf);
4439260219Skevlo	if (chan <= 14)
4440260219Skevlo		rf = 0xbb;
4441260219Skevlo	else if (chan <= 64)
4442260219Skevlo		rf = 0xeb;
4443260219Skevlo	else if (chan <= 128)
4444260219Skevlo		rf = 0xb3;
4445260219Skevlo	else
4446260219Skevlo		rf = 0x9b;
4447260219Skevlo	run_rt3070_rf_write(sc, 45, rf);
4448260219Skevlo
4449260219Skevlo	/* Set FEQ/AEQ control. */
4450260219Skevlo	run_bbp_write(sc, 105, 0x34);
4451260219Skevlo}
4452260219Skevlo
4453260219Skevlostatic void
4454257955Skevlorun_rt5390_set_chan(struct run_softc *sc, u_int chan)
4455257955Skevlo{
4456257955Skevlo	int8_t txpow1, txpow2;
4457257955Skevlo	uint8_t rf;
4458257955Skevlo	int i;
4459257955Skevlo
4460257955Skevlo	/* find the settings for this channel (we know it exists) */
4461257955Skevlo	for (i = 0; rt2860_rf2850[i].chan != chan; i++);
4462257955Skevlo
4463257955Skevlo	/* use Tx power values from EEPROM */
4464257955Skevlo	txpow1 = sc->txpow1[i];
4465257955Skevlo	txpow2 = sc->txpow2[i];
4466257955Skevlo
4467257955Skevlo	run_rt3070_rf_write(sc, 8, rt3070_freqs[i].n);
4468257955Skevlo	run_rt3070_rf_write(sc, 9, rt3070_freqs[i].k & 0x0f);
4469257955Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4470257955Skevlo	rf = (rf & ~0x03) | (rt3070_freqs[i].r & 0x03);
4471257955Skevlo	run_rt3070_rf_write(sc, 11, rf);
4472257955Skevlo
4473257955Skevlo	run_rt3070_rf_read(sc, 49, &rf);
4474257955Skevlo	rf = (rf & ~0x3f) | (txpow1 & 0x3f);
4475257955Skevlo	/* The valid range of the RF R49 is 0x00 to 0x27. */
4476257955Skevlo	if ((rf & 0x3f) > 0x27)
4477257955Skevlo		rf = (rf & ~0x3f) | 0x27;
4478257955Skevlo	run_rt3070_rf_write(sc, 49, rf);
4479257955Skevlo
4480257955Skevlo	if (sc->mac_ver == 0x5392) {
4481257955Skevlo		run_rt3070_rf_read(sc, 50, &rf);
4482257955Skevlo		rf = (rf & ~0x3f) | (txpow2 & 0x3f);
4483257955Skevlo		/* The valid range of the RF R50 is 0x00 to 0x27. */
4484257955Skevlo		if ((rf & 0x3f) > 0x27)
4485257955Skevlo			rf = (rf & ~0x3f) | 0x27;
4486257955Skevlo		run_rt3070_rf_write(sc, 50, rf);
4487257955Skevlo	}
4488257955Skevlo
4489257955Skevlo	run_rt3070_rf_read(sc, 1, &rf);
4490257955Skevlo	rf |= RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD;
4491257955Skevlo	if (sc->mac_ver == 0x5392)
4492257955Skevlo		rf |= RT3070_RX1_PD | RT3070_TX1_PD;
4493257955Skevlo	run_rt3070_rf_write(sc, 1, rf);
4494257955Skevlo
4495257955Skevlo	if (sc->mac_ver != 0x5392) {
4496257955Skevlo		run_rt3070_rf_read(sc, 2, &rf);
4497257955Skevlo		rf |= 0x80;
4498257955Skevlo		run_rt3070_rf_write(sc, 2, rf);
4499257955Skevlo		run_delay(sc, 10);
4500257955Skevlo		rf &= 0x7f;
4501257955Skevlo		run_rt3070_rf_write(sc, 2, rf);
4502257955Skevlo	}
4503257955Skevlo
4504257955Skevlo	run_adjust_freq_offset(sc);
4505257955Skevlo
4506257955Skevlo	if (sc->mac_ver == 0x5392) {
4507257955Skevlo		/* Fix for RT5392C. */
4508257955Skevlo		if (sc->mac_rev >= 0x0223) {
4509259030Skevlo			if (chan <= 4)
4510257955Skevlo				rf = 0x0f;
4511259030Skevlo			else if (chan >= 5 && chan <= 7)
4512257955Skevlo				rf = 0x0e;
4513259030Skevlo			else
4514257955Skevlo				rf = 0x0d;
4515257955Skevlo			run_rt3070_rf_write(sc, 23, rf);
4516257955Skevlo
4517259030Skevlo			if (chan <= 4)
4518257955Skevlo				rf = 0x0c;
4519257955Skevlo			else if (chan == 5)
4520257955Skevlo				rf = 0x0b;
4521259030Skevlo			else if (chan >= 6 && chan <= 7)
4522257955Skevlo				rf = 0x0a;
4523259030Skevlo			else if (chan >= 8 && chan <= 10)
4524257955Skevlo				rf = 0x09;
4525259030Skevlo			else
4526257955Skevlo				rf = 0x08;
4527257955Skevlo			run_rt3070_rf_write(sc, 59, rf);
4528257955Skevlo		} else {
4529259030Skevlo			if (chan <= 11)
4530257955Skevlo				rf = 0x0f;
4531259030Skevlo			else
4532257955Skevlo				rf = 0x0b;
4533257955Skevlo			run_rt3070_rf_write(sc, 59, rf);
4534257955Skevlo		}
4535257955Skevlo	} else {
4536257955Skevlo		/* Fix for RT5390F. */
4537257955Skevlo		if (sc->mac_rev >= 0x0502) {
4538259030Skevlo			if (chan <= 11)
4539257955Skevlo				rf = 0x43;
4540259030Skevlo			else
4541257955Skevlo				rf = 0x23;
4542257955Skevlo			run_rt3070_rf_write(sc, 55, rf);
4543257955Skevlo
4544259030Skevlo			if (chan <= 11)
4545257955Skevlo				rf = 0x0f;
4546257955Skevlo			else if (chan == 12)
4547257955Skevlo				rf = 0x0d;
4548259030Skevlo			else
4549257955Skevlo				rf = 0x0b;
4550257955Skevlo			run_rt3070_rf_write(sc, 59, rf);
4551257955Skevlo		} else {
4552257955Skevlo			run_rt3070_rf_write(sc, 55, 0x44);
4553257955Skevlo			run_rt3070_rf_write(sc, 59, 0x8f);
4554257955Skevlo		}
4555257955Skevlo	}
4556257955Skevlo
4557257955Skevlo	/* Enable VCO calibration. */
4558257955Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4559257955Skevlo	rf |= RT5390_VCOCAL;
4560257955Skevlo	run_rt3070_rf_write(sc, 3, rf);
4561257955Skevlo}
4562257955Skevlo
4563257955Skevlostatic void
4564259032Skevlorun_rt5592_set_chan(struct run_softc *sc, u_int chan)
4565259032Skevlo{
4566259032Skevlo	const struct rt5592_freqs *freqs;
4567259032Skevlo	uint32_t tmp;
4568259032Skevlo	uint8_t reg, rf, txpow_bound;
4569259032Skevlo	int8_t txpow1, txpow2;
4570259032Skevlo	int i;
4571259032Skevlo
4572259032Skevlo	run_read(sc, RT5592_DEBUG_INDEX, &tmp);
4573259032Skevlo	freqs = (tmp & RT5592_SEL_XTAL) ?
4574259032Skevlo	    rt5592_freqs_40mhz : rt5592_freqs_20mhz;
4575259032Skevlo
4576259032Skevlo	/* find the settings for this channel (we know it exists) */
4577259032Skevlo	for (i = 0; rt2860_rf2850[i].chan != chan; i++, freqs++);
4578259032Skevlo
4579259032Skevlo	/* use Tx power values from EEPROM */
4580259032Skevlo	txpow1 = sc->txpow1[i];
4581259032Skevlo	txpow2 = sc->txpow2[i];
4582259032Skevlo
4583259032Skevlo	run_read(sc, RT3070_LDO_CFG0, &tmp);
4584259032Skevlo	tmp &= ~0x1c000000;
4585259032Skevlo	if (chan > 14)
4586259032Skevlo		tmp |= 0x14000000;
4587259032Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
4588259032Skevlo
4589259032Skevlo	/* N setting. */
4590259032Skevlo	run_rt3070_rf_write(sc, 8, freqs->n & 0xff);
4591259032Skevlo	run_rt3070_rf_read(sc, 9, &rf);
4592259032Skevlo	rf &= ~(1 << 4);
4593259032Skevlo	rf |= ((freqs->n & 0x0100) >> 8) << 4;
4594259032Skevlo	run_rt3070_rf_write(sc, 9, rf);
4595259032Skevlo
4596259032Skevlo	/* K setting. */
4597259032Skevlo	run_rt3070_rf_read(sc, 9, &rf);
4598259032Skevlo	rf &= ~0x0f;
4599259032Skevlo	rf |= (freqs->k & 0x0f);
4600259032Skevlo	run_rt3070_rf_write(sc, 9, rf);
4601259032Skevlo
4602259032Skevlo	/* Mode setting. */
4603259032Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4604259032Skevlo	rf &= ~0x0c;
4605259032Skevlo	rf |= ((freqs->m - 0x8) & 0x3) << 2;
4606259032Skevlo	run_rt3070_rf_write(sc, 11, rf);
4607259032Skevlo	run_rt3070_rf_read(sc, 9, &rf);
4608259032Skevlo	rf &= ~(1 << 7);
4609259032Skevlo	rf |= (((freqs->m - 0x8) & 0x4) >> 2) << 7;
4610259032Skevlo	run_rt3070_rf_write(sc, 9, rf);
4611259032Skevlo
4612259032Skevlo	/* R setting. */
4613259032Skevlo	run_rt3070_rf_read(sc, 11, &rf);
4614259032Skevlo	rf &= ~0x03;
4615259032Skevlo	rf |= (freqs->r - 0x1);
4616259032Skevlo	run_rt3070_rf_write(sc, 11, rf);
4617259032Skevlo
4618259032Skevlo	if (chan <= 14) {
4619259032Skevlo		/* Initialize RF registers for 2GHZ. */
4620259032Skevlo		for (i = 0; i < nitems(rt5592_2ghz_def_rf); i++) {
4621259032Skevlo			run_rt3070_rf_write(sc, rt5592_2ghz_def_rf[i].reg,
4622259032Skevlo			    rt5592_2ghz_def_rf[i].val);
4623259032Skevlo		}
4624259032Skevlo
4625259032Skevlo		rf = (chan <= 10) ? 0x07 : 0x06;
4626259032Skevlo		run_rt3070_rf_write(sc, 23, rf);
4627259032Skevlo		run_rt3070_rf_write(sc, 59, rf);
4628259032Skevlo
4629259032Skevlo		run_rt3070_rf_write(sc, 55, 0x43);
4630259032Skevlo
4631259032Skevlo		/*
4632259032Skevlo		 * RF R49/R50 Tx power ALC code.
4633259032Skevlo		 * G-band bit<7:6>=1:0, bit<5:0> range from 0x0 ~ 0x27.
4634259032Skevlo		 */
4635259032Skevlo		reg = 2;
4636259032Skevlo		txpow_bound = 0x27;
4637259032Skevlo	} else {
4638259032Skevlo		/* Initialize RF registers for 5GHZ. */
4639259032Skevlo		for (i = 0; i < nitems(rt5592_5ghz_def_rf); i++) {
4640259032Skevlo			run_rt3070_rf_write(sc, rt5592_5ghz_def_rf[i].reg,
4641259032Skevlo			    rt5592_5ghz_def_rf[i].val);
4642259032Skevlo		}
4643259032Skevlo		for (i = 0; i < nitems(rt5592_chan_5ghz); i++) {
4644259032Skevlo			if (chan >= rt5592_chan_5ghz[i].firstchan &&
4645259032Skevlo			    chan <= rt5592_chan_5ghz[i].lastchan) {
4646259032Skevlo				run_rt3070_rf_write(sc, rt5592_chan_5ghz[i].reg,
4647259032Skevlo				    rt5592_chan_5ghz[i].val);
4648259032Skevlo			}
4649259032Skevlo		}
4650259032Skevlo
4651259032Skevlo		/*
4652259032Skevlo		 * RF R49/R50 Tx power ALC code.
4653259032Skevlo		 * A-band bit<7:6>=1:1, bit<5:0> range from 0x0 ~ 0x2b.
4654259032Skevlo		 */
4655259032Skevlo		reg = 3;
4656259032Skevlo		txpow_bound = 0x2b;
4657259032Skevlo	}
4658259032Skevlo
4659259032Skevlo	/* RF R49 ch0 Tx power ALC code. */
4660259032Skevlo	run_rt3070_rf_read(sc, 49, &rf);
4661259032Skevlo	rf &= ~0xc0;
4662259032Skevlo	rf |= (reg << 6);
4663259032Skevlo	rf = (rf & ~0x3f) | (txpow1 & 0x3f);
4664259032Skevlo	if ((rf & 0x3f) > txpow_bound)
4665259032Skevlo		rf = (rf & ~0x3f) | txpow_bound;
4666259032Skevlo	run_rt3070_rf_write(sc, 49, rf);
4667259032Skevlo
4668259032Skevlo	/* RF R50 ch1 Tx power ALC code. */
4669259032Skevlo	run_rt3070_rf_read(sc, 50, &rf);
4670259032Skevlo	rf &= ~(1 << 7 | 1 << 6);
4671259032Skevlo	rf |= (reg << 6);
4672259032Skevlo	rf = (rf & ~0x3f) | (txpow2 & 0x3f);
4673259032Skevlo	if ((rf & 0x3f) > txpow_bound)
4674259032Skevlo		rf = (rf & ~0x3f) | txpow_bound;
4675259032Skevlo	run_rt3070_rf_write(sc, 50, rf);
4676259032Skevlo
4677259032Skevlo	/* Enable RF_BLOCK, PLL_PD, RX0_PD, and TX0_PD. */
4678259032Skevlo	run_rt3070_rf_read(sc, 1, &rf);
4679259032Skevlo	rf |= (RT3070_RF_BLOCK | RT3070_PLL_PD | RT3070_RX0_PD | RT3070_TX0_PD);
4680259032Skevlo	if (sc->ntxchains > 1)
4681259032Skevlo		rf |= RT3070_TX1_PD;
4682259032Skevlo	if (sc->nrxchains > 1)
4683259032Skevlo		rf |= RT3070_RX1_PD;
4684259032Skevlo	run_rt3070_rf_write(sc, 1, rf);
4685259032Skevlo
4686259032Skevlo	run_rt3070_rf_write(sc, 6, 0xe4);
4687259032Skevlo
4688259032Skevlo	run_rt3070_rf_write(sc, 30, 0x10);
4689259032Skevlo	run_rt3070_rf_write(sc, 31, 0x80);
4690259032Skevlo	run_rt3070_rf_write(sc, 32, 0x80);
4691259032Skevlo
4692259032Skevlo	run_adjust_freq_offset(sc);
4693259032Skevlo
4694259032Skevlo	/* Enable VCO calibration. */
4695259032Skevlo	run_rt3070_rf_read(sc, 3, &rf);
4696259032Skevlo	rf |= RT5390_VCOCAL;
4697259032Skevlo	run_rt3070_rf_write(sc, 3, rf);
4698259032Skevlo}
4699259032Skevlo
4700259032Skevlostatic void
4701203134Sthompsarun_set_rx_antenna(struct run_softc *sc, int aux)
4702203134Sthompsa{
4703203134Sthompsa	uint32_t tmp;
4704257955Skevlo	uint8_t bbp152;
4705203134Sthompsa
4706203134Sthompsa	if (aux) {
4707257955Skevlo		if (sc->rf_rev == RT5390_RF_5370) {
4708257955Skevlo			run_bbp_read(sc, 152, &bbp152);
4709257955Skevlo			run_bbp_write(sc, 152, bbp152 & ~0x80);
4710259030Skevlo		} else {
4711257955Skevlo			run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 0);
4712257955Skevlo			run_read(sc, RT2860_GPIO_CTRL, &tmp);
4713257955Skevlo			run_write(sc, RT2860_GPIO_CTRL, (tmp & ~0x0808) | 0x08);
4714257955Skevlo		}
4715203134Sthompsa	} else {
4716257955Skevlo		if (sc->rf_rev == RT5390_RF_5370) {
4717257955Skevlo			run_bbp_read(sc, 152, &bbp152);
4718257955Skevlo			run_bbp_write(sc, 152, bbp152 | 0x80);
4719259030Skevlo		} else {
4720257955Skevlo			run_mcu_cmd(sc, RT2860_MCU_CMD_ANTSEL, 1);
4721257955Skevlo			run_read(sc, RT2860_GPIO_CTRL, &tmp);
4722257955Skevlo			run_write(sc, RT2860_GPIO_CTRL, tmp & ~0x0808);
4723257955Skevlo		}
4724203134Sthompsa	}
4725203134Sthompsa}
4726203134Sthompsa
4727203134Sthompsastatic int
4728203134Sthompsarun_set_chan(struct run_softc *sc, struct ieee80211_channel *c)
4729203134Sthompsa{
4730287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
4731257429Shselasky	u_int chan, group;
4732203134Sthompsa
4733203134Sthompsa	chan = ieee80211_chan2ieee(ic, c);
4734203134Sthompsa	if (chan == 0 || chan == IEEE80211_CHAN_ANY)
4735209917Sthompsa		return (EINVAL);
4736203134Sthompsa
4737259032Skevlo	if (sc->mac_ver == 0x5592)
4738259032Skevlo		run_rt5592_set_chan(sc, chan);
4739259032Skevlo	else if (sc->mac_ver >= 0x5390)
4740257955Skevlo		run_rt5390_set_chan(sc, chan);
4741260219Skevlo	else if (sc->mac_ver == 0x3593)
4742260219Skevlo		run_rt3593_set_chan(sc, chan);
4743257955Skevlo	else if (sc->mac_ver == 0x3572)
4744205042Sthompsa		run_rt3572_set_chan(sc, chan);
4745205042Sthompsa	else if (sc->mac_ver >= 0x3070)
4746203134Sthompsa		run_rt3070_set_chan(sc, chan);
4747203134Sthompsa	else
4748203134Sthompsa		run_rt2870_set_chan(sc, chan);
4749203134Sthompsa
4750203134Sthompsa	/* determine channel group */
4751203134Sthompsa	if (chan <= 14)
4752203134Sthompsa		group = 0;
4753203134Sthompsa	else if (chan <= 64)
4754203134Sthompsa		group = 1;
4755203134Sthompsa	else if (chan <= 128)
4756203134Sthompsa		group = 2;
4757203134Sthompsa	else
4758203134Sthompsa		group = 3;
4759203134Sthompsa
4760203134Sthompsa	/* XXX necessary only when group has changed! */
4761203134Sthompsa	run_select_chan_group(sc, group);
4762203134Sthompsa
4763203134Sthompsa	run_delay(sc, 10);
4764203134Sthompsa
4765259545Skevlo	/* Perform IQ calibration. */
4766259544Skevlo	if (sc->mac_ver >= 0x5392)
4767259544Skevlo		run_iq_calib(sc, chan);
4768259544Skevlo
4769209917Sthompsa	return (0);
4770203134Sthompsa}
4771203134Sthompsa
4772203134Sthompsastatic void
4773203134Sthompsarun_set_channel(struct ieee80211com *ic)
4774203134Sthompsa{
4775286950Sadrian	struct run_softc *sc = ic->ic_softc;
4776203134Sthompsa
4777203134Sthompsa	RUN_LOCK(sc);
4778203134Sthompsa	run_set_chan(sc, ic->ic_curchan);
4779203134Sthompsa	RUN_UNLOCK(sc);
4780203134Sthompsa
4781203134Sthompsa	return;
4782203134Sthompsa}
4783203134Sthompsa
4784203134Sthompsastatic void
4785300748Savosrun_getradiocaps(struct ieee80211com *ic,
4786300748Savos    int maxchans, int *nchans, struct ieee80211_channel chans[])
4787300748Savos{
4788300748Savos	struct run_softc *sc = ic->ic_softc;
4789300748Savos	uint8_t bands[IEEE80211_MODE_BYTES];
4790300748Savos
4791300748Savos	memset(bands, 0, sizeof(bands));
4792300748Savos	setbit(bands, IEEE80211_MODE_11B);
4793300748Savos	setbit(bands, IEEE80211_MODE_11G);
4794300748Savos	ieee80211_add_channel_list_2ghz(chans, maxchans, nchans,
4795300748Savos	    run_chan_2ghz, nitems(run_chan_2ghz), bands, 0);
4796300748Savos
4797300748Savos	if (sc->rf_rev == RT2860_RF_2750 || sc->rf_rev == RT2860_RF_2850 ||
4798300748Savos	    sc->rf_rev == RT3070_RF_3052 || sc->rf_rev == RT3593_RF_3053 ||
4799300748Savos	    sc->rf_rev == RT5592_RF_5592) {
4800300748Savos		setbit(bands, IEEE80211_MODE_11A);
4801300748Savos		ieee80211_add_channel_list_5ghz(chans, maxchans, nchans,
4802300748Savos		    run_chan_5ghz, nitems(run_chan_5ghz), bands, 0);
4803300748Savos	}
4804300748Savos}
4805300748Savos
4806300748Savosstatic void
4807203134Sthompsarun_scan_start(struct ieee80211com *ic)
4808203134Sthompsa{
4809286950Sadrian	struct run_softc *sc = ic->ic_softc;
4810203134Sthompsa	uint32_t tmp;
4811203134Sthompsa
4812203134Sthompsa	RUN_LOCK(sc);
4813203134Sthompsa
4814203134Sthompsa	/* abort TSF synchronization */
4815203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
4816203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG,
4817203134Sthompsa	    tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
4818203134Sthompsa	    RT2860_TBTT_TIMER_EN));
4819287197Sglebius	run_set_bssid(sc, ieee80211broadcastaddr);
4820203134Sthompsa
4821203134Sthompsa	RUN_UNLOCK(sc);
4822203134Sthompsa
4823203134Sthompsa	return;
4824203134Sthompsa}
4825203134Sthompsa
4826203134Sthompsastatic void
4827203134Sthompsarun_scan_end(struct ieee80211com *ic)
4828203134Sthompsa{
4829286950Sadrian	struct run_softc *sc = ic->ic_softc;
4830203134Sthompsa
4831203134Sthompsa	RUN_LOCK(sc);
4832203134Sthompsa
4833203134Sthompsa	run_enable_tsf_sync(sc);
4834296356Savos	run_set_bssid(sc, sc->sc_bssid);
4835203134Sthompsa
4836203134Sthompsa	RUN_UNLOCK(sc);
4837203134Sthompsa
4838203134Sthompsa	return;
4839203134Sthompsa}
4840203134Sthompsa
4841208019Sthompsa/*
4842208019Sthompsa * Could be called from ieee80211_node_timeout()
4843208019Sthompsa * (non-sleepable thread)
4844208019Sthompsa */
4845208019Sthompsastatic void
4846208019Sthompsarun_update_beacon(struct ieee80211vap *vap, int item)
4847203134Sthompsa{
4848208019Sthompsa	struct ieee80211com *ic = vap->iv_ic;
4849288095Sadrian	struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off;
4850288095Sadrian	struct ieee80211_node *ni = vap->iv_bss;
4851286950Sadrian	struct run_softc *sc = ic->ic_softc;
4852218492Sbschmidt	struct run_vap *rvp = RUN_VAP(vap);
4853218492Sbschmidt	int mcast = 0;
4854208019Sthompsa	uint32_t i;
4855208019Sthompsa
4856218492Sbschmidt	switch (item) {
4857218492Sbschmidt	case IEEE80211_BEACON_ERP:
4858283540Sglebius		run_updateslot(ic);
4859218492Sbschmidt		break;
4860218492Sbschmidt	case IEEE80211_BEACON_HTINFO:
4861218492Sbschmidt		run_updateprot(ic);
4862218492Sbschmidt		break;
4863218492Sbschmidt	case IEEE80211_BEACON_TIM:
4864218492Sbschmidt		mcast = 1;	/*TODO*/
4865218492Sbschmidt		break;
4866218492Sbschmidt	default:
4867218492Sbschmidt		break;
4868218492Sbschmidt	}
4869218492Sbschmidt
4870288095Sadrian	setbit(bo->bo_flags, item);
4871273448Skevlo	if (rvp->beacon_mbuf == NULL) {
4872288636Sadrian		rvp->beacon_mbuf = ieee80211_beacon_alloc(ni);
4873273448Skevlo		if (rvp->beacon_mbuf == NULL)
4874273448Skevlo			return;
4875273448Skevlo	}
4876288636Sadrian	ieee80211_beacon_update(ni, rvp->beacon_mbuf, mcast);
4877218492Sbschmidt
4878208019Sthompsa	i = RUN_CMDQ_GET(&sc->cmdq_store);
4879208019Sthompsa	DPRINTF("cmdq_store=%d\n", i);
4880208019Sthompsa	sc->cmdq[i].func = run_update_beacon_cb;
4881208019Sthompsa	sc->cmdq[i].arg0 = vap;
4882208019Sthompsa	ieee80211_runtask(ic, &sc->cmdq_task);
4883208019Sthompsa
4884208019Sthompsa	return;
4885203134Sthompsa}
4886203134Sthompsa
4887203134Sthompsastatic void
4888208019Sthompsarun_update_beacon_cb(void *arg)
4889203134Sthompsa{
4890208019Sthompsa	struct ieee80211vap *vap = arg;
4891288095Sadrian	struct ieee80211_node *ni = vap->iv_bss;
4892218492Sbschmidt	struct run_vap *rvp = RUN_VAP(vap);
4893203134Sthompsa	struct ieee80211com *ic = vap->iv_ic;
4894286950Sadrian	struct run_softc *sc = ic->ic_softc;
4895203134Sthompsa	struct rt2860_txwi txwi;
4896203134Sthompsa	struct mbuf *m;
4897259032Skevlo	uint16_t txwisize;
4898208019Sthompsa	uint8_t ridx;
4899203134Sthompsa
4900288095Sadrian	if (ni->ni_chan == IEEE80211_CHAN_ANYC)
4901208019Sthompsa		return;
4902236439Shselasky	if (ic->ic_bsschan == IEEE80211_CHAN_ANYC)
4903236439Shselasky		return;
4904208019Sthompsa
4905218492Sbschmidt	/*
4906218492Sbschmidt	 * No need to call ieee80211_beacon_update(), run_update_beacon()
4907298932Spfg	 * is taking care of appropriate calls.
4908218492Sbschmidt	 */
4909218492Sbschmidt	if (rvp->beacon_mbuf == NULL) {
4910288636Sadrian		rvp->beacon_mbuf = ieee80211_beacon_alloc(ni);
4911218492Sbschmidt		if (rvp->beacon_mbuf == NULL)
4912218492Sbschmidt			return;
4913218492Sbschmidt	}
4914218492Sbschmidt	m = rvp->beacon_mbuf;
4915203134Sthompsa
4916259032Skevlo	memset(&txwi, 0, sizeof(txwi));
4917203134Sthompsa	txwi.wcid = 0xff;
4918203134Sthompsa	txwi.len = htole16(m->m_pkthdr.len);
4919259032Skevlo
4920203134Sthompsa	/* send beacons at the lowest available rate */
4921208019Sthompsa	ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
4922208019Sthompsa	    RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
4923208019Sthompsa	txwi.phy = htole16(rt2860_rates[ridx].mcs);
4924208019Sthompsa	if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM)
4925259032Skevlo		txwi.phy |= htole16(RT2860_PHY_OFDM);
4926203134Sthompsa	txwi.txop = RT2860_TX_TXOP_HT;
4927203134Sthompsa	txwi.flags = RT2860_TX_TS;
4928209144Sthompsa	txwi.xflags = RT2860_TX_NSEQ;
4929203134Sthompsa
4930259032Skevlo	txwisize = (sc->mac_ver == 0x5592) ?
4931259032Skevlo	    sizeof(txwi) + sizeof(uint32_t) : sizeof(txwi);
4932259032Skevlo	run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id), (uint8_t *)&txwi,
4933259032Skevlo	    txwisize);
4934259032Skevlo	run_write_region_1(sc, RT2860_BCN_BASE(rvp->rvp_id) + txwisize,
4935259032Skevlo	    mtod(m, uint8_t *), (m->m_pkthdr.len + 1) & ~1);
4936203134Sthompsa}
4937203134Sthompsa
4938203134Sthompsastatic void
4939203134Sthompsarun_updateprot(struct ieee80211com *ic)
4940203134Sthompsa{
4941286950Sadrian	struct run_softc *sc = ic->ic_softc;
4942218492Sbschmidt	uint32_t i;
4943218492Sbschmidt
4944218492Sbschmidt	i = RUN_CMDQ_GET(&sc->cmdq_store);
4945218492Sbschmidt	DPRINTF("cmdq_store=%d\n", i);
4946218492Sbschmidt	sc->cmdq[i].func = run_updateprot_cb;
4947218492Sbschmidt	sc->cmdq[i].arg0 = ic;
4948218492Sbschmidt	ieee80211_runtask(ic, &sc->cmdq_task);
4949218492Sbschmidt}
4950218492Sbschmidt
4951218492Sbschmidtstatic void
4952218492Sbschmidtrun_updateprot_cb(void *arg)
4953218492Sbschmidt{
4954218492Sbschmidt	struct ieee80211com *ic = arg;
4955286950Sadrian	struct run_softc *sc = ic->ic_softc;
4956203134Sthompsa	uint32_t tmp;
4957203134Sthompsa
4958203134Sthompsa	tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL;
4959203134Sthompsa	/* setup protection frame rate (MCS code) */
4960203134Sthompsa	tmp |= (ic->ic_curmode == IEEE80211_MODE_11A) ?
4961270192Skevlo	    rt2860_rates[RT2860_RIDX_OFDM6].mcs | RT2860_PHY_OFDM :
4962203134Sthompsa	    rt2860_rates[RT2860_RIDX_CCK11].mcs;
4963203134Sthompsa
4964203134Sthompsa	/* CCK frames don't require protection */
4965203134Sthompsa	run_write(sc, RT2860_CCK_PROT_CFG, tmp);
4966203134Sthompsa	if (ic->ic_flags & IEEE80211_F_USEPROT) {
4967203134Sthompsa		if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
4968203134Sthompsa			tmp |= RT2860_PROT_CTRL_RTS_CTS;
4969203134Sthompsa		else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
4970203134Sthompsa			tmp |= RT2860_PROT_CTRL_CTS;
4971203134Sthompsa	}
4972203134Sthompsa	run_write(sc, RT2860_OFDM_PROT_CFG, tmp);
4973203134Sthompsa}
4974203134Sthompsa
4975203134Sthompsastatic void
4976208019Sthompsarun_usb_timeout_cb(void *arg)
4977203134Sthompsa{
4978208019Sthompsa	struct ieee80211vap *vap = arg;
4979286950Sadrian	struct run_softc *sc = vap->iv_ic->ic_softc;
4980203134Sthompsa
4981208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
4982203134Sthompsa
4983203134Sthompsa	if(vap->iv_state == IEEE80211_S_RUN &&
4984203134Sthompsa	    vap->iv_opmode != IEEE80211_M_STA)
4985203134Sthompsa		run_reset_livelock(sc);
4986209917Sthompsa	else if (vap->iv_state == IEEE80211_S_SCAN) {
4987203134Sthompsa		DPRINTF("timeout caused by scan\n");
4988203134Sthompsa		/* cancel bgscan */
4989203134Sthompsa		ieee80211_cancel_scan(vap);
4990203134Sthompsa	} else
4991203134Sthompsa		DPRINTF("timeout by unknown cause\n");
4992203134Sthompsa}
4993203134Sthompsa
4994203134Sthompsastatic void
4995203134Sthompsarun_reset_livelock(struct run_softc *sc)
4996203134Sthompsa{
4997203134Sthompsa	uint32_t tmp;
4998203134Sthompsa
4999208019Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
5000208019Sthompsa
5001203134Sthompsa	/*
5002203134Sthompsa	 * In IBSS or HostAP modes (when the hardware sends beacons), the MAC
5003203134Sthompsa	 * can run into a livelock and start sending CTS-to-self frames like
5004203134Sthompsa	 * crazy if protection is enabled.  Reset MAC/BBP for a while
5005203134Sthompsa	 */
5006203134Sthompsa	run_read(sc, RT2860_DEBUG, &tmp);
5007208019Sthompsa	DPRINTFN(3, "debug reg %08x\n", tmp);
5008209917Sthompsa	if ((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))) {
5009203134Sthompsa		DPRINTF("CTS-to-self livelock detected\n");
5010203134Sthompsa		run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST);
5011203134Sthompsa		run_delay(sc, 1);
5012203134Sthompsa		run_write(sc, RT2860_MAC_SYS_CTRL,
5013203134Sthompsa		    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
5014203134Sthompsa	}
5015203134Sthompsa}
5016203134Sthompsa
5017203134Sthompsastatic void
5018283540Sglebiusrun_update_promisc_locked(struct run_softc *sc)
5019203134Sthompsa{
5020203134Sthompsa        uint32_t tmp;
5021203134Sthompsa
5022203134Sthompsa	run_read(sc, RT2860_RX_FILTR_CFG, &tmp);
5023203134Sthompsa
5024203134Sthompsa	tmp |= RT2860_DROP_UC_NOME;
5025287197Sglebius        if (sc->sc_ic.ic_promisc > 0)
5026203134Sthompsa		tmp &= ~RT2860_DROP_UC_NOME;
5027203134Sthompsa
5028203134Sthompsa	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
5029203134Sthompsa
5030287197Sglebius        DPRINTF("%s promiscuous mode\n", (sc->sc_ic.ic_promisc > 0) ?
5031203134Sthompsa            "entering" : "leaving");
5032203134Sthompsa}
5033203134Sthompsa
5034203134Sthompsastatic void
5035283540Sglebiusrun_update_promisc(struct ieee80211com *ic)
5036203134Sthompsa{
5037283540Sglebius	struct run_softc *sc = ic->ic_softc;
5038203134Sthompsa
5039287197Sglebius	if ((sc->sc_flags & RUN_RUNNING) == 0)
5040203134Sthompsa		return;
5041203134Sthompsa
5042203134Sthompsa	RUN_LOCK(sc);
5043283540Sglebius	run_update_promisc_locked(sc);
5044203134Sthompsa	RUN_UNLOCK(sc);
5045203134Sthompsa}
5046203134Sthompsa
5047203134Sthompsastatic void
5048203134Sthompsarun_enable_tsf_sync(struct run_softc *sc)
5049203134Sthompsa{
5050287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5051203134Sthompsa	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
5052203134Sthompsa	uint32_t tmp;
5053203134Sthompsa
5054257955Skevlo	DPRINTF("rvp_id=%d ic_opmode=%d\n", RUN_VAP(vap)->rvp_id,
5055257955Skevlo	    ic->ic_opmode);
5056208019Sthompsa
5057203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
5058203134Sthompsa	tmp &= ~0x1fffff;
5059203134Sthompsa	tmp |= vap->iv_bss->ni_intval * 16;
5060203134Sthompsa	tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN;
5061203134Sthompsa
5062208019Sthompsa	if (ic->ic_opmode == IEEE80211_M_STA) {
5063203134Sthompsa		/*
5064203134Sthompsa		 * Local TSF is always updated with remote TSF on beacon
5065203134Sthompsa		 * reception.
5066203134Sthompsa		 */
5067203134Sthompsa		tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT;
5068208019Sthompsa	} else if (ic->ic_opmode == IEEE80211_M_IBSS) {
5069203134Sthompsa	        tmp |= RT2860_BCN_TX_EN;
5070203134Sthompsa	        /*
5071203134Sthompsa	         * Local TSF is updated with remote TSF on beacon reception
5072203134Sthompsa	         * only if the remote TSF is greater than local TSF.
5073203134Sthompsa	         */
5074203134Sthompsa	        tmp |= 2 << RT2860_TSF_SYNC_MODE_SHIFT;
5075208019Sthompsa	} else if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
5076208019Sthompsa		    ic->ic_opmode == IEEE80211_M_MBSS) {
5077203134Sthompsa	        tmp |= RT2860_BCN_TX_EN;
5078203134Sthompsa	        /* SYNC with nobody */
5079203134Sthompsa	        tmp |= 3 << RT2860_TSF_SYNC_MODE_SHIFT;
5080208019Sthompsa	} else {
5081203134Sthompsa		DPRINTF("Enabling TSF failed. undefined opmode\n");
5082208019Sthompsa		return;
5083208019Sthompsa	}
5084203134Sthompsa
5085203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
5086203134Sthompsa}
5087203134Sthompsa
5088203134Sthompsastatic void
5089287555Skevlorun_enable_tsf(struct run_softc *sc)
5090287555Skevlo{
5091287555Skevlo	uint32_t tmp;
5092287555Skevlo
5093287555Skevlo	if (run_read(sc, RT2860_BCN_TIME_CFG, &tmp) == 0) {
5094287555Skevlo		tmp &= ~(RT2860_BCN_TX_EN | RT2860_TBTT_TIMER_EN);
5095287555Skevlo		tmp |= RT2860_TSF_TIMER_EN;
5096287555Skevlo		run_write(sc, RT2860_BCN_TIME_CFG, tmp);
5097287555Skevlo	}
5098287555Skevlo}
5099287555Skevlo
5100287555Skevlostatic void
5101287554Skevlorun_get_tsf(struct run_softc *sc, uint64_t *buf)
5102287554Skevlo{
5103287554Skevlo	run_read_region_1(sc, RT2860_TSF_TIMER_DW0, (uint8_t *)buf,
5104287554Skevlo	    sizeof(*buf));
5105287554Skevlo}
5106287554Skevlo
5107287554Skevlostatic void
5108203134Sthompsarun_enable_mrr(struct run_softc *sc)
5109203134Sthompsa{
5110259546Skevlo#define	CCK(mcs)	(mcs)
5111259546Skevlo#define	OFDM(mcs)	(1 << 3 | (mcs))
5112203134Sthompsa	run_write(sc, RT2860_LG_FBK_CFG0,
5113203134Sthompsa	    OFDM(6) << 28 |	/* 54->48 */
5114203134Sthompsa	    OFDM(5) << 24 |	/* 48->36 */
5115203134Sthompsa	    OFDM(4) << 20 |	/* 36->24 */
5116203134Sthompsa	    OFDM(3) << 16 |	/* 24->18 */
5117203134Sthompsa	    OFDM(2) << 12 |	/* 18->12 */
5118203134Sthompsa	    OFDM(1) <<  8 |	/* 12-> 9 */
5119203134Sthompsa	    OFDM(0) <<  4 |	/*  9-> 6 */
5120203134Sthompsa	    OFDM(0));		/*  6-> 6 */
5121203134Sthompsa
5122203134Sthompsa	run_write(sc, RT2860_LG_FBK_CFG1,
5123203134Sthompsa	    CCK(2) << 12 |	/* 11->5.5 */
5124203134Sthompsa	    CCK(1) <<  8 |	/* 5.5-> 2 */
5125203134Sthompsa	    CCK(0) <<  4 |	/*   2-> 1 */
5126203134Sthompsa	    CCK(0));		/*   1-> 1 */
5127203134Sthompsa#undef OFDM
5128203134Sthompsa#undef CCK
5129203134Sthompsa}
5130203134Sthompsa
5131203134Sthompsastatic void
5132203134Sthompsarun_set_txpreamble(struct run_softc *sc)
5133203134Sthompsa{
5134287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5135203134Sthompsa	uint32_t tmp;
5136203134Sthompsa
5137203134Sthompsa	run_read(sc, RT2860_AUTO_RSP_CFG, &tmp);
5138203134Sthompsa	if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
5139203134Sthompsa		tmp |= RT2860_CCK_SHORT_EN;
5140203134Sthompsa	else
5141203134Sthompsa		tmp &= ~RT2860_CCK_SHORT_EN;
5142203134Sthompsa	run_write(sc, RT2860_AUTO_RSP_CFG, tmp);
5143203134Sthompsa}
5144203134Sthompsa
5145203134Sthompsastatic void
5146203134Sthompsarun_set_basicrates(struct run_softc *sc)
5147203134Sthompsa{
5148287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5149203134Sthompsa
5150203134Sthompsa	/* set basic rates mask */
5151203134Sthompsa	if (ic->ic_curmode == IEEE80211_MODE_11B)
5152203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x003);
5153203134Sthompsa	else if (ic->ic_curmode == IEEE80211_MODE_11A)
5154203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x150);
5155203134Sthompsa	else	/* 11g */
5156203134Sthompsa		run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x15f);
5157203134Sthompsa}
5158203134Sthompsa
5159203134Sthompsastatic void
5160203134Sthompsarun_set_leds(struct run_softc *sc, uint16_t which)
5161203134Sthompsa{
5162203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LEDS,
5163203134Sthompsa	    which | (sc->leds & 0x7f));
5164203134Sthompsa}
5165203134Sthompsa
5166203134Sthompsastatic void
5167203134Sthompsarun_set_bssid(struct run_softc *sc, const uint8_t *bssid)
5168203134Sthompsa{
5169203134Sthompsa	run_write(sc, RT2860_MAC_BSSID_DW0,
5170203134Sthompsa	    bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24);
5171203134Sthompsa	run_write(sc, RT2860_MAC_BSSID_DW1,
5172203134Sthompsa	    bssid[4] | bssid[5] << 8);
5173203134Sthompsa}
5174203134Sthompsa
5175203134Sthompsastatic void
5176203134Sthompsarun_set_macaddr(struct run_softc *sc, const uint8_t *addr)
5177203134Sthompsa{
5178203134Sthompsa	run_write(sc, RT2860_MAC_ADDR_DW0,
5179203134Sthompsa	    addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24);
5180203134Sthompsa	run_write(sc, RT2860_MAC_ADDR_DW1,
5181203134Sthompsa	    addr[4] | addr[5] << 8 | 0xff << 16);
5182203134Sthompsa}
5183203134Sthompsa
5184203134Sthompsastatic void
5185283540Sglebiusrun_updateslot(struct ieee80211com *ic)
5186203134Sthompsa{
5187283540Sglebius	struct run_softc *sc = ic->ic_softc;
5188218492Sbschmidt	uint32_t i;
5189218492Sbschmidt
5190218492Sbschmidt	i = RUN_CMDQ_GET(&sc->cmdq_store);
5191218492Sbschmidt	DPRINTF("cmdq_store=%d\n", i);
5192218492Sbschmidt	sc->cmdq[i].func = run_updateslot_cb;
5193287197Sglebius	sc->cmdq[i].arg0 = ic;
5194218492Sbschmidt	ieee80211_runtask(ic, &sc->cmdq_task);
5195218492Sbschmidt
5196218492Sbschmidt	return;
5197218492Sbschmidt}
5198218492Sbschmidt
5199218492Sbschmidt/* ARGSUSED */
5200218492Sbschmidtstatic void
5201218492Sbschmidtrun_updateslot_cb(void *arg)
5202218492Sbschmidt{
5203287197Sglebius	struct ieee80211com *ic = arg;
5204286950Sadrian	struct run_softc *sc = ic->ic_softc;
5205203134Sthompsa	uint32_t tmp;
5206203134Sthompsa
5207203134Sthompsa	run_read(sc, RT2860_BKOFF_SLOT_CFG, &tmp);
5208203134Sthompsa	tmp &= ~0xff;
5209292165Savos	tmp |= IEEE80211_GET_SLOTTIME(ic);
5210203134Sthompsa	run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp);
5211203134Sthompsa}
5212203134Sthompsa
5213208019Sthompsastatic void
5214283540Sglebiusrun_update_mcast(struct ieee80211com *ic)
5215208019Sthompsa{
5216208019Sthompsa}
5217208019Sthompsa
5218203134Sthompsastatic int8_t
5219203134Sthompsarun_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain)
5220203134Sthompsa{
5221287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5222203134Sthompsa	struct ieee80211_channel *c = ic->ic_curchan;
5223203134Sthompsa	int delta;
5224203134Sthompsa
5225203134Sthompsa	if (IEEE80211_IS_CHAN_5GHZ(c)) {
5226257429Shselasky		u_int chan = ieee80211_chan2ieee(ic, c);
5227203134Sthompsa		delta = sc->rssi_5ghz[rxchain];
5228203134Sthompsa
5229203134Sthompsa		/* determine channel group */
5230203134Sthompsa		if (chan <= 64)
5231203134Sthompsa			delta -= sc->lna[1];
5232203134Sthompsa		else if (chan <= 128)
5233203134Sthompsa			delta -= sc->lna[2];
5234203134Sthompsa		else
5235203134Sthompsa			delta -= sc->lna[3];
5236203134Sthompsa	} else
5237203134Sthompsa		delta = sc->rssi_2ghz[rxchain] - sc->lna[0];
5238203134Sthompsa
5239209917Sthompsa	return (-12 - delta - rssi);
5240203134Sthompsa}
5241203134Sthompsa
5242257955Skevlostatic void
5243257955Skevlorun_rt5390_bbp_init(struct run_softc *sc)
5244257955Skevlo{
5245299176Spfg	u_int i;
5246259032Skevlo	uint8_t bbp;
5247257955Skevlo
5248259032Skevlo	/* Apply maximum likelihood detection for 2 stream case. */
5249259032Skevlo	run_bbp_read(sc, 105, &bbp);
5250259032Skevlo	if (sc->nrxchains > 1)
5251259032Skevlo		run_bbp_write(sc, 105, bbp | RT5390_MLD);
5252259032Skevlo
5253257955Skevlo	/* Avoid data lost and CRC error. */
5254259032Skevlo	run_bbp_read(sc, 4, &bbp);
5255259031Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5256257955Skevlo
5257259032Skevlo	if (sc->mac_ver == 0x5592) {
5258259032Skevlo		for (i = 0; i < nitems(rt5592_def_bbp); i++) {
5259259032Skevlo			run_bbp_write(sc, rt5592_def_bbp[i].reg,
5260259032Skevlo			    rt5592_def_bbp[i].val);
5261259032Skevlo		}
5262259032Skevlo		for (i = 0; i < nitems(rt5592_bbp_r196); i++) {
5263259032Skevlo			run_bbp_write(sc, 195, i + 0x80);
5264259032Skevlo			run_bbp_write(sc, 196, rt5592_bbp_r196[i]);
5265259032Skevlo		}
5266259032Skevlo	} else {
5267259032Skevlo		for (i = 0; i < nitems(rt5390_def_bbp); i++) {
5268259032Skevlo			run_bbp_write(sc, rt5390_def_bbp[i].reg,
5269259032Skevlo			    rt5390_def_bbp[i].val);
5270259032Skevlo		}
5271257955Skevlo	}
5272257955Skevlo	if (sc->mac_ver == 0x5392) {
5273257955Skevlo		run_bbp_write(sc, 88, 0x90);
5274257955Skevlo		run_bbp_write(sc, 95, 0x9a);
5275257955Skevlo		run_bbp_write(sc, 98, 0x12);
5276257955Skevlo		run_bbp_write(sc, 106, 0x12);
5277257955Skevlo		run_bbp_write(sc, 134, 0xd0);
5278257955Skevlo		run_bbp_write(sc, 135, 0xf6);
5279257955Skevlo		run_bbp_write(sc, 148, 0x84);
5280257955Skevlo	}
5281257955Skevlo
5282259032Skevlo	run_bbp_read(sc, 152, &bbp);
5283259032Skevlo	run_bbp_write(sc, 152, bbp | 0x80);
5284259032Skevlo
5285259032Skevlo	/* Fix BBP254 for RT5592C. */
5286259032Skevlo	if (sc->mac_ver == 0x5592 && sc->mac_rev >= 0x0221) {
5287259032Skevlo		run_bbp_read(sc, 254, &bbp);
5288259032Skevlo		run_bbp_write(sc, 254, bbp | 0x80);
5289259032Skevlo	}
5290259032Skevlo
5291257955Skevlo	/* Disable hardware antenna diversity. */
5292257955Skevlo	if (sc->mac_ver == 0x5390)
5293257955Skevlo		run_bbp_write(sc, 154, 0);
5294259032Skevlo
5295259032Skevlo	/* Initialize Rx CCK/OFDM frequency offset report. */
5296259032Skevlo	run_bbp_write(sc, 142, 1);
5297259032Skevlo	run_bbp_write(sc, 143, 57);
5298257955Skevlo}
5299257955Skevlo
5300203134Sthompsastatic int
5301203134Sthompsarun_bbp_init(struct run_softc *sc)
5302203134Sthompsa{
5303203134Sthompsa	int i, error, ntries;
5304203134Sthompsa	uint8_t bbp0;
5305203134Sthompsa
5306203134Sthompsa	/* wait for BBP to wake up */
5307203134Sthompsa	for (ntries = 0; ntries < 20; ntries++) {
5308203134Sthompsa		if ((error = run_bbp_read(sc, 0, &bbp0)) != 0)
5309203134Sthompsa			return error;
5310203134Sthompsa		if (bbp0 != 0 && bbp0 != 0xff)
5311203134Sthompsa			break;
5312203134Sthompsa	}
5313203134Sthompsa	if (ntries == 20)
5314209917Sthompsa		return (ETIMEDOUT);
5315203134Sthompsa
5316203134Sthompsa	/* initialize BBP registers to default values */
5317257955Skevlo	if (sc->mac_ver >= 0x5390)
5318257955Skevlo		run_rt5390_bbp_init(sc);
5319257955Skevlo	else {
5320257955Skevlo		for (i = 0; i < nitems(rt2860_def_bbp); i++) {
5321257955Skevlo			run_bbp_write(sc, rt2860_def_bbp[i].reg,
5322257955Skevlo			    rt2860_def_bbp[i].val);
5323257955Skevlo		}
5324203134Sthompsa	}
5325203134Sthompsa
5326260219Skevlo	if (sc->mac_ver == 0x3593) {
5327260219Skevlo		run_bbp_write(sc, 79, 0x13);
5328260219Skevlo		run_bbp_write(sc, 80, 0x05);
5329260219Skevlo		run_bbp_write(sc, 81, 0x33);
5330260219Skevlo		run_bbp_write(sc, 86, 0x46);
5331260219Skevlo		run_bbp_write(sc, 137, 0x0f);
5332260219Skevlo	}
5333260219Skevlo
5334203134Sthompsa	/* fix BBP84 for RT2860E */
5335205042Sthompsa	if (sc->mac_ver == 0x2860 && sc->mac_rev != 0x0101)
5336205042Sthompsa		run_bbp_write(sc, 84, 0x19);
5337203134Sthompsa
5338260219Skevlo	if (sc->mac_ver >= 0x3070 && (sc->mac_ver != 0x3593 &&
5339260219Skevlo	    sc->mac_ver != 0x5592)) {
5340203134Sthompsa		run_bbp_write(sc, 79, 0x13);
5341203134Sthompsa		run_bbp_write(sc, 80, 0x05);
5342203134Sthompsa		run_bbp_write(sc, 81, 0x33);
5343205042Sthompsa	} else if (sc->mac_ver == 0x2860 && sc->mac_rev == 0x0100) {
5344203134Sthompsa		run_bbp_write(sc, 69, 0x16);
5345203134Sthompsa		run_bbp_write(sc, 73, 0x12);
5346203134Sthompsa	}
5347209917Sthompsa	return (0);
5348203134Sthompsa}
5349203134Sthompsa
5350203134Sthompsastatic int
5351203134Sthompsarun_rt3070_rf_init(struct run_softc *sc)
5352203134Sthompsa{
5353203134Sthompsa	uint32_t tmp;
5354256722Skevlo	uint8_t bbp4, mingain, rf, target;
5355299176Spfg	u_int i;
5356203134Sthompsa
5357203134Sthompsa	run_rt3070_rf_read(sc, 30, &rf);
5358203134Sthompsa	/* toggle RF R30 bit 7 */
5359203134Sthompsa	run_rt3070_rf_write(sc, 30, rf | 0x80);
5360203134Sthompsa	run_delay(sc, 10);
5361203134Sthompsa	run_rt3070_rf_write(sc, 30, rf & ~0x80);
5362203134Sthompsa
5363203134Sthompsa	/* initialize RF registers to default value */
5364205042Sthompsa	if (sc->mac_ver == 0x3572) {
5365257955Skevlo		for (i = 0; i < nitems(rt3572_def_rf); i++) {
5366205042Sthompsa			run_rt3070_rf_write(sc, rt3572_def_rf[i].reg,
5367205042Sthompsa			    rt3572_def_rf[i].val);
5368205042Sthompsa		}
5369205042Sthompsa	} else {
5370257955Skevlo		for (i = 0; i < nitems(rt3070_def_rf); i++) {
5371205042Sthompsa			run_rt3070_rf_write(sc, rt3070_def_rf[i].reg,
5372205042Sthompsa			    rt3070_def_rf[i].val);
5373205042Sthompsa		}
5374203134Sthompsa	}
5375205042Sthompsa
5376256721Skevlo	if (sc->mac_ver == 0x3070 && sc->mac_rev < 0x0201) {
5377256721Skevlo		/*
5378256721Skevlo		 * Change voltage from 1.2V to 1.35V for RT3070.
5379256721Skevlo		 * The DAC issue (RT3070_LDO_CFG0) has been fixed
5380256721Skevlo		 * in RT3070(F).
5381256721Skevlo		 */
5382203134Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5383203134Sthompsa		tmp = (tmp & ~0x0f000000) | 0x0d000000;
5384203134Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5385203134Sthompsa
5386205042Sthompsa	} else if (sc->mac_ver == 0x3071) {
5387203134Sthompsa		run_rt3070_rf_read(sc, 6, &rf);
5388203134Sthompsa		run_rt3070_rf_write(sc, 6, rf | 0x40);
5389203134Sthompsa		run_rt3070_rf_write(sc, 31, 0x14);
5390203134Sthompsa
5391203134Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5392203134Sthompsa		tmp &= ~0x1f000000;
5393205042Sthompsa		if (sc->mac_rev < 0x0211)
5394205042Sthompsa			tmp |= 0x0d000000;	/* 1.3V */
5395203134Sthompsa		else
5396205042Sthompsa			tmp |= 0x01000000;	/* 1.2V */
5397203134Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5398203134Sthompsa
5399203134Sthompsa		/* patch LNA_PE_G1 */
5400203134Sthompsa		run_read(sc, RT3070_GPIO_SWITCH, &tmp);
5401203134Sthompsa		run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20);
5402208019Sthompsa
5403209917Sthompsa	} else if (sc->mac_ver == 0x3572) {
5404205042Sthompsa		run_rt3070_rf_read(sc, 6, &rf);
5405205042Sthompsa		run_rt3070_rf_write(sc, 6, rf | 0x40);
5406205042Sthompsa
5407208019Sthompsa		/* increase voltage from 1.2V to 1.35V */
5408208019Sthompsa		run_read(sc, RT3070_LDO_CFG0, &tmp);
5409208019Sthompsa		tmp = (tmp & ~0x1f000000) | 0x0d000000;
5410208019Sthompsa		run_write(sc, RT3070_LDO_CFG0, tmp);
5411203134Sthompsa
5412209917Sthompsa		if (sc->mac_rev < 0x0211 || !sc->patch_dac) {
5413203134Sthompsa			run_delay(sc, 1);	/* wait for 1msec */
5414205042Sthompsa			/* decrease voltage back to 1.2V */
5415203134Sthompsa			tmp = (tmp & ~0x1f000000) | 0x01000000;
5416203134Sthompsa			run_write(sc, RT3070_LDO_CFG0, tmp);
5417203134Sthompsa		}
5418203134Sthompsa	}
5419203134Sthompsa
5420203134Sthompsa	/* select 20MHz bandwidth */
5421203134Sthompsa	run_rt3070_rf_read(sc, 31, &rf);
5422203134Sthompsa	run_rt3070_rf_write(sc, 31, rf & ~0x20);
5423203134Sthompsa
5424203134Sthompsa	/* calibrate filter for 20MHz bandwidth */
5425203134Sthompsa	sc->rf24_20mhz = 0x1f;	/* default value */
5426205042Sthompsa	target = (sc->mac_ver < 0x3071) ? 0x16 : 0x13;
5427205042Sthompsa	run_rt3070_filter_calib(sc, 0x07, target, &sc->rf24_20mhz);
5428203134Sthompsa
5429203134Sthompsa	/* select 40MHz bandwidth */
5430203134Sthompsa	run_bbp_read(sc, 4, &bbp4);
5431256721Skevlo	run_bbp_write(sc, 4, (bbp4 & ~0x18) | 0x10);
5432205042Sthompsa	run_rt3070_rf_read(sc, 31, &rf);
5433205042Sthompsa	run_rt3070_rf_write(sc, 31, rf | 0x20);
5434203134Sthompsa
5435203134Sthompsa	/* calibrate filter for 40MHz bandwidth */
5436203134Sthompsa	sc->rf24_40mhz = 0x2f;	/* default value */
5437205042Sthompsa	target = (sc->mac_ver < 0x3071) ? 0x19 : 0x15;
5438205042Sthompsa	run_rt3070_filter_calib(sc, 0x27, target, &sc->rf24_40mhz);
5439203134Sthompsa
5440203134Sthompsa	/* go back to 20MHz bandwidth */
5441203134Sthompsa	run_bbp_read(sc, 4, &bbp4);
5442203134Sthompsa	run_bbp_write(sc, 4, bbp4 & ~0x18);
5443203134Sthompsa
5444205042Sthompsa	if (sc->mac_ver == 0x3572) {
5445205042Sthompsa		/* save default BBP registers 25 and 26 values */
5446205042Sthompsa		run_bbp_read(sc, 25, &sc->bbp25);
5447205042Sthompsa		run_bbp_read(sc, 26, &sc->bbp26);
5448256721Skevlo	} else if (sc->mac_rev < 0x0201 || sc->mac_rev < 0x0211)
5449203134Sthompsa		run_rt3070_rf_write(sc, 27, 0x03);
5450203134Sthompsa
5451203134Sthompsa	run_read(sc, RT3070_OPT_14, &tmp);
5452203134Sthompsa	run_write(sc, RT3070_OPT_14, tmp | 1);
5453203134Sthompsa
5454205042Sthompsa	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
5455205042Sthompsa		run_rt3070_rf_read(sc, 17, &rf);
5456205042Sthompsa		rf &= ~RT3070_TX_LO1;
5457205042Sthompsa		if ((sc->mac_ver == 0x3070 ||
5458205042Sthompsa		     (sc->mac_ver == 0x3071 && sc->mac_rev >= 0x0211)) &&
5459205042Sthompsa		    !sc->ext_2ghz_lna)
5460205042Sthompsa			rf |= 0x20;	/* fix for long range Rx issue */
5461256722Skevlo		mingain = (sc->mac_ver == 0x3070) ? 1 : 2;
5462256722Skevlo		if (sc->txmixgain_2ghz >= mingain)
5463205042Sthompsa			rf = (rf & ~0x7) | sc->txmixgain_2ghz;
5464205042Sthompsa		run_rt3070_rf_write(sc, 17, rf);
5465205042Sthompsa	}
5466205042Sthompsa
5467270643Skevlo	if (sc->mac_ver == 0x3071) {
5468203134Sthompsa		run_rt3070_rf_read(sc, 1, &rf);
5469203134Sthompsa		rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD);
5470203134Sthompsa		rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD;
5471203134Sthompsa		run_rt3070_rf_write(sc, 1, rf);
5472203134Sthompsa
5473203134Sthompsa		run_rt3070_rf_read(sc, 15, &rf);
5474203134Sthompsa		run_rt3070_rf_write(sc, 15, rf & ~RT3070_TX_LO2);
5475203134Sthompsa
5476203134Sthompsa		run_rt3070_rf_read(sc, 20, &rf);
5477203134Sthompsa		run_rt3070_rf_write(sc, 20, rf & ~RT3070_RX_LO1);
5478203134Sthompsa
5479203134Sthompsa		run_rt3070_rf_read(sc, 21, &rf);
5480203134Sthompsa		run_rt3070_rf_write(sc, 21, rf & ~RT3070_RX_LO2);
5481205042Sthompsa	}
5482203134Sthompsa
5483205042Sthompsa	if (sc->mac_ver == 0x3070 || sc->mac_ver == 0x3071) {
5484205042Sthompsa		/* fix Tx to Rx IQ glitch by raising RF voltage */
5485203134Sthompsa		run_rt3070_rf_read(sc, 27, &rf);
5486203134Sthompsa		rf &= ~0x77;
5487205042Sthompsa		if (sc->mac_rev < 0x0211)
5488203134Sthompsa			rf |= 0x03;
5489203134Sthompsa		run_rt3070_rf_write(sc, 27, rf);
5490203134Sthompsa	}
5491209917Sthompsa	return (0);
5492203134Sthompsa}
5493203134Sthompsa
5494257955Skevlostatic void
5495260219Skevlorun_rt3593_rf_init(struct run_softc *sc)
5496260219Skevlo{
5497260219Skevlo	uint32_t tmp;
5498260219Skevlo	uint8_t rf;
5499299176Spfg	u_int i;
5500260219Skevlo
5501260219Skevlo	/* Disable the GPIO bits 4 and 7 for LNA PE control. */
5502260219Skevlo	run_read(sc, RT3070_GPIO_SWITCH, &tmp);
5503260219Skevlo	tmp &= ~(1 << 4 | 1 << 7);
5504260219Skevlo	run_write(sc, RT3070_GPIO_SWITCH, tmp);
5505260219Skevlo
5506260219Skevlo	/* Initialize RF registers to default value. */
5507260219Skevlo	for (i = 0; i < nitems(rt3593_def_rf); i++) {
5508260219Skevlo		run_rt3070_rf_write(sc, rt3593_def_rf[i].reg,
5509260219Skevlo		    rt3593_def_rf[i].val);
5510260219Skevlo	}
5511260219Skevlo
5512260219Skevlo	/* Toggle RF R2 to initiate calibration. */
5513260219Skevlo	run_rt3070_rf_write(sc, 2, RT5390_RESCAL);
5514260219Skevlo
5515260219Skevlo	/* Initialize RF frequency offset. */
5516260219Skevlo	run_adjust_freq_offset(sc);
5517260219Skevlo
5518260219Skevlo	run_rt3070_rf_read(sc, 18, &rf);
5519260219Skevlo	run_rt3070_rf_write(sc, 18, rf | RT3593_AUTOTUNE_BYPASS);
5520260219Skevlo
5521260219Skevlo	/*
5522260219Skevlo	 * Increase voltage from 1.2V to 1.35V, wait for 1 msec to
5523260219Skevlo	 * decrease voltage back to 1.2V.
5524260219Skevlo	 */
5525260219Skevlo	run_read(sc, RT3070_LDO_CFG0, &tmp);
5526260219Skevlo	tmp = (tmp & ~0x1f000000) | 0x0d000000;
5527260219Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
5528260219Skevlo	run_delay(sc, 1);
5529260219Skevlo	tmp = (tmp & ~0x1f000000) | 0x01000000;
5530260219Skevlo	run_write(sc, RT3070_LDO_CFG0, tmp);
5531260219Skevlo
5532260219Skevlo	sc->rf24_20mhz = 0x1f;
5533260219Skevlo	sc->rf24_40mhz = 0x2f;
5534260219Skevlo
5535260219Skevlo	/* Save default BBP registers 25 and 26 values. */
5536260219Skevlo	run_bbp_read(sc, 25, &sc->bbp25);
5537260219Skevlo	run_bbp_read(sc, 26, &sc->bbp26);
5538260219Skevlo
5539260219Skevlo	run_read(sc, RT3070_OPT_14, &tmp);
5540260219Skevlo	run_write(sc, RT3070_OPT_14, tmp | 1);
5541260219Skevlo}
5542260219Skevlo
5543260219Skevlostatic void
5544257955Skevlorun_rt5390_rf_init(struct run_softc *sc)
5545257955Skevlo{
5546257955Skevlo	uint32_t tmp;
5547257955Skevlo	uint8_t rf;
5548299176Spfg	u_int i;
5549257955Skevlo
5550259030Skevlo	/* Toggle RF R2 to initiate calibration. */
5551259030Skevlo	if (sc->mac_ver == 0x5390) {
5552257955Skevlo		run_rt3070_rf_read(sc, 2, &rf);
5553259031Skevlo		run_rt3070_rf_write(sc, 2, rf | RT5390_RESCAL);
5554257955Skevlo		run_delay(sc, 10);
5555259031Skevlo		run_rt3070_rf_write(sc, 2, rf & ~RT5390_RESCAL);
5556259030Skevlo	} else {
5557259031Skevlo		run_rt3070_rf_write(sc, 2, RT5390_RESCAL);
5558259030Skevlo		run_delay(sc, 10);
5559257955Skevlo	}
5560257955Skevlo
5561257955Skevlo	/* Initialize RF registers to default value. */
5562259032Skevlo	if (sc->mac_ver == 0x5592) {
5563259032Skevlo		for (i = 0; i < nitems(rt5592_def_rf); i++) {
5564259032Skevlo			run_rt3070_rf_write(sc, rt5592_def_rf[i].reg,
5565259032Skevlo			    rt5592_def_rf[i].val);
5566259032Skevlo		}
5567259032Skevlo		/* Initialize RF frequency offset. */
5568259032Skevlo		run_adjust_freq_offset(sc);
5569259032Skevlo	} else if (sc->mac_ver == 0x5392) {
5570257955Skevlo		for (i = 0; i < nitems(rt5392_def_rf); i++) {
5571257955Skevlo			run_rt3070_rf_write(sc, rt5392_def_rf[i].reg,
5572257955Skevlo			    rt5392_def_rf[i].val);
5573257955Skevlo		}
5574257955Skevlo		if (sc->mac_rev >= 0x0223) {
5575257955Skevlo			run_rt3070_rf_write(sc, 23, 0x0f);
5576257955Skevlo			run_rt3070_rf_write(sc, 24, 0x3e);
5577257955Skevlo			run_rt3070_rf_write(sc, 51, 0x32);
5578257955Skevlo			run_rt3070_rf_write(sc, 53, 0x22);
5579257955Skevlo			run_rt3070_rf_write(sc, 56, 0xc1);
5580257955Skevlo			run_rt3070_rf_write(sc, 59, 0x0f);
5581257955Skevlo		}
5582257955Skevlo	} else {
5583257955Skevlo		for (i = 0; i < nitems(rt5390_def_rf); i++) {
5584257955Skevlo			run_rt3070_rf_write(sc, rt5390_def_rf[i].reg,
5585257955Skevlo			    rt5390_def_rf[i].val);
5586257955Skevlo		}
5587257955Skevlo		if (sc->mac_rev >= 0x0502) {
5588257955Skevlo			run_rt3070_rf_write(sc, 6, 0xe0);
5589257955Skevlo			run_rt3070_rf_write(sc, 25, 0x80);
5590257955Skevlo			run_rt3070_rf_write(sc, 46, 0x73);
5591257955Skevlo			run_rt3070_rf_write(sc, 53, 0x00);
5592257955Skevlo			run_rt3070_rf_write(sc, 56, 0x42);
5593257955Skevlo			run_rt3070_rf_write(sc, 61, 0xd1);
5594257955Skevlo		}
5595257955Skevlo	}
5596257955Skevlo
5597257955Skevlo	sc->rf24_20mhz = 0x1f;	/* default value */
5598259032Skevlo	sc->rf24_40mhz = (sc->mac_ver == 0x5592) ? 0 : 0x2f;
5599257955Skevlo
5600257955Skevlo	if (sc->mac_rev < 0x0211)
5601257955Skevlo		run_rt3070_rf_write(sc, 27, 0x3);
5602257955Skevlo
5603257955Skevlo	run_read(sc, RT3070_OPT_14, &tmp);
5604257955Skevlo	run_write(sc, RT3070_OPT_14, tmp | 1);
5605257955Skevlo}
5606257955Skevlo
5607203134Sthompsastatic int
5608203134Sthompsarun_rt3070_filter_calib(struct run_softc *sc, uint8_t init, uint8_t target,
5609203134Sthompsa    uint8_t *val)
5610203134Sthompsa{
5611203134Sthompsa	uint8_t rf22, rf24;
5612203134Sthompsa	uint8_t bbp55_pb, bbp55_sb, delta;
5613203134Sthompsa	int ntries;
5614203134Sthompsa
5615203134Sthompsa	/* program filter */
5616205042Sthompsa	run_rt3070_rf_read(sc, 24, &rf24);
5617205042Sthompsa	rf24 = (rf24 & 0xc0) | init;	/* initial filter value */
5618203134Sthompsa	run_rt3070_rf_write(sc, 24, rf24);
5619203134Sthompsa
5620203134Sthompsa	/* enable baseband loopback mode */
5621203134Sthompsa	run_rt3070_rf_read(sc, 22, &rf22);
5622203134Sthompsa	run_rt3070_rf_write(sc, 22, rf22 | 0x01);
5623203134Sthompsa
5624203134Sthompsa	/* set power and frequency of passband test tone */
5625203134Sthompsa	run_bbp_write(sc, 24, 0x00);
5626203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5627203134Sthompsa		/* transmit test tone */
5628203134Sthompsa		run_bbp_write(sc, 25, 0x90);
5629203134Sthompsa		run_delay(sc, 10);
5630203134Sthompsa		/* read received power */
5631203134Sthompsa		run_bbp_read(sc, 55, &bbp55_pb);
5632203134Sthompsa		if (bbp55_pb != 0)
5633203134Sthompsa			break;
5634203134Sthompsa	}
5635203134Sthompsa	if (ntries == 100)
5636257955Skevlo		return (ETIMEDOUT);
5637203134Sthompsa
5638203134Sthompsa	/* set power and frequency of stopband test tone */
5639203134Sthompsa	run_bbp_write(sc, 24, 0x06);
5640203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5641203134Sthompsa		/* transmit test tone */
5642203134Sthompsa		run_bbp_write(sc, 25, 0x90);
5643203134Sthompsa		run_delay(sc, 10);
5644203134Sthompsa		/* read received power */
5645203134Sthompsa		run_bbp_read(sc, 55, &bbp55_sb);
5646203134Sthompsa
5647203134Sthompsa		delta = bbp55_pb - bbp55_sb;
5648203134Sthompsa		if (delta > target)
5649203134Sthompsa			break;
5650203134Sthompsa
5651203134Sthompsa		/* reprogram filter */
5652203134Sthompsa		rf24++;
5653203134Sthompsa		run_rt3070_rf_write(sc, 24, rf24);
5654203134Sthompsa	}
5655203134Sthompsa	if (ntries < 100) {
5656203134Sthompsa		if (rf24 != init)
5657203134Sthompsa			rf24--;	/* backtrack */
5658203134Sthompsa		*val = rf24;
5659203134Sthompsa		run_rt3070_rf_write(sc, 24, rf24);
5660203134Sthompsa	}
5661203134Sthompsa
5662203134Sthompsa	/* restore initial state */
5663203134Sthompsa	run_bbp_write(sc, 24, 0x00);
5664203134Sthompsa
5665203134Sthompsa	/* disable baseband loopback mode */
5666203134Sthompsa	run_rt3070_rf_read(sc, 22, &rf22);
5667203134Sthompsa	run_rt3070_rf_write(sc, 22, rf22 & ~0x01);
5668203134Sthompsa
5669209917Sthompsa	return (0);
5670203134Sthompsa}
5671203134Sthompsa
5672205042Sthompsastatic void
5673205042Sthompsarun_rt3070_rf_setup(struct run_softc *sc)
5674205042Sthompsa{
5675205042Sthompsa	uint8_t bbp, rf;
5676205042Sthompsa	int i;
5677205042Sthompsa
5678260219Skevlo	if (sc->mac_ver == 0x3572) {
5679205042Sthompsa		/* enable DC filter */
5680205042Sthompsa		if (sc->mac_rev >= 0x0201)
5681205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5682205042Sthompsa
5683205042Sthompsa		run_bbp_read(sc, 138, &bbp);
5684205042Sthompsa		if (sc->ntxchains == 1)
5685205042Sthompsa			bbp |= 0x20;	/* turn off DAC1 */
5686205042Sthompsa		if (sc->nrxchains == 1)
5687205042Sthompsa			bbp &= ~0x02;	/* turn off ADC1 */
5688205042Sthompsa		run_bbp_write(sc, 138, bbp);
5689205042Sthompsa
5690205042Sthompsa		if (sc->mac_rev >= 0x0211) {
5691205042Sthompsa			/* improve power consumption */
5692205042Sthompsa			run_bbp_read(sc, 31, &bbp);
5693205042Sthompsa			run_bbp_write(sc, 31, bbp & ~0x03);
5694205042Sthompsa		}
5695205042Sthompsa
5696205042Sthompsa		run_rt3070_rf_read(sc, 16, &rf);
5697205042Sthompsa		rf = (rf & ~0x07) | sc->txmixgain_2ghz;
5698205042Sthompsa		run_rt3070_rf_write(sc, 16, rf);
5699205042Sthompsa
5700205042Sthompsa	} else if (sc->mac_ver == 0x3071) {
5701257409Skevlo		if (sc->mac_rev >= 0x0211) {
5702257409Skevlo			/* enable DC filter */
5703205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5704205042Sthompsa
5705257409Skevlo			/* improve power consumption */
5706257409Skevlo			run_bbp_read(sc, 31, &bbp);
5707257409Skevlo			run_bbp_write(sc, 31, bbp & ~0x03);
5708257409Skevlo		}
5709257409Skevlo
5710205042Sthompsa		run_bbp_read(sc, 138, &bbp);
5711205042Sthompsa		if (sc->ntxchains == 1)
5712205042Sthompsa			bbp |= 0x20;	/* turn off DAC1 */
5713205042Sthompsa		if (sc->nrxchains == 1)
5714205042Sthompsa			bbp &= ~0x02;	/* turn off ADC1 */
5715205042Sthompsa		run_bbp_write(sc, 138, bbp);
5716205042Sthompsa
5717205042Sthompsa		run_write(sc, RT2860_TX_SW_CFG1, 0);
5718205042Sthompsa		if (sc->mac_rev < 0x0211) {
5719205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2,
5720205042Sthompsa			    sc->patch_dac ? 0x2c : 0x0f);
5721205042Sthompsa		} else
5722205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0);
5723205042Sthompsa
5724205042Sthompsa	} else if (sc->mac_ver == 0x3070) {
5725205042Sthompsa		if (sc->mac_rev >= 0x0201) {
5726205042Sthompsa			/* enable DC filter */
5727205042Sthompsa			run_bbp_write(sc, 103, 0xc0);
5728205042Sthompsa
5729205042Sthompsa			/* improve power consumption */
5730205042Sthompsa			run_bbp_read(sc, 31, &bbp);
5731205042Sthompsa			run_bbp_write(sc, 31, bbp & ~0x03);
5732205042Sthompsa		}
5733205042Sthompsa
5734256955Skevlo		if (sc->mac_rev < 0x0201) {
5735205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG1, 0);
5736205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0x2c);
5737205042Sthompsa		} else
5738205042Sthompsa			run_write(sc, RT2860_TX_SW_CFG2, 0);
5739205042Sthompsa	}
5740205042Sthompsa
5741205042Sthompsa	/* initialize RF registers from ROM for >=RT3071*/
5742260219Skevlo	if (sc->mac_ver >= 0x3071) {
5743205042Sthompsa		for (i = 0; i < 10; i++) {
5744205042Sthompsa			if (sc->rf[i].reg == 0 || sc->rf[i].reg == 0xff)
5745205042Sthompsa				continue;
5746205042Sthompsa			run_rt3070_rf_write(sc, sc->rf[i].reg, sc->rf[i].val);
5747205042Sthompsa		}
5748205042Sthompsa	}
5749205042Sthompsa}
5750205042Sthompsa
5751260219Skevlostatic void
5752260219Skevlorun_rt3593_rf_setup(struct run_softc *sc)
5753260219Skevlo{
5754260219Skevlo	uint8_t bbp, rf;
5755260219Skevlo
5756260219Skevlo	if (sc->mac_rev >= 0x0211) {
5757260219Skevlo		/* Enable DC filter. */
5758260219Skevlo		run_bbp_write(sc, 103, 0xc0);
5759260219Skevlo	}
5760260219Skevlo	run_write(sc, RT2860_TX_SW_CFG1, 0);
5761260219Skevlo	if (sc->mac_rev < 0x0211) {
5762260219Skevlo		run_write(sc, RT2860_TX_SW_CFG2,
5763260219Skevlo		    sc->patch_dac ? 0x2c : 0x0f);
5764260219Skevlo	} else
5765260219Skevlo		run_write(sc, RT2860_TX_SW_CFG2, 0);
5766260219Skevlo
5767260219Skevlo	run_rt3070_rf_read(sc, 50, &rf);
5768260219Skevlo	run_rt3070_rf_write(sc, 50, rf & ~RT3593_TX_LO2);
5769260219Skevlo
5770260219Skevlo	run_rt3070_rf_read(sc, 51, &rf);
5771260219Skevlo	rf = (rf & ~(RT3593_TX_LO1 | 0x0c)) |
5772260219Skevlo	    ((sc->txmixgain_2ghz & 0x07) << 2);
5773260219Skevlo	run_rt3070_rf_write(sc, 51, rf);
5774260219Skevlo
5775260219Skevlo	run_rt3070_rf_read(sc, 38, &rf);
5776260219Skevlo	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
5777260219Skevlo
5778260219Skevlo	run_rt3070_rf_read(sc, 39, &rf);
5779260219Skevlo	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
5780260219Skevlo
5781260219Skevlo	run_rt3070_rf_read(sc, 1, &rf);
5782260219Skevlo	run_rt3070_rf_write(sc, 1, rf & ~(RT3070_RF_BLOCK | RT3070_PLL_PD));
5783260219Skevlo
5784260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
5785260219Skevlo	rf = (rf & ~0x18) | 0x10;
5786260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
5787260219Skevlo
5788260219Skevlo	/* Apply maximum likelihood detection for 2 stream case. */
5789260219Skevlo	run_bbp_read(sc, 105, &bbp);
5790260219Skevlo	if (sc->nrxchains > 1)
5791260219Skevlo		run_bbp_write(sc, 105, bbp | RT5390_MLD);
5792260219Skevlo
5793260219Skevlo	/* Avoid data lost and CRC error. */
5794260219Skevlo	run_bbp_read(sc, 4, &bbp);
5795260219Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5796260219Skevlo
5797260219Skevlo	run_bbp_write(sc, 92, 0x02);
5798260219Skevlo	run_bbp_write(sc, 82, 0x82);
5799260219Skevlo	run_bbp_write(sc, 106, 0x05);
5800260219Skevlo	run_bbp_write(sc, 104, 0x92);
5801260219Skevlo	run_bbp_write(sc, 88, 0x90);
5802260219Skevlo	run_bbp_write(sc, 148, 0xc8);
5803260219Skevlo	run_bbp_write(sc, 47, 0x48);
5804260219Skevlo	run_bbp_write(sc, 120, 0x50);
5805260219Skevlo
5806260219Skevlo	run_bbp_write(sc, 163, 0x9d);
5807260219Skevlo
5808260219Skevlo	/* SNR mapping. */
5809260219Skevlo	run_bbp_write(sc, 142, 0x06);
5810260219Skevlo	run_bbp_write(sc, 143, 0xa0);
5811260219Skevlo	run_bbp_write(sc, 142, 0x07);
5812260219Skevlo	run_bbp_write(sc, 143, 0xa1);
5813260219Skevlo	run_bbp_write(sc, 142, 0x08);
5814260219Skevlo	run_bbp_write(sc, 143, 0xa2);
5815260219Skevlo
5816260219Skevlo	run_bbp_write(sc, 31, 0x08);
5817260219Skevlo	run_bbp_write(sc, 68, 0x0b);
5818260219Skevlo	run_bbp_write(sc, 105, 0x04);
5819260219Skevlo}
5820260219Skevlo
5821260219Skevlostatic void
5822260219Skevlorun_rt5390_rf_setup(struct run_softc *sc)
5823260219Skevlo{
5824260219Skevlo	uint8_t bbp, rf;
5825260219Skevlo
5826260219Skevlo	if (sc->mac_rev >= 0x0211) {
5827260219Skevlo		/* Enable DC filter. */
5828260219Skevlo		run_bbp_write(sc, 103, 0xc0);
5829260219Skevlo
5830260219Skevlo		if (sc->mac_ver != 0x5592) {
5831260219Skevlo			/* Improve power consumption. */
5832260219Skevlo			run_bbp_read(sc, 31, &bbp);
5833260219Skevlo			run_bbp_write(sc, 31, bbp & ~0x03);
5834260219Skevlo		}
5835260219Skevlo	}
5836260219Skevlo
5837260219Skevlo	run_bbp_read(sc, 138, &bbp);
5838260219Skevlo	if (sc->ntxchains == 1)
5839260219Skevlo		bbp |= 0x20;	/* turn off DAC1 */
5840260219Skevlo	if (sc->nrxchains == 1)
5841260219Skevlo		bbp &= ~0x02;	/* turn off ADC1 */
5842260219Skevlo	run_bbp_write(sc, 138, bbp);
5843260219Skevlo
5844260219Skevlo	run_rt3070_rf_read(sc, 38, &rf);
5845260219Skevlo	run_rt3070_rf_write(sc, 38, rf & ~RT5390_RX_LO1);
5846260219Skevlo
5847260219Skevlo	run_rt3070_rf_read(sc, 39, &rf);
5848260219Skevlo	run_rt3070_rf_write(sc, 39, rf & ~RT5390_RX_LO2);
5849260219Skevlo
5850260219Skevlo	/* Avoid data lost and CRC error. */
5851260219Skevlo	run_bbp_read(sc, 4, &bbp);
5852260219Skevlo	run_bbp_write(sc, 4, bbp | RT5390_MAC_IF_CTRL);
5853260219Skevlo
5854260219Skevlo	run_rt3070_rf_read(sc, 30, &rf);
5855260219Skevlo	rf = (rf & ~0x18) | 0x10;
5856260219Skevlo	run_rt3070_rf_write(sc, 30, rf);
5857260219Skevlo
5858260219Skevlo	if (sc->mac_ver != 0x5592) {
5859260219Skevlo		run_write(sc, RT2860_TX_SW_CFG1, 0);
5860260219Skevlo		if (sc->mac_rev < 0x0211) {
5861260219Skevlo			run_write(sc, RT2860_TX_SW_CFG2,
5862260219Skevlo			    sc->patch_dac ? 0x2c : 0x0f);
5863260219Skevlo		} else
5864260219Skevlo			run_write(sc, RT2860_TX_SW_CFG2, 0);
5865260219Skevlo	}
5866260219Skevlo}
5867260219Skevlo
5868203134Sthompsastatic int
5869203134Sthompsarun_txrx_enable(struct run_softc *sc)
5870203134Sthompsa{
5871287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5872203134Sthompsa	uint32_t tmp;
5873203134Sthompsa	int error, ntries;
5874203134Sthompsa
5875203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_TX_EN);
5876203134Sthompsa	for (ntries = 0; ntries < 200; ntries++) {
5877203134Sthompsa		if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0)
5878257955Skevlo			return (error);
5879203134Sthompsa		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
5880203134Sthompsa			break;
5881203134Sthompsa		run_delay(sc, 50);
5882203134Sthompsa	}
5883203134Sthompsa	if (ntries == 200)
5884257955Skevlo		return (ETIMEDOUT);
5885203134Sthompsa
5886203134Sthompsa	run_delay(sc, 50);
5887203134Sthompsa
5888203134Sthompsa	tmp |= RT2860_RX_DMA_EN | RT2860_TX_DMA_EN | RT2860_TX_WB_DDONE;
5889203134Sthompsa	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
5890203134Sthompsa
5891203134Sthompsa	/* enable Rx bulk aggregation (set timeout and limit) */
5892203134Sthompsa	tmp = RT2860_USB_TX_EN | RT2860_USB_RX_EN | RT2860_USB_RX_AGG_EN |
5893203134Sthompsa	    RT2860_USB_RX_AGG_TO(128) | RT2860_USB_RX_AGG_LMT(2);
5894203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, tmp);
5895203134Sthompsa
5896203134Sthompsa	/* set Rx filter */
5897203134Sthompsa	tmp = RT2860_DROP_CRC_ERR | RT2860_DROP_PHY_ERR;
5898203134Sthompsa	if (ic->ic_opmode != IEEE80211_M_MONITOR) {
5899203134Sthompsa		tmp |= RT2860_DROP_UC_NOME | RT2860_DROP_DUPL |
5900203134Sthompsa		    RT2860_DROP_CTS | RT2860_DROP_BA | RT2860_DROP_ACK |
5901203134Sthompsa		    RT2860_DROP_VER_ERR | RT2860_DROP_CTRL_RSV |
5902203134Sthompsa		    RT2860_DROP_CFACK | RT2860_DROP_CFEND;
5903203134Sthompsa		if (ic->ic_opmode == IEEE80211_M_STA)
5904203134Sthompsa			tmp |= RT2860_DROP_RTS | RT2860_DROP_PSPOLL;
5905203134Sthompsa	}
5906203134Sthompsa	run_write(sc, RT2860_RX_FILTR_CFG, tmp);
5907203134Sthompsa
5908203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL,
5909203134Sthompsa	    RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
5910203134Sthompsa
5911209917Sthompsa	return (0);
5912203134Sthompsa}
5913203134Sthompsa
5914203134Sthompsastatic void
5915259030Skevlorun_adjust_freq_offset(struct run_softc *sc)
5916257955Skevlo{
5917257955Skevlo	uint8_t rf, tmp;
5918257955Skevlo
5919257955Skevlo	run_rt3070_rf_read(sc, 17, &rf);
5920257955Skevlo	tmp = rf;
5921257955Skevlo	rf = (rf & ~0x7f) | (sc->freq & 0x7f);
5922257955Skevlo	rf = MIN(rf, 0x5f);
5923257955Skevlo
5924257955Skevlo	if (tmp != rf)
5925257955Skevlo		run_mcu_cmd(sc, 0x74, (tmp << 8 ) | rf);
5926257955Skevlo}
5927257955Skevlo
5928257955Skevlostatic void
5929203134Sthompsarun_init_locked(struct run_softc *sc)
5930203134Sthompsa{
5931287197Sglebius	struct ieee80211com *ic = &sc->sc_ic;
5932287197Sglebius	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
5933203134Sthompsa	uint32_t tmp;
5934203134Sthompsa	uint8_t bbp1, bbp3;
5935203134Sthompsa	int i;
5936203134Sthompsa	int ridx;
5937203134Sthompsa	int ntries;
5938203134Sthompsa
5939209917Sthompsa	if (ic->ic_nrunning > 1)
5940208019Sthompsa		return;
5941208019Sthompsa
5942203134Sthompsa	run_stop(sc);
5943203134Sthompsa
5944233283Sbschmidt	if (run_load_microcode(sc) != 0) {
5945233283Sbschmidt		device_printf(sc->sc_dev, "could not load 8051 microcode\n");
5946233283Sbschmidt		goto fail;
5947233283Sbschmidt	}
5948233283Sbschmidt
5949203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5950203134Sthompsa		if (run_read(sc, RT2860_ASIC_VER_ID, &tmp) != 0)
5951203134Sthompsa			goto fail;
5952203134Sthompsa		if (tmp != 0 && tmp != 0xffffffff)
5953203134Sthompsa			break;
5954203134Sthompsa		run_delay(sc, 10);
5955203134Sthompsa	}
5956203134Sthompsa	if (ntries == 100)
5957203134Sthompsa		goto fail;
5958203134Sthompsa
5959203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
5960203134Sthompsa		run_setup_tx_list(sc, &sc->sc_epq[i]);
5961203134Sthompsa
5962287197Sglebius	run_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr);
5963203134Sthompsa
5964203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
5965203134Sthompsa		if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
5966203134Sthompsa			goto fail;
5967203134Sthompsa		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
5968203134Sthompsa			break;
5969203134Sthompsa		run_delay(sc, 10);
5970203134Sthompsa	}
5971203134Sthompsa	if (ntries == 100) {
5972203138Sthompsa		device_printf(sc->sc_dev, "timeout waiting for DMA engine\n");
5973203134Sthompsa		goto fail;
5974203134Sthompsa	}
5975203134Sthompsa	tmp &= 0xff0;
5976203134Sthompsa	tmp |= RT2860_TX_WB_DDONE;
5977203134Sthompsa	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
5978203134Sthompsa
5979203134Sthompsa	/* turn off PME_OEN to solve high-current issue */
5980203134Sthompsa	run_read(sc, RT2860_SYS_CTRL, &tmp);
5981203134Sthompsa	run_write(sc, RT2860_SYS_CTRL, tmp & ~RT2860_PME_OEN);
5982203134Sthompsa
5983203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL,
5984203134Sthompsa	    RT2860_BBP_HRST | RT2860_MAC_SRST);
5985203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, 0);
5986203134Sthompsa
5987203134Sthompsa	if (run_reset(sc) != 0) {
5988203138Sthompsa		device_printf(sc->sc_dev, "could not reset chipset\n");
5989203134Sthompsa		goto fail;
5990203134Sthompsa	}
5991203134Sthompsa
5992203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
5993203134Sthompsa
5994203134Sthompsa	/* init Tx power for all Tx rates (from EEPROM) */
5995203134Sthompsa	for (ridx = 0; ridx < 5; ridx++) {
5996203134Sthompsa		if (sc->txpow20mhz[ridx] == 0xffffffff)
5997203134Sthompsa			continue;
5998203134Sthompsa		run_write(sc, RT2860_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]);
5999203134Sthompsa	}
6000203134Sthompsa
6001257955Skevlo	for (i = 0; i < nitems(rt2870_def_mac); i++)
6002203134Sthompsa		run_write(sc, rt2870_def_mac[i].reg, rt2870_def_mac[i].val);
6003203134Sthompsa	run_write(sc, RT2860_WMM_AIFSN_CFG, 0x00002273);
6004203134Sthompsa	run_write(sc, RT2860_WMM_CWMIN_CFG, 0x00002344);
6005203134Sthompsa	run_write(sc, RT2860_WMM_CWMAX_CFG, 0x000034aa);
6006203134Sthompsa
6007259030Skevlo	if (sc->mac_ver >= 0x5390) {
6008259030Skevlo		run_write(sc, RT2860_TX_SW_CFG0,
6009259030Skevlo		    4 << RT2860_DLY_PAPE_EN_SHIFT | 4);
6010259030Skevlo		if (sc->mac_ver >= 0x5392) {
6011259030Skevlo			run_write(sc, RT2860_MAX_LEN_CFG, 0x00002fff);
6012259032Skevlo			if (sc->mac_ver == 0x5592) {
6013259032Skevlo				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcba980);
6014259032Skevlo				run_write(sc, RT2860_TXOP_HLDR_ET, 0x00000082);
6015259032Skevlo			} else {
6016259032Skevlo				run_write(sc, RT2860_HT_FBK_CFG1, 0xedcb4980);
6017259032Skevlo				run_write(sc, RT2860_LG_FBK_CFG0, 0xedcba322);
6018259032Skevlo			}
6019259030Skevlo		}
6020260219Skevlo	} else if (sc->mac_ver == 0x3593) {
6021260219Skevlo		run_write(sc, RT2860_TX_SW_CFG0,
6022260219Skevlo		    4 << RT2860_DLY_PAPE_EN_SHIFT | 2);
6023257955Skevlo	} else if (sc->mac_ver >= 0x3070) {
6024203134Sthompsa		/* set delay of PA_PE assertion to 1us (unit of 0.25us) */
6025203134Sthompsa		run_write(sc, RT2860_TX_SW_CFG0,
6026203134Sthompsa		    4 << RT2860_DLY_PAPE_EN_SHIFT);
6027203134Sthompsa	}
6028203134Sthompsa
6029203134Sthompsa	/* wait while MAC is busy */
6030203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
6031203134Sthompsa		if (run_read(sc, RT2860_MAC_STATUS_REG, &tmp) != 0)
6032203134Sthompsa			goto fail;
6033203134Sthompsa		if (!(tmp & (RT2860_RX_STATUS_BUSY | RT2860_TX_STATUS_BUSY)))
6034203134Sthompsa			break;
6035203134Sthompsa		run_delay(sc, 10);
6036203134Sthompsa	}
6037203134Sthompsa	if (ntries == 100)
6038203134Sthompsa		goto fail;
6039203134Sthompsa
6040203134Sthompsa	/* clear Host to MCU mailbox */
6041203134Sthompsa	run_write(sc, RT2860_H2M_BBPAGENT, 0);
6042203134Sthompsa	run_write(sc, RT2860_H2M_MAILBOX, 0);
6043203134Sthompsa	run_delay(sc, 10);
6044203134Sthompsa
6045203134Sthompsa	if (run_bbp_init(sc) != 0) {
6046203138Sthompsa		device_printf(sc->sc_dev, "could not initialize BBP\n");
6047203134Sthompsa		goto fail;
6048203134Sthompsa	}
6049203134Sthompsa
6050203134Sthompsa	/* abort TSF synchronization */
6051203134Sthompsa	run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
6052203134Sthompsa	tmp &= ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
6053203134Sthompsa	    RT2860_TBTT_TIMER_EN);
6054203134Sthompsa	run_write(sc, RT2860_BCN_TIME_CFG, tmp);
6055203134Sthompsa
6056203134Sthompsa	/* clear RX WCID search table */
6057203134Sthompsa	run_set_region_4(sc, RT2860_WCID_ENTRY(0), 0, 512);
6058203134Sthompsa	/* clear WCID attribute table */
6059203134Sthompsa	run_set_region_4(sc, RT2860_WCID_ATTR(0), 0, 8 * 32);
6060203134Sthompsa
6061209144Sthompsa	/* hostapd sets a key before init. So, don't clear it. */
6062209917Sthompsa	if (sc->cmdq_key_set != RUN_CMDQ_GO) {
6063209144Sthompsa		/* clear shared key table */
6064209144Sthompsa		run_set_region_4(sc, RT2860_SKEY(0, 0), 0, 8 * 32);
6065209144Sthompsa		/* clear shared key mode */
6066209144Sthompsa		run_set_region_4(sc, RT2860_SKEY_MODE_0_7, 0, 4);
6067209144Sthompsa	}
6068209144Sthompsa
6069203134Sthompsa	run_read(sc, RT2860_US_CYC_CNT, &tmp);
6070203134Sthompsa	tmp = (tmp & ~0xff) | 0x1e;
6071203134Sthompsa	run_write(sc, RT2860_US_CYC_CNT, tmp);
6072203134Sthompsa
6073205042Sthompsa	if (sc->mac_rev != 0x0101)
6074203134Sthompsa		run_write(sc, RT2860_TXOP_CTRL_CFG, 0x0000583f);
6075203134Sthompsa
6076203134Sthompsa	run_write(sc, RT2860_WMM_TXOP0_CFG, 0);
6077203134Sthompsa	run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96);
6078203134Sthompsa
6079203134Sthompsa	/* write vendor-specific BBP values (from EEPROM) */
6080260219Skevlo	if (sc->mac_ver < 0x3593) {
6081257955Skevlo		for (i = 0; i < 10; i++) {
6082257955Skevlo			if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff)
6083257955Skevlo				continue;
6084257955Skevlo			run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val);
6085257955Skevlo		}
6086203134Sthompsa	}
6087203134Sthompsa
6088203134Sthompsa	/* select Main antenna for 1T1R devices */
6089257955Skevlo	if (sc->rf_rev == RT3070_RF_3020 || sc->rf_rev == RT5390_RF_5370)
6090203134Sthompsa		run_set_rx_antenna(sc, 0);
6091203134Sthompsa
6092203134Sthompsa	/* send LEDs operating mode to microcontroller */
6093203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0]);
6094203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1]);
6095203134Sthompsa	(void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2]);
6096203134Sthompsa
6097257955Skevlo	if (sc->mac_ver >= 0x5390)
6098257955Skevlo		run_rt5390_rf_init(sc);
6099260219Skevlo	else if (sc->mac_ver == 0x3593)
6100260219Skevlo		run_rt3593_rf_init(sc);
6101257955Skevlo	else if (sc->mac_ver >= 0x3070)
6102205042Sthompsa		run_rt3070_rf_init(sc);
6103205042Sthompsa
6104203134Sthompsa	/* disable non-existing Rx chains */
6105203134Sthompsa	run_bbp_read(sc, 3, &bbp3);
6106203134Sthompsa	bbp3 &= ~(1 << 3 | 1 << 4);
6107203134Sthompsa	if (sc->nrxchains == 2)
6108203134Sthompsa		bbp3 |= 1 << 3;
6109203134Sthompsa	else if (sc->nrxchains == 3)
6110203134Sthompsa		bbp3 |= 1 << 4;
6111203134Sthompsa	run_bbp_write(sc, 3, bbp3);
6112203134Sthompsa
6113203134Sthompsa	/* disable non-existing Tx chains */
6114203134Sthompsa	run_bbp_read(sc, 1, &bbp1);
6115203134Sthompsa	if (sc->ntxchains == 1)
6116203134Sthompsa		bbp1 &= ~(1 << 3 | 1 << 4);
6117203134Sthompsa	run_bbp_write(sc, 1, bbp1);
6118203134Sthompsa
6119260219Skevlo	if (sc->mac_ver >= 0x5390)
6120260219Skevlo		run_rt5390_rf_setup(sc);
6121260219Skevlo	else if (sc->mac_ver == 0x3593)
6122260219Skevlo		run_rt3593_rf_setup(sc);
6123260219Skevlo	else if (sc->mac_ver >= 0x3070)
6124205042Sthompsa		run_rt3070_rf_setup(sc);
6125203134Sthompsa
6126203134Sthompsa	/* select default channel */
6127203134Sthompsa	run_set_chan(sc, ic->ic_curchan);
6128203134Sthompsa
6129203134Sthompsa	/* setup initial protection mode */
6130218492Sbschmidt	run_updateprot_cb(ic);
6131203134Sthompsa
6132203134Sthompsa	/* turn radio LED on */
6133203134Sthompsa	run_set_leds(sc, RT2860_LED_RADIO);
6134203134Sthompsa
6135287197Sglebius	sc->sc_flags |= RUN_RUNNING;
6136208019Sthompsa	sc->cmdq_run = RUN_CMDQ_GO;
6137203134Sthompsa
6138209917Sthompsa	for (i = 0; i != RUN_N_XFER; i++)
6139203134Sthompsa		usbd_xfer_set_stall(sc->sc_xfer[i]);
6140203134Sthompsa
6141203134Sthompsa	usbd_transfer_start(sc->sc_xfer[RUN_BULK_RX]);
6142203134Sthompsa
6143203134Sthompsa	if (run_txrx_enable(sc) != 0)
6144203134Sthompsa		goto fail;
6145203134Sthompsa
6146203134Sthompsa	return;
6147203134Sthompsa
6148203134Sthompsafail:
6149203134Sthompsa	run_stop(sc);
6150203134Sthompsa}
6151203134Sthompsa
6152203134Sthompsastatic void
6153203134Sthompsarun_stop(void *arg)
6154203134Sthompsa{
6155203134Sthompsa	struct run_softc *sc = (struct run_softc *)arg;
6156203134Sthompsa	uint32_t tmp;
6157203134Sthompsa	int i;
6158203134Sthompsa	int ntries;
6159203134Sthompsa
6160203134Sthompsa	RUN_LOCK_ASSERT(sc, MA_OWNED);
6161203134Sthompsa
6162287197Sglebius	if (sc->sc_flags & RUN_RUNNING)
6163203134Sthompsa		run_set_leds(sc, 0);	/* turn all LEDs off */
6164203134Sthompsa
6165287197Sglebius	sc->sc_flags &= ~RUN_RUNNING;
6166203134Sthompsa
6167208019Sthompsa	sc->ratectl_run = RUN_RATECTL_OFF;
6168209144Sthompsa	sc->cmdq_run = sc->cmdq_key_set;
6169208019Sthompsa
6170203134Sthompsa	RUN_UNLOCK(sc);
6171203134Sthompsa
6172203134Sthompsa	for(i = 0; i < RUN_N_XFER; i++)
6173203134Sthompsa		usbd_transfer_drain(sc->sc_xfer[i]);
6174203134Sthompsa
6175203134Sthompsa	RUN_LOCK(sc);
6176203134Sthompsa
6177288649Sadrian	run_drain_mbufq(sc);
6178288649Sadrian
6179209917Sthompsa	if (sc->rx_m != NULL) {
6180203134Sthompsa		m_free(sc->rx_m);
6181203134Sthompsa		sc->rx_m = NULL;
6182203134Sthompsa	}
6183203134Sthompsa
6184257955Skevlo	/* Disable Tx/Rx DMA. */
6185257955Skevlo	if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
6186257955Skevlo		return;
6187257955Skevlo	tmp &= ~(RT2860_RX_DMA_EN | RT2860_TX_DMA_EN);
6188257955Skevlo	run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
6189257955Skevlo
6190258643Shselasky	for (ntries = 0; ntries < 100; ntries++) {
6191257955Skevlo		if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
6192257955Skevlo			return;
6193257955Skevlo		if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
6194257955Skevlo				break;
6195257955Skevlo		run_delay(sc, 10);
6196257955Skevlo	}
6197257955Skevlo	if (ntries == 100) {
6198257955Skevlo		device_printf(sc->sc_dev, "timeout waiting for DMA engine\n");
6199257955Skevlo		return;
6200257955Skevlo	}
6201257955Skevlo
6202203134Sthompsa	/* disable Tx/Rx */
6203203134Sthompsa	run_read(sc, RT2860_MAC_SYS_CTRL, &tmp);
6204203134Sthompsa	tmp &= ~(RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
6205203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, tmp);
6206203134Sthompsa
6207203134Sthompsa	/* wait for pending Tx to complete */
6208203134Sthompsa	for (ntries = 0; ntries < 100; ntries++) {
6209209917Sthompsa		if (run_read(sc, RT2860_TXRXQ_PCNT, &tmp) != 0) {
6210203134Sthompsa			DPRINTF("Cannot read Tx queue count\n");
6211203134Sthompsa			break;
6212203134Sthompsa		}
6213209917Sthompsa		if ((tmp & RT2860_TX2Q_PCNT_MASK) == 0) {
6214203134Sthompsa			DPRINTF("All Tx cleared\n");
6215203134Sthompsa			break;
6216203134Sthompsa		}
6217203134Sthompsa		run_delay(sc, 10);
6218203134Sthompsa	}
6219209917Sthompsa	if (ntries >= 100)
6220203134Sthompsa		DPRINTF("There are still pending Tx\n");
6221203134Sthompsa	run_delay(sc, 10);
6222203134Sthompsa	run_write(sc, RT2860_USB_DMA_CFG, 0);
6223203134Sthompsa
6224203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST);
6225203134Sthompsa	run_write(sc, RT2860_MAC_SYS_CTRL, 0);
6226203134Sthompsa
6227203134Sthompsa	for (i = 0; i != RUN_EP_QUEUES; i++)
6228203134Sthompsa		run_unsetup_tx_list(sc, &sc->sc_epq[i]);
6229203134Sthompsa}
6230203134Sthompsa
6231203134Sthompsastatic void
6232257429Shselaskyrun_delay(struct run_softc *sc, u_int ms)
6233203134Sthompsa{
6234203134Sthompsa	usb_pause_mtx(mtx_owned(&sc->sc_mtx) ?
6235203134Sthompsa	    &sc->sc_mtx : NULL, USB_MS_TO_TICKS(ms));
6236203134Sthompsa}
6237203134Sthompsa
6238203134Sthompsastatic device_method_t run_methods[] = {
6239203134Sthompsa	/* Device interface */
6240203134Sthompsa	DEVMETHOD(device_probe,		run_match),
6241203134Sthompsa	DEVMETHOD(device_attach,	run_attach),
6242203134Sthompsa	DEVMETHOD(device_detach,	run_detach),
6243246614Shselasky	DEVMETHOD_END
6244203134Sthompsa};
6245203134Sthompsa
6246203134Sthompsastatic driver_t run_driver = {
6247233774Shselasky	.name = "run",
6248233774Shselasky	.methods = run_methods,
6249233774Shselasky	.size = sizeof(struct run_softc)
6250203134Sthompsa};
6251203134Sthompsa
6252203134Sthompsastatic devclass_t run_devclass;
6253203134Sthompsa
6254259812SkevloDRIVER_MODULE(run, uhub, run_driver, run_devclass, run_driver_loaded, NULL);
6255212122SthompsaMODULE_DEPEND(run, wlan, 1, 1, 1);
6256212122SthompsaMODULE_DEPEND(run, usb, 1, 1, 1);
6257212122SthompsaMODULE_DEPEND(run, firmware, 1, 1, 1);
6258212122SthompsaMODULE_VERSION(run, 1);
6259292080SimpUSB_PNP_HOST_INFO(run_devs);
6260